From 4c3757fad0eac358f545fee7be61e5c5d66dddc3 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Fri, 8 Nov 2013 18:00:21 -0500 Subject: [PATCH 01/52] Bug 936446 - Only define HasCPUIDBit on 32-bit platforms; r=jrmuizel --HG-- extra : rebase_source : 0728a7247cbb23e34cd7c6d2bfa57c5359ccef63 --- gfx/2d/Factory.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gfx/2d/Factory.cpp b/gfx/2d/Factory.cpp index ada6a857fbbf..3141e40269d3 100644 --- a/gfx/2d/Factory.cpp +++ b/gfx/2d/Factory.cpp @@ -68,6 +68,8 @@ enum CPUIDRegister { eax = 0, ebx = 1, ecx = 2, edx = 3 }; #ifdef HAVE_CPUID_H +#if !(defined(__SSE2__) || defined(_M_X64) || \ + (defined(_M_IX86_FP) && _M_IX86_FP >= 2)) // cpuid.h is available on gcc 4.3 and higher on i386 and x86_64 #include @@ -78,6 +80,7 @@ HasCPUIDBit(unsigned int level, CPUIDRegister reg, unsigned int bit) return __get_cpuid(level, ®s[0], ®s[1], ®s[2], ®s[3]) && (regs[reg] & bit); } +#endif #define HAVE_CPU_DETECTION #else From 2142e2edaef9892c24c25d648f31f0670ca13590 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 8 Nov 2013 23:05:39 +0000 Subject: [PATCH 02/52] Bug 923625 - DataStore sends the principal as argument in sendAsyncMessage, r=ehsan --- dom/datastore/DataStoreService.js | 32 ++++++++++++++-------- dom/datastore/DataStoreServiceInternal.jsm | 11 ++++++-- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/dom/datastore/DataStoreService.js b/dom/datastore/DataStoreService.js index 0fde3e3ebf86..68faed1154a7 100644 --- a/dom/datastore/DataStoreService.js +++ b/dom/datastore/DataStoreService.js @@ -236,8 +236,11 @@ DataStoreService.prototype = { // This method can be called in the child so we need to send a request // to the parent and create DataStore object here. new DataStoreServiceChild(aWindow, aName, function(aStores) { - debug("DataStoreServiceChild callback!"); + debug("DataStoreServiceChild success callback!"); self.getDataStoreCreate(aWindow, resolve, aStores); + }, function() { + debug("DataStoreServiceChild error callback!"); + reject(new aWindow.DOMError("SecurityError", "Access denied")); }); } }); @@ -425,32 +428,39 @@ DataStoreService.prototype = { /* DataStoreServiceChild */ -function DataStoreServiceChild(aWindow, aName, aCallback) { +function DataStoreServiceChild(aWindow, aName, aSuccessCb, aErrorCb) { debug("DataStoreServiceChild created"); - this.init(aWindow, aName, aCallback); + this.init(aWindow, aName, aSuccessCb, aErrorCb); } DataStoreServiceChild.prototype = { __proto__: DOMRequestIpcHelper.prototype, - init: function(aWindow, aName, aCallback) { + init: function(aWindow, aName, aSuccessCb, aErrorCb) { debug("DataStoreServiceChild init"); - this._callback = aCallback; + this._successCb = aSuccessCb; + this._errorCb = aErrorCb; - this.initDOMRequestHelper(aWindow, [ "DataStore:Get:Return" ]); + this.initDOMRequestHelper(aWindow, [ "DataStore:Get:Return:OK", + "DataStore:Get:Return:KO" ]); // This is a security issue and it will be fixed by Bug 916091 cpmm.sendAsyncMessage("DataStore:Get", - { name: aName, appId: aWindow.document.nodePrincipal.appId }); + { name: aName }, null, aWindow.document.nodePrincipal ); }, receiveMessage: function(aMessage) { debug("DataStoreServiceChild receiveMessage"); - if (aMessage.name != 'DataStore:Get:Return') { - return; - } - this._callback(aMessage.data.stores); + switch (aMessage.name) { + case 'DataStore:Get:Return:OK': + this._successCb(aMessage.data.stores); + break; + + case 'DataStore:Get:Return:KO': + this._errorCb(); + break; + } } } diff --git a/dom/datastore/DataStoreServiceInternal.jsm b/dom/datastore/DataStoreServiceInternal.jsm index 8bafc84c70bb..3bbbeee3958e 100644 --- a/dom/datastore/DataStoreServiceInternal.jsm +++ b/dom/datastore/DataStoreServiceInternal.jsm @@ -42,9 +42,14 @@ this.DataStoreServiceInternal = { let msg = aMessage.data; - // This is a security issue and it will be fixed by Bug 916091 - msg.stores = dataStoreService.getDataStoresInfo(msg.name, msg.appId); - aMessage.target.sendAsyncMessage("DataStore:Get:Return", msg); + if (!aMessage.principal || + aMessage.principal.appId == Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID) { + aMessage.target.sendAsyncMessage("DataStore:Get:Return:KO"); + return; + } + + msg.stores = dataStoreService.getDataStoresInfo(msg.name, aMessage.principal.appId); + aMessage.target.sendAsyncMessage("DataStore:Get:Return:OK", msg); } } From 4abbe765f13f6c59b841d84fb3dd2b068ed1399a Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 8 Nov 2013 23:07:50 +0000 Subject: [PATCH 03/52] Bug 933049 - Remove DataStore getChanges, r=ehsan --- dom/datastore/DataStore.jsm | 98 ------------- dom/datastore/tests/file_basic.html | 1 - dom/datastore/tests/file_revision.html | 196 ------------------------- dom/datastore/tests/mochitest.ini | 2 - dom/datastore/tests/test_revision.html | 140 ------------------ dom/webidl/DataStore.webidl | 10 -- 6 files changed, 447 deletions(-) delete mode 100644 dom/datastore/tests/file_revision.html delete mode 100644 dom/datastore/tests/test_revision.html diff --git a/dom/datastore/DataStore.jsm b/dom/datastore/DataStore.jsm index 45884bf2f260..c3c665acb479 100644 --- a/dom/datastore/DataStore.jsm +++ b/dom/datastore/DataStore.jsm @@ -458,104 +458,6 @@ this.DataStore.prototype = { return this._revisionId; }, - getChanges: function(aRevisionId) { - debug("GetChanges: " + aRevisionId); - - if (aRevisionId === null || aRevisionId === undefined) { - return this._window.Promise.reject( - new this._window.DOMError("SyntaxError", "Invalid revisionId")); - } - - let self = this; - - // Promise - return new this._window.Promise(function(aResolve, aReject) { - debug("GetChanges promise started"); - self._db.revisionTxn( - 'readonly', - function(aTxn, aStore) { - debug("GetChanges transaction success"); - - let request = self._db.getInternalRevisionId( - aRevisionId, - aStore, - function(aInternalRevisionId) { - if (aInternalRevisionId == undefined) { - aResolve(undefined); - return; - } - - // This object is the return value of this promise. - // Initially we use maps, and then we convert them in array. - let changes = { - revisionId: '', - addedIds: {}, - updatedIds: {}, - removedIds: {} - }; - - let request = aStore.mozGetAll(IDBKeyRange.lowerBound(aInternalRevisionId, true)); - request.onsuccess = function(aEvent) { - for (let i = 0; i < aEvent.target.result.length; ++i) { - let data = aEvent.target.result[i]; - - switch (data.operation) { - case REVISION_ADDED: - changes.addedIds[data.objectId] = true; - break; - - case REVISION_UPDATED: - // We don't consider an update if this object has been added - // or if it has been already modified by a previous - // operation. - if (!(data.objectId in changes.addedIds) && - !(data.objectId in changes.updatedIds)) { - changes.updatedIds[data.objectId] = true; - } - break; - - case REVISION_REMOVED: - let id = data.objectId; - - // If the object has been added in this range of revisions - // we can ignore it and remove it from the list. - if (id in changes.addedIds) { - delete changes.addedIds[id]; - } else { - changes.removedIds[id] = true; - } - - if (id in changes.updatedIds) { - delete changes.updatedIds[id]; - } - break; - } - } - - // The last revisionId. - if (aEvent.target.result.length) { - changes.revisionId = aEvent.target.result[aEvent.target.result.length - 1].revisionId; - } - - // From maps to arrays. - changes.addedIds = Object.keys(changes.addedIds).map(function(aKey) { return parseInt(aKey, 10); }); - changes.updatedIds = Object.keys(changes.updatedIds).map(function(aKey) { return parseInt(aKey, 10); }); - changes.removedIds = Object.keys(changes.removedIds).map(function(aKey) { return parseInt(aKey, 10); }); - - let wrappedObject = ObjectWrapper.wrap(changes, self._window); - aResolve(wrappedObject); - }; - } - ); - }, - function(aEvent) { - debug("GetChanges transaction failed"); - aReject(createDOMError(self._window, aEvent)); - } - ); - }); - }, - getLength: function() { let self = this; diff --git a/dom/datastore/tests/file_basic.html b/dom/datastore/tests/file_basic.html index addff1283c63..f6a8084429a7 100644 --- a/dom/datastore/tests/file_basic.html +++ b/dom/datastore/tests/file_basic.html @@ -39,7 +39,6 @@ ok("remove" in store, "store.remove exists"); ok("clear" in store, "store.clear exists"); ok("revisionId" in store, "store.revisionId exists"); - ok("getChanges" in store, "store.getChanges exists"); ok("getLength" in store, "store.getLength exists"); ok("sync" in store, "store.sync exists"); diff --git a/dom/datastore/tests/file_revision.html b/dom/datastore/tests/file_revision.html deleted file mode 100644 index 8781412145b7..000000000000 --- a/dom/datastore/tests/file_revision.html +++ /dev/null @@ -1,196 +0,0 @@ - - - - - Test for DataStore - basic operation on a readonly db - - -

- -
-  
-
- - - diff --git a/dom/datastore/tests/mochitest.ini b/dom/datastore/tests/mochitest.ini index cf3056acfce1..a13df2499244 100644 --- a/dom/datastore/tests/mochitest.ini +++ b/dom/datastore/tests/mochitest.ini @@ -3,7 +3,6 @@ support-files = file_app_install.html file_readonly.html file_basic.html - file_revision.html file_changes.html file_changes2.html file_app.sjs @@ -16,7 +15,6 @@ support-files = [test_app_install.html] [test_readonly.html] [test_basic.html] -[test_revision.html] [test_changes.html] [test_arrays.html] [test_oop.html] diff --git a/dom/datastore/tests/test_revision.html b/dom/datastore/tests/test_revision.html deleted file mode 100644 index 23846c8469b7..000000000000 --- a/dom/datastore/tests/test_revision.html +++ /dev/null @@ -1,140 +0,0 @@ - - - - - Test for DataStore - basic operation on a readonly db - - - - -

