author | Ed Morley <emorley@mozilla.com> |
Fri, 29 Jun 2012 08:41:44 +0100 | |
changeset 97913 | 4a8e0d5fc954ac726af18044ae7e2b1d8a260782 |
parent 97857 | 081d8578beb131516f2d58290eb563bb96d46b72 (current diff) |
parent 97912 | 0b5f8c30088c8279a7b49419c7bb31ee84a2c266 (diff) |
child 97914 | ff38bb1bce5add6c28f079f67353c432efac4f33 |
child 97936 | 8a2458ffa51dd08d8ee7d9885aaf0a6bd0b5a312 |
push id | 23007 |
push user | emorley@mozilla.com |
push date | Fri, 29 Jun 2012 07:42:23 +0000 |
treeherder | mozilla-central@4a8e0d5fc954 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 16.0a1 |
first release with | nightly linux32
4a8e0d5fc954
/
16.0a1
/
20120629030530
/
files
nightly linux64
4a8e0d5fc954
/
16.0a1
/
20120629030530
/
files
nightly mac
4a8e0d5fc954
/
16.0a1
/
20120629030530
/
files
nightly win32
4a8e0d5fc954
/
16.0a1
/
20120629030530
/
files
nightly win64
4a8e0d5fc954
/
16.0a1
/
20120629030530
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
16.0a1
/
20120629030530
/
pushlog to previous
nightly linux64
16.0a1
/
20120629030530
/
pushlog to previous
nightly mac
16.0a1
/
20120629030530
/
pushlog to previous
nightly win32
16.0a1
/
20120629030530
/
pushlog to previous
nightly win64
16.0a1
/
20120629030530
/
pushlog to previous
|
--- a/browser/base/content/openLocation.js +++ b/browser/base/content/openLocation.js @@ -2,24 +2,26 @@ # # 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/. var browser; var dialog = {}; var pref = null; +let openLocationModule = {}; try { pref = Components.classes["@mozilla.org/preferences-service;1"] .getService(Components.interfaces.nsIPrefBranch); } catch (ex) { // not critical, remain silent } -Components.utils.import("resource:///modules/openLocationLastURL.jsm"); +Components.utils.import("resource:///modules/openLocationLastURL.jsm", openLocationModule); +let gOpenLocationLastURL = new openLocationModule.OpenLocationLastURL(window.opener); function onLoad() { dialog.input = document.getElementById("dialog.input"); dialog.open = document.documentElement.getButton("accept"); dialog.openWhereList = document.getElementById("openWhereList"); dialog.openTopWindow = document.getElementById("currentWindow"); dialog.bundle = document.getElementById("openLocationBundle");
--- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -471,20 +471,23 @@ BrowserGlue.prototype = { // // aQuitType == "lastwindow" is overloaded. "lastwindow" is used to indicate // "the last window is closing but we're not quitting (a non-browser window is open)" // and also "we're quitting by closing the last window". var windowcount = 0; var pagecount = 0; var browserEnum = Services.wm.getEnumerator("navigator:browser"); + let allWindowsPrivate = true; while (browserEnum.hasMoreElements()) { windowcount++; var browser = browserEnum.getNext(); + if (("gPrivateBrowsingUI" in browser) && !browser.gPrivateBrowsingUI.privateWindow) + allWindowsPrivate = false; var tabbrowser = browser.document.getElementById("content"); if (tabbrowser) pagecount += tabbrowser.browsers.length - tabbrowser._numPinnedTabs; } this._saveSession = false; if (pagecount < 2) return; @@ -518,20 +521,18 @@ BrowserGlue.prototype = { // we should show the window closing warning instead. warnAboutClosing // tabs checks browser.tabs.warnOnClose and returns if it's ok to close // the window. It doesn't actually close the window. mostRecentBrowserWindow = Services.wm.getMostRecentWindow("navigator:browser"); aCancelQuit.data = !mostRecentBrowserWindow.gBrowser.warnAboutClosingTabs(true); return; } - var inPrivateBrowsing = Cc["@mozilla.org/privatebrowsing;1"]. - getService(Ci.nsIPrivateBrowsingService). - privateBrowsingEnabled; - if (inPrivateBrowsing) + // Never show a prompt inside private browsing mode + if (allWindowsPrivate) return; if (!showPrompt) return; var quitBundle = Services.strings.createBundle("chrome://browser/locale/quitDialog.properties"); var brandBundle = Services.strings.createBundle("chrome://branding/locale/brand.properties"); @@ -1568,31 +1569,29 @@ ContentPermissionPrompt.prototype = { accessKey: browserBundle.GetStringFromName("geolocation.shareLocation.accesskey"), callback: function(notification) { request.allow(); }, }; var message; var secondaryActions = []; + var requestingWindow = request.window.top; + var chromeWin = getChromeWindow(requestingWindow).wrappedJSObject; // Different message/options if it is a local file if (requestingURI.schemeIs("file")) { message = browserBundle.formatStringFromName("geolocation.shareWithFile", [requestingURI.path], 1); } else { message = browserBundle.formatStringFromName("geolocation.shareWithSite", [requestingURI.host], 1); // Don't offer to "always/never share" in PB mode - var inPrivateBrowsing = Cc["@mozilla.org/privatebrowsing;1"]. - getService(Ci.nsIPrivateBrowsingService). - privateBrowsingEnabled; - - if (!inPrivateBrowsing) { + if (("gPrivateBrowsingUI" in chromeWin) && !chromeWin.gPrivateBrowsingUI.privateWindow) { secondaryActions.push({ label: browserBundle.GetStringFromName("geolocation.alwaysShareLocation"), accessKey: browserBundle.GetStringFromName("geolocation.alwaysShareLocation.accesskey"), callback: function () { Services.perms.add(requestingURI, "geo", Ci.nsIPermissionManager.ALLOW_ACTION); request.allow(); } }); @@ -1602,18 +1601,16 @@ ContentPermissionPrompt.prototype = { callback: function () { Services.perms.add(requestingURI, "geo", Ci.nsIPermissionManager.DENY_ACTION); request.cancel(); } }); } } - var requestingWindow = request.window.top; - var chromeWin = getChromeWindow(requestingWindow).wrappedJSObject; var browser = chromeWin.gBrowser.getBrowserForDocument(requestingWindow.document); chromeWin.PopupNotifications.show(browser, "geolocation", message, "geo-notification-icon", mainAction, secondaryActions); } }; var components = [BrowserGlue, ContentPermissionPrompt];
--- a/browser/components/places/content/sidebarUtils.js +++ b/browser/components/places/content/sidebarUtils.js @@ -61,21 +61,21 @@ var SidebarUtils = { // selection as an indication of which link to load. tbo.view.selection.select(row.value); PlacesUIUtils.openNodeWithEvent(aTree.selectedNode, aEvent, aTree); } }, handleTreeKeyPress: function SU_handleTreeKeyPress(aEvent) { // XXX Bug 627901: Post Fx4, this method should take a tree parameter. - let node = aEvent.target.selectedNode; + let tree = aEvent.target; + let node = tree.selectedNode; if (node) { - let view = PlacesUIUtils.getViewForNode(node); if (aEvent.keyCode == KeyEvent.DOM_VK_RETURN) - PlacesUIUtils.openNodeWithEvent(node, aEvent, view); + PlacesUIUtils.openNodeWithEvent(node, aEvent, tree); } }, /** * The following function displays the URL of a node that is being * hovered over. */ handleTreeMouseMove: function SU_handleTreeMouseMove(aEvent) {
--- a/browser/components/places/content/treeView.js +++ b/browser/components/places/content/treeView.js @@ -1,12 +1,19 @@ /* 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/. */ +Components.utils.import('resource://gre/modules/XPCOMUtils.jsm'); + +const PTV_interfaces = [Ci.nsITreeView, + Ci.nsINavHistoryResultObserver, + Ci.nsINavHistoryResultTreeViewer, + Ci.nsISupportsWeakReference]; + function PlacesTreeView(aFlatList, aOnOpenFlatContainer, aController) { this._tree = null; this._result = null; this._selection = null; this._rootNode = null; this._rows = []; this._flatList = aFlatList; this._openContainerCallback = aOnOpenFlatContainer; @@ -34,25 +41,27 @@ PlacesTreeView.prototype = { get _dateService() { if (!this.__dateService) { this.__dateService = Cc["@mozilla.org/intl/scriptabledateformat;1"]. getService(Ci.nsIScriptableDateFormat); } return this.__dateService; }, - QueryInterface: function PTV_QueryInterface(aIID) { - if (aIID.equals(Ci.nsITreeView) || - aIID.equals(Ci.nsINavHistoryResultObserver) || - aIID.equals(Ci.nsINavHistoryResultTreeViewer) || - aIID.equals(Ci.nsISupportsWeakReference) || - aIID.equals(Ci.nsISupports)) - return this; - throw Cr.NS_ERROR_NO_INTERFACE; - }, + QueryInterface: XPCOMUtils.generateQI(PTV_interfaces), + + // Bug 761494: + // ---------- + // Some addons use methods from nsINavHistoryResultObserver and + // nsINavHistoryResultTreeViewer, without QIing to these intefaces first. + // That's not a problem when the view is retrieved through the + // <tree>.view getter (which returns the wrappedJSObject of this object), + // it raises an issue when the view retrieved through the treeBoxObject.view + // getter. Thus, to avoid breaking addons, the interfaces are prefetched. + classInfo: XPCOMUtils.generateCI({ interfaces: PTV_interfaces }), /** * This is called once both the result and the tree are set. */ _finishInit: function PTV__finishInit() { let selection = this.selection; if (selection) selection.selectEventsSuppressed = true;
--- a/browser/components/privatebrowsing/test/unit/test_openLocationLastURL.js +++ b/browser/components/privatebrowsing/test/unit/test_openLocationLastURL.js @@ -1,69 +1,78 @@ /* 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/. */ // Test the correct behavior of the openLocationLastURL.jsm JS module. function run_test_on_service() { - Cu.import("resource:///modules/openLocationLastURL.jsm"); - + let openLocationModule = {}; + // This variable fakes the window required for getting the PB flag + let window = { gPrivateBrowsingUI: { privateWindow: false } }; + Cu.import("resource:///modules/openLocationLastURL.jsm", openLocationModule); + let gOpenLocationLastURL = new openLocationModule.OpenLocationLastURL(window); + function clearHistory() { // simulate clearing the private data Cc["@mozilla.org/observer-service;1"]. getService(Ci.nsIObserverService). notifyObservers(null, "browser:purge-session-history", ""); } - + let pb = Cc[PRIVATEBROWSING_CONTRACT_ID]. getService(Ci.nsIPrivateBrowsingService); let pref = Cc["@mozilla.org/preferences-service;1"]. getService(Ci.nsIPrefBranch); gOpenLocationLastURL.reset(); do_check_eq(typeof gOpenLocationLastURL, "object"); do_check_eq(gOpenLocationLastURL.value, ""); + function switchPrivateBrowsing(flag) { + pb.privateBrowsingEnabled = flag; + window.gPrivateBrowsingUI.privateWindow = flag; + } + const url1 = "mozilla.org"; const url2 = "mozilla.com"; gOpenLocationLastURL.value = url1; do_check_eq(gOpenLocationLastURL.value, url1); gOpenLocationLastURL.value = ""; do_check_eq(gOpenLocationLastURL.value, ""); gOpenLocationLastURL.value = url2; do_check_eq(gOpenLocationLastURL.value, url2); clearHistory(); do_check_eq(gOpenLocationLastURL.value, ""); gOpenLocationLastURL.value = url2; - pb.privateBrowsingEnabled = true; + switchPrivateBrowsing(true); do_check_eq(gOpenLocationLastURL.value, ""); - - pb.privateBrowsingEnabled = false; + + switchPrivateBrowsing(false); do_check_eq(gOpenLocationLastURL.value, url2); - pb.privateBrowsingEnabled = true; + switchPrivateBrowsing(true); gOpenLocationLastURL.value = url1; do_check_eq(gOpenLocationLastURL.value, url1); - pb.privateBrowsingEnabled = false; + switchPrivateBrowsing(false); do_check_eq(gOpenLocationLastURL.value, url2); - pb.privateBrowsingEnabled = true; + switchPrivateBrowsing(true); gOpenLocationLastURL.value = url1; do_check_neq(gOpenLocationLastURL.value, ""); clearHistory(); do_check_eq(gOpenLocationLastURL.value, ""); - pb.privateBrowsingEnabled = false; + switchPrivateBrowsing(false); do_check_eq(gOpenLocationLastURL.value, ""); } // Support running tests on both the service itself and its wrapper function run_test() { run_test_on_all_services(); }
--- a/browser/modules/openLocationLastURL.jsm +++ b/browser/modules/openLocationLastURL.jsm @@ -1,65 +1,78 @@ /* 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/. */ const LAST_URL_PREF = "general.open_location.last_url"; const nsISupportsString = Components.interfaces.nsISupportsString; - -var EXPORTED_SYMBOLS = [ "gOpenLocationLastURL" ]; +const Ci = Components.interfaces; -let pbSvc = Components.classes["@mozilla.org/privatebrowsing;1"] - .getService(Components.interfaces.nsIPrivateBrowsingService); +var EXPORTED_SYMBOLS = [ "OpenLocationLastURL" ]; + let prefSvc = Components.classes["@mozilla.org/preferences-service;1"] .getService(Components.interfaces.nsIPrefBranch); +let gOpenLocationLastURLData = ""; let observer = { QueryInterface: function (aIID) { if (aIID.equals(Components.interfaces.nsIObserver) || aIID.equals(Components.interfaces.nsISupports) || aIID.equals(Components.interfaces.nsISupportsWeakReference)) return this; throw Components.results.NS_NOINTERFACE; }, observe: function (aSubject, aTopic, aData) { switch (aTopic) { - case "private-browsing": + case "last-pb-context-exited": gOpenLocationLastURLData = ""; break; case "browser:purge-session-history": - gOpenLocationLastURL.reset(); + prefSvc.clearUserPref(LAST_URL_PREF); + gOpenLocationLastURLData = ""; break; } } }; let os = Components.classes["@mozilla.org/observer-service;1"] .getService(Components.interfaces.nsIObserverService); -os.addObserver(observer, "private-browsing", true); +os.addObserver(observer, "last-pb-context-exited", true); os.addObserver(observer, "browser:purge-session-history", true); -let gOpenLocationLastURLData = ""; -let gOpenLocationLastURL = { + +function OpenLocationLastURL(aWindow) { + this.window = aWindow; +} + +OpenLocationLastURL.prototype = { + isPrivate: function OpenLocationLastURL_isPrivate() { + // Assume not in private browsing mode, unless the browser window is + // in private mode. + if (!this.window || !("gPrivateBrowsingUI" in this.window)) + return false; + + return this.window.gPrivateBrowsingUI.privateWindow; + }, get value() { - if (pbSvc.privateBrowsingEnabled) + if (this.isPrivate()) return gOpenLocationLastURLData; else { try { return prefSvc.getComplexValue(LAST_URL_PREF, nsISupportsString).data; } catch (e) { return ""; } } }, set value(val) { if (typeof val != "string") val = ""; - if (pbSvc.privateBrowsingEnabled) + if (this.isPrivate()) gOpenLocationLastURLData = val; else { let str = Components.classes["@mozilla.org/supports-string;1"] .createInstance(Components.interfaces.nsISupportsString); str.data = val; prefSvc.setComplexValue(LAST_URL_PREF, nsISupportsString, str); } },
--- a/build/mobile/robocop/FennecNativeActions.java.in +++ b/build/mobile/robocop/FennecNativeActions.java.in @@ -31,34 +31,36 @@ import org.json.*; import com.jayway.android.robotium.solo.Solo; import static @ANDROID_PACKAGE_NAME@.FennecNativeDriver.LogLevel; public class FennecNativeActions implements Actions { private Solo mSolo; private Instrumentation mInstr; private Activity mGeckoApp; + private Assert mAsserter; // Objects for reflexive access of fennec classes. private ClassLoader mClassLoader; private Class mGel; private Class mGe; private Class mGas; private Class mDrawListener; private Method mRegisterGEL; private Method mUnregisterGEL; private Method mSendGE; private Method mGetLayerClient; private Method mSetDrawListener; private static final String LOGTAG = "FennecNativeActions"; - public FennecNativeActions(Activity activity, Solo robocop, Instrumentation instrumentation) { + public FennecNativeActions(Activity activity, Solo robocop, Instrumentation instrumentation, Assert asserter) { mSolo = robocop; mInstr = instrumentation; mGeckoApp = activity; + mAsserter = asserter; // Set up reflexive access of java classes and methods. try { mClassLoader = activity.getClassLoader(); mGel = mClassLoader.loadClass("org.mozilla.gecko.GeckoEventListener"); mGe = mClassLoader.loadClass("org.mozilla.gecko.GeckoEvent"); mGas = mClassLoader.loadClass("org.mozilla.gecko.GeckoAppShell"); Class [] parameters = new Class[2]; parameters[0] = String.class; @@ -112,30 +114,39 @@ public class FennecNativeActions impleme return null; } } class GeckoEventExpecter implements EventExpecter { private final String mGeckoEvent; private final Object[] mRegistrationParams; private boolean mEventReceived; + private static final int MAX_WAIT_MS = 90000; GeckoEventExpecter(String geckoEvent, Object[] registrationParams) { mGeckoEvent = geckoEvent; mRegistrationParams = registrationParams; } public synchronized void blockForEvent() { + long startTime = SystemClock.uptimeMillis(); + long endTime = 0; while (! mEventReceived) { try { - this.wait(); + this.wait(MAX_WAIT_MS); } catch (InterruptedException ie) { FennecNativeDriver.log(LogLevel.ERROR, ie); break; } + endTime = SystemClock.uptimeMillis(); + if (!mEventReceived && (endTime - startTime >= MAX_WAIT_MS)) { + mAsserter.ok(false, "GeckoEventExpecter", + "blockForEvent timeout: "+mGeckoEvent); + return; + } } FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG, "unblocked on expecter for " + mGeckoEvent); } public synchronized boolean eventReceived() { return mEventReceived; } @@ -217,37 +228,45 @@ public class FennecNativeActions impleme } return null; } } class PaintExpecter implements RepeatedEventExpecter { private Object mLayerClient; private boolean mPaintDone; + private static final int MAX_WAIT_MS = 90000; PaintExpecter() throws IllegalAccessException, InvocationTargetException { mLayerClient = mGetLayerClient.invoke(mGeckoApp); mSetDrawListener.invoke(mLayerClient, Proxy.newProxyInstance(mClassLoader, new Class[] { mDrawListener }, new DrawListenerProxy(this))); } void notifyOfEvent() { synchronized (this) { mPaintDone = true; this.notifyAll(); } } public synchronized void blockForEvent() { + long startTime = SystemClock.uptimeMillis(); + long endTime = 0; while (!mPaintDone) { try { - this.wait(); + this.wait(MAX_WAIT_MS); } catch (InterruptedException ie) { FennecNativeDriver.log(LogLevel.ERROR, ie); break; } + endTime = SystemClock.uptimeMillis(); + if (!mPaintDone && (endTime - startTime >= MAX_WAIT_MS)) { + mAsserter.ok(false, "PaintExpecter", "blockForEvent timeout"); + return; + } } try { mSetDrawListener.invoke(mLayerClient, (Object)null); } catch (Exception e) { FennecNativeDriver.log(LogLevel.ERROR, e); } } @@ -255,34 +274,41 @@ public class FennecNativeActions impleme return mPaintDone; } public synchronized void blockUntilClear(long millis) { if (millis <= 0) { throw new IllegalArgumentException("millis must be > 0"); } // wait for at least one event + long startTime = SystemClock.uptimeMillis(); + long endTime = 0; while (!mPaintDone) { try { - this.wait(); + this.wait(MAX_WAIT_MS); } catch (InterruptedException ie) { FennecNativeDriver.log(LogLevel.ERROR, ie); break; } + endTime = SystemClock.uptimeMillis(); + if (!mPaintDone && (endTime - startTime >= MAX_WAIT_MS)) { + mAsserter.ok(false, "PaintExpecter", "blockUtilClear timeout"); + return; + } } // now wait for a period of millis where we don't get an event - long startTime = SystemClock.uptimeMillis(); + startTime = SystemClock.uptimeMillis(); while (true) { try { this.wait(millis); } catch (InterruptedException ie) { FennecNativeDriver.log(LogLevel.ERROR, ie); break; } - long endTime = SystemClock.uptimeMillis(); + endTime = SystemClock.uptimeMillis(); if (endTime - startTime >= millis) { // success break; } // we got a notify() before we could wait long enough, so we need to start over startTime = endTime; } try {
--- a/caps/idl/nsIScriptSecurityManager.idl +++ b/caps/idl/nsIScriptSecurityManager.idl @@ -4,17 +4,17 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsISupports.idl" #include "nsIPrincipal.idl" #include "nsIXPCSecurityManager.idl" interface nsIURI; interface nsIChannel; -[scriptable, uuid(3708aa92-e2d9-4fd1-9e46-edfa3eb5ebf5)] +[scriptable, uuid(cdb27711-492b-4973-938b-de81ac124658)] interface nsIScriptSecurityManager : nsIXPCSecurityManager { ///////////////// Security Checks ////////////////// /** * Checks whether the running script is allowed to access aProperty. */ [noscript] void checkPropertyAccess(in JSContextPtr aJSContext, in JSObjectPtr aJSObject, @@ -255,37 +255,14 @@ interface nsIScriptSecurityManager : nsI * Same as getSubjectPrincipal(), only faster. cx must *never* be * passed null, and it must be the context on the top of the * context stack. Does *not* reference count the returned * principal. */ [noscript,notxpcom] nsIPrincipal getCxSubjectPrincipal(in JSContextPtr cx); [noscript,notxpcom] nsIPrincipal getCxSubjectPrincipalAndFrame(in JSContextPtr cx, out JSStackFramePtr fp); - - /** - * If no scripted code is running "above" (or called from) fp, then - * instead of looking at cx->globalObject, we will return |principal|. - * This function only affects |cx|. If someone pushes another context onto - * the context stack, then it supersedes this call. - * NOTE: If |fp| is non-null popContextPrincipal must be called before fp - * has finished executing. - * - * @param cx The context to clamp. - * @param fp The frame pointer to clamp at. May be 'null'. - * @param principal The principal to clamp to. - */ - [noscript] void pushContextPrincipal(in JSContextPtr cx, - in JSStackFramePtr fp, - in nsIPrincipal principal); - - /** - * Removes a clamp set by pushContextPrincipal from cx. This must be - * called in a stack-like fashion (e.g., given two contexts |a| and |b|, - * it is not legal to do: push(a) push(b) pop(a)). - */ - [noscript] void popContextPrincipal(in JSContextPtr cx); }; %{C++ #define NS_SCRIPTSECURITYMANAGER_CONTRACTID "@mozilla.org/scriptsecuritymanager;1" #define NS_SCRIPTSECURITYMANAGER_CLASSNAME "scriptsecuritymanager" %}
--- a/caps/include/nsScriptSecurityManager.h +++ b/caps/include/nsScriptSecurityManager.h @@ -398,22 +398,21 @@ private: ObjectPrincipalFinder(JSObject *obj); // Decides, based on CSP, whether or not eval() and stuff can be executed. static JSBool ContentSecurityPolicyPermitsJSAction(JSContext *cx); // Returns null if a principal cannot be found; generally callers // should error out at that point. - static nsIPrincipal* - doGetObjectPrincipal(JSObject *obj + static nsIPrincipal* doGetObjectPrincipal(JSObject *obj); #ifdef DEBUG - , bool aAllowShortCircuit = true + static nsIPrincipal* + old_doGetObjectPrincipal(JSObject *obj, bool aAllowShortCircuit = true); #endif - ); // Returns null if a principal cannot be found. Note that rv can be NS_OK // when this happens -- this means that there was no JS running. nsIPrincipal* doGetSubjectPrincipal(nsresult* rv); nsresult CheckPropertyAccessImpl(PRUint32 aAction, @@ -549,40 +548,28 @@ private: nsresult InitPrincipals(PRUint32 prefCount, const char** prefNames); #ifdef DEBUG_CAPS_HACKER void PrintPolicyDB(); #endif - struct ContextPrincipal { - ContextPrincipal(ContextPrincipal *next, JSContext *cx, - JSStackFrame *fp, nsIPrincipal *principal) - : mNext(next), mCx(cx), mFp(fp), mPrincipal(principal) {} - - ContextPrincipal *mNext; - JSContext *mCx; - JSStackFrame *mFp; - nsCOMPtr<nsIPrincipal> mPrincipal; - }; - // JS strings we need to clean up on shutdown static jsid sEnabledID; inline void ScriptSecurityPrefChanged(); nsObjectHashtable* mOriginToPolicyMap; DomainPolicy* mDefaultPolicy; nsObjectHashtable* mCapabilities; nsCOMPtr<nsIPrincipal> mSystemPrincipal; nsCOMPtr<nsIPrincipal> mSystemCertificate; - ContextPrincipal *mContextPrincipals; nsInterfaceHashtable<PrincipalKey, nsIPrincipal> mPrincipals; bool mPrefInitialized; bool mIsJavaScriptEnabled; bool mIsWritingPrefs; bool mPolicyPrefsChanged; static bool sStrictFileOriginPolicy;
--- a/caps/src/nsScriptSecurityManager.cpp +++ b/caps/src/nsScriptSecurityManager.cpp @@ -158,54 +158,16 @@ GetPrincipalDomainOrigin(nsIPrincipal* a } static nsIScriptContext * GetScriptContext(JSContext *cx) { return GetScriptContextFromJSContext(cx); } -// Callbacks for the JS engine to use to push/pop context principals. -static JSBool -PushPrincipalCallback(JSContext *cx, JSPrincipals *principals) -{ - // We should already be in the compartment of the given principal. - MOZ_ASSERT(principals == - JS_GetCompartmentPrincipals((js::GetContextCompartment(cx)))); - - // Get the security manager. - nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); - if (!ssm) { - return true; - } - - // Push the principal. - JSStackFrame *fp = NULL; - nsresult rv = ssm->PushContextPrincipal(cx, JS_FrameIterator(cx, &fp), - nsJSPrincipals::get(principals)); - if (NS_FAILED(rv)) { - JS_ReportOutOfMemory(cx); - return false; - } - - return true; -} - -static JSBool -PopPrincipalCallback(JSContext *cx) -{ - nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); - if (ssm) { - ssm->PopContextPrincipal(cx); - } - - return true; -} - - inline void SetPendingException(JSContext *cx, const char *aMsg) { JSAutoRequest ar(cx); JS_ReportError(cx, "%s", aMsg); } inline void SetPendingException(JSContext *cx, const PRUnichar *aMsg) { @@ -400,44 +362,16 @@ nsScriptSecurityManager::GetCxSubjectPri nsresult rv = NS_ERROR_FAILURE; nsIPrincipal *principal = GetPrincipalAndFrame(cx, fp, &rv); if (NS_FAILED(rv)) return nsnull; return principal; } -NS_IMETHODIMP -nsScriptSecurityManager::PushContextPrincipal(JSContext *cx, - JSStackFrame *fp, - nsIPrincipal *principal) -{ - NS_ASSERTION(principal, "Must pass a non-null principal"); - - ContextPrincipal *cp = new ContextPrincipal(mContextPrincipals, cx, fp, - principal); - if (!cp) - return NS_ERROR_OUT_OF_MEMORY; - - mContextPrincipals = cp; - return NS_OK; -} - -NS_IMETHODIMP -nsScriptSecurityManager::PopContextPrincipal(JSContext *cx) -{ - NS_ASSERTION(mContextPrincipals->mCx == cx, "Mismatched push/pop"); - - ContextPrincipal *next = mContextPrincipals->mNext; - delete mContextPrincipals; - mContextPrincipals = next; - - return NS_OK; -} - //////////////////// // Policy Storage // //////////////////// // Table of security levels static bool DeleteCapability(nsHashKey *aKey, void *aData, void* closure) { @@ -2299,62 +2233,29 @@ nsScriptSecurityManager::GetPrincipalAnd { NS_PRECONDITION(rv, "Null out param"); //-- If there's no principal on the stack, look at the global object // and return the innermost frame for annotations. *rv = NS_OK; if (cx) { - JSStackFrame *target = nsnull; - nsIPrincipal *targetPrincipal = nsnull; - for (ContextPrincipal *cp = mContextPrincipals; cp; cp = cp->mNext) - { - if (cp->mCx == cx) - { - target = cp->mFp; - targetPrincipal = cp->mPrincipal; - break; - } - } - // Get principals from innermost JavaScript frame. JSStackFrame *fp = nsnull; // tell JS_FrameIterator to start at innermost for (fp = JS_FrameIterator(cx, &fp); fp; fp = JS_FrameIterator(cx, &fp)) { - if (fp == target) - break; nsIPrincipal* result = GetFramePrincipal(cx, fp, rv); if (result) { NS_ASSERTION(NS_SUCCEEDED(*rv), "Weird return"); *frameResult = fp; return result; } } - // If targetPrincipal is non-null, then it means that someone wants to - // clamp the principals on this context to this principal. Note that - // fp might not equal target here (fp might be null) because someone - // could have set aside the frame chain in the meantime. - if (targetPrincipal) - { - if (fp && fp == target) - { - *frameResult = fp; - } - else - { - JSStackFrame *inner = nsnull; - *frameResult = JS_FrameIterator(cx, &inner); - } - - return targetPrincipal; - } - nsIScriptContextPrincipal* scp = GetScriptContextPrincipalFromJSContext(cx); if (scp) { nsIScriptObjectPrincipal* globalData = scp->GetObjectPrincipal(); if (!globalData) { *rv = NS_ERROR_FAILURE; @@ -2375,47 +2276,67 @@ nsScriptSecurityManager::GetPrincipalAnd return nsnull; } nsIPrincipal* nsScriptSecurityManager::GetSubjectPrincipal(JSContext *cx, nsresult* rv) { - NS_PRECONDITION(rv, "Null out param"); - JSStackFrame *fp; - return GetPrincipalAndFrame(cx, &fp, rv); + *rv = NS_OK; + JSCompartment *compartment = js::GetContextCompartment(cx); + + // The context should always be in a compartment, either one it has entered + // or the one associated with its global. + MOZ_ASSERT(!!compartment); + + JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment); + return nsJSPrincipals::get(principals); } NS_IMETHODIMP nsScriptSecurityManager::GetObjectPrincipal(JSContext *aCx, JSObject *aObj, nsIPrincipal **result) { *result = doGetObjectPrincipal(aObj); if (!*result) return NS_ERROR_FAILURE; NS_ADDREF(*result); return NS_OK; } // static nsIPrincipal* -nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj +nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj) +{ + JSCompartment *compartment = js::GetObjectCompartment(aObj); + JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment); + nsIPrincipal *principal = nsJSPrincipals::get(principals); + + // We leave the old code in for a little while to make sure that pulling + // object principals directly off the compartment always gives an equivalent + // result (from a security perspective). #ifdef DEBUG - , bool aAllowShortCircuit + nsIPrincipal *old = old_doGetObjectPrincipal(aObj); + MOZ_ASSERT(NS_SUCCEEDED(CheckSameOriginPrincipal(principal, old))); #endif - ) + + return principal; +} + +#ifdef DEBUG +// static +nsIPrincipal* +nsScriptSecurityManager::old_doGetObjectPrincipal(JSObject *aObj, + bool aAllowShortCircuit) { NS_ASSERTION(aObj, "Bad call to doGetObjectPrincipal()!"); nsIPrincipal* result = nsnull; -#ifdef DEBUG JSObject* origObj = aObj; -#endif - js::Class *jsClass = js::GetObjectClass(aObj); // A common case seen in this code is that we enter this function // with aObj being a Function object, whose parent is a Call // object. Neither of those have object principals, so we can skip // those objects here before we enter the below loop. That way we // avoid wasting time checking properties of their classes etc in // the loop. @@ -2439,48 +2360,41 @@ nsScriptSecurityManager::doGetObjectPrin } do { // Note: jsClass is set before this loop, and also at the // *end* of this loop. if (IS_WRAPPER_CLASS(jsClass)) { result = sXPConnect->GetPrincipal(aObj, -#ifdef DEBUG - aAllowShortCircuit -#else - true -#endif - ); + aAllowShortCircuit); if (result) { break; } } else { nsISupports *priv; if (!(~jsClass->flags & (JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS))) { priv = (nsISupports *) js::GetObjectPrivate(aObj); } else if (IsDOMClass(jsClass) && DOMJSClass::FromJSClass(jsClass)->mDOMObjectIsISupports) { priv = UnwrapDOMObject<nsISupports>(aObj); } else { priv = nsnull; } -#ifdef DEBUG if (aAllowShortCircuit) { nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper = do_QueryInterface(priv); NS_ASSERTION(!xpcWrapper || !strcmp(jsClass->name, "XPCNativeWrapper"), "Uh, an nsIXPConnectWrappedNative with the " "wrong JSClass or getObjectOps hooks!"); } -#endif nsCOMPtr<nsIScriptObjectPrincipal> objPrin = do_QueryInterface(priv); if (objPrin) { result = objPrin->GetPrincipal(); if (result) { @@ -2492,63 +2406,47 @@ nsScriptSecurityManager::doGetObjectPrin aObj = js::GetObjectParentMaybeScope(aObj); if (!aObj) break; jsClass = js::GetObjectClass(aObj); } while (1); -#ifdef DEBUG if (aAllowShortCircuit) { - nsIPrincipal *principal = doGetObjectPrincipal(origObj, false); + nsIPrincipal *principal = old_doGetObjectPrincipal(origObj, false); // Because of inner window reuse, we can have objects with one principal // living in a scope with a different (but same-origin) principal. So // just check same-origin here. NS_ASSERTION(NS_SUCCEEDED(CheckSameOriginPrincipal(result, principal)), "Principal mismatch. Not good"); } -#endif return result; } +#endif /* DEBUG */ ///////////////// Capabilities API ///////////////////// NS_IMETHODIMP nsScriptSecurityManager::IsCapabilityEnabled(const char *capability, bool *result) { nsresult rv; JSStackFrame *fp = nsnull; JSContext *cx = GetCurrentJSContext(); fp = cx ? JS_FrameIterator(cx, &fp) : nsnull; - JSStackFrame *target = nsnull; - nsIPrincipal *targetPrincipal = nsnull; - for (ContextPrincipal *cp = mContextPrincipals; cp; cp = cp->mNext) - { - if (cp->mCx == cx) - { - target = cp->mFp; - targetPrincipal = cp->mPrincipal; - break; - } - } - if (!fp) { - // No script code on stack. If we had a principal pushed for this - // context and fp is null, then we use that principal. Otherwise, we - // don't have enough information and have to allow execution. - - *result = (targetPrincipal && !target) - ? (targetPrincipal == mSystemPrincipal) - : true; - + // No script code on stack. Allow access if and only if the subject + // principal is system. + nsresult ignored; + nsIPrincipal *subjectPrin = doGetSubjectPrincipal(&ignored); + *result = (!subjectPrin || subjectPrin == mSystemPrincipal); return NS_OK; } *result = false; nsIPrincipal* previousPrincipal = nsnull; do { nsIPrincipal* principal = GetFramePrincipal(cx, fp, &rv); @@ -2581,17 +2479,17 @@ nsScriptSecurityManager::IsCapabilityEna if (NS_FAILED(rv)) return rv; if (*result) return NS_OK; // Capabilities do not extend to calls into C/C++ and then back into // the JS engine via JS_EvaluateScript or similar APIs. if (JS_IsGlobalFrame(cx, fp)) break; - } while (fp != target && (fp = JS_FrameIterator(cx, &fp)) != nsnull); + } while ((fp = JS_FrameIterator(cx, &fp)) != nsnull); if (!previousPrincipal) { // No principals on the stack, all native code. Allow // execution if the subject principal is the system principal. return SubjectPrincipalIsSystem(result); } @@ -3065,17 +2963,16 @@ nsScriptSecurityManager::Observe(nsISupp ///////////////////////////////////////////// // Constructor, Destructor, Initialization // ///////////////////////////////////////////// nsScriptSecurityManager::nsScriptSecurityManager(void) : mOriginToPolicyMap(nsnull), mDefaultPolicy(nsnull), mCapabilities(nsnull), - mContextPrincipals(nsnull), mPrefInitialized(false), mIsJavaScriptEnabled(false), mIsWritingPrefs(false), mPolicyPrefsChanged(true) { MOZ_STATIC_ASSERT(sizeof(intptr_t) == sizeof(void*), "intptr_t and void* have different lengths on this platform. " "This may cause a security failure with the SecurityLevel union."); @@ -3126,19 +3023,17 @@ nsresult nsScriptSecurityManager::Init() rv = runtimeService->GetRuntime(&sRuntime); NS_ENSURE_SUCCESS(rv, rv); static const JSSecurityCallbacks securityCallbacks = { CheckObjectAccess, nsJSPrincipals::Subsume, ObjectPrincipalFinder, - ContentSecurityPolicyPermitsJSAction, - PushPrincipalCallback, - PopPrincipalCallback + ContentSecurityPolicyPermitsJSAction }; MOZ_ASSERT(!JS_GetSecurityCallbacks(sRuntime)); JS_SetSecurityCallbacks(sRuntime, &securityCallbacks); JS_InitDestroyPrincipalsCallback(sRuntime, nsJSPrincipals::Destroy); JS_SetTrustedPrincipals(sRuntime, system); @@ -3147,17 +3042,16 @@ nsresult nsScriptSecurityManager::Init() static nsRefPtr<nsScriptSecurityManager> gScriptSecMan; jsid nsScriptSecurityManager::sEnabledID = JSID_VOID; nsScriptSecurityManager::~nsScriptSecurityManager(void) { Preferences::RemoveObservers(this, kObservedPrefs); - NS_ASSERTION(!mContextPrincipals, "Leaking mContextPrincipals"); delete mOriginToPolicyMap; if(mDefaultPolicy) mDefaultPolicy->Drop(); delete mCapabilities; } void nsScriptSecurityManager::Shutdown()
--- a/content/base/src/nsFrameMessageManager.cpp +++ b/content/base/src/nsFrameMessageManager.cpp @@ -252,17 +252,17 @@ nsFrameMessageManager::SendAsyncMessage( } return SendAsyncMessageInternal(aMessageName, json); } NS_IMETHODIMP nsFrameMessageManager::Dump(const nsAString& aStr) { #ifdef ANDROID - __android_log_print(ANDROID_LOG_INFO, "Gecko", NS_ConvertUTF16toUTF8(aStr).get()); + __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", NS_ConvertUTF16toUTF8(aStr).get()); #endif fputs(NS_ConvertUTF16toUTF8(aStr).get(), stdout); fflush(stdout); return NS_OK; } NS_IMETHODIMP nsFrameMessageManager::PrivateNoteIntentionalCrash()
--- a/content/events/src/nsEventListenerManager.cpp +++ b/content/events/src/nsEventListenerManager.cpp @@ -208,24 +208,30 @@ nsEventListenerManager::AddEventListener mNoListenerForEvent = NS_EVENT_TYPE_NULL; mNoListenerForEventAtom = nsnull; ls = mListeners.AppendElement(); ls->mListener = aListener; ls->mEventType = aType; ls->mTypeAtom = aTypeAtom; - ls->mWrappedJS = false; ls->mFlags = aFlags; ls->mHandlerIsString = false; - nsCOMPtr<nsIXPConnectWrappedJS> wjs = do_QueryInterface(aListener); - if (wjs) { - ls->mWrappedJS = true; + // Detect the type of event listener. + nsCOMPtr<nsIXPConnectWrappedJS> wjs; + if (aFlags & NS_PRIV_EVENT_FLAG_SCRIPT) { + ls->mListenerType = eJSEventListener; + } else if ((wjs = do_QueryInterface(aListener))) { + ls->mListenerType = eWrappedJSListener; + } else { + ls->mListenerType = eNativeListener; } + + if (aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) { mMayHaveSystemGroupListeners = true; } if (aFlags & NS_EVENT_FLAG_CAPTURE) { mMayHaveCapturingListeners = true; } if (aType == NS_AFTERPAINT) { @@ -453,17 +459,18 @@ nsEventListenerManager::FindJSEventListe { // Run through the listeners for this type and see if a script // listener is registered nsListenerStruct *ls; PRUint32 count = mListeners.Length(); for (PRUint32 i = 0; i < count; ++i) { ls = &mListeners.ElementAt(i); if (EVENT_TYPE_EQUALS(ls, aEventType, aTypeAtom) && - ls->mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) { + (ls->mListenerType == eJSEventListener)) + { return ls; } } return nsnull; } nsresult nsEventListenerManager::SetJSEventListener(nsIScriptContext *aContext, @@ -791,17 +798,17 @@ nsEventListenerManager::HandleEventSubTy nsIDOMEventTarget* aCurrentTarget, PRUint32 aPhaseFlags, nsCxPusher* aPusher) { nsresult result = NS_OK; // If this is a script handler and we haven't yet // compiled the event handler itself - if ((aListenerStruct->mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) && + if ((aListenerStruct->mListenerType == eJSEventListener) && aListenerStruct->mHandlerIsString) { nsIJSEventListener *jslistener = aListenerStruct->GetJSListener(); result = CompileEventHandlerInternal(aListenerStruct, jslistener->GetEventContext() != aPusher->GetCurrentScriptContext(), nsnull); } @@ -858,23 +865,38 @@ nsEventListenerManager::HandleEventInter } if (*aDOMEvent) { if (!aEvent->currentTarget) { aEvent->currentTarget = aCurrentTarget->GetTargetForDOMEvent(); if (!aEvent->currentTarget) { break; } } + + // Push the appropriate context. Note that we explicitly don't push a + // context in the case that the listener is non-scripted, in which case + // it's the native code's responsibility to push a context if it ever + // enters JS. Ideally we'd do things this way for all scripted callbacks, + // but that would involve a lot of changes and context pushing is going + // away soon anyhow. + // + // NB: Since we're looping here, the no-RePush() case needs to actually be + // a Pop(), otherwise we might end up with whatever was pushed in a + // previous iteration. + if (ls->mListenerType == eNativeListener) { + aPusher->Pop(); + } else if (!aPusher->RePush(aCurrentTarget)) { + continue; + } + nsRefPtr<nsIDOMEventListener> kungFuDeathGrip = ls->mListener; - if (aPusher->RePush(aCurrentTarget)) { - if (NS_FAILED(HandleEventSubType(ls, ls->mListener, *aDOMEvent, - aCurrentTarget, aFlags, - aPusher))) { - aEvent->flags |= NS_EVENT_FLAG_EXCEPTION_THROWN; - } + if (NS_FAILED(HandleEventSubType(ls, ls->mListener, *aDOMEvent, + aCurrentTarget, aFlags, + aPusher))) { + aEvent->flags |= NS_EVENT_FLAG_EXCEPTION_THROWN; } } } } } aEvent->currentTarget = nsnull; @@ -987,17 +1009,17 @@ nsEventListenerManager::GetListenerInfo( PRUint32 count = mListeners.Length(); for (PRUint32 i = 0; i < count; ++i) { const nsListenerStruct& ls = mListeners.ElementAt(i); bool capturing = !!(ls.mFlags & NS_EVENT_FLAG_CAPTURE); bool systemGroup = !!(ls.mFlags & NS_EVENT_FLAG_SYSTEM_EVENT); bool allowsUntrusted = !!(ls.mFlags & NS_PRIV_EVENT_UNTRUSTED_PERMITTED); // If this is a script handler and we haven't yet // compiled the event handler itself go ahead and compile it - if ((ls.mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) && ls.mHandlerIsString) { + if ((ls.mListenerType == eJSEventListener) && ls.mHandlerIsString) { CompileEventHandlerInternal(const_cast<nsListenerStruct*>(&ls), true, nsnull); } const nsDependentSubstring& eventType = Substring(nsDependentAtomString(ls.mTypeAtom), 2); nsRefPtr<nsEventListenerInfo> info = new nsEventListenerInfo(eventType, ls.mListener, capturing, allowsUntrusted, systemGroup); @@ -1102,13 +1124,13 @@ nsEventListenerManager::UnmarkGrayJSList { PRUint32 count = mListeners.Length(); for (PRUint32 i = 0; i < count; ++i) { const nsListenerStruct& ls = mListeners.ElementAt(i); nsIJSEventListener* jsl = ls.GetJSListener(); if (jsl) { xpc_UnmarkGrayObject(jsl->GetHandler()); xpc_UnmarkGrayObject(jsl->GetEventScope()); - } else if (ls.mWrappedJS) { + } else if (ls.mListenerType == eWrappedJSListener) { xpc_TryUnmarkWrappedGrayObject(ls.mListener); } } }
--- a/content/events/src/nsEventListenerManager.h +++ b/content/events/src/nsEventListenerManager.h @@ -26,33 +26,40 @@ class nsIWidget; struct nsPoint; struct EventTypeData; class nsEventTargetChainItem; class nsPIDOMWindow; class nsCxPusher; class nsIEventListenerInfo; class nsIDocument; +typedef enum +{ + eNativeListener = 0, + eJSEventListener, + eWrappedJSListener +} nsListenerType; + struct nsListenerStruct { nsRefPtr<nsIDOMEventListener> mListener; PRUint32 mEventType; nsCOMPtr<nsIAtom> mTypeAtom; PRUint16 mFlags; + PRUint8 mListenerType; bool mHandlerIsString; - bool mWrappedJS; nsIJSEventListener* GetJSListener() const { - return (mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) ? + return (mListenerType == eJSEventListener) ? static_cast<nsIJSEventListener *>(mListener.get()) : nsnull; } ~nsListenerStruct() { - if ((mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) && mListener) { + if ((mListenerType == eJSEventListener) && mListener) { static_cast<nsIJSEventListener*>(mListener.get())->Disconnect(); } } }; /* * Event listener manager */
--- a/content/xbl/src/nsXBLPrototypeHandler.cpp +++ b/content/xbl/src/nsXBLPrototypeHandler.cpp @@ -275,16 +275,22 @@ nsXBLPrototypeHandler::ExecuteHandler(ns nsISupports *scriptTarget; if (winRoot) { scriptTarget = boundGlobal; } else { scriptTarget = aTarget; } + // We're about to create a new nsJSEventListener, which means that we're + // responsible for pushing the context of the event target. See the similar + // comment in nsEventManagerListener.cpp. + nsCxPusher pusher; + NS_ENSURE_STATE(pusher.Push(aTarget)); + rv = EnsureEventHandler(boundGlobal, boundContext, onEventAtom, handler); NS_ENSURE_SUCCESS(rv, rv); // Bind it to the bound element JSObject* scope = boundGlobal->GetGlobalJSObject(); nsScriptObjectHolder<JSObject> boundHandler(boundContext); rv = boundContext->BindCompiledEventHandler(scriptTarget, scope, handler.get(), boundHandler);
--- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -1194,56 +1194,55 @@ nsJSContext::EvaluateStringWithValue(con } return NS_OK; } xpc_UnmarkGrayObject(aScopeObject); nsAutoMicroTask mt; - // Safety first: get an object representing the script's principals, i.e., - // the entities who signed this script, or the fully-qualified-domain-name - // or "codebase" from which it was loaded. - nsCOMPtr<nsIPrincipal> principal = aPrincipal; - nsresult rv; - if (!aPrincipal) { - nsIScriptGlobalObject *global = GetGlobalObject(); - if (!global) - return NS_ERROR_FAILURE; - nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal = - do_QueryInterface(global, &rv); - if (NS_FAILED(rv)) - return NS_ERROR_FAILURE; - principal = objPrincipal->GetPrincipal(); - if (!principal) - return NS_ERROR_FAILURE; - } + // Ignore the principal that was passed in, and just assert that it matches + // the one we pull off the global. + nsCOMPtr<nsIPrincipal> principal; + nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal = do_QueryInterface(GetGlobalObject()); + if (!objPrincipal) + return NS_ERROR_FAILURE; + principal = objPrincipal->GetPrincipal(); + if (!principal) + return NS_ERROR_FAILURE; +#ifdef DEBUG + bool equal = false; + principal->Equals(aPrincipal, &equal); + MOZ_ASSERT(equal); + nsIPrincipal *scopeObjectPrincipal = + nsJSPrincipals::get(JS_GetCompartmentPrincipals(js::GetObjectCompartment(aScopeObject))); + equal = false; + principal->Equals(scopeObjectPrincipal, &equal); + MOZ_ASSERT(equal); +#endif bool ok = false; - rv = sSecurityManager->CanExecuteScripts(mContext, principal, &ok); + nsresult rv = sSecurityManager->CanExecuteScripts(mContext, principal, &ok); if (NS_FAILED(rv)) { return NS_ERROR_FAILURE; } // Push our JSContext on the current thread's context stack so JS called // from native code via XPConnect uses the right context. Do this whether // or not the SecurityManager said "ok", in order to simplify control flow // below where we pop before returning. nsCOMPtr<nsIJSContextStack> stack = do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv); if (NS_FAILED(rv) || NS_FAILED(stack->Push(mContext))) { return NS_ERROR_FAILURE; } jsval val; - rv = sSecurityManager->PushContextPrincipal(mContext, nsnull, principal); - NS_ENSURE_SUCCESS(rv, rv); - nsJSContext::TerminationFuncHolder holder(this); // SecurityManager said "ok", but don't compile if aVersion is unknown. // Since the caller is responsible for parsing the version strings, we just // check it isn't JSVERSION_UNKNOWN. if (ok && ((JSVersion)aVersion) != JSVERSION_UNKNOWN) { XPCAutoRequest ar(mContext); @@ -1289,18 +1288,16 @@ nsJSContext::EvaluateStringWithValue(con // tricky... } else { if (aIsUndefined) { *aIsUndefined = true; } } - sSecurityManager->PopContextPrincipal(mContext); - // Pop here, after JS_ValueToString and any other possible evaluation. if (NS_FAILED(stack->Pop(nsnull))) rv = NS_ERROR_FAILURE; // ScriptEvaluated needs to come after we pop the stack ScriptEvaluated(true); return rv; @@ -1396,29 +1393,35 @@ nsJSContext::EvaluateString(const nsAStr nsAutoMicroTask mt; if (!aScopeObject) { aScopeObject = JS_GetGlobalObject(mContext); } xpc_UnmarkGrayObject(aScopeObject); - // Safety first: get an object representing the script's principals, i.e., - // the entities who signed this script, or the fully-qualified-domain-name - // or "codebase" from which it was loaded. - nsCOMPtr<nsIPrincipal> principal = aPrincipal; - if (!aPrincipal) { - nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal = - do_QueryInterface(GetGlobalObject()); - if (!objPrincipal) - return NS_ERROR_FAILURE; - principal = objPrincipal->GetPrincipal(); - if (!principal) - return NS_ERROR_FAILURE; - } + // Ignore the principal that was passed in, and just assert that it matches + // the one we pull off the global. + nsCOMPtr<nsIPrincipal> principal; + nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal = do_QueryInterface(GetGlobalObject()); + if (!objPrincipal) + return NS_ERROR_FAILURE; + principal = objPrincipal->GetPrincipal(); + if (!principal) + return NS_ERROR_FAILURE; +#ifdef DEBUG + bool equal = false; + principal->Equals(aPrincipal, &equal); + MOZ_ASSERT(equal); + nsIPrincipal *scopeObjectPrincipal = + nsJSPrincipals::get(JS_GetCompartmentPrincipals(js::GetObjectCompartment(aScopeObject))); + equal = false; + principal->Equals(scopeObjectPrincipal, &equal); + MOZ_ASSERT(equal); +#endif bool ok = false; nsresult rv = sSecurityManager->CanExecuteScripts(mContext, principal, &ok); if (NS_FAILED(rv)) { return NS_ERROR_FAILURE; } @@ -1433,19 +1436,16 @@ nsJSContext::EvaluateString(const nsAStr } // The result of evaluation, used only if there were no errors. This need // not be a GC root currently, provided we run the GC only from the // operation callback or from ScriptEvaluated. jsval val = JSVAL_VOID; jsval* vp = aRetValue ? &val : NULL; - rv = sSecurityManager->PushContextPrincipal(mContext, nsnull, principal); - NS_ENSURE_SUCCESS(rv, rv); - nsJSContext::TerminationFuncHolder holder(this); ++mExecuteDepth; // SecurityManager said "ok", but don't compile if aVersion is unknown. // Since the caller is responsible for parsing the version strings, we just // check it isn't JSVERSION_UNKNOWN. if (ok && JSVersion(aVersion) != JSVERSION_UNKNOWN) { @@ -1487,18 +1487,16 @@ nsJSContext::EvaluateString(const nsAStr if (aRetValue) { aRetValue->Truncate(); } } --mExecuteDepth; - sSecurityManager->PopContextPrincipal(mContext); - // Pop here, after JS_ValueToString and any other possible evaluation. if (NS_FAILED(stack->Pop(nsnull))) rv = NS_ERROR_FAILURE; // ScriptEvaluated needs to come after we pop the stack ScriptEvaluated(true); return rv; @@ -1586,25 +1584,16 @@ nsJSContext::ExecuteScript(JSScript* aSc // called from JS calls back into JS via XPConnect. nsresult rv; nsCOMPtr<nsIJSContextStack> stack = do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv); if (NS_FAILED(rv) || NS_FAILED(stack->Push(mContext))) { return NS_ERROR_FAILURE; } - nsCOMPtr<nsIPrincipal> principal; - rv = sSecurityManager->GetObjectPrincipal(mContext, - JS_GetGlobalFromScript(aScriptObject), - getter_AddRefs(principal)); - NS_ENSURE_SUCCESS(rv, rv); - - rv = sSecurityManager->PushContextPrincipal(mContext, nsnull, principal); - NS_ENSURE_SUCCESS(rv, rv); - nsJSContext::TerminationFuncHolder holder(this); XPCAutoRequest ar(mContext); ++mExecuteDepth; // The result of evaluation, used only if there were no errors. This need // not be a GC root currently, provided we run the GC only from the // operation callback or from ScriptEvaluated. jsval val; @@ -1621,18 +1610,16 @@ nsJSContext::ExecuteScript(JSScript* aSc if (aRetValue) { aRetValue->Truncate(); } } --mExecuteDepth; - sSecurityManager->PopContextPrincipal(mContext); - // Pop here, after JS_ValueToString and any other possible evaluation. if (NS_FAILED(stack->Pop(nsnull))) rv = NS_ERROR_FAILURE; // ScriptEvaluated needs to come after we pop the stack ScriptEvaluated(true); return rv; @@ -1863,34 +1850,22 @@ nsJSContext::CallEventHandler(nsISupport nsJSContext::TerminationFuncHolder holder(this); if (NS_SUCCEEDED(rv)) { // Convert args to jsvals. PRUint32 argc = 0; jsval *argv = nsnull; JSObject *funobj = aHandler; - nsCOMPtr<nsIPrincipal> principal; - rv = sSecurityManager->GetObjectPrincipal(mContext, funobj, - getter_AddRefs(principal)); - NS_ENSURE_SUCCESS(rv, rv); - - JSStackFrame *currentfp = nsnull; - rv = sSecurityManager->PushContextPrincipal(mContext, - JS_FrameIterator(mContext, ¤tfp), - principal); - NS_ENSURE_SUCCESS(rv, rv); - jsval funval = OBJECT_TO_JSVAL(funobj); JSAutoEnterCompartment ac; js::ForceFrame ff(mContext, funobj); if (!ac.enter(mContext, funobj) || !ff.enter() || !JS_WrapObject(mContext, &target)) { ReportPendingException(); - sSecurityManager->PopContextPrincipal(mContext); return NS_ERROR_FAILURE; } Maybe<nsRootedJSValueArray> tempStorage; // Use |target| as the scope for wrapping the arguments, since aScope is // the safe scope in many cases, which isn't very useful. Wrapping aTarget // was OK because those typically have PreCreate methods that give them the @@ -1923,18 +1898,16 @@ nsJSContext::CallEventHandler(nsISupport rv = nsContentUtils::XPConnect()->JSToVariant(mContext, rval, arv); } // Tell XPConnect about any pending exceptions. This is needed // to avoid dropping JS exceptions in case we got here through // nested calls through XPConnect. if (NS_FAILED(rv)) ReportPendingException(); - - sSecurityManager->PopContextPrincipal(mContext); } pusher.Pop(); // ScriptEvaluated needs to come after we pop the stack ScriptEvaluated(true); return rv;
--- a/dom/indexedDB/ipc/IndexedDBParent.cpp +++ b/dom/indexedDB/ipc/IndexedDBParent.cpp @@ -372,17 +372,17 @@ IndexedDBDatabaseParent::HandleDatabaseE { MOZ_ASSERT(mDatabase); MOZ_ASSERT(!aType.EqualsLiteral(ERROR_EVT_STR), "Should never get error events in the parent process!"); nsresult rv; if (aType.EqualsLiteral(VERSIONCHANGE_EVT_STR)) { - JSContext* cx = nsContentUtils::GetCurrentJSContext(); + JSContext* cx = nsContentUtils::GetSafeJSContext(); NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE); nsCOMPtr<nsIIDBVersionChangeEvent> changeEvent = do_QueryInterface(aEvent); NS_ENSURE_TRUE(changeEvent, NS_ERROR_FAILURE); PRUint64 oldVersion; rv = changeEvent->GetOldVersion(&oldVersion); NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/src/json/nsJSON.cpp +++ b/dom/src/json/nsJSON.cpp @@ -172,42 +172,25 @@ NS_IMETHODIMP nsJSON::EncodeFromJSVal(JS::Value *value, JSContext *cx, nsAString &result) { result.Truncate(); // Begin a new request JSAutoRequest ar(cx); JSAutoEnterCompartment ac; - nsIScriptSecurityManager *ssm = nsnull; if (value->isObject()) { JSObject *obj = &value->toObject(); if (!ac.enter(cx, obj)) { return NS_ERROR_FAILURE; } - - nsCOMPtr<nsIPrincipal> principal; - ssm = nsContentUtils::GetSecurityManager(); - nsresult rv = ssm->GetObjectPrincipal(cx, obj, getter_AddRefs(principal)); - NS_ENSURE_SUCCESS(rv, rv); - - JSStackFrame *fp = nsnull; - rv = ssm->PushContextPrincipal(cx, JS_FrameIterator(cx, &fp), principal); - NS_ENSURE_SUCCESS(rv, rv); } nsJSONWriter writer; - JSBool ok = JS_Stringify(cx, value, NULL, JSVAL_NULL, - WriteCallback, &writer); - - if (ssm) { - ssm->PopContextPrincipal(cx); - } - - if (!ok) { + if (!JS_Stringify(cx, value, NULL, JSVAL_NULL, WriteCallback, &writer)) { return NS_ERROR_XPC_BAD_CONVERT_JS; } NS_ENSURE_TRUE(writer.DidWrite(), NS_ERROR_UNEXPECTED); writer.FlushBuffer(); result.Assign(writer.mOutputString); return NS_OK; }
--- a/dom/tests/mochitest/whatwg/postMessage_chrome_helper.html +++ b/dom/tests/mochitest/whatwg/postMessage_chrome_helper.html @@ -32,19 +32,17 @@ msg += " wrong-message(" + evt.data + ")"; respond(msg); } } function respond(msg) { - // ...so get privileges and test that this works with privileges - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - window.parent.postMessage(msg, "*"); + SpecialPowers.wrap(window).parent.postMessage(msg, "*"); } window.addEventListener("message", receiveMessage, false); </script> </head> <body> <h1 id="domain">example.org</h1> </body>
--- a/dom/tests/mochitest/whatwg/test_postMessage_chrome.html +++ b/dom/tests/mochitest/whatwg/test_postMessage_chrome.html @@ -88,20 +88,16 @@ function chromePathIsSet(evt) /************* * RECEIVERS * *************/ function receiveContent(evt) { is(evt.isTrusted, true, "should have sent a trusted event"); - is(evt.origin, "http://example.org", "content response event has wrong URI"); - is(evt.source, window.frames.contentDomain, - "wrong source for same-domain message!"); - finish(); } /************** * TEST SETUP * **************/
--- a/dom/wifi/WifiWorker.js +++ b/dom/wifi/WifiWorker.js @@ -713,19 +713,21 @@ var WifiManager = (function() { if (kv.length === 2) fields[kv[0]] = kv[1]; } if (!("state" in fields)) return true; fields.state = supplicantStatesMap[fields.state]; // The BSSID field is only valid in the ASSOCIATING and ASSOCIATED - // states. - if (fields.state === "ASSOCIATING" || fields.state == "ASSOCIATED") + // states, except when we "reauth", except this seems to depend on the + // driver, so simply check to make sure that we don't have a null BSSID. + if (fields.BSSID !== "00:00:00:00:00:00") manager.connectionInfo.bssid = fields.BSSID; + notifyStateChange(fields); return true; } if (eventData.indexOf("CTRL-EVENT-DRIVER-STATE") === 0) { var handlerName = driverEventMap[eventData]; if (handlerName) notify(handlerName); return true;
--- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -1228,17 +1228,17 @@ public: else { NS_WARNING("Failed to log script error!"); } } if (!logged) { NS_ConvertUTF16toUTF8 msg(aMessage); #ifdef ANDROID - __android_log_print(ANDROID_LOG_INFO, "Gecko", msg.get()); + __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", msg.get()); #endif fputs(msg.get(), stderr); fflush(stderr); } return true; } };
--- a/dom/workers/WorkerScope.cpp +++ b/dom/workers/WorkerScope.cpp @@ -537,17 +537,17 @@ private: } JSAutoByteString buffer(aCx, str); if (!buffer) { return false; } #ifdef ANDROID - __android_log_print(ANDROID_LOG_INFO, "Gecko", buffer.ptr()); + __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", buffer.ptr()); #endif fputs(buffer.ptr(), stdout); fflush(stdout); } return true; }
--- a/dom/workers/XMLHttpRequest.cpp +++ b/dom/workers/XMLHttpRequest.cpp @@ -1142,19 +1142,19 @@ public: mBody.swap(aBody); mClonedObjects.SwapElements(aClonedObjects); } nsresult MainThreadRun() { nsCOMPtr<nsIVariant> variant; - RuntimeService::AutoSafeJSContext cx; if (mBody.data()) { + RuntimeService::AutoSafeJSContext cx; nsIXPConnect* xpc = nsContentUtils::XPConnect(); NS_ASSERTION(xpc, "This should never be null!"); nsresult rv = NS_OK; JSStructuredCloneCallbacks* callbacks = mWorkerPrivate->IsChromeWorker() ? ChromeWorkerStructuredCloneCallbacks(true) :
--- a/gfx/thebes/gfxGDIFontList.cpp +++ b/gfx/thebes/gfxGDIFontList.cpp @@ -744,34 +744,37 @@ gfxGDIFontList::LookupLocalFont(const gf // lookup in name lookup tables, return null if not found if (!(lookup = mPostscriptNames.GetWeak(aFullname)) && !(lookup = mFullnames.GetWeak(aFullname))) { return nsnull; } - // create a new font entry with the proxy entry style characteristics - PRUint16 w = (aProxyEntry->mWeight == 0 ? 400 : aProxyEntry->mWeight); bool isCFF = false; // jtdfix -- need to determine this // use the face name from the lookup font entry, which will be the localized // face name which GDI mapping tables use (e.g. with the system locale set to // Dutch, a fullname of 'Arial Bold' will find a font entry with the face name // 'Arial Vet' which can be used as a key in GDI font lookups). - gfxFontEntry *fe = GDIFontEntry::CreateFontEntry(lookup->Name(), + GDIFontEntry *fe = GDIFontEntry::CreateFontEntry(lookup->Name(), gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/, - PRUint32(aProxyEntry->mItalic ? NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL), - w, aProxyEntry->mStretch, nsnull); + lookup->mItalic ? NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL, + lookup->mWeight, aProxyEntry->mStretch, nsnull); if (!fe) return nsnull; fe->mIsUserFont = true; fe->mIsLocalUserFont = true; + + // make the new font entry match the proxy entry style characteristics + fe->mWeight = (aProxyEntry->mWeight == 0 ? 400 : aProxyEntry->mWeight); + fe->mItalic = aProxyEntry->mItalic; + return fe; } void gfxGDIFontList::InitializeFontEmbeddingProcs() { static HMODULE fontlib = LoadLibraryW(L"t2embed.dll"); if (!fontlib) return;
--- a/ipc/testshell/XPCShellEnvironment.cpp +++ b/ipc/testshell/XPCShellEnvironment.cpp @@ -875,30 +875,16 @@ FullTrustSecMan::GetCxSubjectPrincipal(J NS_IMETHODIMP_(nsIPrincipal *) FullTrustSecMan::GetCxSubjectPrincipalAndFrame(JSContext *cx, JSStackFrame **fp) { *fp = nsnull; return mSystemPrincipal; } -NS_IMETHODIMP -FullTrustSecMan::PushContextPrincipal(JSContext *cx, - JSStackFrame *fp, - nsIPrincipal *principal) -{ - return NS_OK; -} - -NS_IMETHODIMP -FullTrustSecMan::PopContextPrincipal(JSContext *cx) -{ - return NS_OK; -} - NS_IMETHODIMP_(nsrefcnt) XPCShellDirProvider::AddRef() { return 2; } NS_IMETHODIMP_(nsrefcnt) XPCShellDirProvider::Release()
--- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1660,26 +1660,16 @@ typedef JSPrincipals * /* * Used to check if a CSP instance wants to disable eval() and friends. * See js_CheckCSPPermitsJSAction() in jsobj. */ typedef JSBool (* JSCSPEvalChecker)(JSContext *cx); /* - * Security callbacks for pushing and popping context principals. These are only - * temporarily necessary and will hopefully be gone again in a matter of weeks. - */ -typedef JSBool -(* JSPushContextPrincipalOp)(JSContext *cx, JSPrincipals *principals); - -typedef JSBool -(* JSPopContextPrincipalOp)(JSContext *cx); - -/* * Callback used to ask the embedding for the cross compartment wrapper handler * that implements the desired prolicy for this kind of object in the * destination compartment. */ typedef JSObject * (* JSWrapObjectCallback)(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent, unsigned flags); @@ -4338,18 +4328,16 @@ JS_HoldPrincipals(JSPrincipals *principa extern JS_PUBLIC_API(void) JS_DropPrincipals(JSRuntime *rt, JSPrincipals *principals); struct JSSecurityCallbacks { JSCheckAccessOp checkObjectAccess; JSSubsumePrincipalsOp subsumePrincipals; JSObjectPrincipalsFinder findObjectPrincipals; JSCSPEvalChecker contentSecurityPolicyAllows; - JSPushContextPrincipalOp pushContextPrincipal; - JSPopContextPrincipalOp popContextPrincipal; }; extern JS_PUBLIC_API(void) JS_SetSecurityCallbacks(JSRuntime *rt, const JSSecurityCallbacks *callbacks); extern JS_PUBLIC_API(const JSSecurityCallbacks *) JS_GetSecurityCallbacks(JSRuntime *rt);
--- a/js/src/jsclone.cpp +++ b/js/src/jsclone.cpp @@ -467,47 +467,16 @@ JSStructuredCloneWriter::startObject(JSO if (!objs.append(ObjectValue(*obj)) || !counts.append(count)) return false; checkStack(); /* Write the header for obj. */ return out.writePair(obj->isArray() ? SCTAG_ARRAY_OBJECT : SCTAG_OBJECT_OBJECT, 0); } -class AutoEnterCompartmentAndPushPrincipal : public JSAutoEnterCompartment -{ - public: - bool enter(JSContext *cx, JSObject *target) { - // First, enter the compartment. - if (!JSAutoEnterCompartment::enter(cx, target)) - return false; - - // We only need to push a principal if we changed compartments. - if (state != STATE_OTHER_COMPARTMENT) - return true; - - // Push. - const JSSecurityCallbacks *cb = cx->runtime->securityCallbacks; - if (cb->pushContextPrincipal) - return cb->pushContextPrincipal(cx, target->principals(cx)); - return true; - } - - ~AutoEnterCompartmentAndPushPrincipal() { - // Pop the principal if necessary. - if (state == STATE_OTHER_COMPARTMENT) { - AutoCompartment *ac = getAutoCompartment(); - const JSSecurityCallbacks *cb = ac->context->runtime->securityCallbacks; - if (cb->popContextPrincipal) - cb->popContextPrincipal(ac->context); - } - } -}; - - bool JSStructuredCloneWriter::startWrite(const Value &v) { assertSameCompartment(context(), v); if (v.isString()) { return writeString(SCTAG_STRING, v.toString()); } else if (v.isNumber()) { @@ -524,17 +493,17 @@ JSStructuredCloneWriter::startWrite(cons // The object might be a security wrapper. See if we can clone what's // behind it. If we can, unwrap the object. obj = UnwrapObjectChecked(context(), obj); if (!obj) return false; // If we unwrapped above, we'll need to enter the underlying compartment. // Let the AutoEnterCompartment do the right thing for us. - AutoEnterCompartmentAndPushPrincipal ac; + JSAutoEnterCompartment ac; if (!ac.enter(context(), obj)) return false; if (obj->isRegExp()) { RegExpObject &reobj = obj->asRegExp(); return out.writePair(SCTAG_REGEXP_OBJECT, reobj.getFlags()) && writeString(SCTAG_STRING, reobj.getSource()); } else if (obj->isDate()) { @@ -569,17 +538,17 @@ JSStructuredCloneWriter::write(const Val { if (!startWrite(v)) return false; while (!counts.empty()) { RootedObject obj(context(), &objs.back().toObject()); // The objects in |obj| can live in other compartments. - AutoEnterCompartmentAndPushPrincipal ac; + JSAutoEnterCompartment ac; if (!ac.enter(context(), obj)) return false; if (counts.back()) { counts.back()--; RootedId id(context(), ids.back()); ids.popBack(); checkStack();
--- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -908,27 +908,26 @@ inline InterpreterFrames::InterpreterFra inline InterpreterFrames::~InterpreterFrames() { context->runtime->interpreterFrames = older; } #if defined(DEBUG) && !defined(JS_THREADSAFE) && !defined(JSGC_ROOT_ANALYSIS) void -js::AssertValidPropertyCacheHit(JSContext *cx, - JSObject *start_, JSObject *found, - PropertyCacheEntry *entry) +js::AssertValidPropertyCacheHit(JSContext *cx, JSObject *start_, + JSObject *found, PropertyCacheEntry *entry) { jsbytecode *pc; - cx->stack.currentScript(&pc); + JSScript *script = cx->stack.currentScript(&pc); uint64_t sample = cx->runtime->gcNumber; PropertyCacheEntry savedEntry = *entry; - RootedPropertyName name(cx, GetNameFromBytecode(cx, pc, JSOp(*pc))); + RootedPropertyName name(cx, GetNameFromBytecode(cx, script, pc, JSOp(*pc))); RootedObject start(cx, start_); JSObject *obj, *pobj; JSProperty *prop; JSBool ok; if (JOF_OPMODE(*pc) == JOF_NAME) ok = FindProperty(cx, name, start, &obj, &pobj, &prop); @@ -2325,17 +2324,17 @@ BEGIN_CASE(JSOP_THIS) END_CASE(JSOP_THIS) BEGIN_CASE(JSOP_GETPROP) BEGIN_CASE(JSOP_GETXPROP) BEGIN_CASE(JSOP_LENGTH) BEGIN_CASE(JSOP_CALLPROP) { RootedValue rval(cx); - if (!GetPropertyOperation(cx, regs.pc, regs.sp[-1], rval.address())) + if (!GetPropertyOperation(cx, script, regs.pc, regs.sp[-1], rval.address())) goto error; TypeScript::Monitor(cx, script, regs.pc, rval.reference()); regs.sp[-1] = rval; assertSameCompartment(cx, regs.sp[-1]); } END_CASE(JSOP_GETPROP) @@ -2537,17 +2536,17 @@ END_CASE(JSOP_IMPLICITTHIS) BEGIN_CASE(JSOP_GETGNAME) BEGIN_CASE(JSOP_CALLGNAME) BEGIN_CASE(JSOP_NAME) BEGIN_CASE(JSOP_CALLNAME) { RootedValue &rval = rootValue0; - if (!NameOperation(cx, regs.pc, rval.address())) + if (!NameOperation(cx, script, regs.pc, rval.address())) goto error; PUSH_COPY(rval); TypeScript::Monitor(cx, script, regs.pc, rval); } END_CASE(JSOP_NAME) BEGIN_CASE(JSOP_UINT16)
--- a/js/src/jsinterpinlines.h +++ b/js/src/jsinterpinlines.h @@ -161,17 +161,18 @@ GetPropertyGenericMaybeCallXML(JSContext if (op == JSOP_CALLPROP && obj->isXML()) return js_GetXMLMethod(cx, obj, id, vp); #endif return obj->getGeneric(cx, id, vp); } inline bool -GetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, Value *vp) +GetPropertyOperation(JSContext *cx, JSScript *script, jsbytecode *pc, + const Value &lval, Value *vp) { JS_ASSERT(vp != &lval); JSOp op = JSOp(*pc); if (op == JSOP_LENGTH) { /* Optimize length accesses on strings, arrays, and arguments. */ if (lval.isString()) { @@ -315,17 +316,17 @@ SetPropertyOperation(JSContext *cx, jsby if (!obj->setGeneric(cx, id, rref.address(), strict)) return false; } return true; } inline bool -NameOperation(JSContext *cx, jsbytecode *pc, Value *vp) +NameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, Value *vp) { RootedObject obj(cx, cx->stack.currentScriptedScopeChain()); /* * Skip along the scope chain to the enclosing global object. This is * used for GNAME opcodes where the bytecode emitter has determined a * name access must be on the global. It also insulates us from bugs * in the emitter: type inference will assume that GNAME opcodes are
--- a/js/src/jsopcodeinlines.h +++ b/js/src/jsopcodeinlines.h @@ -6,27 +6,26 @@ #include "jsautooplen.h" #include "frontend/BytecodeEmitter.h" namespace js { static inline PropertyName * -GetNameFromBytecode(JSContext *cx, jsbytecode *pc, JSOp op) +GetNameFromBytecode(JSContext *cx, JSScript *script, jsbytecode *pc, JSOp op) { if (op == JSOP_LENGTH) return cx->runtime->atomState.lengthAtom; // The method JIT's implementation of instanceof contains an internal lookup // of the prototype property. if (op == JSOP_INSTANCEOF) return cx->runtime->atomState.classPrototypeAtom; - JSScript *script = cx->stack.currentScriptWithDiagnostics(); PropertyName *name; GET_NAME_FROM_BYTECODE(script, pc, 0, name); return name; } class BytecodeRange { public: BytecodeRange(JSScript *script)
--- a/js/src/jspropertycache.cpp +++ b/js/src/jspropertycache.cpp @@ -117,32 +117,30 @@ PropertyCache::fill(JSContext *cx, JSObj return entry; } PropertyName * PropertyCache::fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp, JSObject **pobjp, PropertyCacheEntry *entry) { JSObject *obj, *pobj, *tmp; -#ifdef DEBUG JSScript *script = cx->stack.currentScript(); -#endif JS_ASSERT(this == &JS_PROPERTY_CACHE(cx)); JS_ASSERT(uint32_t(pc - script->code) < script->length); JSOp op = JSOp(*pc); const JSCodeSpec &cs = js_CodeSpec[op]; obj = *objp; if (entry->kpc != pc) { PCMETER(kpcmisses++); - PropertyName *name = GetNameFromBytecode(cx, pc, op); + PropertyName *name = GetNameFromBytecode(cx, script, pc, op); #ifdef DEBUG_notme JSAutoByteString printable; fprintf(stderr, "id miss for %s from %s:%u" " (pc %u, kpc %u, kshape %p, shape %p)\n", js_AtomToPrintableString(cx, name, &printable), script->filename, js_PCToLineNumber(cx, script, pc), @@ -155,17 +153,17 @@ PropertyCache::fullTest(JSContext *cx, j JS_FALSE, stderr); #endif return name; } if (entry->kshape != obj->lastProperty()) { PCMETER(kshapemisses++); - return GetNameFromBytecode(cx, pc, op); + return GetNameFromBytecode(cx, script, pc, op); } /* * PropertyCache::test handles only the direct and immediate-prototype hit * cases. All others go here. */ pobj = obj; @@ -188,25 +186,25 @@ PropertyCache::fullTest(JSContext *cx, j if (!tmp || !tmp->isNative()) break; pobj = tmp; protoIndex--; } if (pobj->lastProperty() == entry->pshape) { #ifdef DEBUG - PropertyName *name = GetNameFromBytecode(cx, pc, op); + PropertyName *name = GetNameFromBytecode(cx, script, pc, op); JS_ASSERT(pobj->nativeContains(cx, NameToId(name))); #endif *pobjp = pobj; return NULL; } PCMETER(vcapmisses++); - return GetNameFromBytecode(cx, pc, op); + return GetNameFromBytecode(cx, script, pc, op); } #ifdef DEBUG void PropertyCache::assertEmpty() { JS_ASSERT(empty); for (unsigned i = 0; i < SIZE; i++) {
--- a/js/src/methodjit/PolyIC.cpp +++ b/js/src/methodjit/PolyIC.cpp @@ -1919,17 +1919,17 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic if (!monitor.recompiled() && pic->shouldUpdate(f.cx)) { GetPropCompiler cc(f, script, obj, *pic, name, stub); if (!cc.update()) THROW(); } Value v; if (cached) { - if (!GetPropertyOperation(f.cx, f.pc(), f.regs.sp[-1], &v)) + if (!GetPropertyOperation(f.cx, f.script(), f.pc(), f.regs.sp[-1], &v)) THROW(); } else { if (!obj->getProperty(f.cx, name, &v)) THROW(); } f.regs.sp[-1] = v; }
--- a/js/src/methodjit/StubCalls.cpp +++ b/js/src/methodjit/StubCalls.cpp @@ -93,17 +93,17 @@ stubs::SetGlobalName(VMFrame &f, Propert template void JS_FASTCALL stubs::SetGlobalName<true>(VMFrame &f, PropertyName *name); template void JS_FASTCALL stubs::SetGlobalName<false>(VMFrame &f, PropertyName *name); void JS_FASTCALL stubs::Name(VMFrame &f) { Value rval; - if (!NameOperation(f.cx, f.pc(), &rval)) + if (!NameOperation(f.cx, f.script(), f.pc(), &rval)) THROW(); f.regs.sp[0] = rval; } void JS_FASTCALL stubs::GetElem(VMFrame &f) { Value &lref = f.regs.sp[-2]; @@ -975,17 +975,17 @@ stubs::Lambda(VMFrame &f, JSFunction *fu void JS_FASTCALL stubs::GetProp(VMFrame &f, PropertyName *name) { JSContext *cx = f.cx; FrameRegs ®s = f.regs; Value rval; - if (!GetPropertyOperation(cx, f.pc(), f.regs.sp[-1], &rval)) + if (!GetPropertyOperation(cx, f.script(), f.pc(), f.regs.sp[-1], &rval)) THROW(); regs.sp[-1] = rval; } void JS_FASTCALL stubs::GetPropNoCache(VMFrame &f, PropertyName *name) {
--- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -552,55 +552,16 @@ ContextStack::currentScript(jsbytecode * if (script->compartment() != cx_->compartment) return NULL; if (ppc) *ppc = fp->pcQuadratic(*this); return script; } -inline JSScript * -ContextStack::currentScriptWithDiagnostics(jsbytecode **ppc) const -{ - if (ppc) - *ppc = NULL; - - FrameRegs *regs = maybeRegs(); - StackFrame *fp = regs ? regs->fp() : NULL; - while (fp && fp->isDummyFrame()) - fp = fp->prev(); - if (!fp) - *(int *) 0x10 = 0; - -#ifdef JS_METHODJIT - mjit::CallSite *inlined = regs->inlined(); - if (inlined) { - mjit::JITChunk *chunk = fp->jit()->chunk(regs->pc); - JS_ASSERT(inlined->inlineIndex < chunk->nInlineFrames); - mjit::InlineFrame *frame = &chunk->inlineFrames()[inlined->inlineIndex]; - JSScript *script = frame->fun->script(); - if (script->compartment() != cx_->compartment) - *(int *) 0x20 = 0; - if (ppc) - *ppc = script->code + inlined->pcOffset; - return script; - } -#endif - - JSScript *script = fp->script(); - if (script->compartment() != cx_->compartment) - *(int *) 0x30 = 0; - - if (ppc) - *ppc = fp->pcQuadratic(*this); - if (!script) - *(int *) 0x40 = 0; - return script; -} - inline HandleObject ContextStack::currentScriptedScopeChain() const { return fp()->scopeChain(); } } /* namespace js */ #endif /* Stack_inl_h__ */
--- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -1655,17 +1655,16 @@ class ContextStack InitialFrameFlags initial, Value **stackLimit); void popInlineFrame(FrameRegs ®s); /* Pop a partially-pushed frame after hitting the limit before throwing. */ void popFrameAfterOverflow(); /* Get the topmost script and optional pc on the stack. */ inline JSScript *currentScript(jsbytecode **pc = NULL) const; - inline JSScript *currentScriptWithDiagnostics(jsbytecode **pc = NULL) const; /* Get the scope chain for the topmost scripted call on the stack. */ inline HandleObject currentScriptedScopeChain() const; /* * Called by the methodjit for an arity mismatch. Arity mismatch can be * hot, so getFixupFrame avoids doing call setup performed by jit code when * FixupArity returns.
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp +++ b/js/xpconnect/loader/mozJSComponentLoader.cpp @@ -171,17 +171,17 @@ Dump(JSContext *cx, unsigned argc, jsval size_t length; const jschar *chars = JS_GetStringCharsAndLength(cx, str, &length); if (!chars) return false; NS_ConvertUTF16toUTF8 utf8str(reinterpret_cast<const PRUnichar*>(chars)); #ifdef ANDROID - __android_log_print(ANDROID_LOG_INFO, "Gecko", utf8str.get()); + __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", utf8str.get()); #endif fputs(utf8str.get(), stdout); fflush(stdout); return true; } static JSBool Debug(JSContext *cx, unsigned argc, jsval *vp)
--- a/js/xpconnect/shell/xpcshell.cpp +++ b/js/xpconnect/shell/xpcshell.cpp @@ -418,17 +418,17 @@ Dump(JSContext *cx, unsigned argc, jsval if (!str) return false; JSAutoByteString bytes(cx, str); if (!bytes) return false; #ifdef ANDROID - __android_log_print(ANDROID_LOG_INFO, "Gecko", bytes.ptr()); + __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", bytes.ptr()); #endif fputs(bytes.ptr(), gOutFile); fflush(gOutFile); return true; } static JSBool Load(JSContext *cx, unsigned argc, jsval *vp) @@ -1376,30 +1376,16 @@ FullTrustSecMan::CanExecuteScripts(JSCon /* [noscript] nsIPrincipal getSubjectPrincipal (); */ NS_IMETHODIMP FullTrustSecMan::GetSubjectPrincipal(nsIPrincipal **_retval) { NS_IF_ADDREF(*_retval = mSystemPrincipal); return *_retval ? NS_OK : NS_ERROR_FAILURE; } -/* [noscript] void pushContextPrincipal (in JSContextPtr cx, in JSStackFramePtr fp, in nsIPrincipal principal); */ -NS_IMETHODIMP -FullTrustSecMan::PushContextPrincipal(JSContext * cx, JSStackFrame * fp, nsIPrincipal *principal) -{ - return NS_OK; -} - -/* [noscript] void popContextPrincipal (in JSContextPtr cx); */ -NS_IMETHODIMP -FullTrustSecMan::PopContextPrincipal(JSContext * cx) -{ - return NS_OK; -} - /* [noscript] nsIPrincipal getSystemPrincipal (); */ NS_IMETHODIMP FullTrustSecMan::GetSystemPrincipal(nsIPrincipal **_retval) { NS_IF_ADDREF(*_retval = mSystemPrincipal); return *_retval ? NS_OK : NS_ERROR_FAILURE; }
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp +++ b/js/xpconnect/src/XPCWrappedJSClass.cpp @@ -1107,27 +1107,16 @@ nsXPCWrappedJSClass::CheckForException(X // see if JS code signaled failure result without throwing exception if (NS_FAILED(pending_result)) { return pending_result; } } return NS_ERROR_FAILURE; } -class ContextPrincipalGuard -{ - nsIScriptSecurityManager *ssm; - XPCCallContext &ccx; - public: - ContextPrincipalGuard(XPCCallContext &ccx) - : ssm(nsnull), ccx(ccx) {} - void principalPushed(nsIScriptSecurityManager *ssm) { this->ssm = ssm; } - ~ContextPrincipalGuard() { if (ssm) ssm->PopContextPrincipal(ccx); } -}; - NS_IMETHODIMP nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex, const XPTMethodDescriptor* info, nsXPTCMiniVariant* nativeParams) { jsval* sp = nsnull; jsval* argv = nsnull; uint8_t i; @@ -1161,53 +1150,29 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWra JSAutoEnterCompartment ac; if (!ac.enter(cx, obj)) return NS_ERROR_FAILURE; ccx.SetScopeForNewJSObjects(obj); JS::AutoValueVector args(cx); AutoScriptEvaluate scriptEval(cx); - ContextPrincipalGuard principalGuard(ccx); // XXX ASSUMES that retval is last arg. The xpidl compiler ensures this. uint8_t paramCount = info->num_args; uint8_t argc = paramCount - (paramCount && XPT_PD_IS_RETVAL(info->params[paramCount-1].flags) ? 1 : 0); if (!scriptEval.StartEvaluating(obj, xpcWrappedJSErrorReporter)) goto pre_call_clean_up; xpcc->SetPendingResult(pending_result); xpcc->SetException(nsnull); XPCJSRuntime::Get()->SetPendingException(nsnull); - // This scoping is necessary due to the gotos here. Ugh. - { - // TODO Remove me in favor of security wrappers. - nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); - if (ssm) { - nsIPrincipal *objPrincipal = - xpc::AccessCheck::getPrincipal(js::GetObjectCompartment(obj)); - if (objPrincipal) { - JSStackFrame* fp = nsnull; - nsresult rv = - ssm->PushContextPrincipal(ccx, JS_FrameIterator(ccx, &fp), - objPrincipal); - if (NS_FAILED(rv)) { - JS_ReportOutOfMemory(ccx); - retval = NS_ERROR_OUT_OF_MEMORY; - goto pre_call_clean_up; - } - - principalGuard.principalPushed(ssm); - } - } - } - // We use js_Invoke so that the gcthings we use as args will be rooted by // the engine as we do conversions and prepare to do the function call. // setup stack // if this isn't a function call then we don't need to push extra stuff if (!(XPT_MD_IS_SETTER(info->flags) || XPT_MD_IS_GETTER(info->flags))) { // We get fval before allocating the stack to avoid gc badness that can
--- a/js/xpconnect/wrappers/CrossOriginWrapper.cpp +++ b/js/xpconnect/wrappers/CrossOriginWrapper.cpp @@ -10,25 +10,17 @@ #include "XPCWrapper.h" #include "CrossOriginWrapper.h" #include "AccessCheck.h" #include "WrapperFactory.h" namespace xpc { -NoWaiverWrapper::NoWaiverWrapper(unsigned flags) : js::CrossCompartmentWrapper(flags) -{ -} - -NoWaiverWrapper::~NoWaiverWrapper() -{ -} - -CrossOriginWrapper::CrossOriginWrapper(unsigned flags) : NoWaiverWrapper(flags) +CrossOriginWrapper::CrossOriginWrapper(unsigned flags) : js::CrossCompartmentWrapper(flags) { } CrossOriginWrapper::~CrossOriginWrapper() { } bool @@ -65,41 +57,9 @@ CrossOriginWrapper::call(JSContext *cx, bool CrossOriginWrapper::construct(JSContext *cx, JSObject *wrapper, unsigned argc, js::Value *argv, js::Value *rval) { return CrossCompartmentWrapper::construct(cx, wrapper, argc, argv, rval) && WrapperFactory::WaiveXrayAndWrap(cx, rval); } -bool -NoWaiverWrapper::enter(JSContext *cx, JSObject *wrapper, jsid id, Action act, bool *bp) -{ - *bp = true; // always allowed - nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); - if (!ssm) { - return true; - } - - // Note: By the time enter is called here, CrossCompartmentWrapper has - // already pushed the fake stack frame onto cx. Because of this, the frame - // that we're clamping is the one that we want (the one in our compartment). - JSStackFrame *fp = NULL; - nsIPrincipal *principal = GetCompartmentPrincipal(js::GetObjectCompartment(wrappedObject(wrapper))); - nsresult rv = ssm->PushContextPrincipal(cx, JS_FrameIterator(cx, &fp), principal); - if (NS_FAILED(rv)) { - NS_WARNING("Not allowing call because we're out of memory"); - JS_ReportOutOfMemory(cx); - return false; - } - return true; } - -void -NoWaiverWrapper::leave(JSContext *cx, JSObject *wrapper) -{ - nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); - if (ssm) { - ssm->PopContextPrincipal(cx); - } -} - -}
--- a/js/xpconnect/wrappers/CrossOriginWrapper.h +++ b/js/xpconnect/wrappers/CrossOriginWrapper.h @@ -10,28 +10,17 @@ #include "mozilla/Attributes.h" #include "jsapi.h" #include "jswrapper.h" namespace xpc { -class NoWaiverWrapper : public js::CrossCompartmentWrapper { - public: - NoWaiverWrapper(unsigned flags); - virtual ~NoWaiverWrapper(); - - virtual bool enter(JSContext *cx, JSObject *wrapper, jsid id, Action act, bool *bp) MOZ_OVERRIDE; - virtual void leave(JSContext *cx, JSObject *wrapper) MOZ_OVERRIDE; - - static NoWaiverWrapper singleton; -}; - -class CrossOriginWrapper : public NoWaiverWrapper { +class CrossOriginWrapper : public js::CrossCompartmentWrapper { public: CrossOriginWrapper(unsigned flags); virtual ~CrossOriginWrapper(); virtual bool getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, bool set, js::PropertyDescriptor *desc) MOZ_OVERRIDE; virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, bool set, js::PropertyDescriptor *desc) MOZ_OVERRIDE;
--- a/js/xpconnect/wrappers/WrapperFactory.cpp +++ b/js/xpconnect/wrappers/WrapperFactory.cpp @@ -26,23 +26,16 @@ namespace xpc { // .wrappedJSObject, we want it to cross the membrane into the // chrome compartment without automatically being wrapped into an // X-ray wrapper. We achieve this by wrapping it into a special // transparent wrapper in the origin (non-chrome) compartment. When // an object with that special wrapper applied crosses into chrome, // we know to not apply an X-ray wrapper. DirectWrapper WaiveXrayWrapperWrapper(WrapperFactory::WAIVE_XRAY_WRAPPER_FLAG); -// Objects that haven't been explicitly waived, but have been exposed -// to chrome don't want a CrossOriginWrapper, since that deeply-waives -// but need the transparent behavior of a CrossOriginWrapper. The -// NoWaiverWrapper is like a CrossOriginWrapper that can also hand out -// XrayWrappers as return values. -NoWaiverWrapper NoWaiverWrapper::singleton(0); - // When objects for which we waived the X-ray wrapper cross into // chrome, we wrap them into a special cross-compartment wrapper // that transitively extends the waiver to all properties we get // off it. CrossOriginWrapper CrossOriginWrapper::singleton(0); static JSObject * GetCurrentOuter(JSContext *cx, JSObject *obj) @@ -336,17 +329,17 @@ WrapperFactory::Rewrap(JSContext *cx, JS wrapper = &XrayDOM::singleton; } else if (type == XrayForDOMProxyObject) { wrapper = &XrayProxy::singleton; } else if (type == XrayForWrappedNative) { typedef XrayWrapper<CrossCompartmentWrapper> Xray; usingXray = true; wrapper = &Xray::singleton; } else { - wrapper = &NoWaiverWrapper::singleton; + wrapper = &CrossCompartmentWrapper::singleton; } } } } else if (AccessCheck::isChrome(origin)) { JSFunction *fun = JS_GetObjectFunction(obj); if (fun) { if (JS_IsBuiltinEvalFunction(fun) || JS_IsBuiltinFunctionConstructor(fun)) { JS_ReportError(cx, "Not allowed to access chrome eval or Function from content");
--- a/layout/base/nsDisplayItemTypes.h +++ b/layout/base/nsDisplayItemTypes.h @@ -51,17 +51,17 @@ enum Type { TYPE_PRINT_PLUGIN, TYPE_REMOTE, TYPE_REMOTE_SHADOW, TYPE_SCROLL_LAYER, TYPE_SCROLL_INFO_LAYER, TYPE_SELECTION_OVERLAY, TYPE_SOLID_COLOR, TYPE_SVG_EFFECTS, - TYPE_SVG_EVENT_RECEIVER, + TYPE_SVG_OUTER_SVG, TYPE_TABLE_CELL_BACKGROUND, TYPE_TABLE_CELL_SELECTION, TYPE_TABLE_ROW_BACKGROUND, TYPE_TABLE_ROW_GROUP_BACKGROUND, TYPE_TABLE_BORDER_BACKGROUND, TYPE_TEXT, TYPE_TEXT_DECORATION, TYPE_TEXT_OVERFLOW,
--- a/layout/reftests/font-face/local-1-ref.html +++ b/layout/reftests/font-face/local-1-ref.html @@ -2,17 +2,18 @@ <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta http-equiv="Content-Style-Type" content="text/css"> <title>test src: local() reference</title> <style type="text/css"> body { font-family: Nimbus Sans L, Helvetica, Bitstream Vera Sans, - Arial, Liberation Sans, SwissA, serif; + Arial, Liberation Sans, SwissA, + Droid Sans, Roboto, serif; } </style> </head> <body> <p style="font-weight: normal;"> The quick brown fox jumped over the lazy dog </p> <p style="font-weight: bold;">
--- a/layout/reftests/font-face/local-1.html +++ b/layout/reftests/font-face/local-1.html @@ -29,25 +29,27 @@ obvious. --> <style type="text/css"> @font-face { font-family: "Local"; src: local(Nimbus Sans L), local(NimbusSansL-Regu), local(Helvetica), local(Bitstream Vera Sans), - local(Arial), local(Liberation Sans), local(SwissA); + local(Arial), local(Liberation Sans), local(SwissA), + local(Droid Sans), local(Roboto); font-weight: 100; } @font-face { font-family: "Local"; src: local(Nimbus Sans L Bold), local(NimbusSansL-Bold), local(Helvetica Bold), local(Helvetica-Bold), local(Bitstream Vera Sans Bold), - local(Arial Bold), local(Liberation Sans Bold), local(SwissA Bold); + local(Arial Bold), local(Liberation Sans Bold), local(SwissA Bold), + local(Droid Sans Bold), local(Roboto Bold); font-weight: normal; } body { font-family: Local, serif } </style> </head> <body> <p style="font-weight: 100"> The quick brown fox jumped over the lazy dog
new file mode 100644 --- /dev/null +++ b/layout/reftests/font-face/local-styled-1-ref.html @@ -0,0 +1,33 @@ +<!DOCTYPE html> +<html> +<head> +<style type="text/css"> +@font-face { + font-family: test; + src: local(Nimbus Sans L), local(NimbusSansL-Regu), + local(Helvetica), local(Bitstream Vera Sans), + local(Arial), local(Liberation Sans), local(SwissA), + local(Droid Sans), local(Roboto); +} +div { + font-family: test, serif; + margin: 10px; +} +</style> +</head> +<body> +<div style="font-family:serif"> +This serif font should NOT be used below. +</div> +<hr> +<div> +These three lines should all use the same font face. +</div> +<div> +This line should NOT be bold. +</div> +<div> +This line should NOT be italic. +</div> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/layout/reftests/font-face/local-styled-1.html @@ -0,0 +1,49 @@ +<!DOCTYPE html> +<html> +<head> +<style type="text/css"> +@font-face { + font-family: test; + src: local(Nimbus Sans L), local(NimbusSansL-Regu), + local(Helvetica), local(Bitstream Vera Sans), + local(Arial), local(Liberation Sans), local(SwissA), + local(Droid Sans), local(Roboto); +} +@font-face { + font-family: test; + font-style: italic; + src: local(Nimbus Sans L), local(NimbusSansL-Regu), + local(Helvetica), local(Bitstream Vera Sans), + local(Arial), local(Liberation Sans), local(SwissA), + local(Droid Sans), local(Roboto); +} +@font-face { + font-family: test; + font-weight: bold; + src: local(Nimbus Sans L), local(NimbusSansL-Regu), + local(Helvetica), local(Bitstream Vera Sans), + local(Arial), local(Liberation Sans), local(SwissA), + local(Droid Sans), local(Roboto); +} +div { + font-family: test, serif; + margin: 10px; +} +</style> +</head> +<body> +<div style="font-family:serif"> +This serif font should NOT be used below. +</div> +<hr> +<div> +These three lines should all use the same font face. +</div> +<div> +<b>This line should NOT be bold.</b> +</div> +<div> +<i>This line should NOT be italic.</i> +</div> +</body> +</html>
--- a/layout/reftests/font-face/reftest.list +++ b/layout/reftests/font-face/reftest.list @@ -89,17 +89,20 @@ HTTP(..) == ahem-metrics-1.html ahem-met HTTP(..) == ex-unit-1.html ex-unit-1-ref.html HTTP(..) == ex-unit-1-dynamic.html ex-unit-1-ref.html # bug 493976 - for some reason the Arabic tests below cause Tinderbox timeouts # Arabic support requires AAT fonts under Mac OS, OpenType otherwise # random-if(!cocoaWidget) HTTP(..) == src-format-arabic.html src-format-arabic-aat-ref.html # random-if(cocoaWidget) HTTP(..) == src-format-arabic.html src-format-arabic-ot-ref.html +# bug 769194 - src:local() completely broken on android fails-if(Android) == local-1.html local-1-ref.html +fails-if(Android) == local-styled-1.html local-styled-1-ref.html + HTTP(..) == synthetic-weight-style.html synthetic-weight-style-ref.html HTTP(..) == synthetic-variations.html synthetic-variations-ref.html # Leak test HTTP(..) load 486974-1.html # compare fonts with and without bad head checksum HTTP(..) == load-badchecksum.html load-badchecksum-ref.html
--- a/layout/reftests/position-dynamic-changes/relative/reftest.list +++ b/layout/reftests/position-dynamic-changes/relative/reftest.list @@ -1,4 +1,4 @@ -fuzzy-if(d2d,85,20) == move-right-bottom.html move-right-bottom-ref.html # Bug 742176 +random-if(cocoaWidget) fuzzy-if(d2d,85,20) == move-right-bottom.html move-right-bottom-ref.html # Bug 742176 random-if(cocoaWidget) fuzzy-if(d2d,85,20) == move-top-left.html move-top-left-ref.html # Bug 688545, bug 742176 -fuzzy-if(d2d,85,20) == move-right-bottom-table.html move-right-bottom-table-ref.html # Bug 742176 +random-if(cocoaWidget) fuzzy-if(d2d,85,20) == move-right-bottom-table.html move-right-bottom-table-ref.html # Bug 742176 random-if(cocoaWidget) fuzzy-if(d2d,85,20) == move-top-left-table.html move-top-left-table-ref.html # Bug 688545, bug 742176
new file mode 100644 --- /dev/null +++ b/layout/reftests/svg/svg-integration/mask-transformed-html-01.xhtml @@ -0,0 +1,42 @@ +<!-- + Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ +--> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <title>Test SVG masking of transformed HTML elements</title> + <!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=769103 --> + <style type="text/css"> + +* { margin: 0; border: 0; padding: 0;} + +div { + position: absolute; + left: 1px; + top: 1px; + width: 3px; + height: 3px; + -moz-transform: scale(100,100); + -moz-transform-origin: 0 0; +} + + </style> +</head> +<body bgcolor="lime"> + + <svg xmlns="http://www.w3.org/2000/svg" width="300" height="300" + style="display:block; position:absolute;"> + <mask id="mask1" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <circle cx="0.5" cy="0.5" r="0.48" fill="white"/> + </mask> + <mask id="mask2" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <circle cx="0.5" cy="0.5" r="0.5" fill="white"/> + </mask> + <circle cx="150" cy="150" r="147" fill="red"/> + </svg> + + <div style="background: red; mask: url(#mask1);"/> + <div style="background: lime; mask: url(#mask2);"/> + +</body> +</html>
new file mode 100644 --- /dev/null +++ b/layout/reftests/svg/svg-integration/mask-transformed-html-02.xhtml @@ -0,0 +1,42 @@ +<!-- + Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ +--> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <title>Test SVG masking of transformed HTML elements</title> + <!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=769103 --> + <style type="text/css"> + +* { margin: 0; border: 0; padding: 0;} + +div { + position: absolute; + left: 50px; + top: 50px; + width: 150px; + height: 150px; + -moz-transform: scale(2,2); + -moz-transform-origin: 0 0; +} + + </style> +</head> +<body bgcolor="lime"> + + <svg xmlns="http://www.w3.org/2000/svg" width="350" height="350" + style="display:block; position:absolute;"> + <mask id="mask1" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <circle cx="0.5" cy="0.5" r="0.48" fill="white"/> + </mask> + <mask id="mask2" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <circle cx="0.5" cy="0.5" r="0.50" fill="white"/> + </mask> + <circle cx="200" cy="200" r="147" fill="red"/> + </svg> + + <div style="background: red; mask: url(#mask1);"/> + <div style="background: lime; mask: url(#mask2);"/> + +</body> +</html>
--- a/layout/reftests/svg/svg-integration/reftest.list +++ b/layout/reftests/svg/svg-integration/reftest.list @@ -20,8 +20,12 @@ == filter-html-01.xhtml filter-html-01-ref.svg == filter-html-01-extref.xhtml filter-html-01-ref.svg == filter-html-zoomed-01.xhtml filter-html-01-ref.svg == mask-html-01.xhtml mask-html-01-ref.svg == mask-html-01-extref-01.xhtml mask-html-01-ref.svg == mask-html-01-extref-02.xhtml mask-html-01-ref.svg == mask-html-zoomed-01.xhtml mask-html-01-ref.svg == mask-html-xbl-bound-01.html mask-html-01-ref.svg +== mask-transformed-html-01.xhtml ../pass.svg +== mask-transformed-html-02.xhtml ../pass.svg + +
--- a/layout/svg/base/src/nsSVGIntegrationUtils.cpp +++ b/layout/svg/base/src/nsSVGIntegrationUtils.cpp @@ -358,23 +358,23 @@ private: nsDisplayListBuilder* mBuilder; nsDisplayList* mInnerList; nsIFrame* mFrame; nsPoint mOffset; }; void nsSVGIntegrationUtils::PaintFramesWithEffects(nsRenderingContext* aCtx, - nsIFrame* aEffectsFrame, + nsIFrame* aFrame, const nsRect& aDirtyRect, nsDisplayListBuilder* aBuilder, nsDisplayList* aInnerList) { #ifdef DEBUG - nsISVGChildFrame *svgChildFrame = do_QueryFrame(aEffectsFrame); + nsISVGChildFrame *svgChildFrame = do_QueryFrame(aFrame); NS_ASSERTION(!svgChildFrame, "Should never be called on an SVG frame"); #endif /* SVG defines the following rendering model: * * 1. Render geometry * 2. Apply filter * 3. Apply clipping, masking, group opacity @@ -382,25 +382,25 @@ nsSVGIntegrationUtils::PaintFramesWithEf * We follow this, but perform a couple of optimizations: * * + Use cairo's clipPath when representable natively (single object * clip region). * * + Merge opacity and masking if both used together. */ - float opacity = aEffectsFrame->GetStyleDisplay()->mOpacity; + float opacity = aFrame->GetStyleDisplay()->mOpacity; if (opacity == 0.0f) { return; } /* Properties are added lazily and may have been removed by a restyle, so make sure all applicable ones are set again. */ nsIFrame* firstFrame = - nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aEffectsFrame); + nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aFrame); nsSVGEffects::EffectProperties effectProperties = nsSVGEffects::GetEffectProperties(firstFrame); bool isOK = true; nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK); nsSVGFilterFrame *filterFrame = effectProperties.GetFilterFrame(&isOK); nsSVGMaskFrame *maskFrame = effectProperties.GetMaskFrame(&isOK); if (!isOK) { @@ -408,76 +408,76 @@ nsSVGIntegrationUtils::PaintFramesWithEf } bool isTrivialClip = clipPathFrame ? clipPathFrame->IsTrivial() : true; gfxContext* gfx = aCtx->ThebesContext(); gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(gfx); PRInt32 appUnitsPerDevPixel = - aEffectsFrame->PresContext()->AppUnitsPerDevPixel(); + aFrame->PresContext()->AppUnitsPerDevPixel(); nsPoint firstFrameOffset = GetOffsetToUserSpace(firstFrame); nsPoint offset = (aBuilder->ToReferenceFrame(firstFrame) - firstFrameOffset). ToNearestPixels(appUnitsPerDevPixel). ToAppUnits(appUnitsPerDevPixel); aCtx->Translate(offset); - gfxMatrix cssPxToDevPxMatrix = GetCSSPxToDevPxMatrix(aEffectsFrame); + gfxMatrix cssPxToDevPxMatrix = GetCSSPxToDevPxMatrix(aFrame); bool complexEffects = false; /* Check if we need to do additional operations on this child's * rendering, which necessitates rendering into another surface. */ if (opacity != 1.0f || maskFrame || (clipPathFrame && !isTrivialClip)) { complexEffects = true; gfx->Save(); - aCtx->IntersectClip(aEffectsFrame->GetVisualOverflowRect()); + aCtx->IntersectClip(aFrame->GetVisualOverflowRect()); gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA); } /* If this frame has only a trivial clipPath, set up cairo's clipping now so * we can just do normal painting and get it clipped appropriately. */ if (clipPathFrame && isTrivialClip) { gfx->Save(); - clipPathFrame->ClipPaint(aCtx, aEffectsFrame, cssPxToDevPxMatrix); + clipPathFrame->ClipPaint(aCtx, aFrame, cssPxToDevPxMatrix); } /* Paint the child */ if (filterFrame) { - RegularFramePaintCallback callback(aBuilder, aInnerList, aEffectsFrame, + RegularFramePaintCallback callback(aBuilder, aInnerList, aFrame, offset); nsRect dirtyRect = aDirtyRect - offset; - filterFrame->PaintFilteredFrame(aCtx, aEffectsFrame, &callback, &dirtyRect); + filterFrame->PaintFilteredFrame(aCtx, aFrame, &callback, &dirtyRect); } else { gfx->SetMatrix(matrixAutoSaveRestore.Matrix()); - aInnerList->PaintForFrame(aBuilder, aCtx, aEffectsFrame, + aInnerList->PaintForFrame(aBuilder, aCtx, aFrame, nsDisplayList::PAINT_DEFAULT); aCtx->Translate(offset); } if (clipPathFrame && isTrivialClip) { gfx->Restore(); } /* No more effects, we're done. */ if (!complexEffects) { return; } gfx->PopGroupToSource(); nsRefPtr<gfxPattern> maskSurface = - maskFrame ? maskFrame->ComputeMaskAlpha(aCtx, aEffectsFrame, + maskFrame ? maskFrame->ComputeMaskAlpha(aCtx, aFrame, cssPxToDevPxMatrix, opacity) : nsnull; nsRefPtr<gfxPattern> clipMaskSurface; if (clipPathFrame && !isTrivialClip) { gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA); - nsresult rv = clipPathFrame->ClipPaint(aCtx, aEffectsFrame, cssPxToDevPxMatrix); + nsresult rv = clipPathFrame->ClipPaint(aCtx, aFrame, cssPxToDevPxMatrix); clipMaskSurface = gfx->PopGroup(); if (NS_SUCCEEDED(rv) && clipMaskSurface) { // Still more set after clipping, so clip to another surface if (maskSurface || opacity != 1.0f) { gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA); gfx->Mask(clipMaskSurface); gfx->PopGroupToSource();
--- a/layout/svg/base/src/nsSVGIntegrationUtils.h +++ b/layout/svg/base/src/nsSVGIntegrationUtils.h @@ -124,22 +124,20 @@ public: * Returns true if the given point is not clipped out by effects. * @param aPt in appunits relative to aFrame */ static bool HitTestFrameForEffects(nsIFrame* aFrame, const nsPoint& aPt); /** * Paint non-SVG frame with SVG effects. - * @param aOffset the offset in appunits where aFrame should be positioned - * in aCtx's coordinate system */ static void PaintFramesWithEffects(nsRenderingContext* aCtx, - nsIFrame* aEffectsFrame, const nsRect& aDirtyRect, + nsIFrame* aFrame, const nsRect& aDirtyRect, nsDisplayListBuilder* aBuilder, nsDisplayList* aInnerList); /** * SVG frames expect to paint in SVG user units, which are equal to CSS px * units. This method provides a transform matrix to multiply onto a * gfxContext's current transform to convert the context's current units from * its usual dev pixels to SVG user units/CSS px to keep the SVG code happy.
--- a/layout/svg/base/src/nsSVGMaskFrame.cpp +++ b/layout/svg/base/src/nsSVGMaskFrame.cpp @@ -48,28 +48,24 @@ nsSVGMaskFrame::ComputeMaskAlpha(nsRende bbox = nsSVGUtils::GetBBox(aParent); } gfxRect maskArea = nsSVGUtils::GetRelativeRect(units, &mask->mLengthAttributes[nsSVGMaskElement::X], bbox, aParent); gfxContext *gfx = aContext->ThebesContext(); + // Get the clip extents in device space: gfx->Save(); nsSVGUtils::SetClipRect(gfx, aMatrix, maskArea); + gfx->IdentityMatrix(); gfxRect clipExtents = gfx->GetClipExtents(); clipExtents.RoundOut(); gfx->Restore(); -#ifdef DEBUG_tor - fprintf(stderr, "clip extent: %f,%f %fx%f\n", - clipExtents.X(), clipExtents.Y(), - clipExtents.Width(), clipExtents.Height()); -#endif - bool resultOverflows; gfxIntSize surfaceSize = nsSVGUtils::ConvertToSurfaceSize(gfxSize(clipExtents.Width(), clipExtents.Height()), &resultOverflows); // 0 disables mask, < 0 is an error if (surfaceSize.width <= 0 || surfaceSize.height <= 0) @@ -77,20 +73,29 @@ nsSVGMaskFrame::ComputeMaskAlpha(nsRende if (resultOverflows) return nsnull; nsRefPtr<gfxImageSurface> image = new gfxImageSurface(surfaceSize, gfxASurface::ImageFormatARGB32); if (!image || image->CairoStatus()) return nsnull; - image->SetDeviceOffset(-clipExtents.TopLeft()); + + // We would like to use gfxImageSurface::SetDeviceOffset() to position + // 'image'. However, we need to set the same matrix on the temporary context + // and pattern that we create below as is currently set on 'gfx'. + // Unfortunately, any device offset set by SetDeviceOffset() is affected by + // the transform passed to the SetMatrix() calls, so to avoid that we account + // for the device offset in the transform rather than use SetDeviceOffset(). + gfxMatrix matrix = + gfx->CurrentMatrix() * gfxMatrix().Translate(-clipExtents.TopLeft()); nsRenderingContext tmpCtx; tmpCtx.Init(this->PresContext()->DeviceContext(), image); + tmpCtx.ThebesContext()->SetMatrix(matrix); mMaskParent = aParent; if (mMaskParentMatrix) { *mMaskParentMatrix = aMatrix; } else { mMaskParentMatrix = new gfxMatrix(aMatrix); } @@ -127,16 +132,17 @@ nsSVGMaskFrame::ComputeMaskAlpha(nsRende pixel[GFX_ARGB32_OFFSET_G] * 0.7154 + pixel[GFX_ARGB32_OFFSET_B] * 0.0721) * (pixel[GFX_ARGB32_OFFSET_A] / 255.0) * aOpacity); memset(pixel, alpha, 4); } gfxPattern *retval = new gfxPattern(image); + retval->SetMatrix(matrix); NS_IF_ADDREF(retval); return retval; } /* virtual */ void nsSVGMaskFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) { nsSVGEffects::InvalidateDirectRenderingObservers(this);
--- a/layout/svg/base/src/nsSVGOuterSVGFrame.cpp +++ b/layout/svg/base/src/nsSVGOuterSVGFrame.cpp @@ -435,39 +435,39 @@ nsSVGOuterSVGFrame::DidReflow(nsPresCont PresContext()->PresShell()->SynthesizeMouseMove(false); return rv; } //---------------------------------------------------------------------- // container methods -class nsDisplaySVG : public nsDisplayItem { +class nsDisplayOuterSVG : public nsDisplayItem { public: - nsDisplaySVG(nsDisplayListBuilder* aBuilder, - nsSVGOuterSVGFrame* aFrame) : + nsDisplayOuterSVG(nsDisplayListBuilder* aBuilder, + nsSVGOuterSVGFrame* aFrame) : nsDisplayItem(aBuilder, aFrame) { - MOZ_COUNT_CTOR(nsDisplaySVG); + MOZ_COUNT_CTOR(nsDisplayOuterSVG); } #ifdef NS_BUILD_REFCNT_LOGGING - virtual ~nsDisplaySVG() { - MOZ_COUNT_DTOR(nsDisplaySVG); + virtual ~nsDisplayOuterSVG() { + MOZ_COUNT_DTOR(nsDisplayOuterSVG); } #endif virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames); virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx); - NS_DISPLAY_DECL_NAME("SVGEventReceiver", TYPE_SVG_EVENT_RECEIVER) + NS_DISPLAY_DECL_NAME("SVGOuterSVG", TYPE_SVG_OUTER_SVG) }; void -nsDisplaySVG::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, - HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) +nsDisplayOuterSVG::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, + HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) { nsSVGOuterSVGFrame *outerSVGFrame = static_cast<nsSVGOuterSVGFrame*>(mFrame); nsRect rectAtOrigin = aRect - ToReferenceFrame(); nsRect thisRect(nsPoint(0,0), outerSVGFrame->GetSize()); if (!thisRect.Intersects(rectAtOrigin)) return; nsPoint rectCenter(rectAtOrigin.x + rectAtOrigin.width / 2, @@ -477,39 +477,43 @@ nsDisplaySVG::HitTest(nsDisplayListBuild outerSVGFrame, rectCenter + outerSVGFrame->GetPosition() - outerSVGFrame->GetContentRect().TopLeft()); if (frame) { aOutFrames->AppendElement(frame); } } void -nsDisplaySVG::Paint(nsDisplayListBuilder* aBuilder, - nsRenderingContext* aContext) +nsDisplayOuterSVG::Paint(nsDisplayListBuilder* aBuilder, + nsRenderingContext* aContext) { - nsSVGOuterSVGFrame *frame = static_cast<nsSVGOuterSVGFrame*>(mFrame); - - if (frame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) - return; - #if defined(DEBUG) && defined(SVG_DEBUG_PAINT_TIMING) PRTime start = PR_Now(); #endif aContext->PushState(); + nsSVGOuterSVGFrame *frame = static_cast<nsSVGOuterSVGFrame*>(mFrame); + #ifdef XP_MACOSX if (frame->BitmapFallbackEnabled()) { // nquartz fallback paths, which svg tends to trigger, need // a non-window context target aContext->ThebesContext()->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA); } #endif - frame->Paint(aBuilder, aContext, mVisibleRect, ToReferenceFrame()); + nsRect viewportRect = + frame->GetContentRectRelativeToSelf() + ToReferenceFrame(); + nsRect clipRect = mVisibleRect.Intersect(viewportRect); + + aContext->IntersectClip(clipRect); + aContext->Translate(viewportRect.TopLeft()); + + frame->Paint(aBuilder, aContext, clipRect - viewportRect.TopLeft()); #ifdef XP_MACOSX if (frame->BitmapFallbackEnabled()) { // show the surface we pushed earlier for fallbacks aContext->ThebesContext()->PopGroupToSource(); aContext->ThebesContext()->Paint(); } @@ -614,55 +618,51 @@ nsSVGOuterSVGFrame::AttributeChanged(PRI //---------------------------------------------------------------------- // painting NS_IMETHODIMP nsSVGOuterSVGFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { + if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) { + return NS_OK; + } + nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists); NS_ENSURE_SUCCESS(rv, rv); nsDisplayList replacedContent; rv = replacedContent.AppendNewToTop( - new (aBuilder) nsDisplaySVG(aBuilder, this)); + new (aBuilder) nsDisplayOuterSVG(aBuilder, this)); NS_ENSURE_SUCCESS(rv, rv); WrapReplacedContentForBorderRadius(aBuilder, &replacedContent, aLists); return NS_OK; } void nsSVGOuterSVGFrame::Paint(const nsDisplayListBuilder* aBuilder, nsRenderingContext* aContext, - const nsRect& aDirtyRect, nsPoint aPt) + const nsRect& aDirtyRect) { - nsRect viewportRect = GetContentRect(); - nsPoint viewportOffset = aPt + viewportRect.TopLeft() - GetPosition(); - viewportRect.MoveTo(viewportOffset); - - nsRect clipRect; - clipRect.IntersectRect(aDirtyRect, viewportRect); - aContext->IntersectClip(clipRect); - aContext->Translate(viewportRect.TopLeft()); - nsRect dirtyRect = clipRect - viewportOffset; - - nsIntRect dirtyPxRect = dirtyRect.ToOutsidePixels(PresContext()->AppUnitsPerDevPixel()); - // Create an SVGAutoRenderState so we can call SetPaintingToWindow on // it, but don't change the render mode: SVGAutoRenderState state(aContext, SVGAutoRenderState::GetRenderMode(aContext)); if (aBuilder->IsPaintingToWindow()) { state.SetPaintingToWindow(true); } + // Convert the (content area relative) dirty rect to dev pixels: + nsIntRect dirtyPxRect = + aDirtyRect.ToOutsidePixels(PresContext()->AppUnitsPerDevPixel()); + nsSVGUtils::PaintFrameWithEffects(aContext, &dirtyPxRect, this); } nsSplittableType nsSVGOuterSVGFrame::GetSplittableType() const { return NS_FRAME_NOT_SPLITTABLE; }
--- a/layout/svg/base/src/nsSVGOuterSVGFrame.h +++ b/layout/svg/base/src/nsSVGOuterSVGFrame.h @@ -62,17 +62,17 @@ public: * Get the "type" of the frame * * @see nsGkAtoms::svgOuterSVGFrame */ virtual nsIAtom* GetType() const; void Paint(const nsDisplayListBuilder* aBuilder, nsRenderingContext* aContext, - const nsRect& aDirtyRect, nsPoint aPt); + const nsRect& aDirtyRect); #ifdef DEBUG NS_IMETHOD GetFrameName(nsAString& aResult) const { return MakeFrameName(NS_LITERAL_STRING("SVGOuterSVG"), aResult); } #endif
--- a/mobile/android/base/AwesomeBar.java +++ b/mobile/android/base/AwesomeBar.java @@ -215,16 +215,25 @@ public class AwesomeBar extends GeckoAct openUserEnteredAndFinish(mText.getText().toString()); return true; } else { return false; } } }); + mText.setOnFocusChangeListener(new View.OnFocusChangeListener() { + public void onFocusChange(View v, boolean hasFocus) { + if (!hasFocus) { + InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(v.getWindowToken(), 0); + } + } + }); + registerForContextMenu(mAwesomeTabs.findViewById(R.id.all_pages_list)); registerForContextMenu(mAwesomeTabs.findViewById(R.id.bookmarks_list)); registerForContextMenu(mAwesomeTabs.findViewById(R.id.history_list)); GeckoAppShell.registerGeckoEventListener("SearchEngines:Data", this); GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:Get", null)); } @@ -348,16 +357,21 @@ public class AwesomeBar extends GeckoAct resultIntent.putExtra(URL_KEY, url); resultIntent.putExtra(TARGET_KEY, mTarget); resultIntent.putExtra(SEARCH_KEY, engine); finishWithResult(resultIntent); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { + // Galaxy Note sends key events for the stylus that are outside of the + // valid keyCode range (see bug 758427) + if (keyCode > KeyEvent.getMaxKeyCode()) + return true; + // This method is called only if the key event was not handled // by any of the views, which usually means the edit box lost focus if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU || keyCode == KeyEvent.KEYCODE_SEARCH || keyCode == KeyEvent.KEYCODE_DPAD_UP || keyCode == KeyEvent.KEYCODE_DPAD_DOWN || keyCode == KeyEvent.KEYCODE_DPAD_LEFT ||
--- a/mobile/android/base/AwesomeBarTabs.java +++ b/mobile/android/base/AwesomeBarTabs.java @@ -63,16 +63,17 @@ public class AwesomeBarTabs extends TabH private static final String HISTORY_TAB = "history"; private static enum HistorySection { TODAY, YESTERDAY, WEEK, OLDER }; private Context mContext; private boolean mInflated; private LayoutInflater mInflater; private OnUrlOpenListener mUrlOpenListener; + private View.OnTouchListener mListTouchListener; private ContentResolver mContentResolver; private ContentObserver mContentObserver; private SearchEngine mSuggestEngine; private ArrayList<SearchEngine> mSearchEngines; private BookmarksQueryTask mBookmarksQueryTask; private HistoryQueryTask mHistoryQueryTask; @@ -881,16 +882,24 @@ public class AwesomeBarTabs extends TabH return; mInflated = true; // This should be called before adding any tabs // to the TabHost. setup(); + mListTouchListener = new View.OnTouchListener() { + public boolean onTouch(View view, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) + hideSoftInput(view); + return false; + } + }; + addAllPagesTab(); addBookmarksTab(); addHistoryTab(); setOnTabChangedListener(new TabHost.OnTabChangeListener() { public void onTabChanged(String tabId) { boolean hideSoftInput = true; @@ -969,39 +978,42 @@ public class AwesomeBarTabs extends TabH allPagesList.setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { ((AwesomeBarItem) allPagesList.getItemAtPosition(position)).onClick(); } }); allPagesList.setAdapter(mAllPagesCursorAdapter); + allPagesList.setOnTouchListener(mListTouchListener); } private void addBookmarksTab() { Log.d(LOGTAG, "Creating Bookmarks tab"); addAwesomeTab(BOOKMARKS_TAB, R.string.awesomebar_bookmarks_title, R.id.bookmarks_list); ListView bookmarksList = (ListView) findViewById(R.id.bookmarks_list); + bookmarksList.setOnTouchListener(mListTouchListener); // Only load bookmark list when tab is actually used. // See OnTabChangeListener above. } private void addHistoryTab() { Log.d(LOGTAG, "Creating History tab"); addAwesomeTab(HISTORY_TAB, R.string.awesomebar_history_title, R.id.history_list); ListView historyList = (ListView) findViewById(R.id.history_list); + historyList.setOnTouchListener(mListTouchListener); // Only load history list when tab is actually used. // See OnTabChangeListener above. } private boolean hideSoftInput(View view) { InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE); @@ -1219,21 +1231,9 @@ public class AwesomeBarTabs extends TabH mAllPagesCursorAdapter.notifyDataSetChanged(); } }); } public boolean isInReadingList() { return mInReadingList; } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - // we should only have to hide the soft keyboard once - when the user - // initially touches the screen - if (ev.getAction() == MotionEvent.ACTION_DOWN) - hideSoftInput(this); - - // the android docs make no sense, but returning false will cause this and other - // motion events to be sent to the view the user tapped on - return false; - } }
--- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -2147,17 +2147,17 @@ abstract public class GeckoApp * compatable with our previous implementations */ private String getURIFromIntent(Intent intent) { String uri = intent.getDataString(); if (uri != null) return uri; final String action = intent.getAction(); - if (action.startsWith(ACTION_WEBAPP_PREFIX) || ACTION_BOOKMARK.equals(action)) { + if ((action != null && action.startsWith(ACTION_WEBAPP_PREFIX)) || ACTION_BOOKMARK.equals(action)) { uri = intent.getStringExtra("args"); if (uri != null && uri.startsWith("--url=")) { uri.replace("--url=", ""); } } return uri; }
--- a/mobile/android/base/GeckoInputConnection.java +++ b/mobile/android/base/GeckoInputConnection.java @@ -871,16 +871,19 @@ public class GeckoInputConnection } private boolean processKeyDown(int keyCode, KeyEvent event, boolean isPreIme) { if (DEBUG) { Log.d(LOGTAG, "IME: processKeyDown(keyCode=" + keyCode + ", event=" + event + ", " + isPreIme + ")"); } + if (keyCode > KeyEvent.getMaxKeyCode()) + return false; + clampSelection(); switch (keyCode) { case KeyEvent.KEYCODE_MENU: case KeyEvent.KEYCODE_BACK: case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_SEARCH: @@ -930,16 +933,19 @@ public class GeckoInputConnection } private boolean processKeyUp(int keyCode, KeyEvent event, boolean isPreIme) { if (DEBUG) { Log.d(LOGTAG, "IME: processKeyUp(keyCode=" + keyCode + ", event=" + event + ", " + isPreIme + ")"); } + if (keyCode > KeyEvent.getMaxKeyCode()) + return false; + switch (keyCode) { case KeyEvent.KEYCODE_BACK: case KeyEvent.KEYCODE_SEARCH: case KeyEvent.KEYCODE_MENU: return false; default: break; }
--- a/mobile/android/base/GeckoThread.java +++ b/mobile/android/base/GeckoThread.java @@ -68,19 +68,22 @@ public class GeckoThread extends Thread Configuration config = res.getConfiguration(); config.locale = locale; res.updateConfiguration(config, res.getDisplayMetrics()); Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - runGecko"); // find the right intent type final String action = mIntent.getAction(); - String type = action.startsWith(GeckoApp.ACTION_WEBAPP_PREFIX) ? "-webapp" : - GeckoApp.ACTION_BOOKMARK.equals(action) ? "-bookmark" : - null; + String type = null; + + if (action != null && action.startsWith(GeckoApp.ACTION_WEBAPP_PREFIX)) + type = "-webapp"; + else if (GeckoApp.ACTION_BOOKMARK.equals(action)) + type = "-bookmark"; String args = mIntent.getStringExtra("args"); // if this isn't the default BrowserApp, send the apps default profile to gecko if (!(app instanceof BrowserApp)) { String profile = app.getDefaultProfileName(); args = (args != null ? args : "") + "-P " + profile; }
--- a/mobile/android/base/tests/BaseTest.java.in +++ b/mobile/android/base/tests/BaseTest.java.in @@ -63,33 +63,33 @@ abstract class BaseTest extends Activity Intent i = new Intent(Intent.ACTION_MAIN); mProfile = (String)config.get("profile"); i.putExtra("args", "-no-remote -profile " + mProfile); // Start the activity setActivityIntent(i); mActivity = getActivity(); - // Set up Robotium.solo and Driver objects - mSolo = new Solo(getInstrumentation()); - mDriver = new FennecNativeDriver(mActivity, mSolo); - mActions = new FennecNativeActions(mActivity, mSolo, getInstrumentation()); - mLogFile = (String)config.get("logfile"); mBaseUrl = ((String)config.get("host")).replaceAll("(/$)", ""); mRawBaseUrl = ((String)config.get("rawhost")).replaceAll("(/$)", ""); // Initialize the asserter if (getTestType() == TEST_TALOS) { mAsserter = new FennecTalosAssert(); } else { mAsserter = new FennecMochitestAssert(); } mAsserter.setLogFile(mLogFile); mAsserter.setTestName(this.getClass().getName()); + + // Set up Robotium.solo and Driver objects + mSolo = new Solo(getInstrumentation()); + mDriver = new FennecNativeDriver(mActivity, mSolo); + mActions = new FennecNativeActions(mActivity, mSolo, getInstrumentation(), mAsserter); } @Override protected void runTest() throws Throwable { try { super.runTest(); } catch (Throwable t) { if (mAsserter != null) {
--- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -1379,16 +1379,17 @@ var NativeWindow = { } } }; var SelectionHandler = { // Keeps track of data about the dimensions of the selection cache: null, _active: false, + _viewOffset: null, // The window that holds the selection (can be a sub-frame) get _view() { if (this._viewRef) return this._viewRef.get(); return null; }, @@ -1422,27 +1423,41 @@ var SelectionHandler = { // Units in pixels HANDLE_WIDTH: 35, HANDLE_HEIGHT: 64, HANDLE_PADDING: 20, HANDLE_VERTICAL_OFFSET: 10, init: function sh_init() { Services.obs.addObserver(this, "Gesture:SingleTap", false); + Services.obs.addObserver(this, "Window:Resize", false); }, uninit: function sh_uninit() { Services.obs.removeObserver(this, "Gesture:SingleTap", false); + Services.obs.removeObserver(this, "Window:Resize", false); }, observe: function sh_observe(aSubject, aTopic, aData) { - let data = JSON.parse(aData); - - if (this._active) - this.endSelection(data.x, data.y); + switch (aTopic) { + case "Gesture:SingleTap": { + if (!this._active) + return; + + let data = JSON.parse(aData); + this.endSelection(data.x, data.y); + break; + } + case "Window:Resize": { + // Knowing when the page is done drawing is hard, so let's just cancel + // the selection when the window changes. We should fix this later. + this.endSelection(); + break; + } + } }, notifySelectionChanged: function sh_notifySelectionChanged(aDoc, aSel, aReason) { // If the selection was removed, call endSelection() to clean up if (aSel == "" && aReason == Ci.nsISelectionListener.NO_REASON) this.endSelection(); }, @@ -1458,16 +1473,20 @@ var SelectionHandler = { // Clear out any existing selection this.endSelection(); } // Get the element's view this._view = aElement.ownerDocument.defaultView; this._isRTL = (this._view.getComputedStyle(aElement, "").direction == "rtl"); + let computedStyle = this._view.getComputedStyle(this._view.document.documentElement); + this._viewOffset = { top: parseInt(computedStyle.getPropertyValue("margin-top").replace("px", "")), + left: parseInt(computedStyle.getPropertyValue("margin-left").replace("px", "")) }; + // Remove any previous selected or created ranges. Tapping anywhere on a // page will create an empty range. let selection = this._view.getSelection(); selection.removeAllRanges(); // Position the caret using a fake mouse click let cwu = BrowserApp.selectedBrowser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor). getInterface(Ci.nsIDOMWindowUtils); @@ -1572,21 +1591,21 @@ var SelectionHandler = { if (!element || element instanceof Ci.nsIDOMHTMLInputElement || element instanceof Ci.nsIDOMHTMLTextAreaElement || element.ownerDocument.defaultView != this._view) return; */ // Update the handle position as it's dragged if (aIsStartHandle) { - this._start.style.left = aX + this._view.scrollX + "px"; - this._start.style.top = aY + this._view.scrollY + "px"; + this._start.style.left = aX + this._view.scrollX - this._viewOffset.left + "px"; + this._start.style.top = aY + this._view.scrollY - this._viewOffset.top + "px"; } else { - this._end.style.left = aX + this._view.scrollX + "px"; - this._end.style.top = aY + this._view.scrollY + "px"; + this._end.style.left = aX + this._view.scrollX - this._viewOffset.left + "px"; + this._end.style.top = aY + this._view.scrollY - this._viewOffset.top + "px"; } let cwu = this._view.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); // The handles work the same on both LTR and RTL pages, but the underlying selection // works differently, so we need to reverse how we send mouse events on RTL pages. if (this._isRTL) { // Position the caret at the end handle using a fake mouse click @@ -1691,16 +1710,17 @@ var SelectionHandler = { let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper); clipboard.copyString(selectedText, element.ownerDocument); NativeWindow.toast.show(Strings.browser.GetStringFromName("selectionHelper.textCopied"), "short"); } } this._isRTL = false; this._view = null; + this._viewOffset = null; this.cache = null; return selectedText; }, _pointInSelection: function sh_pointInSelection(aX, aY) { let offset = { x: 0, y: 0 }; let win = this._view; @@ -1739,21 +1759,21 @@ var SelectionHandler = { this.cache.end = end; return selectionReversed; }, // Adjust start/end positions to account for scroll, and account for the dimensions of the // handle elements to ensure the handles point exactly at the ends of the selection. positionHandles: function sh_positionHandles() { - this._start.style.left = (this.cache.start.x + this._view.scrollX - this.HANDLE_WIDTH - this.HANDLE_PADDING) + "px"; - this._start.style.top = (this.cache.start.y + this._view.scrollY - this.HANDLE_VERTICAL_OFFSET) + "px"; - - this._end.style.left = (this.cache.end.x + this._view.scrollX - this.HANDLE_PADDING) + "px"; - this._end.style.top = (this.cache.end.y + this._view.scrollY - this.HANDLE_VERTICAL_OFFSET) + "px"; + this._start.style.left = (this.cache.start.x + this._view.scrollX - this._viewOffset.left - this.HANDLE_WIDTH - this.HANDLE_PADDING) + "px"; + this._start.style.top = (this.cache.start.y + this._view.scrollY - this._viewOffset.top - this.HANDLE_VERTICAL_OFFSET) + "px"; + + this._end.style.left = (this.cache.end.x + this._view.scrollX - this._viewOffset.left - this.HANDLE_PADDING) + "px"; + this._end.style.top = (this.cache.end.y + this._view.scrollY - this._viewOffset.top - this.HANDLE_VERTICAL_OFFSET) + "px"; }, showHandles: function sh_showHandles() { let doc = this._view.document; this._start = doc.getAnonymousElementByAttribute(doc.documentElement, "anonid", "selection-handle-start"); this._end = doc.getAnonymousElementByAttribute(doc.documentElement, "anonid", "selection-handle-end"); if (!this._start || !this._end) {
--- a/netwerk/protocol/http/nsHttpConnection.cpp +++ b/netwerk/protocol/http/nsHttpConnection.cpp @@ -44,16 +44,17 @@ nsHttpConnection::nsHttpConnection() , mConsiderReusedAfterInterval(0) , mConsiderReusedAfterEpoch(0) , mCurrentBytesRead(0) , mMaxBytesRead(0) , mTotalBytesRead(0) , mTotalBytesWritten(0) , mKeepAlive(true) // assume to keep-alive by default , mKeepAliveMask(true) + , mDontReuse(false) , mSupportsPipelining(false) // assume low-grade server , mIsReused(false) , mCompletedProxyConnect(false) , mLastTransactionExpectedNoContent(false) , mIdleMonitoring(false) , mProxyConnectInProgress(false) , mHttp1xTransactionCount(0) , mRemainingConnectionUses(0xffffffff) @@ -511,38 +512,42 @@ nsHttpConnection::ProxyStartSSL() return ssl->ProxyStartSSL(); } void nsHttpConnection::DontReuse() { mKeepAliveMask = false; mKeepAlive = false; + mDontReuse = true; mIdleTimeout = 0; if (mSpdySession) mSpdySession->DontReuse(); } // Checked by the Connection Manager before scheduling a pipelined transaction bool nsHttpConnection::SupportsPipelining() { if (mTransaction && mTransaction->PipelineDepth() >= mRemainingConnectionUses) { LOG(("nsHttpConnection::SupportsPipelining this=%p deny pipeline " "because current depth %d exceeds max remaining uses %d\n", this, mTransaction->PipelineDepth(), mRemainingConnectionUses)); return false; } - return mSupportsPipelining && IsKeepAlive(); + return mSupportsPipelining && IsKeepAlive() && !mDontReuse; } bool nsHttpConnection::CanReuse() { + if (mDontReuse) + return false; + if ((mTransaction ? mTransaction->PipelineDepth() : 0) >= mRemainingConnectionUses) { return false; } bool canReuse; if (mSpdySession)
--- a/netwerk/protocol/http/nsHttpConnection.h +++ b/netwerk/protocol/http/nsHttpConnection.h @@ -212,16 +212,17 @@ private: PRInt64 mTotalBytesWritten; // does not include CONNECT tunnel nsRefPtr<nsIAsyncInputStream> mInputOverflow; PRIntervalTime mRtt; bool mKeepAlive; bool mKeepAliveMask; + bool mDontReuse; bool mSupportsPipelining; bool mIsReused; bool mCompletedProxyConnect; bool mLastTransactionExpectedNoContent; bool mIdleMonitoring; bool mProxyConnectInProgress; // The number of <= HTTP/1.1 transactions performed on this connection. This
--- a/netwerk/socket/nsSOCKSIOLayer.cpp +++ b/netwerk/socket/nsSOCKSIOLayer.cpp @@ -10,35 +10,41 @@ #include "nsIServiceManager.h" #include "nsIDNSService.h" #include "nsIDNSRecord.h" #include "nsISOCKSSocketInfo.h" #include "nsISocketProvider.h" #include "nsSOCKSIOLayer.h" #include "nsNetCID.h" +#include "nsIDNSListener.h" +#include "nsICancelable.h" +#include "nsThreadUtils.h" static PRDescIdentity nsSOCKSIOLayerIdentity; static PRIOMethods nsSOCKSIOLayerMethods; static bool firstTime = true; #if defined(PR_LOGGING) static PRLogModuleInfo *gSOCKSLog; #define LOGDEBUG(args) PR_LOG(gSOCKSLog, PR_LOG_DEBUG, args) #define LOGERROR(args) PR_LOG(gSOCKSLog, PR_LOG_ERROR , args) #else #define LOGDEBUG(args) #define LOGERROR(args) #endif class nsSOCKSSocketInfo : public nsISOCKSSocketInfo + , public nsIDNSListener { enum State { SOCKS_INITIAL, + SOCKS_DNS_IN_PROGRESS, + SOCKS_DNS_COMPLETE, SOCKS_CONNECTING_TO_PROXY, SOCKS4_WRITE_CONNECT_REQUEST, SOCKS4_READ_CONNECT_RESPONSE, SOCKS5_WRITE_AUTH_REQUEST, SOCKS5_READ_AUTH_RESPONSE, SOCKS5_WRITE_CONNECT_REQUEST, SOCKS5_READ_CONNECT_RESPONSE_TOP, SOCKS5_READ_CONNECT_RESPONSE_BOTTOM, @@ -52,30 +58,32 @@ class nsSOCKSSocketInfo : public nsISOCK static const PRUint32 MAX_HOSTNAME_LEN = 255; public: nsSOCKSSocketInfo(); virtual ~nsSOCKSSocketInfo() { HandshakeFinished(); } NS_DECL_ISUPPORTS NS_DECL_NSISOCKSSOCKETINFO + NS_DECL_NSIDNSLISTENER void Init(PRInt32 version, const char *proxyHost, PRInt32 proxyPort, const char *destinationHost, PRUint32 flags); void SetConnectTimeout(PRIntervalTime to); PRStatus DoHandshake(PRFileDesc *fd, PRInt16 oflags = -1); PRInt16 GetPollFlags() const; bool IsConnected() const { return mState == SOCKS_CONNECTED; } private: void HandshakeFinished(PRErrorCode err = 0); + PRStatus StartDNS(PRFileDesc *fd); PRStatus ConnectToProxy(PRFileDesc *fd); PRStatus ContinueConnectingToProxy(PRFileDesc *fd, PRInt16 oflags); PRStatus WriteV4ConnectRequest(); PRStatus ReadV4ConnectResponse(); PRStatus WriteV5AuthRequest(); PRStatus ReadV5AuthResponse(); PRStatus WriteV5ConnectRequest(); PRStatus ReadV5AddrTypeAndLength(PRUint8 *type, PRUint32 *len); @@ -101,17 +109,20 @@ private: private: State mState; PRUint8 * mData; PRUint8 * mDataIoPtr; PRUint32 mDataLength; PRUint32 mReadOffset; PRUint32 mAmountToRead; - nsCOMPtr<nsIDNSRecord> mDnsRec; + nsCOMPtr<nsIDNSRecord> mDnsRec; + nsCOMPtr<nsICancelable> mLookup; + nsresult mLookupStatus; + PRFileDesc *mFD; nsCString mDestinationHost; nsCString mProxyHost; PRInt32 mProxyPort; PRInt32 mVersion; // SOCKS version 4 or 5 PRUint32 mFlags; PRNetAddr mInternalProxyAddr; PRNetAddr mExternalProxyAddr; @@ -141,17 +152,17 @@ nsSOCKSSocketInfo::Init(PRInt32 version, { mVersion = version; mProxyHost = proxyHost; mProxyPort = proxyPort; mDestinationHost = host; mFlags = flags; } -NS_IMPL_THREADSAFE_ISUPPORTS1(nsSOCKSSocketInfo, nsISOCKSSocketInfo) +NS_IMPL_THREADSAFE_ISUPPORTS2(nsSOCKSSocketInfo, nsISOCKSSocketInfo, nsIDNSListener) NS_IMETHODIMP nsSOCKSSocketInfo::GetExternalProxyAddr(PRNetAddr * *aExternalProxyAddr) { memcpy(*aExternalProxyAddr, &mExternalProxyAddr, sizeof(PRNetAddr)); return NS_OK; } @@ -209,39 +220,74 @@ nsSOCKSSocketInfo::HandshakeFinished(PRE // We don't need the buffer any longer, so free it. delete [] mData; mData = nsnull; mDataIoPtr = nsnull; mDataLength = 0; mReadOffset = 0; mAmountToRead = 0; + if (mLookup) { + mLookup->Cancel(NS_ERROR_FAILURE); + mLookup = nsnull; + } +} + +PRStatus +nsSOCKSSocketInfo::StartDNS(PRFileDesc *fd) +{ + NS_ABORT_IF_FALSE(!mDnsRec && mState == SOCKS_INITIAL, + "Must be in initial state to make DNS Lookup"); + + nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID); + if (!dns) + return PR_FAILURE; + + mFD = fd; + nsresult rv = dns->AsyncResolve(mProxyHost, 0, this, + NS_GetCurrentThread(), + getter_AddRefs(mLookup)); + + if (NS_FAILED(rv)) { + LOGERROR(("socks: DNS lookup for SOCKS proxy %s failed", + mProxyHost.get())); + return PR_FAILURE; + } + mState = SOCKS_DNS_IN_PROGRESS; + PR_SetError(PR_IN_PROGRESS_ERROR, 0); + return PR_FAILURE; +} + +NS_IMETHODIMP +nsSOCKSSocketInfo::OnLookupComplete(nsICancelable *aRequest, + nsIDNSRecord *aRecord, + nsresult aStatus) +{ + NS_ABORT_IF_FALSE(aRequest == mLookup, "wrong DNS query"); + mLookup = nsnull; + mLookupStatus = aStatus; + mDnsRec = aRecord; + mState = SOCKS_DNS_COMPLETE; + ConnectToProxy(mFD); + mFD = nsnull; + return NS_OK; } PRStatus nsSOCKSSocketInfo::ConnectToProxy(PRFileDesc *fd) { PRStatus status; nsresult rv; - NS_ABORT_IF_FALSE(mState == SOCKS_INITIAL, - "Must be in initial state to make connection!"); + NS_ABORT_IF_FALSE(mState == SOCKS_DNS_COMPLETE, + "Must have DNS to make connection!"); - // If we haven't performed the DNS lookup, do that now. - if (!mDnsRec) { - nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID); - if (!dns) - return PR_FAILURE; - - rv = dns->Resolve(mProxyHost, 0, getter_AddRefs(mDnsRec)); - if (NS_FAILED(rv)) { - LOGERROR(("socks: DNS lookup for SOCKS proxy %s failed", - mProxyHost.get())); - return PR_FAILURE; - } + if (NS_FAILED(mLookupStatus)) { + PR_SetError(PR_BAD_ADDRESS_ERROR, 0); + return PR_FAILURE; } PRInt32 addresses = 0; do { if (addresses++) mDnsRec->ReportUnusable(mProxyPort); rv = mDnsRec->GetNextAddr(mProxyPort, &mInternalProxyAddr); @@ -286,17 +332,17 @@ nsSOCKSSocketInfo::ContinueConnectingToP LOGDEBUG(("socks: continuing connection to proxy")); status = fd->lower->methods->connectcontinue(fd->lower, oflags); if (status != PR_SUCCESS) { PRErrorCode c = PR_GetError(); if (c != PR_WOULD_BLOCK_ERROR && c != PR_IN_PROGRESS_ERROR) { // A connection failure occured, try another address - mState = SOCKS_INITIAL; + mState = SOCKS_DNS_COMPLETE; return ConnectToProxy(fd); } // We're still connecting return PR_FAILURE; } // Connected now, start SOCKS @@ -629,16 +675,21 @@ nsSOCKSSocketInfo::SetConnectTimeout(PRI PRStatus nsSOCKSSocketInfo::DoHandshake(PRFileDesc *fd, PRInt16 oflags) { LOGDEBUG(("socks: DoHandshake(), state = %d", mState)); switch (mState) { case SOCKS_INITIAL: + return StartDNS(fd); + case SOCKS_DNS_IN_PROGRESS: + PR_SetError(PR_IN_PROGRESS_ERROR, 0); + return PR_FAILURE; + case SOCKS_DNS_COMPLETE: return ConnectToProxy(fd); case SOCKS_CONNECTING_TO_PROXY: return ContinueConnectingToProxy(fd, oflags); case SOCKS4_WRITE_CONNECT_REQUEST: if (WriteToSocket(fd) != PR_SUCCESS) return PR_FAILURE; WantRead(8); mState = SOCKS4_READ_CONNECT_RESPONSE; @@ -691,16 +742,18 @@ nsSOCKSSocketInfo::DoHandshake(PRFileDes return PR_FAILURE; } PRInt16 nsSOCKSSocketInfo::GetPollFlags() const { switch (mState) { + case SOCKS_DNS_IN_PROGRESS: + case SOCKS_DNS_COMPLETE: case SOCKS_CONNECTING_TO_PROXY: return PR_POLL_EXCEPT | PR_POLL_WRITE; case SOCKS4_WRITE_CONNECT_REQUEST: case SOCKS5_WRITE_AUTH_REQUEST: case SOCKS5_WRITE_CONNECT_REQUEST: return PR_POLL_WRITE; case SOCKS4_READ_CONNECT_RESPONSE: case SOCKS5_READ_AUTH_RESPONSE: @@ -1134,12 +1187,12 @@ nsSOCKSIOLayerAddToSocket(PRInt32 family if (NS_FAILED(rv)) { LOGERROR(("PR_PushIOLayer() failed. rv = %x.", rv)); NS_RELEASE(infoObject); PR_DELETE(layer); return NS_ERROR_FAILURE; } - *info = infoObject; + *info = static_cast<nsISOCKSSocketInfo*>(infoObject); NS_ADDREF(*info); return NS_OK; }
--- a/toolkit/components/downloads/nsDownloadManager.cpp +++ b/toolkit/components/downloads/nsDownloadManager.cpp @@ -2874,18 +2874,23 @@ nsDownload::OpenWithApplication() nsDownloadManager::gDownloadManagerService->mInPrivateBrowsing) { // Use the ExternalHelperAppService to push the temporary file to the list // of files to be deleted on exit. nsCOMPtr<nsPIExternalAppLauncher> appLauncher(do_GetService (NS_EXTERNALHELPERAPPSERVICE_CONTRACTID)); // Even if we are unable to get this service we return the result // of LaunchWithFile() which makes more sense. - if (appLauncher) - (void)appLauncher->DeleteTemporaryFileOnExit(target); + if (appLauncher) { + if (nsDownloadManager::gDownloadManagerService->mInPrivateBrowsing) { + (void)appLauncher->DeleteTemporaryPrivateFileWhenPossible(target); + } else { + (void)appLauncher->DeleteTemporaryFileOnExit(target); + } + } } return retVal; } void nsDownload::SetStartTime(PRInt64 aStartTime) {
--- a/toolkit/components/telemetry/TelemetryPing.js +++ b/toolkit/components/telemetry/TelemetryPing.js @@ -60,16 +60,18 @@ const MEM_HISTOGRAMS = { // Seconds of idle time before pinging. // On idle-daily a gather-telemetry notification is fired, during it probes can // start asynchronous tasks to gather data. On the next idle the data is sent. const IDLE_TIMEOUT_SECONDS = 5 * 60; var gLastMemoryPoll = null; +let gWasDebuggerAttached = false; + function getLocale() { return Cc["@mozilla.org/chrome/chrome-registry;1"]. getService(Ci.nsIXULChromeRegistry). getSelectedLocale('global'); } XPCOMUtils.defineLazyServiceGetter(this, "Telemetry", "@mozilla.org/base/telemetry;1", @@ -116,16 +118,22 @@ function getSimpleMeasurements() { for (let p in appTimestamps) { if (!(p in ret) && appTimestamps[p]) ret[p] = appTimestamps[p] - si.process; } } ret.startupInterrupted = new Number(Services.startup.interrupted); + // Update debuggerAttached flag + let debugService = Cc["@mozilla.org/xpcom/debug;1"].getService(Ci.nsIDebug2); + let isDebuggerAttached = debugService.isDebuggerAttached; + gWasDebuggerAttached = gWasDebuggerAttached || isDebuggerAttached; + ret.debuggerAttached = new Number(gWasDebuggerAttached); + ret.js = Cc["@mozilla.org/js/xpc/XPConnect;1"] .getService(Ci.nsIJSEngineTelemetryStats) .telemetryValue; return ret; } /** @@ -771,16 +779,19 @@ TelemetryPing.prototype = { this.detachObservers() } else { this.attachObservers() } break; case "sessionstore-windows-restored": Services.obs.removeObserver(this, "sessionstore-windows-restored"); this._hasWindowRestoredObserver = false; + // Check whether debugger was attached during startup + let debugService = Cc["@mozilla.org/xpcom/debug;1"].getService(Ci.nsIDebug2); + gWasDebuggerAttached = debugService.isDebuggerAttached; // fall through case "test-gather-startup": this.gatherStartupInformation(); break; case "idle-daily": // Enqueue to main-thread, otherwise components may be inited by the // idle-daily category and miss the gather-telemetry notification. Services.tm.mainThread.dispatch((function() {
--- a/toolkit/components/viewsource/content/viewSourceUtils.js +++ b/toolkit/components/viewsource/content/viewSourceUtils.js @@ -114,20 +114,38 @@ var gViewSourceUtils = { var webBrowserPersist = Components .classes["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"] .createInstance(this.mnsIWebBrowserPersist); // the default setting is to not decode. we need to decode. webBrowserPersist.persistFlags = this.mnsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES; webBrowserPersist.progressListener = this.viewSourceProgressListener; webBrowserPersist.saveURI(uri, null, null, null, null, file); - // register the file to be deleted on app exit - Components.classes["@mozilla.org/uriloader/external-helper-app-service;1"] - .getService(Components.interfaces.nsPIExternalAppLauncher) - .deleteTemporaryFileOnExit(file); + let fromPrivateWindow = false; + if (aDocument) { + try { + fromPrivateWindow = + aDocument.defaultView + .QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIWebNavigation) + .QueryInterface(Components.interfaces.nsILoadContext) + .usePrivateBrowsing; + } catch (e) { + } + } + + let helperService = Components.classes["@mozilla.org/uriloader/external-helper-app-service;1"] + .getService(Components.interfaces.nsPIExternalAppLauncher); + if (fromPrivateWindow) { + // register the file to be deleted when possible + helperService.deleteTemporaryPrivateFileWhenPossible(file); + } else { + // register the file to be deleted on app exit + helperService.deleteTemporaryFileOnExit(file); + } } else { // we'll use nsIWebPageDescriptor to get the source because it may // not have to refetch the file from the server // XXXbz this is so broken... This code doesn't set up this docshell // at all correctly; if somehow the view-source stuff managed to // execute script we'd be in big trouble here, I suspect. var webShell = Components.classes["@mozilla.org/docshell;1"].createInstance(); webShell.QueryInterface(Components.interfaces.nsIBaseWindow).create(); @@ -259,20 +277,32 @@ var gViewSourceUtils = { // write the source to the file coStream.writeString(webNavigation.document.body.textContent); // clean up coStream.close(); foStream.close(); - // register the file to be deleted on app exit - Components.classes["@mozilla.org/uriloader/external-helper-app-service;1"] - .getService(Components.interfaces.nsPIExternalAppLauncher) - .deleteTemporaryFileOnExit(this.file); + let fromPrivateWindow = + this.data.doc.defaultView + .QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIWebNavigation) + .QueryInterface(Components.interfaces.nsILoadContext) + .usePrivateBrowsing; + + let helperService = Components.classes["@mozilla.org/uriloader/external-helper-app-service;1"] + .getService(Components.interfaces.nsPIExternalAppLauncher); + if (fromPrivateWindow) { + // register the file to be deleted when possible + helperService.deleteTemporaryPrivateFileWhenPossible(this.file); + } else { + // register the file to be deleted on app exit + helperService.deleteTemporaryFileOnExit(this.file); + } } var editorArgs = gViewSourceUtils.buildEditorArgs(this.file.path, this.data.lineNumber); this.editor.runw(false, editorArgs, editorArgs.length); gViewSourceUtils.handleCallBack(this.callBack, true, this.data); } catch (ex) {
--- a/tools/profiler/TableTicker.cpp +++ b/tools/profiler/TableTicker.cpp @@ -293,16 +293,23 @@ public: switch (entry.mTagName) { case 's': sample = b.CreateObject(); b.DefineProperty(sample, "name", tagStringData); frames = b.CreateArray(); b.DefineProperty(sample, "frames", frames); b.ArrayPush(samples, sample); break; + case 'r': + { + if (sample) { + b.DefineProperty(sample, "responsiveness", entry.mTagFloat); + } + } + break; case 'c': case 'l': { if (sample) { JSObject *frame = b.CreateObject(); if (entry.mTagName == 'l') { // Bug 753041 // We need a double cast here to tell GCC that we don't want to sign
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -95,24 +95,23 @@ #include "nsCRT.h" #include "nsLocalHandlerApp.h" #include "nsIRandomGenerator.h" #include "plbase64.h" #include "prmem.h" -#include "nsIPrivateBrowsingService.h" - #include "ContentChild.h" #include "nsXULAppAPI.h" #include "nsPIDOMWindow.h" #include "nsIDocShellTreeOwner.h" #include "nsIDocShellTreeItem.h" #include "ExternalHelperAppChild.h" +#include "nsILoadContext.h" #ifdef MOZ_WIDGET_ANDROID #include "AndroidBridge.h" #endif #include "mozilla/Preferences.h" using namespace mozilla; @@ -499,44 +498,37 @@ NS_IMPL_ISUPPORTS6( nsExternalHelperAppService, nsIExternalHelperAppService, nsPIExternalAppLauncher, nsIExternalProtocolService, nsIMIMEService, nsIObserver, nsISupportsWeakReference) -nsExternalHelperAppService::nsExternalHelperAppService() : - mInPrivateBrowsing(false) +nsExternalHelperAppService::nsExternalHelperAppService() { } nsresult nsExternalHelperAppService::Init() { - nsCOMPtr<nsIPrivateBrowsingService> pbs = - do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID); - if (pbs) { - pbs->GetPrivateBrowsingEnabled(&mInPrivateBrowsing); - } - // Add an observer for profile change nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); if (!obs) return NS_ERROR_FAILURE; #ifdef PR_LOGGING if (!mLog) { mLog = PR_NewLogModule("HelperAppService"); if (!mLog) return NS_ERROR_OUT_OF_MEMORY; } #endif nsresult rv = obs->AddObserver(this, "profile-before-change", true); NS_ENSURE_SUCCESS(rv, rv); - return obs->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, true); + return obs->AddObserver(this, "last-pb-context-exited", true); } nsExternalHelperAppService::~nsExternalHelperAppService() { } static PRInt64 GetContentLengthAsInt64(nsIRequest *request) { @@ -918,32 +910,44 @@ NS_IMETHODIMP nsExternalHelperAppService return NS_ERROR_NOT_IMPLEMENTED; } ////////////////////////////////////////////////////////////////////////////////////////////////////// // Methods related to deleting temporary files on exit ////////////////////////////////////////////////////////////////////////////////////////////////////// -NS_IMETHODIMP nsExternalHelperAppService::DeleteTemporaryFileOnExit(nsIFile * aTemporaryFile) +/* static */ +nsresult +nsExternalHelperAppService::DeleteTemporaryFileHelper(nsIFile * aTemporaryFile, + nsCOMArray<nsIFile> &aFileList) { bool isFile = false; // as a safety measure, make sure the nsIFile is really a file and not a directory object. aTemporaryFile->IsFile(&isFile); if (!isFile) return NS_OK; - if (mInPrivateBrowsing) - mTemporaryPrivateFilesList.AppendObject(aTemporaryFile); - else - mTemporaryFilesList.AppendObject(aTemporaryFile); + aFileList.AppendObject(aTemporaryFile); return NS_OK; } +NS_IMETHODIMP +nsExternalHelperAppService::DeleteTemporaryFileOnExit(nsIFile* aTemporaryFile) +{ + return DeleteTemporaryFileHelper(aTemporaryFile, mTemporaryFilesList); +} + +NS_IMETHODIMP +nsExternalHelperAppService::DeleteTemporaryPrivateFileWhenPossible(nsIFile* aTemporaryFile) +{ + return DeleteTemporaryFileHelper(aTemporaryFile, mTemporaryPrivateFilesList); +} + void nsExternalHelperAppService::FixFilePermissions(nsIFile* aFile) { // This space intentionally left blank } void nsExternalHelperAppService::ExpungeTemporaryFilesHelper(nsCOMArray<nsIFile> &fileList) { PRInt32 numEntries = fileList.Count(); @@ -1047,23 +1051,18 @@ nsExternalHelperAppService::SetProtocolH } // XPCOM profile change observer NS_IMETHODIMP nsExternalHelperAppService::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData ) { if (!strcmp(aTopic, "profile-before-change")) { ExpungeTemporaryFiles(); - } else if (!strcmp(aTopic, NS_PRIVATE_BROWSING_SWITCH_TOPIC)) { - if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_ENTER).Equals(someData)) - mInPrivateBrowsing = true; - else if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_LEAVE).Equals(someData)) { - mInPrivateBrowsing = false; - ExpungeTemporaryPrivateFiles(); - } + } else if (!strcmp(aTopic, "last-pb-context-exited")) { + ExpungeTemporaryPrivateFiles(); } return NS_OK; } ////////////////////////////////////////////////////////////////////////////////////////////////////// // begin external app handler implementation ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -2175,35 +2174,50 @@ nsresult nsExternalAppHandler::OpenWithA bool deleteTempFileOnExit = Preferences::GetBool("browser.helperApps.deleteTempFileOnExit", #if !defined(XP_MACOSX) true); #else false); #endif + // See whether the channel has been opened in private browsing mode + bool inPrivateBrowsing = false; + NS_ASSERTION(mRequest, "This should never be called with a null request"); + nsCOMPtr<nsIChannel> channel = do_QueryInterface(mRequest); + if (channel) { + nsCOMPtr<nsILoadContext> ctx; + NS_QueryNotificationCallbacks(channel, ctx); + if (ctx) { + inPrivateBrowsing = ctx->UsePrivateBrowsing(); + } + } + // make the tmp file readonly so users won't edit it and lose the changes // only if we're going to delete the file - if (deleteTempFileOnExit || mExtProtSvc->InPrivateBrowsing()) + if (deleteTempFileOnExit || inPrivateBrowsing) mFinalFileDestination->SetPermissions(0400); rv = mMimeInfo->LaunchWithFile(mFinalFileDestination); if (NS_FAILED(rv)) { // Send error notification. nsAutoString path; mFinalFileDestination->GetPath(path); SendStatusChange(kLaunchError, rv, nsnull, path); Cancel(rv); // Cancel, and clean up temp file. } // Always schedule files to be deleted at the end of the private browsing // mode, regardless of the value of the pref. - else if (deleteTempFileOnExit || mExtProtSvc->InPrivateBrowsing()) { + else if (deleteTempFileOnExit) { mExtProtSvc->DeleteTemporaryFileOnExit(mFinalFileDestination); } + else if (inPrivateBrowsing) { + mExtProtSvc->DeleteTemporaryPrivateFileWhenPossible(mFinalFileDestination); + } } return rv; } // LaunchWithApplication should only be called by the helper app dialog which allows // the user to say launch with application or save to disk. It doesn't actually // perform launch with application. That won't happen until we are done downloading
--- a/uriloader/exthandler/nsExternalHelperAppService.h +++ b/uriloader/exthandler/nsExternalHelperAppService.h @@ -106,22 +106,16 @@ public: * application path. */ virtual nsresult GetFileTokenForPath(const PRUnichar * platformAppPath, nsIFile ** aFile); virtual NS_HIDDEN_(nsresult) OSProtocolHandlerExists(const char *aScheme, bool *aExists) = 0; - /** - * Simple accessor to let nsExternalAppHandler know if we are currently - * inside the private browsing mode. - */ - bool InPrivateBrowsing() const { return mInPrivateBrowsing; } - protected: /** * Searches the "extra" array of MIMEInfo objects for an object * with a specific type. If found, it will modify the passed-in * MIMEInfo. Otherwise, it will return an error and the MIMEInfo * will be untouched. * @param aContentType The type to search for. * @param aMIMEInfo [inout] The mime info, if found @@ -168,16 +162,21 @@ protected: friend class nsExternalAppHandler; friend class nsExternalLoadRequest; /** * Helper function for ExpungeTemporaryFiles and ExpungeTemporaryPrivateFiles */ static void ExpungeTemporaryFilesHelper(nsCOMArray<nsIFile> &fileList); /** + * Helper function for DeleteTemporaryFileOnExit and DeleteTemporaryPrivateFileWhenPossible + */ + static nsresult DeleteTemporaryFileHelper(nsIFile* aTemporaryFile, + nsCOMArray<nsIFile> &aFileList); + /** * Functions related to the tempory file cleanup service provided by * nsExternalHelperAppService */ void ExpungeTemporaryFiles(); /** * Functions related to the tempory file cleanup service provided by * nsExternalHelperAppService (for the temporary files added during * the private browsing mode) @@ -187,20 +186,16 @@ protected: * Array for the files that should be deleted */ nsCOMArray<nsIFile> mTemporaryFilesList; /** * Array for the files that should be deleted (for the temporary files * added during the private browsing mode) */ nsCOMArray<nsIFile> mTemporaryPrivateFilesList; - /** - * Whether we are in private browsing mode - */ - bool mInPrivateBrowsing; }; /** * An external app handler is just a small little class that presents itself as * a nsIStreamListener. It saves the incoming data into a temp file. The handler * is bound to an application when it is created. When it receives an * OnStopRequest it launches the application using the temp file it has * stored the data into. We create a handler every time we have to process
--- a/uriloader/exthandler/nsIExternalHelperAppService.idl +++ b/uriloader/exthandler/nsIExternalHelperAppService.idl @@ -48,25 +48,30 @@ interface nsIExternalHelperAppService : in ACString aEncodingType); }; /** * This is a private interface shared between external app handlers and the platform specific * external helper app service */ -[scriptable, uuid(d0b5d7d3-9565-403d-9fb5-e5089c4567c6)] +[scriptable, uuid(6613e2e7-feab-4e3a-bb1f-b03200d544ec)] interface nsPIExternalAppLauncher : nsISupports { /** * mscott --> eventually I should move this into a new service so other * consumers can add temporary files they want deleted on exit. * @param aTemporaryFile A temporary file we should delete on exit. */ void deleteTemporaryFileOnExit(in nsIFile aTemporaryFile); + /** + * Delete a temporary file created inside private browsing mode when + * the private browsing mode has ended. + */ + void deleteTemporaryPrivateFileWhenPossible(in nsIFile aTemporaryFile); }; /** * A helper app launcher is a small object created to handle the launching * of an external application. * * Note that cancelling the load via the nsICancelable interface will release * the reference to the launcher dialog.
--- a/widget/xpwidgets/nsIdleService.cpp +++ b/widget/xpwidgets/nsIdleService.cpp @@ -173,16 +173,20 @@ nsIdleServiceDaily::~nsIdleServiceDaily( mTimer = nsnull; } } // static void nsIdleServiceDaily::DailyCallback(nsITimer* aTimer, void* aClosure) { +#ifdef ANDROID + __android_log_print(ANDROID_LOG_INFO, "IdleService", "DailyCallback running, registering Idle observer"); +#endif + nsIdleServiceDaily* me = static_cast<nsIdleServiceDaily*>(aClosure); // The one thing we do every day is to start waiting for the user to "have // a significant idle time". (void)me->mIdleService->AddIdleObserver(me, DAILY_SIGNIFICANT_IDLE_SERVICE_SEC); }
--- a/xpcom/base/nsDebugImpl.cpp +++ b/xpcom/base/nsDebugImpl.cpp @@ -38,16 +38,23 @@ #include <signal.h> #endif #if defined(XP_WIN) #include <tchar.h> #include "nsString.h" #endif +#if defined(XP_MACOSX) +#include <stdbool.h> +#include <sys/types.h> +#include <unistd.h> +#include <sys/sysctl.h> +#endif + #include "mozilla/mozalloc_abort.h" static void Abort(const char *aMsg); static void RealBreak(); @@ -131,16 +138,50 @@ nsDebugImpl::GetIsDebugBuild(bool* aResu NS_IMETHODIMP nsDebugImpl::GetAssertionCount(PRInt32* aResult) { *aResult = gAssertionCount; return NS_OK; } +NS_IMETHODIMP +nsDebugImpl::GetIsDebuggerAttached(bool* aResult) +{ + *aResult = false; + +#if defined(XP_WIN) + *aResult = ::IsDebuggerPresent(); +#elif defined(XP_MACOSX) + // Specify the info we're looking for + int mib[4]; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + size_t mibSize = sizeof(mib) / sizeof(int); + + struct kinfo_proc info; + size_t infoSize = sizeof(info); + memset(&info, 0, infoSize); + + if (sysctl(mib, mibSize, &info, &infoSize, NULL, 0)) { + // if the call fails, default to false + *aResult = false; + return NS_OK; + } + + if (info.kp_proc.p_flag & P_TRACED) { + *aResult = true; + } +#endif + + return NS_OK; +} + /* static */ void nsDebugImpl::SetMultiprocessMode(const char *aDesc) { sIsMultiprocess = true; sMultiprocessDescription = aDesc; } /**
--- a/xpcom/base/nsIDebug2.idl +++ b/xpcom/base/nsIDebug2.idl @@ -2,23 +2,29 @@ /* 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/. */ /* interface to expose information about calls to NS_DebugBreak */ #include "nsIDebug.idl" -[scriptable, uuid(9c9307ed-480a-4f2a-8f29-21378c03bcbc)] +[scriptable, uuid(6cb17fec-cdf7-4f7c-b267-37a0acaa9cf1)] interface nsIDebug2 : nsIDebug { /** * Whether XPCOM was compiled with DEBUG defined. This often * correlates to whether other code (e.g., Firefox, XULRunner) was * compiled with DEBUG defined. */ readonly attribute boolean isDebugBuild; /** * The number of assertions since process start. */ readonly attribute long assertionCount; + + /** + * Whether a debugger is currently attached. + * Supports Windows + Mac + */ + readonly attribute bool isDebuggerAttached; };