- -
-  
-
- - - diff --git a/dom/webidl/DataStore.webidl b/dom/webidl/DataStore.webidl index 320bb0ddd503..f2372d9ed7c7 100644 --- a/dom/webidl/DataStore.webidl +++ b/dom/webidl/DataStore.webidl @@ -39,22 +39,12 @@ interface DataStore : EventTarget { attribute EventHandler onchange; - // Promise - Promise getChanges(DOMString revisionId); - // Promise Promise getLength(); DataStoreCursor sync(optional DOMString revisionId = ""); }; -dictionary DataStoreChanges { - DOMString revisionId; - sequence addedIds; - sequence updatedIds; - sequence removedIds; -}; - [Pref="dom.datastore.enabled", JSImplementation="@mozilla.org/dom/datastore-cursor;1"] interface DataStoreCursor { From dc77f637fcb667c1491edcc12c90b93df24c0f02 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 8 Nov 2013 23:10:29 +0000 Subject: [PATCH 04/52] Bug 933050 - DataStore.add should receive an optional key value., r=ehsan --- dom/datastore/DataStore.jsm | 27 ++++++---- dom/datastore/DataStoreDB.jsm | 6 +-- dom/datastore/tests/file_arrays.html | 2 +- dom/datastore/tests/file_basic.html | 12 ++--- dom/datastore/tests/file_changes.html | 14 +++--- dom/datastore/tests/file_readonly.html | 6 +-- dom/datastore/tests/file_sync.html | 70 +++++++++++++------------- dom/webidl/DataStore.webidl | 4 +- 8 files changed, 74 insertions(+), 67 deletions(-) diff --git a/dom/datastore/DataStore.jsm b/dom/datastore/DataStore.jsm index c3c665acb479..f6b3ad6b6d0f 100644 --- a/dom/datastore/DataStore.jsm +++ b/dom/datastore/DataStore.jsm @@ -177,17 +177,17 @@ this.DataStore.prototype = { getInternalRequest(); }, - updateInternal: function(aResolve, aStore, aRevisionStore, aId, aObj) { - debug("UpdateInternal " + aId); + putInternal: function(aResolve, aStore, aRevisionStore, aObj, aId) { + debug("putInternal " + aId); let self = this; let request = aStore.put(aObj, aId); request.onsuccess = function(aEvent) { - debug("UpdateInternal success"); + debug("putInternal success"); self.addRevision(aRevisionStore, aId, REVISION_UPDATED, function() { - debug("UpdateInternal - revisionId increased"); + debug("putInternal - revisionId increased"); // No wrap here because the result is always a int. aResolve(aEvent.target.result); } @@ -195,11 +195,11 @@ this.DataStore.prototype = { }; }, - addInternal: function(aResolve, aStore, aRevisionStore, aObj) { + addInternal: function(aResolve, aStore, aRevisionStore, aObj, aId) { debug("AddInternal"); let self = this; - let request = aStore.put(aObj); + let request = aStore.add(aObj, aId); request.onsuccess = function(aEvent) { debug("Request successful. Id: " + aEvent.target.result); self.addRevision(aRevisionStore, aEvent.target.result, REVISION_ADDED, @@ -384,7 +384,7 @@ this.DataStore.prototype = { ); }, - update: function(aId, aObj) { + put: function(aObj, aId) { aId = parseInt(aId); if (isNaN(aId) || aId <= 0) { return throwInvalidArg(this._window); @@ -399,12 +399,19 @@ this.DataStore.prototype = { // Promise return this.newDBPromise("readwrite", function(aResolve, aReject, aTxn, aStore, aRevisionStore) { - self.updateInternal(aResolve, aStore, aRevisionStore, aId, aObj); + self.putInternal(aResolve, aStore, aRevisionStore, aObj, aId); } ); }, - add: function(aObj) { + add: function(aObj, aId) { + if (aId) { + aId = parseInt(aId); + if (isNaN(aId) || aId <= 0) { + return throwInvalidArg(this._window); + } + } + if (this._readOnly) { return throwReadOnly(this._window); } @@ -414,7 +421,7 @@ this.DataStore.prototype = { // Promise return this.newDBPromise("readwrite", function(aResolve, aReject, aTxn, aStore, aRevisionStore) { - self.addInternal(aResolve, aStore, aRevisionStore, aObj); + self.addInternal(aResolve, aStore, aRevisionStore, aObj, aId); } ); }, diff --git a/dom/datastore/DataStoreDB.jsm b/dom/datastore/DataStoreDB.jsm index c7f94a881a55..75c3fdb8af17 100644 --- a/dom/datastore/DataStoreDB.jsm +++ b/dom/datastore/DataStoreDB.jsm @@ -83,10 +83,10 @@ DataStoreDB.prototype = { ); }, - addRevision: function(aStore, aId, aType, aSuccessCb) { - debug("AddRevision: " + aId + " - " + aType); + addRevision: function(aStore, aKey, aType, aSuccessCb) { + debug("AddRevision: " + aKey + " - " + aType); let revisionId = uuidgen.generateUUID().toString(); - let request = aStore.put({ revisionId: revisionId, objectId: aId, operation: aType }); + let request = aStore.put({ revisionId: revisionId, objectId: aKey, operation: aType }); request.onsuccess = function() { aSuccessCb(revisionId); } diff --git a/dom/datastore/tests/file_arrays.html b/dom/datastore/tests/file_arrays.html index 263b5180cba9..3bff02693af1 100644 --- a/dom/datastore/tests/file_arrays.html +++ b/dom/datastore/tests/file_arrays.html @@ -34,7 +34,7 @@ var store = stores[0]; ok("get" in store, "store.get exists"); - ok("update" in store, "store.update exists"); + ok("put" in store, "store.put exists"); ok("add" in store, "store.add exists"); ok("remove" in store, "store.remove exists"); ok("clear" in store, "store.clear exists"); diff --git a/dom/datastore/tests/file_basic.html b/dom/datastore/tests/file_basic.html index f6a8084429a7..d46fe44fa030 100644 --- a/dom/datastore/tests/file_basic.html +++ b/dom/datastore/tests/file_basic.html @@ -34,7 +34,7 @@ var store = stores[0]; ok("get" in store, "store.get exists"); - ok("update" in store, "store.update exists"); + ok("put" in store, "store.put exists"); ok("add" in store, "store.add exists"); ok("remove" in store, "store.remove exists"); ok("clear" in store, "store.clear exists"); @@ -65,9 +65,9 @@ }, cbError); } - function testStoreUpdate(id, value) { - return gStore.update(id, value).then(function() { - ok(true, "store.update() is called"); + function testStorePut(value, id) { + return gStore.put(value, id).then(function() { + ok(true, "store.put() is called"); }, cbError); } @@ -113,8 +113,8 @@ gId = id; runTest(); }, cbError); }, function() { testStoreGet(gId, "hello world"); }, - // Update + Get - string - function() { testStoreUpdate(gId, "hello world 2").then(function() { + // Put + Get - string + function() { testStorePut("hello world 2", gId).then(function() { runTest(); }, cbError); }, function() { testStoreGet(gId, "hello world 2"); }, diff --git a/dom/datastore/tests/file_changes.html b/dom/datastore/tests/file_changes.html index 31ed89cc01a9..8f54936fad16 100644 --- a/dom/datastore/tests/file_changes.html +++ b/dom/datastore/tests/file_changes.html @@ -49,9 +49,9 @@ }, cbError); } - function testStoreUpdate(id, value) { - gStore.update(id, value).then(function(retId) { - is(id, retId, "store.update() is called with the right id"); + function testStorePut(value, id) { + gStore.put(value, id).then(function(retId) { + is(id, retId, "store.put() is called with the right id"); }, cbError); } @@ -84,9 +84,9 @@ function() { gChangeId = 1; gChangeOperation = 'added'; testStoreAdd({ number: 42 }, 1); }, - // Update + // Put function() { gChangeId = 1; gChangeOperation = 'updated'; - testStoreUpdate(1, { number: 43 }); }, + testStorePut({ number: 43 }, 1); }, // Remove function() { gChangeId = 1; gChangeOperation = 'removed'; @@ -103,9 +103,9 @@ function() { gChangeId = 2; gChangeOperation = 'added'; testStoreAdd({ number: 42 }, 2); }, - // Update + // Put function() { gChangeId = 2; gChangeOperation = 'updated'; - testStoreUpdate(2, { number: 43 }); }, + testStorePut({ number: 43 }, 2); }, // Remove function() { gChangeId = 2; gChangeOperation = 'removed'; diff --git a/dom/datastore/tests/file_readonly.html b/dom/datastore/tests/file_readonly.html index 64fbe31e7d91..f478a45dc8e1 100644 --- a/dom/datastore/tests/file_readonly.html +++ b/dom/datastore/tests/file_readonly.html @@ -33,7 +33,7 @@ var store = stores[0]; ok("get" in store, "store.get exists"); - ok("update" in store, "store.update exists"); + ok("put" in store, "store.put exists"); ok("add" in store, "store.add exists"); ok("remove" in store, "store.remove exists"); ok("clear" in store, "store.clear exists"); @@ -51,11 +51,11 @@ f = f.then(cbError, function() { ok(true, "store.add() fails because the db is readonly"); - return store.update(123, {}); + return store.put({}, 123); }) f = f.then(cbError, function() { - ok(true, "store.update() fails because the db is readonly"); + ok(true, "store.put() fails because the db is readonly"); }) f.then(function() { diff --git a/dom/datastore/tests/file_sync.html b/dom/datastore/tests/file_sync.html index 0f00d5fcf98f..b6a20bf47a97 100644 --- a/dom/datastore/tests/file_sync.html +++ b/dom/datastore/tests/file_sync.html @@ -133,14 +133,14 @@ function() { gExpectedEvents = true; - gStore.add(1).then(function(id) { + gStore.add(1,2).then(function(id) { gRevisions.push(gStore.revisionId); ok(true, "Iteme: " + id + " added"); }); }, function() { - gStore.add(2).then(function(id) { + gStore.add(2,3).then(function(id) { gRevisions.push(gStore.revisionId); ok(true, "Iteme: " + id + " added"); }); @@ -150,8 +150,8 @@ gExpectedEvents = false; var cursor = gStore.sync(); var steps = [ { operation: 'clear', }, - { operation: 'add', id: 1, data: 1 }, - { operation: 'add', id: 2, data: 2 }, + { operation: 'add', id: 2, data: 1 }, + { operation: 'add', id: 3, data: 2 }, { operation: 'done' }]; testCursor(cursor, steps); }, @@ -159,23 +159,23 @@ function() { var cursor = gStore.sync('wrong revision ID'); var steps = [ { operation: 'clear', }, - { operation: 'add', id: 1, data: 1 }, - { operation: 'add', id: 2, data: 2 }, + { operation: 'add', id: 2, data: 1 }, + { operation: 'add', id: 3, data: 2 }, { operation: 'done' }]; testCursor(cursor, steps); }, function() { var cursor = gStore.sync(gRevisions[0]); - var steps = [ { operation: 'add', id: 1, data: 1 }, - { operation: 'add', id: 2, data: 2 }, + var steps = [ { operation: 'add', id: 2, data: 1 }, + { operation: 'add', id: 3, data: 2 }, { operation: 'done' }]; testCursor(cursor, steps); }, function() { var cursor = gStore.sync(gRevisions[1]); - var steps = [ { operation: 'add', id: 2, data: 2 }, + var steps = [ { operation: 'add', id: 3, data: 2 }, { operation: 'done' }]; testCursor(cursor, steps); }, @@ -189,7 +189,7 @@ // Test after an update function() { gExpectedEvents = true; - gStore.update(1, 3).then(function() { + gStore.put(3, 2).then(function() { gRevisions.push(gStore.revisionId); }); }, @@ -198,8 +198,8 @@ gExpectedEvents = false; var cursor = gStore.sync(); var steps = [ { operation: 'clear', }, - { operation: 'add', id: 1, data: 3 }, - { operation: 'add', id: 2, data: 2 }, + { operation: 'add', id: 2, data: 3 }, + { operation: 'add', id: 3, data: 2 }, { operation: 'done' }]; testCursor(cursor, steps); }, @@ -207,31 +207,31 @@ function() { var cursor = gStore.sync('wrong revision ID'); var steps = [ { operation: 'clear', }, - { operation: 'add', id: 1, data: 3 }, - { operation: 'add', id: 2, data: 2 }, + { operation: 'add', id: 2, data: 3 }, + { operation: 'add', id: 3, data: 2 }, { operation: 'done' }]; testCursor(cursor, steps); }, function() { var cursor = gStore.sync(gRevisions[0]); - var steps = [ { operation: 'add', id: 1, data: 3 }, - { operation: 'add', id: 2, data: 2 }, + var steps = [ { operation: 'add', id: 2, data: 3 }, + { operation: 'add', id: 3, data: 2 }, { operation: 'done' }]; testCursor(cursor, steps); }, function() { var cursor = gStore.sync(gRevisions[1]); - var steps = [ { operation: 'add', id: 2, data: 2 }, - { operation: 'update', id: 1, data: 3 }, + var steps = [ { operation: 'add', id: 3, data: 2 }, + { operation: 'update', id: 2, data: 3 }, { operation: 'done' }]; testCursor(cursor, steps); }, function() { var cursor = gStore.sync(gRevisions[2]); - var steps = [ { operation: 'update', id: 1, data: 3 }, + var steps = [ { operation: 'update', id: 2, data: 3 }, { operation: 'done' }]; testCursor(cursor, steps); }, @@ -245,7 +245,7 @@ // Test after a remove function() { gExpectedEvents = true; - gStore.remove(2).then(function() { + gStore.remove(3).then(function() { gRevisions.push(gStore.revisionId); }); }, @@ -254,7 +254,7 @@ gExpectedEvents = false; var cursor = gStore.sync(); var steps = [ { operation: 'clear', }, - { operation: 'add', id: 1, data: 3 }, + { operation: 'add', id: 2, data: 3 }, { operation: 'done' }]; testCursor(cursor, steps); }, @@ -262,36 +262,36 @@ function() { var cursor = gStore.sync('wrong revision ID'); var steps = [ { operation: 'clear', }, - { operation: 'add', id: 1, data: 3 }, + { operation: 'add', id: 2, data: 3 }, { operation: 'done' }]; testCursor(cursor, steps); }, function() { var cursor = gStore.sync(gRevisions[0]); - var steps = [ { operation: 'add', id: 1, data: 3 }, + var steps = [ { operation: 'add', id: 2, data: 3 }, { operation: 'done' }]; testCursor(cursor, steps); }, function() { var cursor = gStore.sync(gRevisions[1]); - var steps = [ { operation: 'update', id: 1, data: 3 }, + var steps = [ { operation: 'update', id: 2, data: 3 }, { operation: 'done' }]; testCursor(cursor, steps); }, function() { var cursor = gStore.sync(gRevisions[2]); - var steps = [ { operation: 'update', id: 1, data: 3 }, - { operation: 'remove', id: 2 }, + var steps = [ { operation: 'update', id: 2, data: 3 }, + { operation: 'remove', id: 3 }, { operation: 'done' }]; testCursor(cursor, steps); }, function() { var cursor = gStore.sync(gRevisions[3]); - var steps = [ { operation: 'remove', id: 2 }, + var steps = [ { operation: 'remove', id: 3 }, { operation: 'done' }]; testCursor(cursor, steps); }, @@ -306,7 +306,7 @@ function() { gCursor = gStore.sync(); var steps = [ { operation: 'clear', }, - { operation: 'add', id: 1, data: 3 } ]; + { operation: 'add', id: 2, data: 3 } ]; testCursor(gCursor, steps); }, @@ -320,31 +320,31 @@ // New events when the cursor is active function() { - var steps = [ { operation: 'add', id: 3, data: 42 } ]; + var steps = [ { operation: 'add', id: 4, data: 42 } ]; testCursor(gCursor, steps); }, function() { - gStore.update(1, 42).then(function(id) { + gStore.put(42, 2).then(function(id) { gRevisions.push(gStore.revisionId); runTest(); }); }, function() { - var steps = [ { operation: 'update', id: 1, data: 42 } ]; + var steps = [ { operation: 'update', id: 2, data: 42 } ]; testCursor(gCursor, steps); }, function() { - gStore.remove(1).then(function(id) { + gStore.remove(2).then(function(id) { gRevisions.push(gStore.revisionId); runTest(); }); }, function() { - var steps = [ { operation: 'remove', id: 1 } ]; + var steps = [ { operation: 'remove', id: 2 } ]; testCursor(gCursor, steps); }, @@ -357,7 +357,7 @@ }, function() { - var steps = [ { operation: 'add', id: 4, data: 42 } ]; + var steps = [ { operation: 'add', id: 5, data: 42 } ]; testCursor(gCursor, steps); }, @@ -378,7 +378,7 @@ function() { var steps = [ { operation: 'clear' }, - { operation: 'add', id: 5, data: 42 }, + { operation: 'add', id: 6, data: 42 }, { operation: 'done' } ]; testCursor(gCursor, steps); }, diff --git a/dom/webidl/DataStore.webidl b/dom/webidl/DataStore.webidl index f2372d9ed7c7..e349f6a29646 100644 --- a/dom/webidl/DataStore.webidl +++ b/dom/webidl/DataStore.webidl @@ -24,10 +24,10 @@ interface DataStore : EventTarget { Promise get(sequence id); // Promise - Promise update(unsigned long id, any obj); + Promise put(any obj, unsigned long id); // Promise - Promise add(any obj); + Promise add(any obj, optional unsigned long id); // Promise Promise remove(unsigned long id); From b60db666b6c7b47e21135a58a3b1ce5de4253b72 Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Fri, 8 Nov 2013 15:14:53 -0800 Subject: [PATCH 05/52] Bug 933057 (Part 1) - Correct scaling of SVG images in nsLayoutUtils::DrawSingleImage. r=dholbert --- layout/base/nsLayoutUtils.cpp | 9 +++++++-- layout/svg/nsSVGImageFrame.cpp | 14 +++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index a61c205ebf12..6017629b2e15 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -4342,9 +4342,14 @@ nsLayoutUtils::DrawSingleImage(nsRenderingContext* aRenderingContext, { nsIntSize imageSize; if (aImage->GetType() == imgIContainer::TYPE_VECTOR) { - imageSize.width = nsPresContext::AppUnitsToIntCSSPixels(aDest.width); - imageSize.height = nsPresContext::AppUnitsToIntCSSPixels(aDest.height); + // We choose a size for vector images that emulates a raster image which + // is perfectly sized for the destination rect: each pixel in the image + // maps exactly to a single pixel on-screen. + nscoord appUnitsPerDevPx = aRenderingContext->AppUnitsPerDevPixel(); + imageSize.width = NSAppUnitsToIntPixels(aDest.width, appUnitsPerDevPx); + imageSize.height = NSAppUnitsToIntPixels(aDest.height, appUnitsPerDevPx); } else { + // Raster images have an intrinsic size, so we just use that. aImage->GetWidth(&imageSize.width); aImage->GetHeight(&imageSize.height); } diff --git a/layout/svg/nsSVGImageFrame.cpp b/layout/svg/nsSVGImageFrame.cpp index 21c30bf7632d..02687b3fd4fb 100644 --- a/layout/svg/nsSVGImageFrame.cpp +++ b/layout/svg/nsSVGImageFrame.cpp @@ -273,19 +273,19 @@ nsSVGImageFrame::TransformContextForPainting(gfxContext* aGfxContext, imageTransform = GetRasterImageTransform(nativeWidth, nativeHeight, FOR_PAINTING, aTransformRoot); + + // NOTE: We need to cancel out the effects of Full-Page-Zoom, or else + // it'll get applied an extra time by DrawSingleUnscaledImage. + nscoord appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel(); + gfxFloat pageZoomFactor = + nsPresContext::AppUnitsToFloatCSSPixels(appUnitsPerDevPx); + imageTransform.Scale(pageZoomFactor, pageZoomFactor); } if (imageTransform.IsSingular()) { return false; } - // NOTE: We need to cancel out the effects of Full-Page-Zoom, or else - // it'll get applied an extra time by DrawSingleUnscaledImage. - nscoord appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel(); - gfxFloat pageZoomFactor = - nsPresContext::AppUnitsToFloatCSSPixels(appUnitsPerDevPx); - imageTransform.Scale(pageZoomFactor, pageZoomFactor); - aGfxContext->Multiply(imageTransform); return true; } From 1547539f1a751ea9d6924ba2314f084946e167c1 Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Fri, 8 Nov 2013 15:14:58 -0800 Subject: [PATCH 06/52] Bug 933057 (Part 2) - Add tests for scaling explicitly sized svg:image elements in inline SVGs. r=dholbert --- .../image/image-svg-inline-zoom-in-01c.html | 18 ++++++++++++++++++ .../image/image-svg-inline-zoom-in-01d.html | 18 ++++++++++++++++++ .../image/image-svg-inline-zoom-out-01c.html | 17 +++++++++++++++++ .../image/image-svg-inline-zoom-out-01d.html | 17 +++++++++++++++++ layout/reftests/svg/image/lime100x100.svg | 3 +++ layout/reftests/svg/image/reftest.list | 4 ++++ 6 files changed, 77 insertions(+) create mode 100644 layout/reftests/svg/image/image-svg-inline-zoom-in-01c.html create mode 100644 layout/reftests/svg/image/image-svg-inline-zoom-in-01d.html create mode 100644 layout/reftests/svg/image/image-svg-inline-zoom-out-01c.html create mode 100644 layout/reftests/svg/image/image-svg-inline-zoom-out-01d.html create mode 100644 layout/reftests/svg/image/lime100x100.svg diff --git a/layout/reftests/svg/image/image-svg-inline-zoom-in-01c.html b/layout/reftests/svg/image/image-svg-inline-zoom-in-01c.html new file mode 100644 index 000000000000..9d273c91ec26 --- /dev/null +++ b/layout/reftests/svg/image/image-svg-inline-zoom-in-01c.html @@ -0,0 +1,18 @@ + + + + +
+ + + + +
+ + diff --git a/layout/reftests/svg/image/image-svg-inline-zoom-in-01d.html b/layout/reftests/svg/image/image-svg-inline-zoom-in-01d.html new file mode 100644 index 000000000000..921fa4ec2f12 --- /dev/null +++ b/layout/reftests/svg/image/image-svg-inline-zoom-in-01d.html @@ -0,0 +1,18 @@ + + + + +
+ + + + +
+ + diff --git a/layout/reftests/svg/image/image-svg-inline-zoom-out-01c.html b/layout/reftests/svg/image/image-svg-inline-zoom-out-01c.html new file mode 100644 index 000000000000..5c88134c033c --- /dev/null +++ b/layout/reftests/svg/image/image-svg-inline-zoom-out-01c.html @@ -0,0 +1,17 @@ + + + + +
+ + + + +
+ + diff --git a/layout/reftests/svg/image/image-svg-inline-zoom-out-01d.html b/layout/reftests/svg/image/image-svg-inline-zoom-out-01d.html new file mode 100644 index 000000000000..ad24ce81e5e8 --- /dev/null +++ b/layout/reftests/svg/image/image-svg-inline-zoom-out-01d.html @@ -0,0 +1,17 @@ + + + + +
+ + + + +
+ + diff --git a/layout/reftests/svg/image/lime100x100.svg b/layout/reftests/svg/image/lime100x100.svg new file mode 100644 index 000000000000..bba9d342368a --- /dev/null +++ b/layout/reftests/svg/image/lime100x100.svg @@ -0,0 +1,3 @@ + + + diff --git a/layout/reftests/svg/image/reftest.list b/layout/reftests/svg/image/reftest.list index 492e5d10b878..5a4d59ddfaa5 100644 --- a/layout/reftests/svg/image/reftest.list +++ b/layout/reftests/svg/image/reftest.list @@ -13,8 +13,12 @@ fuzzy-if(Android,4,34) == image-opacity-02.svg image-opacity-02-ref.svg # Bug 77 == image-svg-inline-01.html ../pass.svg == image-svg-inline-zoom-in-01a.html ../pass.svg == image-svg-inline-zoom-in-01b.html ../pass.svg +== image-svg-inline-zoom-in-01c.html ../pass.svg +== image-svg-inline-zoom-in-01d.html ../pass.svg == image-svg-inline-zoom-out-01a.html ../pass.svg == image-svg-inline-zoom-out-01b.html ../pass.svg +== image-svg-inline-zoom-out-01c.html ../pass.svg +== image-svg-inline-zoom-out-01d.html ../pass.svg == image-svg-inline-sprite-zoom-in-01a.html image-svg-inline-sprite-zoom-in-01-ref.html == image-svg-inline-sprite-zoom-in-01b.html image-svg-inline-sprite-zoom-in-01-ref.html == image-svg-inline-sprite-zoom-out-01a.html image-svg-inline-sprite-zoom-out-01-ref.html From ea4ea922573b27ea1093a58b6ef50ee137a508c2 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Sat, 9 Nov 2013 01:29:02 +0200 Subject: [PATCH 07/52] Bug 936495 - Reorder is-this-listener-added-already-to-ELM check , r=bz --- content/events/src/nsEventListenerManager.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/content/events/src/nsEventListenerManager.cpp b/content/events/src/nsEventListenerManager.cpp index 211aa72708cb..17b2fd2d583d 100644 --- a/content/events/src/nsEventListenerManager.cpp +++ b/content/events/src/nsEventListenerManager.cpp @@ -228,10 +228,11 @@ nsEventListenerManager::AddEventListenerInternal( uint32_t count = mListeners.Length(); for (uint32_t i = 0; i < count; i++) { ls = &mListeners.ElementAt(i); - if (ls->mListener == aListener && - ls->mListenerIsHandler == aHandler && + // mListener == aListener is the last one, since it can be a bit slow. + if (ls->mListenerIsHandler == aHandler && ls->mFlags == aFlags && - EVENT_TYPE_EQUALS(ls, aType, aTypeAtom, aTypeString, aAllEvents)) { + EVENT_TYPE_EQUALS(ls, aType, aTypeAtom, aTypeString, aAllEvents) && + ls->mListener == aListener) { return; } } From ac66795d8050245ee65ec6f0ffa07c904382b727 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Sat, 9 Nov 2013 01:29:09 +0200 Subject: [PATCH 08/52] Bug 732815, make Atom's hash value to be the same what strings use, r=bz --- content/base/src/nsNodeInfoManager.cpp | 8 +- xpcom/ds/nsAtomTable.cpp | 104 +++++++++++++++---------- 2 files changed, 66 insertions(+), 46 deletions(-) diff --git a/content/base/src/nsNodeInfoManager.cpp b/content/base/src/nsNodeInfoManager.cpp index 9638cf546441..ea7bf5104393 100644 --- a/content/base/src/nsNodeInfoManager.cpp +++ b/content/base/src/nsNodeInfoManager.cpp @@ -47,13 +47,7 @@ nsNodeInfoManager::GetNodeInfoInnerHashValue(const void *key) const nsINodeInfo::nsNodeInfoInner *node = reinterpret_cast(key); - if (node->mName) { - // Ideally, we'd return node->mName->hash() here. But that doesn't work at - // the moment because node->mName->hash() is not the same as - // HashString(*(node->mNameString)). See bug 732815. - return HashString(nsDependentAtomString(node->mName)); - } - return HashString(*(node->mNameString)); + return node->mName ? node->mName->hash() : HashString(*(node->mNameString)); } diff --git a/xpcom/ds/nsAtomTable.cpp b/xpcom/ds/nsAtomTable.cpp index 1035afbaceac..e33066fa0dfa 100644 --- a/xpcom/ds/nsAtomTable.cpp +++ b/xpcom/ds/nsAtomTable.cpp @@ -8,6 +8,7 @@ #include "mozilla/Attributes.h" #include "mozilla/HashFunctions.h" #include "mozilla/MemoryReporting.h" +#include "mozilla/DebugOnly.h" #include "nsAtomTable.h" #include "nsStaticAtom.h" @@ -54,11 +55,11 @@ static bool gStaticAtomTableSealed = false; class AtomImpl : public nsIAtom { public: - AtomImpl(const nsAString& aString, PLDHashNumber aKeyHash); + AtomImpl(const nsAString& aString, uint32_t aHash); // This is currently only used during startup when creating a permanent atom // from NS_RegisterStaticAtoms - AtomImpl(nsStringBuffer* aData, uint32_t aLength, PLDHashNumber aKeyHash); + AtomImpl(nsStringBuffer* aData, uint32_t aLength, uint32_t aHash); protected: // This is only intended to be used when a normal atom is turned into a @@ -135,43 +136,63 @@ struct AtomTableEntry : public PLDHashEntryHdr { struct AtomTableKey { - AtomTableKey(const PRUnichar* aUTF16String, uint32_t aLength) + AtomTableKey(const PRUnichar* aUTF16String, uint32_t aLength, + /*inout*/ uint32_t& aHash) : mUTF16String(aUTF16String), mUTF8String(nullptr), mLength(aLength) { + if (aHash) { + MOZ_ASSERT(aHash == HashString(mUTF16String, mLength)); + mHash = aHash; + } else { + UpdateHashKey(); + aHash = mHash; + } } - AtomTableKey(const char* aUTF8String, uint32_t aLength) + AtomTableKey(const char* aUTF8String, uint32_t aLength, + /*inout*/ uint32_t& aHash) : mUTF16String(nullptr), mUTF8String(aUTF8String), mLength(aLength) { + if (aHash) { + mozilla::DebugOnly err; + MOZ_ASSERT(aHash == HashUTF8AsUTF16(mUTF8String, mLength, &err)); + mHash = aHash; + } else { + UpdateHashKey(); + aHash = mHash; + } } const PRUnichar* mUTF16String; const char* mUTF8String; uint32_t mLength; + uint32_t mHash; + + void UpdateHashKey() + { + if (mUTF8String) { + bool err; + mHash = HashUTF8AsUTF16(mUTF8String, mLength, &err); + if (err) { + mUTF8String = nullptr; + mLength = 0; + mHash = 0; + } + } else { + mHash = HashString(mUTF16String, mLength); + } + } }; static PLDHashNumber AtomTableGetHash(PLDHashTable *table, const void *key) { const AtomTableKey *k = static_cast(key); - - if (k->mUTF8String) { - bool err; - uint32_t hash = HashUTF8AsUTF16(k->mUTF8String, k->mLength, &err); - if (err) { - AtomTableKey* mutableKey = const_cast(k); - mutableKey->mUTF8String = nullptr; - mutableKey->mLength = 0; - hash = 0; - } - return hash; - } - - return HashString(k->mUTF16String, k->mLength); + return k->mHash; } static bool @@ -292,7 +313,7 @@ NS_PurgeAtomTable() } } -AtomImpl::AtomImpl(const nsAString& aString, PLDHashNumber aKeyHash) +AtomImpl::AtomImpl(const nsAString& aString, uint32_t aHash) { mLength = aString.Length(); nsRefPtr buf = nsStringBuffer::FromString(aString); @@ -305,9 +326,8 @@ AtomImpl::AtomImpl(const nsAString& aString, PLDHashNumber aKeyHash) mString[mLength] = PRUnichar(0); } - // The low bit of aKeyHash is generally useless, so shift it out - MOZ_ASSERT(sizeof(mHash) == sizeof(PLDHashNumber)); - mHash = aKeyHash >> 1; + mHash = aHash; + MOZ_ASSERT(mHash == HashString(mString, mLength)); NS_ASSERTION(mString[mLength] == PRUnichar(0), "null terminated"); NS_ASSERTION(buf && buf->StorageSize() >= (mLength+1) * sizeof(PRUnichar), @@ -319,7 +339,7 @@ AtomImpl::AtomImpl(const nsAString& aString, PLDHashNumber aKeyHash) } AtomImpl::AtomImpl(nsStringBuffer* aStringBuffer, uint32_t aLength, - PLDHashNumber aKeyHash) + uint32_t aHash) { mLength = aLength; mString = static_cast(aStringBuffer->Data()); @@ -327,9 +347,8 @@ AtomImpl::AtomImpl(nsStringBuffer* aStringBuffer, uint32_t aLength, // the static atom buffers have an initial refcount of 2. aStringBuffer->AddRef(); - // The low bit of aKeyHash is generally useless, so shift it out - MOZ_ASSERT(sizeof(mHash) == sizeof(PLDHashNumber)); - mHash = aKeyHash >> 1; + mHash = aHash; + MOZ_ASSERT(mHash == HashString(mString, mLength)); NS_ASSERTION(mString[mLength] == PRUnichar(0), "null terminated"); NS_ASSERTION(aStringBuffer && @@ -344,7 +363,7 @@ AtomImpl::~AtomImpl() // don't want to remove them twice. See comment above in // |AtomTableClearEntry|. if (!IsPermanentInDestructor()) { - AtomTableKey key(mString, mLength); + AtomTableKey key(mString, mLength, mHash); PL_DHashTableOperate(&gAtomTable, &key, PL_DHASH_REMOVE); if (gAtomTable.entryCount == 0) { PL_DHashTableFinish(&gAtomTable); @@ -493,11 +512,11 @@ EnsureTableExists() } static inline AtomTableEntry* -GetAtomHashEntry(const char* aString, uint32_t aLength) +GetAtomHashEntry(const char* aString, uint32_t aLength, uint32_t& aHash) { MOZ_ASSERT(NS_IsMainThread(), "wrong thread"); EnsureTableExists(); - AtomTableKey key(aString, aLength); + AtomTableKey key(aString, aLength, aHash); AtomTableEntry* e = static_cast (PL_DHashTableOperate(&gAtomTable, &key, PL_DHASH_ADD)); @@ -508,11 +527,11 @@ GetAtomHashEntry(const char* aString, uint32_t aLength) } static inline AtomTableEntry* -GetAtomHashEntry(const PRUnichar* aString, uint32_t aLength) +GetAtomHashEntry(const PRUnichar* aString, uint32_t aLength, uint32_t& aHash) { MOZ_ASSERT(NS_IsMainThread(), "wrong thread"); EnsureTableExists(); - AtomTableKey key(aString, aLength); + AtomTableKey key(aString, aLength, aHash); AtomTableEntry* e = static_cast (PL_DHashTableOperate(&gAtomTable, &key, PL_DHASH_ADD)); @@ -558,9 +577,10 @@ RegisterStaticAtoms(const nsStaticAtom* aAtoms, uint32_t aAtomCount) uint32_t stringLen = aAtoms[i].mStringBuffer->StorageSize() / sizeof(PRUnichar) - 1; + uint32_t hash = 0; AtomTableEntry *he = GetAtomHashEntry((PRUnichar*)aAtoms[i].mStringBuffer->Data(), - stringLen); + stringLen, hash); if (he->mAtom) { // there already is an atom with this name in the table.. but we @@ -577,7 +597,7 @@ RegisterStaticAtoms(const nsStaticAtom* aAtoms, uint32_t aAtomCount) else { AtomImpl* atom = new PermanentAtomImpl(aAtoms[i].mStringBuffer, stringLen, - he->keyHash); + hash); he->mAtom = atom; *aAtoms[i].mAtom = atom; @@ -598,8 +618,10 @@ NS_NewAtom(const char* aUTF8String) already_AddRefed NS_NewAtom(const nsACString& aUTF8String) { + uint32_t hash = 0; AtomTableEntry *he = GetAtomHashEntry(aUTF8String.Data(), - aUTF8String.Length()); + aUTF8String.Length(), + hash); if (he->mAtom) { nsCOMPtr atom = he->mAtom; @@ -612,7 +634,7 @@ NS_NewAtom(const nsACString& aUTF8String) // Actually, now there is, sort of: ForgetSharedBuffer. nsString str; CopyUTF8toUTF16(aUTF8String, str); - nsRefPtr atom = new AtomImpl(str, he->keyHash); + nsRefPtr atom = new AtomImpl(str, hash); he->mAtom = atom; @@ -628,8 +650,10 @@ NS_NewAtom(const PRUnichar* aUTF16String) already_AddRefed NS_NewAtom(const nsAString& aUTF16String) { + uint32_t hash = 0; AtomTableEntry *he = GetAtomHashEntry(aUTF16String.Data(), - aUTF16String.Length()); + aUTF16String.Length(), + hash); if (he->mAtom) { nsCOMPtr atom = he->mAtom; @@ -637,7 +661,7 @@ NS_NewAtom(const nsAString& aUTF16String) return atom.forget(); } - nsRefPtr atom = new AtomImpl(aUTF16String, he->keyHash); + nsRefPtr atom = new AtomImpl(aUTF16String, hash); he->mAtom = atom; return atom.forget(); @@ -646,8 +670,10 @@ NS_NewAtom(const nsAString& aUTF16String) nsIAtom* NS_NewPermanentAtom(const nsAString& aUTF16String) { + uint32_t hash = 0; AtomTableEntry *he = GetAtomHashEntry(aUTF16String.Data(), - aUTF16String.Length()); + aUTF16String.Length(), + hash); AtomImpl* atom = he->mAtom; if (atom) { @@ -656,7 +682,7 @@ NS_NewPermanentAtom(const nsAString& aUTF16String) } } else { - atom = new PermanentAtomImpl(aUTF16String, he->keyHash); + atom = new PermanentAtomImpl(aUTF16String, hash); he->mAtom = atom; } From 4fea685b6325e89a0a23d8825341c8836d97ce39 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Fri, 8 Nov 2013 16:05:33 -0800 Subject: [PATCH 09/52] Bug 936681 - Correctly print stderr for jit-test failures (r=terrence) --- js/src/tests/lib/jittests.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/src/tests/lib/jittests.py b/js/src/tests/lib/jittests.py index 1bb2890bff4c..fd10c5c5c768 100755 --- a/js/src/tests/lib/jittests.py +++ b/js/src/tests/lib/jittests.py @@ -390,9 +390,9 @@ def print_tinderbox(ok, res): print("INFO exit-status : {}".format(res.rc)) print("INFO timed-out : {}".format(res.timed_out)) for line in res.out.split('\n'): - print("INFO stdout > " + line) - for line in res.out.split('\n'): - print("INFO stderr 2> " + line) + print("INFO stdout > " + line.strip()) + for line in res.err.split('\n'): + print("INFO stderr 2> " + line.strip()) def wrap_parallel_run_test(test, prefix, resultQueue, options): # Ignore SIGINT in the child From 833d12d59267920f4475b98cdc27d7add93a104a Mon Sep 17 00:00:00 2001 From: Alexander Surkov Date: Fri, 8 Nov 2013 19:25:29 -0500 Subject: [PATCH 10/52] Bug 933322 - menustart/end events are missing when aria-owns makes a menu hierarchy, r=tbsaunde --- accessible/src/base/FocusManager.cpp | 27 +++++++++++++++-- accessible/src/base/nsAccUtils.cpp | 16 ---------- accessible/src/base/nsAccUtils.h | 11 ------- .../mochitest/events/test_aria_menu.html | 29 ++++++++++++++++--- 4 files changed, 50 insertions(+), 33 deletions(-) diff --git a/accessible/src/base/FocusManager.cpp b/accessible/src/base/FocusManager.cpp index 792784fb9578..0b7e03bc1c3e 100644 --- a/accessible/src/base/FocusManager.cpp +++ b/accessible/src/base/FocusManager.cpp @@ -5,6 +5,7 @@ #include "FocusManager.h" #include "Accessible-inl.h" +#include "AccIterator.h" #include "DocAccessible-inl.h" #include "nsAccessibilityService.h" #include "nsAccUtils.h" @@ -288,8 +289,30 @@ FocusManager::ProcessFocusEvent(AccEvent* aEvent) // Fire menu start/end events for ARIA menus. if (target->ARIARole() == roles::MENUITEM) { // The focus was moved into menu. - Accessible* ARIAMenubar = - nsAccUtils::GetAncestorWithRole(target, roles::MENUBAR); + Accessible* ARIAMenubar = nullptr; + Accessible* child = target; + Accessible* parent = child->Parent(); + while (parent) { + nsRoleMapEntry* roleMap = parent->ARIARoleMap(); + if (roleMap) { + if (roleMap->Is(nsGkAtoms::menubar)) { + ARIAMenubar = parent; + break; + } + + // Go up in the parent chain of the menu hierarchy. + if (roleMap->Is(nsGkAtoms::menuitem) || roleMap->Is(nsGkAtoms::menu)) { + child = parent; + parent = child->Parent(); + continue; + } + } + + // If no required context role then check aria-owns relation. + RelatedAccIterator iter(child->Document(), child->GetContent(), + nsGkAtoms::aria_owns); + parent = iter.Next(); + } if (ARIAMenubar != mActiveARIAMenubar) { // Leaving ARIA menu. Fire menu_end event on current menubar. diff --git a/accessible/src/base/nsAccUtils.cpp b/accessible/src/base/nsAccUtils.cpp index 3b1bf2447022..4dcc70b08afa 100644 --- a/accessible/src/base/nsAccUtils.cpp +++ b/accessible/src/base/nsAccUtils.cpp @@ -210,22 +210,6 @@ nsAccUtils::GetARIAToken(dom::Element* aElement, nsIAtom* aAttr) return nullptr; } -Accessible* -nsAccUtils::GetAncestorWithRole(Accessible* aDescendant, uint32_t aRole) -{ - Accessible* document = aDescendant->Document(); - Accessible* parent = aDescendant; - while ((parent = parent->Parent())) { - uint32_t testRole = parent->Role(); - if (testRole == aRole) - return parent; - - if (parent == document) - break; - } - return nullptr; -} - Accessible* nsAccUtils::GetSelectableContainer(Accessible* aAccessible, uint64_t aState) { diff --git a/accessible/src/base/nsAccUtils.h b/accessible/src/base/nsAccUtils.h index 2f09a4f88bdc..6b939d2d9ec5 100644 --- a/accessible/src/base/nsAccUtils.h +++ b/accessible/src/base/nsAccUtils.h @@ -116,17 +116,6 @@ public: return GetAccService()->GetDocAccessible(docShell->GetPresShell()); } - /** - * Return ancestor in this document with the given role if it exists. - * - * @param aDescendant [in] descendant to start search with - * @param aRole [in] role to find matching ancestor for - * @return the ancestor accessible with the given role, or - * nullptr if no match is found - */ - static Accessible* GetAncestorWithRole(Accessible* aDescendant, - uint32_t aRole); - /** * Return single or multi selectable container for the given item. * diff --git a/accessible/tests/mochitest/events/test_aria_menu.html b/accessible/tests/mochitest/events/test_aria_menu.html index a361a72013c9..0259c5f57b7a 100644 --- a/accessible/tests/mochitest/events/test_aria_menu.html +++ b/accessible/tests/mochitest/events/test_aria_menu.html @@ -165,6 +165,10 @@ gQueue.push(new focusInsideMenu("menu-edit", "menubar")); gQueue.push(new blurMenu("menubar")); + gQueue.push(new focusMenu("menubar3", "mb3-mi-outside")); + gQueue.push(new showMenu("mb4-menu", document, kViaDisplayStyle)); + gQueue.push(new focusMenu("menubar4", "mb4-item1")); + gQueue.invoke(); // Will call SimpleTest.finish(); } @@ -178,22 +182,27 @@ - Mozilla Bug 606207 + Bug 606207 - Mozilla Bug 614829 + Bug 614829 - Mozilla Bug 615189 + Bug 615189 - Mozilla Bug 673958 + Bug 673958 + + + Bug 933322

@@ -227,6 +236,18 @@
outsidemenu
+ + + + + + +
From 59651bdb5d5919e9691faf8df50421c350e6be4f Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Fri, 8 Nov 2013 12:04:54 +1300 Subject: [PATCH 11/52] crashtest for bug 933156 --HG-- extra : transplant_source : %9D/%19%13%80%D3cY%5D%93%FA%17%FB%CFTO%5Ex%82%C9 --- content/media/test/crashtests/933156.html | 23 +++++++++++++++++++ content/media/test/crashtests/crashtests.list | 1 + 2 files changed, 24 insertions(+) create mode 100644 content/media/test/crashtests/933156.html diff --git a/content/media/test/crashtests/933156.html b/content/media/test/crashtests/933156.html new file mode 100644 index 000000000000..b89445a43dc3 --- /dev/null +++ b/content/media/test/crashtests/933156.html @@ -0,0 +1,23 @@ + + + + diff --git a/content/media/test/crashtests/crashtests.list b/content/media/test/crashtests/crashtests.list index 2fdf7318e70d..3baaff36fe59 100644 --- a/content/media/test/crashtests/crashtests.list +++ b/content/media/test/crashtests/crashtests.list @@ -61,6 +61,7 @@ load 925619-1.html load 925619-2.html load 926619.html load 933151.html +load 933156.html load offline-buffer-source-ended-1.html skip-if(B2G) load oscillator-ended-1.html # intermittent B2G timeouts, bug 920338 skip-if(B2G) load oscillator-ended-2.html # intermittent B2G timeouts, bug 920338 From 5067764d6911acae5c06b00665dacd93ba70b8e8 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Sat, 9 Nov 2013 14:07:45 +1300 Subject: [PATCH 12/52] b=936317 prevent MediaBufferDecoder threads from waiting after AudioContext shutdown() r=ehsan --HG-- extra : transplant_source : %CE%E5O%83N%8FX%ED%2Ck%17I%B1%92%B6%A0lXH%D1 --- content/media/webaudio/AudioContext.cpp | 2 ++ content/media/webaudio/MediaBufferDecoder.cpp | 11 +++++++++++ content/media/webaudio/MediaBufferDecoder.h | 2 ++ 3 files changed, 15 insertions(+) diff --git a/content/media/webaudio/AudioContext.cpp b/content/media/webaudio/AudioContext.cpp index a559f7f36bc0..c757d574a6b4 100644 --- a/content/media/webaudio/AudioContext.cpp +++ b/content/media/webaudio/AudioContext.cpp @@ -535,6 +535,8 @@ AudioContext::Shutdown() Suspend(); + mDecoder.Shutdown(); + // Release references to active nodes. // Active AudioNodes don't unregister in destructors, at which point the // Node is already unregistered. diff --git a/content/media/webaudio/MediaBufferDecoder.cpp b/content/media/webaudio/MediaBufferDecoder.cpp index a847b335030c..51fc9e6b4fed 100644 --- a/content/media/webaudio/MediaBufferDecoder.cpp +++ b/content/media/webaudio/MediaBufferDecoder.cpp @@ -539,6 +539,17 @@ MediaBufferDecoder::EnsureThreadPoolInitialized() return true; } +void +MediaBufferDecoder::Shutdown() { + if (mThreadPool) { + // Setting threadLimit to 0 causes threads to exit when all events have + // been run, like nsIThreadPool::Shutdown(), but doesn't run a nested event + // loop nor wait until this has happened. + mThreadPool->SetThreadLimit(0); + mThreadPool = nullptr; + } +} + WebAudioDecodeJob::WebAudioDecodeJob(const nsACString& aContentType, AudioContext* aContext, const ArrayBuffer& aBuffer, diff --git a/content/media/webaudio/MediaBufferDecoder.h b/content/media/webaudio/MediaBufferDecoder.h index c5c42aa46b7d..56bad005bbf6 100644 --- a/content/media/webaudio/MediaBufferDecoder.h +++ b/content/media/webaudio/MediaBufferDecoder.h @@ -80,6 +80,8 @@ public: bool SyncDecodeMedia(const char* aContentType, uint8_t* aBuffer, uint32_t aLength, WebAudioDecodeJob& aDecodeJob); + void Shutdown(); + private: bool EnsureThreadPoolInitialized(); From 16c053863297b05dc0f258177841f6cb85085afd Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Sat, 9 Nov 2013 14:07:50 +1300 Subject: [PATCH 13/52] b=931311 wait for HRTF panner to load impulse database before doing test --HG-- extra : transplant_source : %2A%1F%D0kKSr%AA%8F%C1%26%E5%E6%EC%D5%CF%8C%A9%D11 --- .../webaudio/test/test_pannerNodeTail.html | 88 ++++++++++++------- 1 file changed, 58 insertions(+), 30 deletions(-) diff --git a/content/media/webaudio/test/test_pannerNodeTail.html b/content/media/webaudio/test/test_pannerNodeTail.html index c60fbc0cab86..12efbae4d6f4 100644 --- a/content/media/webaudio/test/test_pannerNodeTail.html +++ b/content/media/webaudio/test/test_pannerNodeTail.html @@ -27,7 +27,7 @@ // // Web Audio doesn't provide a means to precisely time connect()s but we can // test that the output of delay nodes matches the output from a reference -// PannerNodes that we know will not be GCed. +// PannerNode that we know will not be GCed. // // Another set of delay nodes is added upstream to ensure that the source node // has removed its self-reference after dispatching its "ended" event. @@ -41,15 +41,14 @@ const blockSize = 128; const bufferSize = 4096; const pannerCount = bufferSize / blockSize; // sourceDelayBufferCount should be long enough to allow the source node -// onended to finish. Because of the way blocks are processed in sets on -// the graph thread, this also affects when the graph thread receives the -// disconnect. +// onended to finish and remove the source self-reference. const sourceDelayBufferCount = 3; var gotEnded = false; // ccDelayLength should be long enough to allow CC to run var ccDelayBufferCount = 20; const ccDelayLength = ccDelayBufferCount * bufferSize; +var ctx; var testPanners = []; var referencePanner; var referenceProcessCount = 0; @@ -58,18 +57,27 @@ var referenceOutput = [new Float32Array(bufferSize), var testProcessor; var testProcessCount = 0; +function isChannelSilent(channel) { + for (var i = 0; i < channel.length; ++i) { + if (channel[i] != 0.0) { + dump("input at " + i + "\n"); + return false; + } + } + return true; +} + function onReferenceOutput(e) { switch(referenceProcessCount) { case sourceDelayBufferCount - 1: // The panners are about to finish. if (!gotEnded) { - todo(false, "Oscillator hasn't ended. Increase sourceDelayBufferCount?"); + todo(false, "Source hasn't ended. Increase sourceDelayBufferCount?"); } // Connect each PannerNode output to a downstream DelayNode, // and connect ScriptProcessors to compare test and reference panners. - var ctx = e.target.context; var delayDuration = ccDelayLength / ctx.sampleRate; for (var i = 0; i < pannerCount; ++i) { var delay = ctx.createDelay(delayDuration); @@ -80,6 +88,9 @@ function onReferenceOutput(e) { testProcessor = null; testPanners = null; + // The panning effect is linear so only one reference panner is required. + // This also checks that the individual panners don't chop their output + // too soon. referencePanner.connect(e.target); // Assuming the above operations have already scheduled an event to run in @@ -101,16 +112,13 @@ function onReferenceOutput(e) { e.target.onaudioprocess = null; e.target.disconnect(); - for (var i = 0; i < referenceOutput[0].length; ++i) { - if (referenceOutput[0][i] != 0.0) { - return; // good - a connection must have been received by the graph - } - } // If the buffer is silent, there is probably not much point just // increasing the buffer size, because, with the buffer size already // significantly larger than panner tail time, it demonstrates that the // lag between threads is much greater than the tail time. - todo(false, "Connections not detected."); + if (isChannelSilent(referenceOutput[0])) { + todo(false, "Connections not detected."); + } } referenceProcessCount++; @@ -131,36 +139,30 @@ function onTestOutput(e) { } function startTest() { - var ctx = new AudioContext(); - // Place the listener to the side of the origin, where the panners are - // positioned, to maximize delay in one ear. - ctx.listener.setPosition(1,0,0); - // 0.002 is MaxDelayTimeSeconds in HRTFpanner.cpp // and 512 is fftSize() at 48 kHz. const expectedPannerTailTime = 0.002 * ctx.sampleRate + 512; // Create some PannerNodes downstream from DelayNodes with delays long - // enough for their source oscillator to finish, dispatch its "ended" event + // enough for their source to finish, dispatch its "ended" event // and release its playing reference. The DelayNodes should expire their // tail-time references before the PannerNodes and so only the PannerNode // lifetimes depends on their tail-time references. Many DelayNodes are // created and timed to finish at different times so that one PannerNode // will be finishing the block processed immediately after the connect is // received. - var oscillator = ctx.createOscillator(); - oscillator.start(0); + var source = ctx.createBufferSource(); // Just short of blockSize here to avoid rounding into the next block - oscillator.stop((blockSize - 1) / ctx.sampleRate); - oscillator.onended = function(e) { + var buffer = ctx.createBuffer(1, blockSize - 1, ctx.sampleRate); + for (var i = 0; i < buffer.length; ++i) { + buffer.getChannelData(0)[i] = Math.cos(Math.PI * i / buffer.length); + } + source.buffer = buffer; + source.start(0); + source.onended = function(e) { gotEnded = true; }; - // The panner effect is linear so only one reference panner is required. - // This also checks that the individual panners don't chop their output too - // soon. - referencePanner = ctx.createPanner(); - // Time the first test panner to finish just before downstream DelayNodes // are about the be connected. Note that DelayNode lifetime depends on // maxDelayTime so set that equal to the delay. @@ -171,11 +173,11 @@ function startTest() { for (var i = 0; i < pannerCount; ++i) { var delay = ctx.createDelay(delayDuration); delay.delayTime.value = delayDuration; - oscillator.connect(delay); + source.connect(delay); delay.connect(referencePanner) var panner = ctx.createPanner(); - delay.connect(panner) + delay.connect(panner); testPanners[i] = panner; delayDuration += blockSize / ctx.sampleRate; @@ -196,7 +198,33 @@ function startTest() { testProcessor.connect(ctx.destination); } -startTest(); +function prepareTest() { + ctx = new AudioContext(); + // Place the listener to the side of the origin, where the panners are + // positioned, to maximize delay in one ear. + ctx.listener.setPosition(1,0,0); + + // A PannerNode will produce no output until it has loaded its HRIR + // database. Wait for this to load before starting the test. + var processor = ctx.createScriptProcessor(bufferSize, 2, 0); + referencePanner = ctx.createPanner(); + referencePanner.connect(processor); + var oscillator = ctx.createOscillator(); + oscillator.connect(referencePanner); + oscillator.start(0); + + processor.onaudioprocess = function(e) { + if (isChannelSilent(e.inputBuffer.getChannelData(0))) + return; + + oscillator.stop(0); + oscillator.disconnect(); + referencePanner.disconnect(); + e.target.onaudioprocess = null; + SimpleTest.executeSoon(startTest); + }; +} +prepareTest(); From 8dc0b551b33c15d01bda567a635e7264236543ca Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Sat, 9 Nov 2013 10:32:53 +0900 Subject: [PATCH 14/52] Bug 934864 - Add option to make INSTALL_TARGETS and PP_TARGETS keep the original path when copying/preprocessing. r=gps Also, refactored them for more debuggability and clarity. --- config/rules.mk | 105 ++++++++++++++++++++++++++----------- js/src/config/rules.mk | 105 ++++++++++++++++++++++++++----------- security/build/Makefile.in | 4 +- 3 files changed, 152 insertions(+), 62 deletions(-) diff --git a/config/rules.mk b/config/rules.mk index 3728cf28c023..ae27caf6b7ae 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -1481,6 +1481,11 @@ endif # # Additionally, a FOO_TARGET variable may be added to indicate the target for # which the files and executables are installed. Default is "libs". +# +# Finally, a FOO_KEEP_PATH variable may be set to 1 to indicate the paths given +# in FOO_FILES/FOO_EXECUTABLES are to be kept at the destination. That is, +# if FOO_FILES is bar/baz/qux.h, and FOO_DEST is $(DIST)/include, the installed +# file would be $(DIST)/include/bar/baz/qux.h instead of $(DIST)/include/qux.h # If we're using binary nsinstall and it's not built yet, fallback to python nsinstall. ifneq (,$(filter $(CONFIG_TOOLS)/nsinstall$(HOST_BIN_SUFFIX),$(install_cmd))) @@ -1493,22 +1498,50 @@ endef endif endif -define install_file_template -$(or $(3),libs):: $(2)/$(notdir $(1)) -$(call install_cmd_override,$(2)/$(notdir $(1))) -$(2)/$(notdir $(1)): $(1) - $$(call install_cmd,$(4) "$$<" "$${@D}") +install_target_tier = $(or $($(1)_TARGET),libs) +INSTALL_TARGETS_TIERS := $(sort $(foreach category,$(INSTALL_TARGETS),$(call install_target_tier,$(category)))) + +install_target_result = $($(1)_DEST:%/=%)/$(if $($(1)_KEEP_PATH),$(2),$(notdir $(2))) +install_target_files = $(foreach file,$($(1)_FILES),$(call install_target_result,$(category),$(file))) +install_target_executables = $(foreach file,$($(1)_EXECUTABLES),$(call install_target_result,$(category),$(file))) + +# Work around a GNU make 3.81 bug where it gives $< the wrong value. +# See details in bug 934864. +define create_dependency +$(1): $(2) +$(1): $(2) endef + +define install_target_template +$(call install_cmd_override,$(2)) +$(call create_dependency,$(2),$(1)) +endef + $(foreach category,$(INSTALL_TARGETS),\ - $(if $($(category)_DEST),,$(error Missing $(category)_DEST))\ - $(foreach file,$($(category)_FILES),\ - $(eval $(call install_file_template,$(file),$($(category)_DEST),$($(category)_TARGET),$(IFLAGS1)))\ - )\ - $(foreach file,$($(category)_EXECUTABLES),\ - $(eval $(call install_file_template,$(file),$($(category)_DEST),$($(category)_TARGET),$(IFLAGS2)))\ - )\ + $(if $($(category)_DEST),,$(error Missing $(category)_DEST)) \ + $(foreach tier,$(call install_target_tier,$(category)),\ + $(eval INSTALL_TARGETS_FILES_$(tier) += $(call install_target_files,$(category))) \ + $(eval INSTALL_TARGETS_EXECUTABLES_$(tier) += $(call install_target_executables,$(category))) \ + ) \ + $(foreach file,$($(category)_FILES) $($(category)_EXECUTABLES), \ + $(eval $(call install_target_template,$(file),$(call install_target_result,$(category),$(file)))) \ + ) \ ) +$(foreach tier,$(INSTALL_TARGETS_TIERS), \ + $(eval $(tier):: $(INSTALL_TARGETS_FILES_$(tier)) $(INSTALL_TARGETS_EXECUTABLES_$(tier))) \ +) + +install_targets_sanity = $(if $(filter-out $(notdir $@),$(notdir $(<))),$(error Looks like $@ has an unexpected dependency on $< which breaks INSTALL_TARGETS)) + +$(sort $(foreach tier,$(INSTALL_TARGETS_TIERS),$(INSTALL_TARGETS_FILES_$(tier)))): + $(install_targets_sanity) + $(call install_cmd,$(IFLAGS1) "$<" "$(@D)") + +$(sort $(foreach tier,$(INSTALL_TARGETS_TIERS),$(INSTALL_TARGETS_EXECUTABLES_$(tier)))): + $(install_targets_sanity) + $(call install_cmd,$(IFLAGS2) "$<" "$(@D)") + ################################################################################ # Preprocessing rules # @@ -1538,26 +1571,38 @@ $(foreach category,$(INSTALL_TARGETS),\ # - _TARGET names the 'make' target that should depend on creating the output # files. Setting this variable is optional; if unset, we preprocess the # files for the 'libs' target. +# +# - _KEEP_PATH may be set to 1 to indicate the paths given in are to be +# kept under _PATH. That is, if is bar/baz/qux.h.in and _PATH is +# $(DIST)/include, the preprocessed file would be $(DIST)/include/bar/baz/qux.h +# instead of $(DIST)/include/qux.h. -# preprocess_file_template defines preprocessing rules. -# $(call preprocess_file_template, source_file, output_file, -# makefile_target, extra_flags) -define preprocess_file_template -$(2): $(1) $$(GLOBAL_DEPS) - $$(RM) "$$@" - $$(PYTHON) $$(topsrcdir)/config/Preprocessor.py $(4) $$(DEFINES) $$(ACDEFINES) $$(XULPPFLAGS) "$$<" -o "$$@" -$(3):: $(2) -endef +pp_target_tier = $(or $($(1)_TARGET),libs) +PP_TARGETS_TIERS := $(sort $(foreach category,$(PP_TARGETS),$(call pp_target_tier,$(category)))) + +pp_target_result = $(or $($(1)_PATH:%/=%),$(CURDIR))/$(if $($(1)_KEEP_PATH),$(2:.in=),$(notdir $(2:.in=))) +pp_target_results = $(foreach file,$($(1)),$(call pp_target_result,$(category),$(file))) + +$(foreach category,$(PP_TARGETS), \ + $(foreach tier,$(call pp_target_tier,$(category)), \ + $(eval PP_TARGETS_RESULTS_$(tier) += $(call pp_target_results,$(category))) \ + ) \ + $(foreach file,$($(category)), \ + $(eval $(call create_dependency,$(call pp_target_result,$(category),$(file)), \ + $(file) $(GLOBAL_DEPS))) \ + ) \ + $(eval $(call pp_target_results,$(category)): PP_TARGET_FLAGS=$($(category)_FLAGS)) \ +) + +$(foreach tier,$(PP_TARGETS_TIERS), \ + $(eval $(tier):: $(PP_TARGETS_RESULTS_$(tier))) \ +) + +$(sort $(foreach tier,$(PP_TARGETS_TIERS),$(PP_TARGETS_RESULTS_$(tier)))): + $(if $(filter-out $(notdir $@),$(notdir $(<:.in=))),$(error Looks like $@ has an unexpected dependency on $< which breaks PP_TARGETS)) + $(RM) "$@" + $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PP_TARGET_FLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) "$<" -o "$@" -$(foreach category,$(PP_TARGETS), \ - $(foreach file,$($(category)), \ - $(eval $(call preprocess_file_template, \ - $(file), \ - $(or $($(category)_PATH),$(CURDIR))/$(notdir $(file:.in=)), \ - $(or $($(category)_TARGET),libs), \ - $($(category)_FLAGS))) \ - ) \ - ) # Pull in non-recursive targets if this is a partial tree build. ifndef TOPLEVEL_BUILD diff --git a/js/src/config/rules.mk b/js/src/config/rules.mk index 3728cf28c023..ae27caf6b7ae 100644 --- a/js/src/config/rules.mk +++ b/js/src/config/rules.mk @@ -1481,6 +1481,11 @@ endif # # Additionally, a FOO_TARGET variable may be added to indicate the target for # which the files and executables are installed. Default is "libs". +# +# Finally, a FOO_KEEP_PATH variable may be set to 1 to indicate the paths given +# in FOO_FILES/FOO_EXECUTABLES are to be kept at the destination. That is, +# if FOO_FILES is bar/baz/qux.h, and FOO_DEST is $(DIST)/include, the installed +# file would be $(DIST)/include/bar/baz/qux.h instead of $(DIST)/include/qux.h # If we're using binary nsinstall and it's not built yet, fallback to python nsinstall. ifneq (,$(filter $(CONFIG_TOOLS)/nsinstall$(HOST_BIN_SUFFIX),$(install_cmd))) @@ -1493,22 +1498,50 @@ endef endif endif -define install_file_template -$(or $(3),libs):: $(2)/$(notdir $(1)) -$(call install_cmd_override,$(2)/$(notdir $(1))) -$(2)/$(notdir $(1)): $(1) - $$(call install_cmd,$(4) "$$<" "$${@D}") +install_target_tier = $(or $($(1)_TARGET),libs) +INSTALL_TARGETS_TIERS := $(sort $(foreach category,$(INSTALL_TARGETS),$(call install_target_tier,$(category)))) + +install_target_result = $($(1)_DEST:%/=%)/$(if $($(1)_KEEP_PATH),$(2),$(notdir $(2))) +install_target_files = $(foreach file,$($(1)_FILES),$(call install_target_result,$(category),$(file))) +install_target_executables = $(foreach file,$($(1)_EXECUTABLES),$(call install_target_result,$(category),$(file))) + +# Work around a GNU make 3.81 bug where it gives $< the wrong value. +# See details in bug 934864. +define create_dependency +$(1): $(2) +$(1): $(2) endef + +define install_target_template +$(call install_cmd_override,$(2)) +$(call create_dependency,$(2),$(1)) +endef + $(foreach category,$(INSTALL_TARGETS),\ - $(if $($(category)_DEST),,$(error Missing $(category)_DEST))\ - $(foreach file,$($(category)_FILES),\ - $(eval $(call install_file_template,$(file),$($(category)_DEST),$($(category)_TARGET),$(IFLAGS1)))\ - )\ - $(foreach file,$($(category)_EXECUTABLES),\ - $(eval $(call install_file_template,$(file),$($(category)_DEST),$($(category)_TARGET),$(IFLAGS2)))\ - )\ + $(if $($(category)_DEST),,$(error Missing $(category)_DEST)) \ + $(foreach tier,$(call install_target_tier,$(category)),\ + $(eval INSTALL_TARGETS_FILES_$(tier) += $(call install_target_files,$(category))) \ + $(eval INSTALL_TARGETS_EXECUTABLES_$(tier) += $(call install_target_executables,$(category))) \ + ) \ + $(foreach file,$($(category)_FILES) $($(category)_EXECUTABLES), \ + $(eval $(call install_target_template,$(file),$(call install_target_result,$(category),$(file)))) \ + ) \ ) +$(foreach tier,$(INSTALL_TARGETS_TIERS), \ + $(eval $(tier):: $(INSTALL_TARGETS_FILES_$(tier)) $(INSTALL_TARGETS_EXECUTABLES_$(tier))) \ +) + +install_targets_sanity = $(if $(filter-out $(notdir $@),$(notdir $(<))),$(error Looks like $@ has an unexpected dependency on $< which breaks INSTALL_TARGETS)) + +$(sort $(foreach tier,$(INSTALL_TARGETS_TIERS),$(INSTALL_TARGETS_FILES_$(tier)))): + $(install_targets_sanity) + $(call install_cmd,$(IFLAGS1) "$<" "$(@D)") + +$(sort $(foreach tier,$(INSTALL_TARGETS_TIERS),$(INSTALL_TARGETS_EXECUTABLES_$(tier)))): + $(install_targets_sanity) + $(call install_cmd,$(IFLAGS2) "$<" "$(@D)") + ################################################################################ # Preprocessing rules # @@ -1538,26 +1571,38 @@ $(foreach category,$(INSTALL_TARGETS),\ # - _TARGET names the 'make' target that should depend on creating the output # files. Setting this variable is optional; if unset, we preprocess the # files for the 'libs' target. +# +# - _KEEP_PATH may be set to 1 to indicate the paths given in are to be +# kept under _PATH. That is, if is bar/baz/qux.h.in and _PATH is +# $(DIST)/include, the preprocessed file would be $(DIST)/include/bar/baz/qux.h +# instead of $(DIST)/include/qux.h. -# preprocess_file_template defines preprocessing rules. -# $(call preprocess_file_template, source_file, output_file, -# makefile_target, extra_flags) -define preprocess_file_template -$(2): $(1) $$(GLOBAL_DEPS) - $$(RM) "$$@" - $$(PYTHON) $$(topsrcdir)/config/Preprocessor.py $(4) $$(DEFINES) $$(ACDEFINES) $$(XULPPFLAGS) "$$<" -o "$$@" -$(3):: $(2) -endef +pp_target_tier = $(or $($(1)_TARGET),libs) +PP_TARGETS_TIERS := $(sort $(foreach category,$(PP_TARGETS),$(call pp_target_tier,$(category)))) + +pp_target_result = $(or $($(1)_PATH:%/=%),$(CURDIR))/$(if $($(1)_KEEP_PATH),$(2:.in=),$(notdir $(2:.in=))) +pp_target_results = $(foreach file,$($(1)),$(call pp_target_result,$(category),$(file))) + +$(foreach category,$(PP_TARGETS), \ + $(foreach tier,$(call pp_target_tier,$(category)), \ + $(eval PP_TARGETS_RESULTS_$(tier) += $(call pp_target_results,$(category))) \ + ) \ + $(foreach file,$($(category)), \ + $(eval $(call create_dependency,$(call pp_target_result,$(category),$(file)), \ + $(file) $(GLOBAL_DEPS))) \ + ) \ + $(eval $(call pp_target_results,$(category)): PP_TARGET_FLAGS=$($(category)_FLAGS)) \ +) + +$(foreach tier,$(PP_TARGETS_TIERS), \ + $(eval $(tier):: $(PP_TARGETS_RESULTS_$(tier))) \ +) + +$(sort $(foreach tier,$(PP_TARGETS_TIERS),$(PP_TARGETS_RESULTS_$(tier)))): + $(if $(filter-out $(notdir $@),$(notdir $(<:.in=))),$(error Looks like $@ has an unexpected dependency on $< which breaks PP_TARGETS)) + $(RM) "$@" + $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PP_TARGET_FLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) "$<" -o "$@" -$(foreach category,$(PP_TARGETS), \ - $(foreach file,$($(category)), \ - $(eval $(call preprocess_file_template, \ - $(file), \ - $(or $($(category)_PATH),$(CURDIR))/$(notdir $(file:.in=)), \ - $(or $($(category)_TARGET),libs), \ - $($(category)_FLAGS))) \ - ) \ - ) # Pull in non-recursive targets if this is a partial tree build. ifndef TOPLEVEL_BUILD diff --git a/security/build/Makefile.in b/security/build/Makefile.in index dbce3103a5cd..030264c15b46 100644 --- a/security/build/Makefile.in +++ b/security/build/Makefile.in @@ -384,8 +384,6 @@ nss3.def: $(NSS_STATIC_LIBS_DEFS) $(DEPTH)/db/sqlite3/src/sqlite-processed.def mv $@.tmp $@ endif -else -$(NSS_DIST_DLL_FILES) $(NSS_SDK_LIB_FILES): libs-nss/lib endif # MOZ_FOLD_LIBS include $(topsrcdir)/config/rules.mk @@ -446,6 +444,8 @@ libs-nss/lib/freebl: $(DIST)/lib/$(IMPORT_PREFIX)nssutil3$(IMPORT_SUFFIX) $(NSPR # For each directory where we build static libraries, force the NSS build system # to only build static libraries. $(addprefix libs-,$(NSS_STATIC_DIRS)): DEFAULT_GMAKE_FLAGS += SHARED_LIBRARY= IMPORT_LIBRARY= +else +$(NSS_DIST_DLL_FILES) $(NSS_SDK_LIB_FILES): libs-nss/lib endif # MOZ_FOLD_LIBS ifeq ($(NSINSTALL_PY),$(NSINSTALL)) From 41a1cabced50cb2e7a54b514a727b175ca6d013a Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Sat, 9 Nov 2013 10:32:58 +0900 Subject: [PATCH 15/52] Bug 934864 - Add REPORT_BUILD do INSTALL_TARGETS and PP_TARGETS. r=gps --- config/rules.mk | 5 ++++- js/src/config/rules.mk | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/config/rules.mk b/config/rules.mk index ae27caf6b7ae..0834e6a430c6 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -53,7 +53,7 @@ else REPORT_BUILD = $(info $(shell $(PYTHON) $(MOZILLA_DIR)/config/rebuild_check.py $@ $^)) endif else -REPORT_BUILD = $(info $(notdir $@)) +REPORT_BUILD = $(info $(if $(filter $(DEPTH)/%,$@),$(@:$(DEPTH)/%=%),$(notdir $@))) endif ifeq ($(OS_ARCH),OS2) @@ -1536,10 +1536,12 @@ install_targets_sanity = $(if $(filter-out $(notdir $@),$(notdir $(<))),$(error $(sort $(foreach tier,$(INSTALL_TARGETS_TIERS),$(INSTALL_TARGETS_FILES_$(tier)))): $(install_targets_sanity) + $(REPORT_BUILD) $(call install_cmd,$(IFLAGS1) "$<" "$(@D)") $(sort $(foreach tier,$(INSTALL_TARGETS_TIERS),$(INSTALL_TARGETS_EXECUTABLES_$(tier)))): $(install_targets_sanity) + $(REPORT_BUILD) $(call install_cmd,$(IFLAGS2) "$<" "$(@D)") ################################################################################ @@ -1600,6 +1602,7 @@ $(foreach tier,$(PP_TARGETS_TIERS), \ $(sort $(foreach tier,$(PP_TARGETS_TIERS),$(PP_TARGETS_RESULTS_$(tier)))): $(if $(filter-out $(notdir $@),$(notdir $(<:.in=))),$(error Looks like $@ has an unexpected dependency on $< which breaks PP_TARGETS)) + $(REPORT_BUILD) $(RM) "$@" $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PP_TARGET_FLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) "$<" -o "$@" diff --git a/js/src/config/rules.mk b/js/src/config/rules.mk index ae27caf6b7ae..0834e6a430c6 100644 --- a/js/src/config/rules.mk +++ b/js/src/config/rules.mk @@ -53,7 +53,7 @@ else REPORT_BUILD = $(info $(shell $(PYTHON) $(MOZILLA_DIR)/config/rebuild_check.py $@ $^)) endif else -REPORT_BUILD = $(info $(notdir $@)) +REPORT_BUILD = $(info $(if $(filter $(DEPTH)/%,$@),$(@:$(DEPTH)/%=%),$(notdir $@))) endif ifeq ($(OS_ARCH),OS2) @@ -1536,10 +1536,12 @@ install_targets_sanity = $(if $(filter-out $(notdir $@),$(notdir $(<))),$(error $(sort $(foreach tier,$(INSTALL_TARGETS_TIERS),$(INSTALL_TARGETS_FILES_$(tier)))): $(install_targets_sanity) + $(REPORT_BUILD) $(call install_cmd,$(IFLAGS1) "$<" "$(@D)") $(sort $(foreach tier,$(INSTALL_TARGETS_TIERS),$(INSTALL_TARGETS_EXECUTABLES_$(tier)))): $(install_targets_sanity) + $(REPORT_BUILD) $(call install_cmd,$(IFLAGS2) "$<" "$(@D)") ################################################################################ @@ -1600,6 +1602,7 @@ $(foreach tier,$(PP_TARGETS_TIERS), \ $(sort $(foreach tier,$(PP_TARGETS_TIERS),$(PP_TARGETS_RESULTS_$(tier)))): $(if $(filter-out $(notdir $@),$(notdir $(<:.in=))),$(error Looks like $@ has an unexpected dependency on $< which breaks PP_TARGETS)) + $(REPORT_BUILD) $(RM) "$@" $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PP_TARGET_FLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) "$<" -o "$@" From a470038314105a70e83e00d4c8a52516664b386d Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Sat, 9 Nov 2013 10:35:44 +0900 Subject: [PATCH 16/52] Bug 935305 - Move preprocessor to mozbuild.action. r=gps --HG-- rename : config/Preprocessor.py => python/mozbuild/mozbuild/preprocessor.py rename : config/tests/unit-Expression.py => python/mozbuild/mozbuild/test/test_expression.py rename : config/tests/unit-LineEndings.py => python/mozbuild/mozbuild/test/test_line_endings.py rename : config/tests/unit-Preprocessor.py => python/mozbuild/mozbuild/test/test_preprocessor.py --- b2g/installer/Makefile.in | 2 +- b2g/locales/Makefile.in | 4 +- browser/app/Makefile.in | 2 +- browser/installer/Makefile.in | 2 +- browser/installer/windows/Makefile.in | 12 +- browser/locales/Makefile.in | 5 +- browser/metro/Makefile.in | 2 +- browser/metro/locales/import/Makefile.in | 4 +- build/Makefile.in | 2 +- build/automation-build.mk | 4 +- build/docs/preprocessor.rst | 2 +- config/Expression.py | 241 --------- config/Makefile.in | 2 +- config/rules.mk | 12 +- db/sqlite3/src/Makefile.in | 6 +- dom/bindings/Makefile.in | 8 +- js/src/Makefile.in | 10 +- js/src/config/Expression.py | 241 --------- js/src/config/Makefile.in | 2 +- js/src/config/Preprocessor.py | 492 ------------------ js/src/config/rules.mk | 12 +- js/xpconnect/src/Makefile.in | 2 +- js/xpconnect/tests/components/js/Makefile.in | 2 +- layout/mathml/Makefile.in | 2 +- layout/media/Makefile.in | 2 +- mobile/android/base/Makefile.in | 5 +- mobile/android/base/locales/Makefile.in | 6 +- mobile/android/installer/Makefile.in | 2 +- mobile/locales/Makefile.in | 6 +- modules/libmar/tests/Makefile.in | 2 +- modules/libpref/src/Makefile.in | 2 +- mozglue/build/Makefile.in | 2 +- .../mozbuild/mozbuild/action/preprocessor.py | 16 + .../mozbuild/backend/configenvironment.py | 2 +- python/mozbuild/mozbuild/jar.py | 2 +- .../mozbuild/mozbuild/preprocessor.py | 274 +++++++++- .../mozbuild/mozbuild/test/test_expression.py | 2 +- .../mozbuild/test/test_line_endings.py | 2 +- .../mozbuild/test/test_preprocessor.py | 2 +- python/mozbuild/mozpack/packager/__init__.py | 2 +- python/mozbuild/mozpack/test/test_packager.py | 2 +- services/sync/Makefile.in | 2 +- toolkit/library/Makefile.in | 4 +- toolkit/locales/l10n.mk | 4 +- toolkit/mozapps/installer/packager.mk | 7 +- webapprt/Makefile.in | 2 +- webapprt/win/Makefile.in | 4 +- xulrunner/app/Makefile.in | 2 +- xulrunner/installer/Makefile.in | 21 +- 49 files changed, 361 insertions(+), 1089 deletions(-) delete mode 100644 config/Expression.py delete mode 100644 js/src/config/Expression.py delete mode 100755 js/src/config/Preprocessor.py create mode 100644 python/mozbuild/mozbuild/action/preprocessor.py rename config/Preprocessor.py => python/mozbuild/mozbuild/preprocessor.py (69%) rename config/tests/unit-Expression.py => python/mozbuild/mozbuild/test/test_expression.py (97%) rename config/tests/unit-LineEndings.py => python/mozbuild/mozbuild/test/test_line_endings.py (95%) rename config/tests/unit-Preprocessor.py => python/mozbuild/mozbuild/test/test_preprocessor.py (99%) diff --git a/b2g/installer/Makefile.in b/b2g/installer/Makefile.in index ef39fb37953c..627c00bd512c 100644 --- a/b2g/installer/Makefile.in +++ b/b2g/installer/Makefile.in @@ -52,7 +52,7 @@ endif ifdef MOZ_PKG_MANIFEST_P $(MOZ_PKG_MANIFEST): $(MOZ_PKG_MANIFEST_P) FORCE - $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $< > $@ + $(call py_action,preprocessor,$(DEFINES) $(ACDEFINES) $< -o $@) ifdef MOZ_CHROME_MULTILOCALE printf "\n[multilocale]\n" >> $@ for LOCALE in $(MOZ_CHROME_MULTILOCALE) ;\ diff --git a/b2g/locales/Makefile.in b/b2g/locales/Makefile.in index 16ff711c18b1..c10090a9c19c 100644 --- a/b2g/locales/Makefile.in +++ b/b2g/locales/Makefile.in @@ -54,8 +54,8 @@ $(DIST)/branding: libs:: @if test -f "$(LOCALE_SRCDIR)/existing-profile-defaults.js"; then \ - $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PREF_PPFLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) \ - $(LOCALE_SRCDIR)/existing-profile-defaults.js > $(FINAL_TARGET)/defaults/existing-profile-defaults.js; \ + $(PYTHON) -m mozbuild.action.preprocessor $(PREF_PPFLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) \ + $(LOCALE_SRCDIR)/existing-profile-defaults.js -o $(FINAL_TARGET)/defaults/existing-profile-defaults.js; \ fi NO_JA_JP_MAC_AB_CD := $(if $(filter ja-JP-mac, $(AB_CD)),ja,$(AB_CD)) diff --git a/browser/app/Makefile.in b/browser/app/Makefile.in index f495df5dd169..bf74c1e9dc01 100644 --- a/browser/app/Makefile.in +++ b/browser/app/Makefile.in @@ -144,7 +144,7 @@ ifndef LIBXUL_SDK # channel-prefs.js is handled separate from other prefs due to bug 756325 libs:: $(srcdir)/profile/channel-prefs.js $(NSINSTALL) -D $(DIST)/bin/defaults/pref - $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PREF_PPFLAGS) $(ACDEFINES) $^ > $(DIST)/bin/defaults/pref/channel-prefs.js + $(call py_action,preprocessor,$(PREF_PPFLAGS) $(ACDEFINES) $^ -o $(DIST)/bin/defaults/pref/channel-prefs.js) endif libs:: $(srcdir)/blocklist.xml diff --git a/browser/installer/Makefile.in b/browser/installer/Makefile.in index bd4fc845b152..eb37d8c9dd24 100644 --- a/browser/installer/Makefile.in +++ b/browser/installer/Makefile.in @@ -79,7 +79,7 @@ ifdef MOZ_PKG_MANIFEST_P MOZ_PKG_MANIFEST = package-manifest $(MOZ_PKG_MANIFEST): $(MOZ_PKG_MANIFEST_P) $(GLOBAL_DEPS) - $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $< > $@ + $(call py_action,preprocessor,$(DEFINES) $(ACDEFINES) $< -o $@) GARBAGE += $(MOZ_PKG_MANIFEST) endif diff --git a/browser/installer/windows/Makefile.in b/browser/installer/windows/Makefile.in index 001f8d659d7b..93b703282cff 100644 --- a/browser/installer/windows/Makefile.in +++ b/browser/installer/windows/Makefile.in @@ -71,8 +71,8 @@ uninstaller:: $(MKDIR) $(CONFIG_DIR) $(INSTALL) $(addprefix $(srcdir)/,$(INSTALLER_FILES)) $(CONFIG_DIR) $(INSTALL) $(addprefix $(DIST)/branding/,$(BRANDING_FILES)) $(CONFIG_DIR) - $(PYTHON) $(topsrcdir)/config/Preprocessor.py -Fsubstitution $(DEFINES) $(ACDEFINES) \ - $(srcdir)/nsis/defines.nsi.in > $(CONFIG_DIR)/defines.nsi + $(call py_action,preprocessor,-Fsubstitution $(DEFINES) $(ACDEFINES) \ + $(srcdir)/nsis/defines.nsi.in -o $(CONFIG_DIR)/defines.nsi) $(PYTHON) $(topsrcdir)/toolkit/mozapps/installer/windows/nsis/preprocess-locale.py \ --preprocess-locale $(topsrcdir) \ $(PPL_LOCALE_ARGS) $(AB_CD) $(CONFIG_DIR) @@ -81,8 +81,8 @@ uninstaller:: ifdef MOZ_MAINTENANCE_SERVICE maintenanceservice_installer:: $(INSTALL) $(addprefix $(srcdir)/,$(INSTALLER_FILES)) $(CONFIG_DIR) - $(PYTHON) $(topsrcdir)/config/Preprocessor.py -Fsubstitution $(DEFINES) $(ACDEFINES) \ - $(srcdir)/nsis/defines.nsi.in > $(CONFIG_DIR)/defines.nsi + $(call py_action,preprocessor,-Fsubstitution $(DEFINES) $(ACDEFINES) \ + $(srcdir)/nsis/defines.nsi.in -o $(CONFIG_DIR)/defines.nsi) $(PYTHON) $(topsrcdir)/toolkit/mozapps/installer/windows/nsis/preprocess-locale.py \ --preprocess-locale $(topsrcdir) \ $(PPL_LOCALE_ARGS) $(AB_CD) $(CONFIG_DIR) @@ -93,8 +93,8 @@ $(CONFIG_DIR)/setup.exe:: $(MKDIR) $(CONFIG_DIR) $(INSTALL) $(addprefix $(srcdir)/,$(INSTALLER_FILES)) $(CONFIG_DIR) $(INSTALL) $(addprefix $(DIST)/branding/,$(BRANDING_FILES)) $(CONFIG_DIR) - $(PYTHON) $(topsrcdir)/config/Preprocessor.py -Fsubstitution $(DEFINES) $(ACDEFINES) \ - $(srcdir)/nsis/defines.nsi.in > $(CONFIG_DIR)/defines.nsi + $(call py_action,preprocessor,-Fsubstitution $(DEFINES) $(ACDEFINES) \ + $(srcdir)/nsis/defines.nsi.in -o $(CONFIG_DIR)/defines.nsi) $(PYTHON) $(topsrcdir)/toolkit/mozapps/installer/windows/nsis/preprocess-locale.py \ --preprocess-locale $(topsrcdir) \ $(PPL_LOCALE_ARGS) $(AB_CD) $(CONFIG_DIR) diff --git a/browser/locales/Makefile.in b/browser/locales/Makefile.in index c6294145feb1..12af0b7df1be 100644 --- a/browser/locales/Makefile.in +++ b/browser/locales/Makefile.in @@ -105,12 +105,11 @@ PROFILE_CHROME = userChrome-example.css userContent-example.css NO_JA_JP_MAC_AB_CD := $(if $(filter ja-JP-mac, $(AB_CD)),ja,$(AB_CD)) %/defaults/profile/bookmarks.html: bookmarks.inc generic/profile/bookmarks.html.in - $(SYSINSTALL) -D $(dir $@) - $(PYTHON) $(topsrcdir)/config/Preprocessor.py \ + $(call py_action,preprocessor, \ -I $< \ -DAB_CD=$(NO_JA_JP_MAC_AB_CD) \ $(srcdir)/generic/profile/bookmarks.html.in \ - > $@ + -o $@) libs:: $(FINAL_TARGET)/defaults/profile/bookmarks.html ; diff --git a/browser/metro/Makefile.in b/browser/metro/Makefile.in index d24a53f55c1e..4aaeac6862d1 100644 --- a/browser/metro/Makefile.in +++ b/browser/metro/Makefile.in @@ -17,7 +17,7 @@ DEFINES += -DGRE_MILESTONE=$(GRE_MILESTONE) -DGRE_BUILDID=$(GRE_BUILDID) # 'application.ini' breaks firefox build config. So we use something different. metroapp.ini: metroapp.ini.in $(DEPTH)/config/buildid $(topsrcdir)/config/milestone.txt $(RM) "metroapp.ini" - $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $< > $@ + $(call py_action,preprocessor,$(DEFINES) $< -o $@) libs:: metroapp.ini $(INSTALL) metroapp.ini $(FINAL_TARGET) diff --git a/browser/metro/locales/import/Makefile.in b/browser/metro/locales/import/Makefile.in index a0b68766f57a..821be825bf57 100644 --- a/browser/metro/locales/import/Makefile.in +++ b/browser/metro/locales/import/Makefile.in @@ -44,9 +44,9 @@ bookmarks-src = $(srcdir)/../generic/profile/bookmarks.json.in # processing of the jar file in the parent directory. bookmarks: bookmarks.inc @echo "Generating: $@" - $(PYTHON) $(topsrcdir)/config/Preprocessor.py \ + $(call py_action,preprocessor, \ -I $^ \ -DAB_CD=$(AB_CD) \ - $(bookmarks-src) > ../bookmarks.json + $(bookmarks-src) -o ../bookmarks.json) export:: bookmarks diff --git a/build/Makefile.in b/build/Makefile.in index 768e63da9450..bcf717eb1978 100644 --- a/build/Makefile.in +++ b/build/Makefile.in @@ -106,7 +106,7 @@ _LEAKTEST_FILES = \ $(NULL) leaktest.py: leaktest.py.in - $(PYTHON) $(topsrcdir)/config/Preprocessor.py $^ > $@ + $(call py_action,preprocessor,$^ -o $@) chmod +x $@ GARBAGE += leaktest.py diff --git a/build/automation-build.mk b/build/automation-build.mk index 567059a9e0d0..1f998485e5f3 100644 --- a/build/automation-build.mk +++ b/build/automation-build.mk @@ -67,7 +67,7 @@ AUTOMATION_PPARGS += -DIS_ASAN=0 endif automation.py: $(MOZILLA_DIR)/build/automation.py.in $(MOZILLA_DIR)/build/automation-build.mk - $(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py \ - $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $< > $@ + $(call py_action,preprocessor, \ + $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $< -o $@) GARBAGE += automation.py automation.pyc diff --git a/build/docs/preprocessor.rst b/build/docs/preprocessor.rst index 23a7766c8358..ab2d8ecf710d 100644 --- a/build/docs/preprocessor.rst +++ b/build/docs/preprocessor.rst @@ -6,7 +6,7 @@ Text Preprocessor The build system contains a text preprocessor similar to the C preprocessor, meant for processing files which have no built-in preprocessor such as XUL -and JavaScript documents. It is implemented at ``config/Preprocessor.py`` and +and JavaScript documents. It is implemented at ``python/mozbuild/mozbuild/preprocessor.py`` and is typically invoked via :ref:`jar_manifests`. While used to preprocess CSS files, the directives are changed to begin with diff --git a/config/Expression.py b/config/Expression.py deleted file mode 100644 index 3e91ae46858c..000000000000 --- a/config/Expression.py +++ /dev/null @@ -1,241 +0,0 @@ -# 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/. - -""" -Parses and evaluates simple statements for Preprocessor: - -Expression currently supports the following grammar, whitespace is ignored: - -expression : - and_cond ( '||' expression ) ? ; -and_cond: - test ( '&&' and_cond ) ? ; -test: - unary ( ( '==' | '!=' ) unary ) ? ; -unary : - '!'? value ; -value : - [0-9]+ # integer - | 'defined(' \w+ ')' - | \w+ # string identifier or value; -""" - -import re - -class Expression: - def __init__(self, expression_string): - """ - Create a new expression with this string. - The expression will already be parsed into an Abstract Syntax Tree. - """ - self.content = expression_string - self.offset = 0 - self.__ignore_whitespace() - self.e = self.__get_logical_or() - if self.content: - raise Expression.ParseError, self - - def __get_logical_or(self): - """ - Production: and_cond ( '||' expression ) ? - """ - if not len(self.content): - return None - rv = Expression.__AST("logical_op") - # test - rv.append(self.__get_logical_and()) - self.__ignore_whitespace() - if self.content[:2] != '||': - # no logical op needed, short cut to our prime element - return rv[0] - # append operator - rv.append(Expression.__ASTLeaf('op', self.content[:2])) - self.__strip(2) - self.__ignore_whitespace() - rv.append(self.__get_logical_or()) - self.__ignore_whitespace() - return rv - - def __get_logical_and(self): - """ - Production: test ( '&&' and_cond ) ? - """ - if not len(self.content): - return None - rv = Expression.__AST("logical_op") - # test - rv.append(self.__get_equality()) - self.__ignore_whitespace() - if self.content[:2] != '&&': - # no logical op needed, short cut to our prime element - return rv[0] - # append operator - rv.append(Expression.__ASTLeaf('op', self.content[:2])) - self.__strip(2) - self.__ignore_whitespace() - rv.append(self.__get_logical_and()) - self.__ignore_whitespace() - return rv - - def __get_equality(self): - """ - Production: unary ( ( '==' | '!=' ) unary ) ? - """ - if not len(self.content): - return None - rv = Expression.__AST("equality") - # unary - rv.append(self.__get_unary()) - self.__ignore_whitespace() - if not re.match('[=!]=', self.content): - # no equality needed, short cut to our prime unary - return rv[0] - # append operator - rv.append(Expression.__ASTLeaf('op', self.content[:2])) - self.__strip(2) - self.__ignore_whitespace() - rv.append(self.__get_unary()) - self.__ignore_whitespace() - return rv - - def __get_unary(self): - """ - Production: '!'? value - """ - # eat whitespace right away, too - not_ws = re.match('!\s*', self.content) - if not not_ws: - return self.__get_value() - rv = Expression.__AST('not') - self.__strip(not_ws.end()) - rv.append(self.__get_value()) - self.__ignore_whitespace() - return rv - - def __get_value(self): - """ - Production: ( [0-9]+ | 'defined(' \w+ ')' | \w+ ) - Note that the order is important, and the expression is kind-of - ambiguous as \w includes 0-9. One could make it unambiguous by - removing 0-9 from the first char of a string literal. - """ - rv = None - m = re.match('defined\s*\(\s*(\w+)\s*\)', self.content) - if m: - word_len = m.end() - rv = Expression.__ASTLeaf('defined', m.group(1)) - else: - word_len = re.match('[0-9]*', self.content).end() - if word_len: - value = int(self.content[:word_len]) - rv = Expression.__ASTLeaf('int', value) - else: - word_len = re.match('\w*', self.content).end() - if word_len: - rv = Expression.__ASTLeaf('string', self.content[:word_len]) - else: - raise Expression.ParseError, self - self.__strip(word_len) - self.__ignore_whitespace() - return rv - - def __ignore_whitespace(self): - ws_len = re.match('\s*', self.content).end() - self.__strip(ws_len) - return - - def __strip(self, length): - """ - Remove a given amount of chars from the input and update - the offset. - """ - self.content = self.content[length:] - self.offset += length - - def evaluate(self, context): - """ - Evaluate the expression with the given context - """ - - # Helper function to evaluate __get_equality results - def eval_equality(tok): - left = opmap[tok[0].type](tok[0]) - right = opmap[tok[2].type](tok[2]) - rv = left == right - if tok[1].value == '!=': - rv = not rv - return rv - # Helper function to evaluate __get_logical_and and __get_logical_or results - def eval_logical_op(tok): - left = opmap[tok[0].type](tok[0]) - right = opmap[tok[2].type](tok[2]) - if tok[1].value == '&&': - return left and right - elif tok[1].value == '||': - return left or right - raise Expression.ParseError, self - - # Mapping from token types to evaluator functions - # Apart from (non-)equality, all these can be simple lambda forms. - opmap = { - 'logical_op': eval_logical_op, - 'equality': eval_equality, - 'not': lambda tok: not opmap[tok[0].type](tok[0]), - 'string': lambda tok: context[tok.value], - 'defined': lambda tok: tok.value in context, - 'int': lambda tok: tok.value} - - return opmap[self.e.type](self.e); - - class __AST(list): - """ - Internal class implementing Abstract Syntax Tree nodes - """ - def __init__(self, type): - self.type = type - super(self.__class__, self).__init__(self) - - class __ASTLeaf: - """ - Internal class implementing Abstract Syntax Tree leafs - """ - def __init__(self, type, value): - self.value = value - self.type = type - def __str__(self): - return self.value.__str__() - def __repr__(self): - return self.value.__repr__() - - class ParseError(StandardError): - """ - Error raised when parsing fails. - It has two members, offset and content, which give the offset of the - error and the offending content. - """ - def __init__(self, expression): - self.offset = expression.offset - self.content = expression.content[:3] - def __str__(self): - return 'Unexpected content at offset {0}, "{1}"'.format(self.offset, - self.content) - -class Context(dict): - """ - This class holds variable values by subclassing dict, and while it - truthfully reports True and False on - - name in context - - it returns the variable name itself on - - context["name"] - - to reflect the ambiguity between string literals and preprocessor - variables. - """ - def __getitem__(self, key): - if key in self: - return super(self.__class__, self).__getitem__(key) - return key diff --git a/config/Makefile.in b/config/Makefile.in index 9ff0bd2252c5..74d477509956 100644 --- a/config/Makefile.in +++ b/config/Makefile.in @@ -74,7 +74,7 @@ export-preqs = \ $(NULL) export:: $(export-preqs) - $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) \ + $(PYTHON) -m mozbuild.action.preprocessor $(DEFINES) $(ACDEFINES) \ -DMOZ_TREE_CAIRO=$(MOZ_TREE_CAIRO) \ -DMOZ_TREE_PIXMAN=$(MOZ_TREE_PIXMAN) \ -DMOZ_NATIVE_HUNSPELL=$(MOZ_NATIVE_HUNSPELL) \ diff --git a/config/rules.mk b/config/rules.mk index 0834e6a430c6..95073b567ddb 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -1559,16 +1559,16 @@ $(sort $(foreach tier,$(INSTALL_TARGETS_TIERS),$(INSTALL_TARGETS_EXECUTABLES_$(t # If PP_TARGETS lists a category name (like FOO, above), then we consult the # following make variables to see what to do: # -# - lists input files to be preprocessed with config/Preprocessor.py. We -# search VPATH for the names given here. If an input file name ends in '.in', -# that suffix is omitted from the output file name. +# - lists input files to be preprocessed with mozbuild.action.preprocessor. +# We search VPATH for the names given here. If an input file name ends in +# '.in', that suffix is omitted from the output file name. # # - _PATH names the directory in which to place the preprocessed output # files. We create this directory if it does not already exist. Setting # this variable is optional; if unset, we install the files in $(CURDIR). # -# - _FLAGS lists flags to pass to Preprocessor.py, in addition to the usual -# bunch. Setting this variable is optional. +# - _FLAGS lists flags to pass to mozbuild.action.preprocessor, in addition +# to the usual bunch. Setting this variable is optional. # # - _TARGET names the 'make' target that should depend on creating the output # files. Setting this variable is optional; if unset, we preprocess the @@ -1604,7 +1604,7 @@ $(sort $(foreach tier,$(PP_TARGETS_TIERS),$(PP_TARGETS_RESULTS_$(tier)))): $(if $(filter-out $(notdir $@),$(notdir $(<:.in=))),$(error Looks like $@ has an unexpected dependency on $< which breaks PP_TARGETS)) $(REPORT_BUILD) $(RM) "$@" - $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PP_TARGET_FLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) "$<" -o "$@" + $(call py_action,preprocessor,$(PP_TARGET_FLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) "$<" -o "$@") # Pull in non-recursive targets if this is a partial tree build. diff --git a/db/sqlite3/src/Makefile.in b/db/sqlite3/src/Makefile.in index cd5ab62697bf..9ab6d52a37c8 100644 --- a/db/sqlite3/src/Makefile.in +++ b/db/sqlite3/src/Makefile.in @@ -26,8 +26,8 @@ sqlite-version.h: sqlite-version.py sqlite3.h # We have to preprocess our def file because we need different symbols in debug # builds exposed that are not built in non-debug builds. $(DEFFILE): sqlite.def - @$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) \ - $(srcdir)/sqlite.def > $(DEFFILE) + @$(call py_action,preprocessor,$(DEFINES) \ + $(srcdir)/sqlite.def -o $(DEFFILE)) export:: sqlite-version.h endif @@ -118,7 +118,7 @@ include $(topsrcdir)/config/rules.mk LOCAL_INCLUDES += -I$(srcdir) ifeq ($(OS_ARCH),OS2) -ADD_TO_DEF_FILE = $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) \ +ADD_TO_DEF_FILE = $(PYTHON) -m mozbuild.action.preprocessor $(DEFINES) \ $(srcdir)/sqlite.def | sed -e '1,/^EXPORTS$$/ d' -e 's,sqlite3,_\0,' \ -e 's,\ DATA.*$$,,' >> $(DEF_FILE) endif diff --git a/dom/bindings/Makefile.in b/dom/bindings/Makefile.in index 18f23256405c..634d05e62866 100644 --- a/dom/bindings/Makefile.in +++ b/dom/bindings/Makefile.in @@ -157,14 +157,14 @@ $(test_webidl_files): %: $(srcdir)/test/% # a symlink, which will clobber files in the srcdir, which is bad. $(preprocessed_webidl_files): %: $(webidl_base)/% $(GLOBAL_DEPS) $(RM) $@ - PYTHONDONTWRITEBYTECODE=1 $(PYTHON) \ - $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $(webidl_base)/$* -o $@ + $(call py_action,preprocessor, \ + $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $(webidl_base)/$* -o $@) # See the comment about PP_TARGETS for $(preprocessed_webidl_files) $(preprocessed_test_webidl_files): %: $(srcdir)/test/% $(GLOBAL_DEPS) $(RM) $@ - PYTHONDONTWRITEBYTECODE=1 $(PYTHON) \ - $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $(srcdir)/test/$* -o $@ + $(call py_action,preprocessor, \ + $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $(srcdir)/test/$* -o $@) # Make is dumb and can get confused between "foo" and "$(CURDIR)/foo". Make # sure that the latter depends on the former, since the latter gets used in .pp diff --git a/js/src/Makefile.in b/js/src/Makefile.in index af179f3ac852..58889ccf9130 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -179,8 +179,8 @@ ifeq (Linux,$(OS_TARGET)) EXTRA_DSO_LDOPTS += -Wl,-version-script,symverscript symverscript: symverscript.in - $(PYTHON) $(topsrcdir)/config/Preprocessor.py \ - -DVERSION="$(subst -,_,$(LIBRARY_NAME))" $< > $@ + $(call py_action,preprocessor, \ + -DVERSION="$(subst -,_,$(LIBRARY_NAME))" $< -o $@) EXTRA_DEPS += symverscript endif @@ -526,14 +526,14 @@ JS_CONFIG_SUBSTITUTIONS=\ $(JS_CONFIG_NAME): js-config.in Makefile $(DEPTH)/config/autoconf.mk $(topsrcdir)/config/config.mk $(topsrcdir)/config/rules.mk $(RM) $@.tmp - $(PYTHON) $(topsrcdir)/config/Preprocessor.py --marker % $(JS_CONFIG_SUBSTITUTIONS) $< > $@.tmp \ - && mv $@.tmp $@ && chmod +x $@ + $(call py_action,preprocessor,--marker % $(JS_CONFIG_SUBSTITUTIONS) $< -o $@.tmp) + mv $@.tmp $@ && chmod +x $@ SCRIPTS = $(JS_CONFIG_NAME) SDK_BINARY = $(JS_CONFIG_NAME) $(LIBRARY_NAME).pc: js.pc.in - $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(JS_CONFIG_SUBSTITUTIONS) $< > $@ + $(call py_action,preprocessor,$(JS_CONFIG_SUBSTITUTIONS) $< -o $@) install:: $(LIBRARY_NAME).pc $(SYSINSTALL) $^ $(DESTDIR)$(libdir)/pkgconfig diff --git a/js/src/config/Expression.py b/js/src/config/Expression.py deleted file mode 100644 index 3e91ae46858c..000000000000 --- a/js/src/config/Expression.py +++ /dev/null @@ -1,241 +0,0 @@ -# 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/. - -""" -Parses and evaluates simple statements for Preprocessor: - -Expression currently supports the following grammar, whitespace is ignored: - -expression : - and_cond ( '||' expression ) ? ; -and_cond: - test ( '&&' and_cond ) ? ; -test: - unary ( ( '==' | '!=' ) unary ) ? ; -unary : - '!'? value ; -value : - [0-9]+ # integer - | 'defined(' \w+ ')' - | \w+ # string identifier or value; -""" - -import re - -class Expression: - def __init__(self, expression_string): - """ - Create a new expression with this string. - The expression will already be parsed into an Abstract Syntax Tree. - """ - self.content = expression_string - self.offset = 0 - self.__ignore_whitespace() - self.e = self.__get_logical_or() - if self.content: - raise Expression.ParseError, self - - def __get_logical_or(self): - """ - Production: and_cond ( '||' expression ) ? - """ - if not len(self.content): - return None - rv = Expression.__AST("logical_op") - # test - rv.append(self.__get_logical_and()) - self.__ignore_whitespace() - if self.content[:2] != '||': - # no logical op needed, short cut to our prime element - return rv[0] - # append operator - rv.append(Expression.__ASTLeaf('op', self.content[:2])) - self.__strip(2) - self.__ignore_whitespace() - rv.append(self.__get_logical_or()) - self.__ignore_whitespace() - return rv - - def __get_logical_and(self): - """ - Production: test ( '&&' and_cond ) ? - """ - if not len(self.content): - return None - rv = Expression.__AST("logical_op") - # test - rv.append(self.__get_equality()) - self.__ignore_whitespace() - if self.content[:2] != '&&': - # no logical op needed, short cut to our prime element - return rv[0] - # append operator - rv.append(Expression.__ASTLeaf('op', self.content[:2])) - self.__strip(2) - self.__ignore_whitespace() - rv.append(self.__get_logical_and()) - self.__ignore_whitespace() - return rv - - def __get_equality(self): - """ - Production: unary ( ( '==' | '!=' ) unary ) ? - """ - if not len(self.content): - return None - rv = Expression.__AST("equality") - # unary - rv.append(self.__get_unary()) - self.__ignore_whitespace() - if not re.match('[=!]=', self.content): - # no equality needed, short cut to our prime unary - return rv[0] - # append operator - rv.append(Expression.__ASTLeaf('op', self.content[:2])) - self.__strip(2) - self.__ignore_whitespace() - rv.append(self.__get_unary()) - self.__ignore_whitespace() - return rv - - def __get_unary(self): - """ - Production: '!'? value - """ - # eat whitespace right away, too - not_ws = re.match('!\s*', self.content) - if not not_ws: - return self.__get_value() - rv = Expression.__AST('not') - self.__strip(not_ws.end()) - rv.append(self.__get_value()) - self.__ignore_whitespace() - return rv - - def __get_value(self): - """ - Production: ( [0-9]+ | 'defined(' \w+ ')' | \w+ ) - Note that the order is important, and the expression is kind-of - ambiguous as \w includes 0-9. One could make it unambiguous by - removing 0-9 from the first char of a string literal. - """ - rv = None - m = re.match('defined\s*\(\s*(\w+)\s*\)', self.content) - if m: - word_len = m.end() - rv = Expression.__ASTLeaf('defined', m.group(1)) - else: - word_len = re.match('[0-9]*', self.content).end() - if word_len: - value = int(self.content[:word_len]) - rv = Expression.__ASTLeaf('int', value) - else: - word_len = re.match('\w*', self.content).end() - if word_len: - rv = Expression.__ASTLeaf('string', self.content[:word_len]) - else: - raise Expression.ParseError, self - self.__strip(word_len) - self.__ignore_whitespace() - return rv - - def __ignore_whitespace(self): - ws_len = re.match('\s*', self.content).end() - self.__strip(ws_len) - return - - def __strip(self, length): - """ - Remove a given amount of chars from the input and update - the offset. - """ - self.content = self.content[length:] - self.offset += length - - def evaluate(self, context): - """ - Evaluate the expression with the given context - """ - - # Helper function to evaluate __get_equality results - def eval_equality(tok): - left = opmap[tok[0].type](tok[0]) - right = opmap[tok[2].type](tok[2]) - rv = left == right - if tok[1].value == '!=': - rv = not rv - return rv - # Helper function to evaluate __get_logical_and and __get_logical_or results - def eval_logical_op(tok): - left = opmap[tok[0].type](tok[0]) - right = opmap[tok[2].type](tok[2]) - if tok[1].value == '&&': - return left and right - elif tok[1].value == '||': - return left or right - raise Expression.ParseError, self - - # Mapping from token types to evaluator functions - # Apart from (non-)equality, all these can be simple lambda forms. - opmap = { - 'logical_op': eval_logical_op, - 'equality': eval_equality, - 'not': lambda tok: not opmap[tok[0].type](tok[0]), - 'string': lambda tok: context[tok.value], - 'defined': lambda tok: tok.value in context, - 'int': lambda tok: tok.value} - - return opmap[self.e.type](self.e); - - class __AST(list): - """ - Internal class implementing Abstract Syntax Tree nodes - """ - def __init__(self, type): - self.type = type - super(self.__class__, self).__init__(self) - - class __ASTLeaf: - """ - Internal class implementing Abstract Syntax Tree leafs - """ - def __init__(self, type, value): - self.value = value - self.type = type - def __str__(self): - return self.value.__str__() - def __repr__(self): - return self.value.__repr__() - - class ParseError(StandardError): - """ - Error raised when parsing fails. - It has two members, offset and content, which give the offset of the - error and the offending content. - """ - def __init__(self, expression): - self.offset = expression.offset - self.content = expression.content[:3] - def __str__(self): - return 'Unexpected content at offset {0}, "{1}"'.format(self.offset, - self.content) - -class Context(dict): - """ - This class holds variable values by subclassing dict, and while it - truthfully reports True and False on - - name in context - - it returns the variable name itself on - - context["name"] - - to reflect the ambiguity between string literals and preprocessor - variables. - """ - def __getitem__(self, key): - if key in self: - return super(self.__class__, self).__getitem__(key) - return key diff --git a/js/src/config/Makefile.in b/js/src/config/Makefile.in index 25e470e46399..6195d37d8422 100644 --- a/js/src/config/Makefile.in +++ b/js/src/config/Makefile.in @@ -40,7 +40,7 @@ ifdef WRAP_SYSTEM_INCLUDES export:: \ $(call mkdir_deps,system_wrappers_js) \ $(NULL) - $(PYTHON) $(srcdir)/Preprocessor.py $(DEFINES) $(ACDEFINES) \ + $(PYTHON) -m mozbuild.action.preprocessor $(DEFINES) $(ACDEFINES) \ -DMOZ_NATIVE_ICU=$(MOZ_NATIVE_ICU) \ $(srcdir)/system-headers | $(PERL) $(srcdir)/make-system-wrappers.pl system_wrappers_js $(INSTALL) system_wrappers_js $(DIST) diff --git a/js/src/config/Preprocessor.py b/js/src/config/Preprocessor.py deleted file mode 100755 index 86891acaf3c6..000000000000 --- a/js/src/config/Preprocessor.py +++ /dev/null @@ -1,492 +0,0 @@ -""" -This is a very primitive line based preprocessor, for times when using -a C preprocessor isn't an option. -""" - -# 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/. - -import sys -import os -import os.path -import re -from optparse import OptionParser -import errno - -# hack around win32 mangling our line endings -# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65443 -if sys.platform == "win32": - import msvcrt - msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) - os.linesep = '\n' - -import Expression - -__all__ = ['Preprocessor', 'preprocess'] - - -class Preprocessor: - """ - Class for preprocessing text files. - """ - class Error(RuntimeError): - def __init__(self, cpp, MSG, context): - self.file = cpp.context['FILE'] - self.line = cpp.context['LINE'] - self.key = MSG - RuntimeError.__init__(self, (self.file, self.line, self.key, context)) - def __init__(self): - self.context = Expression.Context() - for k,v in {'FILE': '', - 'LINE': 0, - 'DIRECTORY': os.path.abspath('.')}.iteritems(): - self.context[k] = v - self.actionLevel = 0 - self.disableLevel = 0 - # ifStates can be - # 0: hadTrue - # 1: wantsTrue - # 2: #else found - self.ifStates = [] - self.checkLineNumbers = False - self.writtenLines = 0 - self.filters = [] - self.cmds = {} - for cmd, level in {'define': 0, - 'undef': 0, - 'if': sys.maxint, - 'ifdef': sys.maxint, - 'ifndef': sys.maxint, - 'else': 1, - 'elif': 1, - 'elifdef': 1, - 'elifndef': 1, - 'endif': sys.maxint, - 'expand': 0, - 'literal': 0, - 'filter': 0, - 'unfilter': 0, - 'include': 0, - 'includesubst': 0, - 'error': 0}.iteritems(): - self.cmds[cmd] = (level, getattr(self, 'do_' + cmd)) - self.out = sys.stdout - self.setMarker('#') - self.LE = '\n' - self.varsubst = re.compile('@(?P\w+)@', re.U) - - def warnUnused(self, file): - if self.actionLevel == 0: - sys.stderr.write('{0}: WARNING: no preprocessor directives found\n'.format(file)) - elif self.actionLevel == 1: - sys.stderr.write('{0}: WARNING: no useful preprocessor directives found\n'.format(file)) - pass - - def setLineEndings(self, aLE): - """ - Set the line endings to be used for output. - """ - self.LE = {'cr': '\x0D', 'lf': '\x0A', 'crlf': '\x0D\x0A'}[aLE] - - def setMarker(self, aMarker): - """ - Set the marker to be used for processing directives. - Used for handling CSS files, with pp.setMarker('%'), for example. - The given marker may be None, in which case no markers are processed. - """ - self.marker = aMarker - if aMarker: - self.instruction = re.compile('{0}(?P[a-z]+)(?:\s(?P.*))?$' - .format(aMarker), - re.U) - self.comment = re.compile(aMarker, re.U) - else: - class NoMatch(object): - def match(self, *args): - return False - self.instruction = self.comment = NoMatch() - - def clone(self): - """ - Create a clone of the current processor, including line ending - settings, marker, variable definitions, output stream. - """ - rv = Preprocessor() - rv.context.update(self.context) - rv.setMarker(self.marker) - rv.LE = self.LE - rv.out = self.out - return rv - - def applyFilters(self, aLine): - for f in self.filters: - aLine = f[1](aLine) - return aLine - - def write(self, aLine): - """ - Internal method for handling output. - """ - if self.checkLineNumbers: - self.writtenLines += 1 - ln = self.context['LINE'] - if self.writtenLines != ln: - self.out.write('//@line {line} "{file}"{le}'.format(line=ln, - file=self.context['FILE'], - le=self.LE)) - self.writtenLines = ln - filteredLine = self.applyFilters(aLine) - if filteredLine != aLine: - self.actionLevel = 2 - # ensure our line ending. Only need to handle \n, as we're reading - # with universal line ending support, at least for files. - filteredLine = re.sub('\n', self.LE, filteredLine) - self.out.write(filteredLine) - - def handleCommandLine(self, args, defaultToStdin = False): - """ - Parse a commandline into this parser. - Uses OptionParser internally, no args mean sys.argv[1:]. - """ - p = self.getCommandLineParser() - (options, args) = p.parse_args(args=args) - includes = options.I - if options.output: - dir = os.path.dirname(options.output) - if dir and not os.path.exists(dir): - try: - os.makedirs(dir) - except OSError as error: - if error.errno != errno.EEXIST: - raise - self.out = open(options.output, 'wb') - if defaultToStdin and len(args) == 0: - args = [sys.stdin] - includes.extend(args) - if includes: - for f in includes: - self.do_include(f, False) - self.warnUnused(f) - pass - - def getCommandLineParser(self, unescapeDefines = False): - escapedValue = re.compile('".*"$') - numberValue = re.compile('\d+$') - def handleE(option, opt, value, parser): - for k,v in os.environ.iteritems(): - self.context[k] = v - def handleD(option, opt, value, parser): - vals = value.split('=', 1) - if len(vals) == 1: - vals.append(1) - elif unescapeDefines and escapedValue.match(vals[1]): - # strip escaped string values - vals[1] = vals[1][1:-1] - elif numberValue.match(vals[1]): - vals[1] = int(vals[1]) - self.context[vals[0]] = vals[1] - def handleU(option, opt, value, parser): - del self.context[value] - def handleF(option, opt, value, parser): - self.do_filter(value) - def handleLE(option, opt, value, parser): - self.setLineEndings(value) - def handleMarker(option, opt, value, parser): - self.setMarker(value) - p = OptionParser() - p.add_option('-I', action='append', type="string", default = [], - metavar="FILENAME", help='Include file') - p.add_option('-E', action='callback', callback=handleE, - help='Import the environment into the defined variables') - p.add_option('-D', action='callback', callback=handleD, type="string", - metavar="VAR[=VAL]", help='Define a variable') - p.add_option('-U', action='callback', callback=handleU, type="string", - metavar="VAR", help='Undefine a variable') - p.add_option('-F', action='callback', callback=handleF, type="string", - metavar="FILTER", help='Enable the specified filter') - p.add_option('-o', '--output', type="string", default=None, - metavar="FILENAME", help='Output to the specified file '+ - 'instead of stdout') - p.add_option('--line-endings', action='callback', callback=handleLE, - type="string", metavar="[cr|lr|crlf]", - help='Use the specified line endings [Default: OS dependent]') - p.add_option('--marker', action='callback', callback=handleMarker, - type="string", - help='Use the specified marker instead of #') - return p - - def handleLine(self, aLine): - """ - Handle a single line of input (internal). - """ - if self.actionLevel == 0 and self.comment.match(aLine): - self.actionLevel = 1 - m = self.instruction.match(aLine) - if m: - args = None - cmd = m.group('cmd') - try: - args = m.group('args') - except IndexError: - pass - if cmd not in self.cmds: - raise Preprocessor.Error(self, 'INVALID_CMD', aLine) - level, cmd = self.cmds[cmd] - if (level >= self.disableLevel): - cmd(args) - if cmd != 'literal': - self.actionLevel = 2 - elif self.disableLevel == 0 and not self.comment.match(aLine): - self.write(aLine) - pass - - # Instruction handlers - # These are named do_'instruction name' and take one argument - - # Variables - def do_define(self, args): - m = re.match('(?P\w+)(?:\s(?P.*))?', args, re.U) - if not m: - raise Preprocessor.Error(self, 'SYNTAX_DEF', args) - val = 1 - if m.group('value'): - val = self.applyFilters(m.group('value')) - try: - val = int(val) - except: - pass - self.context[m.group('name')] = val - def do_undef(self, args): - m = re.match('(?P\w+)$', args, re.U) - if not m: - raise Preprocessor.Error(self, 'SYNTAX_DEF', args) - if args in self.context: - del self.context[args] - # Logic - def ensure_not_else(self): - if len(self.ifStates) == 0 or self.ifStates[-1] == 2: - sys.stderr.write('WARNING: bad nesting of #else\n') - def do_if(self, args, replace=False): - if self.disableLevel and not replace: - self.disableLevel += 1 - return - val = None - try: - e = Expression.Expression(args) - val = e.evaluate(self.context) - except Exception: - # XXX do real error reporting - raise Preprocessor.Error(self, 'SYNTAX_ERR', args) - if type(val) == str: - # we're looking for a number value, strings are false - val = False - if not val: - self.disableLevel = 1 - if replace: - if val: - self.disableLevel = 0 - self.ifStates[-1] = self.disableLevel - else: - self.ifStates.append(self.disableLevel) - pass - def do_ifdef(self, args, replace=False): - if self.disableLevel and not replace: - self.disableLevel += 1 - return - if re.match('\W', args, re.U): - raise Preprocessor.Error(self, 'INVALID_VAR', args) - if args not in self.context: - self.disableLevel = 1 - if replace: - if args in self.context: - self.disableLevel = 0 - self.ifStates[-1] = self.disableLevel - else: - self.ifStates.append(self.disableLevel) - pass - def do_ifndef(self, args, replace=False): - if self.disableLevel and not replace: - self.disableLevel += 1 - return - if re.match('\W', args, re.U): - raise Preprocessor.Error(self, 'INVALID_VAR', args) - if args in self.context: - self.disableLevel = 1 - if replace: - if args not in self.context: - self.disableLevel = 0 - self.ifStates[-1] = self.disableLevel - else: - self.ifStates.append(self.disableLevel) - pass - def do_else(self, args, ifState = 2): - self.ensure_not_else() - hadTrue = self.ifStates[-1] == 0 - self.ifStates[-1] = ifState # in-else - if hadTrue: - self.disableLevel = 1 - return - self.disableLevel = 0 - def do_elif(self, args): - if self.disableLevel == 1: - if self.ifStates[-1] == 1: - self.do_if(args, replace=True) - else: - self.do_else(None, self.ifStates[-1]) - def do_elifdef(self, args): - if self.disableLevel == 1: - if self.ifStates[-1] == 1: - self.do_ifdef(args, replace=True) - else: - self.do_else(None, self.ifStates[-1]) - def do_elifndef(self, args): - if self.disableLevel == 1: - if self.ifStates[-1] == 1: - self.do_ifndef(args, replace=True) - else: - self.do_else(None, self.ifStates[-1]) - def do_endif(self, args): - if self.disableLevel > 0: - self.disableLevel -= 1 - if self.disableLevel == 0: - self.ifStates.pop() - # output processing - def do_expand(self, args): - lst = re.split('__(\w+)__', args, re.U) - do_replace = False - def vsubst(v): - if v in self.context: - return str(self.context[v]) - return '' - for i in range(1, len(lst), 2): - lst[i] = vsubst(lst[i]) - lst.append('\n') # add back the newline - self.write(reduce(lambda x, y: x+y, lst, '')) - def do_literal(self, args): - self.write(args + self.LE) - def do_filter(self, args): - filters = [f for f in args.split(' ') if hasattr(self, 'filter_' + f)] - if len(filters) == 0: - return - current = dict(self.filters) - for f in filters: - current[f] = getattr(self, 'filter_' + f) - filterNames = current.keys() - filterNames.sort() - self.filters = [(fn, current[fn]) for fn in filterNames] - return - def do_unfilter(self, args): - filters = args.split(' ') - current = dict(self.filters) - for f in filters: - if f in current: - del current[f] - filterNames = current.keys() - filterNames.sort() - self.filters = [(fn, current[fn]) for fn in filterNames] - return - # Filters - # - # emptyLines - # Strips blank lines from the output. - def filter_emptyLines(self, aLine): - if aLine == '\n': - return '' - return aLine - # slashslash - # Strips everything after // - def filter_slashslash(self, aLine): - if (aLine.find('//') == -1): - return aLine - [aLine, rest] = aLine.split('//', 1) - if rest: - aLine += '\n' - return aLine - # spaces - # Collapses sequences of spaces into a single space - def filter_spaces(self, aLine): - return re.sub(' +', ' ', aLine).strip(' ') - # substition - # helper to be used by both substition and attemptSubstitution - def filter_substitution(self, aLine, fatal=True): - def repl(matchobj): - varname = matchobj.group('VAR') - if varname in self.context: - return str(self.context[varname]) - if fatal: - raise Preprocessor.Error(self, 'UNDEFINED_VAR', varname) - return matchobj.group(0) - return self.varsubst.sub(repl, aLine) - def filter_attemptSubstitution(self, aLine): - return self.filter_substitution(aLine, fatal=False) - # File ops - def do_include(self, args, filters=True): - """ - Preprocess a given file. - args can either be a file name, or a file-like object. - Files should be opened, and will be closed after processing. - """ - isName = type(args) == str or type(args) == unicode - oldWrittenLines = self.writtenLines - oldCheckLineNumbers = self.checkLineNumbers - self.checkLineNumbers = False - if isName: - try: - args = str(args) - if filters: - args = self.applyFilters(args) - if not os.path.isabs(args): - args = os.path.join(self.context['DIRECTORY'], args) - args = open(args, 'rU') - except Preprocessor.Error: - raise - except: - raise Preprocessor.Error(self, 'FILE_NOT_FOUND', str(args)) - self.checkLineNumbers = bool(re.search('\.(js|jsm|java)(?:\.in)?$', args.name)) - oldFile = self.context['FILE'] - oldLine = self.context['LINE'] - oldDir = self.context['DIRECTORY'] - if args.isatty(): - # we're stdin, use '-' and '' for file and dir - self.context['FILE'] = '-' - self.context['DIRECTORY'] = '' - else: - abspath = os.path.abspath(args.name) - self.context['FILE'] = abspath - self.context['DIRECTORY'] = os.path.dirname(abspath) - self.context['LINE'] = 0 - self.writtenLines = 0 - for l in args: - self.context['LINE'] += 1 - self.handleLine(l) - args.close() - self.context['FILE'] = oldFile - self.checkLineNumbers = oldCheckLineNumbers - self.writtenLines = oldWrittenLines - self.context['LINE'] = oldLine - self.context['DIRECTORY'] = oldDir - def do_includesubst(self, args): - args = self.filter_substitution(args) - self.do_include(args) - def do_error(self, args): - raise Preprocessor.Error(self, 'Error: ', str(args)) - -def main(): - pp = Preprocessor() - pp.handleCommandLine(None, True) - return - -def preprocess(includes=[sys.stdin], defines={}, - output = sys.stdout, - line_endings='\n', marker='#'): - pp = Preprocessor() - pp.context.update(defines) - pp.setLineEndings(line_endings) - pp.setMarker(marker) - pp.out = output - for f in includes: - pp.do_include(f, False) - -if __name__ == "__main__": - main() diff --git a/js/src/config/rules.mk b/js/src/config/rules.mk index 0834e6a430c6..95073b567ddb 100644 --- a/js/src/config/rules.mk +++ b/js/src/config/rules.mk @@ -1559,16 +1559,16 @@ $(sort $(foreach tier,$(INSTALL_TARGETS_TIERS),$(INSTALL_TARGETS_EXECUTABLES_$(t # If PP_TARGETS lists a category name (like FOO, above), then we consult the # following make variables to see what to do: # -# - lists input files to be preprocessed with config/Preprocessor.py. We -# search VPATH for the names given here. If an input file name ends in '.in', -# that suffix is omitted from the output file name. +# - lists input files to be preprocessed with mozbuild.action.preprocessor. +# We search VPATH for the names given here. If an input file name ends in +# '.in', that suffix is omitted from the output file name. # # - _PATH names the directory in which to place the preprocessed output # files. We create this directory if it does not already exist. Setting # this variable is optional; if unset, we install the files in $(CURDIR). # -# - _FLAGS lists flags to pass to Preprocessor.py, in addition to the usual -# bunch. Setting this variable is optional. +# - _FLAGS lists flags to pass to mozbuild.action.preprocessor, in addition +# to the usual bunch. Setting this variable is optional. # # - _TARGET names the 'make' target that should depend on creating the output # files. Setting this variable is optional; if unset, we preprocess the @@ -1604,7 +1604,7 @@ $(sort $(foreach tier,$(PP_TARGETS_TIERS),$(PP_TARGETS_RESULTS_$(tier)))): $(if $(filter-out $(notdir $@),$(notdir $(<:.in=))),$(error Looks like $@ has an unexpected dependency on $< which breaks PP_TARGETS)) $(REPORT_BUILD) $(RM) "$@" - $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PP_TARGET_FLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) "$<" -o "$@" + $(call py_action,preprocessor,$(PP_TARGET_FLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) "$<" -o "$@") # Pull in non-recursive targets if this is a partial tree build. diff --git a/js/xpconnect/src/Makefile.in b/js/xpconnect/src/Makefile.in index f0d72f516a8a..13fdb2836383 100644 --- a/js/xpconnect/src/Makefile.in +++ b/js/xpconnect/src/Makefile.in @@ -113,7 +113,7 @@ GeneratedEvents.$(OBJ_SUFFIX): GeneratedEvents.h \ GeneratedEvents.cpp event_impl_gen.conf : $(srcdir)/event_impl_gen.conf.in - $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $^ > event_impl_gen.conf + $(call py_action,preprocessor,$(DEFINES) $(ACDEFINES) $^ -o event_impl_gen.conf) GeneratedEvents.h: $(srcdir)/dictionary_helper_gen.conf \ event_impl_gen.conf \ diff --git a/js/xpconnect/tests/components/js/Makefile.in b/js/xpconnect/tests/components/js/Makefile.in index 3de3001a593b..c7850db60822 100644 --- a/js/xpconnect/tests/components/js/Makefile.in +++ b/js/xpconnect/tests/components/js/Makefile.in @@ -22,4 +22,4 @@ libs:: $(JS_FILES) $(INSTALL) $^ $(testxpcobjdir)/$(componentdir) libs:: $(MANIFEST_FILE) - $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $< > $(testxpcobjdir)/$(componentdir)/$( $@ + $(call py_action,preprocessor,--marker=% $(DEFINES) $(ACDEFINES) $< -o $@) libs:: $(DIST)/bin/res/fonts/$(math_properties) install:: $(DESTDIR)$(mozappdir)/res/fonts/$(math_properties) diff --git a/layout/media/Makefile.in b/layout/media/Makefile.in index 0637670a0c3a..18e41fbe45b5 100644 --- a/layout/media/Makefile.in +++ b/layout/media/Makefile.in @@ -116,7 +116,7 @@ include $(topsrcdir)/config/rules.mk ifeq (WINNT,$(OS_TARGET)) symbols.def: symbols.def.in $(GLOBAL_DEPS) - $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(ACDEFINES) $< > $@ + $(call py_action,preprocessor,$(ACDEFINES) $< -o $@) OS_LIBS += $(call EXPAND_LIBNAME, msimg32) diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in index 2490c47d2c9e..3d2d8e154630 100644 --- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -178,12 +178,11 @@ android-preqs = \ Makefile.in \ widget/GeckoView.java.frag \ $(SERVICES_MANIFEST_FRAGMENTS) \ - $(call mkdir_deps,$(sort $(dir $(PP_JAVAFILES)))) \ $(NULL) $(android-tgts): % : %.in $(android-preqs) - $(PYTHON) $(topsrcdir)/config/Preprocessor.py \ - $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $< > $@ + $(call py_action,preprocessor, \ + $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $< -o $@) res/drawable-mdpi/icon.png: $(ICON_PATH) $(NSINSTALL) -D res/drawable-mdpi diff --git a/mobile/android/base/locales/Makefile.in b/mobile/android/base/locales/Makefile.in index 25d5e75d5103..acbb04cb5268 100644 --- a/mobile/android/base/locales/Makefile.in +++ b/mobile/android/base/locales/Makefile.in @@ -62,9 +62,7 @@ strings-xml-preqs =\ $(if $(MOZ_ANDROID_SHARED_ACCOUNT_TYPE),,$(error Missing MOZ_ANDROID_SHARED_ACCOUNT_TYPE)) $(dir-strings-xml)/strings.xml: $(strings-xml-preqs) - $(NSINSTALL) -D $(dir-strings-xml) - $(TOUCH) $(call mkdir_deps,$(dir-strings-xml)) - $(PYTHON) $(topsrcdir)/config/Preprocessor.py \ + $(call py_action,preprocessor, \ $(DEFINES) \ -DANDROID_PACKAGE_NAME=$(ANDROID_PACKAGE_NAME) \ -DBOOKMARKSPATH="$(BOOKMARKSPATH)" \ @@ -74,4 +72,4 @@ $(dir-strings-xml)/strings.xml: $(strings-xml-preqs) -DSTRINGSPATH="$(STRINGSPATH)" \ -DSYNCSTRINGSPATH="$(SYNCSTRINGSPATH)" \ $< \ - > $@ + -o $@) diff --git a/mobile/android/installer/Makefile.in b/mobile/android/installer/Makefile.in index a2f3cb8a9d5f..1c982726412e 100644 --- a/mobile/android/installer/Makefile.in +++ b/mobile/android/installer/Makefile.in @@ -47,7 +47,7 @@ endif ifdef MOZ_PKG_MANIFEST_P $(MOZ_PKG_MANIFEST): $(MOZ_PKG_MANIFEST_P) $(GLOBAL_DEPS) - $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $< > $@ + $(call py_action,preprocessor,$(DEFINES) $(ACDEFINES) $< -o $@) ifdef MOZ_CHROME_MULTILOCALE printf "\n[multilocale]\n" >> $@ for LOCALE in en-US $(MOZ_CHROME_MULTILOCALE) ;\ diff --git a/mobile/locales/Makefile.in b/mobile/locales/Makefile.in index f928917e1d55..44f17538389e 100644 --- a/mobile/locales/Makefile.in +++ b/mobile/locales/Makefile.in @@ -177,21 +177,19 @@ bookmarks-inc = $(firstword $(bookmarks-inc-array)) bookmarks-preqs = \ $(bookmarks-inc) \ - $(call mkdir_deps,$(dir $(bookmarks-ts))) \ $(src-bookmarks) \ generic/profile/$(bookmarks).in \ - $(topsrcdir)/config/Preprocessor.py \ $(if $(IS_LANGUAGE_REPACK),FORCE) \ $(GLOBAL_DEPS) \ $(NULL) $(bookmarks-ts): $(bookmarks-preqs) $(display_deps) - $(PYTHON) $(topsrcdir)/config/Preprocessor.py \ + $(call py_action,preprocessor, \ -I $< \ -DAB_CD=$(NO_JA_JP_MAC_AB_CD) \ $(src-bookmarks) \ - > $@ + -o $@) .PHONY: bookmarks $(bookmarks) bookmarks: $(bookmarks) diff --git a/modules/libmar/tests/Makefile.in b/modules/libmar/tests/Makefile.in index fbe09d93c6c5..d3779410a559 100644 --- a/modules/libmar/tests/Makefile.in +++ b/modules/libmar/tests/Makefile.in @@ -9,7 +9,7 @@ DEFINES += -DBIN_SUFFIX=$(BIN_SUFFIX) include $(topsrcdir)/config/rules.mk libs:: unit/head_libmar.js.in - $(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py -Fsubstitution $(DEFINES) $(ACDEFINES) $^ > $(TESTROOT)/unit/head_libmar.js + $(call py_action,preprocessor,-Fsubstitution $(DEFINES) $(ACDEFINES) $^ -o $(TESTROOT)/unit/head_libmar.js) ifneq ($(OS_TARGET),Android) ifndef MOZ_PROFILE_GENERATE diff --git a/modules/libpref/src/Makefile.in b/modules/libpref/src/Makefile.in index 31333bce9427..e4ca661d02cb 100644 --- a/modules/libpref/src/Makefile.in +++ b/modules/libpref/src/Makefile.in @@ -40,7 +40,7 @@ endif greprefs.js: $(grepref_files) - $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PREF_PPFLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $^ > $@ + $(call py_action,preprocessor,$(PREF_PPFLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $^ -o $@) libs:: greprefs.js $(INSTALL) $^ $(DIST)/bin/ diff --git a/mozglue/build/Makefile.in b/mozglue/build/Makefile.in index 0ad69ec9fa94..cd4dae23975a 100644 --- a/mozglue/build/Makefile.in +++ b/mozglue/build/Makefile.in @@ -36,7 +36,7 @@ ifeq (WINNT,$(OS_TARGET)) DEFFILE = mozglue.def mozglue.def: mozglue.def.in - $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(if $(MOZ_REPLACE_MALLOC),-DMOZ_REPLACE_MALLOC) $(ACDEFINES) $< > $@ + $(call py_action,preprocessor,$(if $(MOZ_REPLACE_MALLOC),-DMOZ_REPLACE_MALLOC) $(ACDEFINES) $< -o $@) GARBAGE += mozglue.def diff --git a/python/mozbuild/mozbuild/action/preprocessor.py b/python/mozbuild/mozbuild/action/preprocessor.py new file mode 100644 index 000000000000..d99e1f831a4e --- /dev/null +++ b/python/mozbuild/mozbuild/action/preprocessor.py @@ -0,0 +1,16 @@ +# 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/. + +import sys + +from mozbuild.preprocessor import Preprocessor + + +def main(args): + pp = Preprocessor() + pp.handleCommandLine(args, True) + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/python/mozbuild/mozbuild/backend/configenvironment.py b/python/mozbuild/mozbuild/backend/configenvironment.py index 7f5e75d2afe0..e2ea97eeea97 100644 --- a/python/mozbuild/mozbuild/backend/configenvironment.py +++ b/python/mozbuild/mozbuild/backend/configenvironment.py @@ -10,7 +10,7 @@ import sys from os.path import relpath -from Preprocessor import Preprocessor +from mozbuild.preprocessor import Preprocessor from ..util import ( ensureParentDir, diff --git a/python/mozbuild/mozbuild/jar.py b/python/mozbuild/mozbuild/jar.py index 74b0f4392bcb..7e830b2e0331 100644 --- a/python/mozbuild/mozbuild/jar.py +++ b/python/mozbuild/mozbuild/jar.py @@ -22,7 +22,7 @@ from mozbuild.util import ( PushbackIter, ) -from Preprocessor import Preprocessor +from mozbuild.preprocessor import Preprocessor from mozbuild.action.buildlist import addEntriesToListFile if sys.platform == 'win32': from ctypes import windll, WinError diff --git a/config/Preprocessor.py b/python/mozbuild/mozbuild/preprocessor.py similarity index 69% rename from config/Preprocessor.py rename to python/mozbuild/mozbuild/preprocessor.py index 86891acaf3c6..f1938314d537 100644 --- a/config/Preprocessor.py +++ b/python/mozbuild/mozbuild/preprocessor.py @@ -1,6 +1,22 @@ """ This is a very primitive line based preprocessor, for times when using a C preprocessor isn't an option. + +It currently supports the following grammar for expressions, whitespace is +ignored: + +expression : + and_cond ( '||' expression ) ? ; +and_cond: + test ( '&&' and_cond ) ? ; +test: + unary ( ( '==' | '!=' ) unary ) ? ; +unary : + '!'? value ; +value : + [0-9]+ # integer + | 'defined(' \w+ ')' + | \w+ # string identifier or value; """ # This Source Code Form is subject to the terms of the Mozilla Public @@ -21,9 +37,231 @@ if sys.platform == "win32": msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) os.linesep = '\n' -import Expression -__all__ = ['Preprocessor', 'preprocess'] +__all__ = [ + 'Context', + 'Expression', + 'Preprocessor', + 'preprocess' +] + + +class Expression: + def __init__(self, expression_string): + """ + Create a new expression with this string. + The expression will already be parsed into an Abstract Syntax Tree. + """ + self.content = expression_string + self.offset = 0 + self.__ignore_whitespace() + self.e = self.__get_logical_or() + if self.content: + raise Expression.ParseError, self + + def __get_logical_or(self): + """ + Production: and_cond ( '||' expression ) ? + """ + if not len(self.content): + return None + rv = Expression.__AST("logical_op") + # test + rv.append(self.__get_logical_and()) + self.__ignore_whitespace() + if self.content[:2] != '||': + # no logical op needed, short cut to our prime element + return rv[0] + # append operator + rv.append(Expression.__ASTLeaf('op', self.content[:2])) + self.__strip(2) + self.__ignore_whitespace() + rv.append(self.__get_logical_or()) + self.__ignore_whitespace() + return rv + + def __get_logical_and(self): + """ + Production: test ( '&&' and_cond ) ? + """ + if not len(self.content): + return None + rv = Expression.__AST("logical_op") + # test + rv.append(self.__get_equality()) + self.__ignore_whitespace() + if self.content[:2] != '&&': + # no logical op needed, short cut to our prime element + return rv[0] + # append operator + rv.append(Expression.__ASTLeaf('op', self.content[:2])) + self.__strip(2) + self.__ignore_whitespace() + rv.append(self.__get_logical_and()) + self.__ignore_whitespace() + return rv + + def __get_equality(self): + """ + Production: unary ( ( '==' | '!=' ) unary ) ? + """ + if not len(self.content): + return None + rv = Expression.__AST("equality") + # unary + rv.append(self.__get_unary()) + self.__ignore_whitespace() + if not re.match('[=!]=', self.content): + # no equality needed, short cut to our prime unary + return rv[0] + # append operator + rv.append(Expression.__ASTLeaf('op', self.content[:2])) + self.__strip(2) + self.__ignore_whitespace() + rv.append(self.__get_unary()) + self.__ignore_whitespace() + return rv + + def __get_unary(self): + """ + Production: '!'? value + """ + # eat whitespace right away, too + not_ws = re.match('!\s*', self.content) + if not not_ws: + return self.__get_value() + rv = Expression.__AST('not') + self.__strip(not_ws.end()) + rv.append(self.__get_value()) + self.__ignore_whitespace() + return rv + + def __get_value(self): + """ + Production: ( [0-9]+ | 'defined(' \w+ ')' | \w+ ) + Note that the order is important, and the expression is kind-of + ambiguous as \w includes 0-9. One could make it unambiguous by + removing 0-9 from the first char of a string literal. + """ + rv = None + m = re.match('defined\s*\(\s*(\w+)\s*\)', self.content) + if m: + word_len = m.end() + rv = Expression.__ASTLeaf('defined', m.group(1)) + else: + word_len = re.match('[0-9]*', self.content).end() + if word_len: + value = int(self.content[:word_len]) + rv = Expression.__ASTLeaf('int', value) + else: + word_len = re.match('\w*', self.content).end() + if word_len: + rv = Expression.__ASTLeaf('string', self.content[:word_len]) + else: + raise Expression.ParseError, self + self.__strip(word_len) + self.__ignore_whitespace() + return rv + + def __ignore_whitespace(self): + ws_len = re.match('\s*', self.content).end() + self.__strip(ws_len) + return + + def __strip(self, length): + """ + Remove a given amount of chars from the input and update + the offset. + """ + self.content = self.content[length:] + self.offset += length + + def evaluate(self, context): + """ + Evaluate the expression with the given context + """ + + # Helper function to evaluate __get_equality results + def eval_equality(tok): + left = opmap[tok[0].type](tok[0]) + right = opmap[tok[2].type](tok[2]) + rv = left == right + if tok[1].value == '!=': + rv = not rv + return rv + # Helper function to evaluate __get_logical_and and __get_logical_or results + def eval_logical_op(tok): + left = opmap[tok[0].type](tok[0]) + right = opmap[tok[2].type](tok[2]) + if tok[1].value == '&&': + return left and right + elif tok[1].value == '||': + return left or right + raise Expression.ParseError, self + + # Mapping from token types to evaluator functions + # Apart from (non-)equality, all these can be simple lambda forms. + opmap = { + 'logical_op': eval_logical_op, + 'equality': eval_equality, + 'not': lambda tok: not opmap[tok[0].type](tok[0]), + 'string': lambda tok: context[tok.value], + 'defined': lambda tok: tok.value in context, + 'int': lambda tok: tok.value} + + return opmap[self.e.type](self.e); + + class __AST(list): + """ + Internal class implementing Abstract Syntax Tree nodes + """ + def __init__(self, type): + self.type = type + super(self.__class__, self).__init__(self) + + class __ASTLeaf: + """ + Internal class implementing Abstract Syntax Tree leafs + """ + def __init__(self, type, value): + self.value = value + self.type = type + def __str__(self): + return self.value.__str__() + def __repr__(self): + return self.value.__repr__() + + class ParseError(StandardError): + """ + Error raised when parsing fails. + It has two members, offset and content, which give the offset of the + error and the offending content. + """ + def __init__(self, expression): + self.offset = expression.offset + self.content = expression.content[:3] + def __str__(self): + return 'Unexpected content at offset {0}, "{1}"'.format(self.offset, + self.content) + +class Context(dict): + """ + This class holds variable values by subclassing dict, and while it + truthfully reports True and False on + + name in context + + it returns the variable name itself on + + context["name"] + + to reflect the ambiguity between string literals and preprocessor + variables. + """ + def __getitem__(self, key): + if key in self: + return super(self.__class__, self).__getitem__(key) + return key class Preprocessor: @@ -37,7 +275,7 @@ class Preprocessor: self.key = MSG RuntimeError.__init__(self, (self.file, self.line, self.key, context)) def __init__(self): - self.context = Expression.Context() + self.context = Context() for k,v in {'FILE': '', 'LINE': 0, 'DIRECTORY': os.path.abspath('.')}.iteritems(): @@ -75,7 +313,7 @@ class Preprocessor: self.setMarker('#') self.LE = '\n' self.varsubst = re.compile('@(?P\w+)@', re.U) - + def warnUnused(self, file): if self.actionLevel == 0: sys.stderr.write('{0}: WARNING: no preprocessor directives found\n'.format(file)) @@ -88,7 +326,7 @@ class Preprocessor: Set the line endings to be used for output. """ self.LE = {'cr': '\x0D', 'lf': '\x0A', 'crlf': '\x0D\x0A'}[aLE] - + def setMarker(self, aMarker): """ Set the marker to be used for processing directives. @@ -98,7 +336,7 @@ class Preprocessor: self.marker = aMarker if aMarker: self.instruction = re.compile('{0}(?P[a-z]+)(?:\s(?P.*))?$' - .format(aMarker), + .format(aMarker), re.U) self.comment = re.compile(aMarker, re.U) else: @@ -106,7 +344,7 @@ class Preprocessor: def match(self, *args): return False self.instruction = self.comment = NoMatch() - + def clone(self): """ Create a clone of the current processor, including line ending @@ -118,12 +356,12 @@ class Preprocessor: rv.LE = self.LE rv.out = self.out return rv - + def applyFilters(self, aLine): for f in self.filters: aLine = f[1](aLine) return aLine - + def write(self, aLine): """ Internal method for handling output. @@ -143,7 +381,7 @@ class Preprocessor: # with universal line ending support, at least for files. filteredLine = re.sub('\n', self.LE, filteredLine) self.out.write(filteredLine) - + def handleCommandLine(self, args, defaultToStdin = False): """ Parse a commandline into this parser. @@ -168,7 +406,8 @@ class Preprocessor: for f in includes: self.do_include(f, False) self.warnUnused(f) - pass + if options.output: + self.out.close() def getCommandLineParser(self, unescapeDefines = False): escapedValue = re.compile('".*"$') @@ -243,7 +482,7 @@ class Preprocessor: # Instruction handlers # These are named do_'instruction name' and take one argument - + # Variables def do_define(self, args): m = re.match('(?P\w+)(?:\s(?P.*))?', args, re.U) @@ -273,7 +512,7 @@ class Preprocessor: return val = None try: - e = Expression.Expression(args) + e = Expression(args) val = e.evaluate(self.context) except Exception: # XXX do real error reporting @@ -472,10 +711,6 @@ class Preprocessor: def do_error(self, args): raise Preprocessor.Error(self, 'Error: ', str(args)) -def main(): - pp = Preprocessor() - pp.handleCommandLine(None, True) - return def preprocess(includes=[sys.stdin], defines={}, output = sys.stdout, @@ -488,5 +723,8 @@ def preprocess(includes=[sys.stdin], defines={}, for f in includes: pp.do_include(f, False) + +# Keep this module independently executable. if __name__ == "__main__": - main() + pp = Preprocessor() + pp.handleCommandLine(None, True) diff --git a/config/tests/unit-Expression.py b/python/mozbuild/mozbuild/test/test_expression.py similarity index 97% rename from config/tests/unit-Expression.py rename to python/mozbuild/mozbuild/test/test_expression.py index d153211e9342..fb3c45894c81 100644 --- a/config/tests/unit-Expression.py +++ b/python/mozbuild/mozbuild/test/test_expression.py @@ -4,7 +4,7 @@ import sys import os.path import mozunit -from Expression import Expression, Context +from mozbuild.preprocessor import Expression, Context class TestContext(unittest.TestCase): """ diff --git a/config/tests/unit-LineEndings.py b/python/mozbuild/mozbuild/test/test_line_endings.py similarity index 95% rename from config/tests/unit-LineEndings.py rename to python/mozbuild/mozbuild/test/test_line_endings.py index 56914aae9945..565abc8c93ff 100644 --- a/config/tests/unit-LineEndings.py +++ b/python/mozbuild/mozbuild/test/test_line_endings.py @@ -6,7 +6,7 @@ import sys import os.path import mozunit -from Preprocessor import Preprocessor +from mozbuild.preprocessor import Preprocessor class TestLineEndings(unittest.TestCase): """ diff --git a/config/tests/unit-Preprocessor.py b/python/mozbuild/mozbuild/test/test_preprocessor.py similarity index 99% rename from config/tests/unit-Preprocessor.py rename to python/mozbuild/mozbuild/test/test_preprocessor.py index 9ca640b20977..3039b204827e 100644 --- a/config/tests/unit-Preprocessor.py +++ b/python/mozbuild/mozbuild/test/test_preprocessor.py @@ -6,7 +6,7 @@ import sys import os.path from mozunit import main, MockedOpen -from Preprocessor import Preprocessor +from mozbuild.preprocessor import Preprocessor def NamedIO(name, content): with open(name, 'w') as f: diff --git a/python/mozbuild/mozpack/packager/__init__.py b/python/mozbuild/mozpack/packager/__init__.py index 6ad3ccc9ca15..5e83c1a6f9a5 100644 --- a/python/mozbuild/mozpack/packager/__init__.py +++ b/python/mozbuild/mozpack/packager/__init__.py @@ -2,7 +2,7 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -from Preprocessor import Preprocessor +from mozbuild.preprocessor import Preprocessor import re import os from mozpack.errors import errors diff --git a/python/mozbuild/mozpack/test/test_packager.py b/python/mozbuild/mozpack/test/test_packager.py index 3d84fe950a75..3dd10f0723b8 100644 --- a/python/mozbuild/mozpack/test/test_packager.py +++ b/python/mozbuild/mozpack/test/test_packager.py @@ -18,7 +18,7 @@ from mozpack.chrome.manifest import ( ManifestContent, ) from mozunit import MockedOpen -from Preprocessor import Preprocessor +from mozbuild.preprocessor import Preprocessor from mozpack.errors import ( errors, ErrorMessage, diff --git a/services/sync/Makefile.in b/services/sync/Makefile.in index 494c66de08c5..5cad09b580ea 100644 --- a/services/sync/Makefile.in +++ b/services/sync/Makefile.in @@ -10,7 +10,7 @@ weave_id := {340c2bbc-ce74-4362-90b5-7c26312808ef} SYNC_PP := modules/constants.js SYNC_PP_FLAGS := \ -Dweave_version=$(weave_version) \ - -Dweave_id=$(weave_id) + -Dweave_id="$(weave_id)" SYNC_PP_PATH = $(FINAL_TARGET)/modules/services-sync PP_TARGETS += SYNC_PP diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in index ee4fc27fb188..8a0e57f2caf6 100644 --- a/toolkit/library/Makefile.in +++ b/toolkit/library/Makefile.in @@ -127,8 +127,8 @@ OS_LIBS += -lrt EXTRA_DSO_LDOPTS += -Wl,-version-script,symverscript symverscript: symverscript.in - $(PYTHON) $(topsrcdir)/config/Preprocessor.py \ - -DVERSION="$(LIBRARY_NAME)$(MOZILLA_SYMBOLVERSION)" $< > $@ + $(call py_action,preprocessor, \ + -DVERSION="$(LIBRARY_NAME)$(MOZILLA_SYMBOLVERSION)" $< -o $@) EXTRA_DEPS += symverscript endif diff --git a/toolkit/locales/l10n.mk b/toolkit/locales/l10n.mk index 9b38addd05c7..b5bb4c78fc82 100644 --- a/toolkit/locales/l10n.mk +++ b/toolkit/locales/l10n.mk @@ -158,8 +158,8 @@ langpack-%: XPI_NAME=locale-$* langpack-%: libs-% @echo "Making langpack $(LANGPACK_FILE)" $(NSINSTALL) -D $(DIST)/$(PKG_LANGPACK_PATH) - $(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) \ - -I$(TK_DEFINES) -I$(APP_DEFINES) $(srcdir)/generic/install.rdf > $(DIST)/xpi-stage/$(XPI_NAME)/install.rdf + $(call py_action,preprocessor,$(DEFINES) $(ACDEFINES) \ + -I$(TK_DEFINES) -I$(APP_DEFINES) $(srcdir)/generic/install.rdf -o $(DIST)/xpi-stage/$(XPI_NAME)/install.rdf) cd $(DIST)/xpi-stage/locale-$(AB_CD) && \ $(ZIP) -r9D $(LANGPACK_FILE) install.rdf $(PKG_ZIP_DIRS) chrome.manifest diff --git a/toolkit/mozapps/installer/packager.mk b/toolkit/mozapps/installer/packager.mk index 262882e7ef85..16bc3a7de7fc 100644 --- a/toolkit/mozapps/installer/packager.mk +++ b/toolkit/mozapps/installer/packager.mk @@ -178,12 +178,11 @@ RPM_INCIDENTALS=$(topsrcdir)/toolkit/mozapps/installer/linux/rpm RPM_CMD = \ echo Creating RPM && \ - mkdir -p $(RPMBUILD_SOURCEDIR) && \ - $(PYTHON) $(topsrcdir)/config/Preprocessor.py \ + $(PYTHON) -m mozbuild.action.preprocessor \ -DMOZ_APP_NAME=$(MOZ_APP_NAME) \ -DMOZ_APP_DISPLAYNAME="$(MOZ_APP_DISPLAYNAME)" \ - < $(RPM_INCIDENTALS)/mozilla.desktop \ - > $(RPMBUILD_SOURCEDIR)/$(MOZ_APP_NAME).desktop && \ + $(RPM_INCIDENTALS)/mozilla.desktop \ + -o $(RPMBUILD_SOURCEDIR)/$(MOZ_APP_NAME).desktop && \ rm -rf $(_ABS_DIST)/$(TARGET_CPU) && \ $(RPMBUILD) -bb \ $(SPEC_FILE) \ diff --git a/webapprt/Makefile.in b/webapprt/Makefile.in index 388f8d7d4abc..0f5710f92d0e 100644 --- a/webapprt/Makefile.in +++ b/webapprt/Makefile.in @@ -28,7 +28,7 @@ DEFINES += -DGRE_MILESTONE=$(GRE_MILESTONE) \ $(NULL) webapprt.ini: application.ini.in $(DEPTH)/config/buildid $(topsrcdir)/config/milestone.txt - $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $< > $@ + $(call py_action,preprocessor,$(DEFINES) $< -o $@) libs:: webapprt.ini $(INSTALL) webapprt.ini $(FINAL_TARGET) diff --git a/webapprt/win/Makefile.in b/webapprt/win/Makefile.in index d86b5f110b4e..365ea0afd247 100644 --- a/webapprt/win/Makefile.in +++ b/webapprt/win/Makefile.in @@ -68,9 +68,9 @@ endif libs:: $(RM) -r $(CONFIG_DIR) $(MKDIR) $(CONFIG_DIR) - $(PYTHON) $(topsrcdir)/config/Preprocessor.py -Fsubstitution \ + $(call py_action,preprocessor,-Fsubstitution \ $(DEFINES) $(ACDEFINES) \ - $(srcdir)/webapp-uninstaller.nsi.in > $(CONFIG_DIR)/webapp-uninstaller.nsi + $(srcdir)/webapp-uninstaller.nsi.in -o $(CONFIG_DIR)/webapp-uninstaller.nsi) $(PYTHON) \ $(topsrcdir)/toolkit/mozapps/installer/windows/nsis/preprocess-locale.py \ --create-nlf-file $(topsrcdir) $(AB_CD) $(CONFIG_DIR) diff --git a/xulrunner/app/Makefile.in b/xulrunner/app/Makefile.in index 59b37cca96df..62dbe48d4372 100644 --- a/xulrunner/app/Makefile.in +++ b/xulrunner/app/Makefile.in @@ -103,7 +103,7 @@ endif # XXX applications would need to supply this file #export:: brand.dtd.in -# $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $^ > brand.dtd +# $(call py_action,preprocessor,$(DEFINES) $(ACDEFINES) $^ -o brand.dtd) export:: $(NSINSTALL) -D $(DIST)/branding diff --git a/xulrunner/installer/Makefile.in b/xulrunner/installer/Makefile.in index 52ecf057e8e5..27206463ba72 100644 --- a/xulrunner/installer/Makefile.in +++ b/xulrunner/installer/Makefile.in @@ -107,25 +107,24 @@ DEFINES += \ ifeq ($(OS_TARGET),Linux) debian/changelog: $(srcdir)/debian/changelog.in $(LIBXUL_DIST)/bin/platform.ini - mkdir -p debian - $(PYTHON) $(topsrcdir)/config/Preprocessor.py \ - $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $^ > $@ + $(call py_action,preprocessor, \ + $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $^ -o $@) debian/xulrunner.links: $(srcdir)/debian/xulrunner.links.in - $(PYTHON) $(topsrcdir)/config/Preprocessor.py \ - $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $^ > $@ + $(call py_action,preprocessor, \ + $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $^ -o $@) debian/xulrunner.service: $(srcdir)/debian/xulrunner.service.in - $(PYTHON) $(topsrcdir)/config/Preprocessor.py \ - $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $^ > $@ + $(call py_action,preprocessor, \ + $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $^ -o $@) debian/prerm: $(srcdir)/debian/prerm.in - $(PYTHON) $(topsrcdir)/config/Preprocessor.py \ - $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $^ > $@ + $(call py_action,preprocessor, \ + $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $^ -o $@) debian/postinst: $(srcdir)/debian/postinst.in - $(PYTHON) $(topsrcdir)/config/Preprocessor.py \ - $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $^ > $@ + $(call py_action,preprocessor, \ + $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $^ -o $@) package: $(MAKE) package -C $(DEPTH) From d0143abc0debce1c4546e6b7df392f0bc980b62b Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Sat, 9 Nov 2013 10:35:45 +0900 Subject: [PATCH 17/52] Bug 935305 - Track preprocessor output dependencies. r=gps --- config/rules.mk | 31 +++++++++++++++++-- js/src/config/rules.mk | 31 +++++++++++++++++-- python/mozbuild/mozbuild/preprocessor.py | 39 ++++++++++++++++++++---- 3 files changed, 91 insertions(+), 10 deletions(-) diff --git a/config/rules.mk b/config/rules.mk index 95073b567ddb..5415605a1dca 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -1600,12 +1600,39 @@ $(foreach tier,$(PP_TARGETS_TIERS), \ $(eval $(tier):: $(PP_TARGETS_RESULTS_$(tier))) \ ) -$(sort $(foreach tier,$(PP_TARGETS_TIERS),$(PP_TARGETS_RESULTS_$(tier)))): +PP_TARGETS_ALL_RESULTS := $(sort $(foreach tier,$(PP_TARGETS_TIERS),$(PP_TARGETS_RESULTS_$(tier)))) +$(PP_TARGETS_ALL_RESULTS): $(if $(filter-out $(notdir $@),$(notdir $(<:.in=))),$(error Looks like $@ has an unexpected dependency on $< which breaks PP_TARGETS)) $(REPORT_BUILD) $(RM) "$@" - $(call py_action,preprocessor,$(PP_TARGET_FLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) "$<" -o "$@") + $(call py_action,preprocessor,--depend $(MDDEPDIR)/$(@F).pp $(PP_TARGET_FLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) "$<" -o "$@") +# The depfile is based on the filename, and we don't want conflicts. So check +# there's only one occurrence of any given filename in PP_TARGETS_ALL_RESULTS. +PP_TARGETS_ALL_RESULT_NAMES := $(notdir $(PP_TARGETS_ALL_RESULTS)) +$(foreach file,$(sort $(PP_TARGETS_ALL_RESULT_NAMES)), \ + $(if $(filter-out 1,$(words $(filter $(file),$(PP_TARGETS_ALL_RESULT_NAMES)))), \ + $(error Multiple preprocessing rules are creating a $(file) file) \ + ) \ +) + +ifneq (,$(filter $(PP_TARGETS_TIERS) $(PP_TARGETS_ALL_RESULTS),$(MAKECMDGOALS))) +# If the depfile for a preprocessed file doesn't exist, add a dep to force +# re-preprocessing. +$(foreach file,$(PP_TARGETS_ALL_RESULTS), \ + $(if $(wildcard $(MDDEPDIR)/$(notdir $(file)).pp), \ + , \ + $(eval $(file): FORCE) \ + ) \ +) + +MDDEPEND_FILES := $(strip $(wildcard $(addprefix $(MDDEPDIR)/,$(addsuffix .pp,$(notdir $(PP_TARGETS_ALL_RESULTS)))))) + +ifneq (,$(MDDEPEND_FILES)) +$(call include_deps,$(MDDEPEND_FILES)) +endif + +endif # Pull in non-recursive targets if this is a partial tree build. ifndef TOPLEVEL_BUILD diff --git a/js/src/config/rules.mk b/js/src/config/rules.mk index 95073b567ddb..5415605a1dca 100644 --- a/js/src/config/rules.mk +++ b/js/src/config/rules.mk @@ -1600,12 +1600,39 @@ $(foreach tier,$(PP_TARGETS_TIERS), \ $(eval $(tier):: $(PP_TARGETS_RESULTS_$(tier))) \ ) -$(sort $(foreach tier,$(PP_TARGETS_TIERS),$(PP_TARGETS_RESULTS_$(tier)))): +PP_TARGETS_ALL_RESULTS := $(sort $(foreach tier,$(PP_TARGETS_TIERS),$(PP_TARGETS_RESULTS_$(tier)))) +$(PP_TARGETS_ALL_RESULTS): $(if $(filter-out $(notdir $@),$(notdir $(<:.in=))),$(error Looks like $@ has an unexpected dependency on $< which breaks PP_TARGETS)) $(REPORT_BUILD) $(RM) "$@" - $(call py_action,preprocessor,$(PP_TARGET_FLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) "$<" -o "$@") + $(call py_action,preprocessor,--depend $(MDDEPDIR)/$(@F).pp $(PP_TARGET_FLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) "$<" -o "$@") +# The depfile is based on the filename, and we don't want conflicts. So check +# there's only one occurrence of any given filename in PP_TARGETS_ALL_RESULTS. +PP_TARGETS_ALL_RESULT_NAMES := $(notdir $(PP_TARGETS_ALL_RESULTS)) +$(foreach file,$(sort $(PP_TARGETS_ALL_RESULT_NAMES)), \ + $(if $(filter-out 1,$(words $(filter $(file),$(PP_TARGETS_ALL_RESULT_NAMES)))), \ + $(error Multiple preprocessing rules are creating a $(file) file) \ + ) \ +) + +ifneq (,$(filter $(PP_TARGETS_TIERS) $(PP_TARGETS_ALL_RESULTS),$(MAKECMDGOALS))) +# If the depfile for a preprocessed file doesn't exist, add a dep to force +# re-preprocessing. +$(foreach file,$(PP_TARGETS_ALL_RESULTS), \ + $(if $(wildcard $(MDDEPDIR)/$(notdir $(file)).pp), \ + , \ + $(eval $(file): FORCE) \ + ) \ +) + +MDDEPEND_FILES := $(strip $(wildcard $(addprefix $(MDDEPDIR)/,$(addsuffix .pp,$(notdir $(PP_TARGETS_ALL_RESULTS)))))) + +ifneq (,$(MDDEPEND_FILES)) +$(call include_deps,$(MDDEPEND_FILES)) +endif + +endif # Pull in non-recursive targets if this is a partial tree build. ifndef TOPLEVEL_BUILD diff --git a/python/mozbuild/mozbuild/preprocessor.py b/python/mozbuild/mozbuild/preprocessor.py index f1938314d537..4d79cf0d73d3 100644 --- a/python/mozbuild/mozbuild/preprocessor.py +++ b/python/mozbuild/mozbuild/preprocessor.py @@ -313,6 +313,8 @@ class Preprocessor: self.setMarker('#') self.LE = '\n' self.varsubst = re.compile('@(?P\w+)@', re.U) + self.depfile = None + self.includes = set() def warnUnused(self, file): if self.actionLevel == 0: @@ -387,25 +389,46 @@ class Preprocessor: Parse a commandline into this parser. Uses OptionParser internally, no args mean sys.argv[1:]. """ - p = self.getCommandLineParser() - (options, args) = p.parse_args(args=args) - includes = options.I - if options.output: - dir = os.path.dirname(options.output) + def get_output_file(path): + dir = os.path.dirname(path) if dir and not os.path.exists(dir): try: os.makedirs(dir) except OSError as error: if error.errno != errno.EEXIST: raise - self.out = open(options.output, 'wb') + return open(path, 'wb') + + p = self.getCommandLineParser() + options, args = p.parse_args(args=args) + includes = options.I + if options.output: + self.out = get_output_file(options.output) if defaultToStdin and len(args) == 0: args = [sys.stdin] + if options.depend: + raise Preprocessor.Error(self, "--depend doesn't work with stdin", + None) + if options.depend: + if not options.output: + raise Preprocessor.Error(self, "--depend doesn't work with stdout", + None) + try: + from makeutil import Makefile + except: + raise Preprocessor.Error(self, "--depend requires the " + "mozbuild.makeutil module", None) + self.depfile = get_output_file(options.depend) includes.extend(args) if includes: for f in includes: self.do_include(f, False) self.warnUnused(f) + if self.depfile: + mk = Makefile() + mk.create_rule([options.output]).add_dependencies(self.includes) + mk.dump(self.depfile) + self.depfile.close() if options.output: self.out.close() @@ -447,6 +470,8 @@ class Preprocessor: p.add_option('-o', '--output', type="string", default=None, metavar="FILENAME", help='Output to the specified file '+ 'instead of stdout') + p.add_option('--depend', type="string", default=None, metavar="FILENAME", + help='Generate dependencies in the given file') p.add_option('--line-endings', action='callback', callback=handleLE, type="string", metavar="[cr|lr|crlf]", help='Use the specified line endings [Default: OS dependent]') @@ -692,6 +717,8 @@ class Preprocessor: self.context['DIRECTORY'] = '' else: abspath = os.path.abspath(args.name) + if self.depfile: + self.includes.add(abspath) self.context['FILE'] = abspath self.context['DIRECTORY'] = os.path.dirname(abspath) self.context['LINE'] = 0 From b15d15ee6873cac106d4eddc64c6dc1ffc438827 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Sat, 9 Nov 2013 10:37:04 +0900 Subject: [PATCH 18/52] Bug 935870 - Raise an exception when an emitted object is not acknowledged by the build backend. r=gps --- python/mozbuild/mozbuild/backend/recursivemake.py | 6 +++++- python/mozbuild/mozbuild/frontend/data.py | 9 +++++++++ python/mozbuild/mozbuild/frontend/emitter.py | 2 ++ python/mozbuild/mozbuild/test/frontend/test_emitter.py | 5 ++++- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/python/mozbuild/mozbuild/backend/recursivemake.py b/python/mozbuild/mozbuild/backend/recursivemake.py index 1ee71ff8ae6f..95e6f24d55fb 100644 --- a/python/mozbuild/mozbuild/backend/recursivemake.py +++ b/python/mozbuild/mozbuild/backend/recursivemake.py @@ -445,8 +445,12 @@ class RecursiveMakeBackend(CommonBackend): # automated. if isinstance(obj.wrapped, JavaJarData): self._process_java_jar_data(obj.wrapped, backend_file) + else: + return - self._backend_files[obj.srcdir] = backend_file + else: + return + obj.ack() def _fill_root_mk(self): """ diff --git a/python/mozbuild/mozbuild/frontend/data.py b/python/mozbuild/mozbuild/frontend/data.py index d84377b3e0c0..5a57f920b015 100644 --- a/python/mozbuild/mozbuild/frontend/data.py +++ b/python/mozbuild/mozbuild/frontend/data.py @@ -26,11 +26,18 @@ from .sandbox_symbols import compute_final_target class TreeMetadata(object): """Base class for all data being captured.""" + def __init__(self): + self._ack = False + + def ack(self): + self._ack = True + class ReaderSummary(TreeMetadata): """A summary of what the reader did.""" def __init__(self, total_file_count, total_execution_time): + TreeMetadata.__init__(self) self.total_file_count = total_file_count self.total_execution_time = total_execution_time @@ -53,6 +60,8 @@ class SandboxDerived(TreeMetadata): ) def __init__(self, sandbox): + TreeMetadata.__init__(self) + # Capture the files that were evaluated to build this sandbox. self.sandbox_main_path = sandbox.main_path self.sandbox_all_paths = sandbox.all_paths diff --git a/python/mozbuild/mozbuild/frontend/emitter.py b/python/mozbuild/mozbuild/frontend/emitter.py index efcc74165ddd..2b756317af34 100644 --- a/python/mozbuild/mozbuild/frontend/emitter.py +++ b/python/mozbuild/mozbuild/frontend/emitter.py @@ -83,6 +83,8 @@ class TreeMetadataEmitter(LoggingMixin): if isinstance(out, MozbuildSandbox): for o in self.emit_from_sandbox(out): yield o + if not o._ack: + raise Exception('Unhandled object of type %s' % type(o)) # Update the stats. file_count += len(out.all_paths) diff --git a/python/mozbuild/mozbuild/test/frontend/test_emitter.py b/python/mozbuild/mozbuild/test/frontend/test_emitter.py index 8e435ecdb225..79d0556a220b 100644 --- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py +++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py @@ -47,8 +47,11 @@ class TestEmitterBasic(unittest.TestCase): def read_topsrcdir(self, reader): emitter = TreeMetadataEmitter(reader.config) + def ack(obj): + obj.ack() + return obj - objs = list(emitter.emit(reader.read_topsrcdir())) + objs = list(ack(o) for o in emitter.emit(reader.read_topsrcdir())) self.assertGreater(len(objs), 0) self.assertIsInstance(objs[-1], ReaderSummary) From 670d30dca6b07361f10ceadf2d6568527394e28f Mon Sep 17 00:00:00 2001 From: Chris Peterson Date: Thu, 7 Nov 2013 20:13:20 -0800 Subject: [PATCH 19/52] Bug 936336 - Remove unused private member variable MacIOAutoObservation::mFd. r=jonasfj --- xpcom/build/PoisonIOInterposerMac.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/xpcom/build/PoisonIOInterposerMac.cpp b/xpcom/build/PoisonIOInterposerMac.cpp index 0cb030c7c694..094decc0c129 100644 --- a/xpcom/build/PoisonIOInterposerMac.cpp +++ b/xpcom/build/PoisonIOInterposerMac.cpp @@ -56,8 +56,7 @@ class MacIOAutoObservation : public IOInterposeObserver::Observation public: MacIOAutoObservation(IOInterposeObserver::Operation aOp, const char* aReference, int aFd) - : mFd(aFd), - mShouldObserve(sIsEnabled && IOInterposer::IsObservedOperation(aOp) && + : mShouldObserve(sIsEnabled && IOInterposer::IsObservedOperation(aOp) && !IsDebugFile(aFd)) { if (mShouldObserve) { @@ -70,8 +69,7 @@ public: MacIOAutoObservation(IOInterposeObserver::Operation aOp, const char* aReference, int aFd, const void *aBuf, size_t aCount) - : mFd(aFd), - mShouldObserve(sIsEnabled && IOInterposer::IsObservedOperation(aOp) && + : mShouldObserve(sIsEnabled && IOInterposer::IsObservedOperation(aOp) && !IsDebugFile(aFd)) { if (mShouldObserve) { @@ -95,7 +93,6 @@ public: } private: - int mFd; bool mShouldObserve; }; @@ -337,4 +334,4 @@ void ClearPoisonIOInterposer() { sIsEnabled = false; } -} // namespace mozilla \ No newline at end of file +} // namespace mozilla From 66e11b8305ec663992f95f79f3fb87983b5f5b90 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Thu, 7 Nov 2013 12:07:32 -0800 Subject: [PATCH 20/52] Bug 934669 - Add preliminary code to make Object.prototype.watch/unwatch warn about deprecation when called for the first time, but don't actually emit the warnings just yet (more needs doing in this bug before that can happen). r=evilpie --HG-- extra : rebase_source : 11a270e6d8b6d0f03effc14780208a36789e2ff1 --- js/src/builtin/Object.cpp | 35 ++++++++++++++++++++++++++--------- js/src/js.msg | 2 +- js/src/vm/GlobalObject.cpp | 17 +++++++++++++++++ js/src/vm/GlobalObject.h | 23 +++++++++++++---------- 4 files changed, 57 insertions(+), 20 deletions(-) diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index 1256b43227a5..c7123c716b4e 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -552,6 +552,15 @@ obj_watch(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); + RootedObject obj(cx, ToObject(cx, args.thisv())); + if (!obj) + return false; + +#if 0 /* pending addressing Firebug's use of this method */ + if (!GlobalObject::warnOnceAboutWatch(cx, obj)) + return false; +#endif + if (args.length() <= 1) { js_ReportMissingArg(cx, args.calleev(), 1); return false; @@ -565,18 +574,16 @@ obj_watch(JSContext *cx, unsigned argc, Value *vp) if (!ValueToId(cx, args[0], &propid)) return false; - RootedObject obj(cx, ToObject(cx, args.thisv())); - if (!obj) - return false; - RootedValue tmp(cx); unsigned attrs; if (!CheckAccess(cx, obj, propid, JSACC_WATCH, &tmp, &attrs)) return false; - args.rval().setUndefined(); + if (!JS_SetWatchPoint(cx, obj, propid, obj_watch_handler, callable)) + return false; - return JS_SetWatchPoint(cx, obj, propid, obj_watch_handler, callable); + args.rval().setUndefined(); + return true; } static bool @@ -587,15 +594,25 @@ obj_unwatch(JSContext *cx, unsigned argc, Value *vp) RootedObject obj(cx, ToObject(cx, args.thisv())); if (!obj) return false; - args.rval().setUndefined(); + +#if 0 /* pending addressing Firebug's use of this method */ + if (!GlobalObject::warnOnceAboutWatch(cx, obj)) + return false; +#endif + RootedId id(cx); - if (argc != 0) { + if (args.length() != 0) { if (!ValueToId(cx, args[0], &id)) return false; } else { id = JSID_VOID; } - return JS_ClearWatchPoint(cx, obj, id, nullptr, nullptr); + + if (!JS_ClearWatchPoint(cx, obj, id, nullptr, nullptr)) + return false; + + args.rval().setUndefined(); + return true; } #endif /* JS_HAS_OBJ_WATCHPOINT */ diff --git a/js/src/js.msg b/js/src/js.msg index 8bd4f8bd0556..296811dcc926 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -244,7 +244,7 @@ MSG_DEF(JSMSG_UNUSED190, 190, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_UNUSED191, 191, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_UNUSED192, 192, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 193, 0, JSEXN_SYNTAXERR, "invalid for each loop") -MSG_DEF(JSMSG_UNUSED194, 194, 0, JSEXN_NONE, "") +MSG_DEF(JSMSG_OBJECT_WATCH_DEPRECATED,194, 0, JSEXN_TYPEERR, "Object.prototype.watch and unwatch are very slow, non-standard, and deprecated; use a getter/setter instead") MSG_DEF(JSMSG_UNUSED195, 195, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_UNUSED196, 196, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_INTERNAL_INTL_ERROR, 197, 0, JSEXN_ERR, "internal error while computing Intl data") diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index 7e968403356a..26d608832250 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -504,6 +504,23 @@ GlobalObject::isRuntimeCodeGenEnabled(JSContext *cx, Handle globa return !v.isFalse(); } +/* static */ bool +GlobalObject::warnOnceAboutWatch(JSContext *cx, HandleObject obj) +{ + Rooted global(cx, &obj->global()); + HeapSlot &v = global->getSlotRef(WARNED_WATCH_DEPRECATED); + if (v.isUndefined()) { + // Warn only once per global object. + if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, js_GetErrorMessage, NULL, + JSMSG_OBJECT_WATCH_DEPRECATED)) + { + return false; + } + v.init(global, HeapSlot::Slot, WARNED_WATCH_DEPRECATED, BooleanValue(true)); + } + return true; +} + JSFunction * GlobalObject::createConstructor(JSContext *cx, Native ctor, JSAtom *nameArg, unsigned length, gc::AllocKind kind) diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 401bf8b2c4e3..cbe9ee03d224 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -105,8 +105,8 @@ class GlobalObject : public JSObject static const unsigned NUMBER_FORMAT_PROTO = COLLATOR_PROTO + 1; static const unsigned DATE_TIME_FORMAT_PROTO = NUMBER_FORMAT_PROTO + 1; static const unsigned REGEXP_STATICS = DATE_TIME_FORMAT_PROTO + 1; - static const unsigned FUNCTION_NS = REGEXP_STATICS + 1; - static const unsigned RUNTIME_CODEGEN_ENABLED = FUNCTION_NS + 1; + static const unsigned WARNED_WATCH_DEPRECATED = REGEXP_STATICS + 1; + static const unsigned RUNTIME_CODEGEN_ENABLED = WARNED_WATCH_DEPRECATED + 1; static const unsigned DEBUGGERS = RUNTIME_CODEGEN_ENABLED + 1; static const unsigned INTRINSICS = DEBUGGERS + 1; static const unsigned ARRAY_TYPE = INTRINSICS + 1; @@ -114,14 +114,13 @@ class GlobalObject : public JSObject /* Total reserved-slot count for global objects. */ static const unsigned RESERVED_SLOTS = ARRAY_TYPE + 1; - void staticAsserts() { - /* - * The slot count must be in the public API for JSCLASS_GLOBAL_FLAGS, - * and we aren't going to expose GlobalObject, so just assert that the - * two values are synchronized. - */ - JS_STATIC_ASSERT(JSCLASS_GLOBAL_SLOT_COUNT == RESERVED_SLOTS); - } + /* + * The slot count must be in the public API for JSCLASS_GLOBAL_FLAGS, and + * we won't expose GlobalObject, so just assert that the two values are + * synchronized. + */ + static_assert(JSCLASS_GLOBAL_SLOT_COUNT == RESERVED_SLOTS, + "global object slot counts are inconsistent"); friend JSObject * ::js_InitObjectClass(JSContext *cx, js::HandleObject); @@ -575,6 +574,10 @@ class GlobalObject : public JSObject static bool isRuntimeCodeGenEnabled(JSContext *cx, Handle global); + // Warn about use of the deprecated watch/unwatch functions in the global + // in which |obj| was created, if no prior warning was given. + static bool warnOnceAboutWatch(JSContext *cx, HandleObject obj); + const Value &getOriginalEval() const { JS_ASSERT(getSlot(EVAL).isObject()); return getSlot(EVAL); From 3e47e0b0694bf624bdabdbfa84fbf08143cf25eb Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Tue, 29 Oct 2013 16:39:09 -0700 Subject: [PATCH 21/52] Bug 903332 - Make watch/unwatch into proxy hooks and such, and make watching/unwatching work on DOM proxies and windows (or at least work as much as it ever did, which is to say kinda-sorta-ish). r=bhackett, r=efaust --HG-- extra : rebase_source : 58dc71e7e58208a2cfa12b265adca7b189e5e5bd --- content/html/document/test/Makefile.in | 1 + .../document/test/test_document.watch.html | 129 ++++++++++++++++++ dom/base/nsGlobalWindow.cpp | 19 +++ dom/bindings/DOMJSProxyHandler.cpp | 13 ++ dom/bindings/DOMJSProxyHandler.h | 5 + js/public/Class.h | 11 +- js/src/builtin/Object.cpp | 10 +- js/src/builtin/Object.h | 7 +- js/src/builtin/TypedObject.cpp | 2 + js/src/jsfriendapi.h | 27 ++++ js/src/jsobj.cpp | 66 +++++++++ js/src/jsobj.h | 10 ++ js/src/jsobjinlines.h | 15 ++ js/src/jsproxy.cpp | 41 ++++++ js/src/jsproxy.h | 10 ++ js/src/vm/ScopeObject.cpp | 1 + js/src/vm/TypedArrayObject.cpp | 2 + js/xpconnect/src/XPCWrappedNativeJSOps.cpp | 1 + js/xpconnect/src/xpcprivate.h | 2 + testing/mochitest/b2g.json | 1 + 20 files changed, 365 insertions(+), 8 deletions(-) create mode 100644 content/html/document/test/test_document.watch.html diff --git a/content/html/document/test/Makefile.in b/content/html/document/test/Makefile.in index 73a216d04741..0cbab9038a4a 100644 --- a/content/html/document/test/Makefile.in +++ b/content/html/document/test/Makefile.in @@ -35,6 +35,7 @@ MOCHITEST_FILES = test_bug1682.html \ test_viewport.html \ test_documentAll.html \ test_document-element-inserted.html \ + test_document.watch.html \ $(filter disabled-temporarily--bug-559932, test_bug445004.html) \ bug445004-inner.js \ bug445004-outer-rel.html \ diff --git a/content/html/document/test/test_document.watch.html b/content/html/document/test/test_document.watch.html new file mode 100644 index 000000000000..54509823bef0 --- /dev/null +++ b/content/html/document/test/test_document.watch.html @@ -0,0 +1,129 @@ + + + + + + Test for Bug 903332 + + + + + +Mozilla Bug 903332 +

+ +
+
+ + diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index c551b8335e23..ccbe43062259 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -604,6 +604,11 @@ public: virtual bool enumerate(JSContext *cx, JS::Handle proxy, JS::AutoIdVector &props) MOZ_OVERRIDE; + virtual bool watch(JSContext *cx, JS::Handle proxy, + JS::Handle id, JS::Handle callable) MOZ_OVERRIDE; + virtual bool unwatch(JSContext *cx, JS::Handle proxy, + JS::Handle id) MOZ_OVERRIDE; + // Derived traps virtual bool has(JSContext *cx, JS::Handle proxy, JS::Handle id, bool *bp) MOZ_OVERRIDE; @@ -953,6 +958,20 @@ nsOuterWindowProxy::AppendIndexedPropertyNames(JSContext *cx, JSObject *proxy, return true; } +bool +nsOuterWindowProxy::watch(JSContext *cx, JS::Handle proxy, + JS::Handle id, JS::Handle callable) +{ + return js::WatchGuts(cx, proxy, id, callable); +} + +bool +nsOuterWindowProxy::unwatch(JSContext *cx, JS::Handle proxy, + JS::Handle id) +{ + return js::UnwatchGuts(cx, proxy, id); +} + nsOuterWindowProxy nsOuterWindowProxy::singleton; diff --git a/dom/bindings/DOMJSProxyHandler.cpp b/dom/bindings/DOMJSProxyHandler.cpp index 3bb3185d181a..495d11abee3c 100644 --- a/dom/bindings/DOMJSProxyHandler.cpp +++ b/dom/bindings/DOMJSProxyHandler.cpp @@ -235,6 +235,19 @@ BaseDOMProxyHandler::enumerate(JSContext* cx, JS::Handle proxy, (!proto || js::GetPropertyNames(cx, proto, 0, &props)); } +bool +BaseDOMProxyHandler::watch(JSContext* cx, JS::Handle proxy, JS::Handle id, + JS::Handle callable) +{ + return js::WatchGuts(cx, proxy, id, callable); +} + +bool +BaseDOMProxyHandler::unwatch(JSContext* cx, JS::Handle proxy, JS::Handle id) +{ + return js::UnwatchGuts(cx, proxy, id); +} + bool DOMProxyHandler::has(JSContext* cx, JS::Handle proxy, JS::Handle id, bool* bp) { diff --git a/dom/bindings/DOMJSProxyHandler.h b/dom/bindings/DOMJSProxyHandler.h index 9b27d082d0ab..891f4d87533a 100644 --- a/dom/bindings/DOMJSProxyHandler.h +++ b/dom/bindings/DOMJSProxyHandler.h @@ -58,6 +58,11 @@ public: JS::Handle id, JS::MutableHandle desc, unsigned flags) MOZ_OVERRIDE; + + bool watch(JSContext* cx, JS::Handle proxy, JS::Handle id, + JS::Handle callable) MOZ_OVERRIDE; + bool unwatch(JSContext* cx, JS::Handle proxy, + JS::Handle id) MOZ_OVERRIDE; }; class DOMProxyHandler : public BaseDOMProxyHandler diff --git a/js/public/Class.h b/js/public/Class.h index 3c0851707371..c3f97e83b9c2 100644 --- a/js/public/Class.h +++ b/js/public/Class.h @@ -377,6 +377,11 @@ typedef bool typedef bool (* DeleteSpecialOp)(JSContext *cx, JS::HandleObject obj, HandleSpecialId sid, bool *succeeded); +typedef bool +(* WatchOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable); + +typedef bool +(* UnwatchOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id); typedef JSObject * (* ObjectOp)(JSContext *cx, JS::HandleObject obj); @@ -465,6 +470,8 @@ struct ObjectOps DeletePropertyOp deleteProperty; DeleteElementOp deleteElement; DeleteSpecialOp deleteSpecial; + WatchOp watch; + UnwatchOp unwatch; JSNewEnumerateOp enumerate; ObjectOp thisObject; @@ -473,7 +480,7 @@ struct ObjectOps #define JS_NULL_OBJECT_OPS \ {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr, \ nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr, \ - nullptr,nullptr,nullptr,nullptr,nullptr,nullptr} + nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr} } // namespace js @@ -502,7 +509,7 @@ struct JSClass { JSNative construct; JSTraceOp trace; - void *reserved[40]; + void *reserved[42]; }; #define JSCLASS_HAS_PRIVATE (1<<0) // objects have private slot diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index c7123c716b4e..70dd5d2161b0 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -525,9 +525,9 @@ obj_getPrototypeOf(JSContext *cx, unsigned argc, Value *vp) #if JS_HAS_OBJ_WATCHPOINT -static bool -obj_watch_handler(JSContext *cx, JSObject *obj_, jsid id_, jsval old, - jsval *nvp, void *closure) +bool +js::WatchHandler(JSContext *cx, JSObject *obj_, jsid id_, JS::Value old, + JS::Value *nvp, void *closure) { RootedObject obj(cx, obj_); RootedId id(cx, id_); @@ -579,7 +579,7 @@ obj_watch(JSContext *cx, unsigned argc, Value *vp) if (!CheckAccess(cx, obj, propid, JSACC_WATCH, &tmp, &attrs)) return false; - if (!JS_SetWatchPoint(cx, obj, propid, obj_watch_handler, callable)) + if (!JSObject::watch(cx, obj, propid, callable)) return false; args.rval().setUndefined(); @@ -608,7 +608,7 @@ obj_unwatch(JSContext *cx, unsigned argc, Value *vp) id = JSID_VOID; } - if (!JS_ClearWatchPoint(cx, obj, id, nullptr, nullptr)) + if (!JSObject::unwatch(cx, obj, id)) return false; args.rval().setUndefined(); diff --git a/js/src/builtin/Object.h b/js/src/builtin/Object.h index 5e528f44aaac..39950d1b1b4f 100644 --- a/js/src/builtin/Object.h +++ b/js/src/builtin/Object.h @@ -8,7 +8,8 @@ #define builtin_Object_h #include "jsapi.h" -#include "js/Value.h" + +namespace JS { class Value; } namespace js { @@ -25,6 +26,10 @@ JSString * ObjectToSource(JSContext *cx, JS::HandleObject obj); #endif // JS_HAS_TOSOURCE +extern bool +WatchHandler(JSContext *cx, JSObject *obj, jsid id, JS::Value old, + JS::Value *nvp, void *closure); + } /* namespace js */ #endif /* builtin_Object_h */ diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index 583de578c5fb..064c97fc6c00 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -2169,6 +2169,7 @@ const Class TypedObject::class_ = { TypedDatum::obj_deleteProperty, TypedDatum::obj_deleteElement, TypedDatum::obj_deleteSpecial, + nullptr, nullptr, // watch/unwatch TypedDatum::obj_enumerate, nullptr, /* thisObject */ } @@ -2259,6 +2260,7 @@ const Class TypedHandle::class_ = { TypedDatum::obj_deleteProperty, TypedDatum::obj_deleteElement, TypedDatum::obj_deleteSpecial, + nullptr, nullptr, // watch/unwatch TypedDatum::obj_enumerate, nullptr, /* thisObject */ } diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index d0c13dfd9410..2dda4f373b0d 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -1298,6 +1298,33 @@ JS_GetDataViewByteLength(JSObject *obj); JS_FRIEND_API(void *) JS_GetDataViewData(JSObject *obj); +namespace js { + +/* + * Add a watchpoint -- in the Object.prototype.watch sense -- to |obj| for the + * property |id|, using the callable object |callable| as the function to be + * called for notifications. + * + * This is an internal function exposed -- temporarily -- only so that DOM + * proxies can be watchable. Don't use it! We'll soon kill off the + * Object.prototype.{,un}watch functions, at which point this will go too. + */ +extern JS_FRIEND_API(bool) +WatchGuts(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable); + +/* + * Remove a watchpoint -- in the Object.prototype.watch sense -- from |obj| for + * the property |id|. + * + * This is an internal function exposed -- temporarily -- only so that DOM + * proxies can be watchable. Don't use it! We'll soon kill off the + * Object.prototype.{,un}watch functions, at which point this will go too. + */ +extern JS_FRIEND_API(bool) +UnwatchGuts(JSContext *cx, JS::HandleObject obj, JS::HandleId id); + +} // namespace js + /* * A class, expected to be passed by value, which represents the CallArgs for a * JSJitGetterOp. diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 7e05a78fdf21..53aa651fafb2 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -21,6 +21,7 @@ #include "jsarray.h" #include "jsatom.h" #include "jscntxt.h" +#include "jsfriendapi.h" #include "jsfun.h" #include "jsgc.h" #include "jsiter.h" @@ -35,6 +36,7 @@ #include "jswatchpoint.h" #include "jswrapper.h" +#include "builtin/Object.h" #include "frontend/BytecodeCompiler.h" #include "gc/Marking.h" #include "jit/AsmJSModule.h" @@ -4984,6 +4986,70 @@ baseops::DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, boo return baseops::DeleteGeneric(cx, obj, id, succeeded); } +bool +js::WatchGuts(JSContext *cx, JS::HandleObject origObj, JS::HandleId id, JS::HandleObject callable) +{ + RootedObject obj(cx, GetInnerObject(cx, origObj)); + if (origObj != obj) { + // If by unwrapping and innerizing, we changed the object, check again + // to make sure that we're allowed to set a watch point. + RootedValue v(cx); + unsigned attrs; + if (!CheckAccess(cx, obj, id, JSACC_WATCH, &v, &attrs)) + return false; + } + + if (obj->isNative()) { + // Use sparse indexes for watched objects, as dense elements can be + // written to without checking the watchpoint map. + if (!JSObject::sparsifyDenseElements(cx, obj)) + return false; + + types::MarkTypePropertyConfigured(cx, obj, id); + } + + WatchpointMap *wpmap = cx->compartment()->watchpointMap; + if (!wpmap) { + wpmap = cx->runtime()->new_(); + if (!wpmap || !wpmap->init()) { + js_ReportOutOfMemory(cx); + return false; + } + cx->compartment()->watchpointMap = wpmap; + } + + return wpmap->watch(cx, obj, id, js::WatchHandler, callable); +} + +bool +baseops::Watch(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable) +{ + if (!obj->isNative()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_WATCH, + obj->getClass()->name); + return false; + } + + return WatchGuts(cx, obj, id, callable); +} + +bool +js::UnwatchGuts(JSContext *cx, JS::HandleObject origObj, JS::HandleId id) +{ + // Looking in the map for an unsupported object will never hit, so we don't + // need to check for nativeness or watchable-ness here. + RootedObject obj(cx, GetInnerObject(cx, origObj)); + if (WatchpointMap *wpmap = cx->compartment()->watchpointMap) + wpmap->unwatch(obj, id, nullptr, nullptr); + return true; +} + +bool +baseops::Unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id) +{ + return UnwatchGuts(cx, obj, id); +} + bool js::HasDataProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) { diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 1d73720e26bc..8909ec0bae45 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -155,6 +155,12 @@ DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, bool *succee extern bool DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded); +extern bool +Watch(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable); + +extern bool +Unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id); + } /* namespace js::baseops */ extern const Class IntlClass; @@ -1090,6 +1096,10 @@ class JSObject : public js::ObjectImpl static bool deleteByValue(JSContext *cx, js::HandleObject obj, const js::Value &property, bool *succeeded); + static inline bool watch(JSContext *cx, JS::HandleObject obj, JS::HandleId id, + JS::HandleObject callable); + static inline bool unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id); + static bool enumerate(JSContext *cx, JS::HandleObject obj, JSIterateOp iterop, JS::MutableHandleValue statep, JS::MutableHandleId idp) { diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index edc32e4c7552..6d148542f496 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -69,6 +69,21 @@ JSObject::deleteSpecial(JSContext *cx, js::HandleObject obj, js::HandleSpecialId return (op ? op : js::baseops::DeleteSpecial)(cx, obj, sid, succeeded); } +/* static */ inline bool +JSObject::watch(JSContext *cx, JS::HandleObject obj, JS::HandleId id, + JS::HandleObject callable) +{ + js::WatchOp op = obj->getOps()->watch; + return (op ? op : js::baseops::Watch)(cx, obj, id, callable); +} + +/* static */ inline bool +JSObject::unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id) +{ + js::UnwatchOp op = obj->getOps()->unwatch; + return (op ? op : js::baseops::Unwatch)(cx, obj, id); +} + inline void JSObject::finalize(js::FreeOp *fop) { diff --git a/js/src/jsproxy.cpp b/js/src/jsproxy.cpp index 871510bbc40b..7b1ba62377a6 100644 --- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -371,6 +371,19 @@ BaseProxyHandler::getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandl return true; } +bool +BaseProxyHandler::watch(JSContext *cx, HandleObject proxy, HandleId id, HandleObject callable) +{ + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_WATCH, + proxy->getClass()->name); + return false; +} + +bool +BaseProxyHandler::unwatch(JSContext *cx, HandleObject proxy, HandleId id) +{ + return true; +} bool DirectProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, @@ -2747,6 +2760,20 @@ Proxy::getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject pro JSObject * const Proxy::LazyProto = reinterpret_cast(0x1); +/* static */ bool +Proxy::watch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleObject callable) +{ + JS_CHECK_RECURSION(cx, return false); + return proxy->as().handler()->watch(cx, proxy, id, callable); +} + +/* static */ bool +Proxy::unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id) +{ + JS_CHECK_RECURSION(cx, return false); + return proxy->as().handler()->unwatch(cx, proxy, id); +} + static JSObject * proxy_innerObject(JSContext *cx, HandleObject obj) { @@ -3046,6 +3073,18 @@ proxy_Construct(JSContext *cx, unsigned argc, Value *vp) return Proxy::construct(cx, proxy, args); } +static bool +proxy_Watch(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable) +{ + return Proxy::watch(cx, obj, id, callable); +} + +static bool +proxy_Unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id) +{ + return Proxy::unwatch(cx, obj, id); +} + #define PROXY_CLASS_EXT \ { \ nullptr, /* outerObject */ \ @@ -3098,6 +3137,7 @@ proxy_Construct(JSContext *cx, unsigned argc, Value *vp) proxy_DeleteProperty, \ proxy_DeleteElement, \ proxy_DeleteSpecial, \ + proxy_Watch, proxy_Unwatch, \ nullptr, /* enumerate */ \ nullptr, /* thisObject */ \ } \ @@ -3155,6 +3195,7 @@ const Class js::OuterWindowProxyObject::class_ = { proxy_DeleteProperty, proxy_DeleteElement, proxy_DeleteSpecial, + proxy_Watch, proxy_Unwatch, nullptr, /* enumerate */ nullptr, /* thisObject */ } diff --git a/js/src/jsproxy.h b/js/src/jsproxy.h index aab5136f6328..0f59cba2549e 100644 --- a/js/src/jsproxy.h +++ b/js/src/jsproxy.h @@ -166,6 +166,12 @@ class JS_FRIEND_API(BaseProxyHandler) uint32_t index, MutableHandleValue vp, bool *present); virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop); + // These two hooks must be overridden, or not overridden, in tandem -- no + // overriding just one! + virtual bool watch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, + JS::HandleObject callable); + virtual bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id); + /* See comment for weakmapKeyDelegateOp in js/Class.h. */ virtual JSObject *weakmapKeyDelegate(JSObject *proxy); }; @@ -275,6 +281,10 @@ class Proxy static bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp); static bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop); + static bool watch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, + JS::HandleObject callable); + static bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id); + /* IC entry path for handling __noSuchMethod__ on access. */ static bool callProp(JSContext *cx, HandleObject proxy, HandleObject reveiver, HandleId id, MutableHandleValue vp); diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 82b23cb7545f..fd9df13c3833 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -536,6 +536,7 @@ const Class WithObject::class_ = { with_DeleteProperty, with_DeleteElement, with_DeleteSpecial, + nullptr, nullptr, /* watch/unwatch */ with_Enumerate, with_ThisObject, } diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index 439a7a29c6ea..8f90340191a2 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -3470,6 +3470,7 @@ const Class ArrayBufferObject::class_ = { ArrayBufferObject::obj_deleteProperty, ArrayBufferObject::obj_deleteElement, ArrayBufferObject::obj_deleteSpecial, + nullptr, nullptr, /* watch/unwatch */ ArrayBufferObject::obj_enumerate, nullptr, /* thisObject */ } @@ -3632,6 +3633,7 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double) _typedArray##Object::obj_deleteProperty, \ _typedArray##Object::obj_deleteElement, \ _typedArray##Object::obj_deleteSpecial, \ + nullptr, nullptr, /* watch/unwatch */ \ _typedArray##Object::obj_enumerate, \ nullptr, /* thisObject */ \ } \ diff --git a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp index 53b6f7f72e95..a3a69cf20f21 100644 --- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp +++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp @@ -739,6 +739,7 @@ const XPCWrappedNativeJSClass XPC_WN_NoHelper_JSClass = { nullptr, // deleteProperty nullptr, // deleteElement nullptr, // deleteSpecial + nullptr, nullptr, // watch/unwatch XPC_WN_JSOp_Enumerate, XPC_WN_JSOp_ThisObject, } diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 1e6fe32a6789..35f7722d0672 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -1172,6 +1172,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS::HandleObject obj); nullptr, /* deleteProperty */ \ nullptr, /* deleteElement */ \ nullptr, /* deleteSpecial */ \ + nullptr, nullptr, /* watch/unwatch */ \ XPC_WN_JSOp_Enumerate, \ XPC_WN_JSOp_ThisObject, \ } @@ -1200,6 +1201,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS::HandleObject obj); nullptr, /* deleteProperty */ \ nullptr, /* deleteElement */ \ nullptr, /* deleteSpecial */ \ + nullptr, nullptr, /* watch/unwatch */ \ XPC_WN_JSOp_Enumerate, \ XPC_WN_JSOp_ThisObject, \ } diff --git a/testing/mochitest/b2g.json b/testing/mochitest/b2g.json index 970c5617e48a..ac311ca2f9f7 100644 --- a/testing/mochitest/b2g.json +++ b/testing/mochitest/b2g.json @@ -258,6 +258,7 @@ "content/base/test/test_bug424359-2.html":"", "content/base/test/test_mixed_content_blocker_bug803225.html":"", "content/html/document/test/test_non-ascii-cookie.html":"", + "content/html/document/test/test_document.watch.html":"expects document.cookie setting to work", "docshell/test/navigation/test_bug13871.html":"", "docshell/test/navigation/test_bug270414.html":"", From 2bb5fe2c42330985a44f363ef33af6657a414ffa Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Fri, 8 Nov 2013 21:46:44 -0800 Subject: [PATCH 22/52] Bug 903332 - Update the two other b2g*.json files to skip the new test. r=orange --- testing/mochitest/b2g-debug.json | 1 + testing/mochitest/b2g-desktop.json | 1 + 2 files changed, 2 insertions(+) diff --git a/testing/mochitest/b2g-debug.json b/testing/mochitest/b2g-debug.json index 2a848013966d..5f033776abe3 100644 --- a/testing/mochitest/b2g-debug.json +++ b/testing/mochitest/b2g-debug.json @@ -254,6 +254,7 @@ "content/base/test/test_bug424359-2.html":"", "content/base/test/test_mixed_content_blocker_bug803225.html":"", "content/html/document/test/test_non-ascii-cookie.html":"", + "content/html/document/test/test_document.watch.html":"expects document.cookie setting to work", "docshell/test/navigation/test_bug13871.html":"", "docshell/test/navigation/test_bug270414.html":"", diff --git a/testing/mochitest/b2g-desktop.json b/testing/mochitest/b2g-desktop.json index f9a3bca24c6d..e35b43faa6de 100644 --- a/testing/mochitest/b2g-desktop.json +++ b/testing/mochitest/b2g-desktop.json @@ -253,6 +253,7 @@ "content/base/test/test_bug426308.html":"", "content/base/test/test_mixed_content_blocker_bug803225.html":"", "content/html/document/test/test_non-ascii-cookie.html":"", + "content/html/document/test/test_document.watch.html":"expects document.cookie setting to work", "docshell/test/navigation/test_bug13871.html":"", "docshell/test/navigation/test_bug270414.html":"", From 867a2bd662bafc8872eb0cefbfeeb4a0848a2eb9 Mon Sep 17 00:00:00 2001 From: Martin Husemann Date: Sat, 9 Nov 2013 08:36:19 +0100 Subject: [PATCH 23/52] Bug 935962: [OS.File] create a special type for stat.st_size and deal with NetBSD libc symbol names. r=yoric --- .../osfile/modules/osfile_unix_back.jsm | 60 +++++++++++++++++-- .../osfile/modules/osfile_unix_front.jsm | 2 +- 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/toolkit/components/osfile/modules/osfile_unix_back.jsm b/toolkit/components/osfile/modules/osfile_unix_back.jsm index 5acd4a9b2aa4..a3aedd3b63b2 100644 --- a/toolkit/components/osfile/modules/osfile_unix_back.jsm +++ b/toolkit/components/osfile/modules/osfile_unix_back.jsm @@ -92,6 +92,15 @@ Type.gid_t = Type.intn_t(Const.OSFILE_SIZEOF_GID_T).withName("gid_t"); + /** + * A file size (st_size in struct stat) + */ + if (OS.Constants.Sys.Name == "NetBSD") { + Type.stat_size_t = Type.off_t.withName("stat_size_t"); + } else { + Type.stat_size_t = Type.size_t.withName("stat_size_t"); + } + /** * Type |time_t| */ @@ -165,7 +174,7 @@ } stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_SIZE, - "st_size", Type.size_t.implementation); + "st_size", Type.stat_size_t.implementation); Type.stat = stat.getType(); } @@ -398,9 +407,15 @@ /*oflags*/Type.int, /*mode*/ Type.int); - declareLazyFFI(SysFile, "opendir", libc, "opendir", ctypes.default_abi, + if (OS.Constants.Sys.Name == "NetBSD") { + declareLazyFFI(SysFile, "opendir", libc, "__opendir30", ctypes.default_abi, + /*return*/ Type.null_or_DIR_ptr, + /*path*/ Type.path); + } else { + declareLazyFFI(SysFile, "opendir", libc, "opendir", ctypes.default_abi, /*return*/ Type.null_or_DIR_ptr, /*path*/ Type.path); + } declareLazyFFI(SysFile, "pread", libc, "pread", ctypes.default_abi, /*return*/ Type.negativeone_or_ssize_t, @@ -437,6 +452,10 @@ declareLazyFFI(SysFile, "readdir", libc, "readdir$INODE64", ctypes.default_abi, /*return*/Type.null_or_dirent_ptr, /*dir*/ Type.DIR.in_ptr); // For MacOS X + } else if (OS.Constants.Sys.Name == "NetBSD") { + declareLazyFFI(SysFile, "readdir", libc, "__readdir30", ctypes.default_abi, + /*return*/Type.null_or_dirent_ptr, + /*dir*/ Type.DIR.in_ptr); // Other Unices } else { declareLazyFFI(SysFile, "readdir", libc, "readdir", ctypes.default_abi, /*return*/Type.null_or_dirent_ptr, @@ -547,6 +566,23 @@ SysFile.fstat = function fstat(fd, buf) { return Stat.fxstat(ver, fd, buf); }; + } else if (OS.Constants.Sys.Name == "NetBSD") { + // NetBSD 5.0 and newer + declareLazyFFI(SysFile, "stat", libc, "__stat50", ctypes.default_abi, + /*return*/ Type.negativeone_or_nothing, + /*path*/ Type.path, + /*buf*/ Type.stat.out_ptr + ); + declareLazyFFI(SysFile, "lstat", libc, "__lstat50", ctypes.default_abi, + /*return*/ Type.negativeone_or_nothing, + /*path*/ Type.path, + /*buf*/ Type.stat.out_ptr + ); + declareLazyFFI(SysFile, "fstat", libc, "__fstat50", ctypes.default_abi, + /*return*/ Type.negativeone_or_nothing, + /*fd*/ Type.fd, + /*buf*/ Type.stat.out_ptr + ); } else { // Mac OS X 32-bits, other Unix declareLazyFFI(SysFile, "stat", libc, "stat", ctypes.default_abi, @@ -589,16 +625,32 @@ return result; }; - declareLazyFFI(SysFile, "utimes", libc, "utimes", ctypes.default_abi, + if (OS.Constants.Sys.Name == "NetBSD") { + declareLazyFFI(SysFile, "utimes", libc, "__utimes50", ctypes.default_abi, /*return*/ Type.negativeone_or_nothing, /*path*/ Type.path, /*timeval[2]*/ Type.timevals.out_ptr ); - declareLazyFFI(SysFile, "futimes", libc, "futimes", ctypes.default_abi, + } else { + declareLazyFFI(SysFile, "utimes", libc, "utimes", ctypes.default_abi, + /*return*/ Type.negativeone_or_nothing, + /*path*/ Type.path, + /*timeval[2]*/ Type.timevals.out_ptr + ); + } + if (OS.Constants.Sys.Name == "NetBSD") { + declareLazyFFI(SysFile, "futimes", libc, "__futimes50", ctypes.default_abi, /*return*/ Type.negativeone_or_nothing, /*fd*/ Type.fd, /*timeval[2]*/ Type.timevals.out_ptr ); + } else { + declareLazyFFI(SysFile, "futimes", libc, "futimes", ctypes.default_abi, + /*return*/ Type.negativeone_or_nothing, + /*fd*/ Type.fd, + /*timeval[2]*/ Type.timevals.out_ptr + ); + } }; exports.OS.Unix = { diff --git a/toolkit/components/osfile/modules/osfile_unix_front.jsm b/toolkit/components/osfile/modules/osfile_unix_front.jsm index acec273169ad..7bb87903909a 100644 --- a/toolkit/components/osfile/modules/osfile_unix_front.jsm +++ b/toolkit/components/osfile/modules/osfile_unix_front.jsm @@ -789,7 +789,7 @@ File.Info = function Info(stat) { let isDir = (stat.st_mode & Const.S_IFMT) == Const.S_IFDIR; let isSymLink = (stat.st_mode & Const.S_IFMT) == Const.S_IFLNK; - let size = Type.size_t.importFromC(stat.st_size); + let size = Type.stat_size_t.importFromC(stat.st_size); let lastAccessDate = new Date(stat.st_atime * 1000); let lastModificationDate = new Date(stat.st_mtime * 1000); From 2f2903b54162a72f311244896589edda4963d514 Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Sat, 9 Nov 2013 10:06:10 +0100 Subject: [PATCH 24/52] Backed out changeset 6da206d64b49 (bug 923625) for failing mochitest 3 on b2g ics --- dom/datastore/DataStoreService.js | 32 ++++++++-------------- dom/datastore/DataStoreServiceInternal.jsm | 11 ++------ 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/dom/datastore/DataStoreService.js b/dom/datastore/DataStoreService.js index 68faed1154a7..0fde3e3ebf86 100644 --- a/dom/datastore/DataStoreService.js +++ b/dom/datastore/DataStoreService.js @@ -236,11 +236,8 @@ DataStoreService.prototype = { // This method can be called in the child so we need to send a request // to the parent and create DataStore object here. new DataStoreServiceChild(aWindow, aName, function(aStores) { - debug("DataStoreServiceChild success callback!"); + debug("DataStoreServiceChild callback!"); self.getDataStoreCreate(aWindow, resolve, aStores); - }, function() { - debug("DataStoreServiceChild error callback!"); - reject(new aWindow.DOMError("SecurityError", "Access denied")); }); } }); @@ -428,39 +425,32 @@ DataStoreService.prototype = { /* DataStoreServiceChild */ -function DataStoreServiceChild(aWindow, aName, aSuccessCb, aErrorCb) { +function DataStoreServiceChild(aWindow, aName, aCallback) { debug("DataStoreServiceChild created"); - this.init(aWindow, aName, aSuccessCb, aErrorCb); + this.init(aWindow, aName, aCallback); } DataStoreServiceChild.prototype = { __proto__: DOMRequestIpcHelper.prototype, - init: function(aWindow, aName, aSuccessCb, aErrorCb) { + init: function(aWindow, aName, aCallback) { debug("DataStoreServiceChild init"); - this._successCb = aSuccessCb; - this._errorCb = aErrorCb; + this._callback = aCallback; - this.initDOMRequestHelper(aWindow, [ "DataStore:Get:Return:OK", - "DataStore:Get:Return:KO" ]); + this.initDOMRequestHelper(aWindow, [ "DataStore:Get:Return" ]); // This is a security issue and it will be fixed by Bug 916091 cpmm.sendAsyncMessage("DataStore:Get", - { name: aName }, null, aWindow.document.nodePrincipal ); + { name: aName, appId: aWindow.document.nodePrincipal.appId }); }, receiveMessage: function(aMessage) { debug("DataStoreServiceChild receiveMessage"); - - switch (aMessage.name) { - case 'DataStore:Get:Return:OK': - this._successCb(aMessage.data.stores); - break; - - case 'DataStore:Get:Return:KO': - this._errorCb(); - break; + if (aMessage.name != 'DataStore:Get:Return') { + return; } + + this._callback(aMessage.data.stores); } } diff --git a/dom/datastore/DataStoreServiceInternal.jsm b/dom/datastore/DataStoreServiceInternal.jsm index 3bbbeee3958e..8bafc84c70bb 100644 --- a/dom/datastore/DataStoreServiceInternal.jsm +++ b/dom/datastore/DataStoreServiceInternal.jsm @@ -42,14 +42,9 @@ this.DataStoreServiceInternal = { let msg = aMessage.data; - if (!aMessage.principal || - aMessage.principal.appId == Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID) { - aMessage.target.sendAsyncMessage("DataStore:Get:Return:KO"); - return; - } - - msg.stores = dataStoreService.getDataStoresInfo(msg.name, aMessage.principal.appId); - aMessage.target.sendAsyncMessage("DataStore:Get:Return:OK", msg); + // This is a security issue and it will be fixed by Bug 916091 + msg.stores = dataStoreService.getDataStoresInfo(msg.name, msg.appId); + aMessage.target.sendAsyncMessage("DataStore:Get:Return", msg); } } From 336053fa455b05c325277092782c958cc15529bb Mon Sep 17 00:00:00 2001 From: Kai Engert Date: Sat, 9 Nov 2013 11:18:00 +0100 Subject: [PATCH 25/52] Bug 935568, update Mozilla to NSPR 4.10.2 RTM, r=wtc/me --- nsprpub/TAG-INFO | 2 +- nsprpub/config/prdepend.h | 1 + nsprpub/lib/ds/plarena.c | 12 ++++++++---- nsprpub/pr/include/prinit.h | 4 ++-- nsprpub/pr/src/pthreads/ptio.c | 2 +- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/nsprpub/TAG-INFO b/nsprpub/TAG-INFO index 7924a0f09cd6..4cf11c329c1d 100644 --- a/nsprpub/TAG-INFO +++ b/nsprpub/TAG-INFO @@ -1 +1 @@ -NSPR_4_10_2_BETA1 +NSPR_4_10_2_RTM diff --git a/nsprpub/config/prdepend.h b/nsprpub/config/prdepend.h index e49e92677e3e..6c66b37ca0fc 100644 --- a/nsprpub/config/prdepend.h +++ b/nsprpub/config/prdepend.h @@ -10,3 +10,4 @@ */ #error "Do not include this header file." + diff --git a/nsprpub/lib/ds/plarena.c b/nsprpub/lib/ds/plarena.c index 23610ea88d94..95e1931ee66b 100644 --- a/nsprpub/lib/ds/plarena.c +++ b/nsprpub/lib/ds/plarena.c @@ -153,7 +153,7 @@ PR_IMPLEMENT(void *) PL_ArenaAllocate(PLArenaPool *pool, PRUint32 nb) { a = pool->current; do { - if ( a->avail +nb <= a->limit ) { + if ( nb <= a->limit - a->avail ) { pool->current = a; rp = (char *)a->avail; a->avail += nb; @@ -171,7 +171,7 @@ PR_IMPLEMENT(void *) PL_ArenaAllocate(PLArenaPool *pool, PRUint32 nb) return(0); for ( a = arena_freelist, p = NULL; a != NULL ; p = a, a = a->next ) { - if ( a->base +nb <= a->limit ) { + if ( nb <= a->limit - a->base ) { if ( p == NULL ) arena_freelist = a->next; else @@ -196,8 +196,12 @@ PR_IMPLEMENT(void *) PL_ArenaAllocate(PLArenaPool *pool, PRUint32 nb) /* attempt to allocate from the heap */ { PRUint32 sz = PR_MAX(pool->arenasize, nb); - sz += sizeof *a + pool->mask; /* header and alignment slop */ - a = (PLArena*)PR_MALLOC(sz); + if (PR_UINT32_MAX - sz < sizeof *a + pool->mask) { + a = NULL; + } else { + sz += sizeof *a + pool->mask; /* header and alignment slop */ + a = (PLArena*)PR_MALLOC(sz); + } if ( NULL != a ) { a->limit = (PRUword)a + sz; a->base = a->avail = (PRUword)PL_ARENA_ALIGN(pool, a + 1); diff --git a/nsprpub/pr/include/prinit.h b/nsprpub/pr/include/prinit.h index d2e76bbf2e29..557f2e2202b4 100644 --- a/nsprpub/pr/include/prinit.h +++ b/nsprpub/pr/include/prinit.h @@ -31,11 +31,11 @@ PR_BEGIN_EXTERN_C ** The format of the version string is ** ".[.] []" */ -#define PR_VERSION "4.10.2 Beta" +#define PR_VERSION "4.10.2" #define PR_VMAJOR 4 #define PR_VMINOR 10 #define PR_VPATCH 2 -#define PR_BETA PR_TRUE +#define PR_BETA PR_FALSE /* ** PRVersionCheck diff --git a/nsprpub/pr/src/pthreads/ptio.c b/nsprpub/pr/src/pthreads/ptio.c index abf61d5d2b83..79d58ce8fa05 100644 --- a/nsprpub/pr/src/pthreads/ptio.c +++ b/nsprpub/pr/src/pthreads/ptio.c @@ -4586,7 +4586,7 @@ PR_IMPLEMENT(PRFileDesc*) PR_ImportUDPSocket(PRInt32 osfd) if (!_pr_initialized) _PR_ImplicitInitialization(); fd = pt_SetMethods(osfd, PR_DESC_SOCKET_UDP, PR_FALSE, PR_TRUE); - if (NULL != fd) close(osfd); + if (NULL == fd) close(osfd); return fd; } /* PR_ImportUDPSocket */ From 9e2232b7de510e631e5f2dcd8dfd5ffd01ce2f8b Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Sat, 9 Nov 2013 07:53:02 -0800 Subject: [PATCH 26/52] Bug 936100 part 1: Adjust reftests and crashtests to no longer bother with flexbox pref. r=mats --- layout/generic/crashtests/crashtests.list | 48 +++++++++---------- layout/reftests/bugs/reftest.list | 2 +- .../flexbox/flexbox-pref-1-disabled-ref.xhtml | 22 --------- .../flexbox/flexbox-pref-1-enabled-ref.xhtml | 22 --------- layout/reftests/flexbox/flexbox-pref-1.xhtml | 40 ---------------- layout/reftests/flexbox/reftest.list | 12 ----- 6 files changed, 25 insertions(+), 121 deletions(-) delete mode 100644 layout/reftests/flexbox/flexbox-pref-1-disabled-ref.xhtml delete mode 100644 layout/reftests/flexbox/flexbox-pref-1-enabled-ref.xhtml delete mode 100644 layout/reftests/flexbox/flexbox-pref-1.xhtml diff --git a/layout/generic/crashtests/crashtests.list b/layout/generic/crashtests/crashtests.list index 3dadddc3c81f..8eb981531acd 100644 --- a/layout/generic/crashtests/crashtests.list +++ b/layout/generic/crashtests/crashtests.list @@ -450,9 +450,9 @@ load 730559.html load first-letter-638937.html load first-letter-638937-2.html load 734777.html -test-pref(layout.css.flexbox.enabled,true) load 737313-1.html -test-pref(layout.css.flexbox.enabled,true) load 737313-2.html -test-pref(layout.css.flexbox.enabled,true) load 737313-3.html +load 737313-1.html +load 737313-2.html +load 737313-3.html load 747688.html load 750066.html test-pref(font.size.inflation.emPerLine,15) asserts(1-100) load font-inflation-762332.html # bug 762332 @@ -467,37 +467,37 @@ load 769120.html load 786740-1.html asserts(0-4) test-pref(font.size.inflation.emPerLine,15) load 791601.xhtml # 3 counts of bug 871327, 1 bug 367185 test-pref(font.size.inflation.minTwips,120) load 794693.html -asserts(8) test-pref(layout.css.flexbox.enabled,true) load 798020-1.html -test-pref(layout.css.flexbox.enabled,true) load 798235-1.html -test-pref(layout.css.flexbox.enabled,true) load 799207-1.html -asserts(12) test-pref(layout.css.flexbox.enabled,true) load 799207-2.html -test-pref(layout.css.flexbox.enabled,true) load 801268-1.html -test-pref(layout.css.flexbox.enabled,true) load 804089-1.xhtml +asserts(8) load 798020-1.html +load 798235-1.html +load 799207-1.html +asserts(12) load 799207-2.html +load 801268-1.html +load 804089-1.xhtml load 810726.html -test-pref(layout.css.flexbox.enabled,true) load 825810-1.html -test-pref(layout.css.flexbox.enabled,true) load 825810-2.html -test-pref(layout.css.flexbox.enabled,true) load 827076.html +load 825810-1.html +load 825810-2.html +load 827076.html load 840818.html -test-pref(layout.css.flexbox.enabled,true) load 812822-1.html -asserts(1) test-pref(layout.css.flexbox.enabled,true) load 824297-1.html # bug 399262 -test-pref(layout.css.flexbox.enabled,true) load 826483-1.html -asserts(1) test-pref(layout.css.flexbox.enabled,true) load 826532-1.html # bug 399262 -test-pref(layout.css.flexbox.enabled,true) load 827168-1.html +load 812822-1.html +asserts(1) load 824297-1.html # bug 399262 +load 826483-1.html +asserts(1) load 826532-1.html # bug 399262 +load 827168-1.html load 836895.html load 840787.html load 842132-1.html -test-pref(layout.css.flexbox.enabled,true) load 844529-1.html +load 844529-1.html load 847130.xhtml load 847208.html asserts(4) load 847209.html # bug 847368 -test-pref(layout.css.flexbox.enabled,true) load 847211-1.html +load 847211-1.html load 849603.html -test-pref(layout.css.flexbox.enabled,true) load 851396-1.html -test-pref(layout.css.flexbox.enabled,true) load 854263-1.html -test-pref(layout.css.flexbox.enabled,true) load 862947-1.html +load 851396-1.html +load 854263-1.html +load 862947-1.html needs-focus pref(accessibility.browsewithcaret,true) load 868906.html -test-pref(layout.css.flexbox.enabled,true) load 866547-1.html -asserts(1-4) test-pref(layout.css.flexbox.enabled,true) load 876074-1.html # bug 876749 +load 866547-1.html +asserts(1-4) load 876074-1.html # bug 876749 load 885009-1.html load 893523.html test-pref(layout.css.sticky.enabled,true) load 914891.html diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 1641f71ce973..46812d2ae1da 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1759,7 +1759,7 @@ fails-if(Android&&AndroidVersion<15) == 836844-1.html 836844-1-ref.html == 846144-1.html 846144-1-ref.html == 847850-1.html 847850-1-ref.html == 848421-1.html 848421-1-ref.html -test-pref(layout.css.flexbox.enabled,true) == 849407-1.html 849407-1-ref.html +== 849407-1.html 849407-1-ref.html == 849996-1.html 849996-1-ref.html == 858803-1.html 858803-1-ref.html == 860242-1.html 860242-1-ref.html diff --git a/layout/reftests/flexbox/flexbox-pref-1-disabled-ref.xhtml b/layout/reftests/flexbox/flexbox-pref-1-disabled-ref.xhtml deleted file mode 100644 index 8dc18f44a664..000000000000 --- a/layout/reftests/flexbox/flexbox-pref-1-disabled-ref.xhtml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - -

- "display: flex" is: -

disabled
-

-

- "display: inline-flex" is: -

disabled
-

- - diff --git a/layout/reftests/flexbox/flexbox-pref-1-enabled-ref.xhtml b/layout/reftests/flexbox/flexbox-pref-1-enabled-ref.xhtml deleted file mode 100644 index 9bfba5f31505..000000000000 --- a/layout/reftests/flexbox/flexbox-pref-1-enabled-ref.xhtml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - -

- "display: flex" is: -

enabled
-

-

- "display: inline-flex" is: -

enabled
-

- - diff --git a/layout/reftests/flexbox/flexbox-pref-1.xhtml b/layout/reftests/flexbox/flexbox-pref-1.xhtml deleted file mode 100644 index 471f388b4e6a..000000000000 --- a/layout/reftests/flexbox/flexbox-pref-1.xhtml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - -

- "display: flex" is: - -

enabled
-
disabled
-

-

- "display: inline-flex" is:
- -

enabled
-
disabled
-

- - diff --git a/layout/reftests/flexbox/reftest.list b/layout/reftests/flexbox/reftest.list index 1fb0234e3d49..3c599e92f256 100644 --- a/layout/reftests/flexbox/reftest.list +++ b/layout/reftests/flexbox/reftest.list @@ -9,18 +9,6 @@ # tests over to the w3c-css directory, so that they can become part of the # W3C's test suite. -# Tests for flexbox pref "layout.css.flexbox.enabled" -# (Note that it defaults to being off in release builds - see bug 841876) -# Check that manually setting the pref on/off w/ test-pref() works correctly: -test-pref(layout.css.flexbox.enabled,false) == flexbox-pref-1.xhtml flexbox-pref-1-disabled-ref.xhtml -test-pref(layout.css.flexbox.enabled,true) == flexbox-pref-1.xhtml flexbox-pref-1-enabled-ref.xhtml - -# Enable pref for remaining tests -# (Most tests only need it in the testcase, but a few use it in the -# reference case, so we'll just enable it using "pref()" to make -# it available for both.) -default-preferences pref(layout.css.flexbox.enabled,true) - # Tests for cross-axis alignment (align-self / align-items properties) fails == flexbox-align-self-baseline-horiz-2.xhtml flexbox-align-self-baseline-horiz-2-ref.xhtml # bug 793456, and possibly others # This one fails on windows R (but not Ru, strangely). On Windows R, the From 95689eaaae9ed5c3d2fc79673b861c8daa7f3459 Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Sat, 9 Nov 2013 07:53:02 -0800 Subject: [PATCH 27/52] Bug 936100 part 2: Adjust non-flexbox-specific mochitests to no longer bother with flexbox pref. r=mats --- layout/style/test/property_database.js | 342 +++++++++--------- .../style/test/test_computed_style_prefs.html | 1 - .../test/test_transitions_per_property.html | 24 +- 3 files changed, 173 insertions(+), 194 deletions(-) diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index 4fcf577a84d1..e971dc7f2d54 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -2356,6 +2356,8 @@ var gCSSProperties = { prerequisites: { "float": "none", "position": "static" }, other_values: [ "block", + "flex", + "inline-flex", "list-item", "inline-block", "table", @@ -3694,6 +3696,170 @@ var gCSSProperties = { other_values: [ "non-scaling-stroke" ], invalid_values: [] }, + "align-items": { + domProp: "alignItems", + inherited: false, + type: CSS_TYPE_LONGHAND, + initial_values: [ "stretch" ], + other_values: [ "flex-start", "flex-end", "center", "baseline" ], + invalid_values: [ "space-between", "abc", "30px" ] + }, + "align-self": { + domProp: "alignSelf", + inherited: false, + type: CSS_TYPE_LONGHAND, + // (Assuming defaults on the parent, 'auto' will compute to 'stretch'.) + initial_values: [ "auto", "stretch" ], + other_values: [ "flex-start", "flex-end", "center", "baseline" ], + invalid_values: [ "space-between", "abc", "30px" ] + }, + "flex": { + domProp: "flex", + inherited: false, + type: CSS_TYPE_TRUE_SHORTHAND, + subproperties: [ + "flex-grow", + "flex-shrink", + "flex-basis" + ], + initial_values: [ "0 1 auto", "auto 0 1", "0 auto", "auto 0" ], + other_values: [ + "none", + "1", + "0", + "0 1", + "0.5", + "1.2 3.4", + "0 0 0", + "0 0 0px", + "0px 0 0", + "5px 0 0", + "2 auto", + "auto 4", + "auto 5.6 7.8", + "-moz-max-content", + "1 -moz-max-content", + "1 2 -moz-max-content", + "-moz-max-content 1", + "-moz-max-content 1 2", + "-0" + ], + invalid_values: [ + "1 2px 3", + "1 auto 3", + "1px 2 3px", + "1px 2 3 4px", + "-1", + "1 -1" + ] + }, + "flex-basis": { + domProp: "flexBasis", + inherited: false, + type: CSS_TYPE_LONGHAND, + initial_values: [ " auto" ], + // NOTE: This is cribbed directly from the "width" chunk, since this + // property takes the exact same values as width (albeit with + // different semantics on 'auto'). + // XXXdholbert (Maybe these should get separated out into + // a reusable array defined at the top of this file?) + other_values: [ "15px", "3em", "15%", "-moz-max-content", "-moz-min-content", "-moz-fit-content", "-moz-available", + // valid calc() values + "calc(-2px)", + "calc(2px)", + "calc(50%)", + "calc(50% + 2px)", + "calc( 50% + 2px)", + "calc(50% + 2px )", + "calc( 50% + 2px )", + "calc(50% - -2px)", + "calc(2px - -50%)", + "calc(3*25px)", + "calc(3 *25px)", + "calc(3 * 25px)", + "calc(3* 25px)", + "calc(25px*3)", + "calc(25px *3)", + "calc(25px* 3)", + "calc(25px * 3)", + "calc(3*25px + 50%)", + "calc(50% - 3em + 2px)", + "calc(50% - (3em + 2px))", + "calc((50% - 3em) + 2px)", + "calc(2em)", + "calc(50%)", + "calc(50px/2)", + "calc(50px/(2 - 1))" + ], + invalid_values: [ "none", "-2px", + // invalid calc() values + "calc(50%+ 2px)", + "calc(50% +2px)", + "calc(50%+2px)", + "-moz-min()", + "calc(min())", + "-moz-max()", + "calc(max())", + "-moz-min(5px)", + "calc(min(5px))", + "-moz-max(5px)", + "calc(max(5px))", + "-moz-min(5px,2em)", + "calc(min(5px,2em))", + "-moz-max(5px,2em)", + "calc(max(5px,2em))", + "calc(50px/(2 - 2))", + // If we ever support division by values, which is + // complicated for the reasons described in + // http://lists.w3.org/Archives/Public/www-style/2010Jan/0007.html + // , we should support all 4 of these as described in + // http://lists.w3.org/Archives/Public/www-style/2009Dec/0296.html + "calc((3em / 100%) * 3em)", + "calc(3em / 100% * 3em)", + "calc(3em * (3em / 100%))", + "calc(3em * 3em / 100%)" + ] + }, + "flex-direction": { + domProp: "flexDirection", + inherited: false, + type: CSS_TYPE_LONGHAND, + initial_values: [ "row" ], + other_values: [ "row-reverse", "column", "column-reverse" ], + invalid_values: [ "10px", "30%", "justify", "column wrap" ] + }, + "flex-grow": { + domProp: "flexGrow", + inherited: false, + type: CSS_TYPE_LONGHAND, + initial_values: [ "0" ], + other_values: [ "3", "1", "1.0", "2.5", "123" ], + invalid_values: [ "0px", "-5", "1%", "3em", "stretch", "auto" ] + }, + "flex-shrink": { + domProp: "flexShrink", + inherited: false, + type: CSS_TYPE_LONGHAND, + initial_values: [ "1" ], + other_values: [ "3", "0", "0.0", "2.5", "123" ], + invalid_values: [ "0px", "-5", "1%", "3em", "stretch", "auto" ] + }, + "order": { + domProp: "order", + inherited: false, + type: CSS_TYPE_LONGHAND, + initial_values: [ "0" ], + other_values: [ "1", "99999", "-1", "-50" ], + invalid_values: [ "0px", "1.0", "1.", "1%", "0.2", "3em", "stretch" ] + }, + "justify-content": { + domProp: "justifyContent", + inherited: false, + type: CSS_TYPE_LONGHAND, + initial_values: [ "flex-start" ], + other_values: [ "flex-end", "center", "space-between", "space-around" ], + invalid_values: [ "baseline", "stretch", "30px", "5%" ] + }, // Aliases "-moz-transform": { @@ -4068,182 +4234,6 @@ function get_computed_value(cs, property) return cs.getPropertyValue(property); } -// Automatically add pref-controlled CSS properties & keywords -// to gCSSProperties, if the flexbox pref is enabled. -if (SpecialPowers.getBoolPref("layout.css.flexbox.enabled")) { - var flexProperties = { - "align-items": { - domProp: "alignItems", - inherited: false, - type: CSS_TYPE_LONGHAND, - initial_values: [ "stretch" ], - other_values: [ "flex-start", "flex-end", "center", "baseline" ], - invalid_values: [ "space-between", "abc", "30px" ] - }, - "align-self": { - domProp: "alignSelf", - inherited: false, - type: CSS_TYPE_LONGHAND, - // (Assuming defaults on the parent, 'auto' will compute to 'stretch'.) - initial_values: [ "auto", "stretch" ], - other_values: [ "flex-start", "flex-end", "center", "baseline" ], - invalid_values: [ "space-between", "abc", "30px" ] - }, - "flex": { - domProp: "flex", - inherited: false, - type: CSS_TYPE_TRUE_SHORTHAND, - subproperties: [ - "flex-grow", - "flex-shrink", - "flex-basis" - ], - initial_values: [ "0 1 auto", "auto 0 1", "0 auto", "auto 0" ], - other_values: [ - "none", - "1", - "0", - "0 1", - "0.5", - "1.2 3.4", - "0 0 0", - "0 0 0px", - "0px 0 0", - "5px 0 0", - "2 auto", - "auto 4", - "auto 5.6 7.8", - "-moz-max-content", - "1 -moz-max-content", - "1 2 -moz-max-content", - "-moz-max-content 1", - "-moz-max-content 1 2", - "-0" - ], - invalid_values: [ - "1 2px 3", - "1 auto 3", - "1px 2 3px", - "1px 2 3 4px", - "-1", - "1 -1" - ] - }, - "flex-basis": { - domProp: "flexBasis", - inherited: false, - type: CSS_TYPE_LONGHAND, - initial_values: [ " auto" ], - // NOTE: This is cribbed directly from the "width" chunk, since this - // property takes the exact same values as width (albeit with - // different semantics on 'auto'). - // XXXdholbert (Maybe these should get separated out into - // a reusable array defined at the top of this file?) - other_values: [ "15px", "3em", "15%", "-moz-max-content", "-moz-min-content", "-moz-fit-content", "-moz-available", - // valid calc() values - "calc(-2px)", - "calc(2px)", - "calc(50%)", - "calc(50% + 2px)", - "calc( 50% + 2px)", - "calc(50% + 2px )", - "calc( 50% + 2px )", - "calc(50% - -2px)", - "calc(2px - -50%)", - "calc(3*25px)", - "calc(3 *25px)", - "calc(3 * 25px)", - "calc(3* 25px)", - "calc(25px*3)", - "calc(25px *3)", - "calc(25px* 3)", - "calc(25px * 3)", - "calc(3*25px + 50%)", - "calc(50% - 3em + 2px)", - "calc(50% - (3em + 2px))", - "calc((50% - 3em) + 2px)", - "calc(2em)", - "calc(50%)", - "calc(50px/2)", - "calc(50px/(2 - 1))" - ], - invalid_values: [ "none", "-2px", - // invalid calc() values - "calc(50%+ 2px)", - "calc(50% +2px)", - "calc(50%+2px)", - "-moz-min()", - "calc(min())", - "-moz-max()", - "calc(max())", - "-moz-min(5px)", - "calc(min(5px))", - "-moz-max(5px)", - "calc(max(5px))", - "-moz-min(5px,2em)", - "calc(min(5px,2em))", - "-moz-max(5px,2em)", - "calc(max(5px,2em))", - "calc(50px/(2 - 2))", - // If we ever support division by values, which is - // complicated for the reasons described in - // http://lists.w3.org/Archives/Public/www-style/2010Jan/0007.html - // , we should support all 4 of these as described in - // http://lists.w3.org/Archives/Public/www-style/2009Dec/0296.html - "calc((3em / 100%) * 3em)", - "calc(3em / 100% * 3em)", - "calc(3em * (3em / 100%))", - "calc(3em * 3em / 100%)" - ] - }, - "flex-direction": { - domProp: "flexDirection", - inherited: false, - type: CSS_TYPE_LONGHAND, - initial_values: [ "row" ], - other_values: [ "row-reverse", "column", "column-reverse" ], - invalid_values: [ "10px", "30%", "justify", "column wrap" ] - }, - "flex-grow": { - domProp: "flexGrow", - inherited: false, - type: CSS_TYPE_LONGHAND, - initial_values: [ "0" ], - other_values: [ "3", "1", "1.0", "2.5", "123" ], - invalid_values: [ "0px", "-5", "1%", "3em", "stretch", "auto" ] - }, - "flex-shrink": { - domProp: "flexShrink", - inherited: false, - type: CSS_TYPE_LONGHAND, - initial_values: [ "1" ], - other_values: [ "3", "0", "0.0", "2.5", "123" ], - invalid_values: [ "0px", "-5", "1%", "3em", "stretch", "auto" ] - }, - "order": { - domProp: "order", - inherited: false, - type: CSS_TYPE_LONGHAND, - initial_values: [ "0" ], - other_values: [ "1", "99999", "-1", "-50" ], - invalid_values: [ "0px", "1.0", "1.", "1%", "0.2", "3em", "stretch" ] - }, - "justify-content": { - domProp: "justifyContent", - inherited: false, - type: CSS_TYPE_LONGHAND, - initial_values: [ "flex-start" ], - other_values: [ "flex-end", "center", "space-between", "space-around" ], - invalid_values: [ "baseline", "stretch", "30px", "5%" ] - } - }; - for (var prop in flexProperties) { - gCSSProperties[prop] = flexProperties[prop]; - } - gCSSProperties["display"].other_values.push("flex"); - gCSSProperties["display"].other_values.push("inline-flex"); -} - if (SpecialPowers.getBoolPref("layout.css.vertical-text.enabled")) { var verticalTextProperties = { "writing-mode": { diff --git a/layout/style/test/test_computed_style_prefs.html b/layout/style/test/test_computed_style_prefs.html index 9adcb4876186..56c0053050cd 100644 --- a/layout/style/test/test_computed_style_prefs.html +++ b/layout/style/test/test_computed_style_prefs.html @@ -69,7 +69,6 @@ function step() { var gProps = { "layout.css.vertical-text.enabled": ["text-combine-horizontal", "text-orientation", "writing-mode"], - "layout.css.flexbox.enabled": ["align-items", "align-self", "flex-basis", "flex-direction", "flex-grow", "flex-shrink", "order", "justify-content"], "layout.css.font-features.enabled": ["font-kerning", "font-synthesis", "font-variant-alternates", "font-variant-caps", "font-variant-east-asian", "font-variant-ligatures", "font-variant-numeric", "font-variant-position"], "layout.css.image-orientation.enabled": ["image-orientation"], "layout.css.mix-blend-mode.enabled": ["mix-blend-mode"], diff --git a/layout/style/test/test_transitions_per_property.html b/layout/style/test/test_transitions_per_property.html index a82393e924e5..d772e66402e0 100644 --- a/layout/style/test/test_transitions_per_property.html +++ b/layout/style/test/test_transitions_per_property.html @@ -123,6 +123,12 @@ var supported_properties = { // (not parsing/interpolation) test_float_zeroToOne_clamped ], "filter" : [ test_filter_transition ], + "flex-basis": [ test_length_transition, test_percent_transition, + test_length_clamped, test_percent_clamped ], + "flex-grow": [ test_float_zeroToOne_transition, + test_float_aboveOne_transition ], + "flex-shrink": [ test_float_zeroToOne_transition, + test_float_aboveOne_transition ], "flood-color": [ test_color_transition ], "flood-opacity" : [ test_float_zeroToOne_transition, // opacity is clamped in computed style @@ -179,6 +185,7 @@ var supported_properties = { // opacity is clamped in computed style // (not parsing/interpolation) test_float_zeroToOne_clamped ], + "order": [ test_integer_transition ], "outline-color": [ test_color_transition ], "outline-offset": [ test_length_transition, test_length_unclamped ], "outline-width": [ test_length_transition, test_length_clamped ], @@ -244,23 +251,6 @@ var supported_properties = { "z-index": [ test_integer_transition, test_pos_integer_or_auto_transition ], }; -// Automatically add pref-controlled CSS properties & keywords -// to supported_properties, if the flexbox pref is enabled. -if (SpecialPowers.getBoolPref("layout.css.flexbox.enabled")) { - var flexbox_properties = { - "flex-basis": [ test_length_transition, test_percent_transition, - test_length_clamped, test_percent_clamped ], - "flex-grow": [ test_float_zeroToOne_transition, - test_float_aboveOne_transition ], - "flex-shrink": [ test_float_zeroToOne_transition, - test_float_aboveOne_transition ], - "order": [ test_integer_transition ] - }; - for (var prop in flexbox_properties) { - supported_properties[prop] = flexbox_properties[prop]; - } -} - var div = document.getElementById("display"); var OMTAdiv = document.getElementById("transformTest"); var cs = getComputedStyle(div, ""); From b67a0b187c993be39721eac4b9d69dd278a30ee0 Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Sat, 9 Nov 2013 07:53:03 -0800 Subject: [PATCH 28/52] Bug 936100 part 3: Remove pref-setting mochitest wrappers for flexbox-specific mochitests, and transfer their boilerplate into the actual test files (currently named "file_"). r=mats --- layout/style/test/Makefile.in | 7 --- .../test/file_flexbox_align_self_auto.html | 19 ++++---- .../file_flexbox_child_display_values.xhtml | 21 ++++---- .../file_flexbox_flex_grow_and_shrink.html | 17 ++++--- .../test/file_flexbox_flex_shorthand.html | 20 ++++---- layout/style/test/file_flexbox_layout.html | 24 +++++----- layout/style/test/file_flexbox_order.html | 17 ++++--- .../style/test/file_flexbox_order_table.html | 17 ++++--- .../test/test_flexbox_align_self_auto.html | 43 ----------------- .../test_flexbox_child_display_values.html | 44 ----------------- .../test_flexbox_flex_grow_and_shrink.html | 44 ----------------- .../test/test_flexbox_flex_shorthand.html | 43 ----------------- layout/style/test/test_flexbox_layout.html | 43 ----------------- layout/style/test/test_flexbox_order.html | 43 ----------------- .../style/test/test_flexbox_order_table.html | 48 ------------------- 15 files changed, 73 insertions(+), 377 deletions(-) delete mode 100644 layout/style/test/test_flexbox_align_self_auto.html delete mode 100644 layout/style/test/test_flexbox_child_display_values.html delete mode 100644 layout/style/test/test_flexbox_flex_grow_and_shrink.html delete mode 100644 layout/style/test/test_flexbox_flex_shorthand.html delete mode 100644 layout/style/test/test_flexbox_layout.html delete mode 100644 layout/style/test/test_flexbox_order.html delete mode 100644 layout/style/test/test_flexbox_order_table.html diff --git a/layout/style/test/Makefile.in b/layout/style/test/Makefile.in index 80eacde102f3..204d2a9d9724 100644 --- a/layout/style/test/Makefile.in +++ b/layout/style/test/Makefile.in @@ -94,20 +94,13 @@ MOCHITEST_FILES = test_acid3_test46.html \ test_descriptor_syntax_errors.html \ test_dont_use_document_colors.html \ file_flexbox_align_self_auto.html \ - test_flexbox_align_self_auto.html \ file_flexbox_child_display_values.xhtml \ - test_flexbox_child_display_values.html \ file_flexbox_flex_grow_and_shrink.html \ - test_flexbox_flex_grow_and_shrink.html \ file_flexbox_flex_shorthand.html \ - test_flexbox_flex_shorthand.html \ file_flexbox_layout.html \ - test_flexbox_layout.html \ flexbox_layout_testcases.js \ file_flexbox_order.html \ - test_flexbox_order.html \ file_flexbox_order_table.html \ - test_flexbox_order_table.html \ test_font_face_parser.html \ test_font_family_parsing.html \ test_font_feature_values_parsing.html \ diff --git a/layout/style/test/file_flexbox_align_self_auto.html b/layout/style/test/file_flexbox_align_self_auto.html index 9588f4ea19ec..5a5e37ab95db 100644 --- a/layout/style/test/file_flexbox_align_self_auto.html +++ b/layout/style/test/file_flexbox_align_self_auto.html @@ -1,6 +1,16 @@ + + + + Test behavior of 'align-self:auto' (Bug 696253) + + + +Mozilla Bug 696253
@@ -41,10 +51,6 @@ * This mochitest tests that situation and a few other similar tricky situations. */ -// Use "is()" and "ok()" from parent document. -var is = parent.is; -var ok = parent.ok; - /* * Utility function for getting computed style of "align-self": */ @@ -162,9 +168,6 @@ function testNodeThatHasGrandparent(elem) { * Main test function */ function main() { - ok(SpecialPowers.getBoolPref("layout.css.flexbox.enabled"), - "expecting to be run with flexbox support enabled"); - // Test the root node // ================== // (It's special because it has no parent style context.) @@ -201,8 +204,6 @@ function main() { testGeneralNode(displayNode); testNodeThatHasParent(displayNode); testNodeThatHasGrandparent(displayNode); - - parent.finish(); } main(); diff --git a/layout/style/test/file_flexbox_child_display_values.xhtml b/layout/style/test/file_flexbox_child_display_values.xhtml index 53d646c19287..9a38748df929 100644 --- a/layout/style/test/file_flexbox_child_display_values.xhtml +++ b/layout/style/test/file_flexbox_child_display_values.xhtml @@ -1,6 +1,16 @@ + + + + Test "display" values of content in a flex container (Bug 783415) + + + -
+Mozilla Bug 783415 +
@@ -18,10 +28,6 @@
  * specified display-value.)
  */
 
-// Use "is()" and "ok()" from parent document.
-let is = parent.is;
-let ok = parent.ok;
-
 /*
  * Utility function for getting computed style of "display".
  *
@@ -120,9 +126,6 @@ function testDisplayValue(aSpecifiedDisplay,
  * Main test function
  */
 function main() {
-  ok(SpecialPowers.getBoolPref("layout.css.flexbox.enabled"),
-     "expecting to be run with flexbox support enabled");
-
   testDisplayValue("none");
   testDisplayValue("block");
   testDisplayValue("flex");
@@ -176,8 +179,6 @@ function main() {
     function(aSpecifiedDisplay) {
       testDisplayValue(aSpecifiedDisplay, aSpecifiedDisplay, "block");
   });
-
-  parent.finish();
 }
 
 main();
diff --git a/layout/style/test/file_flexbox_flex_grow_and_shrink.html b/layout/style/test/file_flexbox_flex_grow_and_shrink.html
index dc81fd0d62c8..2cfb5c6e9692 100644
--- a/layout/style/test/file_flexbox_flex_grow_and_shrink.html
+++ b/layout/style/test/file_flexbox_flex_grow_and_shrink.html
@@ -1,7 +1,14 @@
 
 
+
 
+  
+  Test for flex-grow and flex-shrink animation (Bug 696253)
+  
   
+  
   
 
 
+Mozilla Bug 696253
 
@@ -62,13 +70,6 @@ function advance_clock(milliseconds) { SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(milliseconds); } -// Use "is()" and "ok()" from parent document. -var is = parent.is; -var ok = parent.ok; - -ok(SpecialPowers.getBoolPref("layout.css.flexbox.enabled"), - "expecting to be run with flexbox support enabled"); - var display = document.getElementById("display"); var div = null; var cs = null; @@ -176,8 +177,6 @@ done_div(); SpecialPowers.DOMWindowUtils.restoreNormalRefresh(); -parent.finish(); -
diff --git a/layout/style/test/file_flexbox_flex_shorthand.html b/layout/style/test/file_flexbox_flex_shorthand.html index 7ee985325a28..23d94a250827 100644 --- a/layout/style/test/file_flexbox_flex_shorthand.html +++ b/layout/style/test/file_flexbox_flex_shorthand.html @@ -1,10 +1,20 @@ + + + Test for Bug 696253 + + -
+Mozilla Bug 696253 +
+
+
 
   
   
+  
 
 
-
+Mozilla Bug 666041 +
+
+
 
 
diff --git a/layout/style/test/file_flexbox_order.html b/layout/style/test/file_flexbox_order.html index cf8ebf9b752d..4d5a3890abca 100644 --- a/layout/style/test/file_flexbox_order.html +++ b/layout/style/test/file_flexbox_order.html @@ -1,7 +1,14 @@ + + + Test for Bug 666041 + + +Mozilla Bug 666041
@@ -67,6 +75,8 @@ + +Mozilla Bug 799775
@@ -71,6 +79,8 @@ - - - -Mozilla Bug 696253 -
- -
-
-
-
- - diff --git a/layout/style/test/test_flexbox_child_display_values.html b/layout/style/test/test_flexbox_child_display_values.html deleted file mode 100644 index d503d70ffa91..000000000000 --- a/layout/style/test/test_flexbox_child_display_values.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - Test "display" values of content in a flex container (Bug 783415) - - - - -Mozilla Bug 783415 -
- -
-
-
-
- - diff --git a/layout/style/test/test_flexbox_flex_grow_and_shrink.html b/layout/style/test/test_flexbox_flex_grow_and_shrink.html deleted file mode 100644 index 4ac48ada4111..000000000000 --- a/layout/style/test/test_flexbox_flex_grow_and_shrink.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - Test for flex-grow and flex-shrink animation (Bug 696253) - - - - -Mozilla Bug 696253 -
- -
-
-
-
- - diff --git a/layout/style/test/test_flexbox_flex_shorthand.html b/layout/style/test/test_flexbox_flex_shorthand.html deleted file mode 100644 index 5c572f66138a..000000000000 --- a/layout/style/test/test_flexbox_flex_shorthand.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - Test for Bug 696253 - - - - -Mozilla Bug 696253 -
- -
-
-
-
- - diff --git a/layout/style/test/test_flexbox_layout.html b/layout/style/test/test_flexbox_layout.html deleted file mode 100644 index e39eacd32b98..000000000000 --- a/layout/style/test/test_flexbox_layout.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - Test for Bug 666041 - - - - -Mozilla Bug 666041 -
- -
-
-
-
- - diff --git a/layout/style/test/test_flexbox_order.html b/layout/style/test/test_flexbox_order.html deleted file mode 100644 index 03507d28e0da..000000000000 --- a/layout/style/test/test_flexbox_order.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - Test for Bug 666041 - - - - -Mozilla Bug 666041 -
- -
-
-
-
- - diff --git a/layout/style/test/test_flexbox_order_table.html b/layout/style/test/test_flexbox_order_table.html deleted file mode 100644 index 1bbd091d485d..000000000000 --- a/layout/style/test/test_flexbox_order_table.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - Test for Bug 799775 - - - - -Mozilla Bug 799775 -
- -
-
-
-
- - From 07aa1248086685df30dbe8b64df10a20c05279ba Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Sat, 9 Nov 2013 07:53:03 -0800 Subject: [PATCH 29/52] Bug 936100 part 4: Rename file_flexbox* mochitests (which were previously loaded in iframes) to test_flexbox*. r=mats --HG-- rename : layout/style/test/file_flexbox_align_self_auto.html => layout/style/test/test_flexbox_align_self_auto.html rename : layout/style/test/file_flexbox_child_display_values.xhtml => layout/style/test/test_flexbox_child_display_values.xhtml rename : layout/style/test/file_flexbox_flex_grow_and_shrink.html => layout/style/test/test_flexbox_flex_grow_and_shrink.html rename : layout/style/test/file_flexbox_flex_shorthand.html => layout/style/test/test_flexbox_flex_shorthand.html rename : layout/style/test/file_flexbox_layout.html => layout/style/test/test_flexbox_layout.html rename : layout/style/test/file_flexbox_order.html => layout/style/test/test_flexbox_order.html rename : layout/style/test/file_flexbox_order_table.html => layout/style/test/test_flexbox_order_table.html --- layout/style/test/Makefile.in | 14 +++++++------- ...auto.html => test_flexbox_align_self_auto.html} | 0 ...tml => test_flexbox_child_display_values.xhtml} | 0 ...html => test_flexbox_flex_grow_and_shrink.html} | 0 ...thand.html => test_flexbox_flex_shorthand.html} | 0 ...lexbox_layout.html => test_flexbox_layout.html} | 0 ..._flexbox_order.html => test_flexbox_order.html} | 0 ...er_table.html => test_flexbox_order_table.html} | 0 8 files changed, 7 insertions(+), 7 deletions(-) rename layout/style/test/{file_flexbox_align_self_auto.html => test_flexbox_align_self_auto.html} (100%) rename layout/style/test/{file_flexbox_child_display_values.xhtml => test_flexbox_child_display_values.xhtml} (100%) rename layout/style/test/{file_flexbox_flex_grow_and_shrink.html => test_flexbox_flex_grow_and_shrink.html} (100%) rename layout/style/test/{file_flexbox_flex_shorthand.html => test_flexbox_flex_shorthand.html} (100%) rename layout/style/test/{file_flexbox_layout.html => test_flexbox_layout.html} (100%) rename layout/style/test/{file_flexbox_order.html => test_flexbox_order.html} (100%) rename layout/style/test/{file_flexbox_order_table.html => test_flexbox_order_table.html} (100%) diff --git a/layout/style/test/Makefile.in b/layout/style/test/Makefile.in index 204d2a9d9724..3fdfb0d263c2 100644 --- a/layout/style/test/Makefile.in +++ b/layout/style/test/Makefile.in @@ -93,14 +93,14 @@ MOCHITEST_FILES = test_acid3_test46.html \ test_descriptor_storage.html \ test_descriptor_syntax_errors.html \ test_dont_use_document_colors.html \ - file_flexbox_align_self_auto.html \ - file_flexbox_child_display_values.xhtml \ - file_flexbox_flex_grow_and_shrink.html \ - file_flexbox_flex_shorthand.html \ - file_flexbox_layout.html \ + test_flexbox_align_self_auto.html \ + test_flexbox_child_display_values.xhtml \ + test_flexbox_flex_grow_and_shrink.html \ + test_flexbox_flex_shorthand.html \ + test_flexbox_layout.html \ flexbox_layout_testcases.js \ - file_flexbox_order.html \ - file_flexbox_order_table.html \ + test_flexbox_order.html \ + test_flexbox_order_table.html \ test_font_face_parser.html \ test_font_family_parsing.html \ test_font_feature_values_parsing.html \ diff --git a/layout/style/test/file_flexbox_align_self_auto.html b/layout/style/test/test_flexbox_align_self_auto.html similarity index 100% rename from layout/style/test/file_flexbox_align_self_auto.html rename to layout/style/test/test_flexbox_align_self_auto.html diff --git a/layout/style/test/file_flexbox_child_display_values.xhtml b/layout/style/test/test_flexbox_child_display_values.xhtml similarity index 100% rename from layout/style/test/file_flexbox_child_display_values.xhtml rename to layout/style/test/test_flexbox_child_display_values.xhtml diff --git a/layout/style/test/file_flexbox_flex_grow_and_shrink.html b/layout/style/test/test_flexbox_flex_grow_and_shrink.html similarity index 100% rename from layout/style/test/file_flexbox_flex_grow_and_shrink.html rename to layout/style/test/test_flexbox_flex_grow_and_shrink.html diff --git a/layout/style/test/file_flexbox_flex_shorthand.html b/layout/style/test/test_flexbox_flex_shorthand.html similarity index 100% rename from layout/style/test/file_flexbox_flex_shorthand.html rename to layout/style/test/test_flexbox_flex_shorthand.html diff --git a/layout/style/test/file_flexbox_layout.html b/layout/style/test/test_flexbox_layout.html similarity index 100% rename from layout/style/test/file_flexbox_layout.html rename to layout/style/test/test_flexbox_layout.html diff --git a/layout/style/test/file_flexbox_order.html b/layout/style/test/test_flexbox_order.html similarity index 100% rename from layout/style/test/file_flexbox_order.html rename to layout/style/test/test_flexbox_order.html diff --git a/layout/style/test/file_flexbox_order_table.html b/layout/style/test/test_flexbox_order_table.html similarity index 100% rename from layout/style/test/file_flexbox_order_table.html rename to layout/style/test/test_flexbox_order_table.html From 8ebaab47403433fb50b883f19eafc9d3bc84da86 Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Sat, 9 Nov 2013 07:53:14 -0800 Subject: [PATCH 30/52] Bug 936100 part 5: Remove usage of flexbox pref from C++ code. r=mats --- layout/base/nsLayoutUtils.cpp | 56 ----------------------------------- layout/style/nsCSSPropList.h | 18 +++++------ layout/style/nsCSSProps.cpp | 3 +- layout/style/nsCSSProps.h | 4 +-- 4 files changed, 11 insertions(+), 70 deletions(-) diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 6017629b2e15..8c5bb2fd4a62 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -94,7 +94,6 @@ using mozilla::image::Flip; using mozilla::image::ImageOps; using mozilla::image::Orientation; -#define FLEXBOX_ENABLED_PREF_NAME "layout.css.flexbox.enabled" #define STICKY_ENABLED_PREF_NAME "layout.css.sticky.enabled" #define TEXT_ALIGN_TRUE_ENABLED_PREF_NAME "layout.css.text-align-true-value.enabled" @@ -125,56 +124,6 @@ static ContentMap& GetContentMap() { return *sContentMap; } -// When the pref "layout.css.flexbox.enabled" changes, this function is invoked -// to let us update kDisplayKTable, to selectively disable or restore the -// entries for "flex" and "inline-flex" in that table. -static int -FlexboxEnabledPrefChangeCallback(const char* aPrefName, void* aClosure) -{ - MOZ_ASSERT(strncmp(aPrefName, FLEXBOX_ENABLED_PREF_NAME, - NS_ARRAY_LENGTH(FLEXBOX_ENABLED_PREF_NAME)) == 0, - "We only registered this callback for a single pref, so it " - "should only be called for that pref"); - - static int32_t sIndexOfFlexInDisplayTable; - static int32_t sIndexOfInlineFlexInDisplayTable; - static bool sAreFlexKeywordIndicesInitialized; // initialized to false - - bool isFlexboxEnabled = - Preferences::GetBool(FLEXBOX_ENABLED_PREF_NAME, false); - - if (!sAreFlexKeywordIndicesInitialized) { - // First run: find the position of "flex" and "inline-flex" in - // kDisplayKTable. - sIndexOfFlexInDisplayTable = - nsCSSProps::FindIndexOfKeyword(eCSSKeyword_flex, - nsCSSProps::kDisplayKTable); - MOZ_ASSERT(sIndexOfFlexInDisplayTable >= 0, - "Couldn't find flex in kDisplayKTable"); - - sIndexOfInlineFlexInDisplayTable = - nsCSSProps::FindIndexOfKeyword(eCSSKeyword_inline_flex, - nsCSSProps::kDisplayKTable); - MOZ_ASSERT(sIndexOfInlineFlexInDisplayTable >= 0, - "Couldn't find inline-flex in kDisplayKTable"); - - sAreFlexKeywordIndicesInitialized = true; - } - - // OK -- now, stomp on or restore the "flex" entries in kDisplayKTable, - // depending on whether the flexbox pref is enabled vs. disabled. - if (sIndexOfFlexInDisplayTable >= 0) { - nsCSSProps::kDisplayKTable[sIndexOfFlexInDisplayTable] = - isFlexboxEnabled ? eCSSKeyword_flex : eCSSKeyword_UNKNOWN; - } - if (sIndexOfInlineFlexInDisplayTable >= 0) { - nsCSSProps::kDisplayKTable[sIndexOfInlineFlexInDisplayTable] = - isFlexboxEnabled ? eCSSKeyword_inline_flex : eCSSKeyword_UNKNOWN; - } - - return 0; -} - // When the pref "layout.css.sticky.enabled" changes, this function is invoked // to let us update kPositionKTable, to selectively disable or restore the // entry for "sticky" in that table. @@ -5217,9 +5166,6 @@ nsLayoutUtils::Initialize() Preferences::AddBoolVarCache(&sInvalidationDebuggingIsEnabled, "nglayout.debug.invalidation"); - Preferences::RegisterCallback(FlexboxEnabledPrefChangeCallback, - FLEXBOX_ENABLED_PREF_NAME); - FlexboxEnabledPrefChangeCallback(FLEXBOX_ENABLED_PREF_NAME, nullptr); Preferences::RegisterCallback(StickyEnabledPrefChangeCallback, STICKY_ENABLED_PREF_NAME); StickyEnabledPrefChangeCallback(STICKY_ENABLED_PREF_NAME, nullptr); @@ -5240,8 +5186,6 @@ nsLayoutUtils::Shutdown() sContentMap = nullptr; } - Preferences::UnregisterCallback(FlexboxEnabledPrefChangeCallback, - FLEXBOX_ENABLED_PREF_NAME); Preferences::UnregisterCallback(StickyEnabledPrefChangeCallback, STICKY_ENABLED_PREF_NAME); diff --git a/layout/style/nsCSSPropList.h b/layout/style/nsCSSPropList.h index af92d93337ad..e4e6a896f703 100644 --- a/layout/style/nsCSSPropList.h +++ b/layout/style/nsCSSPropList.h @@ -1603,7 +1603,7 @@ CSS_PROP_POSITION( align_items, AlignItems, CSS_PROPERTY_PARSE_VALUE, - "layout.css.flexbox.enabled", + "", VARIANT_HK, kAlignItemsKTable, offsetof(nsStylePosition, mAlignItems), @@ -1613,7 +1613,7 @@ CSS_PROP_POSITION( align_self, AlignSelf, CSS_PROPERTY_PARSE_VALUE, - "layout.css.flexbox.enabled", + "", VARIANT_HK, kAlignSelfKTable, offsetof(nsStylePosition, mAlignSelf), @@ -1623,7 +1623,7 @@ CSS_PROP_SHORTHAND( flex, Flex, CSS_PROPERTY_PARSE_FUNCTION, - "layout.css.flexbox.enabled") + "") CSS_PROP_POSITION( flex-basis, flex_basis, @@ -1631,7 +1631,7 @@ CSS_PROP_POSITION( CSS_PROPERTY_PARSE_VALUE | CSS_PROPERTY_VALUE_NONNEGATIVE | CSS_PROPERTY_STORES_CALC, - "layout.css.flexbox.enabled", + "", // NOTE: The parsing implementation for the 'flex' shorthand property has // its own code to parse each subproperty. It does not depend on the // longhand parsing defined here. @@ -1644,7 +1644,7 @@ CSS_PROP_POSITION( flex_direction, FlexDirection, CSS_PROPERTY_PARSE_VALUE, - "layout.css.flexbox.enabled", + "", VARIANT_HK, kFlexDirectionKTable, offsetof(nsStylePosition, mFlexDirection), @@ -1655,7 +1655,7 @@ CSS_PROP_POSITION( FlexGrow, CSS_PROPERTY_PARSE_VALUE | CSS_PROPERTY_VALUE_NONNEGATIVE, - "layout.css.flexbox.enabled", + "", // NOTE: The parsing implementation for the 'flex' shorthand property has // its own code to parse each subproperty. It does not depend on the // longhand parsing defined here. @@ -1669,7 +1669,7 @@ CSS_PROP_POSITION( FlexShrink, CSS_PROPERTY_PARSE_VALUE | CSS_PROPERTY_VALUE_NONNEGATIVE, - "layout.css.flexbox.enabled", + "", // NOTE: The parsing implementation for the 'flex' shorthand property has // its own code to parse each subproperty. It does not depend on the // longhand parsing defined here. @@ -1682,7 +1682,7 @@ CSS_PROP_POSITION( order, Order, CSS_PROPERTY_PARSE_VALUE, - "layout.css.flexbox.enabled", + "", VARIANT_HI, nullptr, offsetof(nsStylePosition, mOrder), @@ -1692,7 +1692,7 @@ CSS_PROP_POSITION( justify_content, JustifyContent, CSS_PROPERTY_PARSE_VALUE, - "layout.css.flexbox.enabled", + "", VARIANT_HK, kJustifyContentKTable, offsetof(nsStylePosition, mJustifyContent), diff --git a/layout/style/nsCSSProps.cpp b/layout/style/nsCSSProps.cpp index a893d010a557..35221d7dc9a8 100644 --- a/layout/style/nsCSSProps.cpp +++ b/layout/style/nsCSSProps.cpp @@ -929,7 +929,7 @@ const int32_t nsCSSProps::kDirectionKTable[] = { eCSSKeyword_UNKNOWN,-1 }; -int32_t nsCSSProps::kDisplayKTable[] = { +const int32_t nsCSSProps::kDisplayKTable[] = { eCSSKeyword_none, NS_STYLE_DISPLAY_NONE, eCSSKeyword_inline, NS_STYLE_DISPLAY_INLINE, eCSSKeyword_block, NS_STYLE_DISPLAY_BLOCK, @@ -960,7 +960,6 @@ int32_t nsCSSProps::kDisplayKTable[] = { eCSSKeyword__moz_popup, NS_STYLE_DISPLAY_POPUP, eCSSKeyword__moz_groupbox, NS_STYLE_DISPLAY_GROUPBOX, #endif - // The next two entries are controlled by the layout.css.flexbox.enabled pref. eCSSKeyword_flex, NS_STYLE_DISPLAY_FLEX, eCSSKeyword_inline_flex, NS_STYLE_DISPLAY_INLINE_FLEX, eCSSKeyword_UNKNOWN,-1 diff --git a/layout/style/nsCSSProps.h b/layout/style/nsCSSProps.h index 63004d6ba47a..bd1fda67631a 100644 --- a/layout/style/nsCSSProps.h +++ b/layout/style/nsCSSProps.h @@ -476,9 +476,7 @@ public: static const int32_t kContentKTable[]; static const int32_t kCursorKTable[]; static const int32_t kDirectionKTable[]; - // Not const because we modify its entries when the pref - // "layout.css.flexbox.enabled" changes: - static int32_t kDisplayKTable[]; + static const int32_t kDisplayKTable[]; static const int32_t kElevationKTable[]; static const int32_t kEmptyCellsKTable[]; static const int32_t kAlignItemsKTable[]; From 22a34fc8b5d089c7c29b066ffd08d6315bb0abf8 Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Sat, 9 Nov 2013 07:53:32 -0800 Subject: [PATCH 31/52] Bug 936100 part 6: Remove flexbox pref from all.js. r=mats --- modules/libpref/src/init/all.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index 716823270b25..f8a2bc6bd7af 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -1873,9 +1873,6 @@ pref("layout.css.supports-rule.enabled", true); // Is support for CSS Filters enabled? pref("layout.css.filters.enabled", false); -// Is support for CSS Flexbox enabled? -pref("layout.css.flexbox.enabled", true); - // Is support for CSS sticky positioning enabled? #ifdef RELEASE_BUILD pref("layout.css.sticky.enabled", false); From 1da990368c33badd3bcdf865904a91ae7f5f43bd Mon Sep 17 00:00:00 2001 From: Garrett Robinson Date: Fri, 8 Nov 2013 15:44:39 -0800 Subject: [PATCH 32/52] Bug 855326 - CSP 1.1 nonce-source for scripts and styles r=mrbkap r=dholbert r=geekboy --- caps/src/nsScriptSecurityManager.cpp | 3 +- .../base/public/nsIContentSecurityPolicy.idl | 33 +++- content/base/src/CSPUtils.jsm | 97 +++++++++--- content/base/src/contentSecurityPolicy.js | 68 +++++++- content/base/src/nsGkAtomList.h | 1 + content/base/src/nsScriptLoader.cpp | 46 ++++-- content/base/src/nsStyleLinkElement.cpp | 5 +- content/base/src/nsStyledElement.cpp | 2 +- content/base/test/csp/file_nonce_source.html | 67 ++++++++ .../test/csp/file_nonce_source.html^headers^ | 2 + content/base/test/csp/mochitest.ini | 3 + content/base/test/csp/test_nonce_source.html | 149 ++++++++++++++++++ content/events/src/nsEventListenerManager.cpp | 3 +- content/smil/nsSMILCSSValueType.cpp | 3 +- dom/base/nsJSTimeoutHandler.cpp | 2 +- dom/src/jsurl/nsJSProtocolHandler.cpp | 3 +- dom/workers/RuntimeService.cpp | 2 +- layout/style/nsStyleUtil.cpp | 60 +++++-- layout/style/nsStyleUtil.h | 29 +++- modules/libpref/src/init/all.js | 1 + security/manager/ssl/src/nsCrypto.cpp | 3 +- testing/mochitest/b2g.json | 1 + 22 files changed, 516 insertions(+), 67 deletions(-) create mode 100644 content/base/test/csp/file_nonce_source.html create mode 100644 content/base/test/csp/file_nonce_source.html^headers^ create mode 100644 content/base/test/csp/test_nonce_source.html diff --git a/caps/src/nsScriptSecurityManager.cpp b/caps/src/nsScriptSecurityManager.cpp index 63185dc446c6..4bf43b6d2917 100644 --- a/caps/src/nsScriptSecurityManager.cpp +++ b/caps/src/nsScriptSecurityManager.cpp @@ -489,7 +489,8 @@ nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx) csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL, fileName, scriptSample, - lineNum); + lineNum, + EmptyString()); } return evalOK; diff --git a/content/base/public/nsIContentSecurityPolicy.idl b/content/base/public/nsIContentSecurityPolicy.idl index 0c4259e09b98..c353efc00453 100644 --- a/content/base/public/nsIContentSecurityPolicy.idl +++ b/content/base/public/nsIContentSecurityPolicy.idl @@ -15,7 +15,7 @@ interface nsIDocShell; * one of these per document/principal. */ -[scriptable, uuid(e5020ec3-1437-46f5-b4eb-8b60766d02c0)] +[scriptable, uuid(781b6511-f1fa-4e2c-8eff-1739d091eb2f)] interface nsIContentSecurityPolicy : nsISupports { @@ -104,6 +104,24 @@ interface nsIContentSecurityPolicy : nsISupports */ boolean getAllowsInlineStyle(out boolean shouldReportViolations); + /** + * Whether this policy accepts the given nonce + * @param aNonce + * The nonce string to check against the policy + * @param aContentType + * The type of element on which we encountered this nonce + * @param shouldReportViolation + * Whether or not the use of an incorrect nonce should be reported. + * This function always returns "true" for report-only policies, but when + * the report-only policy is violated, shouldReportViolation is true as + * well. + * @return + * Whether or not this nonce is valid + */ + boolean getAllowsNonce(in AString aNonce, + in unsigned long aContentType, + out boolean shouldReportViolation); + /** * For each violated policy (of type violationType), log policy violation on * the Error Console and send a report to report-uris present in the violated @@ -117,15 +135,22 @@ interface nsIContentSecurityPolicy : nsISupports * sample of the violating content (to aid debugging) * @param lineNum * source line number of the violation (if available) + * @param aNonce + * (optional) If this is a nonce violation, include the nonce so we can + * recheck to determine which policies were violated and send the + * appropriate reports. */ void logViolationDetails(in unsigned short violationType, in AString sourceFile, in AString scriptSample, - in int32_t lineNum); + in int32_t lineNum, + [optional] in AString nonce); const unsigned short VIOLATION_TYPE_INLINE_SCRIPT = 1; - const unsigned short VIOLATION_TYPE_EVAL = 2; - const unsigned short VIOLATION_TYPE_INLINE_STYLE = 3; + const unsigned short VIOLATION_TYPE_EVAL = 2; + const unsigned short VIOLATION_TYPE_INLINE_STYLE = 3; + const unsigned short VIOLATION_TYPE_NONCE_SCRIPT = 4; + const unsigned short VIOLATION_TYPE_NONCE_STYLE = 5; /** * Called after the CSP object is created to fill in the appropriate request diff --git a/content/base/src/CSPUtils.jsm b/content/base/src/CSPUtils.jsm index a9898f8a3264..35c9761a0e88 100644 --- a/content/base/src/CSPUtils.jsm +++ b/content/base/src/CSPUtils.jsm @@ -24,7 +24,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "Services", // Module stuff this.EXPORTED_SYMBOLS = ["CSPRep", "CSPSourceList", "CSPSource", "CSPHost", - "CSPdebug", "CSPViolationReportListener", "CSPLocalizer"]; + "CSPdebug", "CSPViolationReportListener", "CSPLocalizer", + "CSPPrefObserver"]; var STRINGS_URI = "chrome://global/locale/security/csp.properties"; @@ -65,25 +66,37 @@ const R_EXTHOSTSRC = new RegExp ("^" + R_HOSTSRC.source + "\\/[:print:]+$", 'i') // keyword-source = "'self'" / "'unsafe-inline'" / "'unsafe-eval'" const R_KEYWORDSRC = new RegExp ("^('self'|'unsafe-inline'|'unsafe-eval')$", 'i'); +// nonce-source = "'nonce-" nonce-value "'" +// nonce-value = 1*( ALPHA / DIGIT / "+" / "/" ) +const R_NONCESRC = new RegExp ("^'nonce-([a-zA-Z0-9\+\/]+)'$", 'i'); + // source-exp = scheme-source / host-source / keyword-source const R_SOURCEEXP = new RegExp (R_SCHEMESRC.source + "|" + R_HOSTSRC.source + "|" + - R_KEYWORDSRC.source, 'i'); + R_KEYWORDSRC.source + "|" + + R_NONCESRC.source, 'i'); -var gPrefObserver = { +this.CSPPrefObserver = { get debugEnabled () { if (!this._branch) this._initialize(); return this._debugEnabled; }, + get experimentalEnabled () { + if (!this._branch) + this._initialize(); + return this._experimentalEnabled; + }, + _initialize: function() { var prefSvc = Components.classes["@mozilla.org/preferences-service;1"] .getService(Ci.nsIPrefService); this._branch = prefSvc.getBranch("security.csp."); this._branch.addObserver("", this, false); this._debugEnabled = this._branch.getBoolPref("debug"); + this._experimentalEnabled = this._branch.getBoolPref("experimentalEnabled"); }, unregister: function() { @@ -95,11 +108,13 @@ var gPrefObserver = { if (aTopic != "nsPref:changed") return; if (aData === "debug") this._debugEnabled = this._branch.getBoolPref("debug"); + if (aData === "experimentalEnabled") + this._experimentalEnabled = this._branch.getBoolPref("experimentalEnabled"); }, }; this.CSPdebug = function CSPdebug(aMsg) { - if (!gPrefObserver.debugEnabled) return; + if (!CSPPrefObserver.debugEnabled) return; aMsg = 'CSP debug: ' + aMsg + "\n"; Components.classes["@mozilla.org/consoleservice;1"] @@ -793,14 +808,28 @@ CSPRep.prototype = { /** * Determines if this policy accepts a URI. - * @param aContext + * @param aURI + * URI of the requested resource + * @param aDirective * one of the SRC_DIRECTIVES defined above + * @param aContext + * Context of the resource being requested. This is a type inheriting + * from nsIDOMHTMLElement if this is called from shouldLoad to check + * an external resource load, and refers to the HTML element that is + * causing the resource load. Otherwise, it is a string containing + * a nonce from a nonce="" attribute if it is called from + * getAllowsNonce. * @returns * true if the policy permits the URI in given context. */ permits: - function csp_permits(aURI, aContext) { - if (!aURI) return false; + function csp_permits(aURI, aDirective, aContext) { + // In the case where permits is called from getAllowsNonce (for an inline + // element), aURI is null and aContext has a specific value. Otherwise, + // calling permits without aURI is invalid. + let checking_nonce = aContext instanceof Ci.nsIDOMHTMLElement || + typeof aContext === 'string'; + if (!aURI && !checking_nonce) return false; // GLOBALLY ALLOW "about:" SCHEME if (aURI instanceof String && aURI.substring(0,6) === "about:") @@ -811,13 +840,13 @@ CSPRep.prototype = { // make sure the right directive set is used let DIRS = this._specCompliant ? CSPRep.SRC_DIRECTIVES_NEW : CSPRep.SRC_DIRECTIVES_OLD; - let contextIsSrcDir = false; + let directiveInPolicy = false; for (var i in DIRS) { - if (DIRS[i] === aContext) { + if (DIRS[i] === aDirective) { // for catching calls with invalid contexts (below) - contextIsSrcDir = true; - if (this._directives.hasOwnProperty(aContext)) { - return this._directives[aContext].permits(aURI); + directiveInPolicy = true; + if (this._directives.hasOwnProperty(aDirective)) { + return this._directives[aDirective].permits(aURI, aContext); } //found matching dir, can stop looking break; @@ -825,15 +854,15 @@ CSPRep.prototype = { } // frame-ancestors is a special case; it doesn't fall back to default-src. - if (aContext === DIRS.FRAME_ANCESTORS) + if (aDirective === DIRS.FRAME_ANCESTORS) return true; // All directives that don't fall back to default-src should have an escape // hatch above (like frame-ancestors). - if (!contextIsSrcDir) { + if (!directiveInPolicy) { // if this code runs, there's probably something calling permits() that // shouldn't be calling permits(). - CSPdebug("permits called with invalid load type: " + aContext); + CSPdebug("permits called with invalid load type: " + aDirective); return false; } @@ -842,7 +871,7 @@ CSPRep.prototype = { // indicates no relevant directives were present and the load should be // permitted). if (this._directives.hasOwnProperty(DIRS.DEFAULT_SRC)) { - return this._directives[DIRS.DEFAULT_SRC].permits(aURI); + return this._directives[DIRS.DEFAULT_SRC].permits(aURI, aContext); } // no relevant directives present -- this means for CSP 1.0 that the load @@ -1081,12 +1110,12 @@ CSPSourceList.prototype = { * true if the URI matches a source in this source list. */ permits: - function cspsd_permits(aURI) { + function cspsd_permits(aURI, aContext) { if (this.isNone()) return false; if (this.isAll()) return true; for (var i in this._sources) { - if (this._sources[i].permits(aURI)) { + if (this._sources[i].permits(aURI, aContext)) { return true; } } @@ -1102,6 +1131,7 @@ this.CSPSource = function CSPSource() { this._scheme = undefined; this._port = undefined; this._host = undefined; + this._nonce = undefined; //when set to true, this allows all source this._permitAll = false; @@ -1346,6 +1376,19 @@ CSPSource.fromString = function(aStr, aCSPRep, self, enforceSelfChecks) { return sObj; } + // check for a nonce-source match + if (R_NONCESRC.test(aStr)) { + // We can't put this check outside of the regex test because R_NONCESRC is + // included in R_SOURCEEXP, which is const. By testing here, we can + // explicitly return null for nonces if experimental is not enabled, + // instead of letting it fall through and assuming it won't accidentally + // match something later in this function. + if (!CSPPrefObserver.experimentalEnabled) return null; + var nonceSrcMatch = R_NONCESRC.exec(aStr); + sObj._nonce = nonceSrcMatch[1]; + return sObj; + } + // check for 'self' (case insensitive) if (aStr.toUpperCase() === "'SELF'") { if (!self) { @@ -1450,6 +1493,8 @@ CSPSource.prototype = { s = s + this._host; if (this.port) s = s + ":" + this.port; + if (this._nonce) + s = s + "'nonce-" + this._nonce + "'"; return s; }, @@ -1465,6 +1510,7 @@ CSPSource.prototype = { aClone._scheme = this._scheme; aClone._port = this._port; aClone._host = this._host ? this._host.clone() : undefined; + aClone._nonce = this._nonce; aClone._isSelf = this._isSelf; aClone._CSPRep = this._CSPRep; return aClone; @@ -1474,11 +1520,24 @@ CSPSource.prototype = { * Determines if this Source accepts a URI. * @param aSource * the URI, or CSPSource in question + * @param aContext + * the context of the resource being loaded * @returns * true if the URI matches a source in this source list. */ permits: - function(aSource) { + function(aSource, aContext) { + if (this._nonce && CSPPrefObserver.experimentalEnabled) { + if (aContext instanceof Ci.nsIDOMHTMLElement) { + return this._nonce === aContext.getAttribute('nonce'); + } else if (typeof aContext === 'string') { + return this._nonce === aContext; + } + } + // We only use aContext for nonce checks. If it's otherwise provided, + // ignore it. + if (!CSPPrefObserver.experimentalEnabled && aContext) return false; + if (!aSource) return false; if (!(aSource instanceof CSPSource)) diff --git a/content/base/src/contentSecurityPolicy.js b/content/base/src/contentSecurityPolicy.js index 06cf4b69beca..f5be9abe93c7 100644 --- a/content/base/src/contentSecurityPolicy.js +++ b/content/base/src/contentSecurityPolicy.js @@ -31,6 +31,8 @@ const ERROR_FLAG = Ci.nsIScriptError.ERROR_FLAG; const INLINE_STYLE_VIOLATION_OBSERVER_SUBJECT = 'violated base restriction: Inline Stylesheets will not apply'; const INLINE_SCRIPT_VIOLATION_OBSERVER_SUBJECT = 'violated base restriction: Inline Scripts will not execute'; const EVAL_VIOLATION_OBSERVER_SUBJECT = 'violated base restriction: Code will not be created from strings'; +const SCRIPT_NONCE_VIOLATION_OBSERVER_SUBJECT = 'Inline Script had invalid nonce' +const STYLE_NONCE_VIOLATION_OBSERVER_SUBJECT = 'Inline Style had invalid nonce' // The cutoff length of content location in creating CSP cache key. const CSP_CACHE_URI_CUTOFF_SIZE = 512; @@ -189,6 +191,28 @@ ContentSecurityPolicy.prototype = { }); }, + getAllowsNonce: function(aNonce, aContentType, shouldReportViolation) { + if (!CSPPrefObserver.experimentalEnabled) + return false; + + if (!(aContentType == Ci.nsIContentPolicy.TYPE_SCRIPT || + aContentType == Ci.nsIContentPolicy.TYPE_STYLESHEET)) { + CSPdebug("Nonce check requested for an invalid content type (not script or style): " + aContentType); + return false; + } + let ct = ContentSecurityPolicy._MAPPINGS[aContentType]; + + // allow it to execute? + let policyAllowsNonce = [ policy.permits(null, ct, aNonce) for (policy of this._policies) ]; + + shouldReportViolation.value = policyAllowsNonce.some(function(a) { return !a; }); + + // allow it to execute? (Do all the policies allow it to execute)? + return this._policies.every(function(policy, i) { + return policy._reportOnlyMode || policyAllowsNonce[i]; + }); + }, + /** * For each policy, log any violation on the Error Console and send a report * if a report-uri is present in the policy @@ -201,9 +225,13 @@ ContentSecurityPolicy.prototype = { * sample of the violating content (to aid debugging) * @param aLineNum * source line number of the violation (if available) + * @param aNonce + * (optional) If this is a nonce violation, include the nonce should we + * can recheck to determine which policies were violated and send the + * appropriate reports. */ logViolationDetails: - function(aViolationType, aSourceFile, aScriptSample, aLineNum, violatedPolicyIndex) { + function(aViolationType, aSourceFile, aScriptSample, aLineNum, aNonce) { for (let policyIndex=0; policyIndex < this._policies.length; policyIndex++) { let policy = this._policies[policyIndex]; @@ -237,6 +265,24 @@ ContentSecurityPolicy.prototype = { aSourceFile, aScriptSample, aLineNum); } break; + case Ci.nsIContentSecurityPolicy.VIOLATION_TYPE_NONCE_SCRIPT: + let scriptType = ContentSecurityPolicy._MAPPINGS[Ci.nsIContentPolicy.TYPE_SCRIPT]; + if (!policy.permits(null, scriptType, aNonce)) { + var violatedDirective = this._buildViolatedDirectiveString('SCRIPT_SRC', policy); + this._asyncReportViolation('self', null, violatedDirective, policyIndex, + SCRIPT_NONCE_VIOLATION_OBSERVER_SUBJECT, + aSourceFile, aScriptSample, aLineNum); + } + break; + case Ci.nsIContentSecurityPolicy.VIOLATION_TYPE_NONCE_STYLE: + let styleType = ContentSecurityPolicy._MAPPINGS[Ci.nsIContentPolicy.TYPE_STYLE]; + if (!policy.permits(null, styleType, aNonce)) { + var violatedDirective = this._buildViolatedDirectiveString('STYLE_SRC', policy); + this._asyncReportViolation('self', null, violatedDirective, policyIndex, + STYLE_NONCE_VIOLATION_OBSERVER_SUBJECT, + aSourceFile, aScriptSample, aLineNum); + } + break; } } }, @@ -628,6 +674,14 @@ ContentSecurityPolicy.prototype = { let cp = Ci.nsIContentPolicy; + // Infer if this is a preload for elements that use nonce-source. Since, + // for preloads, aContext is the document and not the element associated + // with the resource, we cannot determine the nonce. See Bug 612921 and + // Bug 855326. + var possiblePreloadNonceConflict = + (aContentType == cp.TYPE_SCRIPT || aContentType == cp.TYPE_STYLESHEET) && + aContext instanceof Ci.nsIDOMHTMLDocument; + // iterate through all the _policies and send reports where a policy is // violated. After the check, determine the overall effect (blocked or // loaded?) and cache it. @@ -661,15 +715,18 @@ ContentSecurityPolicy.prototype = { // otherwise, honor the translation // var source = aContentLocation.scheme + "://" + aContentLocation.hostPort; - var res = policy.permits(aContentLocation, cspContext) - ? cp.ACCEPT : cp.REJECT_SERVER; + let context = CSPPrefObserver.experimentalEnabled ? aContext : null; + var res = policy.permits(aContentLocation, cspContext, context) ? + cp.ACCEPT : cp.REJECT_SERVER; // record whether the thing should be blocked or just reported. policyAllowsLoadArray.push(res == cp.ACCEPT || policy._reportOnlyMode); // frame-ancestors is taken care of early on (as this document is loaded) // If the result is *NOT* ACCEPT, then send report - if (res != Ci.nsIContentPolicy.ACCEPT) { + // Do not send report if this is a nonce-source preload - the decision may + // be wrong and will incorrectly fail the unit tests. + if (res != Ci.nsIContentPolicy.ACCEPT && !possiblePreloadNonceConflict) { CSPdebug("blocking request for " + aContentLocation.asciiSpec); try { let directive = "unknown directive", @@ -704,7 +761,8 @@ ContentSecurityPolicy.prototype = { let ret = (policyAllowsLoadArray.some(function(a,b) { return !a; }) ? cp.REJECT_SERVER : cp.ACCEPT); - if (key) { + // Do not cache the result if this is a nonce-source preload + if (key && !possiblePreloadNonceConflict) { this._cache[key] = ret; } return ret; diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h index ad96f8ccfc42..b8f1eb7f9055 100644 --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -608,6 +608,7 @@ GK_ATOM(nodeSet, "node-set") GK_ATOM(noembed, "noembed") GK_ATOM(noframes, "noframes") GK_ATOM(nohref, "nohref") +GK_ATOM(nonce, "nonce") GK_ATOM(none, "none") GK_ATOM(noresize, "noresize") GK_ATOM(normal, "normal") diff --git a/content/base/src/nsScriptLoader.cpp b/content/base/src/nsScriptLoader.cpp index 3b26af68f12e..4d92be0b33bf 100644 --- a/content/base/src/nsScriptLoader.cpp +++ b/content/base/src/nsScriptLoader.cpp @@ -624,13 +624,31 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) NS_ENSURE_SUCCESS(rv, false); if (csp) { - PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("New ScriptLoader i ****with CSP****")); - bool inlineOK = true; - bool reportViolations = false; - rv = csp->GetAllowsInlineScript(&reportViolations, &inlineOK); + PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("New ScriptLoader ****with CSP****")); + + bool reportViolation = false; + bool allowInlineScript = true; + rv = csp->GetAllowsInlineScript(&reportViolation, &allowInlineScript); NS_ENSURE_SUCCESS(rv, false); - if (reportViolations) { + bool foundNonce = false; + nsAutoString nonce; + if (!allowInlineScript) { + foundNonce = scriptContent->GetAttr(kNameSpaceID_None, nsGkAtoms::nonce, nonce); + if (foundNonce) { + // We can overwrite the outparams from GetAllowsInlineScript because + // if the nonce is correct, then we don't want to report the original + // inline violation (it has been whitelisted by the nonce), and if + // the nonce is incorrect, then we want to return just the specific + // "nonce violation" rather than both a "nonce violation" and + // a generic "inline violation". + rv = csp->GetAllowsNonce(nonce, nsIContentPolicy::TYPE_SCRIPT, + &reportViolation, &allowInlineScript); + NS_ENSURE_SUCCESS(rv, false); + } + } + + if (reportViolation) { // gather information to log with violation report nsIURI* uri = mDocument->GetDocumentURI(); nsAutoCString asciiSpec; @@ -641,17 +659,21 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) // cap the length of the script sample at 40 chars if (scriptText.Length() > 40) { scriptText.Truncate(40); - scriptText.Append(NS_LITERAL_STRING("...")); + scriptText.AppendLiteral("..."); } - csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_SCRIPT, - NS_ConvertUTF8toUTF16(asciiSpec), - scriptText, - aElement->GetScriptLineNumber()); + // The type of violation to report is determined by whether there was + // a nonce present. + unsigned short violationType = foundNonce ? + nsIContentSecurityPolicy::VIOLATION_TYPE_NONCE_SCRIPT : + nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_SCRIPT; + csp->LogViolationDetails(violationType, NS_ConvertUTF8toUTF16(asciiSpec), + scriptText, aElement->GetScriptLineNumber(), nonce); } - if (!inlineOK) { - PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("CSP blocked inline scripts (2)")); + if (!allowInlineScript) { + NS_ASSERTION(reportViolation, + "CSP blocked inline script but is not reporting a violation"); return false; } } diff --git a/content/base/src/nsStyleLinkElement.cpp b/content/base/src/nsStyleLinkElement.cpp index 808f6124385c..b560237840db 100644 --- a/content/base/src/nsStyleLinkElement.cpp +++ b/content/base/src/nsStyleLinkElement.cpp @@ -360,7 +360,10 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument *aOldDocument, nsAutoString text; nsContentUtils::GetNodeTextContent(thisContent, false, text); - if (!nsStyleUtil::CSPAllowsInlineStyle(thisContent->NodePrincipal(), + MOZ_ASSERT(thisContent->Tag() != nsGkAtoms::link, + " is not 'inline', and needs different CSP checks"); + if (!nsStyleUtil::CSPAllowsInlineStyle(thisContent, + thisContent->NodePrincipal(), doc->GetDocumentURI(), mLineNumber, text, &rv)) return rv; diff --git a/content/base/src/nsStyledElement.cpp b/content/base/src/nsStyledElement.cpp index a60887185a57..5b5c91fc73e5 100644 --- a/content/base/src/nsStyledElement.cpp +++ b/content/base/src/nsStyledElement.cpp @@ -236,7 +236,7 @@ nsStyledElementNotElementCSSInlineStyle::ParseStyleAttribute(const nsAString& aV { nsIDocument* doc = OwnerDoc(); - if (!nsStyleUtil::CSPAllowsInlineStyle(NodePrincipal(), + if (!nsStyleUtil::CSPAllowsInlineStyle(nullptr, NodePrincipal(), doc->GetDocumentURI(), 0, aValue, nullptr)) return; diff --git a/content/base/test/csp/file_nonce_source.html b/content/base/test/csp/file_nonce_source.html new file mode 100644 index 000000000000..e146467448ce --- /dev/null +++ b/content/base/test/csp/file_nonce_source.html @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
  1. + (inline style with correct nonce) This text should be green +
  2. +
  3. + (inline style with incorrect nonce) This text should be black +
  4. +
  5. + (inline style with correct script, not style, nonce) This text should be black +
  6. +
  7. + (inline style with no nonce) This text should be black +
  8. +
+ + + + + + diff --git a/content/base/test/csp/file_nonce_source.html^headers^ b/content/base/test/csp/file_nonce_source.html^headers^ new file mode 100644 index 000000000000..865e5fe98439 --- /dev/null +++ b/content/base/test/csp/file_nonce_source.html^headers^ @@ -0,0 +1,2 @@ +Content-Security-Policy: script-src 'self' 'nonce-correctscriptnonce' 'nonce-anothercorrectscriptnonce'; style-src 'nonce-correctstylenonce'; +Cache-Control: no-cache diff --git a/content/base/test/csp/mochitest.ini b/content/base/test/csp/mochitest.ini index b0634e0c3afd..42b7767a1b7a 100644 --- a/content/base/test/csp/mochitest.ini +++ b/content/base/test/csp/mochitest.ini @@ -85,6 +85,8 @@ support-files = file_policyuri_regression_from_multipolicy.html file_policyuri_regression_from_multipolicy.html^headers^ file_policyuri_regression_from_multipolicy_policy + file_nonce_source.html + file_nonce_source.html^headers^ [test_CSP.html] [test_CSP_bug663567.html] @@ -103,3 +105,4 @@ support-files = [test_CSP_bug910139.html] [test_CSP_bug909029.html] [test_policyuri_regression_from_multipolicy.html] +[test_nonce_source.html] diff --git a/content/base/test/csp/test_nonce_source.html b/content/base/test/csp/test_nonce_source.html new file mode 100644 index 000000000000..e5d47453d8f1 --- /dev/null +++ b/content/base/test/csp/test_nonce_source.html @@ -0,0 +1,149 @@ + + + + Test CSP 1.1 nonce-source for scripts and styles + + + + + +

+ + +
+ + diff --git a/content/events/src/nsEventListenerManager.cpp b/content/events/src/nsEventListenerManager.cpp index 17b2fd2d583d..3cc88c88c239 100644 --- a/content/events/src/nsEventListenerManager.cpp +++ b/content/events/src/nsEventListenerManager.cpp @@ -729,7 +729,8 @@ nsEventListenerManager::SetEventHandler(nsIAtom *aName, csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_SCRIPT, NS_ConvertUTF8toUTF16(asciiSpec), scriptSample, - 0); + 0, + EmptyString()); } // return early if CSP wants us to block inline scripts diff --git a/content/smil/nsSMILCSSValueType.cpp b/content/smil/nsSMILCSSValueType.cpp index a09067d71062..7a0636faf7d4 100644 --- a/content/smil/nsSMILCSSValueType.cpp +++ b/content/smil/nsSMILCSSValueType.cpp @@ -394,7 +394,8 @@ nsSMILCSSValueType::ValueFromString(nsCSSProperty aPropID, } nsIDocument* doc = aTargetElement->GetCurrentDoc(); - if (doc && !nsStyleUtil::CSPAllowsInlineStyle(doc->NodePrincipal(), + if (doc && !nsStyleUtil::CSPAllowsInlineStyle(nullptr, + doc->NodePrincipal(), doc->GetDocumentURI(), 0, aString, nullptr)) { return; diff --git a/dom/base/nsJSTimeoutHandler.cpp b/dom/base/nsJSTimeoutHandler.cpp index 3cc8311999fb..154d0ae6e1ed 100644 --- a/dom/base/nsJSTimeoutHandler.cpp +++ b/dom/base/nsJSTimeoutHandler.cpp @@ -181,7 +181,7 @@ CheckCSPForEval(JSContext* aCx, nsGlobalWindow* aWindow, ErrorResult& aError) } csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL, - fileNameString, scriptSample, lineNum); + fileNameString, scriptSample, lineNum, EmptyString()); } return allowsEval; diff --git a/dom/src/jsurl/nsJSProtocolHandler.cpp b/dom/src/jsurl/nsJSProtocolHandler.cpp index 453b37511b54..6fb55a490ca5 100644 --- a/dom/src/jsurl/nsJSProtocolHandler.cpp +++ b/dom/src/jsurl/nsJSProtocolHandler.cpp @@ -179,7 +179,8 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel, csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_SCRIPT, NS_ConvertUTF8toUTF16(asciiSpec), NS_ConvertUTF8toUTF16(mURL), - 0); + 0, + EmptyString()); } //return early if inline scripts are not allowed diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index d6dbd2c1d574..df477c6af9a0 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -707,7 +707,7 @@ public: "Call to eval() or related function blocked by CSP."); if (mWorkerPrivate->GetReportCSPViolations()) { csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL, - mFileName, scriptSample, mLineNum); + mFileName, scriptSample, mLineNum, EmptyString()); } } diff --git a/layout/style/nsStyleUtil.cpp b/layout/style/nsStyleUtil.cpp index f2f3532dd1da..925b8b71a2aa 100644 --- a/layout/style/nsStyleUtil.cpp +++ b/layout/style/nsStyleUtil.cpp @@ -10,6 +10,7 @@ #include "nsCSSProps.h" #include "nsRuleNode.h" #include "nsROCSSPrimitiveValue.h" +#include "nsIContentPolicy.h" #include "nsIContentSecurityPolicy.h" #include "nsIURI.h" @@ -441,7 +442,8 @@ nsStyleUtil::IsSignificantChild(nsIContent* aChild, bool aTextIsSignificant, } /* static */ bool -nsStyleUtil::CSPAllowsInlineStyle(nsIPrincipal* aPrincipal, +nsStyleUtil::CSPAllowsInlineStyle(nsIContent* aContent, + nsIPrincipal* aPrincipal, nsIURI* aSourceURI, uint32_t aLineNumber, const nsSubstring& aStyleText, @@ -453,6 +455,10 @@ nsStyleUtil::CSPAllowsInlineStyle(nsIPrincipal* aPrincipal, *aRv = NS_OK; } + MOZ_ASSERT(!aContent || aContent->Tag() == nsGkAtoms::style, + "aContent passed to CSPAllowsInlineStyle " + "for an element that is not