Merge m-c to fx-team
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 28 Nov 2013 14:35:04 +0100
changeset 158051 9edf20552d79e2bc4e7a281f8839fa85bdaaac9c
parent 158050 e95f769be558d11f00ff51f6240102522c050511 (current diff)
parent 157964 3ccec665a6aa1a0a44a12f42c144aa9fcda3dadf (diff)
child 158052 662e8032dccec26c23af53aaa6883178f27e4cc0
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
milestone28.0a1
Merge m-c to fx-team
b2g/chrome/Makefile.in
browser/base/Makefile.in
browser/components/migration/src/Makefile.in
browser/components/preferences/Makefile.in
browser/components/preferences/in-content/Makefile.in
browser/metro/base/Makefile.in
browser/modules/Makefile.in
content/canvas/src/WebGLMemoryReporterWrapper.h
gfx/ots/src/Makefile.in
js/src/editline/Makefile.in
media/mtransport/build/Makefile.in
media/mtransport/standalone/Makefile.in
mobile/android/chrome/Makefile.in
mobile/android/components/Makefile.in
netwerk/base/public/Makefile.in
parser/expat/lib/Makefile.in
security/manager/ssl/src/Makefile.in
testing/marionette/Makefile.in
testing/marionette/components/Makefile.in
toolkit/components/search/Makefile.in
toolkit/modules/Makefile.in
toolkit/webapps/Makefile.in
xulrunner/setup/Makefile.in
new file mode 100644
--- /dev/null
+++ b/.reviewboardrc
@@ -0,0 +1,5 @@
+# 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/.
+
+REVIEWBOARD_URL = 'https://reviewboard.allizom.org/'
--- a/accessible/public/ia2/Makefile.in
+++ b/accessible/public/ia2/Makefile.in
@@ -1,18 +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/.
 
 DEFFILE       = $(win_srcdir)/IA2Marshal.def
 
 IA2DIR        = $(topsrcdir)/other-licenses/ia2
 
-DEFINES       += -DREGISTER_PROXY_DLL
-
 GARBAGE       += $(MIDL_GENERATED_FILES)
 
 # Please keep this list in sync with the moz.build file until the rest of this
 # Makefile is ported over.
 MIDL_INTERFACES = \
   Accessible2.idl \
   Accessible2_2.idl \
   AccessibleAction.idl \
--- a/accessible/public/ia2/moz.build
+++ b/accessible/public/ia2/moz.build
@@ -2,8 +2,10 @@
 # vim: set filetype=python:
 # 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/.
 
 LIBRARY_NAME = 'IA2Marshal'
 
 FORCE_SHARED_LIB = True
+
+DEFINES['REGISTER_PROXY_DLL'] = True
--- a/accessible/public/msaa/Makefile.in
+++ b/accessible/public/msaa/Makefile.in
@@ -1,16 +1,14 @@
 # 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/.
 
 DEFFILE = $(win_srcdir)/AccessibleMarshal.def
 
-DEFINES += -DREGISTER_PROXY_DLL
-
 GARBAGE += $(MIDL_GENERATED_FILES) done_gen dlldata.c
 
 MIDL_GENERATED_FILES = \
 	ISimpleDOMNode.h \
 	ISimpleDOMNode_p.c \
 	ISimpleDOMNode_i.c \
 	ISimpleDOMDocument.h \
 	ISimpleDOMDocument_p.c \
--- a/accessible/public/msaa/moz.build
+++ b/accessible/public/msaa/moz.build
@@ -12,8 +12,10 @@ GENERATED_SOURCES += [
     'ISimpleDOMDocument_p.c',
     'ISimpleDOMNode_i.c',
     'ISimpleDOMNode_p.c',
     'ISimpleDOMText_i.c',
     'ISimpleDOMText_p.c',
 ]
 
 FORCE_SHARED_LIB = True
+
+DEFINES['REGISTER_PROXY_DLL'] = True
--- a/accessible/tests/mochitest/jsat/a11y.ini
+++ b/accessible/tests/mochitest/jsat/a11y.ini
@@ -1,12 +1,14 @@
 [DEFAULT]
 support-files =
   jsatcommon.js
   output.js
+  doc_traversal.html
 
 [test_alive.html]
 [test_braille.html]
 [test_explicit_names.html]
 [test_landmarks.html]
 [test_live_regions.html]
 [test_tables.html]
+[test_traversal.html]
 [test_utterance_order.html]
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/jsat/doc_traversal.html
@@ -0,0 +1,117 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Traversal Rule test document</title>
+  <meta charset="utf-8" />
+</head>
+<body>
+  <h3 id="heading-1">A small first heading</h3>
+  <form>
+    <label for="input-1-1">Name:</label>
+    <input id="input-1-1">
+    <label id="label-1-2">Favourite Ice Cream Flavour:<input id="input-1-2"></label>
+    <button id="button-1-1">Magic Button</button>
+    <label for="radio-1-1">Radios are old: </label>
+    <input id="radio-1-1" type="radio">
+    <label for="radio-1-2">Radios are new: </label>
+    <input id="radio-1-2" type="radio">
+    <label for="input-1-3">Password:</label>
+    <input id="input-1-3" type="password">
+    <label for="input-1-4">Unlucky number:</label>
+    <input id="input-1-4" type="tel">
+    <input id="button-1-2" type="button" value="Fun">
+    <label for="checkbox-1-1">Check me: </label>
+    <input id="checkbox-1-1" type="checkbox">
+    <select id="select-1-1">
+      <option>Value 1</option>
+      <option>Value 2</option>
+      <option>Value 3</option>
+    </select>
+    <select id="select-1-2" multiple="true">
+      <option>Value 1</option>
+      <option>Value 2</option>
+      <option>Value 3</option>
+    </select>
+    <label for="checkbox-1-2">Check me too: </label>
+    <input id="checkbox-1-2" type="checkbox">
+    <label for="checkbox-1-3">But not me: </label>
+    <input id="checkbox-1-3" type="checkbox" aria-hidden="true">
+    <label for="checkbox-1-4">Or me! </label>
+    <input id="checkbox-1-3" type="checkbox" style="visibility:hidden">
+    <select id="select-1-3" size="3">
+      <option>Value 1</option>
+      <option>Value 2</option>
+      <option>Value 3</option>
+    </select>
+    <label for="input-1-5">Electronic mailing address:</label>
+    <input id="input-1-5" type="email">
+    <input id="button-1-3" type="submit" value="Submit">
+
+  </form>
+  <h2 id="heading-2">A larger second</h2>
+  <div id="heading-3" role="heading">ARIA is fun</div>
+  <input id="button-2-1" type="button" value="More Fun">
+  <div id="button-2-2" tabindex="0" role="button">ARIA fun</div>
+  <div id="button-2-3" tabindex="0" role="button" aria-pressed="false">My little togglebutton</div>
+  <div id="button-2-4" tabindex="0" role="spinbutton">ARIA fun</div>
+  <h1 id="heading-4" style="display:none">Invisible header</h1>
+  <dl id="list-1">
+    <dt id="listitem-1-1">Programming Language</dt>
+    <dd>A esoteric weapon wielded by only the most formidable warriors,
+    for its unrelenting strict power is unfathomable.</dd>
+  </dl>
+  <ul id="list-2">
+    <li id="listitem-2-1">Lists of Programming Languages</li>
+    <li id="listitem-2-2">Lisp
+      <ol id="list-3">
+        <li id="listitem-3-1">Scheme</li>
+        <li id="listitem-3-2">Racket</li>
+        <li id="listitem-3-3">Clojure</li>
+      </ol>
+    </li>
+    <li id="listitem-2-3">JavaScript</li>
+  </ul>
+  <h6 id="heading-5">The last (visible) one!</h6>
+  <img id="image-1" src="http://example.com" alt="">
+  <img id="image-2" src="../moz.png" alt="stuff">
+  <div id="image-3" tabindex="0" role="img">Not actually an image</div>
+  <h4 id="heading-6" aria-hidden="true">Hidden header</h4>
+  <a id="link-1" href="http://www.mozilla.org">Link</a>
+  <a id="anchor-1">Words</a>
+  <a id="link-2" href="http://www.mozilla.org">Link the second</a>
+  <a id="anchor-2">Sentences</a>
+  <a id="link-3" href="http://www.example.com">Link the third</a>
+  <hr id="separator-1">
+  <table id="table-1">
+  <tr>
+    <td>3</td>
+    <td>1</td>
+  </tr>
+  <tr>
+    <td>4</td>
+    <td>1</td>
+  </tr>
+  </table>
+  <div id="separator-2" role="separator">Just an innocuous separator</div>
+  <table id="table-2">
+    <thead>
+      <tr>
+        <th>Dirty Words</th>
+        <th>Meaning</th>
+      </tr>
+    </thead>
+    <tfoot>
+      <tr>
+        <td>Mud</td>
+        <td>Wet Dirt</td>
+      </tr>
+    </tfoot>
+    <tbody>
+      <tr>
+        <td>Dirt</td>
+        <td>Messy Stuff</td>
+      </tr>
+    </tbody>
+  </table>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/jsat/test_traversal.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Tests AccessFu TraversalRules</title>
+  <meta charset="utf-8" />
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js">
+  </script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/chrome-harness.js">
+  </script>
+
+  <script type="application/javascript" src="../common.js"></script>
+  <script type="application/javascript" src="../browser.js"></script>
+  <script type="application/javascript" src="../events.js"></script>
+  <script type="application/javascript" src="../role.js"></script>
+  <script type="application/javascript" src="../states.js"></script>
+  <script type="application/javascript" src="../pivot.js"></script>
+  <script type="application/javascript" src="../layout.js"></script>
+
+  <script type="application/javascript">
+    Components.utils.import("resource://gre/modules/accessibility/TraversalRules.jsm");
+    var gBrowserWnd = null;
+    var gQueue = null;
+
+    function doTest()
+    {
+      var doc = currentTabDocument();
+      var docAcc = getAccessible(doc, [nsIAccessibleDocument]);
+
+      gQueue = new eventQueue();
+
+      gQueue.onFinish = function onFinish()
+      {
+        closeBrowserWindow();
+      }
+
+      queueTraversalSequence(gQueue, docAcc, TraversalRules.Heading, null,
+                             ['heading-1', 'heading-2', 'heading-3', 'heading-5']);
+
+      queueTraversalSequence(gQueue, docAcc, TraversalRules.Entry, null,
+                             ['input-1-1', 'label-1-2', 'input-1-3',
+                              'input-1-4', 'input-1-5']);
+
+      // move back an element to hit all the form elements, because the VC is
+      // currently at the first input element
+      gQueue.push(new setVCPosInvoker(docAcc, "movePrevious",
+                                      TraversalRules.Heading, "heading-1"));
+
+      queueTraversalSequence(gQueue, docAcc, TraversalRules.FormElement, null,
+                             ['input-1-1', 'label-1-2', 'button-1-1',
+                              'radio-1-1', 'radio-1-2', 'input-1-3',
+                              'input-1-4', 'button-1-2', 'checkbox-1-1',
+                              'select-1-1', 'select-1-2', 'checkbox-1-2',
+                              'select-1-3', 'input-1-5', 'button-1-3',
+                              'button-2-1', 'button-2-2', 'button-2-3',
+                              'button-2-4']);
+
+      queueTraversalSequence(gQueue, docAcc, TraversalRules.Button, null,
+                             ['button-1-1', 'button-1-2', 'button-1-3',
+                              'button-2-1', 'button-2-2', 'button-2-3',
+                              'button-2-4']);
+
+      queueTraversalSequence(gQueue, docAcc, TraversalRules.RadioButton, null,
+                             ['radio-1-1', 'radio-1-2']);
+
+      queueTraversalSequence(gQueue, docAcc, TraversalRules.Checkbox, null,
+                             ['checkbox-1-1', 'checkbox-1-2']);
+
+      queueTraversalSequence(gQueue, docAcc, TraversalRules.Combobox, null,
+                             ['select-1-1', 'select-1-2', 'select-1-3']);
+
+      queueTraversalSequence(gQueue, docAcc, TraversalRules.List, null,
+                             ['list-1', 'list-2', 'list-3']);
+
+      queueTraversalSequence(gQueue, docAcc, TraversalRules.ListItem, null,
+                             ['listitem-1-1', 'listitem-2-1', 'listitem-2-2',
+                              'listitem-3-1', 'listitem-3-2', 'listitem-3-3',
+                              'listitem-2-3']);
+
+      queueTraversalSequence(gQueue, docAcc, TraversalRules.Graphic, null,
+                             ['image-2', 'image-3']);
+
+      queueTraversalSequence(gQueue, docAcc, TraversalRules.Link, null,
+                             ['link-1', 'link-2', 'link-3']);
+
+      queueTraversalSequence(gQueue, docAcc, TraversalRules.Anchor, null,
+                             ['anchor-1', 'anchor-2']);
+
+      queueTraversalSequence(gQueue, docAcc, TraversalRules.Separator, null,
+                             ['separator-1', 'separator-2']);
+
+      queueTraversalSequence(gQueue, docAcc, TraversalRules.Table, null,
+                             ['table-1', 'table-2']);
+
+      gQueue.invoke();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addLoadEvent(function () {
+      /* We open a new browser because we need to test with a top-level content
+         document. */
+      openBrowserWindow(
+        doTest,
+        getRootDirectory(window.location.href) + "doc_traversal.html");
+    });
+  </script>
+</head>
+<body id="body">
+
+  <a target="_blank"
+     title="Add tests for AccessFu TraversalRules"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=933808">Mozilla Bug 933808</a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+</body>
+</html>
--- a/b2g/app/Makefile.in
+++ b/b2g/app/Makefile.in
@@ -2,20 +2,16 @@
 # 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/.
 
 USE_RCS_MK := 1
 include $(topsrcdir)/config/makefiles/rcs.mk
 
 PREF_JS_EXPORTS = $(srcdir)/b2g.js
 
-ifdef ENABLE_MARIONETTE
-DEFINES += -DENABLE_MARIONETTE=1
-endif
-
 ifndef LIBXUL_SDK
 
 ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 LIBS += \
   -lui \
   -lEGL \
   -lhardware_legacy \
   -lhardware \
@@ -34,17 +30,16 @@ OS_LDFLAGS += -Wl,--export-dynamic
 LOCAL_INCLUDES += -I$(topsrcdir)/widget/gonk/libdisplay
 endif
 
 LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
 LOCAL_INCLUDES += -I$(topsrcdir)/xpcom/base
 LOCAL_INCLUDES += -I$(topsrcdir)/xpcom/build
 LOCAL_INCLUDES += -I$(DEPTH)/build
 
-DEFINES += -DXPCOM_GLUE
 STL_FLAGS=
 
 LIBS += $(JEMALLOC_LIBS)
 
 LIBS += \
   $(XPCOM_STANDALONE_GLUE_LDOPTS) \
   $(NULL)
 
@@ -78,22 +73,16 @@ INSTALL_TARGETS += UA_UPDATE
 
 # Make sure the standalone glue doesn't try to get libxpcom.so from b2g/app.
 NSDISTMODE = copy
 
 include $(topsrcdir)/config/rules.mk
 
 APP_ICON = b2g
 
-DEFINES += \
-  -DAPP_NAME=$(MOZ_APP_NAME) \
-  -DAPP_VERSION=$(MOZ_APP_VERSION) \
-  -DMOZ_UPDATER=$(MOZ_UPDATER) \
-  $(NULL)
-
 source_repo ?= $(call getSourceRepo,$(srcdir)/..)
 ifneq (,$(filter http%,$(source_repo)))
   DEFINES += -DMOZ_SOURCE_REPO="$(source_repo)"
 endif
 
 ifeq ($(OS_ARCH),WINNT)
 REDIT_PATH = $(LIBXUL_DIST)/bin
 endif
--- a/b2g/app/moz.build
+++ b/b2g/app/moz.build
@@ -7,8 +7,16 @@
 if not CONFIG['LIBXUL_SDK']:
     if CONFIG['GAIADIR']:
         PROGRAM = CONFIG['MOZ_APP_NAME'] + "-bin"
     else:
         PROGRAM = CONFIG['MOZ_APP_NAME']
     SOURCES += [
         'nsBrowserApp.cpp',
     ]
+
+if CONFIG['ENABLE_MARIONETTE']:
+    DEFINES['ENABLE_MARIONETTE'] = 1
+
+DEFINES['XPCOM_GLUE'] = True
+
+for var in ('MOZ_APP_NAME', 'MOZ_APP_VERSION', 'MOZ_UPDATER'):
+    DEFINES[var] = CONFIG[var]
deleted file mode 100644
--- a/b2g/chrome/Makefile.in
+++ /dev/null
@@ -1,8 +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/.
-
-DEFINES += -DAB_CD=$(MOZ_UI_LOCALE) \
-           -DPACKAGE=browser \
-           -DMOZ_APP_VERSION=$(MOZ_APP_VERSION) \
-           $(NULL)
--- a/b2g/chrome/moz.build
+++ b/b2g/chrome/moz.build
@@ -1,6 +1,9 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
+DEFINES['AB_CD'] = CONFIG['MOZ_UI_LOCALE']
+DEFINES['PACKAGE'] = 'browser'
+DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "74ed51578aa6d69a994d88be8d97f3b136288cd7", 
+    "revision": "3fe38577e17209728a54b14624143dbf99ade2df", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/gaia/Makefile.in
+++ b/b2g/gaia/Makefile.in
@@ -1,26 +1,14 @@
 # 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/.
 
 GAIA_PATH := gaia/profile
 
-ifeq ($(OS_ARCH),WINNT)
-DEFINES += \
-  -DB2G_NAME=L\"$(MOZ_APP_NAME)-bin$(BIN_SUFFIX)\" \
-  -DGAIA_PATH=L\"$(subst /,\\\\,$(GAIA_PATH))\" \
-  $(NULL)
-else # Non-windows machines use the same wrapper program
-DEFINES += \
-  -DB2G_NAME=\"$(MOZ_APP_NAME)-bin$(BIN_SUFFIX)\" \
-  -DGAIA_PATH=\"$(GAIA_PATH)\" \
-  $(NULL)
-endif
-
 ifdef .PYMAKE
 # For use of GNU make in pymake builds.
 GAIA_MAKE=$(GMAKE)
 else
 GAIA_MAKE=$(MAKE)
 endif
 
 # This is needed to avoid making run-b2g depend on mozglue
--- a/b2g/gaia/moz.build
+++ b/b2g/gaia/moz.build
@@ -5,12 +5,16 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 PROGRAM = CONFIG['MOZ_APP_NAME']
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     SOURCES += [
         'run-b2g.cpp',
     ]
+    DEFINES['B2G_NAME'] = 'L"%s-bin%s"' % (PROGRAM, CONFIG['BIN_SUFFIX'])
+    DEFINES['GAIA_PATH'] = 'L"gaia\\\\profile"'
 else:
     SOURCES += [
         'run-b2g.c',
     ]
+    DEFINES['B2G_NAME'] = '"%s-bin%s"' % (PROGRAM, CONFIG['BIN_SUFFIX'])
+    DEFINES['GAIA_PATH'] = '"gaia/profile"'
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -1,54 +1,43 @@
 # 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/.
 
 dist_dest   = $(DIST)/$(MOZ_MACBUNDLE_NAME)
 
-ifdef ENABLE_MARIONETTE
-DEFINES += -DENABLE_MARIONETTE=1
-endif
-
 PREF_JS_EXPORTS = $(srcdir)/profile/firefox.js \
 		  $(NULL)
 
 
 # hardcode en-US for the moment
 AB_CD = en-US
 
 DEFINES += \
   -DAB_CD=$(AB_CD) \
-  -DAPP_VERSION="$(MOZ_APP_VERSION)" \
   -DFIREFOX_ICO=\"$(DIST)/branding/firefox.ico\" \
   -DDOCUMENT_ICO=\"$(DIST)/branding/document.ico\" \
   -DNEWWINDOW_ICO=\"$(DIST)/branding/newwindow.ico\" \
   -DNEWTAB_ICO=\"$(DIST)/branding/newtab.ico\" \
   -DPBMODE_ICO=\"$(DIST)/branding/pbmode.ico\" \
   $(NULL)
 
-ifdef MOZILLA_OFFICIAL
-DEFINES += -DMOZILLA_OFFICIAL
-endif
-
 ifdef LIBXUL_SDK #{
 PREF_JS_EXPORTS += $(srcdir)/profile/channel-prefs.js
-DEFINES += -DLIBXUL_SDK
 endif #} LIBXUL_SDK
 
 # Build a binary bootstrapping with XRE_main
 
 LOCAL_INCLUDES += \
   -I$(topsrcdir)/toolkit/xre \
   -I$(topsrcdir)/xpcom/base \
   -I$(topsrcdir)/xpcom/build \
   -I$(DEPTH)/build \
   $(NULL)
 
-DEFINES += -DXPCOM_GLUE
 STL_FLAGS=
 
 LIBS += \
 	$(XPCOM_STANDALONE_GLUE_LDOPTS) \
 	$(NULL)
 
 ifdef MOZ_LINKER
 LIBS += $(MOZ_ZLIB_LIBS)
--- a/browser/app/moz.build
+++ b/browser/app/moz.build
@@ -6,8 +6,19 @@
 
 DIRS += ['profile/extensions']
 
 PROGRAM = CONFIG['MOZ_APP_NAME']
 
 SOURCES += [
     'nsBrowserApp.cpp',
 ]
+
+if CONFIG['ENABLE_MARIONETTE']:
+    DEFINES['ENABLE_MARIONETTE'] = 1
+
+DEFINES['APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
+
+for var in ('MOZILLA_OFFICIAL', 'LIBXUL_SDK'):
+    if CONFIG[var]:
+        DEFINES[var] = True
+
+DEFINES['XPCOM_GLUE'] = True
deleted file mode 100644
--- a/browser/base/Makefile.in
+++ /dev/null
@@ -1,34 +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/.
-
-include $(topsrcdir)/config/config.mk
-
-abs_srcdir = $(abspath $(srcdir))
-
-include $(topsrcdir)/config/rules.mk
-
-PRE_RELEASE_SUFFIX := ""
-
-DEFINES += \
-	-DMOZ_APP_VERSION=$(MOZ_APP_VERSION) \
-	-DAPP_LICENSE_BLOCK=$(abs_srcdir)/content/overrides/app-license.html \
-	-DPRE_RELEASE_SUFFIX="$(PRE_RELEASE_SUFFIX)" \
-	$(NULL)
-
-ifneq (,$(filter windows gtk2 gtk3 cocoa, $(MOZ_WIDGET_TOOLKIT)))
-DEFINES += -DHAVE_SHELL_SERVICE=1
-endif
-
-ifneq (,$(filter windows cocoa gtk2 gtk3, $(MOZ_WIDGET_TOOLKIT)))
-DEFINES += -DCONTEXT_COPY_IMAGE_CONTENTS=1
-endif
-
-ifneq (,$(filter windows cocoa, $(MOZ_WIDGET_TOOLKIT)))
-DEFINES += -DCAN_DRAW_IN_TITLEBAR=1
-endif
-
-ifneq (,$(filter windows gtk2 gtk3, $(MOZ_WIDGET_TOOLKIT)))
-DEFINES += -DMENUBAR_CAN_AUTOHIDE=1
-endif
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -22,29 +22,29 @@
 #include browser-doctype.inc
 
 <window id="main-window"
         xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns:svg="http://www.w3.org/2000/svg"
         xmlns:html="http://www.w3.org/1999/xhtml"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         onload="gBrowserInit.onLoad()" onunload="gBrowserInit.onUnload()" onclose="return WindowIsClosing();"
-        title="&mainWindow.title;@PRE_RELEASE_SUFFIX@"
-        title_normal="&mainWindow.title;@PRE_RELEASE_SUFFIX@"
+        title="&mainWindow.title;"
+        title_normal="&mainWindow.title;"
 #ifdef XP_MACOSX
-        title_privatebrowsing="&mainWindow.title;@PRE_RELEASE_SUFFIX@&mainWindow.titlemodifiermenuseparator;&mainWindow.titlePrivateBrowsingSuffix;"
-        titledefault="&mainWindow.title;@PRE_RELEASE_SUFFIX@"
+        title_privatebrowsing="&mainWindow.title;&mainWindow.titlemodifiermenuseparator;&mainWindow.titlePrivateBrowsingSuffix;"
+        titledefault="&mainWindow.title;"
         titlemodifier=""
         titlemodifier_normal=""
         titlemodifier_privatebrowsing="&mainWindow.titlePrivateBrowsingSuffix;"
 #else
-        title_privatebrowsing="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@ &mainWindow.titlePrivateBrowsingSuffix;"
-        titlemodifier="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@"
-        titlemodifier_normal="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@"
-        titlemodifier_privatebrowsing="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@ &mainWindow.titlePrivateBrowsingSuffix;"
+        title_privatebrowsing="&mainWindow.titlemodifier; &mainWindow.titlePrivateBrowsingSuffix;"
+        titlemodifier="&mainWindow.titlemodifier;"
+        titlemodifier_normal="&mainWindow.titlemodifier;"
+        titlemodifier_privatebrowsing="&mainWindow.titlemodifier; &mainWindow.titlePrivateBrowsingSuffix;"
 #endif
 #ifdef CAN_DRAW_IN_TITLEBAR
 #ifdef XP_WIN
         chromemargin="0,2,2,2"
 #else
         chromemargin="0,-1,-1,-1"
 #endif
         tabsintitlebar="true"
--- a/browser/base/content/chatWindow.xul
+++ b/browser/base/content/chatWindow.xul
@@ -13,17 +13,17 @@
 <?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
 
 #include browser-doctype.inc
 
 <window id="chat-window"
         windowtype="Social:Chat"
         xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-        title="&mainWindow.title;@PRE_RELEASE_SUFFIX@"
+        title="&mainWindow.title;"
         onload="gChatWindow.onLoad();"
         onunload="gChatWindow.onUnload();"
         macanimationtype="document"
         fullscreenbutton="true"
 # width and height are also used in socialchat.xml: chatbar dragend handler
         width="400px"
         height="420px"
         persist="screenX screenY width height sizemode">
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -4083,59 +4083,47 @@
                             .add(Date.now() - aTab._animStartTime);
           aTab._animStartTime = 0;
 
           // Handle tab animation smoothness telemetry/logging of frame intervals and paint times
           if (!("_recordingHandle" in aTab)) {
             return;
           }
 
-          let paints = {};
           let intervals = window.QueryInterface(Ci.nsIInterfaceRequestor)
                                 .getInterface(Ci.nsIDOMWindowUtils)
-                                .stopFrameTimeRecording(aTab._recordingHandle, paints);
+                                .stopFrameTimeRecording(aTab._recordingHandle);
           delete aTab._recordingHandle;
-          paints = paints.value; // The result array itself.
           let frameCount = intervals.length;
 
           if (this._tabAnimationLoggingEnabled) {
-            let msg = "Tab " + (aTab.closing ? "close" : "open") + " (Frame-interval / paint-processing):\n";
+            let msg = "Tab " + (aTab.closing ? "close" : "open") + " (Frame-interval):\n";
             for (let i = 0; i < frameCount; i++) {
-              msg += Math.round(intervals[i]) + " / " + Math.round(paints[i]) + "\n";
+              msg += Math.round(intervals[i]) + "\n";
             }
             Services.console.logStringMessage(msg);
           }
 
           // For telemetry, the first frame interval is not useful since it may represent an interval
           // to a relatively old frame (prior to recording start). So we'll ignore it for the average.
-          // But if we recorded only 1 frame (very rare), then the first paint duration is a good
-          // representative of the first frame interval for our cause (indicates very bad animation).
-          // First paint duration is always useful for us.
-          if (frameCount > 0) {
+          if (frameCount > 1) {
             let averageInterval = 0;
-            let averagePaint = paints[0];
             for (let i = 1; i < frameCount; i++) {
               averageInterval += intervals[i];
-              averagePaint    += paints[i];
             };
-            averagePaint /= frameCount;
-            averageInterval = (frameCount == 1)
-                              ? averagePaint
-                              : averageInterval / (frameCount - 1);
+            averageInterval = averageInterval / (frameCount - 1);
 
             Services.telemetry.getHistogramById("FX_TAB_ANIM_ANY_FRAME_INTERVAL_MS").add(averageInterval);
-            Services.telemetry.getHistogramById("FX_TAB_ANIM_ANY_FRAME_PAINT_MS").add(averagePaint);
 
             if (aTab._recordingTabOpenPlain) {
               delete aTab._recordingTabOpenPlain;
               // While we do have a telemetry probe NEWTAB_PAGE_ENABLED to monitor newtab preview, it'll be
               // easier to overview the data without slicing by it. Hence the additional histograms with _PREVIEW.
               let preview = this._browserNewtabpageEnabled ? "_PREVIEW" : "";
               Services.telemetry.getHistogramById("FX_TAB_ANIM_OPEN" + preview + "_FRAME_INTERVAL_MS").add(averageInterval);
-              Services.telemetry.getHistogramById("FX_TAB_ANIM_OPEN" + preview + "_FRAME_PAINT_MS").add(averagePaint);
             }
           }
         ]]>
         </body>
       </method>
 
       <!-- Deprecated stuff, implemented for backwards compatibility. -->
       <property name="mTabstripClosebutton" readonly="true"
--- a/browser/base/moz.build
+++ b/browser/base/moz.build
@@ -16,8 +16,21 @@ MOCHITEST_CHROME_MANIFESTS += [
     'content/test/chrome/chrome.ini',
 ]
 
 BROWSER_CHROME_MANIFESTS += [
     'content/test/general/browser.ini',
     'content/test/newtab/browser.ini',
     'content/test/social/browser.ini',
 ]
+
+DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
+DEFINES['APP_LICENSE_BLOCK'] = '%s/content/overrides/app-license.html' % SRCDIR
+
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3', 'cocoa'):
+    DEFINES['HAVE_SHELL_SERVICE'] = 1
+    DEFINES['CONTEXT_COPY_IMAGE_CONTENTS'] = 1
+
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa'):
+    DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1
+
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3'):
+    DEFINES['MENUBAR_CAN_AUTOHIDE'] = 1
--- a/browser/branding/aurora/locales/Makefile.in
+++ b/browser/branding/aurora/locales/Makefile.in
@@ -1,5 +1,5 @@
 # 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/.
 
-DEFINES += -DAB_CD=$(AB_CD) -DMOZ_DISTRIBUTION_ID_UNQUOTED=$(MOZ_DISTRIBUTION_ID)
+DEFINES += -DAB_CD=$(AB_CD)
--- a/browser/branding/aurora/locales/moz.build
+++ b/browser/branding/aurora/locales/moz.build
@@ -1,6 +1,7 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
+DEFINES['MOZ_DISTRIBUTION_ID_UNQUOTED'] = CONFIG['MOZ_DISTRIBUTION_ID']
--- a/browser/branding/nightly/locales/Makefile.in
+++ b/browser/branding/nightly/locales/Makefile.in
@@ -1,5 +1,5 @@
 # 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/.
 
-DEFINES += -DAB_CD=$(AB_CD) -DMOZ_DISTRIBUTION_ID_UNQUOTED=$(MOZ_DISTRIBUTION_ID)
+DEFINES += -DAB_CD=$(AB_CD)
--- a/browser/branding/nightly/locales/moz.build
+++ b/browser/branding/nightly/locales/moz.build
@@ -1,6 +1,7 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
+DEFINES['MOZ_DISTRIBUTION_ID_UNQUOTED'] = CONFIG['MOZ_DISTRIBUTION_ID']
--- a/browser/branding/unofficial/locales/Makefile.in
+++ b/browser/branding/unofficial/locales/Makefile.in
@@ -1,5 +1,5 @@
 # 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/.
 
-DEFINES += -DAB_CD=$(AB_CD) -DMOZ_DISTRIBUTION_ID_UNQUOTED=$(MOZ_DISTRIBUTION_ID)
+DEFINES += -DAB_CD=$(AB_CD)
--- a/browser/branding/unofficial/locales/moz.build
+++ b/browser/branding/unofficial/locales/moz.build
@@ -1,6 +1,7 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
+DEFINES['MOZ_DISTRIBUTION_ID_UNQUOTED'] = CONFIG['MOZ_DISTRIBUTION_ID']
--- a/browser/components/feeds/src/Makefile.in
+++ b/browser/components/feeds/src/Makefile.in
@@ -1,11 +1,5 @@
 # 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/.
 
-DEFINES += \
-	-DMOZ_APP_NAME=$(MOZ_APP_NAME) \
-	-DMOZ_MACBUNDLE_NAME=$(MOZ_MACBUNDLE_NAME) \
-	$(NULL)
-
-
 LOCAL_INCLUDES = -I$(srcdir)/../../build
--- a/browser/components/feeds/src/moz.build
+++ b/browser/components/feeds/src/moz.build
@@ -14,8 +14,11 @@ EXTRA_COMPONENTS += [
     'WebContentConverter.js',
 ]
 
 EXTRA_PP_COMPONENTS += [
     'FeedWriter.js',
 ]
 
 FINAL_LIBRARY = 'browsercomps'
+
+for var in ('MOZ_APP_NAME', 'MOZ_MACBUNDLE_NAME'):
+    DEFINES[var] = CONFIG[var]
deleted file mode 100644
--- a/browser/components/migration/src/Makefile.in
+++ /dev/null
@@ -1,12 +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/.
-
-ifeq ($(OS_ARCH),WINNT)
-
-DEFINES += -DHAS_IE_MIGRATOR -DHAS_SAFARI_MIGRATOR
-endif
-
-ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
-DEFINES += -DHAS_SAFARI_MIGRATOR
-endif
--- a/browser/components/migration/src/moz.build
+++ b/browser/components/migration/src/moz.build
@@ -13,29 +13,32 @@ EXTRA_COMPONENTS += [
     'FirefoxProfileMigrator.js',
     'ProfileMigrator.js',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     EXTRA_COMPONENTS += [
         'IEProfileMigrator.js',
     ]
+    DEFINES['HAS_IE_MIGRATOR'] = True
 
 EXTRA_PP_COMPONENTS += [
     'BrowserProfileMigrators.manifest',
     'ChromeProfileMigrator.js',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     EXTRA_PP_COMPONENTS += [
         'SafariProfileMigrator.js',
     ]
+    DEFINES['HAS_SAFARI_MIGRATOR'] = True
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     EXTRA_PP_COMPONENTS += [
         'SafariProfileMigrator.js',
     ]
+    DEFINES['HAS_SAFARI_MIGRATOR'] = True
 
 EXTRA_PP_JS_MODULES += [
     'MigrationUtils.jsm',
 ]
 
 FINAL_LIBRARY = 'browsercomps'
deleted file mode 100644
--- a/browser/components/preferences/Makefile.in
+++ /dev/null
@@ -1,15 +0,0 @@
-# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-include $(topsrcdir)/config/rules.mk
-
-DEFINES += \
-	-DMOZ_APP_NAME=$(MOZ_APP_NAME) \
-	-DMOZ_MACBUNDLE_NAME=$(MOZ_MACBUNDLE_NAME) \
-	$(NULL)
-
-ifneq (,$(filter windows gtk2 gtk3 cocoa, $(MOZ_WIDGET_TOOLKIT)))
-DEFINES += -DHAVE_SHELL_SERVICE=1
-endif
deleted file mode 100644
--- a/browser/components/preferences/in-content/Makefile.in
+++ /dev/null
@@ -1,14 +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/.
-
-include $(topsrcdir)/config/rules.mk
-
-DEFINES += \
-	-DMOZ_APP_NAME=$(MOZ_APP_NAME) \
-	-DMOZ_MACBUNDLE_NAME=$(MOZ_MACBUNDLE_NAME) \
-	$(NULL)
-
-ifneq (,$(filter windows gtk2 cocoa, $(MOZ_WIDGET_TOOLKIT)))
-DEFINES += -DHAVE_SHELL_SERVICE=1
-endif
--- a/browser/components/preferences/in-content/moz.build
+++ b/browser/components/preferences/in-content/moz.build
@@ -1,6 +1,11 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
+for var in ('MOZ_APP_NAME', 'MOZ_MACBUNDLE_NAME'):
+    DEFINES[var] = CONFIG[var]
+
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'cocoa'):
+    DEFINES['HAVE_SHELL_SERVICE'] = 1
--- a/browser/components/preferences/moz.build
+++ b/browser/components/preferences/moz.build
@@ -5,8 +5,14 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 PARALLEL_DIRS += ['in-content']
 
 BROWSER_CHROME_MANIFESTS += [
     'in-content/tests/browser.ini',
     'tests/browser.ini',
 ]
+
+for var in ('MOZ_APP_NAME', 'MOZ_MACBUNDLE_NAME'):
+    DEFINES[var] = CONFIG[var]
+
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3', 'cocoa'):
+    DEFINES['HAVE_SHELL_SERVICE'] = 1
--- a/browser/components/shell/src/Makefile.in
+++ b/browser/components/shell/src/Makefile.in
@@ -1,14 +1,11 @@
 #
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 include $(topsrcdir)/config/rules.mk
 
-DEFINES += -DMOZ_APP_NAME=\"$(MOZ_APP_NAME)\" \
-  -DMOZ_APP_VERSION=\"$(MOZ_APP_VERSION)\"
-
 CXXFLAGS += $(TK_CFLAGS)
 
 clobber::
 	rm -f $(DIST)/lib/$(LIBRARY_NAME).lib
--- a/browser/components/shell/src/moz.build
+++ b/browser/components/shell/src/moz.build
@@ -19,8 +19,11 @@ elif CONFIG['MOZ_WIDGET_GTK']:
 
 if SOURCES:
     FINAL_LIBRARY = 'browsercomps'
 
 EXTRA_COMPONENTS += [
     'nsSetDefaultBrowser.js',
     'nsSetDefaultBrowser.manifest',
 ]
+
+for var in ('MOZ_APP_NAME', 'MOZ_APP_VERSION'):
+    DEFINES[var] = '"%s"' % CONFIG[var]
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -13,11 +13,10 @@ MOCHITEST_BROWSER_FILES += \
 	$(NULL)
 endif
 
 # Bug 895426:
 #   Disable browser_dbg_break-on-dom-event.js due to frequent failures
 ifneq (Darwin,$(OS_ARCH))
 MOCHITEST_BROWSER_FILES += \
 	browser_dbg_break-on-dom-event.js \
-	browser_dbg_event-listeners.js \
 	$(NULL)
 endif
--- a/browser/devtools/debugger/test/browser.ini
+++ b/browser/devtools/debugger/test/browser.ini
@@ -92,16 +92,17 @@ skip-if = true
 [browser_dbg_cmd-blackbox.js]
 [browser_dbg_cmd-break.js]
 [browser_dbg_cmd-dbg.js]
 [browser_dbg_conditional-breakpoints-01.js]
 [browser_dbg_conditional-breakpoints-02.js]
 [browser_dbg_debugger-statement.js]
 [browser_dbg_editor-contextmenu.js]
 [browser_dbg_editor-mode.js]
+[browser_dbg_event-listeners.js]
 [browser_dbg_function-display-name.js]
 [browser_dbg_globalactor.js]
 [browser_dbg_host-layout.js]
 [browser_dbg_iframes.js]
 [browser_dbg_instruments-pane-collapse.js]
 [browser_dbg_listaddons.js]
 [browser_dbg_listtabs-01.js]
 [browser_dbg_listtabs-02.js]
--- a/browser/installer/windows/Makefile.in
+++ b/browser/installer/windows/Makefile.in
@@ -3,18 +3,16 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 include $(topsrcdir)/toolkit/mozapps/installer/package-name.mk
 
 CONFIG_DIR = instgen
 SFX_MODULE = $(topsrcdir)/other-licenses/7zstub/firefox/7zSD.sfx
 APP_VERSION := $(shell cat $(srcdir)/../../config/version.txt)
 DEFINES += -DAPP_VERSION=$(APP_VERSION)
-PRE_RELEASE_SUFFIX := ""
-DEFINES += -DPRE_RELEASE_SUFFIX="$(PRE_RELEASE_SUFFIX)"
 
 INSTALLER_FILES = \
 	app.tag \
 	nsis/installer.nsi \
 	nsis/uninstaller.nsi \
 	nsis/stub.nsi \
 	nsis/shared.nsh \
 	stub.tag \
--- a/browser/installer/windows/nsis/defines.nsi.in
+++ b/browser/installer/windows/nsis/defines.nsi.in
@@ -27,18 +27,17 @@
 !define AB_CD                 "@AB_CD@"
 
 !define FileMainEXE           "@MOZ_APP_NAME@.exe"
 !define WindowClass           "FirefoxMessageWindow"
 !define DDEApplication        "Firefox"
 !define AppRegName            "Firefox"
 
 !define BrandShortName        "@MOZ_APP_DISPLAYNAME@"
-!define PreReleaseSuffix      "@PRE_RELEASE_SUFFIX@"
-!define BrandFullName         "${BrandFullNameInternal}${PreReleaseSuffix}"
+!define BrandFullName         "${BrandFullNameInternal}"
 
 !define NO_UNINSTALL_SURVEY
 
 !define CERTIFICATE_NAME      "Mozilla Corporation"
 !define CERTIFICATE_ISSUER    "DigiCert Assured ID Code Signing CA-1"
 
 # LSP_CATEGORIES is the permitted LSP categories for the application. Each LSP
 # category value is ANDed together to set multiple permitted categories.
@@ -55,25 +54,16 @@
 # Due to official and beta using the same branding this is needed to
 # differentiante between the url used by the stub for downloading.
 !if "@MOZ_UPDATE_CHANNEL@" == "beta"
 !define BETA_UPDATE_CHANNEL
 !endif
 
 !define BaseURLStubPing "http://download-stats.mozilla.org/stub"
 
-# NO_INSTDIR_FROM_REG is defined for pre-releases which have a PreReleaseSuffix
-# (e.g. Alpha X, Beta X, etc.) to prevent finding a non-default installation
-# directory in the registry and using that as the default. This prevents
-# Beta releases built with official branding from finding an existing install
-# of an official release and defaulting to its installation directory.
-!if "@PRE_RELEASE_SUFFIX@" != ""
-!define NO_INSTDIR_FROM_REG
-!endif
-
 # ARCH is used when it is necessary to differentiate the x64 registry keys from
 # the x86 registry keys (e.g. the uninstall registry key).
 #ifdef HAVE_64BIT_OS
 !define HAVE_64BIT_OS
 !define ARCH "x64"
 !define MinSupportedVer "Microsoft Windows Vista x64"
 #else
 !define ARCH "x86"
--- a/browser/metro/Makefile.in
+++ b/browser/metro/Makefile.in
@@ -2,22 +2,18 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 include $(topsrcdir)/config/rules.mk
 
 #########################################
 # application.ini
 
-ifdef MOZILLA_OFFICIAL
-DEFINES += -DMOZILLA_OFFICIAL
-endif
-
 GRE_BUILDID := $(shell cat $(DEPTH)/config/buildid)
-DEFINES += -DGRE_MILESTONE=$(GRE_MILESTONE) -DGRE_BUILDID=$(GRE_BUILDID)
+DEFINES += -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"
 	$(call py_action,preprocessor,$(DEFINES) $< -o $@)
 
 libs:: metroapp.ini
 	$(INSTALL) metroapp.ini $(FINAL_TARGET)
deleted file mode 100644
--- a/browser/metro/base/Makefile.in
+++ /dev/null
@@ -1,10 +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/.
-
-include $(topsrcdir)/config/config.mk
-
-DEFINES += -DAB_CD=$(MOZ_UI_LOCALE) \
-           -DPACKAGE=browser \
-           -DMOZ_APP_VERSION=$(MOZ_APP_VERSION) \
-           $(NULL)
--- a/browser/metro/base/moz.build
+++ b/browser/metro/base/moz.build
@@ -3,8 +3,12 @@
 # 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/.
 
 METRO_CHROME_MANIFESTS += ['tests/mochiperf/metro.ini', 'tests/mochitest/metro.ini']
 XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
 
 DIST_SUBDIR = 'metro'
+
+DEFINES['AB_CD'] = CONFIG['MOZ_UI_LOCALE']
+DEFINES['PACKAGE'] = 'browser'
+DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
--- a/browser/metro/moz.build
+++ b/browser/metro/moz.build
@@ -12,8 +12,13 @@ DIRS += [
     'profile',
     'locales',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     DIRS += ['shell']
 
 DIST_SUBDIR = 'metro'
+
+if CONFIG['MOZILLA_OFFICIAL']:
+    DEFINES['MOZILLA_OFFICIAL'] = True
+
+DEFINES['GRE_MILESTONE'] = CONFIG['GRE_MILESTONE']
--- a/browser/metro/shell/commandexecutehandler/Makefile.in
+++ b/browser/metro/shell/commandexecutehandler/Makefile.in
@@ -16,10 +16,8 @@ OS_LIBS = \
 	kernel32.lib \
 	user32.lib \
 	ole32.lib \
 	shlwapi.lib \
 	propsys.lib \
 	advapi32.lib \
 	wininet.lib \
 	$(NULL)
-
-DEFINES += -DUNICODE -D_UNICODE -DNS_NO_XPCOM
--- a/browser/metro/shell/commandexecutehandler/moz.build
+++ b/browser/metro/shell/commandexecutehandler/moz.build
@@ -8,8 +8,11 @@ PROGRAM = 'CommandExecuteHandler'
 
 SOURCES += [
     'CEHHelper.cpp',
     'CommandExecuteHandler.cpp',
 ]
 
 # We want this exe in dist/bin
 DIST_SUBDIR = ''
+
+for var in ('UNICODE', '_UNICODE', 'NS_NO_XPCOM'):
+    DEFINES[var] = True
--- a/browser/metro/shell/linktool/Makefile.in
+++ b/browser/metro/shell/linktool/Makefile.in
@@ -9,10 +9,8 @@ include $(topsrcdir)/config/config.mk
 OS_LIBS = \
 	kernel32.lib \
 	user32.lib \
 	ole32.lib \
 	shlwapi.lib \
 	shell32.lib \
 	propsys.lib \
 	$(NULL)
-
-DEFINES += -DUNICODE -D_UNICODE
--- a/browser/metro/shell/linktool/moz.build
+++ b/browser/metro/shell/linktool/moz.build
@@ -6,8 +6,11 @@
 
 PROGRAM = 'linktool'
 
 SOURCES += [
     'linktool.cpp',
 ]
 
 DIST_SUBDIR = 'metro/install'
+
+for var in ('UNICODE', '_UNICODE'):
+    DEFINES[var] = True
--- a/browser/metro/shell/testing/Makefile.in
+++ b/browser/metro/shell/testing/Makefile.in
@@ -16,10 +16,8 @@ include $(topsrcdir)/config/config.mk
 OS_LIBS = \
 	kernel32.lib \
 	user32.lib \
 	ole32.lib \
 	shlwapi.lib \
 	propsys.lib \
 	advapi32.lib \
 	$(NULL)
-
-DEFINES += -DUNICODE -D_UNICODE
--- a/browser/metro/shell/testing/moz.build
+++ b/browser/metro/shell/testing/moz.build
@@ -7,8 +7,11 @@
 PROGRAM = 'metrotestharness'
 
 SOURCES += [
     'metrotestharness.cpp',
 ]
 
 # We want this exe in dist/bin
 DIST_SUBDIR = ''
+
+for var in ('UNICODE', '_UNICODE'):
+    DEFINES[var] = True
deleted file mode 100644
--- a/browser/modules/Makefile.in
+++ /dev/null
@@ -1,9 +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/.
-
-include $(topsrcdir)/config/config.mk
-
-ifdef MOZILLA_OFFICIAL
-DEFINES += -DMOZILLA_OFFICIAL=1
-endif
--- a/browser/modules/moz.build
+++ b/browser/modules/moz.build
@@ -29,8 +29,10 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'wind
         'WindowsPreviewPerTab.jsm',
     ]
 
 EXTRA_PP_JS_MODULES += [
     'AboutHome.jsm',
     'RecentWindow.jsm',
 ]
 
+if CONFIG['MOZILLA_OFFICIAL']:
+    DEFINES['MOZILLA_OFFICIAL'] = 1
--- a/build/Makefile.in
+++ b/build/Makefile.in
@@ -19,59 +19,30 @@ ifdef LIBXUL_SDK
 APP_INI_DEPS = $(LIBXUL_DIST)/bin/platform.ini
 else
 APP_INI_DEPS = $(topsrcdir)/config/milestone.txt
 endif
 
 APP_BUILDID := $(shell cat $(DEPTH)/config/buildid)
 APP_INI_DEPS += $(DEPTH)/config/buildid
 
-DEFINES += -DGRE_MILESTONE=$(GRE_MILESTONE) -DAPP_BUILDID=$(APP_BUILDID)
+DEFINES += -DAPP_BUILDID=$(APP_BUILDID)
 
-DEFINES += -DMOZ_APP_VERSION="$(MOZ_APP_VERSION)"
 APP_INI_DEPS += $(DEPTH)/config/autoconf.mk
 
 MOZ_SOURCE_STAMP := $(firstword $(shell cd $(topsrcdir)/$(MOZ_BUILD_APP)/.. && hg parent --template="{node|short}\n" 2>/dev/null))
 ifdef MOZ_SOURCE_STAMP
 DEFINES += -DMOZ_SOURCE_STAMP="$(MOZ_SOURCE_STAMP)"
 endif
 
 source_repo ?= $(call getSourceRepo,$(topsrcdir)/$(MOZ_BUILD_APP)/..)
 ifneq (,$(source_repo))
   DEFINES += -DMOZ_SOURCE_REPO="$(source_repo)"
 endif
 
-DEFINES += \
-  -DMOZ_APP_BASENAME="$(MOZ_APP_BASENAME)" \
-  -DMOZ_APP_VENDOR="$(MOZ_APP_VENDOR)" \
-  -DMOZ_APP_ID="$(MOZ_APP_ID)" \
-  -DMAR_CHANNEL_ID="$(MAR_CHANNEL_ID)" \
-  -DACCEPTED_MAR_CHANNEL_IDS="$(ACCEPTED_MAR_CHANNEL_IDS)" \
-  $(NULL)
-
-ifeq ($(MOZ_BUILD_APP),browser)
-DEFINES += -DMOZ_BUILD_APP_IS_BROWSER
-endif
-
-ifdef MOZ_APP_PROFILE
-DEFINES += -DMOZ_APP_PROFILE="$(MOZ_APP_PROFILE)"
-endif
-
-ifdef MOZ_CRASHREPORTER
-DEFINES += -DMOZ_CRASHREPORTER
-endif
-
-ifdef MOZ_PROFILE_MIGRATOR
-DEFINES += -DMOZ_PROFILE_MIGRATOR
-endif
-
-ifdef MOZ_EXTENSION_MANAGER
-DEFINES += -DMOZ_EXTENSION_MANAGER
-endif
-
 endif
 
 # Put a useful .gdbinit in the bin directory, to be picked up automatically
 # by GDB when we debug executables there.
 # NOTE: Keep .gdbinit in the topsrcdir for people who run gdb from the topsrcdir.
 GDBINIT_FILES := $(topsrcdir)/.gdbinit
 GDBINIT_DEST = $(FINAL_TARGET)
 INSTALL_TARGETS += GDBINIT
@@ -118,18 +89,16 @@ leaktest.py: leaktest.py.in
 	$(call py_action,preprocessor,$^ -o $@)
 	chmod +x $@
 GARBAGE += leaktest.py
 
 ifdef MOZ_APP_BASENAME
 $(FINAL_TARGET)/application.ini: $(APP_INI_DEPS)
 
 ifdef MOZ_APP_STATIC_INI
-DEFINES += -DMOZ_APP_STATIC_INI
-
 application.ini.h: appini_header.py $(FINAL_TARGET)/application.ini
 	$(PYTHON) $^ > $@
 export:: application.ini.h
 GARBAGE += application.ini.h
 endif
 endif
 
 libs:: $(_LEAKTEST_FILES)
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -565,24 +565,17 @@ class ShutdownLeaks(object):
       # don't track a test if no windows or docShells leaked
       if self.currentTest and (self.currentTest["windows"] or self.currentTest["docShells"]):
         self.tests.append(self.currentTest)
       self.currentTest = None
     elif line.startswith("INFO TEST-START | Shutdown"):
       self.seenShutdown = True
 
   def process(self):
-    leakingTests = self._parseLeakingTests()
-
-    if leakingTests:
-      totalWindows = sum(len(test["leakedWindows"]) for test in leakingTests)
-      totalDocShells = sum(len(test["leakedDocShells"]) for test in leakingTests)
-      self.logger("TEST-UNEXPECTED-FAIL | ShutdownLeaks | leaked %d DOMWindow(s) and %d DocShell(s) until shutdown", totalWindows, totalDocShells)
-
-    for test in leakingTests:
+    for test in self._parseLeakingTests():
       for url, count in self._zipLeakedWindows(test["leakedWindows"]):
         self.logger("TEST-UNEXPECTED-FAIL | %s | leaked %d window(s) until shutdown [url = %s]", test["fileName"], count, url)
 
       if test["leakedDocShells"]:
         self.logger("TEST-UNEXPECTED-FAIL | %s | leaked %d docShell(s) until shutdown", test["fileName"], len(test["leakedDocShells"]))
 
   def _logWindow(self, line):
     created = line[:2] == "++"
--- a/build/mobile/robocop/Makefile.in
+++ b/build/mobile/robocop/Makefile.in
@@ -70,20 +70,16 @@ GARBAGE += \
 
 JAVAFILES += \
   $(java-harness) \
   $(java-tests) \
   $(robocop-deps) \
   $(testconstants-dep) \
   $(NULL)
 
-DEFINES += \
-  -DANDROID_PACKAGE_NAME=$(ANDROID_PACKAGE_NAME) \
-  $(NULL)
-
 include $(topsrcdir)/config/rules.mk
 
 tools:: $(ANDROID_APK_NAME).apk
 
 GENERATED_DIRS += $(dir-tests)
 
 # The test APK needs to know the contents of the target APK while not
 # being linked against them.  This is a best effort to avoid getting
--- a/build/mobile/robocop/moz.build
+++ b/build/mobile/robocop/moz.build
@@ -2,8 +2,10 @@
 # vim: set filetype=python:
 # 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/.
 
 ANDROID_RESFILES = [
     'res/values/strings.xml',
 ]
+
+DEFINES['ANDROID_PACKAGE_NAME'] = CONFIG['ANDROID_PACKAGE_NAME']
--- a/build/moz.build
+++ b/build/moz.build
@@ -17,8 +17,24 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'andr
     TEST_DIRS += [
         'mobile/sutagent/android',
         'mobile/sutagent/android/watcher',
         'mobile/sutagent/android/ffxcp',
         'mobile/sutagent/android/fencp',
         'mobile/robocop',
     ]
 
+for var in ('GRE_MILESTONE', 'MOZ_APP_VERSION', 'MOZ_APP_BASENAME',
+            'MOZ_APP_VENDOR', 'MOZ_APP_ID', 'MAR_CHANNEL_ID',
+            'ACCEPTED_MAR_CHANNEL_IDS'):
+    DEFINES[var] = CONFIG[var]
+
+if CONFIG['MOZ_BUILD_APP'] == 'browser':
+    DEFINES['MOZ_BUILD_APP_IS_BROWSER'] = True
+
+if CONFIG['MOZ_APP_PROFILE']:
+    DEFINES['MOZ_APP_PROFILE'] = CONFIG['MOZ_APP_PROFILE']
+
+for var in ('MOZ_CRASHREPORTER', 'MOZ_PROFILE_MIGRATOR',
+            'MOZ_EXTENSION_MANAGER', 'MOZ_APP_STATIC_INI'):
+    if CONFIG[var]:
+        DEFINES[var] = True
+
--- a/build/stlport/Makefile.in
+++ b/build/stlport/Makefile.in
@@ -6,11 +6,10 @@ MODULES = stlport
 STL_FLAGS =
 
 # Force to build a static library, instead of a fake library, without
 # installing it in dist/lib.
 LIBRARY = $(LIB_PREFIX)$(LIBRARY_NAME).$(LIB_SUFFIX)
 
 include $(topsrcdir)/config/rules.mk
 
-DEFINES += -D_GNU_SOURCE
 CXXFLAGS += -fuse-cxa-atexit
 INCLUDES += -I$(srcdir)/stlport
--- a/build/stlport/moz.build
+++ b/build/stlport/moz.build
@@ -40,8 +40,10 @@ SOURCES += [
     'src/strstream.cpp',
     'src/time_facets.cpp',
 ]
 
 SOURCES += [
     'src/c_locale.c',
     'src/cxa.c',
 ]
+
+DEFINES['_GNU_SOURCE'] = True
--- a/build/unix/elfhack/Makefile.in
+++ b/build/unix/elfhack/Makefile.in
@@ -10,18 +10,16 @@ NO_PROFILE_GUIDED_OPTIMIZE = 1
 VPATH += $(topsrcdir)/build
 
 OS_CXXFLAGS := $(filter-out -fno-exceptions,$(OS_CXXFLAGS)) -fexceptions
 
 WRAP_LDFLAGS=
 
 include $(topsrcdir)/config/rules.mk
 
-DEFINES += -DELFHACK_BUILD
-
 test-array$(DLL_SUFFIX) test-ctors$(DLL_SUFFIX): %$(DLL_SUFFIX): %.$(OBJ_SUFFIX) elfhack
 	$(MKSHLIB) $(LDFLAGS) $< -nostartfiles
 	@echo ===
 	@echo === If you get failures below, please file a bug describing the error
 	@echo === and your environment \(compiler and linker versions\), and use
 	@echo === --disable-elf-hack until this is fixed.
 	@echo ===
 	# Fail if the library doesn't have $(DT_TYPE) .dynamic info
--- a/build/unix/elfhack/inject/Makefile.in
+++ b/build/unix/elfhack/inject/Makefile.in
@@ -10,11 +10,9 @@ include $(topsrcdir)/config/rules.mk
 
 export:: $(CSRCS:.c=.$(OBJ_SUFFIX))
 
 $(CSRCS): %.c: ../inject.c
 	cp $< $@
 
 GARBAGE += $(CSRCS)
 
-DEFINES += -DELFHACK_BUILD
-
 CFLAGS := -O2 -fno-stack-protector $(filter -m% -I%,$(CFLAGS))
--- a/build/unix/elfhack/inject/moz.build
+++ b/build/unix/elfhack/inject/moz.build
@@ -11,8 +11,10 @@ if CONFIG['TARGET_CPU'].endswith('86'):
 elif CONFIG['TARGET_CPU'].startswith('arm'):
     cpu = 'arm'
 else:
     cpu = CONFIG['TARGET_CPU']
 
 GENERATED_SOURCES += [
     "%s.c" % cpu,
 ]
+
+DEFINES['ELFHACK_BUILD'] = True
--- a/build/unix/elfhack/moz.build
+++ b/build/unix/elfhack/moz.build
@@ -18,8 +18,10 @@ if not CONFIG['CROSS_COMPILE']:
     ]
 
 HOST_SOURCES += [
     'elf.cpp',
     'elfhack.cpp',
 ]
 
 HOST_PROGRAM = 'elfhack'
+
+DEFINES['ELFHACK_BUILD'] = True
--- a/caps/src/nsNullPrincipal.cpp
+++ b/caps/src/nsNullPrincipal.cpp
@@ -30,30 +30,30 @@ NS_IMPL_CLASSINFO(nsNullPrincipal, nullp
                   NS_NULLPRINCIPAL_CID)
 NS_IMPL_QUERY_INTERFACE2_CI(nsNullPrincipal,
                             nsIPrincipal,
                             nsISerializable)
 NS_IMPL_CI_INTERFACE_GETTER2(nsNullPrincipal,
                              nsIPrincipal,
                              nsISerializable)
 
-NS_IMETHODIMP_(nsrefcnt) 
+NS_IMETHODIMP_(nsrefcnt)
 nsNullPrincipal::AddRef()
 {
   NS_PRECONDITION(int32_t(refcount) >= 0, "illegal refcnt");
-  nsrefcnt count = PR_ATOMIC_INCREMENT(&refcount);
+  nsrefcnt count = ++refcount;
   NS_LOG_ADDREF(this, count, "nsNullPrincipal", sizeof(*this));
   return count;
 }
 
 NS_IMETHODIMP_(nsrefcnt)
 nsNullPrincipal::Release()
 {
   NS_PRECONDITION(0 != refcount, "dup release");
-  nsrefcnt count = PR_ATOMIC_DECREMENT(&refcount);
+  nsrefcnt count = --refcount;
   NS_LOG_RELEASE(this, count, "nsNullPrincipal");
   if (count == 0) {
     delete this;
   }
 
   return count;
 }
 
--- a/caps/src/nsPrincipal.cpp
+++ b/caps/src/nsPrincipal.cpp
@@ -46,26 +46,26 @@ static bool URIIsImmutable(nsIURI* aURI)
 // Static member variables
 const char nsBasePrincipal::sInvalid[] = "Invalid";
 
 NS_IMETHODIMP_(nsrefcnt)
 nsBasePrincipal::AddRef()
 {
   NS_PRECONDITION(int32_t(refcount) >= 0, "illegal refcnt");
   // XXXcaa does this need to be threadsafe?  See bug 143559.
-  nsrefcnt count = PR_ATOMIC_INCREMENT(&refcount);
+  nsrefcnt count = ++refcount;
   NS_LOG_ADDREF(this, count, "nsBasePrincipal", sizeof(*this));
   return count;
 }
 
 NS_IMETHODIMP_(nsrefcnt)
 nsBasePrincipal::Release()
 {
   NS_PRECONDITION(0 != refcount, "dup release");
-  nsrefcnt count = PR_ATOMIC_DECREMENT(&refcount);
+  nsrefcnt count = --refcount;
   NS_LOG_RELEASE(this, count, "nsBasePrincipal");
   if (count == 0) {
     delete this;
   }
 
   return count;
 }
 
--- a/caps/src/nsSystemPrincipal.cpp
+++ b/caps/src/nsSystemPrincipal.cpp
@@ -24,30 +24,30 @@ NS_IMPL_CLASSINFO(nsSystemPrincipal, nul
                   NS_SYSTEMPRINCIPAL_CID)
 NS_IMPL_QUERY_INTERFACE2_CI(nsSystemPrincipal,
                             nsIPrincipal,
                             nsISerializable)
 NS_IMPL_CI_INTERFACE_GETTER2(nsSystemPrincipal,
                              nsIPrincipal,
                              nsISerializable)
 
-NS_IMETHODIMP_(nsrefcnt) 
+NS_IMETHODIMP_(nsrefcnt)
 nsSystemPrincipal::AddRef()
 {
   NS_PRECONDITION(int32_t(refcount) >= 0, "illegal refcnt");
-  nsrefcnt count = PR_ATOMIC_INCREMENT(&refcount);
+  nsrefcnt count = ++refcount;
   NS_LOG_ADDREF(this, count, "nsSystemPrincipal", sizeof(*this));
   return count;
 }
 
 NS_IMETHODIMP_(nsrefcnt)
 nsSystemPrincipal::Release()
 {
   NS_PRECONDITION(0 != refcount, "dup release");
-  nsrefcnt count = PR_ATOMIC_DECREMENT(&refcount);
+  nsrefcnt count = --refcount;
   NS_LOG_RELEASE(this, count, "nsSystemPrincipal");
   if (count == 0) {
     delete this;
   }
 
   return count;
 }
 
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -902,17 +902,17 @@ public:
     return outer && outer->IsBackground();
   }
   
   /**
    * Return the inner window used as the script compilation scope for
    * this document. If you're not absolutely sure you need this, use
    * GetWindow().
    */
-  nsPIDOMWindow* GetInnerWindow()
+  nsPIDOMWindow* GetInnerWindow() const
   {
     return mRemovedFromDocShell ? nullptr : mWindow;
   }
 
   /**
    * Return the outer window ID.
    */
   uint64_t OuterWindowID() const
@@ -1608,17 +1608,20 @@ public:
   /**
    * Return whether the document and all its ancestors are visible in the sense of
    * pageshow / hide.
    */
   bool IsVisibleConsideringAncestors() const;
 
   /**
    * Return true when this document is active, i.e., the active document
-   * in a content viewer.
+   * in a content viewer.  Note that this will return true for bfcached
+   * documents, so this does NOT match the "active document" concept in
+   * the WHATWG spec.  That would correspond to GetInnerWindow() &&
+   * GetInnerWindow()->IsCurrentInnerWindow().
    */
   bool IsActive() const { return mDocumentContainer && !mRemovedFromDocShell; }
 
   void RegisterFreezableElement(nsIContent* aContent);
   bool UnregisterFreezableElement(nsIContent* aContent);
   typedef void (* FreezableElementEnumerator)(nsIContent*, void*);
   void EnumerateFreezableElements(FreezableElementEnumerator aEnumerator,
                                   void* aData);
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -5,17 +5,17 @@
 
 #include "WebGLContext.h"
 #include "WebGL1Context.h"
 #include "WebGLObjectModel.h"
 #include "WebGLExtensions.h"
 #include "WebGLContextUtils.h"
 #include "WebGLBuffer.h"
 #include "WebGLVertexAttribData.h"
-#include "WebGLMemoryReporterWrapper.h"
+#include "WebGLMemoryTracker.h"
 #include "WebGLFramebuffer.h"
 #include "WebGLVertexArray.h"
 #include "WebGLQuery.h"
 
 #include "AccessCheck.h"
 #include "nsIConsoleService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIClassInfoImpl.h"
@@ -173,17 +173,17 @@ WebGLContext::WebGLContext()
     mGLMaxColorAttachments = 1;
     mGLMaxDrawBuffers = 1;
     mGLMaxTransformFeedbackSeparateAttribs = 0;
 
     // See OpenGL ES 2.0.25 spec, 6.2 State Tables, table 6.13
     mPixelStorePackAlignment = 4;
     mPixelStoreUnpackAlignment = 4;
 
-    WebGLMemoryReporterWrapper::AddWebGLContext(this);
+    WebGLMemoryTracker::AddWebGLContext(this);
 
     mAllowRestore = true;
     mContextLossTimerRunning = false;
     mDrawSinceContextLossTimerSet = false;
     mContextRestorer = do_CreateInstance("@mozilla.org/timer;1");
     mContextStatus = ContextNotLost;
     mContextLostErrorSet = false;
     mLoseContextOnHeapMinimize = false;
@@ -207,17 +207,17 @@ WebGLContext::WebGLContext()
     mDisableFragHighP = false;
 
     mDrawCallsSinceLastFlush = 0;
 }
 
 WebGLContext::~WebGLContext()
 {
     DestroyResourcesAndContext();
-    WebGLMemoryReporterWrapper::RemoveWebGLContext(this);
+    WebGLMemoryTracker::RemoveWebGLContext(this);
     TerminateContextLossTimer();
     mContextRestorer = nullptr;
 }
 
 void
 WebGLContext::DestroyResourcesAndContext()
 {
     if (mMemoryPressureObserver) {
@@ -664,18 +664,18 @@ void WebGLContext::LoseOldestWebGLContex
 #endif
     MOZ_ASSERT(kMaxWebGLContextsPerPrincipal < kMaxWebGLContexts);
 
     // it's important to update the index on a new context before losing old contexts,
     // otherwise new unused contexts would all have index 0 and we couldn't distinguish older ones
     // when choosing which one to lose first.
     UpdateLastUseIndex();
 
-    WebGLMemoryReporterWrapper::ContextsArrayType &contexts
-      = WebGLMemoryReporterWrapper::Contexts();
+    WebGLMemoryTracker::ContextsArrayType &contexts
+      = WebGLMemoryTracker::Contexts();
 
     // quick exit path, should cover a majority of cases
     if (contexts.Length() <= kMaxWebGLContextsPerPrincipal) {
         return;
     }
 
     // note that here by "context" we mean "non-lost context". See the check for
     // IsContextLost() below. Indeed, the point of this function is to maybe lose
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -117,17 +117,17 @@ class WebGLContext :
     public nsIDOMWebGLRenderingContext,
     public nsICanvasRenderingContextInternal,
     public nsSupportsWeakReference,
     public WebGLRectangleObject,
     public nsWrapperCache
 {
     friend class WebGLContextUserData;
     friend class WebGLMemoryPressureObserver;
-    friend class WebGLMemoryReporterWrapper;
+    friend class WebGLMemoryTracker;
     friend class WebGLExtensionLoseContext;
     friend class WebGLExtensionCompressedTextureS3TC;
     friend class WebGLExtensionCompressedTextureATC;
     friend class WebGLExtensionCompressedTexturePVRTC;
     friend class WebGLExtensionDepthTexture;
     friend class WebGLExtensionDrawBuffers;
     friend class WebGLExtensionVertexArray;
 
--- a/content/canvas/src/WebGLContextReporter.cpp
+++ b/content/canvas/src/WebGLContextReporter.cpp
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebGLContext.h"
-#include "WebGLMemoryReporterWrapper.h"
+#include "WebGLMemoryTracker.h"
 #include "nsIMemoryReporter.h"
 
 using namespace mozilla;
 
 NS_IMPL_ISUPPORTS1(WebGLMemoryPressureObserver, nsIObserver)
 
 class WebGLMemoryReporter MOZ_FINAL : public MemoryMultiReporter
 {
@@ -32,111 +32,113 @@ WebGLMemoryReporter::CollectReports(nsIM
       rv = aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), _kind,    \
                          _units, _amount, NS_LITERAL_CSTRING(_desc),          \
                          aClosure);                                           \
       NS_ENSURE_SUCCESS(rv, rv);                                              \
     } while (0)
 
     REPORT("webgl-texture-memory",
            nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_BYTES,
-           WebGLMemoryReporterWrapper::GetTextureMemoryUsed(),
+           WebGLMemoryTracker::GetTextureMemoryUsed(),
            "Memory used by WebGL textures.The OpenGL"
            " implementation is free to store these textures in either video"
            " memory or main memory. This measurement is only a lower bound,"
            " actual memory usage may be higher for example if the storage"
            " is strided.");
 
     REPORT("webgl-texture-count",
            nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT,
-           WebGLMemoryReporterWrapper::GetTextureCount(),
+           WebGLMemoryTracker::GetTextureCount(),
            "Number of WebGL textures.");
 
     REPORT("webgl-buffer-memory",
            nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_BYTES,
-           WebGLMemoryReporterWrapper::GetBufferMemoryUsed(),
+           WebGLMemoryTracker::GetBufferMemoryUsed(),
            "Memory used by WebGL buffers. The OpenGL"
            " implementation is free to store these buffers in either video"
            " memory or main memory. This measurement is only a lower bound,"
            " actual memory usage may be higher for example if the storage"
            " is strided.");
 
     REPORT("explicit/webgl/buffer-cache-memory",
            nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES,
-           WebGLMemoryReporterWrapper::GetBufferCacheMemoryUsed(),
+           WebGLMemoryTracker::GetBufferCacheMemoryUsed(),
            "Memory used by WebGL buffer caches. The WebGL"
            " implementation caches the contents of element array buffers"
            " only.This adds up with the webgl-buffer-memory value, but"
            " contrary to it, this one represents bytes on the heap,"
            " not managed by OpenGL.");
 
     REPORT("webgl-buffer-count",
            nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT,
-           WebGLMemoryReporterWrapper::GetBufferCount(),
+           WebGLMemoryTracker::GetBufferCount(),
            "Number of WebGL buffers.");
 
     REPORT("webgl-renderbuffer-memory",
            nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_BYTES,
-           WebGLMemoryReporterWrapper::GetRenderbufferMemoryUsed(),
+           WebGLMemoryTracker::GetRenderbufferMemoryUsed(),
            "Memory used by WebGL renderbuffers. The OpenGL"
            " implementation is free to store these renderbuffers in either"
            " video memory or main memory. This measurement is only a lower"
            " bound, actual memory usage may be higher for example if the"
            " storage is strided.");
 
     REPORT("webgl-renderbuffer-count",
            nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT,
-           WebGLMemoryReporterWrapper::GetRenderbufferCount(),
+           WebGLMemoryTracker::GetRenderbufferCount(),
            "Number of WebGL renderbuffers.");
 
     REPORT("explicit/webgl/shader",
            nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES,
-           WebGLMemoryReporterWrapper::GetShaderSize(),
+           WebGLMemoryTracker::GetShaderSize(),
            "Combined size of WebGL shader ASCII sources and translation"
            " logs cached on the heap.");
 
     REPORT("webgl-shader-count",
            nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT,
-           WebGLMemoryReporterWrapper::GetShaderCount(),
+           WebGLMemoryTracker::GetShaderCount(),
            "Number of WebGL shaders.");
 
     REPORT("webgl-context-count",
            nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT,
-           WebGLMemoryReporterWrapper::GetContextCount(),
+           WebGLMemoryTracker::GetContextCount(),
            "Number of WebGL contexts.");
 
 #undef REPORT
 
     return NS_OK;
 }
 
-WebGLMemoryReporterWrapper* WebGLMemoryReporterWrapper::sUniqueInstance = nullptr;
+NS_IMPL_ISUPPORTS1(WebGLMemoryTracker, nsISupports)
 
-WebGLMemoryReporterWrapper* WebGLMemoryReporterWrapper::UniqueInstance()
+StaticRefPtr<WebGLMemoryTracker> WebGLMemoryTracker::sUniqueInstance;
+
+WebGLMemoryTracker* WebGLMemoryTracker::UniqueInstance()
 {
     if (!sUniqueInstance) {
-        sUniqueInstance = new WebGLMemoryReporterWrapper;
+        sUniqueInstance = new WebGLMemoryTracker;
     }
     return sUniqueInstance;
 }
 
-WebGLMemoryReporterWrapper::WebGLMemoryReporterWrapper()
+WebGLMemoryTracker::WebGLMemoryTracker()
 {
     mReporter = new WebGLMemoryReporter;
     NS_RegisterMemoryReporter(mReporter);
 }
 
-WebGLMemoryReporterWrapper::~WebGLMemoryReporterWrapper()
+WebGLMemoryTracker::~WebGLMemoryTracker()
 {
     NS_UnregisterMemoryReporter(mReporter);
 }
 
 NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(WebGLBufferMallocSizeOf)
 
 int64_t
-WebGLMemoryReporterWrapper::GetBufferCacheMemoryUsed() {
+WebGLMemoryTracker::GetBufferCacheMemoryUsed() {
     const ContextsArrayType & contexts = Contexts();
     int64_t result = 0;
     for(size_t i = 0; i < contexts.Length(); ++i) {
         for (const WebGLBuffer *buffer = contexts[i]->mBuffers.getFirst();
              buffer;
              buffer = buffer->getNext())
         {
             if (buffer->Target() == LOCAL_GL_ELEMENT_ARRAY_BUFFER)
@@ -144,17 +146,17 @@ WebGLMemoryReporterWrapper::GetBufferCac
         }
     }
     return result;
 }
 
 NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(WebGLShaderMallocSizeOf)
 
 int64_t
-WebGLMemoryReporterWrapper::GetShaderSize() {
+WebGLMemoryTracker::GetShaderSize() {
     const ContextsArrayType & contexts = Contexts();
     int64_t result = 0;
     for(size_t i = 0; i < contexts.Length(); ++i) {
         for (const WebGLShader *shader = contexts[i]->mShaders.getFirst();
              shader;
              shader = shader->getNext())
         {
             result += shader->SizeOfIncludingThis(WebGLShaderMallocSizeOf);
rename from content/canvas/src/WebGLMemoryReporterWrapper.h
rename to content/canvas/src/WebGLMemoryTracker.h
--- a/content/canvas/src/WebGLMemoryReporterWrapper.h
+++ b/content/canvas/src/WebGLMemoryTracker.h
@@ -1,58 +1,60 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef WEBGLMEMORYREPORTERWRAPPER_H_
-#define WEBGLMEMORYREPORTERWRAPPER_H_
+#ifndef WEBGLMEMORYTRACKER_H_
+#define WEBGLMEMORYTRACKER_H_
 
 #include "WebGLContext.h"
 #include "WebGLBuffer.h"
 #include "WebGLVertexAttribData.h"
 #include "WebGLShader.h"
 #include "WebGLProgram.h"
 #include "WebGLUniformLocation.h"
 #include "WebGLTexture.h"
 #include "WebGLRenderbuffer.h"
+#include "mozilla/StaticPtr.h"
 
 namespace mozilla {
 
-class WebGLMemoryReporterWrapper
+class WebGLMemoryTracker : public nsISupports
 {
-    WebGLMemoryReporterWrapper();
-    ~WebGLMemoryReporterWrapper();
-    static WebGLMemoryReporterWrapper* sUniqueInstance;
+    NS_DECL_ISUPPORTS
+
+    WebGLMemoryTracker();
+    virtual ~WebGLMemoryTracker();
+    static StaticRefPtr<WebGLMemoryTracker> sUniqueInstance;
 
     // here we store plain pointers, not RefPtrs: we don't want the
-    // WebGLMemoryReporterWrapper unique instance to keep alive all
+    // WebGLMemoryTracker unique instance to keep alive all
     // WebGLContexts ever created.
     typedef nsTArray<const WebGLContext*> ContextsArrayType;
     ContextsArrayType mContexts;
 
     nsCOMPtr<nsIMemoryReporter> mReporter;
 
-    static WebGLMemoryReporterWrapper* UniqueInstance();
+    static WebGLMemoryTracker* UniqueInstance();
 
     static ContextsArrayType & Contexts() { return UniqueInstance()->mContexts; }
 
     friend class WebGLContext;
 
   public:
 
     static void AddWebGLContext(const WebGLContext* c) {
         Contexts().AppendElement(c);
     }
 
     static void RemoveWebGLContext(const WebGLContext* c) {
         ContextsArrayType & contexts = Contexts();
         contexts.RemoveElement(c);
         if (contexts.IsEmpty()) {
-            delete sUniqueInstance; 
             sUniqueInstance = nullptr;
         }
     }
 
     static int64_t GetTextureMemoryUsed() {
         const ContextsArrayType & contexts = Contexts();
         int64_t result = 0;
         for(size_t i = 0; i < contexts.Length(); ++i) {
--- a/content/events/src/nsDOMEventTargetHelper.cpp
+++ b/content/events/src/nsDOMEventTargetHelper.cpp
@@ -353,8 +353,22 @@ nsDOMEventTargetHelper::WantsUntrusted(b
   nsIScriptContext* context = GetContextForEventHandlers(&rv);
   NS_ENSURE_SUCCESS(rv, rv);
   nsCOMPtr<nsIDocument> doc =
     nsContentUtils::GetDocumentFromScriptContext(context);
   // We can let listeners on workers to always handle all the events.
   *aRetVal = (doc && !nsContentUtils::IsChromeDoc(doc)) || !NS_IsMainThread();
   return rv;
 }
+
+void
+nsDOMEventTargetHelper::EventListenerAdded(nsIAtom* aType)
+{
+  mozilla::ErrorResult rv;
+  EventListenerWasAdded(Substring(nsDependentAtomString(aType), 2), rv);
+}
+
+void
+nsDOMEventTargetHelper::EventListenerRemoved(nsIAtom* aType)
+{
+  mozilla::ErrorResult rv;
+  EventListenerWasRemoved(Substring(nsDependentAtomString(aType), 2), rv);
+}
--- a/content/events/src/nsDOMEventTargetHelper.h
+++ b/content/events/src/nsDOMEventTargetHelper.h
@@ -12,19 +12,24 @@
 #include "nsPIDOMWindow.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsEventListenerManager.h"
 #include "nsIScriptContext.h"
 #include "MainThreadUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/EventTarget.h"
 
+class JSCompartment;
+namespace mozilla {
+class ErrorResult;
+}
+
 #define NS_DOMEVENTTARGETHELPER_IID \
-{ 0xda0e6d40, 0xc17b, 0x4937, \
-  { 0x8e, 0xa2, 0x99, 0xca, 0x1c, 0x81, 0xea, 0xbe } }
+{ 0xa28385c6, 0x9451, 0x4d7e, \
+  { 0xa3, 0xdd, 0xf4, 0xb6, 0x87, 0x2f, 0xa4, 0x76 } }
 
 class nsDOMEventTargetHelper : public mozilla::dom::EventTarget
 {
 public:
   nsDOMEventTargetHelper()
     : mParentObject(nullptr)
     , mOwnerWindow(nullptr)
     , mHasOrHasHadOwnerWindow(false)
@@ -120,16 +125,25 @@ public:
 
   nsPIDOMWindow* GetOwner() const { return mOwnerWindow; }
   void BindToOwner(nsIGlobalObject* aOwner);
   void BindToOwner(nsPIDOMWindow* aOwner);
   void BindToOwner(nsDOMEventTargetHelper* aOther);
   virtual void DisconnectFromOwner();                   
   nsIGlobalObject* GetParentObject() const { return mParentObject; }
   bool HasOrHasHadOwner() { return mHasOrHasHadOwnerWindow; }
+
+  virtual void EventListenerAdded(nsIAtom* aType) MOZ_OVERRIDE;
+  virtual void EventListenerRemoved(nsIAtom* aType) MOZ_OVERRIDE;
+  virtual void EventListenerWasAdded(const nsAString& aType,
+                                     mozilla::ErrorResult& aRv,
+                                     JSCompartment* aCompartment = nullptr) {}
+  virtual void EventListenerWasRemoved(const nsAString& aType,
+                                       mozilla::ErrorResult& aRv,
+                                       JSCompartment* aCompartment = nullptr) {}
 protected:
   nsresult WantsUntrusted(bool* aRetVal);
 
   nsRefPtr<nsEventListenerManager> mListenerManager;
   // Dispatch a trusted, non-cancellable and non-bubbling event to |this|.
   nsresult DispatchTrustedEvent(const nsAString& aEventName);
   // Make |event| trusted and dispatch |aEvent| to |this|.
   nsresult DispatchTrustedEvent(nsIDOMEvent* aEvent);
--- a/content/events/src/nsEventListenerManager.cpp
+++ b/content/events/src/nsEventListenerManager.cpp
@@ -569,38 +569,37 @@ nsEventListenerManager::FindEventHandler
         EVENT_TYPE_EQUALS(ls, aEventType, aTypeAtom, aTypeString, false)) {
       return ls;
     }
   }
   return nullptr;
 }
 
 nsListenerStruct*
-nsEventListenerManager::SetEventHandlerInternal(nsIScriptContext *aContext,
-                                                JS::Handle<JSObject*> aScopeObject,
+nsEventListenerManager::SetEventHandlerInternal(JS::Handle<JSObject*> aScopeObject,
                                                 nsIAtom* aName,
                                                 const nsAString& aTypeString,
                                                 const nsEventHandler& aHandler,
                                                 bool aPermitUntrustedEvents)
 {
-  MOZ_ASSERT((aContext && aScopeObject) || aHandler.HasEventHandler(),
+  MOZ_ASSERT(aScopeObject || aHandler.HasEventHandler(),
              "Must have one or the other!");
   MOZ_ASSERT(aName || !aTypeString.IsEmpty());
 
   uint32_t eventType = nsContentUtils::GetEventId(aName);
   nsListenerStruct* ls = FindEventHandler(eventType, aName, aTypeString);
 
   if (!ls) {
     // If we didn't find a script listener or no listeners existed
     // create and add a new one.
     EventListenerFlags flags;
     flags.mListenerIsJSListener = true;
 
     nsCOMPtr<nsIJSEventListener> scriptListener;
-    NS_NewJSEventListener(aContext, aScopeObject, mTarget, aName,
+    NS_NewJSEventListener(aScopeObject, mTarget, aName,
                           aHandler, getter_AddRefs(scriptListener));
 
     if (!aName && aTypeString.EqualsLiteral("error")) {
       eventType = NS_LOAD_ERROR;
     }
 
     EventListenerHolder holder(scriptListener);
     AddEventListenerInternal(holder, eventType, aName, aTypeString, flags,
@@ -609,18 +608,18 @@ nsEventListenerManager::SetEventHandlerI
     ls = FindEventHandler(eventType, aName, aTypeString);
   } else {
     nsIJSEventListener* scriptListener = ls->GetJSListener();
     MOZ_ASSERT(scriptListener,
                "How can we have an event handler with no nsIJSEventListener?");
 
     bool same = scriptListener->GetHandler() == aHandler;
     // Possibly the same listener, but update still the context and scope.
-    scriptListener->SetHandler(aHandler, aContext, aScopeObject);
-    if (mTarget && !same) {
+    scriptListener->SetHandler(aHandler, aScopeObject);
+    if (mTarget && !same && aName) {
       mTarget->EventListenerRemoved(aName);
       mTarget->EventListenerAdded(aName);
     }
   }
 
   // Set flag to indicate possible need for compilation later
   ls->mHandlerIsString = !aHandler.HasEventHandler();
   if (aPermitUntrustedEvents) {
@@ -646,41 +645,19 @@ nsEventListenerManager::SetEventHandler(
   // such scripts based on the source of their code, not just the source
   // of the event.
   if (aPermitUntrustedEvents && 
       aLanguage != nsIProgrammingLanguage::JAVASCRIPT) {
     NS_WARNING("Discarding non-JS event listener from untrusted source");
     return NS_ERROR_FAILURE;
   }
 
-  nsCOMPtr<nsINode> node(do_QueryInterface(mTarget));
-
   nsCOMPtr<nsIDocument> doc;
-
-  nsCOMPtr<nsIScriptGlobalObject> global;
-
-  if (node) {
-    // Try to get context from doc
-    // XXX sXBL/XBL2 issue -- do we really want the owner here?  What
-    // if that's the XBL document?
-    doc = node->OwnerDoc();
-    MOZ_ASSERT(!doc->IsLoadedAsData(), "Should not get in here at all");
-
-    // We want to allow compiling an event handler even in an unloaded
-    // document, so use GetScopeObject here, not GetScriptHandlingObject.
-    global = do_QueryInterface(doc->GetScopeObject());
-  } else {
-    nsCOMPtr<nsPIDOMWindow> win = GetTargetAsInnerWindow();
-    if (win) {
-      doc = win->GetDoc();
-      global = do_QueryInterface(win);
-    } else {
-      global = do_QueryInterface(mTarget);
-    }
-  }
+  nsCOMPtr<nsIScriptGlobalObject> global =
+    GetScriptGlobalAndDocument(getter_AddRefs(doc));
 
   if (!global) {
     // This can happen; for example this document might have been
     // loaded as data.
     return NS_OK;
   }
 
 #ifdef DEBUG
@@ -749,23 +726,24 @@ nsEventListenerManager::SetEventHandler(
 
   nsIScriptContext* context = global->GetScriptContext();
   NS_ENSURE_TRUE(context, NS_ERROR_FAILURE);
 
   JSAutoRequest ar(context->GetNativeContext());
   JS::Rooted<JSObject*> scope(context->GetNativeContext(),
                               global->GetGlobalJSObject());
 
-  nsListenerStruct* ls = SetEventHandlerInternal(context, scope, aName,
+  nsListenerStruct* ls = SetEventHandlerInternal(scope, aName,
                                                  EmptyString(),
                                                  nsEventHandler(),
                                                  aPermitUntrustedEvents);
 
   if (!aDeferCompilation) {
-    return CompileEventHandlerInternal(ls, true, &aBody);
+    nsCxPusher pusher;
+    return CompileEventHandlerInternal(ls, pusher, &aBody);
   }
 
   return NS_OK;
 }
 
 void
 nsEventListenerManager::RemoveEventHandler(nsIAtom* aName,
                                            const nsAString& aTypeString)
@@ -784,38 +762,43 @@ nsEventListenerManager::RemoveEventHandl
     if (mTarget) {
       mTarget->EventListenerRemoved(aName);
     }
   }
 }
 
 nsresult
 nsEventListenerManager::CompileEventHandlerInternal(nsListenerStruct *aListenerStruct,
-                                                    bool aNeedsCxPush,
+                                                    nsCxPusher& aPusher,
                                                     const nsAString* aBody)
 {
   NS_PRECONDITION(aListenerStruct->GetJSListener(),
                   "Why do we not have a JS listener?");
   NS_PRECONDITION(aListenerStruct->mHandlerIsString,
                   "Why are we compiling a non-string JS listener?");
 
   nsresult result = NS_OK;
 
   nsIJSEventListener *listener = aListenerStruct->GetJSListener();
   NS_ASSERTION(!listener->GetHandler().HasEventHandler(),
                "What is there to compile?");
 
-  nsIScriptContext *context = listener->GetEventContext();
+  nsCOMPtr<nsIDocument> doc;
+  nsCOMPtr<nsIScriptGlobalObject> global =
+    GetScriptGlobalAndDocument(getter_AddRefs(doc));
+  NS_ENSURE_STATE(global);
+
+  nsIScriptContext* context = global->GetScriptContext();
+  NS_ENSURE_STATE(context);
+
   JSContext *cx = context->GetNativeContext();
   JS::Rooted<JSObject*> handler(cx);
 
-  nsCOMPtr<nsPIDOMWindow> win; // Will end up non-null if mTarget is a window
-
   nsCxPusher pusher;
-  if (aNeedsCxPush) {
+  if (aPusher.GetCurrentScriptContext() != context) {
     pusher.Push(cx);
   }
 
   if (aListenerStruct->mHandlerIsString) {
     // OK, we didn't find an existing compiled event handler.  Flag us
     // as not a string so we don't keep trying to compile strings
     // which can't be compiled
     aListenerStruct->mHandlerIsString = false;
@@ -854,26 +837,16 @@ nsEventListenerManager::CompileEventHand
         attrName = nsGkAtoms::onend;
 
       content->GetAttr(kNameSpaceID_None, attrName, handlerBody);
       body = &handlerBody;
     }
 
     uint32_t lineNo = 0;
     nsAutoCString url (NS_LITERAL_CSTRING("-moz-evil:lying-event-listener"));
-    nsCOMPtr<nsIDocument> doc;
-    if (content) {
-      doc = content->OwnerDoc();
-    } else {
-      win = do_QueryInterface(mTarget);
-      if (win) {
-        doc = win->GetExtantDoc();
-      }
-    }
-
     if (doc) {
       nsIURI *uri = doc->GetDocumentURI();
       if (uri) {
         uri->GetSpec(url);
         lineNo = 1;
       }
     }
 
@@ -899,16 +872,17 @@ nsEventListenerManager::CompileEventHand
                                         nsAtomCString(aListenerStruct->mTypeAtom),
                                         argCount, argNames, *body, handlerFun.address());
     NS_ENSURE_SUCCESS(result, result);
     handler = handlerFun;
     NS_ENSURE_TRUE(handler, NS_ERROR_FAILURE);
   }
 
   if (handler) {
+    nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mTarget);
     // Bind it
     JS::Rooted<JSObject*> boundHandler(cx);
     JS::Rooted<JSObject*> scope(cx, listener->GetEventScope());
     context->BindCompiledEventHandler(mTarget, scope, handler, &boundHandler);
     aListenerStruct = nullptr;
     if (!boundHandler) {
       listener->ForgetHandler();
     } else if (listener->EventName() == nsGkAtoms::onerror && win) {
@@ -937,21 +911,17 @@ nsEventListenerManager::HandleEventSubTy
 {
   nsresult result = NS_OK;
   EventListenerHolder listener(aListenerStruct->mListener);  // strong ref
 
   // If this is a script handler and we haven't yet
   // compiled the event handler itself
   if ((aListenerStruct->mListenerType == eJSEventListener) &&
       aListenerStruct->mHandlerIsString) {
-    nsIJSEventListener *jslistener = aListenerStruct->GetJSListener();
-    result = CompileEventHandlerInternal(aListenerStruct,
-                                         jslistener->GetEventContext() !=
-                                           aPusher->GetCurrentScriptContext(),
-                                         nullptr);
+    result = CompileEventHandlerInternal(aListenerStruct, *aPusher, nullptr);
     aListenerStruct = nullptr;
   }
 
   if (NS_SUCCEEDED(result)) {
     if (mIsMainThreadELM) {
       nsContentUtils::EnterMicroTask();
     }
     // nsIDOMEvent::currentTarget is set in nsEventDispatcher.
@@ -1192,18 +1162,19 @@ nsEventListenerManager::GetListenerInfo(
   NS_ENSURE_STATE(target);
   aList->Clear();
   uint32_t count = mListeners.Length();
   for (uint32_t i = 0; i < count; ++i) {
     const nsListenerStruct& ls = mListeners.ElementAt(i);
     // If this is a script handler and we haven't yet
     // compiled the event handler itself go ahead and compile it
     if ((ls.mListenerType == eJSEventListener) && ls.mHandlerIsString) {
+      nsCxPusher pusher;
       CompileEventHandlerInternal(const_cast<nsListenerStruct*>(&ls),
-                                  true, nullptr);
+                                  pusher, nullptr);
     }
     nsAutoString eventType;
     if (ls.mAllEvents) {
       eventType.SetIsVoid(true);
     } else {
       eventType.Assign(Substring(nsDependentAtomString(ls.mTypeAtom), 2));
     }
     // EventListenerInfo is defined in XPCOM, so we have to go ahead
@@ -1239,60 +1210,60 @@ nsEventListenerManager::SetEventHandler(
 {
   if (!aHandler) {
     RemoveEventHandler(aEventName, aTypeString);
     return;
   }
 
   // Untrusted events are always permitted for non-chrome script
   // handlers.
-  SetEventHandlerInternal(nullptr, JS::NullPtr(), aEventName,
+  SetEventHandlerInternal(JS::NullPtr(), aEventName,
                           aTypeString, nsEventHandler(aHandler),
                           !mIsMainThreadELM ||
                           !nsContentUtils::IsCallerChrome());
 }
 
 void
 nsEventListenerManager::SetEventHandler(OnErrorEventHandlerNonNull* aHandler)
 {
   if (mIsMainThreadELM) {
     if (!aHandler) {
       RemoveEventHandler(nsGkAtoms::onerror, EmptyString());
       return;
     }
 
     // Untrusted events are always permitted for non-chrome script
     // handlers.
-    SetEventHandlerInternal(nullptr, JS::NullPtr(), nsGkAtoms::onerror,
+    SetEventHandlerInternal(JS::NullPtr(), nsGkAtoms::onerror,
                             EmptyString(), nsEventHandler(aHandler),
                             !nsContentUtils::IsCallerChrome());
   } else {
     if (!aHandler) {
       RemoveEventHandler(nullptr, NS_LITERAL_STRING("error"));
       return;
     }
 
     // Untrusted events are always permitted.
-    SetEventHandlerInternal(nullptr, JS::NullPtr(), nullptr,
+    SetEventHandlerInternal(JS::NullPtr(), nullptr,
                             NS_LITERAL_STRING("error"),
                             nsEventHandler(aHandler), true);
   }
 }
 
 void
 nsEventListenerManager::SetEventHandler(OnBeforeUnloadEventHandlerNonNull* aHandler)
 {
   if (!aHandler) {
     RemoveEventHandler(nsGkAtoms::onbeforeunload, EmptyString());
     return;
   }
 
   // Untrusted events are always permitted for non-chrome script
   // handlers.
-  SetEventHandlerInternal(nullptr, JS::NullPtr(), nsGkAtoms::onbeforeunload,
+  SetEventHandlerInternal(JS::NullPtr(), nsGkAtoms::onbeforeunload,
                           EmptyString(), nsEventHandler(aHandler),
                           !mIsMainThreadELM ||
                           !nsContentUtils::IsCallerChrome());
 }
 
 const nsEventHandler*
 nsEventListenerManager::GetEventHandlerInternal(nsIAtom *aEventName,
                                                 const nsAString& aTypeString)
@@ -1302,17 +1273,18 @@ nsEventListenerManager::GetEventHandlerI
 
   if (!ls) {
     return nullptr;
   }
 
   nsIJSEventListener *listener = ls->GetJSListener();
     
   if (ls->mHandlerIsString) {
-    CompileEventHandlerInternal(ls, true, nullptr);
+    nsCxPusher pusher;
+    CompileEventHandlerInternal(ls, pusher, nullptr);
   }
 
   const nsEventHandler& handler = listener->GetHandler();
   if (handler.HasEventHandler()) {
     return &handler;
   }
 
   return nullptr;
@@ -1354,8 +1326,38 @@ nsEventListenerManager::MarkForCC()
       // Callback() unmarks gray
       ls.mListener.GetWebIDLCallback()->Callback();
     }
   }
   if (mRefCnt.IsPurple()) {
     mRefCnt.RemovePurple();
   }
 }
+
+already_AddRefed<nsIScriptGlobalObject>
+nsEventListenerManager::GetScriptGlobalAndDocument(nsIDocument** aDoc)
+{
+  nsCOMPtr<nsINode> node(do_QueryInterface(mTarget));
+  nsCOMPtr<nsIDocument> doc;
+  nsCOMPtr<nsIScriptGlobalObject> global;
+  if (node) {
+    // Try to get context from doc
+    // XXX sXBL/XBL2 issue -- do we really want the owner here?  What
+    // if that's the XBL document?
+    doc = node->OwnerDoc();
+    MOZ_ASSERT(!doc->IsLoadedAsData(), "Should not get in here at all");
+
+    // We want to allow compiling an event handler even in an unloaded
+    // document, so use GetScopeObject here, not GetScriptHandlingObject.
+    global = do_QueryInterface(doc->GetScopeObject());
+  } else {
+    nsCOMPtr<nsPIDOMWindow> win = GetTargetAsInnerWindow();
+    if (win) {
+      doc = win->GetExtantDoc();
+      global = do_QueryInterface(win);
+    } else {
+      global = do_QueryInterface(mTarget);
+    }
+  }
+
+  doc.forget(aDoc);
+  return global.forget();
+}
--- a/content/events/src/nsEventListenerManager.h
+++ b/content/events/src/nsEventListenerManager.h
@@ -422,35 +422,34 @@ protected:
                               nsCxPusher* aPusher);
 
   /**
    * Compile the "inline" event listener for aListenerStruct.  The
    * body of the listener can be provided in aBody; if this is null we
    * will look for it on mTarget.
    */
   nsresult CompileEventHandlerInternal(nsListenerStruct *aListenerStruct,
-                                       bool aNeedsCxPush,
+                                       nsCxPusher& aPusher,
                                        const nsAString* aBody);
 
   /**
    * Find the nsListenerStruct for the "inline" event listener for aTypeAtom.
    */
   nsListenerStruct* FindEventHandler(uint32_t aEventType, nsIAtom* aTypeAtom,
                                      const nsAString& aTypeString);
 
   /**
    * Set the "inline" event listener for aName to aHandler.  aHandler may be
    * have no actual handler set to indicate that we should lazily get and
    * compile the string for this listener, but in that case aContext and
    * aScopeGlobal must be non-null.  Otherwise, aContext and aScopeGlobal are
    * allowed to be null.  The nsListenerStruct that results, if any, is returned
    * in aListenerStruct.
    */
-  nsListenerStruct* SetEventHandlerInternal(nsIScriptContext *aContext,
-                                            JS::Handle<JSObject*> aScopeGlobal,
+  nsListenerStruct* SetEventHandlerInternal(JS::Handle<JSObject*> aScopeGlobal,
                                             nsIAtom* aName,
                                             const nsAString& aTypeString,
                                             const nsEventHandler& aHandler,
                                             bool aPermitUntrustedEvents);
 
   bool IsDeviceType(uint32_t aType);
   void EnableDevice(uint32_t aType);
   void DisableDevice(uint32_t aType);
@@ -533,16 +532,19 @@ protected:
   void RemoveAllListeners();
   const EventTypeData* GetTypeDataForIID(const nsIID& aIID);
   const EventTypeData* GetTypeDataForEventName(nsIAtom* aName);
   nsPIDOMWindow* GetInnerWindowForTarget();
   already_AddRefed<nsPIDOMWindow> GetTargetAsInnerWindow() const;
 
   bool ListenerCanHandle(nsListenerStruct* aLs, mozilla::WidgetEvent* aEvent);
 
+  already_AddRefed<nsIScriptGlobalObject>
+  GetScriptGlobalAndDocument(nsIDocument** aDoc);
+
   uint32_t mMayHavePaintEventListener : 1;
   uint32_t mMayHaveMutationListeners : 1;
   uint32_t mMayHaveCapturingListeners : 1;
   uint32_t mMayHaveSystemGroupListeners : 1;
   uint32_t mMayHaveAudioAvailableEventListener : 1;
   uint32_t mMayHaveTouchEventListener : 1;
   uint32_t mMayHaveMouseEnterLeaveEventListener : 1;
   uint32_t mClearingListeners : 1;
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -3315,18 +3315,19 @@ HTMLInputElement::PreHandleEvent(nsEvent
   return rv;
 }
 
 void
 HTMLInputElement::StartRangeThumbDrag(WidgetGUIEvent* aEvent)
 {
   mIsDraggingRange = true;
   mRangeThumbDragStartValue = GetValueAsDecimal();
-  nsIPresShell::SetCapturingContent(this, CAPTURE_IGNOREALLOWED |
-                                          CAPTURE_RETARGETTOELEMENT);
+  // Don't use CAPTURE_RETARGETTOELEMENT, as that breaks pseudo-class styling
+  // of the thumb.
+  nsIPresShell::SetCapturingContent(this, CAPTURE_IGNOREALLOWED);
   nsRangeFrame* rangeFrame = do_QueryFrame(GetPrimaryFrame());
 
   // Before we change the value, record the current value so that we'll
   // correctly send a 'change' event if appropriate. We need to do this here
   // because the 'focus' event is handled after the 'mousedown' event that
   // we're being called for (i.e. too late to update mFocusedValue, since we'll
   // have changed it by then).
   GetValueInternal(mFocusedValue);
--- a/content/media/MediaDecoder.cpp
+++ b/content/media/MediaDecoder.cpp
@@ -13,16 +13,17 @@
 #include "VideoUtils.h"
 #include "MediaDecoderStateMachine.h"
 #include "mozilla/dom/TimeRanges.h"
 #include "nsContentUtils.h"
 #include "ImageContainer.h"
 #include "MediaResource.h"
 #include "nsError.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/StaticPtr.h"
 #include "nsIMemoryReporter.h"
 #include "nsComponentManagerUtils.h"
 #include "nsITimer.h"
 #include <algorithm>
 
 #ifdef MOZ_WMF
 #include "WMFDecoder.h"
 #endif
@@ -48,21 +49,23 @@ static const int64_t CAN_PLAY_THROUGH_MA
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* gMediaDecoderLog;
 #define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
 #else
 #define DECODER_LOG(type, msg)
 #endif
 
-class MediaMemoryTracker
+class MediaMemoryTracker : public nsISupports
 {
+  NS_DECL_ISUPPORTS
+
   MediaMemoryTracker();
-  ~MediaMemoryTracker();
-  static MediaMemoryTracker* sUniqueInstance;
+  virtual ~MediaMemoryTracker();
+  static StaticRefPtr<MediaMemoryTracker> sUniqueInstance;
 
   static MediaMemoryTracker* UniqueInstance() {
     if (!sUniqueInstance) {
       sUniqueInstance = new MediaMemoryTracker();
     }
     return sUniqueInstance;
   }
 
@@ -81,34 +84,35 @@ public:
     Decoders().AppendElement(aDecoder);
   }
 
   static void RemoveMediaDecoder(MediaDecoder* aDecoder)
   {
     DecodersArray& decoders = Decoders();
     decoders.RemoveElement(aDecoder);
     if (decoders.IsEmpty()) {
-      delete sUniqueInstance;
       sUniqueInstance = nullptr;
     }
   }
 
   static void GetAmounts(int64_t* aVideo, int64_t* aAudio)
   {
     *aVideo = 0;
     *aAudio = 0;
     DecodersArray& decoders = Decoders();
     for (size_t i = 0; i < decoders.Length(); ++i) {
       *aVideo += decoders[i]->VideoQueueMemoryInUse();
       *aAudio += decoders[i]->AudioQueueMemoryInUse();
     }
   }
 };
 
-MediaMemoryTracker* MediaMemoryTracker::sUniqueInstance = nullptr;
+StaticRefPtr<MediaMemoryTracker> MediaMemoryTracker::sUniqueInstance;
+
+NS_IMPL_ISUPPORTS1(MediaMemoryTracker, nsISupports)
 
 NS_IMPL_ISUPPORTS1(MediaDecoder, nsIObserver)
 
 void MediaDecoder::SetDormantIfNecessary(bool aDormant)
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
 
--- a/content/media/fmp4/MP4Reader.cpp
+++ b/content/media/fmp4/MP4Reader.cpp
@@ -88,72 +88,96 @@ MP4Reader::MP4Reader(AbstractMediaDecode
   MOZ_COUNT_CTOR(MP4Reader);
 }
 
 MP4Reader::~MP4Reader()
 {
   MOZ_COUNT_DTOR(MP4Reader);
 }
 
+void
+MP4Reader::InitLayersBackendType()
+{
+  if (!IsVideoContentType(mDecoder->GetResource()->GetContentType())) {
+    // Not playing video, we don't care about the layers backend type.
+    return;
+  }
+  // Extract the layer manager backend type so that platform decoders
+  // can determine whether it's worthwhile using hardware accelerated
+  // video decoding.
+  MediaDecoderOwner* owner = mDecoder->GetOwner();
+  if (!owner) {
+    NS_WARNING("MP4Reader without a decoder owner, can't get HWAccel");
+    return;
+  }
+
+  dom::HTMLMediaElement* element = owner->GetMediaElement();
+  NS_ENSURE_TRUE_VOID(element);
+
+  nsRefPtr<LayerManager> layerManager =
+    nsContentUtils::LayerManagerForDocument(element->OwnerDoc());
+  NS_ENSURE_TRUE_VOID(layerManager);
+
+  mLayersBackendType = layerManager->GetBackendType();
+}
+
 nsresult
 MP4Reader::Init(MediaDecoderReader* aCloneDonor)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
   mMP4Stream = new MP4Stream(mDecoder->GetResource());
   mDemuxer = new MP4Demuxer(mMP4Stream);
 
   mPlatform = PlatformDecoderModule::Create();
   NS_ENSURE_TRUE(mPlatform, NS_ERROR_FAILURE);
 
-  if (IsVideoContentType(mDecoder->GetResource()->GetContentType())) {
-    // Extract the layer manager backend type so that platform decoders
-    // can determine whether it's worthwhile using hardware accelerated
-    // video decoding.
-    MediaDecoderOwner* owner = mDecoder->GetOwner();
-    NS_ENSURE_TRUE(owner, NS_ERROR_FAILURE);
-
-    dom::HTMLMediaElement* element = owner->GetMediaElement();
-    NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
-
-    nsRefPtr<LayerManager> layerManager =
-      nsContentUtils::LayerManagerForDocument(element->OwnerDoc());
-    NS_ENSURE_TRUE(layerManager, NS_ERROR_FAILURE);
-
-    mLayersBackendType = layerManager->GetBackendType();
-  }
+  InitLayersBackendType();
 
   return NS_OK;
 }
 
 nsresult
 MP4Reader::ReadMetadata(MediaInfo* aInfo,
                         MetadataTags** aTags)
 {
   bool ok = mDemuxer->Init();
   NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
 
-  mInfo.mAudio.mHasAudio = mHasAudio = mDemuxer->HasAudio();
+  const AudioDecoderConfig& audio = mDemuxer->AudioConfig();
+  mInfo.mAudio.mHasAudio = mHasAudio = mDemuxer->HasAudio() &&
+                                       audio.IsValidConfig();
+  // If we have audio, we *only* allow AAC to be decoded.
+  if (mHasAudio && audio.codec() != kCodecAAC) {
+    return NS_ERROR_FAILURE;
+  }
+
+  const VideoDecoderConfig& video = mDemuxer->VideoConfig();
+  mInfo.mVideo.mHasVideo = mHasVideo = mDemuxer->HasVideo() &&
+                                       video.IsValidConfig();
+  // If we have video, we *only* allow H.264 to be decoded.
+  if (mHasVideo && video.codec() != kCodecH264) {
+    return NS_ERROR_FAILURE;
+  }
+
   if (mHasAudio) {
-    const AudioDecoderConfig& config = mDemuxer->AudioConfig();
-    mInfo.mAudio.mRate = config.samples_per_second();
-    mInfo.mAudio.mChannels = ChannelLayoutToChannelCount(config.channel_layout());
+    mInfo.mAudio.mRate = audio.samples_per_second();
+    mInfo.mAudio.mChannels = ChannelLayoutToChannelCount(audio.channel_layout());
     mAudioDecoder = mPlatform->CreateAudioDecoder(mInfo.mAudio.mChannels,
                                                   mInfo.mAudio.mRate,
-                                                  config.bits_per_channel(),
-                                                  config.extra_data(),
-                                                  config.extra_data_size());
+                                                  audio.bits_per_channel(),
+                                                  audio.extra_data(),
+                                                  audio.extra_data_size());
     NS_ENSURE_TRUE(mAudioDecoder != nullptr, NS_ERROR_FAILURE);
   }
 
   mInfo.mVideo.mHasVideo = mHasVideo = mDemuxer->HasVideo();
   if (mHasVideo) {
     const VideoDecoderConfig& config = mDemuxer->VideoConfig();
     IntSize sz = config.natural_size();
     mInfo.mVideo.mDisplay = nsIntSize(sz.width(), sz.height());
-
     mVideoDecoder = mPlatform->CreateVideoDecoder(mLayersBackendType,
                                                   mDecoder->GetImageContainer());
     NS_ENSURE_TRUE(mVideoDecoder != nullptr, NS_ERROR_FAILURE);
   }
 
   // Get the duration, and report it to the decoder if we have it.
   Microseconds duration = mDemuxer->Duration();
   if (duration != -1) {
--- a/content/media/fmp4/MP4Reader.h
+++ b/content/media/fmp4/MP4Reader.h
@@ -48,16 +48,18 @@ public:
                         int64_t aStartTime,
                         int64_t aEndTime,
                         int64_t aCurrentTime) MOZ_OVERRIDE;
 
   virtual void OnDecodeThreadStart() MOZ_OVERRIDE;
   virtual void OnDecodeThreadFinish() MOZ_OVERRIDE;
 
 private:
+  // Initializes mLayersBackendType if possible.
+  void InitLayersBackendType();
 
   MP4SampleQueue& SampleQueue(mp4_demuxer::TrackType aTrack);
 
   // Blocks until the demuxer produces an sample of specified type.
   // Returns nullptr on error on EOS. Caller must delete sample.
   mp4_demuxer::MP4Sample* PopSample(mp4_demuxer::TrackType aTrack);
 
   bool Decode(mp4_demuxer::TrackType aTrack,
--- a/content/svg/content/src/SVGComponentTransferFunctionElement.h
+++ b/content/svg/content/src/SVGComponentTransferFunctionElement.h
@@ -28,26 +28,29 @@ class SVGComponentTransferFunctionElemen
 {
 protected:
   SVGComponentTransferFunctionElement(already_AddRefed<nsINodeInfo> aNodeInfo)
     : SVGComponentTransferFunctionElementBase(aNodeInfo)
   {
   }
 
 public:
+  typedef gfx::AttributeMap AttributeMap;
+
   // interfaces:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_SVG_FE_COMPONENT_TRANSFER_FUNCTION_ELEMENT_CID)
 
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const MOZ_OVERRIDE;
 
   virtual int32_t GetChannel() = 0;
-  bool GenerateLookupTable(uint8_t* aTable);
+
+  AttributeMap ComputeAttributes();
 
   // WebIDL
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE = 0;
   already_AddRefed<SVGAnimatedEnumeration> Type();
   already_AddRefed<DOMSVGAnimatedNumberList> TableValues();
   already_AddRefed<SVGAnimatedNumber> Slope();
   already_AddRefed<SVGAnimatedNumber> Intercept();
--- a/content/svg/content/src/SVGFEBlendElement.cpp
+++ b/content/svg/content/src/SVGFEBlendElement.cpp
@@ -4,16 +4,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGFEBlendElement.h"
 #include "mozilla/dom/SVGFEBlendElementBinding.h"
 #include "nsSVGUtils.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEBlend)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGFEBlendElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGFEBlendElementBinding::Wrap(aCx, aScope, this);
 }
@@ -63,70 +65,25 @@ SVGFEBlendElement::In2()
 }
 
 already_AddRefed<SVGAnimatedEnumeration>
 SVGFEBlendElement::Mode()
 {
   return mEnumAttributes[MODE].ToDOMAnimatedEnum(this);
 }
 
-nsresult
-SVGFEBlendElement::Filter(nsSVGFilterInstance* aInstance,
-                          const nsTArray<const Image*>& aSources,
-                          const Image* aTarget,
-                          const nsIntRect& rect)
+FilterPrimitiveDescription
+SVGFEBlendElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                                           const IntRect& aFilterSubregion,
+                                           nsTArray<nsRefPtr<gfxASurface> >& aInputImages)
 {
-  CopyRect(aTarget, aSources[0], rect);
-
-  uint8_t* sourceData = aSources[1]->mImage->Data();
-  uint8_t* targetData = aTarget->mImage->Data();
-  uint32_t stride = aTarget->mImage->Stride();
-
-  uint16_t mode = mEnumAttributes[MODE].GetAnimValue();
-
-  for (int32_t x = rect.x; x < rect.XMost(); x++) {
-    for (int32_t y = rect.y; y < rect.YMost(); y++) {
-      uint32_t targIndex = y * stride + 4 * x;
-      uint32_t qa = targetData[targIndex + GFX_ARGB32_OFFSET_A];
-      uint32_t qb = sourceData[targIndex + GFX_ARGB32_OFFSET_A];
-      for (int32_t i = std::min(GFX_ARGB32_OFFSET_B, GFX_ARGB32_OFFSET_R);
-           i <= std::max(GFX_ARGB32_OFFSET_B, GFX_ARGB32_OFFSET_R); i++) {
-        uint32_t ca = targetData[targIndex + i];
-        uint32_t cb = sourceData[targIndex + i];
-        uint32_t val;
-        switch (mode) {
-          case SVG_FEBLEND_MODE_NORMAL:
-            val = (255 - qa) * cb + 255 * ca;
-            break;
-          case SVG_FEBLEND_MODE_MULTIPLY:
-            val = ((255 - qa) * cb + (255 - qb + cb) * ca);
-            break;
-          case SVG_FEBLEND_MODE_SCREEN:
-            val = 255 * (cb + ca) - ca * cb;
-            break;
-          case SVG_FEBLEND_MODE_DARKEN:
-            val = std::min((255 - qa) * cb + 255 * ca,
-                         (255 - qb) * ca + 255 * cb);
-            break;
-          case SVG_FEBLEND_MODE_LIGHTEN:
-            val = std::max((255 - qa) * cb + 255 * ca,
-                         (255 - qb) * ca + 255 * cb);
-            break;
-          default:
-            return NS_ERROR_FAILURE;
-            break;
-        }
-        val = std::min(val / 255, 255U);
-        targetData[targIndex + i] =  static_cast<uint8_t>(val);
-      }
-      uint32_t alpha = 255 * 255 - (255 - qa) * (255 - qb);
-      FAST_DIVIDE_BY_255(targetData[targIndex + GFX_ARGB32_OFFSET_A], alpha);
-    }
-  }
-  return NS_OK;
+  uint32_t mode = mEnumAttributes[MODE].GetAnimValue();
+  FilterPrimitiveDescription descr(FilterPrimitiveDescription::eBlend);
+  descr.Attributes().Set(eBlendBlendmode, mode);
+  return descr;
 }
 
 bool
 SVGFEBlendElement::AttributeAffectsRendering(int32_t aNameSpaceID,
                                              nsIAtom* aAttribute) const
 {
   return SVGFEBlendElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
          (aNameSpaceID == kNameSpaceID_None &&
--- a/content/svg/content/src/SVGFEBlendElement.h
+++ b/content/svg/content/src/SVGFEBlendElement.h
@@ -9,42 +9,35 @@
 #include "nsSVGFilters.h"
 #include "nsSVGEnum.h"
 
 nsresult NS_NewSVGFEBlendElement(nsIContent **aResult,
                                  already_AddRefed<nsINodeInfo> aNodeInfo);
 namespace mozilla {
 namespace dom {
 
-static const unsigned short SVG_FEBLEND_MODE_UNKNOWN = 0;
-static const unsigned short SVG_FEBLEND_MODE_NORMAL = 1;
-static const unsigned short SVG_FEBLEND_MODE_MULTIPLY = 2;
-static const unsigned short SVG_FEBLEND_MODE_SCREEN = 3;
-static const unsigned short SVG_FEBLEND_MODE_DARKEN = 4;
-static const unsigned short SVG_FEBLEND_MODE_LIGHTEN = 5;
-
 typedef nsSVGFE SVGFEBlendElementBase;
 
 class SVGFEBlendElement : public SVGFEBlendElementBase
 {
   friend nsresult (::NS_NewSVGFEBlendElement(nsIContent **aResult,
                                              already_AddRefed<nsINodeInfo> aNodeInfo));
 protected:
   SVGFEBlendElement(already_AddRefed<nsINodeInfo> aNodeInfo)
     : SVGFEBlendElementBase(aNodeInfo)
   {
   }
   virtual JSObject* WrapNode(JSContext *cx,
                              JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
 
 public:
-  virtual nsresult Filter(nsSVGFilterInstance* aInstance,
-                          const nsTArray<const Image*>& aSources,
-                          const Image* aTarget,
-                          const nsIntRect& aDataRect) MOZ_OVERRIDE;
+  virtual FilterPrimitiveDescription
+    GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                            const IntRect& aFilterSubregion,
+                            nsTArray<nsRefPtr<gfxASurface> >& aInputImages) MOZ_OVERRIDE;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const MOZ_OVERRIDE;
   virtual nsSVGString& GetResultImageName() MOZ_OVERRIDE { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
--- a/content/svg/content/src/SVGFEColorMatrixElement.cpp
+++ b/content/svg/content/src/SVGFEColorMatrixElement.cpp
@@ -7,16 +7,18 @@
 #include "mozilla/dom/SVGFEColorMatrixElement.h"
 #include "mozilla/dom/SVGFEColorMatrixElementBinding.h"
 #include "nsSVGUtils.h"
 
 #define NUM_ENTRIES_IN_4x5_MATRIX 20
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEColorMatrix)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGFEColorMatrixElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGFEColorMatrixElementBinding::Wrap(aCx, aScope, this);
 }
@@ -77,152 +79,45 @@ SVGFEColorMatrixElement::Values()
 }
 
 void
 SVGFEColorMatrixElement::GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources)
 {
   aSources.AppendElement(nsSVGStringInfo(&mStringAttributes[IN1], this));
 }
 
-nsresult
-SVGFEColorMatrixElement::Filter(nsSVGFilterInstance* instance,
-                                const nsTArray<const Image*>& aSources,
-                                const Image* aTarget,
-                                const nsIntRect& rect)
+FilterPrimitiveDescription
+SVGFEColorMatrixElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                                                 const IntRect& aFilterSubregion,
+                                                 nsTArray<nsRefPtr<gfxASurface> >& aInputImages)
 {
-  uint8_t* sourceData = aSources[0]->mImage->Data();
-  uint8_t* targetData = aTarget->mImage->Data();
-  uint32_t stride = aTarget->mImage->Stride();
-
-  uint16_t type = mEnumAttributes[TYPE].GetAnimValue();
+  uint32_t type = mEnumAttributes[TYPE].GetAnimValue();
   const SVGNumberList &values = mNumberListAttributes[VALUES].GetAnimValue();
 
+  FilterPrimitiveDescription descr(FilterPrimitiveDescription::eColorMatrix);
   if (!mNumberListAttributes[VALUES].IsExplicitlySet() &&
       (type == SVG_FECOLORMATRIX_TYPE_MATRIX ||
        type == SVG_FECOLORMATRIX_TYPE_SATURATE ||
        type == SVG_FECOLORMATRIX_TYPE_HUE_ROTATE)) {
-    // identity matrix filter
-    CopyRect(aTarget, aSources[0], rect);
-    return NS_OK;
-  }
-
-  static const float identityMatrix[] = 
-    { 1, 0, 0, 0, 0,
-      0, 1, 0, 0, 0,
-      0, 0, 1, 0, 0,
-      0, 0, 0, 1, 0 };
-
-  static const float luminanceToAlphaMatrix[] = 
-    { 0,       0,       0,       0, 0,
-      0,       0,       0,       0, 0,
-      0,       0,       0,       0, 0,
-      0.2125f, 0.7154f, 0.0721f, 0, 0 };
-
-  float colorMatrix[NUM_ENTRIES_IN_4x5_MATRIX];
-  float s, c;
-
-  switch (type) {
-  case SVG_FECOLORMATRIX_TYPE_MATRIX:
-
-    if (values.Length() != NUM_ENTRIES_IN_4x5_MATRIX)
-      return NS_ERROR_FAILURE;
-
-    for(uint32_t j = 0; j < values.Length(); j++) {
-      colorMatrix[j] = values[j];
-    }
-    break;
-  case SVG_FECOLORMATRIX_TYPE_SATURATE:
-
-    if (values.Length() != 1)
-      return NS_ERROR_FAILURE;
-
-    s = values[0];
-
-    if (s > 1 || s < 0)
-      return NS_ERROR_FAILURE;
-
-    memcpy(colorMatrix, identityMatrix, sizeof(colorMatrix));
-
-    colorMatrix[0] = 0.213f + 0.787f * s;
-    colorMatrix[1] = 0.715f - 0.715f * s;
-    colorMatrix[2] = 0.072f - 0.072f * s;
-
-    colorMatrix[5] = 0.213f - 0.213f * s;
-    colorMatrix[6] = 0.715f + 0.285f * s;
-    colorMatrix[7] = 0.072f - 0.072f * s;
-
-    colorMatrix[10] = 0.213f - 0.213f * s;
-    colorMatrix[11] = 0.715f - 0.715f * s;
-    colorMatrix[12] = 0.072f + 0.928f * s;
-
-    break;
-
-  case SVG_FECOLORMATRIX_TYPE_HUE_ROTATE:
-  {
-    memcpy(colorMatrix, identityMatrix, sizeof(colorMatrix));
-
-    if (values.Length() != 1)
-      return NS_ERROR_FAILURE;
-
-    float hueRotateValue = values[0];
-
-    c = static_cast<float>(cos(hueRotateValue * M_PI / 180));
-    s = static_cast<float>(sin(hueRotateValue * M_PI / 180));
-
-    memcpy(colorMatrix, identityMatrix, sizeof(colorMatrix));
-
-    colorMatrix[0] = 0.213f + 0.787f * c - 0.213f * s;
-    colorMatrix[1] = 0.715f - 0.715f * c - 0.715f * s;
-    colorMatrix[2] = 0.072f - 0.072f * c + 0.928f * s;
-
-    colorMatrix[5] = 0.213f - 0.213f * c + 0.143f * s;
-    colorMatrix[6] = 0.715f + 0.285f * c + 0.140f * s;
-    colorMatrix[7] = 0.072f - 0.072f * c - 0.283f * s;
-
-    colorMatrix[10] = 0.213f - 0.213f * c - 0.787f * s;
-    colorMatrix[11] = 0.715f - 0.715f * c + 0.715f * s;
-    colorMatrix[12] = 0.072f + 0.928f * c + 0.072f * s;
-
-    break;
-  }
-
-  case SVG_FECOLORMATRIX_TYPE_LUMINANCE_TO_ALPHA:
-
-    memcpy(colorMatrix, luminanceToAlphaMatrix, sizeof(colorMatrix));
-    break;
-
-  default:
-    return NS_ERROR_FAILURE;
-  }
-
-  for (int32_t x = rect.x; x < rect.XMost(); x++) {
-    for (int32_t y = rect.y; y < rect.YMost(); y++) {
-      uint32_t targIndex = y * stride + 4 * x;
-
-      float col[4];
-      for (int i = 0, row = 0; i < 4; i++, row += 5) {
-        col[i] =
-          sourceData[targIndex + GFX_ARGB32_OFFSET_R] * colorMatrix[row + 0] +
-          sourceData[targIndex + GFX_ARGB32_OFFSET_G] * colorMatrix[row + 1] +
-          sourceData[targIndex + GFX_ARGB32_OFFSET_B] * colorMatrix[row + 2] +
-          sourceData[targIndex + GFX_ARGB32_OFFSET_A] * colorMatrix[row + 3] +
-          255 *                                         colorMatrix[row + 4];
-        col[i] = clamped(col[i], 0.f, 255.f);
-      }
-      targetData[targIndex + GFX_ARGB32_OFFSET_R] =
-        static_cast<uint8_t>(col[0]);
-      targetData[targIndex + GFX_ARGB32_OFFSET_G] =
-        static_cast<uint8_t>(col[1]);
-      targetData[targIndex + GFX_ARGB32_OFFSET_B] =
-        static_cast<uint8_t>(col[2]);
-      targetData[targIndex + GFX_ARGB32_OFFSET_A] =
-        static_cast<uint8_t>(col[3]);
+    descr.Attributes().Set(eColorMatrixType, (uint32_t)SVG_FECOLORMATRIX_TYPE_MATRIX);
+    static const float identityMatrix[] = 
+      { 1, 0, 0, 0, 0,
+        0, 1, 0, 0, 0,
+        0, 0, 1, 0, 0,
+        0, 0, 0, 1, 0 };
+    descr.Attributes().Set(eColorMatrixValues, identityMatrix, 20);
+  } else {
+    descr.Attributes().Set(eColorMatrixType, type);
+    if (values.Length()) {
+      descr.Attributes().Set(eColorMatrixValues, &values[0], values.Length());
+    } else {
+      descr.Attributes().Set(eColorMatrixValues, nullptr, 0);
     }
   }
-  return NS_OK;
+  return descr;
 }
 
 bool
 SVGFEColorMatrixElement::AttributeAffectsRendering(int32_t aNameSpaceID,
                                                    nsIAtom* aAttribute) const
 {
   return SVGFEColorMatrixElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
          (aNameSpaceID == kNameSpaceID_None &&
--- a/content/svg/content/src/SVGFEColorMatrixElement.h
+++ b/content/svg/content/src/SVGFEColorMatrixElement.h
@@ -13,54 +13,46 @@
 nsresult NS_NewSVGFEColorMatrixElement(nsIContent **aResult,
                                        already_AddRefed<nsINodeInfo> aNodeInfo);
 
 namespace mozilla {
 namespace dom {
 
 typedef nsSVGFE SVGFEColorMatrixElementBase;
 
-static const unsigned short SVG_FECOLORMATRIX_TYPE_UNKNOWN = 0;
-static const unsigned short SVG_FECOLORMATRIX_TYPE_MATRIX = 1;
-static const unsigned short SVG_FECOLORMATRIX_TYPE_SATURATE = 2;
-static const unsigned short SVG_FECOLORMATRIX_TYPE_HUE_ROTATE = 3;
-static const unsigned short SVG_FECOLORMATRIX_TYPE_LUMINANCE_TO_ALPHA = 4;
-
 class SVGFEColorMatrixElement : public SVGFEColorMatrixElementBase
 {
   friend nsresult (::NS_NewSVGFEColorMatrixElement(nsIContent **aResult,
                                                    already_AddRefed<nsINodeInfo> aNodeInfo));
 protected:
   SVGFEColorMatrixElement(already_AddRefed<nsINodeInfo> aNodeInfo)
     : SVGFEColorMatrixElementBase(aNodeInfo)
   {
   }
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
 public:
-  virtual nsresult Filter(nsSVGFilterInstance* aInstance,
-                          const nsTArray<const Image*>& aSources,
-                          const Image* aTarget,
-                          const nsIntRect& aDataRect) MOZ_OVERRIDE;
+  virtual FilterPrimitiveDescription
+    GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                            const IntRect& aFilterSubregion,
+                            nsTArray<nsRefPtr<gfxASurface> >& aInputImages) MOZ_OVERRIDE;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const MOZ_OVERRIDE;
   virtual nsSVGString& GetResultImageName() MOZ_OVERRIDE { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
   already_AddRefed<SVGAnimatedEnumeration> Type();
   already_AddRefed<DOMSVGAnimatedNumberList> Values();
 
  protected:
-  virtual bool OperatesOnPremultipledAlpha(int32_t) MOZ_OVERRIDE { return false; }
-
   virtual EnumAttributesInfo GetEnumInfo() MOZ_OVERRIDE;
   virtual StringAttributesInfo GetStringInfo() MOZ_OVERRIDE;
   virtual NumberListAttributesInfo GetNumberListInfo() MOZ_OVERRIDE;
 
   enum { TYPE };
   nsSVGEnum mEnumAttributes[1];
   static nsSVGEnumMapping sTypeMap[];
   static EnumInfo sEnumInfo[1];
--- a/content/svg/content/src/SVGFEComponentTransferElement.cpp
+++ b/content/svg/content/src/SVGFEComponentTransferElement.cpp
@@ -2,19 +2,22 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGComponentTransferFunctionElement.h"
 #include "mozilla/dom/SVGFEComponentTransferElement.h"
 #include "mozilla/dom/SVGFEComponentTransferElementBinding.h"
 #include "nsSVGUtils.h"
+#include "mozilla/gfx/2D.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEComponentTransfer)
 
+using namespace mozilla::gfx;;
+
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGFEComponentTransferElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGFEComponentTransferElementBinding::Wrap(aCx, aScope, this);
 }
@@ -43,58 +46,54 @@ nsSVGElement::StringAttributesInfo
 SVGFEComponentTransferElement::GetStringInfo()
 {
   return StringAttributesInfo(mStringAttributes, sStringInfo,
                               ArrayLength(sStringInfo));
 }
 
 //--------------------------------------------
 
-nsresult
-SVGFEComponentTransferElement::Filter(nsSVGFilterInstance *instance,
-                                      const nsTArray<const Image*>& aSources,
-                                      const Image* aTarget,
-                                      const nsIntRect& rect)
+FilterPrimitiveDescription
+SVGFEComponentTransferElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                                                       const IntRect& aFilterSubregion,
+                                                       nsTArray<nsRefPtr<gfxASurface> >& aInputImages)
 {
-  uint8_t* sourceData = aSources[0]->mImage->Data();
-  uint8_t* targetData = aTarget->mImage->Data();
-  uint32_t stride = aTarget->mImage->Stride();
+  nsRefPtr<SVGComponentTransferFunctionElement> childForChannel[4];
 
-  uint8_t tableR[256], tableG[256], tableB[256], tableA[256];
-  for (int i=0; i<256; i++)
-    tableR[i] = tableG[i] = tableB[i] = tableA[i] = i;
-  uint8_t* tables[] = { tableR, tableG, tableB, tableA };
   for (nsIContent* childContent = nsINode::GetFirstChild();
        childContent;
        childContent = childContent->GetNextSibling()) {
 
     nsRefPtr<SVGComponentTransferFunctionElement> child;
     CallQueryInterface(childContent,
             (SVGComponentTransferFunctionElement**)getter_AddRefs(child));
     if (child) {
-      if (!child->GenerateLookupTable(tables[child->GetChannel()])) {
-        return NS_ERROR_FAILURE;
-      }
+      childForChannel[child->GetChannel()] = child;
     }
   }
 
-  for (int32_t y = rect.y; y < rect.YMost(); y++) {
-    for (int32_t x = rect.x; x < rect.XMost(); x++) {
-      int32_t targIndex = y * stride + x * 4;
-      targetData[targIndex + GFX_ARGB32_OFFSET_B] =
-        tableB[sourceData[targIndex + GFX_ARGB32_OFFSET_B]];
-      targetData[targIndex + GFX_ARGB32_OFFSET_G] =
-        tableG[sourceData[targIndex + GFX_ARGB32_OFFSET_G]];
-      targetData[targIndex + GFX_ARGB32_OFFSET_R] =
-        tableR[sourceData[targIndex + GFX_ARGB32_OFFSET_R]];
-      targetData[targIndex + GFX_ARGB32_OFFSET_A] =
-        tableA[sourceData[targIndex + GFX_ARGB32_OFFSET_A]];
+  static const AttributeName attributeNames[4] = {
+    eComponentTransferFunctionR,
+    eComponentTransferFunctionG,
+    eComponentTransferFunctionB,
+    eComponentTransferFunctionA
+  };
+
+  FilterPrimitiveDescription descr(FilterPrimitiveDescription::eComponentTransfer);
+  for (int32_t i = 0; i < 4; i++) {
+    if (childForChannel[i]) {
+      descr.Attributes().Set(attributeNames[i], childForChannel[i]->ComputeAttributes());
+    } else {
+      AttributeMap functionAttributes;
+      functionAttributes.Set(eComponentTransferFunctionType,
+                             (uint32_t)SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY);
+      descr.Attributes().Set(attributeNames[i], functionAttributes);
     }
   }
-  return NS_OK;
+  return descr;
 }
 
 bool
 SVGFEComponentTransferElement::AttributeAffectsRendering(int32_t aNameSpaceID,
                                                          nsIAtom* aAttribute) const
 {
   return SVGFEComponentTransferElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
          (aNameSpaceID == kNameSpaceID_None &&
--- a/content/svg/content/src/SVGFEComponentTransferElement.h
+++ b/content/svg/content/src/SVGFEComponentTransferElement.h
@@ -24,34 +24,32 @@ protected:
   SVGFEComponentTransferElement(already_AddRefed<nsINodeInfo> aNodeInfo)
     : SVGFEComponentTransferElementBase(aNodeInfo)
   {
   }
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
 public:
-  virtual nsresult Filter(nsSVGFilterInstance* aInstance,
-                          const nsTArray<const Image*>& aSources,
-                          const Image* aTarget,
-                          const nsIntRect& aDataRect) MOZ_OVERRIDE;
+  virtual FilterPrimitiveDescription
+    GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                            const IntRect& aFilterSubregion,
+                            nsTArray<nsRefPtr<gfxASurface> >& aInputImages) MOZ_OVERRIDE;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const MOZ_OVERRIDE;
   virtual nsSVGString& GetResultImageName() MOZ_OVERRIDE { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) MOZ_OVERRIDE;
 
   // nsIContent
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
 
 protected:
-  virtual bool OperatesOnPremultipledAlpha(int32_t) MOZ_OVERRIDE { return false; }
-
   virtual StringAttributesInfo GetStringInfo() MOZ_OVERRIDE;
 
   enum { RESULT, IN1 };
   nsSVGString mStringAttributes[2];
   static StringInfo sStringInfo[2];
 };
 
 } // namespace mozilla
--- a/content/svg/content/src/SVGFECompositeElement.cpp
+++ b/content/svg/content/src/SVGFECompositeElement.cpp
@@ -4,16 +4,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGFECompositeElement.h"
 #include "mozilla/dom/SVGFECompositeElementBinding.h"
 #include "gfxContext.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEComposite)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGFECompositeElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGFECompositeElementBinding::Wrap(aCx, aScope, this);
 }
@@ -102,77 +104,32 @@ void
 SVGFECompositeElement::SetK(float k1, float k2, float k3, float k4)
 {
   mNumberAttributes[ATTR_K1].SetBaseValue(k1, this);
   mNumberAttributes[ATTR_K2].SetBaseValue(k2, this);
   mNumberAttributes[ATTR_K3].SetBaseValue(k3, this);
   mNumberAttributes[ATTR_K4].SetBaseValue(k4, this);
 }
 
-nsresult
-SVGFECompositeElement::Filter(nsSVGFilterInstance* instance,
-                              const nsTArray<const Image*>& aSources,
-                              const Image* aTarget,
-                              const nsIntRect& rect)
+FilterPrimitiveDescription
+SVGFECompositeElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                                               const IntRect& aFilterSubregion,
+                                               nsTArray<nsRefPtr<gfxASurface> >& aInputImages)
 {
-  uint16_t op = mEnumAttributes[OPERATOR].GetAnimValue();
-
-  // Cairo does not support arithmetic operator
-  if (op == SVG_FECOMPOSITE_OPERATOR_ARITHMETIC) {
-    float k1, k2, k3, k4;
-    GetAnimatedNumberValues(&k1, &k2, &k3, &k4, nullptr);
-
-    // Copy the first source image
-    CopyRect(aTarget, aSources[0], rect);
+  FilterPrimitiveDescription descr(FilterPrimitiveDescription::eComposite);
+  uint32_t op = mEnumAttributes[OPERATOR].GetAnimValue();
+  descr.Attributes().Set(eCompositeOperator, op);
 
-    uint8_t* sourceData = aSources[1]->mImage->Data();
-    uint8_t* targetData = aTarget->mImage->Data();
-    uint32_t stride = aTarget->mImage->Stride();
-
-    // Blend in the second source image
-    float k1Scaled = k1 / 255.0f;
-    float k4Scaled = k4*255.0f;
-    for (int32_t x = rect.x; x < rect.XMost(); x++) {
-      for (int32_t y = rect.y; y < rect.YMost(); y++) {
-        uint32_t targIndex = y * stride + 4 * x;
-        for (int32_t i = 0; i < 4; i++) {
-          uint8_t i1 = targetData[targIndex + i];
-          uint8_t i2 = sourceData[targIndex + i];
-          float result = k1Scaled*i1*i2 + k2*i1 + k3*i2 + k4Scaled;
-          targetData[targIndex + i] =
-                       static_cast<uint8_t>(clamped(result, 0.f, 255.f));
-        }
-      }
-    }
-    return NS_OK;
+  if (op == SVG_FECOMPOSITE_OPERATOR_ARITHMETIC) {
+    float k[4];
+    GetAnimatedNumberValues(k, k+1, k+2, k+3, nullptr);
+    descr.Attributes().Set(eCompositeCoefficients, k, 4);
   }
 
-  // Cairo supports the operation we are trying to perform
-
-  gfxContext ctx(aTarget->mImage);
-  ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
-  ctx.SetSource(aSources[1]->mImage);
-  // Ensure rendering is limited to the filter primitive subregion
-  ctx.Clip(aTarget->mFilterPrimitiveSubregion);
-  ctx.Paint();
-
-  if (op < SVG_FECOMPOSITE_OPERATOR_OVER || op > SVG_FECOMPOSITE_OPERATOR_XOR) {
-    return NS_ERROR_FAILURE;
-  }
-  static const gfxContext::GraphicsOperator opMap[] = {
-                                           gfxContext::OPERATOR_DEST,
-                                           gfxContext::OPERATOR_OVER,
-                                           gfxContext::OPERATOR_IN,
-                                           gfxContext::OPERATOR_OUT,
-                                           gfxContext::OPERATOR_ATOP,
-                                           gfxContext::OPERATOR_XOR };
-  ctx.SetOperator(opMap[op]);
-  ctx.SetSource(aSources[0]->mImage);
-  ctx.Paint();
-  return NS_OK;
+  return descr;
 }
 
 bool
 SVGFECompositeElement::AttributeAffectsRendering(int32_t aNameSpaceID,
                                                  nsIAtom* aAttribute) const
 {
   return SVGFECompositeElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
          (aNameSpaceID == kNameSpaceID_None &&
@@ -187,44 +144,16 @@ SVGFECompositeElement::AttributeAffectsR
 
 void
 SVGFECompositeElement::GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources)
 {
   aSources.AppendElement(nsSVGStringInfo(&mStringAttributes[IN1], this));
   aSources.AppendElement(nsSVGStringInfo(&mStringAttributes[IN2], this));
 }
 
-nsIntRect
-SVGFECompositeElement::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-        const nsSVGFilterInstance& aInstance)
-{
-  uint16_t op = mEnumAttributes[OPERATOR].GetAnimValue();
-
-  if (op == SVG_FECOMPOSITE_OPERATOR_ARITHMETIC) {
-    // "arithmetic" operator can produce non-zero alpha values even where
-    // all input alphas are zero, so we can actually render outside the
-    // union of the source bboxes.
-    // XXX we could also check that k4 is nonzero and check for other
-    // cases like k1/k2 or k1/k3 zero.
-    return GetMaxRect();
-  }
-
-  if (op == SVG_FECOMPOSITE_OPERATOR_IN ||
-      op == SVG_FECOMPOSITE_OPERATOR_ATOP) {
-    // We will only draw where in2 has nonzero alpha, so it's a good
-    // bounding box for us
-    return aSourceBBoxes[1];
-  }
-
-  // The regular Porter-Duff operators always compute zero alpha values
-  // where all sources have zero alpha, so the union of their bounding
-  // boxes is also a bounding box for our rendering
-  return SVGFECompositeElementBase::ComputeTargetBBox(aSourceBBoxes, aInstance);
-}
-
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 nsSVGElement::NumberAttributesInfo
 SVGFECompositeElement::GetNumberInfo()
 {
   return NumberAttributesInfo(mNumberAttributes, sNumberInfo,
                               ArrayLength(sNumberInfo));
--- a/content/svg/content/src/SVGFECompositeElement.h
+++ b/content/svg/content/src/SVGFECompositeElement.h
@@ -11,50 +11,39 @@
 #include "nsSVGNumber2.h"
 
 nsresult NS_NewSVGFECompositeElement(nsIContent **aResult,
                                      already_AddRefed<nsINodeInfo> aNodeInfo);
 
 namespace mozilla {
 namespace dom {
 
-// Composite Operators
-static const unsigned short SVG_FECOMPOSITE_OPERATOR_UNKNOWN = 0;
-static const unsigned short SVG_FECOMPOSITE_OPERATOR_OVER = 1;
-static const unsigned short SVG_FECOMPOSITE_OPERATOR_IN = 2;
-static const unsigned short SVG_FECOMPOSITE_OPERATOR_OUT = 3;
-static const unsigned short SVG_FECOMPOSITE_OPERATOR_ATOP = 4;
-static const unsigned short SVG_FECOMPOSITE_OPERATOR_XOR = 5;
-static const unsigned short SVG_FECOMPOSITE_OPERATOR_ARITHMETIC = 6;
-
 typedef nsSVGFE SVGFECompositeElementBase;
 
 class SVGFECompositeElement : public SVGFECompositeElementBase
 {
   friend nsresult (::NS_NewSVGFECompositeElement(nsIContent **aResult,
                                                  already_AddRefed<nsINodeInfo> aNodeInfo));
 protected:
   SVGFECompositeElement(already_AddRefed<nsINodeInfo> aNodeInfo)
     : SVGFECompositeElementBase(aNodeInfo)
   {
   }
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
 public:
-  virtual nsresult Filter(nsSVGFilterInstance* aInstance,
-                          const nsTArray<const Image*>& aSources,
-                          const Image* aTarget,
-                          const nsIntRect& aDataRect) MOZ_OVERRIDE;
+  virtual FilterPrimitiveDescription
+    GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                            const IntRect& aFilterSubregion,
+                            nsTArray<nsRefPtr<gfxASurface> >& aInputImages) MOZ_OVERRIDE;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const MOZ_OVERRIDE;
   virtual nsSVGString& GetResultImageName() MOZ_OVERRIDE { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) MOZ_OVERRIDE;
-  virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-          const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
 
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
   already_AddRefed<SVGAnimatedString> In2();
   already_AddRefed<SVGAnimatedEnumeration> Operator();
--- a/content/svg/content/src/SVGFEConvolveMatrixElement.cpp
+++ b/content/svg/content/src/SVGFEConvolveMatrixElement.cpp
@@ -2,27 +2,25 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGFEConvolveMatrixElement.h"
 #include "mozilla/dom/SVGFEConvolveMatrixElementBinding.h"
 #include "DOMSVGAnimatedNumberList.h"
 #include "nsSVGUtils.h"
+#include "nsSVGFilterInstance.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEConvolveMatrix)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
-// Edge Mode Values
-static const unsigned short SVG_EDGEMODE_DUPLICATE = 1;
-static const unsigned short SVG_EDGEMODE_WRAP = 2;
-static const unsigned short SVG_EDGEMODE_NONE = 3;
-
 JSObject*
 SVGFEConvolveMatrixElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGFEConvolveMatrixElementBinding::Wrap(aCx, aScope, this);
 }
 
 nsSVGElement::NumberInfo SVGFEConvolveMatrixElement::sNumberInfo[2] =
 {
@@ -160,207 +158,94 @@ SVGFEConvolveMatrixElement::KernelUnitLe
 }
 
 void
 SVGFEConvolveMatrixElement::GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources)
 {
   aSources.AppendElement(nsSVGStringInfo(&mStringAttributes[IN1], this));
 }
 
-nsIntRect
-SVGFEConvolveMatrixElement::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-        const nsSVGFilterInstance& aInstance)
-{
-  // XXX A more precise box is possible when 'bias' is zero and 'edgeMode' is
-  // 'none', but it requires analysis of 'kernelUnitLength', 'order' and
-  // 'targetX/Y', so it's quite a lot of work. Don't do it for now.
-  return GetMaxRect();
-}
-
-void
-SVGFEConvolveMatrixElement::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
-          nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance)
-{
-  // XXX Precise results are possible but we're going to skip that work
-  // for now. Do nothing, which means the needed-box remains the
-  // source's output bounding box.
-}
-
-nsIntRect
-SVGFEConvolveMatrixElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
-                                              const nsSVGFilterInstance& aInstance)
-{
-  // XXX Precise results are possible but we're going to skip that work
-  // for now.
-  return GetMaxRect();
-}
-
-static int32_t BoundInterval(int32_t aVal, int32_t aMax)
-{
-  aVal = std::max(aVal, 0);
-  return std::min(aVal, aMax - 1);
-}
-
-static int32_t WrapInterval(int32_t aVal, int32_t aMax)
-{
-  aVal = aVal % aMax;
-  return aVal < 0 ? aMax + aVal : aVal;
-}
-
-static void
-ConvolvePixel(const uint8_t *aSourceData,
-              uint8_t *aTargetData,
-              int32_t aWidth, int32_t aHeight,
-              int32_t aStride,
-              int32_t aX, int32_t aY,
-              uint16_t aEdgeMode,
-              const float *aKernel,
-              float aDivisor, float aBias,
-              bool aPreserveAlpha,
-              int32_t aOrderX, int32_t aOrderY,
-              int32_t aTargetX, int32_t aTargetY)
+FilterPrimitiveDescription
+SVGFEConvolveMatrixElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                                                    const IntRect& aFilterSubregion,
+                                                    nsTArray<nsRefPtr<gfxASurface> >& aInputImages)
 {
-  float sum[4] = {0, 0, 0, 0};
-  aBias *= 255;
-  int32_t offsets[4] = {GFX_ARGB32_OFFSET_R,
-                        GFX_ARGB32_OFFSET_G,
-                        GFX_ARGB32_OFFSET_B,
-                        GFX_ARGB32_OFFSET_A } ;
-  int32_t channels = aPreserveAlpha ? 3 : 4;
+  const FilterPrimitiveDescription failureDescription(FilterPrimitiveDescription::eNone);
 
-  for (int32_t y = 0; y < aOrderY; y++) {
-    int32_t sampleY = aY + y - aTargetY;
-    bool overscanY = sampleY < 0 || sampleY >= aHeight;
-    for (int32_t x = 0; x < aOrderX; x++) {
-      int32_t sampleX = aX + x - aTargetX;
-      bool overscanX = sampleX < 0 || sampleX >= aWidth;
-      for (int32_t i = 0; i < channels; i++) {
-        if (overscanY || overscanX) {
-          switch (aEdgeMode) {
-            case SVG_EDGEMODE_DUPLICATE:
-              sum[i] +=
-                aSourceData[BoundInterval(sampleY, aHeight) * aStride +
-                            BoundInterval(sampleX, aWidth) * 4 + offsets[i]] *
-                aKernel[aOrderX * y + x];
-              break;
-            case SVG_EDGEMODE_WRAP:
-              sum[i] +=
-                aSourceData[WrapInterval(sampleY, aHeight) * aStride +
-                            WrapInterval(sampleX, aWidth) * 4 + offsets[i]] *
-                aKernel[aOrderX * y + x];
-              break;
-            default:
-              break;
-          }
-        } else {
-          sum[i] +=
-            aSourceData[sampleY * aStride + 4 * sampleX + offsets[i]] *
-            aKernel[aOrderX * y + x];
-        }
-      }
-    }
-  }
-  for (int32_t i = 0; i < channels; i++) {
-    aTargetData[aY * aStride + 4 * aX + offsets[i]] =
-      BoundInterval(static_cast<int32_t>(sum[i] / aDivisor + aBias), 256);
-  }
-  if (aPreserveAlpha) {
-    aTargetData[aY * aStride + 4 * aX + GFX_ARGB32_OFFSET_A] =
-      aSourceData[aY * aStride + 4 * aX + GFX_ARGB32_OFFSET_A];
-  }
-}
-
-nsresult
-SVGFEConvolveMatrixElement::Filter(nsSVGFilterInstance* instance,
-                                   const nsTArray<const Image*>& aSources,
-                                   const Image* aTarget,
-                                   const nsIntRect& rect)
-{
   const SVGNumberList &kernelMatrix =
     mNumberListAttributes[KERNELMATRIX].GetAnimValue();
   uint32_t kmLength = kernelMatrix.Length();
 
   int32_t orderX = mIntegerPairAttributes[ORDER].GetAnimValue(nsSVGIntegerPair::eFirst);
   int32_t orderY = mIntegerPairAttributes[ORDER].GetAnimValue(nsSVGIntegerPair::eSecond);
 
   if (orderX <= 0 || orderY <= 0 ||
       static_cast<uint32_t>(orderX * orderY) != kmLength) {
-    return NS_ERROR_FAILURE;
+    return failureDescription;
   }
 
   int32_t targetX, targetY;
   GetAnimatedIntegerValues(&targetX, &targetY, nullptr);
 
   if (mIntegerAttributes[TARGET_X].IsExplicitlySet()) {
     if (targetX < 0 || targetX >= orderX)
-      return NS_ERROR_FAILURE;
+      return failureDescription;
   } else {
     targetX = orderX / 2;
   }
   if (mIntegerAttributes[TARGET_Y].IsExplicitlySet()) {
     if (targetY < 0 || targetY >= orderY)
-      return NS_ERROR_FAILURE;
+      return failureDescription;
   } else {
     targetY = orderY / 2;
   }
 
   if (orderX > NS_SVG_OFFSCREEN_MAX_DIMENSION ||
       orderY > NS_SVG_OFFSCREEN_MAX_DIMENSION)
-    return NS_ERROR_FAILURE;
+    return failureDescription;
   const fallible_t fallible = fallible_t();
   nsAutoArrayPtr<float> kernel(new (fallible) float[orderX * orderY]);
   if (!kernel)
-    return NS_ERROR_FAILURE;
+    return failureDescription;
   for (uint32_t i = 0; i < kmLength; i++) {
     kernel[kmLength - 1 - i] = kernelMatrix[i];
   }
 
   float divisor;
   if (mNumberAttributes[DIVISOR].IsExplicitlySet()) {
     divisor = mNumberAttributes[DIVISOR].GetAnimValue();
     if (divisor == 0)
-      return NS_ERROR_FAILURE;
+      return failureDescription;
   } else {
     divisor = kernel[0];
     for (uint32_t i = 1; i < kmLength; i++)
       divisor += kernel[i];
     if (divisor == 0)
       divisor = 1;
   }
 
-  ScaleInfo info = SetupScalingFilter(instance, aSources[0], aTarget, rect,
-                                      &mNumberPairAttributes[KERNEL_UNIT_LENGTH]);
-  if (!info.mTarget)
-    return NS_ERROR_FAILURE;
-
-  uint16_t edgeMode = mEnumAttributes[EDGEMODE].GetAnimValue();
+  uint32_t edgeMode = mEnumAttributes[EDGEMODE].GetAnimValue();
   bool preserveAlpha = mBooleanAttributes[PRESERVEALPHA].GetAnimValue();
-
   float bias = mNumberAttributes[BIAS].GetAnimValue();
 
-  const nsIntRect& dataRect = info.mDataRect;
-  int32_t stride = info.mSource->Stride();
-  int32_t width = info.mSource->GetSize().width;
-  int32_t height = info.mSource->GetSize().height;
-  uint8_t *sourceData = info.mSource->Data();
-  uint8_t *targetData = info.mTarget->Data();
+  Size kernelUnitLength =
+    GetKernelUnitLength(aInstance, &mNumberPairAttributes[KERNEL_UNIT_LENGTH]);
 
-  for (int32_t y = dataRect.y; y < dataRect.YMost(); y++) {
-    for (int32_t x = dataRect.x; x < dataRect.XMost(); x++) {
-      ConvolvePixel(sourceData, targetData,
-                    width, height, stride,
-                    x, y,
-                    edgeMode, kernel, divisor, bias, preserveAlpha,
-                    orderX, orderY, targetX, targetY);
-    }
-  }
+  FilterPrimitiveDescription descr(FilterPrimitiveDescription::eConvolveMatrix);
+  AttributeMap& atts = descr.Attributes();
+  atts.Set(eConvolveMatrixKernelSize, IntSize(orderX, orderY));
+  atts.Set(eConvolveMatrixKernelMatrix, &kernelMatrix[0], kmLength);
+  atts.Set(eConvolveMatrixDivisor, divisor);
+  atts.Set(eConvolveMatrixBias, bias);
+  atts.Set(eConvolveMatrixTarget, IntPoint(targetX, targetY));
+  atts.Set(eConvolveMatrixEdgeMode, edgeMode);
+  atts.Set(eConvolveMatrixKernelUnitLength, kernelUnitLength);
+  atts.Set(eConvolveMatrixPreserveAlpha, preserveAlpha);
 
-  FinishScalingFilter(&info);
-
-  return NS_OK;
+  return descr;
 }
 
 bool
 SVGFEConvolveMatrixElement::AttributeAffectsRendering(int32_t aNameSpaceID,
                                                       nsIAtom* aAttribute) const
 {
   return SVGFEConvolveMatrixElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
          (aNameSpaceID == kNameSpaceID_None &&
--- a/content/svg/content/src/SVGFEConvolveMatrixElement.h
+++ b/content/svg/content/src/SVGFEConvolveMatrixElement.h
@@ -34,31 +34,24 @@ protected:
   SVGFEConvolveMatrixElement(already_AddRefed<nsINodeInfo> aNodeInfo)
     : SVGFEConvolveMatrixElementBase(aNodeInfo)
   {
   }
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
 public:
-  virtual nsresult Filter(nsSVGFilterInstance* aInstance,
-                          const nsTArray<const Image*>& aSources,
-                          const Image* aTarget,
-                          const nsIntRect& aDataRect) MOZ_OVERRIDE;
+  virtual FilterPrimitiveDescription
+    GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                            const IntRect& aFilterSubregion,
+                            nsTArray<nsRefPtr<gfxASurface> >& aInputImages) MOZ_OVERRIDE;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const MOZ_OVERRIDE;
   virtual nsSVGString& GetResultImageName() MOZ_OVERRIDE { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) MOZ_OVERRIDE;
-  virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-          const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
-  virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
-          nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
-  virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
-          const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
-
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
   already_AddRefed<SVGAnimatedInteger> OrderX();
   already_AddRefed<SVGAnimatedInteger> OrderY();
   already_AddRefed<DOMSVGAnimatedNumberList> KernelMatrix();
@@ -67,20 +60,16 @@ public:
   already_AddRefed<SVGAnimatedEnumeration> EdgeMode();
   already_AddRefed<SVGAnimatedBoolean> PreserveAlpha();
   already_AddRefed<SVGAnimatedNumber> Divisor();
   already_AddRefed<SVGAnimatedNumber> Bias();
   already_AddRefed<SVGAnimatedNumber> KernelUnitLengthX();
   already_AddRefed<SVGAnimatedNumber> KernelUnitLengthY();
 
 protected:
-  virtual bool OperatesOnPremultipledAlpha(int32_t) MOZ_OVERRIDE {
-    return !mBooleanAttributes[PRESERVEALPHA].GetAnimValue();
-  }
-
   virtual NumberAttributesInfo GetNumberInfo() MOZ_OVERRIDE;
   virtual NumberPairAttributesInfo GetNumberPairInfo() MOZ_OVERRIDE;
   virtual IntegerAttributesInfo GetIntegerInfo() MOZ_OVERRIDE;
   virtual IntegerPairAttributesInfo GetIntegerPairInfo() MOZ_OVERRIDE;
   virtual BooleanAttributesInfo GetBooleanInfo() MOZ_OVERRIDE;
   virtual EnumAttributesInfo GetEnumInfo() MOZ_OVERRIDE;
   virtual StringAttributesInfo GetStringInfo() MOZ_OVERRIDE;
   virtual NumberListAttributesInfo GetNumberListInfo() MOZ_OVERRIDE;
--- a/content/svg/content/src/SVGFEDiffuseLightingElement.cpp
+++ b/content/svg/content/src/SVGFEDiffuseLightingElement.cpp
@@ -1,19 +1,22 @@
 /* a*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGFEDiffuseLightingElement.h"
 #include "mozilla/dom/SVGFEDiffuseLightingElementBinding.h"
 #include "nsSVGUtils.h"
+#include "nsSVGFilterInstance.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEDiffuseLighting)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGFEDiffuseLightingElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGFEDiffuseLightingElementBinding::Wrap(aCx, aScope, this);
 }
@@ -52,40 +55,31 @@ SVGFEDiffuseLightingElement::KernelUnitL
 
 already_AddRefed<SVGAnimatedNumber>
 SVGFEDiffuseLightingElement::KernelUnitLengthY()
 {
   return mNumberPairAttributes[KERNEL_UNIT_LENGTH].ToDOMAnimatedNumber(
     nsSVGNumberPair::eSecond, this);
 }
 
+FilterPrimitiveDescription
+SVGFEDiffuseLightingElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                                                     const IntRect& aFilterSubregion,
+                                                     nsTArray<nsRefPtr<gfxASurface> >& aInputImages)
+{
+  float diffuseConstant = mNumberAttributes[DIFFUSE_CONSTANT].GetAnimValue();
+
+  FilterPrimitiveDescription descr(FilterPrimitiveDescription::eDiffuseLighting);
+  descr.Attributes().Set(eDiffuseLightingDiffuseConstant, diffuseConstant);
+  return AddLightingAttributes(descr, aInstance);
+}
+
 bool
 SVGFEDiffuseLightingElement::AttributeAffectsRendering(int32_t aNameSpaceID,
                                                        nsIAtom* aAttribute) const
 {
   return SVGFEDiffuseLightingElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
          (aNameSpaceID == kNameSpaceID_None &&
           aAttribute == nsGkAtoms::diffuseConstant);
 }
 
-//----------------------------------------------------------------------
-// nsSVGElement methods
-
-void
-SVGFEDiffuseLightingElement::LightPixel(const float *N, const float *L,
-                                        nscolor color, uint8_t *targetData)
-{
-  float diffuseNL =
-    mNumberAttributes[DIFFUSE_CONSTANT].GetAnimValue() * DOT(N, L);
-
-  if (diffuseNL < 0) diffuseNL = 0;
-
-  targetData[GFX_ARGB32_OFFSET_B] =
-    std::min(uint32_t(diffuseNL * NS_GET_B(color)), 255U);
-  targetData[GFX_ARGB32_OFFSET_G] =
-    std::min(uint32_t(diffuseNL * NS_GET_G(color)), 255U);
-  targetData[GFX_ARGB32_OFFSET_R] =
-    std::min(uint32_t(diffuseNL * NS_GET_R(color)), 255U);
-  targetData[GFX_ARGB32_OFFSET_A] = 255;
-}
-
 } // namespace dom
 } // namespace mozilla
--- a/content/svg/content/src/SVGFEDiffuseLightingElement.h
+++ b/content/svg/content/src/SVGFEDiffuseLightingElement.h
@@ -24,30 +24,29 @@ protected:
   SVGFEDiffuseLightingElement(already_AddRefed<nsINodeInfo> aNodeInfo)
     : SVGFEDiffuseLightingElementBase(aNodeInfo)
   {
   }
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
 public:
+  virtual FilterPrimitiveDescription
+    GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                            const IntRect& aFilterSubregion,
+                            nsTArray<nsRefPtr<gfxASurface> >& aInputImages) MOZ_OVERRIDE;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
   already_AddRefed<SVGAnimatedNumber> SurfaceScale();
   already_AddRefed<SVGAnimatedNumber> DiffuseConstant();
   already_AddRefed<SVGAnimatedNumber> KernelUnitLengthX();
   already_AddRefed<SVGAnimatedNumber> KernelUnitLengthY();
-
-protected:
-  virtual void LightPixel(const float *N, const float *L,
-                          nscolor color, uint8_t *targetData);
-
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_SVGFEDiffuseLightingElement_h
--- a/content/svg/content/src/SVGFEDisplacementMapElement.cpp
+++ b/content/svg/content/src/SVGFEDisplacementMapElement.cpp
@@ -5,25 +5,21 @@
 
 #include "mozilla/dom/SVGFEDisplacementMapElement.h"
 #include "mozilla/dom/SVGFEDisplacementMapElementBinding.h"
 #include "nsSVGFilterInstance.h"
 #include "nsSVGUtils.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEDisplacementMap)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
-// Channel Selectors
-static const unsigned short SVG_CHANNEL_R = 1;
-static const unsigned short SVG_CHANNEL_G = 2;
-static const unsigned short SVG_CHANNEL_B = 3;
-static const unsigned short SVG_CHANNEL_A = 4;
-
 JSObject*
 SVGFEDisplacementMapElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGFEDisplacementMapElementBinding::Wrap(aCx, aScope, this);
 }
 
 nsSVGElement::NumberInfo SVGFEDisplacementMapElement::sNumberInfo[1] =
 {
@@ -89,78 +85,30 @@ SVGFEDisplacementMapElement::XChannelSel
 }
 
 already_AddRefed<SVGAnimatedEnumeration>
 SVGFEDisplacementMapElement::YChannelSelector()
 {
   return mEnumAttributes[CHANNEL_Y].ToDOMAnimatedEnum(this);
 }
 
-nsresult
-SVGFEDisplacementMapElement::Filter(nsSVGFilterInstance* instance,
-                                    const nsTArray<const Image*>& aSources,
-                                    const Image* aTarget,
-                                    const nsIntRect& rect)
+FilterPrimitiveDescription
+SVGFEDisplacementMapElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                                                     const IntRect& aFilterSubregion,
+                                                     nsTArray<nsRefPtr<gfxASurface> >& aInputImages)
 {
-  float scale = instance->GetPrimitiveNumber(SVGContentUtils::XY,
-                                             &mNumberAttributes[SCALE]);
-  if (scale == 0.0f) {
-    CopyRect(aTarget, aSources[0], rect);
-    return NS_OK;
-  }
-
-  int32_t width = instance->GetSurfaceWidth();
-  int32_t height = instance->GetSurfaceHeight();
-
-  uint8_t* sourceData = aSources[0]->mImage->Data();
-  uint8_t* displacementData = aSources[1]->mImage->Data();
-  uint8_t* targetData = aTarget->mImage->Data();
-  uint32_t stride = aTarget->mImage->Stride();
-
-  static const uint8_t dummyData[4] = { 0, 0, 0, 0 };
-
-  static const uint16_t channelMap[5] = {
-                             0,
-                             GFX_ARGB32_OFFSET_R,
-                             GFX_ARGB32_OFFSET_G,
-                             GFX_ARGB32_OFFSET_B,
-                             GFX_ARGB32_OFFSET_A };
-  uint16_t xChannel = channelMap[mEnumAttributes[CHANNEL_X].GetAnimValue()];
-  uint16_t yChannel = channelMap[mEnumAttributes[CHANNEL_Y].GetAnimValue()];
-
-  double scaleOver255 = scale / 255.0;
-  double scaleAdjustment = 0.5 - 0.5 * scale;
-
-  for (int32_t y = rect.y; y < rect.YMost(); y++) {
-    for (int32_t x = rect.x; x < rect.XMost(); x++) {
-      uint32_t targIndex = y * stride + 4 * x;
-      // At some point we might want to replace this with a bilinear sample.
-      int32_t sourceX = x +
-        NSToIntFloor(scaleOver255 * displacementData[targIndex + xChannel] +
-                scaleAdjustment);
-      int32_t sourceY = y +
-        NSToIntFloor(scaleOver255 * displacementData[targIndex + yChannel] +
-                scaleAdjustment);
-
-      bool outOfBounds = sourceX < 0 || sourceX >= width ||
-                         sourceY < 0 || sourceY >= height;
-      const uint8_t* data;
-      int32_t multiplier;
-      if (outOfBounds) {
-        data = dummyData;
-        multiplier = 0;
-      } else {
-        data = sourceData;
-        multiplier = 1;
-      }
-      *(uint32_t*)(targetData + targIndex) =
-        *(uint32_t*)(data + multiplier * (sourceY * stride + 4 * sourceX));
-    }
-  }
-  return NS_OK;
+  float scale = aInstance->GetPrimitiveNumber(SVGContentUtils::XY,
+                                              &mNumberAttributes[SCALE]);
+  uint32_t xChannel = mEnumAttributes[CHANNEL_X].GetAnimValue();
+  uint32_t yChannel = mEnumAttributes[CHANNEL_Y].GetAnimValue();
+  FilterPrimitiveDescription descr(FilterPrimitiveDescription::eDisplacementMap);
+  descr.Attributes().Set(eDisplacementMapScale, scale);
+  descr.Attributes().Set(eDisplacementMapXChannel, xChannel);
+  descr.Attributes().Set(eDisplacementMapYChannel, yChannel);
+  return descr;
 }
 
 bool
 SVGFEDisplacementMapElement::AttributeAffectsRendering(int32_t aNameSpaceID,
                                                        nsIAtom* aAttribute) const
 {
   return SVGFEDisplacementMapElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
          (aNameSpaceID == kNameSpaceID_None &&
@@ -173,48 +121,16 @@ SVGFEDisplacementMapElement::AttributeAf
 
 void
 SVGFEDisplacementMapElement::GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources)
 {
   aSources.AppendElement(nsSVGStringInfo(&mStringAttributes[IN1], this));
   aSources.AppendElement(nsSVGStringInfo(&mStringAttributes[IN2], this));
 }
 
-nsIntRect
-SVGFEDisplacementMapElement::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-          const nsSVGFilterInstance& aInstance)
-{
-  // XXX we could do something clever here involving analysis of 'scale'
-  // to figure out the maximum displacement, and then return mIn1's bounds
-  // adjusted for the maximum displacement
-  return GetMaxRect();
-}
-
-void
-SVGFEDisplacementMapElement::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
-          nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance)
-{
-  // in2 contains the displacements, which we read for each target pixel
-  aSourceBBoxes[1] = aTargetBBox;
-  // XXX to figure out which parts of 'in' we might read, we could
-  // do some analysis of 'scale' to figure out the maximum displacement.
-  // For now, just leave aSourceBBoxes[0] alone, i.e. assume we use its
-  // entire output bounding box.
-  // If we change this, we need to change coordinate assumptions above
-}
-
-nsIntRect
-SVGFEDisplacementMapElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
-                                               const nsSVGFilterInstance& aInstance)
-{
-  // XXX we could do something clever here involving analysis of 'scale'
-  // to figure out the maximum displacement
-  return GetMaxRect();
-}
-
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 nsSVGElement::NumberAttributesInfo
 SVGFEDisplacementMapElement::GetNumberInfo()
 {
   return NumberAttributesInfo(mNumberAttributes, sNumberInfo,
                               ArrayLength(sNumberInfo));
--- a/content/svg/content/src/SVGFEDisplacementMapElement.h
+++ b/content/svg/content/src/SVGFEDisplacementMapElement.h
@@ -25,58 +25,47 @@ protected:
   SVGFEDisplacementMapElement(already_AddRefed<nsINodeInfo> aNodeInfo)
     : SVGFEDisplacementMapElementBase(aNodeInfo)
   {
   }
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
 public:
-  virtual nsresult Filter(nsSVGFilterInstance* aInstance,
-                          const nsTArray<const Image*>& aSources,
-                          const Image* aTarget,
-                          const nsIntRect& aDataRect) MOZ_OVERRIDE;
+  virtual FilterPrimitiveDescription
+    GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                            const IntRect& aFilterSubregion,
+                            nsTArray<nsRefPtr<gfxASurface> >& aInputImages) MOZ_OVERRIDE;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const MOZ_OVERRIDE;
   virtual nsSVGString& GetResultImageName() MOZ_OVERRIDE { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) MOZ_OVERRIDE;
-  virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-          const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
-  virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
-          nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
-  virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
-          const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
-
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
   already_AddRefed<SVGAnimatedString> In2();
   already_AddRefed<SVGAnimatedNumber> Scale();
   already_AddRefed<SVGAnimatedEnumeration> XChannelSelector();
   already_AddRefed<SVGAnimatedEnumeration> YChannelSelector();
 
 protected:
-  virtual bool OperatesOnSRGB(nsSVGFilterInstance* aInstance,
-                              int32_t aInput, Image* aImage) MOZ_OVERRIDE {
-    switch (aInput) {
+  virtual bool OperatesOnSRGB(int32_t aInputIndex,
+                              bool aInputIsAlreadySRGB) MOZ_OVERRIDE {
+    switch (aInputIndex) {
     case 0:
-      return aImage->mColorModel.mColorSpace == ColorModel::SRGB;
+      return aInputIsAlreadySRGB;
     case 1:
-      return SVGFEDisplacementMapElementBase::OperatesOnSRGB(aInstance,
-                                                             aInput, aImage);
+      return SVGFEDisplacementMapElementBase::OperatesOnSRGB(aInputIndex, aInputIsAlreadySRGB);
     default:
-      NS_ERROR("Will not give correct output color model");
+      NS_ERROR("Will not give correct color model");
       return false;
     }
   }
-  virtual bool OperatesOnPremultipledAlpha(int32_t aInput) MOZ_OVERRIDE {
-    return !(aInput == 1);
-  }
 
   virtual NumberAttributesInfo GetNumberInfo() MOZ_OVERRIDE;
   virtual EnumAttributesInfo GetEnumInfo() MOZ_OVERRIDE;
   virtual StringAttributesInfo GetStringInfo() MOZ_OVERRIDE;
 
   enum { SCALE };
   nsSVGNumber2 mNumberAttributes[1];
   static NumberInfo sNumberInfo[1];
--- a/content/svg/content/src/SVGFEDistantLightElement.cpp
+++ b/content/svg/content/src/SVGFEDistantLightElement.cpp
@@ -1,18 +1,21 @@
 /* a*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGFEDistantLightElement.h"
 #include "mozilla/dom/SVGFEDistantLightElementBinding.h"
+#include "nsSVGFilterInstance.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEDistantLight)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGFEDistantLightElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGFEDistantLightElementBinding::Wrap(aCx, aScope, this);
 }
@@ -35,16 +38,29 @@ bool
 SVGFEDistantLightElement::AttributeAffectsRendering(int32_t aNameSpaceID,
                                                     nsIAtom* aAttribute) const
 {
   return aNameSpaceID == kNameSpaceID_None &&
          (aAttribute == nsGkAtoms::azimuth ||
           aAttribute == nsGkAtoms::elevation);
 }
 
+AttributeMap
+SVGFEDistantLightElement::ComputeLightAttributes(nsSVGFilterInstance* aInstance)
+{
+  float azimuth, elevation;
+  GetAnimatedNumberValues(&azimuth, &elevation, nullptr);
+
+  AttributeMap map;
+  map.Set(eLightType, (uint32_t)eLightTypeDistant);
+  map.Set(eDistantLightAzimuth, azimuth);
+  map.Set(eDistantLightElevation, elevation);
+  return map;
+}
+
 already_AddRefed<SVGAnimatedNumber>
 SVGFEDistantLightElement::Azimuth()
 {
   return mNumberAttributes[AZIMUTH].ToDOMAnimatedNumber(this);
 }
 
 already_AddRefed<SVGAnimatedNumber>
 SVGFEDistantLightElement::Elevation()
--- a/content/svg/content/src/SVGFEDistantLightElement.h
+++ b/content/svg/content/src/SVGFEDistantLightElement.h
@@ -4,37 +4,38 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_SVGFEDistantLightElement_h
 #define mozilla_dom_SVGFEDistantLightElement_h
 
 #include "nsSVGFilters.h"
 #include "nsSVGNumber2.h"
 
-typedef SVGFEUnstyledElement SVGFEDistantLightElementBase;
-
 nsresult NS_NewSVGFEDistantLightElement(nsIContent **aResult,
                                         already_AddRefed<nsINodeInfo> aNodeInfo);
 
 namespace mozilla {
 namespace dom {
 
+typedef SVGFELightElement SVGFEDistantLightElementBase;
+
 class SVGFEDistantLightElement : public SVGFEDistantLightElementBase
 {
   friend nsresult (::NS_NewSVGFEDistantLightElement(nsIContent **aResult,
                                                     already_AddRefed<nsINodeInfo> aNodeInfo));
 protected:
   SVGFEDistantLightElement(already_AddRefed<nsINodeInfo> aNodeInfo)
     : SVGFEDistantLightElementBase(aNodeInfo)
   {
   }
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
 public:
+  virtual AttributeMap ComputeLightAttributes(nsSVGFilterInstance* aInstance) MOZ_OVERRIDE;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedNumber> Azimuth();
   already_AddRefed<SVGAnimatedNumber> Elevation();
--- a/content/svg/content/src/SVGFEFloodElement.cpp
+++ b/content/svg/content/src/SVGFEFloodElement.cpp
@@ -2,19 +2,22 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGFEFloodElement.h"
 #include "mozilla/dom/SVGFEFloodElementBinding.h"
 #include "gfxContext.h"
 #include "gfxColor.h"
+#include "nsIFrame.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEFlood)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGFEFloodElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGFEFloodElementBinding::Wrap(aCx, aScope, this);
 }
@@ -24,44 +27,36 @@ nsSVGElement::StringInfo SVGFEFloodEleme
   { &nsGkAtoms::result, kNameSpaceID_None, true }
 };
 
 //----------------------------------------------------------------------
 // nsIDOMNode methods
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFloodElement)
 
-nsresult
-SVGFEFloodElement::Filter(nsSVGFilterInstance *instance,
-                          const nsTArray<const Image*>& aSources,
-                          const Image* aTarget,
-                          const nsIntRect& aDataRect)
+FilterPrimitiveDescription
+SVGFEFloodElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                                           const IntRect& aFilterSubregion,
+                                           nsTArray<nsRefPtr<gfxASurface> >& aInputImages)
 {
+  FilterPrimitiveDescription descr(FilterPrimitiveDescription::eFlood);
   nsIFrame* frame = GetPrimaryFrame();
-  if (!frame) return NS_ERROR_FAILURE;
-  nsStyleContext* style = frame->StyleContext();
-
-  nscolor floodColor = style->StyleSVGReset()->mFloodColor;
-  float floodOpacity = style->StyleSVGReset()->mFloodOpacity;
-
-  gfxContext ctx(aTarget->mImage);
-  ctx.SetColor(gfxRGBA(NS_GET_R(floodColor) / 255.0,
-                       NS_GET_G(floodColor) / 255.0,
-                       NS_GET_B(floodColor) / 255.0,
-                       NS_GET_A(floodColor) / 255.0 * floodOpacity));
-  ctx.Rectangle(aTarget->mFilterPrimitiveSubregion);
-  ctx.Fill();
-  return NS_OK;
-}
-
-nsIntRect
-SVGFEFloodElement::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-                                     const nsSVGFilterInstance& aInstance)
-{
-  return GetMaxRect();
+  if (frame) {
+    nsStyleContext* style = frame->StyleContext();
+    nscolor floodColor = style->StyleSVGReset()->mFloodColor;
+    float floodOpacity = style->StyleSVGReset()->mFloodOpacity;
+    Color color(NS_GET_R(floodColor) / 255.0,
+                NS_GET_G(floodColor) / 255.0,
+                NS_GET_B(floodColor) / 255.0,
+                NS_GET_A(floodColor) / 255.0 * floodOpacity);
+    descr.Attributes().Set(eFloodColor, color);
+  } else {
+    descr.Attributes().Set(eFloodColor, Color());
+  }
+  return descr;
 }
 
 //----------------------------------------------------------------------
 // nsIContent methods
 
 NS_IMETHODIMP_(bool)
 SVGFEFloodElement::IsAttributeMapped(const nsIAtom* name) const
 {
--- a/content/svg/content/src/SVGFEFloodElement.h
+++ b/content/svg/content/src/SVGFEFloodElement.h
@@ -26,32 +26,29 @@ protected:
   {
   }
   virtual JSObject* WrapNode(JSContext *cx,
                              JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
 
 public:
   virtual bool SubregionIsUnionOfRegions() MOZ_OVERRIDE { return false; }
 
-  virtual nsresult Filter(nsSVGFilterInstance* aInstance,
-                          const nsTArray<const Image*>& aSources,
-                          const Image* aTarget,
-                          const nsIntRect& aDataRect) MOZ_OVERRIDE;
+  virtual FilterPrimitiveDescription
+    GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                            const IntRect& aFilterSubregion,
+                            nsTArray<nsRefPtr<gfxASurface> >& aInputImages) MOZ_OVERRIDE;
   virtual nsSVGString& GetResultImageName() MOZ_OVERRIDE { return mStringAttributes[RESULT]; }
-  virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-          const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
 
   // nsIContent interface
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
 protected:
-  virtual bool OperatesOnSRGB(nsSVGFilterInstance*,
-                              int32_t, Image*) MOZ_OVERRIDE { return true; }
+  virtual bool ProducesSRGB() MOZ_OVERRIDE { return true; }
 
   virtual StringAttributesInfo GetStringInfo() MOZ_OVERRIDE;
 
   enum { RESULT };
   nsSVGString mStringAttributes[1];
   static StringInfo sStringInfo[1];
 };
 
--- a/content/svg/content/src/SVGFEGaussianBlurElement.cpp
+++ b/content/svg/content/src/SVGFEGaussianBlurElement.cpp
@@ -5,16 +5,18 @@
 
 #include "mozilla/dom/SVGFEGaussianBlurElement.h"
 #include "mozilla/dom/SVGFEGaussianBlurElementBinding.h"
 #include "nsSVGFilterInstance.h"
 #include "nsSVGUtils.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEGaussianBlur)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGFEGaussianBlurElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGFEGaussianBlurElementBinding::Wrap(aCx, aScope, this);
 }
@@ -56,298 +58,38 @@ SVGFEGaussianBlurElement::StdDeviationY(
 }
 
 void
 SVGFEGaussianBlurElement::SetStdDeviation(float stdDeviationX, float stdDeviationY)
 {
   mNumberPairAttributes[STD_DEV].SetBaseValues(stdDeviationX, stdDeviationY, this);
 }
 
-/**
- * We want to speed up 1/N integer divisions --- integer division is
- * often rather slow.
- * We know that our input numerators V are constrained to be <= 255*N,
- * so the result of dividing by N always fits in 8 bits.
- * So we can try approximating the division V/N as V*K/(2^24) (integer
- * division, 32-bit multiply). Dividing by 2^24 is a simple shift so it's
- * fast. The main problem is choosing a value for K; this function returns
- * K's value.
- *
- * If the result is correct for the extrema, V=0 and V=255*N, then we'll
- * be in good shape since both the original function and our approximation
- * are linear. V=0 always gives 0 in both cases, no problem there.
- * For V=255*N, let's choose the largest K that doesn't cause overflow
- * and ensure that it gives the right answer. The constraints are
- *     (1)   255*N*K < 2^32
- * and (2)   255*N*K >= 255*(2^24)
- *
- * From (1) we find the best value of K is floor((2^32 - 1)/(255*N)).
- * (2) tells us when this will be valid:
- *    N*floor((2^32 - 1)/(255*N)) >= 2^24
- * Now, floor(X) > X - 1, so (2) holds if
- *    N*((2^32 - 1)/(255*N) - 1) >= 2^24
- *         (2^32 - 1)/255 - 2^24 >= N
- *                             N <= 65793
- *
- * If all that math confuses you, this should convince you:
- * > perl -e 'for($N=1;(255*$N*int(0xFFFFFFFF/(255*$N)))>>24==255;++$N){}print"$N\n"'
- * 66052
- *
- * So this is fine for all reasonable values of N. For larger values of N
- * we may as well just use the same approximation and accept the fact that
- * the output channel values will be a little low.
- */
-static uint32_t ComputeScaledDivisor(uint32_t aDivisor)
+static const float kMaxStdDeviation = 500;
+
+FilterPrimitiveDescription
+SVGFEGaussianBlurElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                                                  const IntRect& aFilterSubregion,
+                                                  nsTArray<nsRefPtr<gfxASurface> >& aInputImages)
 {
-  return UINT32_MAX/(255*aDivisor);
-}
-
-static void
-BoxBlur(const uint8_t *aInput, uint8_t *aOutput,
-        int32_t aStrideMinor, int32_t aStartMinor, int32_t aEndMinor,
-        int32_t aLeftLobe, int32_t aRightLobe, bool aAlphaOnly)
-{
-  int32_t boxSize = aLeftLobe + aRightLobe + 1;
-  uint32_t scaledDivisor = ComputeScaledDivisor(boxSize);
-  uint32_t sums[4] = {0, 0, 0, 0};
-
-  for (int32_t i=0; i < boxSize; i++) {
-    int32_t pos = aStartMinor - aLeftLobe + i;
-    pos = std::max(pos, aStartMinor);
-    pos = std::min(pos, aEndMinor - 1);
-#define SUM(j)     sums[j] += aInput[aStrideMinor*pos + j];
-    SUM(0); SUM(1); SUM(2); SUM(3);
-#undef SUM
+  float stdX = aInstance->GetPrimitiveNumber(SVGContentUtils::X,
+                                             &mNumberPairAttributes[STD_DEV],
+                                             nsSVGNumberPair::eFirst);
+  float stdY = aInstance->GetPrimitiveNumber(SVGContentUtils::Y,
+                                             &mNumberPairAttributes[STD_DEV],
+                                             nsSVGNumberPair::eSecond);
+  if (stdX < 0 || stdY < 0) {
+    return FilterPrimitiveDescription(FilterPrimitiveDescription::eNone);
   }
 
-  aOutput += aStrideMinor*aStartMinor;
-  if (aStartMinor + boxSize <= aEndMinor) {
-    const uint8_t *lastInput = aInput + aStartMinor*aStrideMinor;
-    const uint8_t *nextInput = aInput + (aStartMinor + aRightLobe + 1)*aStrideMinor;
-#define OUTPUT(j)     aOutput[j] = (sums[j]*scaledDivisor) >> 24;
-#define SUM(j)        sums[j] += nextInput[j] - lastInput[j];
-    // process pixels in B, G, R, A order because that's 0, 1, 2, 3 for x86
-#define OUTPUT_PIXEL() \
-        if (!aAlphaOnly) { OUTPUT(GFX_ARGB32_OFFSET_B); \
-                           OUTPUT(GFX_ARGB32_OFFSET_G); \
-                           OUTPUT(GFX_ARGB32_OFFSET_R); } \
-        OUTPUT(GFX_ARGB32_OFFSET_A);
-#define SUM_PIXEL() \
-        if (!aAlphaOnly) { SUM(GFX_ARGB32_OFFSET_B); \
-                           SUM(GFX_ARGB32_OFFSET_G); \
-                           SUM(GFX_ARGB32_OFFSET_R); } \
-        SUM(GFX_ARGB32_OFFSET_A);
-    for (int32_t minor = aStartMinor;
-         minor < aStartMinor + aLeftLobe;
-         minor++) {
-      OUTPUT_PIXEL();
-      SUM_PIXEL();
-      nextInput += aStrideMinor;
-      aOutput += aStrideMinor;
-    }
-    for (int32_t minor = aStartMinor + aLeftLobe;
-         minor < aEndMinor - aRightLobe - 1;
-         minor++) {
-      OUTPUT_PIXEL();
-      SUM_PIXEL();
-      lastInput += aStrideMinor;
-      nextInput += aStrideMinor;
-      aOutput += aStrideMinor;
-    }
-    // nextInput is now aInput + aEndMinor*aStrideMinor. Set it back to
-    // aInput + (aEndMinor - 1)*aStrideMinor so we read the last pixel in every
-    // iteration of the next loop.
-    nextInput -= aStrideMinor;
-    for (int32_t minor = aEndMinor - aRightLobe - 1; minor < aEndMinor; minor++) {
-      OUTPUT_PIXEL();
-      SUM_PIXEL();
-      lastInput += aStrideMinor;
-      aOutput += aStrideMinor;
-#undef SUM_PIXEL
-#undef SUM
-    }
-  } else {
-    for (int32_t minor = aStartMinor; minor < aEndMinor; minor++) {
-      int32_t tmp = minor - aLeftLobe;
-      int32_t last = std::max(tmp, aStartMinor);
-      int32_t next = std::min(tmp + int32_t(boxSize), aEndMinor - 1);
-
-      OUTPUT_PIXEL();
-#define SUM(j)     sums[j] += aInput[aStrideMinor*next + j] - \
-                              aInput[aStrideMinor*last + j];
-      if (!aAlphaOnly) { SUM(GFX_ARGB32_OFFSET_B);
-                         SUM(GFX_ARGB32_OFFSET_G);
-                         SUM(GFX_ARGB32_OFFSET_R); }
-      SUM(GFX_ARGB32_OFFSET_A);
-      aOutput += aStrideMinor;
-#undef SUM
-#undef OUTPUT_PIXEL
-#undef OUTPUT
-    }
-  }
-}
-
-static uint32_t
-GetBlurBoxSize(double aStdDev)
-{
-  NS_ASSERTION(aStdDev >= 0, "Negative standard deviations not allowed");
-
-  double size = aStdDev*3*sqrt(2*M_PI)/4;
-  // Doing super-large blurs accurately isn't very important.
-  uint32_t max = 1024;
-  if (size > max)
-    return max;
-  return uint32_t(floor(size + 0.5));
-}
-
-nsresult
-SVGFEGaussianBlurElement::GetDXY(uint32_t *aDX, uint32_t *aDY,
-                                 const nsSVGFilterInstance& aInstance)
-{
-  float stdX = aInstance.GetPrimitiveNumber(SVGContentUtils::X,
-                                            &mNumberPairAttributes[STD_DEV],
-                                            nsSVGNumberPair::eFirst);
-  float stdY = aInstance.GetPrimitiveNumber(SVGContentUtils::Y,
-                                            &mNumberPairAttributes[STD_DEV],
-                                            nsSVGNumberPair::eSecond);
-  if (stdX < 0 || stdY < 0)
-    return NS_ERROR_FAILURE;
-
-  // If the box size is greater than twice the temporary surface size
-  // in an axis, then each pixel will be set to the average of all the
-  // other pixel values.
-  *aDX = GetBlurBoxSize(stdX);
-  *aDY = GetBlurBoxSize(stdY);
-  return NS_OK;
-}
-
-static bool
-AreAllColorChannelsZero(const nsSVGFE::Image* aTarget)
-{
-  return aTarget->mConstantColorChannels &&
-         aTarget->mImage->GetDataSize() >= 4 &&
-         (*reinterpret_cast<uint32_t*>(aTarget->mImage->Data()) & 0x00FFFFFF) == 0;
-}
-
-void
-SVGFEGaussianBlurElement::GaussianBlur(const Image* aSource,
-                                       const Image* aTarget,
-                                       const nsIntRect& aDataRect,
-                                       uint32_t aDX, uint32_t aDY)
-{
-  NS_ASSERTION(nsIntRect(0, 0, aTarget->mImage->Width(), aTarget->mImage->Height()).Contains(aDataRect),
-               "aDataRect out of bounds");
-
-  const fallible_t fallible = fallible_t();
-  nsAutoArrayPtr<uint8_t> tmp(new (fallible) uint8_t[aTarget->mImage->GetDataSize()]);
-  if (!tmp)
-    return;
-  memset(tmp, 0, aTarget->mImage->GetDataSize());
-
-  bool alphaOnly = AreAllColorChannelsZero(aTarget);
-
-  const uint8_t* sourceData = aSource->mImage->Data();
-  uint8_t* targetData = aTarget->mImage->Data();
-  uint32_t stride = aTarget->mImage->Stride();
-
-  if (aDX == 0) {
-    CopyDataRect(tmp, sourceData, stride, aDataRect);
-  } else {
-    int32_t longLobe = aDX/2;
-    int32_t shortLobe = (aDX & 1) ? longLobe : longLobe - 1;
-    for (int32_t major = aDataRect.y; major < aDataRect.YMost(); ++major) {
-      int32_t ms = major*stride;
-      BoxBlur(sourceData + ms, tmp + ms, 4, aDataRect.x, aDataRect.XMost(), longLobe, shortLobe, alphaOnly);
-      BoxBlur(tmp + ms, targetData + ms, 4, aDataRect.x, aDataRect.XMost(), shortLobe, longLobe, alphaOnly);
-      BoxBlur(targetData + ms, tmp + ms, 4, aDataRect.x, aDataRect.XMost(), longLobe, longLobe, alphaOnly);
-    }
-  }
-
-  if (aDY == 0) {
-    CopyDataRect(targetData, tmp, stride, aDataRect);
-  } else {
-    int32_t longLobe = aDY/2;
-    int32_t shortLobe = (aDY & 1) ? longLobe : longLobe - 1;
-    for (int32_t major = aDataRect.x; major < aDataRect.XMost(); ++major) {
-      int32_t ms = major*4;
-      BoxBlur(tmp + ms, targetData + ms, stride, aDataRect.y, aDataRect.YMost(), longLobe, shortLobe, alphaOnly);
-      BoxBlur(targetData + ms, tmp + ms, stride, aDataRect.y, aDataRect.YMost(), shortLobe, longLobe, alphaOnly);
-      BoxBlur(tmp + ms, targetData + ms, stride, aDataRect.y, aDataRect.YMost(), longLobe, longLobe, alphaOnly);
-    }
-  }
-}
-
-static void
-InflateRectForBlurDXY(nsIntRect* aRect, uint32_t aDX, uint32_t aDY)
-{
-  aRect->Inflate(3*(aDX/2), 3*(aDY/2));
-}
-
-static void
-ClearRect(gfxImageSurface* aSurface, int32_t aX, int32_t aY,
-          int32_t aXMost, int32_t aYMost)
-{
-  NS_ASSERTION(aX <= aXMost && aY <= aYMost, "Invalid rectangle");
-  NS_ASSERTION(aX >= 0 && aY >= 0 && aXMost <= aSurface->Width() && aYMost <= aSurface->Height(),
-               "Rectangle out of bounds");
-
-  if (aX == aXMost || aY == aYMost)
-    return;
-  for (int32_t y = aY; y < aYMost; ++y) {
-    memset(aSurface->Data() + aSurface->Stride()*y + aX*4, 0, (aXMost - aX)*4);
-  }
-}
-
-// Clip aTarget's image to its filter primitive subregion.
-// aModifiedRect contains all the pixels which might not be RGBA(0,0,0,0),
-// it's relative to the surface data.
-static void
-ClipTarget(nsSVGFilterInstance* aInstance, const nsSVGFE::Image* aTarget,
-           const nsIntRect& aModifiedRect)
-{
-  nsIntPoint surfaceTopLeft = aInstance->GetSurfaceRect().TopLeft();
-
-  NS_ASSERTION(aInstance->GetSurfaceRect().Contains(aModifiedRect + surfaceTopLeft),
-               "Modified data area overflows the surface?");
-
-  nsIntRect clip = aModifiedRect;
-  nsSVGUtils::ClipToGfxRect(&clip,
-    aTarget->mFilterPrimitiveSubregion - gfxPoint(surfaceTopLeft.x, surfaceTopLeft.y));
-
-  ClearRect(aTarget->mImage, aModifiedRect.x, aModifiedRect.y, aModifiedRect.XMost(), clip.y);
-  ClearRect(aTarget->mImage, aModifiedRect.x, clip.y, clip.x, clip.YMost());
-  ClearRect(aTarget->mImage, clip.XMost(), clip.y, aModifiedRect.XMost(), clip.YMost());
-  ClearRect(aTarget->mImage, aModifiedRect.x, clip.YMost(), aModifiedRect.XMost(), aModifiedRect.YMost());
-}
-
-static void
-ClipComputationRectToSurface(nsSVGFilterInstance* aInstance,
-                             nsIntRect* aDataRect)
-{
-  aDataRect->IntersectRect(*aDataRect,
-          nsIntRect(nsIntPoint(0, 0), aInstance->GetSurfaceRect().Size()));
-}
-
-nsresult
-SVGFEGaussianBlurElement::Filter(nsSVGFilterInstance* aInstance,
-                                 const nsTArray<const Image*>& aSources,
-                                 const Image* aTarget,
-                                 const nsIntRect& rect)
-{
-  uint32_t dx, dy;
-  nsresult rv = GetDXY(&dx, &dy, *aInstance);
-  if (NS_FAILED(rv))
-    return rv;
-
-  nsIntRect computationRect = rect;
-  InflateRectForBlurDXY(&computationRect, dx, dy);
-  ClipComputationRectToSurface(aInstance, &computationRect);
-  GaussianBlur(aSources[0], aTarget, computationRect, dx, dy);
-  ClipTarget(aInstance, aTarget, computationRect);
-  return NS_OK;
+  stdX = std::min(stdX, kMaxStdDeviation);
+  stdY = std::min(stdY, kMaxStdDeviation);
+  FilterPrimitiveDescription descr(FilterPrimitiveDescription::eGaussianBlur);
+  descr.Attributes().Set(eGaussianBlurStdDeviation, Size(stdX, stdY));
+  return descr;
 }
 
 bool
 SVGFEGaussianBlurElement::AttributeAffectsRendering(int32_t aNameSpaceID,
                                                     nsIAtom* aAttribute) const
 {
   return SVGFEGaussianBlurElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
          (aNameSpaceID == kNameSpaceID_None &&
@@ -356,50 +98,16 @@ SVGFEGaussianBlurElement::AttributeAffec
 }
 
 void
 SVGFEGaussianBlurElement::GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources)
 {
   aSources.AppendElement(nsSVGStringInfo(&mStringAttributes[IN1], this));
 }
 
-nsIntRect
-SVGFEGaussianBlurElement::InflateRectForBlur(const nsIntRect& aRect,
-                                             const nsSVGFilterInstance& aInstance)
-{
-  uint32_t dX, dY;
-  nsresult rv = GetDXY(&dX, &dY, aInstance);
-  nsIntRect result = aRect;
-  if (NS_SUCCEEDED(rv)) {
-    InflateRectForBlurDXY(&result, dX, dY);
-  }
-  return result;
-}
-
-nsIntRect
-SVGFEGaussianBlurElement::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-        const nsSVGFilterInstance& aInstance)
-{
-  return InflateRectForBlur(aSourceBBoxes[0], aInstance);
-}
-
-void
-SVGFEGaussianBlurElement::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
-          nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance)
-{
-  aSourceBBoxes[0] = InflateRectForBlur(aTargetBBox, aInstance);
-}
-
-nsIntRect
-SVGFEGaussianBlurElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
-                                            const nsSVGFilterInstance& aInstance)
-{
-  return InflateRectForBlur(aSourceChangeBoxes[0], aInstance);
-}
-
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 nsSVGElement::NumberPairAttributesInfo
 SVGFEGaussianBlurElement::GetNumberPairInfo()
 {
   return NumberPairAttributesInfo(mNumberPairAttributes, sNumberPairInfo,
                                   ArrayLength(sNumberPairInfo));
--- a/content/svg/content/src/SVGFEGaussianBlurElement.h
+++ b/content/svg/content/src/SVGFEGaussianBlurElement.h
@@ -26,31 +26,24 @@ protected:
   SVGFEGaussianBlurElement(already_AddRefed<nsINodeInfo> aNodeInfo)
     : SVGFEGaussianBlurElementBase(aNodeInfo)
   {
   }
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
 public:
-  virtual nsresult Filter(nsSVGFilterInstance* aInstance,
-                          const nsTArray<const Image*>& aSources,
-                          const Image* aTarget,
-                          const nsIntRect& aDataRect) MOZ_OVERRIDE;
+  virtual FilterPrimitiveDescription
+    GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                            const IntRect& aFilterSubregion,
+                            nsTArray<nsRefPtr<gfxASurface> >& aInputImages) MOZ_OVERRIDE;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const MOZ_OVERRIDE;
   virtual nsSVGString& GetResultImageName() MOZ_OVERRIDE { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo >& aSources) MOZ_OVERRIDE;
-  virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-          const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
-  virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
-          nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
-  virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
-          const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
-
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
   already_AddRefed<SVGAnimatedNumber> StdDeviationX();
   already_AddRefed<SVGAnimatedNumber> StdDeviationY();
   void SetStdDeviation(float stdDeviationX, float stdDeviationY);
@@ -61,22 +54,14 @@ protected:
 
   enum { STD_DEV };
   nsSVGNumberPair mNumberPairAttributes[1];
   static NumberPairInfo sNumberPairInfo[1];
 
   enum { RESULT, IN1 };
   nsSVGString mStringAttributes[2];
   static StringInfo sStringInfo[2];
-
-private:
-  nsresult GetDXY(uint32_t *aDX, uint32_t *aDY, const nsSVGFilterInstance& aInstance);
-  nsIntRect InflateRectForBlur(const nsIntRect& aRect, const nsSVGFilterInstance& aInstance);
-
-  void GaussianBlur(const Image *aSource, const Image *aTarget,
-                    const nsIntRect& aDataRect,
-                    uint32_t aDX, uint32_t aDY);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_SVGFEGaussianBlurElement_h
--- a/content/svg/content/src/SVGFEImageElement.cpp
+++ b/content/svg/content/src/SVGFEImageElement.cpp
@@ -7,19 +7,22 @@
 
 #include "mozilla/dom/SVGFEImageElementBinding.h"
 #include "mozilla/dom/SVGFilterElement.h"
 #include "nsContentUtils.h"
 #include "nsLayoutUtils.h"
 #include "nsSVGUtils.h"
 #include "nsNetUtil.h"
 #include "imgIContainer.h"
+#include "gfx2DGlue.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEImage)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGFEImageElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGFEImageElementBinding::Wrap(aCx, aScope, this);
 }
@@ -182,91 +185,82 @@ already_AddRefed<SVGAnimatedString>
 SVGFEImageElement::Href()
 {
   return mStringAttributes[HREF].ToDOMAnimatedString(this);
 }
 
 //----------------------------------------------------------------------
 // nsIDOMSVGFEImageElement methods
 
-nsresult
-SVGFEImageElement::Filter(nsSVGFilterInstance *instance,
-                          const nsTArray<const Image*>& aSources,
-                          const Image* aTarget,
-                          const nsIntRect& rect)
+FilterPrimitiveDescription
+SVGFEImageElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                                           const IntRect& aFilterSubregion,
+                                           nsTArray<nsRefPtr<gfxASurface> >& aInputImages)
 {
   nsIFrame* frame = GetPrimaryFrame();
-  if (!frame) return NS_ERROR_FAILURE;
+  if (!frame) {
+    return FilterPrimitiveDescription(FilterPrimitiveDescription::eNone);
+  }
 
   nsCOMPtr<imgIRequest> currentRequest;
   GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
              getter_AddRefs(currentRequest));
 
   nsCOMPtr<imgIContainer> imageContainer;
-  if (currentRequest)
+  if (currentRequest) {
     currentRequest->GetImage(getter_AddRefs(imageContainer));
+  }
 
   nsRefPtr<gfxASurface> currentFrame;
-  if (imageContainer)
+  if (imageContainer) {
     imageContainer->GetFrame(imgIContainer::FRAME_CURRENT,
                              imgIContainer::FLAG_SYNC_DECODE,
                              getter_AddRefs(currentFrame));
-
-  // We need to wrap the surface in a pattern to have somewhere to set the
-  // graphics filter.
-  nsRefPtr<gfxPattern> thebesPattern;
-  if (currentFrame)
-    thebesPattern = new gfxPattern(currentFrame);
-
-  if (thebesPattern) {
-    thebesPattern->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(frame));
-
-    int32_t nativeWidth, nativeHeight;
-    imageContainer->GetWidth(&nativeWidth);
-    imageContainer->GetHeight(&nativeHeight);
+  }
 
-    const gfxRect& filterSubregion = aTarget->mFilterPrimitiveSubregion;
-
-    gfxMatrix viewBoxTM =
-      SVGContentUtils::GetViewBoxTransform(filterSubregion.Width(), filterSubregion.Height(),
-                                           0,0, nativeWidth, nativeHeight,
-                                           mPreserveAspectRatio);
-
-    gfxMatrix xyTM = gfxMatrix().Translate(gfxPoint(filterSubregion.X(), filterSubregion.Y()));
-
-    gfxMatrix TM = viewBoxTM * xyTM;
-    
-    nsRefPtr<gfxContext> ctx = new gfxContext(aTarget->mImage);
-    nsSVGUtils::CompositePatternMatrix(ctx, thebesPattern, TM, nativeWidth, nativeHeight, 1.0);
+  if (!currentFrame) {
+    return FilterPrimitiveDescription(FilterPrimitiveDescription::eNone);
   }
 
-  return NS_OK;
+  IntSize nativeSize;
+  imageContainer->GetWidth(&nativeSize.width);
+  imageContainer->GetHeight(&nativeSize.height);
+
+  gfxMatrix viewBoxTM =
+    SVGContentUtils::GetViewBoxTransform(aFilterSubregion.width, aFilterSubregion.height,
+                                         0, 0, nativeSize.width, nativeSize.height,
+                                         mPreserveAspectRatio);
+  Matrix xyTM = Matrix().Translate(aFilterSubregion.x, aFilterSubregion.y);
+  Matrix TM = ToMatrix(viewBoxTM) * xyTM;
+
+  Filter filter = ToFilter(nsLayoutUtils::GetGraphicsFilterForFrame(frame));
+
+  FilterPrimitiveDescription descr(FilterPrimitiveDescription::eImage);
+  descr.Attributes().Set(eImageFilter, (uint32_t)filter);
+  descr.Attributes().Set(eImageTransform, TM);
+
+  // Append the image to aInputImages and store its index in the description.
+  size_t imageIndex = aInputImages.Length();
+  aInputImages.AppendElement(currentFrame);
+  descr.Attributes().Set(eImageInputIndex, (uint32_t)imageIndex);
+
+  return descr;
 }
 
 bool
 SVGFEImageElement::AttributeAffectsRendering(int32_t aNameSpaceID,
                                              nsIAtom* aAttribute) const
 {
   // nsGkAtoms::href is deliberately omitted as the frame has special
   // handling to load the image
   return SVGFEImageElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
          (aNameSpaceID == kNameSpaceID_None &&
           aAttribute == nsGkAtoms::preserveAspectRatio);
 }
 
-nsIntRect
-SVGFEImageElement::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-        const nsSVGFilterInstance& aInstance)
-{
-  // XXX can do better here ... we could check what we know of the source
-  // image bounds and compute an accurate bounding box for the filter
-  // primitive result.
-  return GetMaxRect();
-}
-
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
 SVGFEImageElement::PreserveAspectRatio()
 {
   nsRefPtr<DOMSVGAnimatedPreserveAspectRatio> ratio;
   mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(getter_AddRefs(ratio), this);
--- a/content/svg/content/src/SVGFEImageElement.h
+++ b/content/svg/content/src/SVGFEImageElement.h
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_SVGFEImageElement_h
 #define mozilla_dom_SVGFEImageElement_h
 
 #include "nsSVGFilters.h"
+#include "SVGAnimatedPreserveAspectRatio.h"
 
 class SVGFEImageFrame;
 
 nsresult NS_NewSVGFEImageElement(nsIContent **aResult,
                                  already_AddRefed<nsINodeInfo> aNodeInfo);
 
 namespace mozilla {
 namespace dom {
@@ -32,25 +33,23 @@ protected:
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
 public:
   virtual bool SubregionIsUnionOfRegions() MOZ_OVERRIDE { return false; }
 
   // interfaces:
   NS_DECL_ISUPPORTS_INHERITED
 
-  virtual nsresult Filter(nsSVGFilterInstance* aInstance,
-                          const nsTArray<const Image*>& aSources,
-                          const Image* aTarget,
-                          const nsIntRect& aDataRect) MOZ_OVERRIDE;
+  virtual FilterPrimitiveDescription
+    GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                            const IntRect& aFilterSubregion,
+                            nsTArray<nsRefPtr<gfxASurface> >& aInputImages) MOZ_OVERRIDE;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const MOZ_OVERRIDE;
   virtual nsSVGString& GetResultImageName() MOZ_OVERRIDE { return mStringAttributes[RESULT]; }
-  virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-          const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
 
   // nsIContent
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue, bool aNotify) MOZ_OVERRIDE;
@@ -70,18 +69,17 @@ public:
 
 private:
   // Invalidate users of the filter containing this element.
   void Invalidate();
 
   nsresult LoadSVGImage(bool aForce, bool aNotify);
 
 protected:
-  virtual bool OperatesOnSRGB(nsSVGFilterInstance*,
-                                int32_t, Image*) MOZ_OVERRIDE { return true; }
+  virtual bool ProducesSRGB() MOZ_OVERRIDE { return true; }
 
   virtual SVGAnimatedPreserveAspectRatio *GetPreserveAspectRatio() MOZ_OVERRIDE;
   virtual StringAttributesInfo GetStringInfo() MOZ_OVERRIDE;
 
   enum { RESULT, HREF };
   nsSVGString mStringAttributes[2];
   static StringInfo sStringInfo[2];
 
--- a/content/svg/content/src/SVGFEMergeElement.cpp
+++ b/content/svg/content/src/SVGFEMergeElement.cpp
@@ -1,50 +1,43 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGFEMergeElement.h"
 #include "mozilla/dom/SVGFEMergeElementBinding.h"
 #include "mozilla/dom/SVGFEMergeNodeElement.h"
-#include "gfxContext.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEMerge)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGFEMergeElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGFEMergeElementBinding::Wrap(aCx, aScope, this);
 }
 
 nsSVGElement::StringInfo SVGFEMergeElement::sStringInfo[1] =
 {
   { &nsGkAtoms::result, kNameSpaceID_None, true }
 };
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEMergeElement)
 
-nsresult
-SVGFEMergeElement::Filter(nsSVGFilterInstance *instance,
-                          const nsTArray<const Image*>& aSources,
-                          const Image* aTarget,
-                          const nsIntRect& rect)
+FilterPrimitiveDescription
+SVGFEMergeElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                                           const IntRect& aFilterSubregion,
+                                           nsTArray<nsRefPtr<gfxASurface> >& aInputImages)
 {
-  gfxContext ctx(aTarget->mImage);
-  ctx.Clip(aTarget->mFilterPrimitiveSubregion);
-
-  for (uint32_t i = 0; i < aSources.Length(); i++) {
-    ctx.SetSource(aSources[i]->mImage);
-    ctx.Paint();
-  }
-  return NS_OK;
+  return FilterPrimitiveDescription(FilterPrimitiveDescription::eMerge);
 }
 
 void
 SVGFEMergeElement::GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources)
 {
   for (nsIContent* child = nsINode::GetFirstChild();
        child;
        child = child->GetNextSibling()) {
--- a/content/svg/content/src/SVGFEMergeElement.h
+++ b/content/svg/content/src/SVGFEMergeElement.h
@@ -24,20 +24,20 @@ protected:
   SVGFEMergeElement(already_AddRefed<nsINodeInfo> aNodeInfo)
     : SVGFEMergeElementBase(aNodeInfo)
   {
   }
   virtual JSObject* WrapNode(JSContext *cx,
                              JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
 
 public:
-  virtual nsresult Filter(nsSVGFilterInstance* aInstance,
-                          const nsTArray<const Image*>& aSources,
-                          const Image* aTarget,
-                          const nsIntRect& aDataRect) MOZ_OVERRIDE;
+  virtual FilterPrimitiveDescription
+    GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                            const IntRect& aFilterSubregion,
+                            nsTArray<nsRefPtr<gfxASurface> >& aInputImages) MOZ_OVERRIDE;
   virtual nsSVGString& GetResultImageName() MOZ_OVERRIDE { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) MOZ_OVERRIDE;
 
   // nsIContent
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 protected:
   virtual StringAttributesInfo GetStringInfo() MOZ_OVERRIDE;
 
--- a/content/svg/content/src/SVGFEMorphologyElement.cpp
+++ b/content/svg/content/src/SVGFEMorphologyElement.cpp
@@ -4,29 +4,27 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGFEMorphologyElement.h"
 #include "mozilla/dom/SVGFEMorphologyElementBinding.h"
 #include "nsSVGFilterInstance.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEMorphology)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGFEMorphologyElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGFEMorphologyElementBinding::Wrap(aCx, aScope, this);
 }
 
-// Morphology Operators
-static const unsigned short SVG_OPERATOR_ERODE = 1;
-static const unsigned short SVG_OPERATOR_DILATE = 2;
-
 nsSVGElement::NumberPairInfo SVGFEMorphologyElement::sNumberPairInfo[1] =
 {
   { &nsGkAtoms::radius, 0, 0 }
 };
 
 nsSVGEnumMapping SVGFEMorphologyElement::sOperatorMap[] = {
   {&nsGkAtoms::erode, SVG_OPERATOR_ERODE},
   {&nsGkAtoms::dilate, SVG_OPERATOR_DILATE},
@@ -88,48 +86,16 @@ SVGFEMorphologyElement::SetRadius(float 
 }
 
 void
 SVGFEMorphologyElement::GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources)
 {
   aSources.AppendElement(nsSVGStringInfo(&mStringAttributes[IN1], this));
 }
 
-nsIntRect
-SVGFEMorphologyElement::InflateRect(const nsIntRect& aRect,
-                                    const nsSVGFilterInstance& aInstance)
-{
-  int32_t rx, ry;
-  GetRXY(&rx, &ry, aInstance);
-  nsIntRect result = aRect;
-  result.Inflate(std::max(0, rx), std::max(0, ry));
-  return result;
-}
-
-nsIntRect
-SVGFEMorphologyElement::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-        const nsSVGFilterInstance& aInstance)
-{
-  return InflateRect(aSourceBBoxes[0], aInstance);
-}
-
-void
-SVGFEMorphologyElement::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
-          nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance)
-{
-  aSourceBBoxes[0] = InflateRect(aTargetBBox, aInstance);
-}
-
-nsIntRect
-SVGFEMorphologyElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
-                                          const nsSVGFilterInstance& aInstance)
-{
-  return InflateRect(aSourceChangeBoxes[0], aInstance);
-}
-
 #define MORPHOLOGY_EPSILON 0.0001
 
 void
 SVGFEMorphologyElement::GetRXY(int32_t *aRX, int32_t *aRY,
                                const nsSVGFilterInstance& aInstance)
 {
   // Subtract an epsilon here because we don't want a value that's just
   // slightly larger than an integer to round up to the next integer; it's
@@ -140,101 +106,28 @@ SVGFEMorphologyElement::GetRXY(int32_t *
                                                   nsSVGNumberPair::eFirst) -
                      MORPHOLOGY_EPSILON);
   *aRY = NSToIntCeil(aInstance.GetPrimitiveNumber(SVGContentUtils::Y,
                                                   &mNumberPairAttributes[RADIUS],
                                                   nsSVGNumberPair::eSecond) -
                      MORPHOLOGY_EPSILON);
 }
 
-template<uint32_t Operator>
-static void
-DoMorphology(nsSVGFilterInstance* instance,
-             uint8_t* sourceData,
-             uint8_t* targetData,
-             int32_t stride,
-             const nsIntRect& rect,
-             int32_t rx,
-             int32_t ry)
-{
-  static_assert(Operator == SVG_OPERATOR_ERODE ||
-                Operator == SVG_OPERATOR_DILATE,
-                "unexpected morphology operator");
-
-  volatile uint8_t extrema[4];         // RGBA magnitude of extrema
-
-  // Scan the kernel for each pixel to determine max/min RGBA values.
-  for (int32_t y = rect.y; y < rect.YMost(); y++) {
-    int32_t startY = std::max(0, y - ry);
-    // We need to read pixels not just in 'rect', which is limited to
-    // the dirty part of our filter primitive subregion, but all pixels in
-    // the given radii from the source surface, so use the surface size here.
-    int32_t endY = std::min(y + ry, instance->GetSurfaceHeight() - 1);
-    for (int32_t x = rect.x; x < rect.XMost(); x++) {
-      int32_t startX = std::max(0, x - rx);
-      int32_t endX = std::min(x + rx, instance->GetSurfaceWidth() - 1);
-      int32_t targIndex = y * stride + 4 * x;
-
-      for (int32_t i = 0; i < 4; i++) {
-        extrema[i] = sourceData[targIndex + i];
-      }
-      for (int32_t y1 = startY; y1 <= endY; y1++) {
-        for (int32_t x1 = startX; x1 <= endX; x1++) {
-          for (int32_t i = 0; i < 4; i++) {
-            uint8_t pixel = sourceData[y1 * stride + 4 * x1 + i];
-            if (Operator == SVG_OPERATOR_ERODE) {
-              extrema[i] -= (extrema[i] - pixel) & -(extrema[i] > pixel);
-            } else {
-              extrema[i] -= (extrema[i] - pixel) & -(extrema[i] < pixel);
-            }
-          }
-        }
-      }
-      targetData[targIndex  ] = extrema[0];
-      targetData[targIndex+1] = extrema[1];
-      targetData[targIndex+2] = extrema[2];
-      targetData[targIndex+3] = extrema[3];
-    }
-  }
-}
-
-nsresult
-SVGFEMorphologyElement::Filter(nsSVGFilterInstance* instance,
-                               const nsTArray<const Image*>& aSources,
-                               const Image* aTarget,
-                               const nsIntRect& rect)
+FilterPrimitiveDescription
+SVGFEMorphologyElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                                                const IntRect& aFilterSubregion,
+                                                nsTArray<nsRefPtr<gfxASurface> >& aInputImages)
 {
   int32_t rx, ry;
-  GetRXY(&rx, &ry, *instance);
-
-  if (rx < 0 || ry < 0) {
-    // XXX SVGContentUtils::ReportToConsole()
-    return NS_OK;
-  }
-  if (rx == 0 && ry == 0) {
-    return NS_OK;
-  }
-
-  // Clamp radii to prevent completely insane values:
-  rx = std::min(rx, 100000);
-  ry = std::min(ry, 100000);
-
-  uint8_t* sourceData = aSources[0]->mImage->Data();
-  uint8_t* targetData = aTarget->mImage->Data();
-  int32_t stride = aTarget->mImage->Stride();
-
-  if (mEnumAttributes[OPERATOR].GetAnimValue() == SVG_OPERATOR_ERODE) {
-    DoMorphology<SVG_OPERATOR_ERODE>(instance, sourceData, targetData, stride,
-                                     rect, rx, ry);
-  } else {
-    DoMorphology<SVG_OPERATOR_DILATE>(instance, sourceData, targetData, stride,
-                                      rect, rx, ry);
-  }
-
-  return NS_OK;
+  GetRXY(&rx, &ry, *aInstance);
+  FilterPrimitiveDescription descr(FilterPrimitiveDescription::eMorphology);
+  descr.Attributes().Set(eMorphologyRadii, Size(rx, ry));
+  descr.Attributes().Set(eMorphologyOperator,
+                         (uint32_t)mEnumAttributes[OPERATOR].GetAnimValue());
+  return descr;
 }
 
 bool
 SVGFEMorphologyElement::AttributeAffectsRendering(int32_t aNameSpaceID,
                                                   nsIAtom* aAttribute) const
 {
   return SVGFEMorphologyElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
          (aNameSpaceID == kNameSpaceID_None &&
--- a/content/svg/content/src/SVGFEMorphologyElement.h
+++ b/content/svg/content/src/SVGFEMorphologyElement.h
@@ -27,43 +27,36 @@ protected:
   SVGFEMorphologyElement(already_AddRefed<nsINodeInfo> aNodeInfo)
     : SVGFEMorphologyElementBase(aNodeInfo)
   {
   }
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
 public:
-  virtual nsresult Filter(nsSVGFilterInstance* aInstance,
-                          const nsTArray<const Image*>& aSources,
-                          const Image* aTarget,
-                          const nsIntRect& aDataRect) MOZ_OVERRIDE;
+  virtual FilterPrimitiveDescription
+    GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                            const IntRect& aFilterSubregion,
+                            nsTArray<nsRefPtr<gfxASurface> >& aInputImages) MOZ_OVERRIDE;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const MOZ_OVERRIDE;
   virtual nsSVGString& GetResultImageName() MOZ_OVERRIDE { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) MOZ_OVERRIDE;
-  virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-          const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
-  virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
-          nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
-  virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
-          const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
   already_AddRefed<SVGAnimatedEnumeration> Operator();
   already_AddRefed<SVGAnimatedNumber> RadiusX();
   already_AddRefed<SVGAnimatedNumber> RadiusY();
   void SetRadius(float rx, float ry);
 
 protected:
   void GetRXY(int32_t *aRX, int32_t *aRY, const nsSVGFilterInstance& aInstance);
-  nsIntRect InflateRect(const nsIntRect& aRect, const nsSVGFilterInstance& aInstance);
 
   virtual NumberPairAttributesInfo GetNumberPairInfo() MOZ_OVERRIDE;
   virtual EnumAttributesInfo GetEnumInfo() MOZ_OVERRIDE;
   virtual StringAttributesInfo GetStringInfo() MOZ_OVERRIDE;
 
   enum { RADIUS };
   nsSVGNumberPair mNumberPairAttributes[1];
   static NumberPairInfo sNumberPairInfo[1];
--- a/content/svg/content/src/SVGFEOffsetElement.cpp
+++ b/content/svg/content/src/SVGFEOffsetElement.cpp
@@ -5,16 +5,18 @@
 
 #include "mozilla/dom/SVGFEOffsetElement.h"
 #include "mozilla/dom/SVGFEOffsetElementBinding.h"
 #include "nsSVGFilterInstance.h"
 #include "gfxContext.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEOffset)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGFEOffsetElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGFEOffsetElementBinding::Wrap(aCx, aScope, this);
 }
@@ -62,33 +64,25 @@ nsIntPoint
 SVGFEOffsetElement::GetOffset(const nsSVGFilterInstance& aInstance)
 {
   return nsIntPoint(int32_t(aInstance.GetPrimitiveNumber(
                               SVGContentUtils::X, &mNumberAttributes[DX])),
                     int32_t(aInstance.GetPrimitiveNumber(
                               SVGContentUtils::Y, &mNumberAttributes[DY])));
 }
 
-nsresult
-SVGFEOffsetElement::Filter(nsSVGFilterInstance* instance,
-                           const nsTArray<const Image*>& aSources,
-                           const Image* aTarget,
-                           const nsIntRect& rect)
+FilterPrimitiveDescription
+SVGFEOffsetElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                                            const IntRect& aFilterSubregion,
+                                            nsTArray<nsRefPtr<gfxASurface> >& aInputImages)
 {
-  nsIntPoint offset = GetOffset(*instance);
-
-  gfxContext ctx(aTarget->mImage);
-  ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
-  // Ensure rendering is limited to the filter primitive subregion
-  ctx.Clip(aTarget->mFilterPrimitiveSubregion);
-  ctx.Translate(gfxPoint(offset.x, offset.y));
-  ctx.SetSource(aSources[0]->mImage);
-  ctx.Paint();
-
-  return NS_OK;
+  FilterPrimitiveDescription descr(FilterPrimitiveDescription::eOffset);
+  nsIntPoint offset = GetOffset(*aInstance);
+  descr.Attributes().Set(eOffsetOffset, IntPoint(offset.x, offset.y));
+  return descr;
 }
 
 bool
 SVGFEOffsetElement::AttributeAffectsRendering(int32_t aNameSpaceID,
                                               nsIAtom* aAttribute) const
 {
   return SVGFEOffsetElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
          (aNameSpaceID == kNameSpaceID_None &&
@@ -98,37 +92,16 @@ SVGFEOffsetElement::AttributeAffectsRend
 }
 
 void
 SVGFEOffsetElement::GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources)
 {
   aSources.AppendElement(nsSVGStringInfo(&mStringAttributes[IN1], this));
 }
 
-nsIntRect
-SVGFEOffsetElement::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-        const nsSVGFilterInstance& aInstance)
-{
-  return aSourceBBoxes[0] + GetOffset(aInstance);
-}
-
-nsIntRect
-SVGFEOffsetElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
-                                      const nsSVGFilterInstance& aInstance)
-{
-  return aSourceChangeBoxes[0] + GetOffset(aInstance);
-}
-
-void
-SVGFEOffsetElement::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
-          nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance)
-{
-  aSourceBBoxes[0] = aTargetBBox - GetOffset(aInstance);
-}
-
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 nsSVGElement::NumberAttributesInfo
 SVGFEOffsetElement::GetNumberInfo()
 {
   return NumberAttributesInfo(mNumberAttributes, sNumberInfo,
                               ArrayLength(sNumberInfo));
--- a/content/svg/content/src/SVGFEOffsetElement.h
+++ b/content/svg/content/src/SVGFEOffsetElement.h
@@ -26,30 +26,24 @@ protected:
   SVGFEOffsetElement(already_AddRefed<nsINodeInfo> aNodeInfo)
     : SVGFEOffsetElementBase(aNodeInfo)
   {
   }
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
 public:
-  virtual nsresult Filter(nsSVGFilterInstance* aInstance,
-                          const nsTArray<const Image*>& aSources,
-                          const Image* aTarget,
-                          const nsIntRect& aDataRect) MOZ_OVERRIDE;
+  virtual FilterPrimitiveDescription
+    GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                            const IntRect& aFilterSubregion,
+                            nsTArray<nsRefPtr<gfxASurface> >& aInputImages) MOZ_OVERRIDE;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const MOZ_OVERRIDE;
   virtual nsSVGString& GetResultImageName() { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) MOZ_OVERRIDE;
-  virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-          const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
-  virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
-          nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
-  virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
-          const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
   already_AddRefed<SVGAnimatedNumber> Dx();
   already_AddRefed<SVGAnimatedNumber> Dy();
 
--- a/content/svg/content/src/SVGFEPointLightElement.cpp
+++ b/content/svg/content/src/SVGFEPointLightElement.cpp
@@ -1,18 +1,21 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGFEPointLightElement.h"
 #include "mozilla/dom/SVGFEPointLightElementBinding.h"
+#include "nsSVGFilterInstance.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEPointLight)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGFEPointLightElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGFEPointLightElementBinding::Wrap(aCx, aScope, this);
 }
@@ -39,16 +42,28 @@ SVGFEPointLightElement::AttributeAffects
   return aNameSpaceID == kNameSpaceID_None &&
          (aAttribute == nsGkAtoms::x ||
           aAttribute == nsGkAtoms::y ||
           aAttribute == nsGkAtoms::z);
 }
 
 //----------------------------------------------------------------------
 
+AttributeMap
+SVGFEPointLightElement::ComputeLightAttributes(nsSVGFilterInstance* aInstance)
+{
+  Point3D lightPos;
+  GetAnimatedNumberValues(&lightPos.x, &lightPos.y, &lightPos.z, nullptr);
+  
+  AttributeMap map;
+  map.Set(eLightType, (uint32_t)eLightTypePoint);
+  map.Set(ePointLightPosition, aInstance->ConvertLocation(lightPos));
+  return map;
+}
+
 already_AddRefed<SVGAnimatedNumber>
 SVGFEPointLightElement::X()
 {
   return mNumberAttributes[ATTR_X].ToDOMAnimatedNumber(this);
 }
 
 already_AddRefed<SVGAnimatedNumber>
 SVGFEPointLightElement::Y()
--- a/content/svg/content/src/SVGFEPointLightElement.h
+++ b/content/svg/content/src/SVGFEPointLightElement.h
@@ -4,37 +4,38 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_SVGFEPointLightElement_h
 #define mozilla_dom_SVGFEPointLightElement_h
 
 #include "nsSVGFilters.h"
 #include "nsSVGNumber2.h"
 
-typedef SVGFEUnstyledElement SVGFEPointLightElementBase;
-
 nsresult NS_NewSVGFEPointLightElement(nsIContent **aResult,
                                       already_AddRefed<nsINodeInfo> aNodeInfo);
 
 namespace mozilla {
 namespace dom {
 
+typedef SVGFELightElement SVGFEPointLightElementBase;
+
 class SVGFEPointLightElement : public SVGFEPointLightElementBase
 {
   friend nsresult (::NS_NewSVGFEPointLightElement(nsIContent **aResult,
                                                   already_AddRefed<nsINodeInfo> aNodeInfo));
 protected:
   SVGFEPointLightElement(already_AddRefed<nsINodeInfo> aNodeInfo)
     : SVGFEPointLightElementBase(aNodeInfo)
   {
   }
   virtual JSObject* WrapNode(JSContext *cx,
                              JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
 
 public:
+  virtual AttributeMap ComputeLightAttributes(nsSVGFilterInstance* aInstance) MOZ_OVERRIDE;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedNumber> X();
   already_AddRefed<SVGAnimatedNumber> Y();
--- a/content/svg/content/src/SVGFESpecularLightingElement.cpp
+++ b/content/svg/content/src/SVGFESpecularLightingElement.cpp
@@ -1,19 +1,22 @@
 /* a*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGFESpecularLightingElement.h"
 #include "mozilla/dom/SVGFESpecularLightingElementBinding.h"
 #include "nsSVGUtils.h"
+#include "nsSVGFilterInstance.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FESpecularLighting)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGFESpecularLightingElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGFESpecularLightingElementBinding::Wrap(aCx, aScope, this);
 }
@@ -59,68 +62,39 @@ SVGFESpecularLightingElement::KernelUnit
 {
   return mNumberPairAttributes[KERNEL_UNIT_LENGTH].ToDOMAnimatedNumber(
     nsSVGNumberPair::eSecond, this);
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
-nsresult
-SVGFESpecularLightingElement::Filter(nsSVGFilterInstance* instance,
-                                     const nsTArray<const Image*>& aSources,
-                                     const Image* aTarget,
-                                     const nsIntRect& rect)
+FilterPrimitiveDescription
+SVGFESpecularLightingElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                                                      const IntRect& aFilterSubregion,
+                                                      nsTArray<nsRefPtr<gfxASurface> >& aInputImages)
 {
   float specularExponent = mNumberAttributes[SPECULAR_EXPONENT].GetAnimValue();
+  float specularConstant = mNumberAttributes[SPECULAR_CONSTANT].GetAnimValue();
 
   // specification defined range (15.22)
-  if (specularExponent < 1 || specularExponent > 128)
-    return NS_ERROR_FAILURE;
+  if (specularExponent < 1 || specularExponent > 128) {
+    return FilterPrimitiveDescription(FilterPrimitiveDescription::eNone);
+  }
 
-  return SVGFESpecularLightingElementBase::Filter(instance, aSources, aTarget, rect);
+  FilterPrimitiveDescription descr(FilterPrimitiveDescription::eSpecularLighting);
+  descr.Attributes().Set(eSpecularLightingSpecularConstant, specularConstant);
+  descr.Attributes().Set(eSpecularLightingSpecularExponent, specularExponent);
+  return AddLightingAttributes(descr, aInstance);
 }
 
 bool
 SVGFESpecularLightingElement::AttributeAffectsRendering(int32_t aNameSpaceID,
                                                         nsIAtom* aAttribute) const
 {
   return SVGFESpecularLightingElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
          (aNameSpaceID == kNameSpaceID_None &&
           (aAttribute == nsGkAtoms::specularConstant ||
            aAttribute == nsGkAtoms::specularExponent));
 }
 
-void
-SVGFESpecularLightingElement::LightPixel(const float *N, const float *L,
-                                         nscolor color, uint8_t *targetData)
-{
-  float H[3];
-  H[0] = L[0];
-  H[1] = L[1];
-  H[2] = L[2] + 1;
-  NORMALIZE(H);
-
-  float kS = mNumberAttributes[SPECULAR_CONSTANT].GetAnimValue();
-  float dotNH = DOT(N, H);
-
-  bool invalid = dotNH <= 0 || kS <= 0;
-  kS *= invalid ? 0 : 1;
-  uint8_t minAlpha = invalid ? 255 : 0;
-
-  float specularNH =
-    kS * pow(dotNH, mNumberAttributes[SPECULAR_EXPONENT].GetAnimValue());
-
-  targetData[GFX_ARGB32_OFFSET_B] =
-    std::min(uint32_t(specularNH * NS_GET_B(color)), 255U);
-  targetData[GFX_ARGB32_OFFSET_G] =
-    std::min(uint32_t(specularNH * NS_GET_G(color)), 255U);
-  targetData[GFX_ARGB32_OFFSET_R] =
-    std::min(uint32_t(specularNH * NS_GET_R(color)), 255U);
-
-  targetData[GFX_ARGB32_OFFSET_A] =
-    std::max(minAlpha, std::max(targetData[GFX_ARGB32_OFFSET_B],
-                            std::max(targetData[GFX_ARGB32_OFFSET_G],
-                                   targetData[GFX_ARGB32_OFFSET_R])));
-}
-
 } // namespace dom
 } // namespace mozilla
--- a/content/svg/content/src/SVGFESpecularLightingElement.h
+++ b/content/svg/content/src/SVGFESpecularLightingElement.h
@@ -28,33 +28,28 @@ protected:
   {
   }
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
 public:
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
-  virtual nsresult Filter(nsSVGFilterInstance* aInstance,
-                          const nsTArray<const Image*>& aSources,
-                          const Image* aTarget,
-                          const nsIntRect& aDataRect);
+  virtual FilterPrimitiveDescription
+    GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                            const IntRect& aFilterSubregion,
+                            nsTArray<nsRefPtr<gfxASurface> >& aInputImages) MOZ_OVERRIDE;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
   already_AddRefed<SVGAnimatedNumber> SurfaceScale();
   already_AddRefed<SVGAnimatedNumber> SpecularConstant();
   already_AddRefed<SVGAnimatedNumber> SpecularExponent();
   already_AddRefed<SVGAnimatedNumber> KernelUnitLengthX();
   already_AddRefed<SVGAnimatedNumber> KernelUnitLengthY();
-
-protected:
-  virtual void LightPixel(const float *N, const float *L,
-                          nscolor color, uint8_t *targetData);
-
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_SVGFESpecularLightingElement_h
--- a/content/svg/content/src/SVGFESpotLightElement.cpp
+++ b/content/svg/content/src/SVGFESpotLightElement.cpp
@@ -1,18 +1,21 @@
 /* a*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGFESpotLightElement.h"
 #include "mozilla/dom/SVGFESpotLightElementBinding.h"
+#include "nsSVGFilterInstance.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FESpotLight)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGFESpotLightElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGFESpotLightElementBinding::Wrap(aCx, aScope, this);
 }
@@ -49,16 +52,38 @@ SVGFESpotLightElement::AttributeAffectsR
           aAttribute == nsGkAtoms::pointsAtY ||
           aAttribute == nsGkAtoms::pointsAtZ ||
           aAttribute == nsGkAtoms::specularExponent ||
           aAttribute == nsGkAtoms::limitingConeAngle);
 }
 
 //----------------------------------------------------------------------
 
+AttributeMap
+SVGFESpotLightElement::ComputeLightAttributes(nsSVGFilterInstance* aInstance)
+{
+  Point3D lightPos, pointsAt;
+  float specularExponent, limitingConeAngle;
+  GetAnimatedNumberValues(&lightPos.x, &lightPos.y, &lightPos.z,
+                          &pointsAt.x, &pointsAt.y, &pointsAt.z,
+                          &specularExponent, &limitingConeAngle,
+                          nullptr);
+  if (!mNumberAttributes[SVGFESpotLightElement::LIMITING_CONE_ANGLE].IsExplicitlySet()) {
+    limitingConeAngle = 90;
+  }
+
+  AttributeMap map;
+  map.Set(eLightType, (uint32_t)eLightTypeSpot);
+  map.Set(eSpotLightPosition, aInstance->ConvertLocation(lightPos));
+  map.Set(eSpotLightPointsAt, aInstance->ConvertLocation(pointsAt));
+  map.Set(eSpotLightFocus, specularExponent);
+  map.Set(eSpotLightLimitingConeAngle, limitingConeAngle);
+  return map;
+}
+
 already_AddRefed<SVGAnimatedNumber>
 SVGFESpotLightElement::X()
 {
   return mNumberAttributes[ATTR_X].ToDOMAnimatedNumber(this);
 }
 
 already_AddRefed<SVGAnimatedNumber>
 SVGFESpotLightElement::Y()
--- a/content/svg/content/src/SVGFESpotLightElement.h
+++ b/content/svg/content/src/SVGFESpotLightElement.h
@@ -4,40 +4,39 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_SVGFESpotLightElement_h
 #define mozilla_dom_SVGFESpotLightElement_h
 
 #include "nsSVGFilters.h"
 #include "nsSVGNumber2.h"
 
-class nsSVGFELightingElement;
-
 nsresult NS_NewSVGFESpotLightElement(nsIContent **aResult,
                                      already_AddRefed<nsINodeInfo> aNodeInfo);
 
 namespace mozilla {
 namespace dom {
 
-typedef SVGFEUnstyledElement SVGFESpotLightElementBase;
+typedef SVGFELightElement SVGFESpotLightElementBase;
 
 class SVGFESpotLightElement : public SVGFESpotLightElementBase
 {
   friend nsresult (::NS_NewSVGFESpotLightElement(nsIContent **aResult,
                                                  already_AddRefed<nsINodeInfo> aNodeInfo));
   friend class ::nsSVGFELightingElement;
 protected:
   SVGFESpotLightElement(already_AddRefed<nsINodeInfo> aNodeInfo)
     : SVGFESpotLightElementBase(aNodeInfo)
   {
   }
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
 public:
+  virtual AttributeMap ComputeLightAttributes(nsSVGFilterInstance* aInstance) MOZ_OVERRIDE;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedNumber> X();
   already_AddRefed<SVGAnimatedNumber> Y();
--- a/content/svg/content/src/SVGFETileElement.cpp
+++ b/content/svg/content/src/SVGFETileElement.cpp
@@ -5,16 +5,18 @@
 
 #include "mozilla/dom/SVGFETileElement.h"
 #include "mozilla/dom/SVGFETileElementBinding.h"
 #include "nsSVGFilterInstance.h"
 #include "gfxUtils.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FETile)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGFETileElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGFETileElementBinding::Wrap(aCx, aScope, this);
 }
@@ -38,378 +40,25 @@ SVGFETileElement::In1()
 }
 
 void
 SVGFETileElement::GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources)
 {
   aSources.AppendElement(nsSVGStringInfo(&mStringAttributes[IN1], this));
 }
 
-nsIntRect
-SVGFETileElement::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-        const nsSVGFilterInstance& aInstance)
-{
-  return GetMaxRect();
-}
-
-void
-SVGFETileElement::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
-          nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance)
-{
-  // Just assume we need the entire source bounding box, so do nothing.
-}
-
-nsIntRect
-SVGFETileElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
-                                    const nsSVGFilterInstance& aInstance)
-{
-  return GetMaxRect();
-}
-
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
-/*
- * This function computes the size of partial match on either side of the tile.
- * eg: If we are talking about the X-axis direction, then it computes, the 
- * size of the tile that would be copied to the lesser X-axis side (usually
- * left), the higher X-axis side (usualy right) and the centre.
- * This is needed because often, the tile doesn't exactly align to the target
- * region and is partially copied on the edges. This function computes the
- * dimensions of the partially copied regions in one axis.
- *
- * OUTPUT:
- * aLesserSidePartialMatchSize: The size of the partial match on the lesser
- *                              side of the axis being considered.
- *                              eg: for X-axis, usually left side and
- *                                  for Y-axis, usually top
- * aHigherSidePartialMatchSize: The size of the partial match on the higher
- *                              side of the axis being considered.
- *                              eg: for X-axis, usually right side and
- *                                  for Y-axis, usually bottom
- * aCentreSize: The size of the target area where the tile is copied in full.
- *              This lies between the lesser and higher side partial matches.
- *              (the partially matched areas may be of zero width)
- *
- * INPUT:
- * aLesserTargetExtent: Edge of the target area on the axis being considered
- *                      on the lesser side. (eg: usually left on the X-axis)
- * aTargetSize: Size of the target area on the axis being considered (eg:
- *              usually width for X-axis)
- * aLesserTileExtent: Edge of the tile on the axis being considered on the
- *                    lesser side.
- * aTileSize: Size of the tile on the axis being considered.
- */
-static inline void
-ComputePartialTileExtents(int32_t *aLesserSidePartialMatchSize,
-                          int32_t *aHigherSidePartialMatchSize,
-                          int32_t *aCentreSize,
-                          int32_t aLesserTargetExtent,
-                          int32_t aTargetSize,
-                          int32_t aLesserTileExtent,
-                          int32_t aTileSize)
-{
-  int32_t targetExtentMost = aLesserTargetExtent + aTargetSize;
-  int32_t tileExtentMost = aLesserTileExtent + aTileSize;
-
-  int32_t lesserSidePartialMatchSize;
-  if (aLesserTileExtent < aLesserTargetExtent) {
-    lesserSidePartialMatchSize = tileExtentMost - aLesserTargetExtent;
-  } else {
-    lesserSidePartialMatchSize = (aLesserTileExtent - aLesserTargetExtent) %
-                                    aTileSize;
-  }
-
-  int32_t higherSidePartialMatchSize;
-  if (lesserSidePartialMatchSize > aTargetSize) {
-    lesserSidePartialMatchSize = aTargetSize;
-    higherSidePartialMatchSize = 0;
-  } else if (tileExtentMost > targetExtentMost) {
-      higherSidePartialMatchSize = targetExtentMost - aLesserTileExtent;
-  } else {
-    higherSidePartialMatchSize = (targetExtentMost - tileExtentMost) %
-                                    aTileSize;
-  }
-
-  if (lesserSidePartialMatchSize + higherSidePartialMatchSize >
-        aTargetSize) {
-    higherSidePartialMatchSize = aTargetSize - lesserSidePartialMatchSize;
-  }
-
-  /*
-   * To understand the conditon below, let us consider the X-Axis:
-   * Lesser side is left and the Higher side is right.
-   * This implies:
-   * aTargetSize is rect.width.
-   * lesserSidePartialMatchSize would mean leftPartialTileWidth.
-   * higherSidePartialMatchSize would mean rightPartialTileWidth.
-   *
-   * leftPartialTileWidth == rect.width only happens when the tile entirely
-   * overlaps with the target area in the X-axis and exceeds its bounds by at
-   * least one pixel on the lower X-Axis side.
-   *
-   * leftPartialTileWidth + rightPartialTileWidth == rect.width only happens
-   * when the tile overlaps the target area in such a way that the edge of the
-   * tile on the higher X-Axis side cuts through the target area and there is no
-   * space for a complete tile in the X-Axis in the target area on either side
-   * of that edge. In this scenario, centre will be of zero width and the
-   * partial widths on left and right will add up to the width of the rect. In
-   * case the tile is bigger than the rect in the X-axis, it will get clipped
-   * and remain equal to rect.width.
-   *
-   * Therefore, those two conditions are separate cases which lead to centre
-   * being of zero width.
-   *
-   * The condition below is the same logic as above expressed independent of
-   * the axis in consideration.
-   */
-
-  int32_t centreSize;
-  if (lesserSidePartialMatchSize == aTargetSize ||
-        lesserSidePartialMatchSize + higherSidePartialMatchSize ==
-        aTargetSize) {
-    centreSize = 0;
-  } else {
-    centreSize = aTargetSize -
-                   (lesserSidePartialMatchSize + higherSidePartialMatchSize);
-  }
-
-  *aLesserSidePartialMatchSize = lesserSidePartialMatchSize;
-  *aHigherSidePartialMatchSize = higherSidePartialMatchSize;
-  *aCentreSize = centreSize;
-}
-
-static inline void
-TilePixels(uint8_t *aTargetData,
-           const uint8_t *aSourceData,
-           const nsIntRect &targetRegion,
-           const nsIntRect &aTile,
-           uint32_t aStride)
-{
-  if (targetRegion.IsEmpty()) {
-    return;
-  }
-
-  uint32_t tileRowCopyMemSize = aTile.width * 4;
-  uint32_t numTimesToCopyTileRows = targetRegion.width / aTile.width;
-
-  uint8_t *targetFirstRowOffset = aTargetData + 4 * targetRegion.x;
-  const uint8_t *tileFirstRowOffset = aSourceData + 4 * aTile.x;
-
-  int32_t tileYOffset = 0;
-  for (int32_t targetY = targetRegion.y;
-       targetY < targetRegion.YMost();
-       ++targetY) {
-    uint8_t *targetRowOffset = targetFirstRowOffset + aStride * targetY;
-    const uint8_t *tileRowOffset = tileFirstRowOffset +
-                                             aStride * (aTile.y + tileYOffset);
-
-    for (uint32_t i = 0; i < numTimesToCopyTileRows; ++i) {
-      memcpy(targetRowOffset + i * tileRowCopyMemSize,
-             tileRowOffset,
-             tileRowCopyMemSize);
-    }
-
-    tileYOffset = (tileYOffset + 1) % aTile.height;
-  }
-}
-
-nsresult
-SVGFETileElement::Filter(nsSVGFilterInstance *instance,
-                         const nsTArray<const Image*>& aSources,
-                         const Image* aTarget,
-                         const nsIntRect& rect)
+FilterPrimitiveDescription
+SVGFETileElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                                          const IntRect& aFilterSubregion,
+                                          nsTArray<nsRefPtr<gfxASurface> >& aInputImages)
 {
-  // XXX This code depends on the surface rect containing the filter
-  // primitive subregion. ComputeTargetBBox, ComputeNeededSourceBBoxes
-  // and ComputeChangeBBox are all pessimal, so that will normally be OK,
-  // but nothing clips mFilterPrimitiveSubregion so this should be changed.
-
-  nsIntRect tile;
-  bool res = gfxUtils::GfxRectToIntRect(aSources[0]->mFilterPrimitiveSubregion,
-                                        &tile);
-
-  NS_ENSURE_TRUE(res, NS_ERROR_FAILURE); // asserts on failure (not 
-  if (tile.IsEmpty())
-    return NS_OK;
-
-  const nsIntRect &surfaceRect = instance->GetSurfaceRect();
-  if (!tile.Intersects(surfaceRect)) {
-    // nothing to draw
-    return NS_OK;
-  }
-
-  // clip tile
-  tile = tile.Intersect(surfaceRect);
-
-  // Get it into surface space
-  tile -= surfaceRect.TopLeft();
-
-  uint8_t* sourceData = aSources[0]->mImage->Data();
-  uint8_t* targetData = aTarget->mImage->Data();
-  uint32_t stride = aTarget->mImage->Stride();
-
-  /*
-   * priority: left before right before centre
-   *             and
-   *           top before bottom before centre
-   *
-   * eg: If we have a target area which is 1.5 times the width of a tile,
-   *     then, based on alignment, we get:
-   *       'left and right'
-   *         or
-   *       'left and centre'
-   *
-   */
-
-  int32_t leftPartialTileWidth;
-  int32_t rightPartialTileWidth;
-  int32_t centreWidth;
-  ComputePartialTileExtents(&leftPartialTileWidth,
-                            &rightPartialTileWidth,
-                            &centreWidth,
-                            rect.x,
-                            rect.width,
-                            tile.x,
-                            tile.width);
-
-  int32_t topPartialTileHeight;
-  int32_t bottomPartialTileHeight;
-  int32_t centreHeight;
-  ComputePartialTileExtents(&topPartialTileHeight,
-                            &bottomPartialTileHeight,
-                            &centreHeight,
-                            rect.y,
-                            rect.height,
-                            tile.y,
-                            tile.height);
-
-  /* We have nine regions of the target area which have to be tiled differetly:
-   *
-   * Top Left,    Top Middle,    Top Right,
-   * Left Middle, Centre,        Right Middle,
-   * Bottom Left, Bottom Middle, Bottom Right
-   *
-   * + Centre is tiled by repeating the tiled image in full.
-   * + Top Left, Top Middle and Top Right:
-   *     Some of the rows from the top of the tile will be clipped here.
-   * + Bottom Left, Bottom Middle and Bottom Right:
-   *     Some of the rows from the bottom of the tile will be clipped here.
-   * + Top Left, Left Middle and Bottom left:
-   *     Some of the columns from the Left of the tile will be clipped here.
-   * + Top Right, Right Middle and Bottom Right:
-   *     Some of the columns from the right of the tile will be clipped here.
-   *
-   * If the sizes and positions of the target and tile are such that the tile
-   * aligns exactly on any (or all) of the edges, then some (or all) of the
-   * regions above (except Centre) will be zero sized.
-   */
-
-  nsIntRect targetRects[] = {
-    // Top Left
-    nsIntRect(rect.x, rect.y, leftPartialTileWidth, topPartialTileHeight),
-    // Top Middle
-    nsIntRect(rect.x + leftPartialTileWidth,
-              rect.y,
-              centreWidth,
-              topPartialTileHeight),
-    // Top Right
-    nsIntRect(rect.XMost() - rightPartialTileWidth,
-              rect.y,
-              rightPartialTileWidth,
-              topPartialTileHeight),
-    // Left Middle
-    nsIntRect(rect.x,
-              rect.y + topPartialTileHeight,
-              leftPartialTileWidth,
-              centreHeight),
-    // Centre
-    nsIntRect(rect.x + leftPartialTileWidth,
-              rect.y + topPartialTileHeight,
-              centreWidth,
-              centreHeight),
-    // Right Middle
-    nsIntRect(rect.XMost() - rightPartialTileWidth,
-              rect.y + topPartialTileHeight,
-              rightPartialTileWidth,
-              centreHeight),
-    // Bottom Left
-    nsIntRect(rect.x,
-              rect.YMost() - bottomPartialTileHeight,
-              leftPartialTileWidth,
-              bottomPartialTileHeight),
-    // Bottom Middle
-    nsIntRect(rect.x + leftPartialTileWidth,
-              rect.YMost() - bottomPartialTileHeight,
-              centreWidth,
-              bottomPartialTileHeight),
-    // Bottom Right
-    nsIntRect(rect.XMost() - rightPartialTileWidth,
-              rect.YMost() - bottomPartialTileHeight,
-              rightPartialTileWidth,
-              bottomPartialTileHeight)
-  };
-
-  nsIntRect tileRects[] = {
-    // Top Left
-    nsIntRect(tile.XMost() - leftPartialTileWidth,
-              tile.YMost() - topPartialTileHeight,
-              leftPartialTileWidth,
-              topPartialTileHeight),
-    // Top Middle
-    nsIntRect(tile.x,
-              tile.YMost() - topPartialTileHeight,
-              tile.width,
-              topPartialTileHeight),
-    // Top Right
-    nsIntRect(tile.x,
-              tile.YMost() - topPartialTileHeight,
-              rightPartialTileWidth,
-              topPartialTileHeight),
-    // Left Middle
-    nsIntRect(tile.XMost() - leftPartialTileWidth,
-              tile.y,
-              leftPartialTileWidth,
-              tile.height),
-    // Centre
-    nsIntRect(tile.x,
-              tile.y,
-              tile.width,
-              tile.height),
-    // Right Middle
-    nsIntRect(tile.x,
-              tile.y,
-              rightPartialTileWidth,
-              tile.height),
-    // Bottom Left
-    nsIntRect(tile.XMost() - leftPartialTileWidth,
-              tile.y,
-              leftPartialTileWidth,
-              bottomPartialTileHeight),
-    // Bottom Middle
-    nsIntRect(tile.x,
-              tile.y,
-              tile.width,
-              bottomPartialTileHeight),
-    // Bottom Right
-    nsIntRect(tile.x,
-              tile.y,
-              rightPartialTileWidth,
-              bottomPartialTileHeight)
-  };
-
-  for (uint32_t i = 0; i < ArrayLength(targetRects); ++i) {
-    TilePixels(targetData,
-               sourceData,
-               targetRects[i],
-               tileRects[i],
-               stride);
-  }
-
-  return NS_OK;
+  return FilterPrimitiveDescription(FilterPrimitiveDescription::eTile);
 }
 
 bool
 SVGFETileElement::AttributeAffectsRendering(int32_t aNameSpaceID,
                                             nsIAtom* aAttribute) const
 {
   return SVGFETileElementBase::AttributeAffectsRendering(aNameSpaceID,
                                                          aAttribute) ||
--- a/content/svg/content/src/SVGFETileElement.h
+++ b/content/svg/content/src/SVGFETileElement.h
@@ -26,30 +26,24 @@ protected:
   {
   }
   virtual JSObject* WrapNode(JSContext *cx,
                              JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
 
 public:
   virtual bool SubregionIsUnionOfRegions() { return false; }
 
-  virtual nsresult Filter(nsSVGFilterInstance* aInstance,
-                          const nsTArray<const Image*>& aSources,
-                          const Image* aTarget,
-                          const nsIntRect& aDataRect) MOZ_OVERRIDE;
+  virtual FilterPrimitiveDescription
+    GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                            const IntRect& aFilterSubregion,
+                            nsTArray<nsRefPtr<gfxASurface> >& aInputImages) MOZ_OVERRIDE;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const MOZ_OVERRIDE;
   virtual nsSVGString& GetResultImageName() MOZ_OVERRIDE { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) MOZ_OVERRIDE;
-  virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-          const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
-  virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
-          nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
-  virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
-          const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
 
 protected:
   virtual StringAttributesInfo GetStringInfo() MOZ_OVERRIDE;
--- a/content/svg/content/src/SVGFETurbulenceElement.cpp
+++ b/content/svg/content/src/SVGFETurbulenceElement.cpp
@@ -5,23 +5,21 @@
 
 #include "mozilla/dom/SVGFETurbulenceElement.h"
 #include "mozilla/dom/SVGFETurbulenceElementBinding.h"
 #include "nsSVGFilterInstance.h"
 #include "nsSVGUtils.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FETurbulence)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
-// Turbulence Types
-static const unsigned short SVG_TURBULENCE_TYPE_FRACTALNOISE = 1;
-static const unsigned short SVG_TURBULENCE_TYPE_TURBULENCE = 2;
-
 // Stitch Options
 static const unsigned short SVG_STITCHTYPE_STITCH = 1;
 static const unsigned short SVG_STITCHTYPE_NOSTITCH = 2;
 
 static const int32_t MAX_OCTAVES = 10;
 
 JSObject*
 SVGFETurbulenceElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
@@ -115,278 +113,66 @@ SVGFETurbulenceElement::StitchTiles()
 }
 
 already_AddRefed<SVGAnimatedEnumeration>
 SVGFETurbulenceElement::Type()
 {
   return mEnumAttributes[TYPE].ToDOMAnimatedEnum(this);
 }
 
-nsresult
-SVGFETurbulenceElement::Filter(nsSVGFilterInstance* instance,
-                               const nsTArray<const Image*>& aSources,
-                               const Image* aTarget,
-                               const nsIntRect& rect)
+FilterPrimitiveDescription
+SVGFETurbulenceElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                                                const IntRect& aFilterSubregion,
+                                                nsTArray<nsRefPtr<gfxASurface> >& aInputImages)
 {
-  uint8_t* targetData = aTarget->mImage->Data();
-  uint32_t stride = aTarget->mImage->Stride();
-
-  nsIntRect filterSubregion(int32_t(aTarget->mFilterPrimitiveSubregion.X()),
-                            int32_t(aTarget->mFilterPrimitiveSubregion.Y()),
-                            int32_t(aTarget->mFilterPrimitiveSubregion.Width()),
-                            int32_t(aTarget->mFilterPrimitiveSubregion.Height()));
-
   float fX = mNumberPairAttributes[BASE_FREQ].GetAnimValue(nsSVGNumberPair::eFirst);
   float fY = mNumberPairAttributes[BASE_FREQ].GetAnimValue(nsSVGNumberPair::eSecond);
   float seed = mNumberAttributes[OCTAVES].GetAnimValue();
-  int32_t octaves = std::min(mIntegerAttributes[OCTAVES].GetAnimValue(), MAX_OCTAVES);
-  uint16_t type = mEnumAttributes[TYPE].GetAnimValue();
+  uint32_t octaves = clamped(mIntegerAttributes[OCTAVES].GetAnimValue(), 0, MAX_OCTAVES);
+  uint32_t type = mEnumAttributes[TYPE].GetAnimValue();
   uint16_t stitch = mEnumAttributes[STITCHTILES].GetAnimValue();
 
-  InitSeed((int32_t)seed);
-
-  // XXXroc this makes absolutely no sense to me.
-  float filterX = instance->GetFilterRegion().X();
-  float filterY = instance->GetFilterRegion().Y();
-  float filterWidth = instance->GetFilterRegion().Width();
-  float filterHeight = instance->GetFilterRegion().Height();
-
-  bool doStitch = false;
-  if (stitch == SVG_STITCHTYPE_STITCH) {
-    doStitch = true;
-
-    float lowFreq, hiFreq;
-
-    lowFreq = floor(filterWidth * fX) / filterWidth;
-    hiFreq = ceil(filterWidth * fX) / filterWidth;
-    if (fX / lowFreq < hiFreq / fX)
-      fX = lowFreq;
-    else
-      fX = hiFreq;
-
-    lowFreq = floor(filterHeight * fY) / filterHeight;
-    hiFreq = ceil(filterHeight * fY) / filterHeight;
-    if (fY / lowFreq < hiFreq / fY)
-      fY = lowFreq;
-    else
-      fY = hiFreq;
-  }
-  for (int32_t y = rect.y; y < rect.YMost(); y++) {
-    for (int32_t x = rect.x; x < rect.XMost(); x++) {
-      int32_t targIndex = y * stride + x * 4;
-      double point[2];
-      point[0] = filterX + (filterWidth * (x + instance->GetSurfaceRect().x)) / (filterSubregion.width - 1);
-      point[1] = filterY + (filterHeight * (y + instance->GetSurfaceRect().y)) / (filterSubregion.height - 1);
-
-      float col[4];
-      if (type == SVG_TURBULENCE_TYPE_TURBULENCE) {
-        for (int i = 0; i < 4; i++)
-          col[i] = Turbulence(i, point, fX, fY, octaves, false,
-                              doStitch, filterX, filterY, filterWidth, filterHeight) * 255;
-      } else {
-        for (int i = 0; i < 4; i++)
-          col[i] = (Turbulence(i, point, fX, fY, octaves, true,
-                               doStitch, filterX, filterY, filterWidth, filterHeight) * 255 + 255) / 2;
-      }
-      for (int i = 0; i < 4; i++) {
-        col[i] = std::min(col[i], 255.f);
-        col[i] = std::max(col[i], 0.f);
-      }
-
-      uint8_t r, g, b, a;
-      a = uint8_t(col[3]);
-      FAST_DIVIDE_BY_255(r, unsigned(col[0]) * a);
-      FAST_DIVIDE_BY_255(g, unsigned(col[1]) * a);
-      FAST_DIVIDE_BY_255(b, unsigned(col[2]) * a);
-
-      targetData[targIndex + GFX_ARGB32_OFFSET_B] = b;
-      targetData[targIndex + GFX_ARGB32_OFFSET_G] = g;
-      targetData[targIndex + GFX_ARGB32_OFFSET_R] = r;
-      targetData[targIndex + GFX_ARGB32_OFFSET_A] = a;
-    }
+  if (fX == 0 || fY == 0) {
+    return FilterPrimitiveDescription(FilterPrimitiveDescription::eNone);
   }
 
-  return NS_OK;
+  // We interpret the base frequency as relative to user space units. In other
+  // words, we consider one turbulence base period to be 1 / fX user space
+  // units wide and 1 / fY user space units high. We do not scale the frequency
+  // depending on the filter primitive region.
+  gfxRect firstPeriodInUserSpace(0, 0, 1 / fX, 1 / fY);
+  gfxMatrix m = aInstance->GetUserSpaceToFilterSpaceTransform();
+  gfxRect firstPeriodInFilterSpace = m.TransformBounds(firstPeriodInUserSpace);
+  Size frequencyInFilterSpace(1 / firstPeriodInFilterSpace.width,
+                              1 / firstPeriodInFilterSpace.height);
+  gfxPoint offset = firstPeriodInFilterSpace.TopLeft();
+
+  FilterPrimitiveDescription descr(FilterPrimitiveDescription::eTurbulence);
+  descr.Attributes().Set(eTurbulenceOffset, IntPoint(offset.x, offset.y));
+  descr.Attributes().Set(eTurbulenceBaseFrequency, frequencyInFilterSpace);
+  descr.Attributes().Set(eTurbulenceSeed, seed);
+  descr.Attributes().Set(eTurbulenceNumOctaves, octaves);
+  descr.Attributes().Set(eTurbulenceStitchable, stitch == SVG_STITCHTYPE_STITCH);
+  descr.Attributes().Set(eTurbulenceType, type);
+  return descr;
 }
 
 bool
 SVGFETurbulenceElement::AttributeAffectsRendering(int32_t aNameSpaceID,
                                                     nsIAtom* aAttribute) const
 {
   return SVGFETurbulenceElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
          (aNameSpaceID == kNameSpaceID_None &&
           (aAttribute == nsGkAtoms::seed ||
            aAttribute == nsGkAtoms::baseFrequency ||
            aAttribute == nsGkAtoms::numOctaves ||
            aAttribute == nsGkAtoms::type ||
            aAttribute == nsGkAtoms::stitchTiles));
 }
 
-void
-SVGFETurbulenceElement::InitSeed(int32_t aSeed)
-{
-  double s;
-  int i, j, k;
-  aSeed = SetupSeed(aSeed);
-  for (k = 0; k < 4; k++) {
-    for (i = 0; i < sBSize; i++) {
-      mLatticeSelector[i] = i;
-      for (j = 0; j < 2; j++) {
-        mGradient[k][i][j] =
-          (double) (((aSeed =
-                      Random(aSeed)) % (sBSize + sBSize)) - sBSize) / sBSize;
-      }
-      s = double (sqrt
-                  (mGradient[k][i][0] * mGradient[k][i][0] +
-                   mGradient[k][i][1] * mGradient[k][i][1]));
-      mGradient[k][i][0] /= s;
-      mGradient[k][i][1] /= s;
-    }
-  }
-  while (--i) {
-    k = mLatticeSelector[i];
-    mLatticeSelector[i] = mLatticeSelector[j =
-                                           (aSeed =
-                                            Random(aSeed)) % sBSize];
-    mLatticeSelector[j] = k;
-  }
-  for (i = 0; i < sBSize + 2; i++) {
-    mLatticeSelector[sBSize + i] = mLatticeSelector[i];
-    for (k = 0; k < 4; k++)
-      for (j = 0; j < 2; j++)
-        mGradient[k][sBSize + i][j] = mGradient[k][i][j];
-  }
-}
-
-#define S_CURVE(t) ( t * t * (3. - 2. * t) )
-#define LERP(t, a, b) ( a + t * (b - a) )
-double
-SVGFETurbulenceElement::Noise2(int aColorChannel, double aVec[2],
-                               StitchInfo *aStitchInfo)
-{
-  int bx0, bx1, by0, by1, b00, b10, b01, b11;
-  double rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v;
-  long i, j;
-  t = aVec[0] + sPerlinN;
-  bx0 = (int) t;
-  bx1 = bx0 + 1;
-  rx0 = t - (int) t;
-  rx1 = rx0 - 1.0f;
-  t = aVec[1] + sPerlinN;
-  by0 = (int) t;
-  by1 = by0 + 1;
-  ry0 = t - (int) t;
-  ry1 = ry0 - 1.0f;
-  // If stitching, adjust lattice points accordingly.
-  if (aStitchInfo != nullptr) {
-    if (bx0 >= aStitchInfo->mWrapX)
-      bx0 -= aStitchInfo->mWidth;
-    if (bx1 >= aStitchInfo->mWrapX)
-      bx1 -= aStitchInfo->mWidth;
-    if (by0 >= aStitchInfo->mWrapY)
-      by0 -= aStitchInfo->mHeight;
-    if (by1 >= aStitchInfo->mWrapY)
-      by1 -= aStitchInfo->mHeight;
-  }
-  bx0 &= sBM;
-  bx1 &= sBM;
-  by0 &= sBM;
-  by1 &= sBM;
-  i = mLatticeSelector[bx0];
-  j = mLatticeSelector[bx1];
-  b00 = mLatticeSelector[i + by0];
-  b10 = mLatticeSelector[j + by0];
-  b01 = mLatticeSelector[i + by1];
-  b11 = mLatticeSelector[j + by1];
-  sx = double (S_CURVE(rx0));
-  sy = double (S_CURVE(ry0));
-  q = mGradient[aColorChannel][b00];
-  u = rx0 * q[0] + ry0 * q[1];
-  q = mGradient[aColorChannel][b10];
-  v = rx1 * q[0] + ry0 * q[1];
-  a = LERP(sx, u, v);
-  q = mGradient[aColorChannel][b01];
-  u = rx0 * q[0] + ry1 * q[1];
-  q = mGradient[aColorChannel][b11];
-  v = rx1 * q[0] + ry1 * q[1];
-  b = LERP(sx, u, v);
-  return LERP(sy, a, b);
-}
-#undef S_CURVE
-#undef LERP
-
-double
-SVGFETurbulenceElement::Turbulence(int aColorChannel, double* aPoint,
-                                   double aBaseFreqX, double aBaseFreqY,
-                                   int aNumOctaves, bool aFractalSum,
-                                   bool aDoStitching,
-                                   double aTileX, double aTileY,
-                                   double aTileWidth, double aTileHeight)
-{
-  StitchInfo stitch;
-  StitchInfo *stitchInfo = nullptr; // Not stitching when nullptr.
-  // Adjust the base frequencies if necessary for stitching.
-  if (aDoStitching) {
-    // When stitching tiled turbulence, the frequencies must be adjusted
-    // so that the tile borders will be continuous.
-    if (aBaseFreqX != 0.0) {
-      double loFreq = double (floor(aTileWidth * aBaseFreqX)) / aTileWidth;
-      double hiFreq = double (ceil(aTileWidth * aBaseFreqX)) / aTileWidth;
-      if (aBaseFreqX / loFreq < hiFreq / aBaseFreqX)
-        aBaseFreqX = loFreq;
-      else
-        aBaseFreqX = hiFreq;
-    }
-    if (aBaseFreqY != 0.0) {
-      double loFreq = double (floor(aTileHeight * aBaseFreqY)) / aTileHeight;
-      double hiFreq = double (ceil(aTileHeight * aBaseFreqY)) / aTileHeight;
-      if (aBaseFreqY / loFreq < hiFreq / aBaseFreqY)
-        aBaseFreqY = loFreq;
-      else
-        aBaseFreqY = hiFreq;
-    }
-    // Set up initial stitch values.
-    stitchInfo = &stitch;
-    stitch.mWidth = int (aTileWidth * aBaseFreqX + 0.5f);
-    stitch.mWrapX = int (aTileX * aBaseFreqX + sPerlinN + stitch.mWidth);
-    stitch.mHeight = int (aTileHeight * aBaseFreqY + 0.5f);
-    stitch.mWrapY = int (aTileY * aBaseFreqY + sPerlinN + stitch.mHeight);
-  }
-  double sum = 0.0f;
-  double vec[2];
-  vec[0] = aPoint[0] * aBaseFreqX;
-  vec[1] = aPoint[1] * aBaseFreqY;
-  double ratio = 1;
-  for (int octave = 0; octave < aNumOctaves; octave++) {
-    if (aFractalSum)
-      sum += double (Noise2(aColorChannel, vec, stitchInfo) / ratio);
-    else
-      sum += double (fabs(Noise2(aColorChannel, vec, stitchInfo)) / ratio);
-    vec[0] *= 2;
-    vec[1] *= 2;
-    ratio *= 2;
-    if (stitchInfo != nullptr) {
-      // Update stitch values. Subtracting sPerlinN before the multiplication
-      // and adding it afterward simplifies to subtracting it once.
-      stitch.mWidth *= 2;
-      stitch.mWrapX = 2 * stitch.mWrapX - sPerlinN;
-      stitch.mHeight *= 2;
-      stitch.mWrapY = 2 * stitch.mWrapY - sPerlinN;
-    }
-  }
-  return sum;
-}
-
-nsIntRect
-SVGFETurbulenceElement::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-        const nsSVGFilterInstance& aInstance)
-{
-  return GetMaxRect();
-}
-
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 nsSVGElement::NumberAttributesInfo
 SVGFETurbulenceElement::GetNumberInfo()
 {
   return NumberAttributesInfo(mNumberAttributes, sNumberInfo,
                               ArrayLength(sNumberInfo));
--- a/content/svg/content/src/SVGFETurbulenceElement.h
+++ b/content/svg/content/src/SVGFETurbulenceElement.h
@@ -30,25 +30,23 @@ protected:
   {
   }
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
 public:
   virtual bool SubregionIsUnionOfRegions() MOZ_OVERRIDE { return false; }
 
-  virtual nsresult Filter(nsSVGFilterInstance* aInstance,
-                          const nsTArray<const Image*>& aSources,
-                          const Image* aTarget,
-                          const nsIntRect& aDataRect) MOZ_OVERRIDE;
+  virtual FilterPrimitiveDescription
+    GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                            const IntRect& aFilterSubregion,
+                            nsTArray<nsRefPtr<gfxASurface> >& aInputImages) MOZ_OVERRIDE;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const MOZ_OVERRIDE;
   virtual nsSVGString& GetResultImageName() MOZ_OVERRIDE { return mStringAttributes[RESULT]; }
-  virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-          const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedNumber> BaseFrequencyX();
   already_AddRefed<SVGAnimatedNumber> BaseFrequencyY();
   already_AddRefed<SVGAnimatedInteger> NumOctaves();
   already_AddRefed<SVGAnimatedNumber> Seed();
@@ -78,75 +76,14 @@ protected:
   nsSVGEnum mEnumAttributes[2];
   static nsSVGEnumMapping sTypeMap[];
   static nsSVGEnumMapping sStitchTilesMap[];
   static EnumInfo sEnumInfo[2];
 
   enum { RESULT };
   nsSVGString mStringAttributes[1];
   static StringInfo sStringInfo[1];
-
-private:
-
-  /* The turbulence calculation code is an adapted version of what
-     appears in the SVG 1.1 specification:
-         http://www.w3.org/TR/SVG11/filters.html#feTurbulence
-  */
-
-  /* Produces results in the range [1, 2**31 - 2].
-     Algorithm is: r = (a * r) mod m
-     where a = 16807 and m = 2**31 - 1 = 2147483647
-     See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988
-     To test: the algorithm should produce the result 1043618065
-     as the 10,000th generated number if the original seed is 1.
-  */
-#define RAND_M 2147483647	/* 2**31 - 1 */
-#define RAND_A 16807		/* 7**5; primitive root of m */
-#define RAND_Q 127773		/* m / a */
-#define RAND_R 2836		/* m % a */
-
-  int32_t SetupSeed(int32_t aSeed) {
-    if (aSeed <= 0)
-      aSeed = -(aSeed % (RAND_M - 1)) + 1;
-    if (aSeed > RAND_M - 1)
-      aSeed = RAND_M - 1;
-    return aSeed;
-  }
-
-  uint32_t Random(uint32_t aSeed) {
-    int32_t result = RAND_A * (aSeed % RAND_Q) - RAND_R * (aSeed / RAND_Q);
-    if (result <= 0)
-      result += RAND_M;
-    return result;
-  }
-#undef RAND_M
-#undef RAND_A
-#undef RAND_Q
-#undef RAND_R
-
-  const static int sBSize = 0x100;
-  const static int sBM = 0xff;
-  const static int sPerlinN = 0x1000;
-  const static int sNP = 12;			/* 2^PerlinN */
-  const static int sNM = 0xfff;
-
-  int32_t mLatticeSelector[sBSize + sBSize + 2];
-  double mGradient[4][sBSize + sBSize + 2][2];
-  struct StitchInfo {
-    int mWidth;			// How much to subtract to wrap for stitching.
-    int mHeight;
-    int mWrapX;			// Minimum value to wrap.
-    int mWrapY;
-  };
-
-  void InitSeed(int32_t aSeed);
-  double Noise2(int aColorChannel, double aVec[2], StitchInfo *aStitchInfo);
-  double
-  Turbulence(int aColorChannel, double *aPoint, double aBaseFreqX,
-             double aBaseFreqY, int aNumOctaves, bool aFractalSum,
-             bool aDoStitching, double aTileX, double aTileY,
-             double aTileWidth, double aTileHeight);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_SVGFETurbulenceElement_h
--- a/content/svg/content/src/nsSVGFilters.cpp
+++ b/content/svg/content/src/nsSVGFilters.cpp
@@ -44,43 +44,17 @@
 
 #if defined(XP_WIN)
 // Prevent Windows redefining LoadImage
 #undef LoadImage
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
-
-static const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY = 1;
-static const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_TABLE    = 2;
-static const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE = 3;
-static const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_LINEAR   = 4;
-static const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_GAMMA    = 5;
-
-void
-CopyDataRect(uint8_t *aDest, const uint8_t *aSrc, uint32_t aStride,
-             const nsIntRect& aDataRect)
-{
-  for (int32_t y = aDataRect.y; y < aDataRect.YMost(); y++) {
-    memcpy(aDest + y * aStride + 4 * aDataRect.x,
-           aSrc + y * aStride + 4 * aDataRect.x,
-           4 * aDataRect.width);
-  }
-}
-
-static void
-CopyAndScaleDeviceOffset(const gfxImageSurface *aImage, gfxImageSurface *aResult,
-                         gfxFloat kernelX, gfxFloat kernelY)
-{
-  gfxPoint deviceOffset = aImage->GetDeviceOffset();
-  deviceOffset.x /= kernelX;
-  deviceOffset.y /= kernelY;
-  aResult->SetDeviceOffset(deviceOffset);
-}
+using namespace mozilla::gfx;
 
 //--------------------Filter Element Base Class-----------------------
 
 nsSVGElement::LengthInfo nsSVGFE::sLengthInfo[4] =
 {
   { &nsGkAtoms::x, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::X },
   { &nsGkAtoms::y, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::Y },
   { &nsGkAtoms::width, 100, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::X },
@@ -101,140 +75,16 @@ NS_INTERFACE_MAP_BEGIN(nsSVGFE)
    if ( aIID.Equals(NS_GET_IID(nsSVGFE)) )
      foundInterface = static_cast<nsISupports*>(static_cast<void*>(this));
    else
 NS_INTERFACE_MAP_END_INHERITING(nsSVGFEBase)
 
 //----------------------------------------------------------------------
 // Implementation
 
-nsSVGFE::ScaleInfo
-nsSVGFE::SetupScalingFilter(nsSVGFilterInstance *aInstance,
-                            const Image *aSource, const Image *aTarget,
-                            const nsIntRect& aDataRect,
-                            nsSVGNumberPair *aKernelUnitLength)
-{
-  ScaleInfo result;
-  result.mRescaling = aKernelUnitLength->IsExplicitlySet();
-  if (!result.mRescaling) {
-    result.mSource = aSource->mImage;
-    result.mTarget = aTarget->mImage;
-    result.mDataRect = aDataRect;
-    return result;
-  }
-
-  gfxFloat kernelX = aInstance->GetPrimitiveNumber(SVGContentUtils::X,
-                                                   aKernelUnitLength,
-                                                   nsSVGNumberPair::eFirst);
-  gfxFloat kernelY = aInstance->GetPrimitiveNumber(SVGContentUtils::Y,
-                                                   aKernelUnitLength,
-                                                   nsSVGNumberPair::eSecond);
-  if (kernelX <= 0 || kernelY <= 0)
-    return result;
-
-  bool overflow = false;
-  gfxIntSize scaledSize =
-    nsSVGUtils::ConvertToSurfaceSize(gfxSize(aTarget->mImage->Width() / kernelX,
-                                             aTarget->mImage->Height() / kernelY),
-                                     &overflow);
-  // If the requested size based on the kernel unit is too big, we
-  // need to bail because the effect is pixel size dependent.  Also
-  // need to check if we ended up with a negative size (arithmetic
-  // overflow) or zero size (large kernel unit)
-  if (overflow || scaledSize.width <= 0 || scaledSize.height <= 0)
-    return result;
-
-  gfxRect r(aDataRect.x, aDataRect.y, aDataRect.width, aDataRect.height);
-  r.Scale(1 / kernelX, 1 / kernelY);
-  r.RoundOut();
-  if (!gfxUtils::GfxRectToIntRect(r, &result.mDataRect))
-    return result;
-
-  // Rounding in the code above can mean that result.mDataRect is not contained
-  // within the bounds of the surfaces that we're about to create. We must
-  // clamp to these bounds to prevent out-of-bounds reads and writes:
-  result.mDataRect.IntersectRect(result.mDataRect,
-                                 nsIntRect(nsIntPoint(), scaledSize));
-
-  result.mSource = new gfxImageSurface(scaledSize,
-                                       gfxImageFormatARGB32);
-  result.mTarget = new gfxImageSurface(scaledSize,
-                                       gfxImageFormatARGB32);
-  if (!result.mSource || result.mSource->CairoStatus() ||
-      !result.mTarget || result.mTarget->CairoStatus()) {
-    result.mSource = nullptr;
-    result.mTarget = nullptr;
-    return result;
-  }
-
-  CopyAndScaleDeviceOffset(aSource->mImage, result.mSource, kernelX, kernelY);
-  CopyAndScaleDeviceOffset(aTarget->mImage, result.mTarget, kernelX, kernelY);
-
-  result.mRealTarget = aTarget->mImage;
-
-  gfxContext ctx(result.mSource);
-  ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
-  ctx.Scale(double(scaledSize.width) / aTarget->mImage->Width(),
-            double(scaledSize.height) / aTarget->mImage->Height());
-  ctx.SetSource(aSource->mImage);
-  ctx.Paint();
-
-  // mTarget was already cleared when it was created
-
-  return result;
-}
-
-void
-nsSVGFE::FinishScalingFilter(ScaleInfo *aScaleInfo)
-{
-  if (!aScaleInfo->mRescaling)
-    return;
-
-  gfxIntSize scaledSize = aScaleInfo->mTarget->GetSize();
-
-  gfxContext ctx(aScaleInfo->mRealTarget);
-  ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
-  ctx.Scale(double(aScaleInfo->mRealTarget->Width()) / scaledSize.width,
-            double(aScaleInfo->mRealTarget->Height()) / scaledSize.height);
-  ctx.SetSource(aScaleInfo->mTarget);
-  ctx.Paint();
-}
-
-nsIntRect
-nsSVGFE::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-                           const nsSVGFilterInstance& aInstance)
-{
-  nsIntRect r;
-  for (uint32_t i = 0; i < aSourceBBoxes.Length(); ++i) {
-    r.UnionRect(r, aSourceBBoxes[i]);
-  }
-  return r;
-}
-
-void
-nsSVGFE::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
-                                   nsTArray<nsIntRect>& aSourceBBoxes,
-                                   const nsSVGFilterInstance& aInstance)
-{
-  for (uint32_t i = 0; i < aSourceBBoxes.Length(); ++i) {
-    aSourceBBoxes[i] = aTargetBBox;
-  }
-}
-
-nsIntRect
-nsSVGFE::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
-                           const nsSVGFilterInstance& aInstance)
-{
-  nsIntRect r;
-  for (uint32_t i = 0; i < aSourceChangeBoxes.Length(); ++i) {
-    r.UnionRect(r, aSourceChangeBoxes[i]);
-  }
-  return r;
-}
-
 void
 nsSVGFE::GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources)
 {
 }
 
 bool
 nsSVGFE::AttributeAffectsRendering(int32_t aNameSpaceID,
                                    nsIAtom* aAttribute) const
@@ -289,25 +139,54 @@ nsSVGFE::IsAttributeMapped(const nsIAtom
   
   return FindAttributeDependence(name, map) ||
     nsSVGFEBase::IsAttributeMapped(name);
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
+
+bool
+nsSVGFE::StyleIsSetToSRGB()
+{
+  nsIFrame* frame = GetPrimaryFrame();
+  if (!frame) return false;
+
+  nsStyleContext* style = frame->StyleContext();
+  return style->StyleSVG()->mColorInterpolationFilters ==
+           NS_STYLE_COLOR_INTERPOLATION_SRGB;
+}
+
 /* virtual */ bool
 nsSVGFE::HasValidDimensions() const
 {
   return (!mLengthAttributes[ATTR_WIDTH].IsExplicitlySet() ||
            mLengthAttributes[ATTR_WIDTH].GetAnimValInSpecifiedUnits() > 0) &&
          (!mLengthAttributes[ATTR_HEIGHT].IsExplicitlySet() ||
            mLengthAttributes[ATTR_HEIGHT].GetAnimValInSpecifiedUnits() > 0);
 }
 
+Size
+nsSVGFE::GetKernelUnitLength(nsSVGFilterInstance* aInstance,
+                             nsSVGNumberPair *aKernelUnitLength)
+{
+  if (!aKernelUnitLength->IsExplicitlySet()) {
+    return Size(1, 1);
+  }
+
+  float kernelX = aInstance->GetPrimitiveNumber(SVGContentUtils::X,
+                                                aKernelUnitLength,
+                                                nsSVGNumberPair::eFirst);
+  float kernelY = aInstance->GetPrimitiveNumber(SVGContentUtils::Y,
+                                                aKernelUnitLength,
+                                                nsSVGNumberPair::eSecond);
+  return Size(kernelX, kernelY);
+}
+
 nsSVGElement::LengthAttributesInfo
 nsSVGFE::GetLengthInfo()
 {
   return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
                               ArrayLength(sLengthInfo));
 }
 
 namespace mozilla {
@@ -423,94 +302,41 @@ SVGComponentTransferFunctionElement::Exp
 }
 
 already_AddRefed<SVGAnimatedNumber>
 SVGComponentTransferFunctionElement::Offset()
 {
   return mNumberAttributes[OFFSET].ToDOMAnimatedNumber(this);
 }
 
-bool
-SVGComponentTransferFunctionElement::GenerateLookupTable(uint8_t *aTable)
+AttributeMap
+SVGComponentTransferFunctionElement::ComputeAttributes()
 {
-  uint16_t type = mEnumAttributes[TYPE].GetAnimValue();
+  uint32_t type = mEnumAttributes[TYPE].GetAnimValue();
 
   float slope, intercept, amplitude, exponent, offset;
   GetAnimatedNumberValues(&slope, &intercept, &amplitude, 
                           &exponent, &offset, nullptr);
 
   const SVGNumberList &tableValues =
     mNumberListAttributes[TABLEVALUES].GetAnimValue();
-  uint32_t tvLength = tableValues.Length();
 
-  uint32_t i;
-
-  switch (type) {
-  case SVG_FECOMPONENTTRANSFER_TYPE_TABLE:
-  {
-    if (tableValues.Length() < 2)
-      return false;
-
-    for (i = 0; i < 256; i++) {
-      uint32_t k = (i * (tvLength - 1)) / 255;
-      float v1 = tableValues[k];
-      float v2 = tableValues[std::min(k + 1, tvLength - 1)];
-      int32_t val =
-        int32_t(255 * (v1 + (i/255.0f - k/float(tvLength-1))*(tvLength - 1)*(v2 - v1)));
-      val = std::min(255, val);
-      val = std::max(0, val);
-      aTable[i] = val;
-    }
-    break;
+  AttributeMap map;
+  map.Set(eComponentTransferFunctionType, type);
+  map.Set(eComponentTransferFunctionSlope, slope);
+  map.Set(eComponentTransferFunctionIntercept, intercept);
+  map.Set(eComponentTransferFunctionAmplitude, amplitude);
+  map.Set(eComponentTransferFunctionExponent, exponent);
+  map.Set(eComponentTransferFunctionOffset, offset);
+  if (tableValues.Length()) {
+    map.Set(eComponentTransferFunctionTableValues, &tableValues[0], tableValues.Length());
+  } else {
+    map.Set(eComponentTransferFunctionTableValues, nullptr, 0);
   }
-
-  case SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE:
-  {
-    if (tableValues.Length() < 1)
-      return false;
-
-    for (i = 0; i < 256; i++) {
-      uint32_t k = (i * tvLength) / 255;
-      k = std::min(k, tvLength - 1);
-      float v = tableValues[k];
-      int32_t val = int32_t(255 * v);
-      val = std::min(255, val);
-      val = std::max(0, val);
-      aTable[i] = val;
-    }
-    break;
-  }
-
-  case SVG_FECOMPONENTTRANSFER_TYPE_LINEAR:
-  {
-    for (i = 0; i < 256; i++) {
-      int32_t val = int32_t(slope * i + 255 * intercept);
-      val = std::min(255, val);
-      val = std::max(0, val);
-      aTable[i] = val;
-    }
-    break;
-  }
-
-  case SVG_FECOMPONENTTRANSFER_TYPE_GAMMA:
-  {
-    for (i = 0; i < 256; i++) {
-      int32_t val = int32_t(255 * (amplitude * pow(i / 255.0f, exponent) + offset));
-      val = std::min(255, val);
-      val = std::max(0, val);
-      aTable[i] = val;
-    }
-    break;
-  }
-
-  case SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY:
-  default:
-    break;
-  }
-  return true;
+  return map;
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 nsSVGElement::NumberListAttributesInfo
 SVGComponentTransferFunctionElement::GetNumberListInfo()
 {
@@ -644,280 +470,60 @@ nsSVGFELightingElement::IsAttributeMappe
 }
 
 void
 nsSVGFELightingElement::GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources)
 {
   aSources.AppendElement(nsSVGStringInfo(&mStringAttributes[IN1], this));
 }
 
-void
-nsSVGFELightingElement::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
-          nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance)
-{
-  // XXX lighting can depend on more than the target area, because
-  // of the kernels it uses. We could compute something precise here
-  // but just leave it and assume we use the entire source bounding box.
-}
-
-nsIntRect
-nsSVGFELightingElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
-                                          const nsSVGFilterInstance& aInstance)
-{
-  // XXX be conservative for now
-  return GetMaxRect();
-}
-
-static int32_t
-Convolve3x3(const uint8_t *index, int32_t stride,
-            const int8_t kernel[3][3]
-#ifdef DEBUG
-            , const uint8_t *minData, const uint8_t *maxData
-#endif // DEBUG
-)
-{
-  int32_t sum = 0;
-  for (int32_t y = 0; y < 3; y++) {
-    for (int32_t x = 0; x < 3; x++) {
-      int8_t k = kernel[y][x];
-      if (k) {
-        const uint8_t *valPtr = index + (4 * (x - 1) + stride * (y - 1));
-        NS_ASSERTION(valPtr >= minData, "out of bounds read (before buffer)");
-        NS_ASSERTION(valPtr < maxData,  "out of bounds read (after buffer)");
-        sum += k * (*valPtr);
-      }
-    }
-  }
-  return sum;
-}
-
-static void
-GenerateNormal(float *N, const uint8_t *data, int32_t stride,
-               int32_t surfaceWidth, int32_t surfaceHeight,
-               int32_t x, int32_t y, float surfaceScale)
+AttributeMap
+nsSVGFELightingElement::ComputeLightAttributes(nsSVGFilterInstance* aInstance)
 {
-  // See this for source of constants:
-  //   http://www.w3.org/TR/SVG11/filters.html#feDiffuseLightingElement
-  static const int8_t Kx[3][3][3][3] =
-    { { { {  0,  0,  0}, { 0, -2,  2}, { 0, -1,  1} },
-        { {  0,  0,  0}, {-2,  0,  2}, {-1,  0,  1} },
-        { {  0,  0,  0}, {-2,  2,  0}, {-1,  1,  0} } },
-      { { {  0, -1,  1}, { 0, -2,  2}, { 0, -1,  1} },
-        { { -1,  0,  1}, {-2,  0,  2}, {-1,  0,  1} },
-        { { -1,  1,  0}, {-2,  2,  0}, {-1,  1,  0} } },
-      { { {  0, -1,  1}, { 0, -2,  2}, { 0,  0,  0} },
-        { { -1,  0,  1}, {-2,  0,  2}, { 0,  0,  0} },
-        { { -1,  1,  0}, {-2,  2,  0}, { 0,  0,  0} } } };
-  static const int8_t Ky[3][3][3][3] =
-    { { { {  0,  0,  0}, { 0, -2, -1}, { 0,  2,  1} },
-        { {  0,  0,  0}, {-1, -2, -1}, { 1,  2,  1} },
-        { {  0,  0,  0}, {-1, -2,  1}, { 1,  2,  0} } },
-      { { {  0, -2, -1}, { 0,  0,  0}, { 0,  2,  1} },
-        { { -1, -2, -1}, { 0,  0,  0}, { 1,  2,  1} },
-        { { -1, -2,  0}, { 0,  0,  0}, { 1,  2,  0} } },
-      { { {  0, -2, -1}, { 0,  2,  1}, { 0,  0,  0} },
-        { { -1, -2, -1}, { 1,  2,  1}, { 0,  0,  0} },
-        { { -1, -2,  0}, { 1,  2,  0}, { 0,  0,  0} } } };
-  static const float FACTORx[3][3] =
-    { { 2.0f / 3.0f, 1.0f / 3.0f, 2.0f / 3.0f },
-      { 1.0f / 2.0f, 1.0f / 4.0f, 1.0f / 2.0f },
-      { 2.0f / 3.0f, 1.0f / 3.0f, 2.0f / 3.0f } };
-  static const float FACTORy[3][3] =
-    { { 2.0f / 3.0f, 1.0f / 2.0f, 2.0f / 3.0f },
-      { 1.0f / 3.0f, 1.0f / 4.0f, 1.0f / 3.0f },
-      { 2.0f / 3.0f, 1.0f / 2.0f, 2.0f / 3.0f } };
-
-  // degenerate cases
-  if (surfaceWidth == 1 || surfaceHeight == 1) {
-    // just return a unit vector pointing towards the viewer
-    N[0] = 0;
-    N[1] = 0;
-    N[2] = 255;
-    return;
-  }
-
-  int8_t xflag, yflag;
-  if (x == 0) {
-    xflag = 0;
-  } else if (x == surfaceWidth - 1) {
-    xflag = 2;
-  } else {
-    xflag = 1;
-  }
-  if (y == 0) {
-    yflag = 0;
-  } else if (y == surfaceHeight - 1) {
-    yflag = 2;
-  } else {
-    yflag = 1;
-  }
-
-  const uint8_t *index = data + y * stride + 4 * x + GFX_ARGB32_OFFSET_A;
-
-#ifdef DEBUG
-  // For sanity-checking, to be sure we're not reading outside source buffer:
-  const uint8_t* minData = data;
-  const uint8_t* maxData = minData + (surfaceHeight * surfaceWidth * stride);
-
-  // We'll sanity-check each value we read inside of Convolve3x3, but we
-  // might as well ensure we're passing it a valid pointer to start with, too:
-  NS_ASSERTION(index >= minData, "index points before buffer start");
-  NS_ASSERTION(index < maxData, "index points after buffer end");
-#endif // DEBUG
-
-  N[0] = -surfaceScale * FACTORx[yflag][xflag] *
-    Convolve3x3(index, stride, Kx[yflag][xflag]
-#ifdef DEBUG
-                , minData, maxData
-#endif // DEBUG
-                );
-
-  N[1] = -surfaceScale * FACTORy[yflag][xflag] *
-    Convolve3x3(index, stride, Ky[yflag][xflag]
-#ifdef DEBUG
-                , minData, maxData
-#endif // DEBUG
-                );
-  N[2] = 255;
-  NORMALIZE(N);
-}
-
-nsresult
-nsSVGFELightingElement::Filter(nsSVGFilterInstance *instance,
-                               const nsTArray<const Image*>& aSources,
-                               const Image* aTarget,
-                               const nsIntRect& rect)
-{
-  ScaleInfo info = SetupScalingFilter(instance, aSources[0], aTarget, rect,
-                                      &mNumberPairAttributes[KERNEL_UNIT_LENGTH]);
-  if (!info.mTarget)
-    return NS_ERROR_FAILURE;
-
-  SVGFEDistantLightElement* distantLight = nullptr;
-  SVGFEPointLightElement* pointLight = nullptr;
-  SVGFESpotLightElement* spotLight = nullptr;
-
-  nsIFrame* frame = GetPrimaryFrame();
-  if (!frame) return NS_ERROR_FAILURE;
-  nsStyleContext* style = frame->StyleContext();
-
-  nscolor lightColor = style->StyleSVGReset()->mLightingColor;
-
   // find specified light
   for (nsCOMPtr<nsIContent> child = nsINode::GetFirstChild();
        child;
        child = child->GetNextSibling()) {
-    distantLight = child->IsSVG(nsGkAtoms::feDistantLight) ?
-                     static_cast<SVGFEDistantLightElement*>(child.get()) : nullptr;
-    pointLight = child->IsSVG(nsGkAtoms::fePointLight) ?
-                   static_cast<SVGFEPointLightElement*>(child.get()) : nullptr;
-    spotLight = child->IsSVG(nsGkAtoms::feSpotLight) ?
-                   static_cast<SVGFESpotLightElement*>(child.get()) : nullptr;
-    if (distantLight || pointLight || spotLight)
-      break;
-  }
-
-  if (!distantLight && !pointLight && !spotLight)
-    return NS_ERROR_FAILURE;
-
-  const float radPerDeg = static_cast<float>(M_PI/180.0);
-
-  float L[3];
-  if (distantLight) {
-    float azimuth, elevation;
-    distantLight->GetAnimatedNumberValues(&azimuth,
-                                          &elevation,
-                                          nullptr);
-    L[0] = cos(azimuth * radPerDeg) * cos(elevation * radPerDeg);
-    L[1] = sin(azimuth * radPerDeg) * cos(elevation * radPerDeg);
-    L[2] = sin(elevation * radPerDeg);
-  }
-  float lightPos[3], pointsAt[3], specularExponent;
-  float cosConeAngle = 0;
-  if (pointLight) {
-    pointLight->GetAnimatedNumberValues(lightPos,
-                                        lightPos + 1,
-                                        lightPos + 2,
-                                        nullptr);
-    instance->ConvertLocation(lightPos);
-  }
-  if (spotLight) {
-    float limitingConeAngle;
-    spotLight->GetAnimatedNumberValues(lightPos,
-                                       lightPos + 1,
-                                       lightPos + 2,
-                                       pointsAt,
-                                       pointsAt + 1,
-                                       pointsAt + 2,
-                                       &specularExponent,
-                                       &limitingConeAngle,
-                                       nullptr);
-    instance->ConvertLocation(lightPos);
-    instance->ConvertLocation(pointsAt);
-
-    if (spotLight->mNumberAttributes[SVGFESpotLightElement::LIMITING_CONE_ANGLE].
-                                       IsExplicitlySet()) {
-      cosConeAngle = std::max<double>(cos(limitingConeAngle * radPerDeg), 0.0);
+    if (child->IsSVG(nsGkAtoms::feDistantLight) ||
+        child->IsSVG(nsGkAtoms::fePointLight) ||
+        child->IsSVG(nsGkAtoms::feSpotLight)) {
+      return static_cast<SVGFELightElement*>(child.get())->ComputeLightAttributes(aInstance);
     }
   }
 
-  float surfaceScale = mNumberAttributes[SURFACE_SCALE].GetAnimValue();
-
-  const nsIntRect& dataRect = info.mDataRect;
-  int32_t stride = info.mSource->Stride();
-  uint8_t *sourceData = info.mSource->Data();
-  uint8_t *targetData = info.mTarget->Data();
-  int32_t surfaceWidth = info.mSource->Width();
-  int32_t surfaceHeight = info.mSource->Height();
-
-  for (int32_t y = dataRect.y; y < dataRect.YMost(); y++) {
-    for (int32_t x = dataRect.x; x < dataRect.XMost(); x++) {
-      int32_t index = y * stride + x * 4;
-
-      float N[3];
-      GenerateNormal(N, sourceData, stride, surfaceWidth, surfaceHeight,
-                     x, y, surfaceScale);
-
-      if (pointLight || spotLight) {
-        gfxPoint pt = instance->FilterSpaceToUserSpace(
-                gfxPoint(x + instance->GetSurfaceRect().x,
-                         y + instance->GetSurfaceRect().y));
-        float Z = surfaceScale * sourceData[index + GFX_ARGB32_OFFSET_A] / 255;
+  AttributeMap map;
+  map.Set(eLightType, (uint32_t)eLightTypeNone);
+  return map;
+}
 
-        L[0] = lightPos[0] - pt.x;
-        L[1] = lightPos[1] - pt.y;
-        L[2] = lightPos[2] - Z;
-        NORMALIZE(L);
-      }
-
-      nscolor color;
-
-      if (spotLight) {
-        float S[3];
-        S[0] = pointsAt[0] - lightPos[0];
-        S[1] = pointsAt[1] - lightPos[1];
-        S[2] = pointsAt[2] - lightPos[2];
-        NORMALIZE(S);
-        float dot = -DOT(L, S);
-        float tmp = pow(dot, specularExponent);
-        if (dot < cosConeAngle) tmp = 0;
-        color = NS_RGB(uint8_t(NS_GET_R(lightColor) * tmp),
-                       uint8_t(NS_GET_G(lightColor) * tmp),
-                       uint8_t(NS_GET_B(lightColor) * tmp));
-      } else {
-        color = lightColor;
-      }
-
-      LightPixel(N, L, color, targetData + index);
-    }
+FilterPrimitiveDescription
+nsSVGFELightingElement::AddLightingAttributes(FilterPrimitiveDescription aDescription,
+                                              nsSVGFilterInstance* aInstance)
+{
+  nsIFrame* frame = GetPrimaryFrame();
+  if (!frame) {
+    return FilterPrimitiveDescription(FilterPrimitiveDescription::eNone);
   }
 
-  FinishScalingFilter(&info);
+  nsStyleContext* style = frame->StyleContext();
+  nscolor lightColor = style->StyleSVGReset()->mLightingColor;
+  Color color(NS_GET_R(lightColor) / 255.0f,
+                   NS_GET_G(lightColor) / 255.0f,
+                   NS_GET_B(lightColor) / 255.0f,
+                   1.0f);
+  float surfaceScale = mNumberAttributes[SURFACE_SCALE].GetAnimValue();
+  Size kernelUnitLength =
+    GetKernelUnitLength(aInstance, &mNumberPairAttributes[KERNEL_UNIT_LENGTH]);
 
-  return NS_OK;
+  FilterPrimitiveDescription& descr = aDescription;
+  descr.Attributes().Set(eLightingLight, ComputeLightAttributes(aInstance));
+  descr.Attributes().Set(eLightingSurfaceScale, surfaceScale);
+  descr.Attributes().Set(eLightingKernelUnitLength, kernelUnitLength);
+  descr.Attributes().Set(eLightingColor, color);
+  return descr;
 }
 
 bool
 nsSVGFELightingElement::AttributeAffectsRendering(int32_t aNameSpaceID,
                                                   nsIAtom* aAttribute) const
 {
   return nsSVGFELightingElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
          (aNameSpaceID == kNameSpaceID_None &&
--- a/content/svg/content/src/nsSVGFilters.h
+++ b/content/svg/content/src/nsSVGFilters.h
@@ -2,42 +2,29 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __NS_SVGFILTERSELEMENT_H__
 #define __NS_SVGFILTERSELEMENT_H__
 
 #include "mozilla/Attributes.h"
-#include "gfxImageSurface.h"
-#include "gfxRect.h"
-#include "nsIFrame.h"
 #include "nsImageLoadingContent.h"
 #include "nsSVGLength2.h"
 #include "nsSVGString.h"
 #include "nsSVGElement.h"
-#include "SVGAnimatedPreserveAspectRatio.h"
 #include "nsSVGNumber2.h"
 #include "nsSVGNumberPair.h"
+#include "FilterSupport.h"
+#include "gfxASurface.h"
 
 class nsSVGFilterInstance;
 class nsSVGFilterResource;
 class nsSVGNumberPair;
 
-inline float DOT(const float* a, const float* b) {
-  return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
-}
-
-inline void NORMALIZE(float* vec) {
-  float norm = sqrt(DOT(vec, vec));
-  vec[0] /= norm;
-  vec[1] /= norm;
-  vec[2] /= norm;
-}
-
 struct nsSVGStringInfo {
   nsSVGStringInfo(const nsSVGString* aString,
                   nsSVGElement *aElement) :
     mString(aString), mElement(aElement) {}
 
   const nsSVGString* mString;
   nsSVGElement* mElement;
 };
@@ -52,83 +39,38 @@ typedef nsSVGElement nsSVGFEBase;
  * Base class for filter primitive elements
  * Children of those elements e.g. feMergeNode
  * derive from SVGFEUnstyledElement instead
  */
 class nsSVGFE : public nsSVGFEBase
 {
   friend class nsSVGFilterInstance;
 
-public:
-  class ColorModel {
-  public:
-    enum ColorSpace { SRGB, LINEAR_RGB };
-    enum AlphaChannel { UNPREMULTIPLIED, PREMULTIPLIED };
+protected:
+  typedef mozilla::gfx::Size Size;
+  typedef mozilla::gfx::IntRect IntRect;
+  typedef mozilla::gfx::ColorSpace ColorSpace;
+  typedef mozilla::gfx::FilterPrimitiveDescription FilterPrimitiveDescription;
 
-    ColorModel(ColorSpace aColorSpace, AlphaChannel aAlphaChannel) :
-      mColorSpace(aColorSpace), mAlphaChannel(aAlphaChannel) {}
-    ColorModel() :
-      mColorSpace(SRGB), mAlphaChannel(PREMULTIPLIED) {}
-    bool operator==(const ColorModel& aOther) const {
-      return mColorSpace == aOther.mColorSpace &&
-             mAlphaChannel == aOther.mAlphaChannel;
-    }
-    ColorSpace   mColorSpace;
-    AlphaChannel mAlphaChannel;
-  };
-
-  struct Image {
-    // The device offset of mImage makes it relative to filter space
-    nsRefPtr<gfxImageSurface> mImage;
-    // The filter primitive subregion bounding this image, in filter space
-    gfxRect                   mFilterPrimitiveSubregion;
-    ColorModel                mColorModel;
-    // When true, the RGB values are the same for all pixels in mImage
-    bool                      mConstantColorChannels;
-    
-    Image() : mConstantColorChannels(false) {}
-  };
-
-protected:
   nsSVGFE(already_AddRefed<nsINodeInfo> aNodeInfo) : nsSVGFEBase(aNodeInfo) {}
 
-  struct ScaleInfo {
-    nsRefPtr<gfxImageSurface> mRealTarget;
-    nsRefPtr<gfxImageSurface> mSource;
-    nsRefPtr<gfxImageSurface> mTarget;
-    nsIntRect mDataRect; // rect in mSource and mTarget to operate on
-    bool mRescaling;
-  };
+public:
+  typedef mozilla::gfx::AttributeMap AttributeMap;
 
-  ScaleInfo SetupScalingFilter(nsSVGFilterInstance *aInstance,
-                               const Image *aSource,
-                               const Image *aTarget,
-                               const nsIntRect& aDataRect,
-                               nsSVGNumberPair *aUnit);
-
-  void FinishScalingFilter(ScaleInfo *aScaleInfo);
-
-public:
-  ColorModel
-  GetInputColorModel(nsSVGFilterInstance* aInstance, int32_t aInputIndex,
-                     Image* aImage) {
-    return ColorModel(
-          (OperatesOnSRGB(aInstance, aInputIndex, aImage) ?
-             ColorModel::SRGB : ColorModel::LINEAR_RGB),
-          (OperatesOnPremultipledAlpha(aInputIndex) ?
-             ColorModel::PREMULTIPLIED : ColorModel::UNPREMULTIPLIED));
+  ColorSpace
+  GetInputColorSpace(int32_t aInputIndex, ColorSpace aUnchangedInputColorSpace) {
+    return OperatesOnSRGB(aInputIndex, aUnchangedInputColorSpace == mozilla::gfx::SRGB) ?
+             mozilla::gfx::SRGB : mozilla::gfx::LINEAR_RGB;
   }
 
-  ColorModel
-  GetOutputColorModel(nsSVGFilterInstance* aInstance) {
-    return ColorModel(
-          (OperatesOnSRGB(aInstance, -1, nullptr) ?
-             ColorModel::SRGB : ColorModel::LINEAR_RGB),
-          (OperatesOnPremultipledAlpha(-1) ?
-             ColorModel::PREMULTIPLIED : ColorModel::UNPREMULTIPLIED));
+  // This is only called for filter primitives without inputs. For primitives
+  // with inputs, the output color model is the same as of the first input.
+  ColorSpace
+  GetOutputColorSpace() {
+    return ProducesSRGB() ? mozilla::gfx::SRGB : mozilla::gfx::LINEAR_RGB;
   }
 
   // See http://www.w3.org/TR/SVG/filters.html#FilterPrimitiveSubRegion
   virtual bool SubregionIsUnionOfRegions() { return true; }
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_SVG_FE_CID)
 
   // interfaces:
@@ -144,55 +86,21 @@ public:
 
   bool IsNodeOfType(uint32_t aFlags) const MOZ_OVERRIDE
     { return !(aFlags & ~(eCONTENT | eFILTER)); }
 
   virtual nsSVGString& GetResultImageName() = 0;
   // Return a list of all image names used as sources. Default is to
   // return no sources.
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources);
-  // Compute the bounding box of the filter output. The default is just the
-  // union of the source bounding boxes. The caller is
-  // responsible for clipping this to the filter primitive subregion, so
-  // if the filter fills its filter primitive subregion, it can just
-  // return GetMaxRect() here.
-  // The source bounding boxes are ordered corresponding to GetSourceImageNames.
-  virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
-          const nsSVGFilterInstance& aInstance);
-  // Given a bounding box for what we need to compute in the target,
-  // compute which regions of the inputs are needed. On input
-  // aSourceBBoxes contains the bounding box of what's rendered by
-  // each source; this function should change those boxes to indicate
-  // which region of the source's output it needs.
-  // The default implementation sets all the source bboxes to the
-  // target bbox.
-  virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
-          nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance);
-  // Given the bounding boxes for the pixels that have changed in the inputs,
-  // compute the bounding box of the changes in this primitive's output.
-  // The result will be clipped by the caller to the result of ComputeTargetBBox
-  // since there's no way anything outside that can change.
-  // The default implementation returns the union of the source change boxes.
-  virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
-          const nsSVGFilterInstance& aInstance);
-  
-  // Perform the actual filter operation.
-  // We guarantee that every mImage from aSources and aTarget has the
-  // same width, height, stride and device offset.
-  // aTarget is already filled in. This function just needs to fill in the
-  // pixels of aTarget->mImage (which have already been cleared).
-  // @param aDataRect the destination rectangle that needs to be painted,
-  // relative to aTarget's surface data. This is the intersection of the
-  // filter primitive subregion for this filter element and the
-  // temporary surface area. Output need not be clipped to this rect but
-  // it must be clipped to aTarget->mFilterPrimitiveSubregion.
-  virtual nsresult Filter(nsSVGFilterInstance* aInstance,
-                          const nsTArray<const Image*>& aSources,
-                          const Image* aTarget,
-                          const nsIntRect& aDataRect) = 0;
+
+  virtual FilterPrimitiveDescription
+    GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                            const IntRect& aFilterSubregion,
+                            nsTArray<nsRefPtr<gfxASurface> >& aInputImages) = 0;
 
   // returns true if changes to the attribute should cause us to
   // repaint the filter
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const;
 
   static nsIntRect GetMaxRect() {
     // Try to avoid overflow errors dealing with this rect. It will
@@ -205,34 +113,31 @@ public:
   // WebIDL
   already_AddRefed<mozilla::dom::SVGAnimatedLength> X();
   already_AddRefed<mozilla::dom::SVGAnimatedLength> Y();
   already_AddRefed<mozilla::dom::SVGAnimatedLength> Width();
   already_AddRefed<mozilla::dom::SVGAnimatedLength> Height();
   already_AddRefed<mozilla::dom::SVGAnimatedString> Result();
 
 protected:
-  virtual bool OperatesOnPremultipledAlpha(int32_t) { return true; }
+  virtual bool OperatesOnSRGB(int32_t aInputIndex, bool aInputIsAlreadySRGB) {
+    return StyleIsSetToSRGB();
+  }
 
-  // Called either with aInputIndex >=0 in which case this is
-  // testing whether the input 'aInputIndex' should be SRGB, or
-  // if aInputIndex is -1 returns true if the output will be SRGB
-  virtual bool OperatesOnSRGB(nsSVGFilterInstance* aInstance,
-                                int32_t aInputIndex, Image* aImage) {
-    nsIFrame* frame = GetPrimaryFrame();
-    if (!frame) return false;
+  // Only called for filter primitives without inputs.
+  virtual bool ProducesSRGB() { return StyleIsSetToSRGB(); }
 
-    nsStyleContext* style = frame->StyleContext();
-    return style->StyleSVG()->mColorInterpolationFilters ==
-             NS_STYLE_COLOR_INTERPOLATION_SRGB;
-  }
+  bool StyleIsSetToSRGB();
 
   // nsSVGElement specializations:
   virtual LengthAttributesInfo GetLengthInfo() MOZ_OVERRIDE;
 
+  Size GetKernelUnitLength(nsSVGFilterInstance* aInstance,
+                          nsSVGNumberPair *aKernelUnitLength);
+
   enum { ATTR_X, ATTR_Y, ATTR_WIDTH, ATTR_HEIGHT };
   nsSVGLength2 mLengthAttributes[4];
   static LengthInfo sLengthInfo[4];
 };
 
 typedef nsSVGElement SVGFEUnstyledElementBase;
 
 class SVGFEUnstyledElement : public SVGFEUnstyledElementBase
@@ -259,68 +164,65 @@ class nsSVGFELightingElement : public ns
 protected:
   nsSVGFELightingElement(already_AddRefed<nsINodeInfo> aNodeInfo)
     : nsSVGFELightingElementBase(aNodeInfo) {}
 
 public:
   // interfaces:
   NS_DECL_ISUPPORTS_INHERITED
 
-  virtual nsresult Filter(nsSVGFilterInstance* aInstance,
-                          const nsTArray<const Image*>& aSources,
-                          const Image* aTarget,
-                          const nsIntRect& aDataRect) MOZ_OVERRIDE;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const MOZ_OVERRIDE;
   virtual nsSVGString& GetResultImageName() MOZ_OVERRIDE { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) MOZ_OVERRIDE;
-  // XXX shouldn't we have ComputeTargetBBox here, since the output can
-  // extend beyond the bounds of the inputs thanks to the convolution kernel?
-  virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
-          nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
-  virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
-          const nsSVGFilterInstance& aInstance) MOZ_OVERRIDE;
-
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGFELightingElementBase::)
 
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const MOZ_OVERRIDE;
 
 protected:
-  virtual bool OperatesOnSRGB(nsSVGFilterInstance*,
-                              int32_t, Image*) MOZ_OVERRIDE { return true; }
-  virtual void
-  LightPixel(const float *N, const float *L,
-             nscolor color, uint8_t *targetData) = 0;
+  virtual bool OperatesOnSRGB(int32_t aInputIndex,
+                              bool aInputIsAlreadySRGB) MOZ_OVERRIDE { return true; }
 
   virtual NumberAttributesInfo GetNumberInfo() MOZ_OVERRIDE;
   virtual NumberPairAttributesInfo GetNumberPairInfo() MOZ_OVERRIDE;
   virtual StringAttributesInfo GetStringInfo() MOZ_OVERRIDE;
 
+  AttributeMap ComputeLightAttributes(nsSVGFilterInstance* aInstance);
+
+  FilterPrimitiveDescription
+    AddLightingAttributes(FilterPrimitiveDescription aDescription,
+                          nsSVGFilterInstance* aInstance);
+
   enum { SURFACE_SCALE, DIFFUSE_CONSTANT, SPECULAR_CONSTANT, SPECULAR_EXPONENT };
   nsSVGNumber2 mNumberAttributes[4];
   static NumberInfo sNumberInfo[4];
 
   enum { KERNEL_UNIT_LENGTH };
   nsSVGNumberPair mNumberPairAttributes[1];
   static NumberPairInfo sNumberPairInfo[1];
 
   enum { RESULT, IN1 };
   nsSVGString mStringAttributes[2];
   static StringInfo sStringInfo[2];
 };
 
-void
-CopyDataRect(uint8_t *aDest, const uint8_t *aSrc, uint32_t aStride,
-             const nsIntRect& aDataRect);
+namespace mozilla {
+namespace dom {
 
-inline void
-CopyRect(const nsSVGFE::Image* aDest, const nsSVGFE::Image* aSrc, const nsIntRect& aDataRect)
+typedef SVGFEUnstyledElement SVGFELightElementBase;
+
+class SVGFELightElement : public SVGFELightElementBase
 {
-  NS_ASSERTION(aDest->mImage->Stride() == aSrc->mImage->Stride(), "stride mismatch");
-  NS_ASSERTION(aDest->mImage->GetSize() == aSrc->mImage->GetSize(), "size mismatch");
-  NS_ASSERTION(nsIntRect(0, 0, aDest->mImage->Width(), aDest->mImage->Height()).Contains(aDataRect),
-               "aDataRect out of bounds");
+protected:
+  SVGFELightElement(already_AddRefed<nsINodeInfo> aNodeInfo)
+    : SVGFELightElementBase(aNodeInfo) {}
 
-  CopyDataRect(aDest->mImage->Data(), aSrc->mImage->Data(),
-               aSrc->mImage->Stride(), aDataRect);
+public:
+  typedef gfx::AttributeMap AttributeMap;
+
+  virtual AttributeMap
+    ComputeLightAttributes(nsSVGFilterInstance* aInstance) = 0;
+};
+
+}
 }
 
 #endif
--- a/content/xbl/src/XBLChildrenElement.h
+++ b/content/xbl/src/XBLChildrenElement.h
@@ -68,21 +68,16 @@ public:
     // only insert in the innermost insertion point.
     //NS_ASSERTION(mInsertedChildren.Contains(aChild),
     //             "Removing child that's not there");
     mInsertedChildren.RemoveElement(aChild);
   }
 
   void ClearInsertedChildren()
   {
-    mInsertedChildren.Clear();
-  }
-
-  void ClearInsertedChildrenAndInsertionParents()
-  {
     for (uint32_t c = 0; c < mInsertedChildren.Length(); ++c) {
       mInsertedChildren[c]->SetXBLInsertionParent(nullptr);
     }
     mInsertedChildren.Clear();
   }
 
   void MaybeSetupDefaultContent()
   {
--- a/content/xbl/src/nsBindingManager.cpp
+++ b/content/xbl/src/nsBindingManager.cpp
@@ -1085,17 +1085,17 @@ nsBindingManager::ContentRemoved(nsIDocu
     parent = newParent;
   } while (parent);
 }
 
 void
 nsBindingManager::ClearInsertionPointsRecursively(nsIContent* aContent)
 {
   if (aContent->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
-    static_cast<XBLChildrenElement*>(aContent)->ClearInsertedChildrenAndInsertionParents();
+    static_cast<XBLChildrenElement*>(aContent)->ClearInsertedChildren();
   }
 
   for (nsIContent* child = aContent->GetFirstChild(); child;
        child = child->GetNextSibling()) {
     ClearInsertionPointsRecursively(child);
   }
 }
 
--- a/content/xbl/src/nsXBLPrototypeHandler.cpp
+++ b/content/xbl/src/nsXBLPrototypeHandler.cpp
@@ -323,17 +323,17 @@ nsXBLPrototypeHandler::ExecuteHandler(Ev
 
   nsRefPtr<EventHandlerNonNull> handlerCallback =
     new EventHandlerNonNull(bound);
 
   nsEventHandler eventHandler(handlerCallback);
 
   // Execute it.
   nsCOMPtr<nsIJSEventListener> eventListener;
-  rv = NS_NewJSEventListener(nullptr, globalObject,
+  rv = NS_NewJSEventListener(globalObject,
                              scriptTarget, onEventAtom,
                              eventHandler,
                              getter_AddRefs(eventListener));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Handle the event.
   eventListener->HandleEvent(aEvent);
   eventListener->Disconnect();
--- a/content/xbl/src/nsXBLWindowKeyHandler.cpp
+++ b/content/xbl/src/nsXBLWindowKeyHandler.cpp
@@ -11,17 +11,16 @@
 #include "nsIDOMKeyEvent.h"
 #include "nsXBLService.h"
 #include "nsIServiceManager.h"
 #include "nsGkAtoms.h"
 #include "nsXBLDocumentInfo.h"
 #include "nsIDOMElement.h"
 #include "nsINativeKeyBindings.h"
 #include "nsIController.h"
-#include "nsIControllers.h"
 #include "nsFocusManager.h"
 #include "nsPIWindowRoot.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "nsContentUtils.h"
 #include "nsXBLPrototypeBinding.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDocShell.h"
@@ -282,23 +281,23 @@ GetEditorKeyBindings()
   }
 
   return sNativeEditorBindings;
 }
 
 static void
 DoCommandCallback(const char *aCommand, void *aData)
 {
-  nsIControllers *controllers = static_cast<nsIControllers*>(aData);
-  if (!controllers) {
+  nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(static_cast<EventTarget*>(aData));
+  if (!root) {
     return;
   }
 
   nsCOMPtr<nsIController> controller;
-  controllers->GetControllerForCommand(aCommand, getter_AddRefs(controller));
+  root->GetControllerForCommand(aCommand, getter_AddRefs(controller));
   if (!controller) {
     return;
   }
 
   bool commandEnabled;
   nsresult rv = controller->IsCommandEnabled(aCommand, &commandEnabled);
   NS_ENSURE_SUCCESS_VOID(rv);
   if (commandEnabled) {
@@ -348,43 +347,36 @@ nsXBLWindowKeyHandler::WalkHandlers(nsID
   if (prevent) {
     return NS_OK;
   }
 
   // XXX Shouldn't we prefer the native key binding rather than our key
   //     bindings?  I.e., should we call WalkHandlersInternal() after this
   //     block?
   if (isEditor && GetEditorKeyBindings()) {
-    // get the DOM window we're attached to
-    nsCOMPtr<nsIControllers> controllers;
-    nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(mTarget);
-    if (root) {
-      root->GetControllers(getter_AddRefs(controllers));
-    }
-
     WidgetKeyboardEvent* keyEvent =
       aKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
     MOZ_ASSERT(keyEvent,
                "DOM key event's internal event must be WidgetKeyboardEvent");
     bool handled = false;
     switch (keyEvent->message) {
       case NS_KEY_PRESS:
         handled = sNativeEditorBindings->KeyPress(*keyEvent,
                                                   DoCommandCallback,
-                                                  controllers);
+                                                  mTarget);
         break;
       case NS_KEY_UP:
         handled = sNativeEditorBindings->KeyUp(*keyEvent,
                                                DoCommandCallback,
-                                               controllers);
+                                               mTarget);
         break;
       case NS_KEY_DOWN:
         handled = sNativeEditorBindings->KeyDown(*keyEvent,
                                                  DoCommandCallback,
-                                                 controllers);
+                                                 mTarget);
         break;
       default:
         MOZ_CRASH("Unknown key message");
     }
 
     if (handled)
       aKeyEvent->PreventDefault();
 
--- a/content/xul/content/src/moz.build
+++ b/content/xul/content/src/moz.build
@@ -2,17 +2,17 @@
 # vim: set filetype=python:
 # 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/.
 
 if CONFIG['MOZ_XUL']:
     MSVC_ENABLE_PGO = True
 
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'nsXULContextMenuBuilder.cpp',
         'nsXULElement.cpp',
         'nsXULPopupListener.cpp',
     ]
 
 FAIL_ON_WARNINGS = True
 
 LOCAL_INCLUDES += [
--- a/content/xul/document/src/moz.build
+++ b/content/xul/document/src/moz.build
@@ -1,20 +1,20 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'nsXULControllers.cpp',
 ]
 
 if CONFIG['MOZ_XUL']:
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'nsXULCommandDispatcher.cpp',
         'nsXULContentSink.cpp',
         'nsXULPrototypeCache.cpp',
         'nsXULPrototypeDocument.cpp',
         'XULDocument.cpp',
     ]
 
 FAIL_ON_WARNINGS = True
--- a/content/xul/document/src/nsXULCommandDispatcher.cpp
+++ b/content/xul/document/src/nsXULCommandDispatcher.cpp
@@ -33,28 +33,28 @@
 #include "nsEventDispatcher.h"
 #include "nsDOMClassInfoID.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 
 #ifdef PR_LOGGING
-static PRLogModuleInfo* gLog;
+static PRLogModuleInfo* gCommandLog;
 #endif
 
 ////////////////////////////////////////////////////////////////////////
 
 nsXULCommandDispatcher::nsXULCommandDispatcher(nsIDocument* aDocument)
     : mDocument(aDocument), mUpdaters(nullptr)
 {
 
 #ifdef PR_LOGGING
-  if (! gLog)
-    gLog = PR_NewLogModule("nsXULCommandDispatcher");
+  if (! gCommandLog)
+    gCommandLog = PR_NewLogModule("nsXULCommandDispatcher");
 #endif
 }
 
 nsXULCommandDispatcher::~nsXULCommandDispatcher()
 {
   Disconnect();
 }
 
@@ -269,23 +269,23 @@ nsXULCommandDispatcher::AddCommandUpdate
 
   Updater* updater = mUpdaters;
   Updater** link = &mUpdaters;
 
   while (updater) {
     if (updater->mElement == aElement) {
 
 #ifdef DEBUG
-      if (PR_LOG_TEST(gLog, PR_LOG_NOTICE)) {
+      if (PR_LOG_TEST(gCommandLog, PR_LOG_NOTICE)) {
         nsAutoCString eventsC, targetsC, aeventsC, atargetsC; 
         eventsC.AssignWithConversion(updater->mEvents);
         targetsC.AssignWithConversion(updater->mTargets);
         CopyUTF16toUTF8(aEvents, aeventsC);
         CopyUTF16toUTF8(aTargets, atargetsC);
-        PR_LOG(gLog, PR_LOG_NOTICE,
+        PR_LOG(gCommandLog, PR_LOG_NOTICE,
                ("xulcmd[%p] replace %p(events=%s targets=%s) with (events=%s targets=%s)",
                 this, aElement,
                 eventsC.get(),
                 targetsC.get(),
                 aeventsC.get(),
                 atargetsC.get()));
       }
 #endif
@@ -297,22 +297,22 @@ nsXULCommandDispatcher::AddCommandUpdate
       updater->mTargets = aTargets;
       return NS_OK;
     }
 
     link = &(updater->mNext);
     updater = updater->mNext;
   }
 #ifdef DEBUG
-  if (PR_LOG_TEST(gLog, PR_LOG_NOTICE)) {
+  if (PR_LOG_TEST(gCommandLog, PR_LOG_NOTICE)) {
     nsAutoCString aeventsC, atargetsC; 
     CopyUTF16toUTF8(aEvents, aeventsC);
     CopyUTF16toUTF8(aTargets, atargetsC);
 
-    PR_LOG(gLog, PR_LOG_NOTICE,
+    PR_LOG(gCommandLog, PR_LOG_NOTICE,
            ("xulcmd[%p] add     %p(events=%s targets=%s)",
             this, aElement,
             aeventsC.get(),
             atargetsC.get()));
   }
 #endif
 
   // If we get here, this is a new updater. Append it to the list.
@@ -332,21 +332,21 @@ nsXULCommandDispatcher::RemoveCommandUpd
     return NS_ERROR_NULL_POINTER;
 
   Updater* updater = mUpdaters;
   Updater** link = &mUpdaters;
 
   while (updater) {
     if (updater->mElement == aElement) {
 #ifdef DEBUG
-      if (PR_LOG_TEST(gLog, PR_LOG_NOTICE)) {
+      if (PR_LOG_TEST(gCommandLog, PR_LOG_NOTICE)) {
         nsAutoCString eventsC, targetsC; 
         eventsC.AssignWithConversion(updater->mEvents);
         targetsC.AssignWithConversion(updater->mTargets);
-        PR_LOG(gLog, PR_LOG_NOTICE,
+        PR_LOG(gCommandLog, PR_LOG_NOTICE,
                ("xulcmd[%p] remove  %p(events=%s targets=%s)",
                 this, aElement,
                 eventsC.get(),
                 targetsC.get()));
       }
 #endif
 
       *link = updater->mNext;
@@ -398,20 +398,20 @@ nsXULCommandDispatcher::UpdateCommands(c
 
     nsCOMPtr<nsIDocument> document = content->GetDocument();
 
     NS_ASSERTION(document != nullptr, "element has no document");
     if (! document)
       continue;
 
 #ifdef DEBUG
-    if (PR_LOG_TEST(gLog, PR_LOG_NOTICE)) {
+    if (PR_LOG_TEST(gCommandLog, PR_LOG_NOTICE)) {
       nsAutoCString aeventnameC; 
       CopyUTF16toUTF8(aEventName, aeventnameC);
-      PR_LOG(gLog, PR_LOG_NOTICE,
+      PR_LOG(gCommandLog, PR_LOG_NOTICE,
              ("xulcmd[%p] update %p event=%s",
               this, content,
               aeventnameC.get()));
     }
 #endif
 
     nsCOMPtr<nsIPresShell> shell = document->GetShell();
     if (shell) {
--- a/content/xul/document/src/nsXULContentSink.cpp
+++ b/content/xul/document/src/nsXULContentSink.cpp
@@ -53,17 +53,17 @@
 #include "nsContentUtils.h"
 #include "nsAttrName.h"
 #include "nsXMLContentSink.h"
 #include "nsIConsoleService.h"
 #include "nsIScriptError.h"
 #include "nsContentTypeParser.h"
 
 #ifdef PR_LOGGING
-static PRLogModuleInfo* gLog;
+static PRLogModuleInfo* gContentSinkLog;
 #endif
 
 //----------------------------------------------------------------------
 
 XULContentSinkImpl::ContextStack::ContextStack()
     : mTop(nullptr), mDepth(0)
 {
 }
@@ -164,18 +164,18 @@ XULContentSinkImpl::XULContentSinkImpl()
       mTextLength(0),
       mTextSize(0),
       mConstrainSize(true),
       mState(eInProlog),
       mParser(nullptr)
 {
 
 #ifdef PR_LOGGING
-    if (! gLog)
-        gLog = PR_NewLogModule("nsXULContentSink");
+    if (! gContentSinkLog)
+        gContentSinkLog = PR_NewLogModule("nsXULContentSink");
 #endif
 }
 
 
 XULContentSinkImpl::~XULContentSinkImpl()
 {
     NS_IF_RELEASE(mParser); // XXX should've been released by now, unless error.
 
@@ -491,17 +491,17 @@ XULContentSinkImpl::HandleStartElement(c
       break;
 
   case eInDocumentElement:
       rv = OpenTag(aAtts, aAttsCount, aLineNumber, nodeInfo);
       break;
 
   case eInEpilog:
   case eInScript:
-      PR_LOG(gLog, PR_LOG_WARNING,
+      PR_LOG(gContentSinkLog, PR_LOG_WARNING,
              ("xul: warning: unexpected tags in epilog at line %d",
              aLineNumber));
       rv = NS_ERROR_UNEXPECTED; // XXX
       break;
   }
 
   // Set the ID attribute atom on the node info object for this node
   if (aIndex != -1 && NS_SUCCEEDED(rv)) {
@@ -754,32 +754,32 @@ XULContentSinkImpl::OpenRoot(const PRUni
     NS_ASSERTION(mState == eInProlog, "how'd we get here?");
     if (mState != eInProlog)
         return NS_ERROR_UNEXPECTED;
 
     nsresult rv;
 
     if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) || 
         aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XUL)) {
-        PR_LOG(gLog, PR_LOG_ERROR,
+        PR_LOG(gContentSinkLog, PR_LOG_ERROR,
                ("xul: script tag not allowed as root content element"));
 
         return NS_ERROR_UNEXPECTED;
     }
 
     // Create the element
     nsXULPrototypeElement* element;
     rv = CreateElement(aNodeInfo, &element);
 
     if (NS_FAILED(rv)) {
 #ifdef PR_LOGGING
-        if (PR_LOG_TEST(gLog, PR_LOG_ERROR)) {
+        if (PR_LOG_TEST(gContentSinkLog, PR_LOG_ERROR)) {
             nsAutoString anodeC;
             aNodeInfo->GetName(anodeC);
-            PR_LOG(gLog, PR_LOG_ERROR,
+            PR_LOG(gContentSinkLog, PR_LOG_ERROR,
                    ("xul: unable to create element '%s' at line %d",
                     NS_ConvertUTF16toUTF8(anodeC).get(),
                     -1)); // XXX pass in line number
         }
 #endif
 
         return rv;
     }
@@ -809,20 +809,20 @@ XULContentSinkImpl::OpenTag(const PRUnic
     nsresult rv;
 
     // Create the element
     nsXULPrototypeElement* element;
     rv = CreateElement(aNodeInfo, &element);
 
     if (NS_FAILED(rv)) {
 #ifdef PR_LOGGING
-        if (PR_LOG_TEST(gLog, PR_LOG_ERROR)) {
+        if (PR_LOG_TEST(gContentSinkLog, PR_LOG_ERROR)) {
             nsAutoString anodeC;
             aNodeInfo->GetName(anodeC);
-            PR_LOG(gLog, PR_LOG_ERROR,
+            PR_LOG(gContentSinkLog, PR_LOG_ERROR,
                    ("xul: unable to create element '%s' at line %d",
                     NS_ConvertUTF16toUTF8(anodeC).get(),
                     aLineNumber));
         }
 #endif
 
         return rv;
     }
@@ -1029,25 +1029,25 @@ XULContentSinkImpl::AddAttributes(const 
       rv = NormalizeAttributeString(aAttributes[i * 2], attrs[i].mName);
       NS_ENSURE_SUCCESS(rv, rv);
 
       rv = aElement->SetAttrAt(i, nsDependentString(aAttributes[i * 2 + 1]),
                                mDocumentURL);
       NS_ENSURE_SUCCESS(rv, rv);
 
 #ifdef PR_LOGGING
-      if (PR_LOG_TEST(gLog, PR_LOG_DEBUG)) {
+      if (PR_LOG_TEST(gContentSinkLog, PR_LOG_DEBUG)) {
           nsAutoString extraWhiteSpace;
           int32_t cnt = mContextStack.Depth();
           while (--cnt >= 0)
               extraWhiteSpace.AppendLiteral("  ");
           nsAutoString qnameC,valueC;
           qnameC.Assign(aAttributes[0]);
           valueC.Assign(aAttributes[1]);
-          PR_LOG(gLog, PR_LOG_DEBUG,
+          PR_LOG(gContentSinkLog, PR_LOG_DEBUG,
                  ("xul: %.5d. %s    %s=%s",
                   -1, // XXX pass in line number
                   NS_ConvertUTF16toUTF8(extraWhiteSpace).get(),
                   NS_ConvertUTF16toUTF8(qnameC).get(),
                   NS_ConvertUTF16toUTF8(valueC).get()));
       }
 #endif
   }
--- a/db/sqlite3/src/Makefile.in
+++ b/db/sqlite3/src/Makefile.in
@@ -41,78 +41,21 @@ MODULE_OPTIMIZE_FLAGS = -O2
 endif
 
 # Force /O2 optimisation on Windows because using the default /O1 causes
 # crashes with MSVC2005 and PGO. See bug 719584.
 ifeq ($(OS_ARCH),WINNT)
 MODULE_OPTIMIZE_FLAGS = -O2
 endif
 
-# -DSQLITE_SECURE_DELETE=1 will cause SQLITE to 0-fill delete data so we
-# don't have to vacuum to make sure the data is not visible in the file.
-# -DSQLITE_ENABLE_FTS3=1 enables the full-text index module.
-# -DSQLITE_CORE=1 statically links that module into the SQLite library.
-# -DSQLITE_DEFAULT_PAGE_SIZE=32768 and SQLITE_MAX_DEFAULT_PAGE_SIZE=32768
-# increases the page size from 1k, see bug 416330.  It must be kept in sync with
-# the value of PREF_TS_PAGESIZE_DEFAULT in mozStorageService.cpp.  The value can
-# be overridden on a per-platform basis through the use of the PREF_TS_PAGESIZE
-# hidden preference.  If that preference is missing or invalid then this value
-# will be used.
-# -DSQLITE_MAX_SCHEMA_RETRY increases the times SQLite may try to reparse
-# statements when the schema changes. This is important when supporting lots of
-# concurrent connections, especially when they use shared cache.
-# Note: Be sure to update the configure.in checks when these change!
-DEFINES = \
-  -DSQLITE_SECURE_DELETE=1 \
-  -DSQLITE_THREADSAFE=1 \
-  -DSQLITE_CORE=1 \
-  -DSQLITE_ENABLE_FTS3=1 \
-  -DSQLITE_ENABLE_UNLOCK_NOTIFY=1 \
-  -DSQLITE_DEFAULT_PAGE_SIZE=32768 \
-  -DSQLITE_MAX_DEFAULT_PAGE_SIZE=32768 \
-  -DSQLITE_MAX_SCHEMA_RETRY=25 \
-  $(NULL)
-
-# -DSQLITE_ENABLE_LOCKING_STYLE=1 to help with AFP folders
-ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
-DEFINES += -DSQLITE_ENABLE_LOCKING_STYLE=1
-endif
-
-# Turn on SQLite's assertions in debug builds.
-ifdef MOZ_DEBUG
-DEFINES += -DSQLITE_DEBUG=1
-endif
-
 # disable PGO for Sun Studio
 ifdef SOLARIS_SUNPRO_CC
 NO_PROFILE_GUIDED_OPTIMIZE = 1
 endif
 
-ifeq ($(OS_ARCH),OS2)
-ifdef MOZ_OS2_HIGH_MEMORY
-DEFINES += -DOS2_HIGH_MEMORY
-endif
-endif
-
-ifeq ($(OS_TARGET),Android)
-# default to user readable only to fit Android security model
-DEFINES += -DSQLITE_DEFAULT_FILE_PERMISSIONS=0600
-endif
-
-# Force using malloc_usable_size when building with jemalloc because _msize
-# causes assertions on Win64. See bug 719579.
-ifeq ($(OS_ARCH),WINNT)
-ifdef MOZ_MEMORY
-DEFINES += \
-  -DHAVE_MALLOC_USABLE_SIZE \
-  -DSQLITE_WITHOUT_MSIZE \
-  $(NULL)
-endif
-endif
-
 include $(topsrcdir)/config/rules.mk
 
 # next line allows use of MOZ_OBJDIR in .mozconfig with older gcc on BeOS, maybe others
 LOCAL_INCLUDES += -I$(srcdir)
 
 ifeq ($(OS_ARCH),OS2)
 ADD_TO_DEF_FILE = $(PYTHON) -m mozbuild.action.preprocessor $(DEFINES) \
        $(srcdir)/sqlite.def | sed -e '1,/^EXPORTS$$/ d' -e 's,sqlite3,_\0,' \
--- a/db/sqlite3/src/moz.build
+++ b/db/sqlite3/src/moz.build
@@ -14,8 +14,51 @@ LIBRARY_NAME = 'mozsqlite3'
 SOURCES += [
     'sqlite3.c',
 ]
 
 if CONFIG['MOZ_FOLD_LIBS']:
     FORCE_STATIC_LIB = True
 else:
     FORCE_SHARED_LIB = True
+
+# -DSQLITE_SECURE_DELETE=1 will cause SQLITE to 0-fill delete data so we
+# don't have to vacuum to make sure the data is not visible in the file.
+# -DSQLITE_ENABLE_FTS3=1 enables the full-text index module.
+# -DSQLITE_CORE=1 statically links that module into the SQLite library.
+# -DSQLITE_DEFAULT_PAGE_SIZE=32768 and SQLITE_MAX_DEFAULT_PAGE_SIZE=32768
+# increases the page size from 1k, see bug 416330.  It must be kept in sync with
+# the value of PREF_TS_PAGESIZE_DEFAULT in mozStorageService.cpp.  The value can
+# be overridden on a per-platform basis through the use of the PREF_TS_PAGESIZE
+# hidden preference.  If that preference is missing or invalid then this value
+# will be used.
+# -DSQLITE_MAX_SCHEMA_RETRY increases the times SQLite may try to reparse
+# statements when the schema changes. This is important when supporting lots of
+# concurrent connections, especially when they use shared cache.
+# Note: Be sure to update the configure.in checks when these change!
+for var in ('SQLITE_SECURE_DELETE', 'SQLITE_THREADSAFE', 'SQLITE_CORE',
+            'SQLITE_ENABLE_FTS3', 'SQLITE_ENABLE_UNLOCK_NOTIFY'):
+    DEFINES[var] = 1
+
+DEFINES['SQLITE_DEFAULT_PAGE_SIZE'] = 32768
+DEFINES['SQLITE_MAX_DEFAULT_PAGE_SIZE'] = 32768
+DEFINES['SQLITE_MAX_SCHEMA_RETRY'] = 25
+
+# -DSQLITE_ENABLE_LOCKING_STYLE=1 to help with AFP folders
+if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
+    DEFINES['SQLITE_ENABLE_LOCKING_STYLE'] = 1
+
+# Turn on SQLite's assertions in debug builds.
+if CONFIG['MOZ_DEBUG']:
+    DEFINES['SQLITE_DEBUG'] = 1
+
+if CONFIG['OS_ARCH'] == 'OS2' and CONFIG['MOZ_OS2_HIGH_MEMORY']:
+    DEFINES['OS2_HIGH_MEMORY'] = True
+
+if CONFIG['OS_TARGET'] == 'Android':
+    # default to user readable only to fit Android security model
+    DEFINES['SQLITE_DEFAULT_FILE_PERMISSIONS'] = '0600'
+
+# Force using malloc_usable_size when building with jemalloc because _msize
+# causes assertions on Win64. See bug 719579.
+if CONFIG['OS_ARCH'] == 'WINNT' and CONFIG['MOZ_MEMORY']:
+    DEFINES['HAVE_MALLOC_USABLE_SIZE'] = True
+    DEFINES['SQLITE_WITHOUT_MSIZE'] = True
--- a/dom/base/Makefile.in
+++ b/dom/base/Makefile.in
@@ -1,22 +1,10 @@
 # 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/.
 
-ifdef MOZ_JSDEBUGGER
-DEFINES += -DMOZ_JSDEBUGGER
-endif
-
-ifdef MOZ_B2G_RIL
-DEFINES += -DMOZ_B2G_RIL
-endif
-
-ifdef MOZ_B2G_FM
-DEFINES += -DMOZ_B2G_FM
-endif
-
 include $(topsrcdir)/config/rules.mk
 
 ifdef MOZ_X11
 CXXFLAGS += $(TK_CFLAGS)
 LDFLAGS += $(TK_LIBS)
 endif
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -159,8 +159,11 @@ include('/ipc/chromium/chromium-config.m
 FINAL_LIBRARY = 'gklayout'
 
 LOCAL_INCLUDES += [
     '/js/xpconnect/src',
     '/js/xpconnect/wrappers',
     '/xpcom/ds',
 ]
 
+for var in ('MOZ_JSDEBUGGER', 'MOZ_B2G_RIL', 'MOZ_B2G_FM'):
+    if CONFIG[var]:
+        DEFINES[var] = True
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/layers/CompositorParent.h"
-#include "mozilla/layers/PLayerTransactionChild.h"
+#include "mozilla/layers/LayerTransactionChild.h"
 #include "nsPresContext.h"
 #include "nsDOMClassInfoID.h"
 #include "nsError.h"
 #include "nsIDOMEvent.h"
 #include "nsDOMWindowUtils.h"
 #include "nsQueryContentEventResult.h"
 #include "CompositionStringSynthesizer.h"
 #include "nsGlobalWindow.h"
@@ -78,16 +78,17 @@
 #include "nsWidgetsCID.h"
 #include "FrameLayerBuilder.h"
 #include "nsDisplayList.h"
 #include "nsROCSSPrimitiveValue.h"
 #include "nsIBaseWindow.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "GeckoProfiler.h"
+#include "mozilla/Preferences.h"
 
 #ifdef XP_WIN
 #undef GetClassName
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::layers;
@@ -1476,42 +1477,48 @@ nsDOMWindowUtils::SuppressEventHandling(
     doc->SuppressEventHandling();
   } else {
     doc->UnsuppressEventHandlingAndFireEvents(true);
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDOMWindowUtils::GetScrollXY(bool aFlushLayout, int32_t* aScrollX, int32_t* aScrollY)
-{
+static nsresult
+getScrollXYAppUnits(nsWeakPtr mWindow, bool aFlushLayout, nsPoint& aScrollPos) {
   if (!nsContentUtils::IsCallerChrome()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
   NS_ENSURE_STATE(window);
 
   nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
   NS_ENSURE_STATE(doc);
 
   if (aFlushLayout) {
     doc->FlushPendingNotifications(Flush_Layout);
   }
 
-  nsPoint scrollPos(0,0);
   nsIPresShell *presShell = doc->GetShell();
   if (presShell) {
     nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
     if (sf) {
-      scrollPos = sf->GetScrollPosition();
+      aScrollPos = sf->GetScrollPosition();
     }
   }
-
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMWindowUtils::GetScrollXY(bool aFlushLayout, int32_t* aScrollX, int32_t* aScrollY)
+{
+  nsPoint scrollPos(0,0);
+  nsresult rv = getScrollXYAppUnits(mWindow, aFlushLayout, scrollPos);
+  NS_ENSURE_SUCCESS(rv, rv);
   *aScrollX = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.x);
   *aScrollY = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.y);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::ScrollToCSSPixelsApproximate(float aX, float aY, bool* aRetVal)
@@ -1526,16 +1533,28 @@ nsDOMWindowUtils::ScrollToCSSPixelsAppro
   if (aRetVal) {
     *aRetVal = (sf != nullptr);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDOMWindowUtils::GetScrollXYFloat(bool aFlushLayout, float* aScrollX, float* aScrollY)
+{
+  nsPoint scrollPos(0,0);
+  nsresult rv = getScrollXYAppUnits(mWindow, aFlushLayout, scrollPos);
+  NS_ENSURE_SUCCESS(rv, rv);
+  *aScrollX = nsPresContext::AppUnitsToFloatCSSPixels(scrollPos.x);
+  *aScrollY = nsPresContext::AppUnitsToFloatCSSPixels(scrollPos.y);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDOMWindowUtils::GetScrollbarSize(bool aFlushLayout, int32_t* aWidth,
                                                       int32_t* aHeight)
 {
   if (!nsContentUtils::IsCallerChrome()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   *aWidth = 0;
@@ -2237,60 +2256,55 @@ nsDOMWindowUtils::StartFrameTimeRecordin
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget)
     return NS_ERROR_FAILURE;
 
   LayerManager *mgr = widget->GetLayerManager();
   if (!mgr)
     return NS_ERROR_FAILURE;
 
-  *startIndex = mgr->StartFrameTimeRecording();
+  const uint32_t kRecordingMinSize = 60 * 10; // 10 seconds @60 fps.
+  const uint32_t kRecordingMaxSize = 60 * 60 * 60; // One hour
+  uint32_t bufferSize = Preferences::GetUint("toolkit.framesRecording.bufferSize", uint32_t(0));
+  bufferSize = std::min(bufferSize, kRecordingMaxSize);
+  bufferSize = std::max(bufferSize, kRecordingMinSize);
+  *startIndex = mgr->StartFrameTimeRecording(bufferSize);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::StopFrameTimeRecording(uint32_t   startIndex,
-                                         float    **paintTimes,
                                          uint32_t  *frameCount,
                                          float    **frameIntervals)
 {
   if (!nsContentUtils::IsCallerChrome()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   NS_ENSURE_ARG_POINTER(frameCount);
   NS_ENSURE_ARG_POINTER(frameIntervals);
-  NS_ENSURE_ARG_POINTER(paintTimes);
 
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget)
     return NS_ERROR_FAILURE;
 
   LayerManager *mgr = widget->GetLayerManager();
   if (!mgr)
     return NS_ERROR_FAILURE;
 
   nsTArray<float> tmpFrameIntervals;
-  nsTArray<float> tmpPaintTimes;
-  mgr->StopFrameTimeRecording(startIndex, tmpFrameIntervals, tmpPaintTimes);
+  mgr->StopFrameTimeRecording(startIndex, tmpFrameIntervals);
   *frameCount = tmpFrameIntervals.Length();
 
   *frameIntervals = (float*)nsMemory::Alloc(*frameCount * sizeof(float*));
-  *paintTimes =     (float*)nsMemory::Alloc(*frameCount * sizeof(float*));
 
   /* copy over the frame intervals and paint times into the arrays we just allocated */
   for (uint32_t i = 0; i < *frameCount; i++) {
     (*frameIntervals)[i] = tmpFrameIntervals[i];
-#ifndef MOZ_WIDGET_GONK
-    (*paintTimes)[i] = tmpPaintTimes[i];
-#else
-    // Waiting for bug 830475 to work on B2G.
-    (*paintTimes)[i] = 0;
-#endif
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::BeginTabSwitch()
 {
--- a/dom/base/nsHistory.cpp
+++ b/dom/base/nsHistory.cpp
@@ -65,17 +65,17 @@ nsHistory::WrapObject(JSContext* aCx, JS
 {
   return HistoryBinding::Wrap(aCx, aScope, this);
 }
 
 uint32_t
 nsHistory::GetLength(ErrorResult& aRv) const
 {
   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
-  if (!win || !win->IsCurrentInnerWindow()) {
+  if (!win || !win->HasActiveDocument()) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
 
     return 0;
   }
 
   // Get session History from docshell
   nsCOMPtr<nsISHistory> sHistory = GetSessionHistory();
   if (!sHistory) {
@@ -101,17 +101,17 @@ nsHistory::GetState(JSContext* aCx, Erro
 {
   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
   if (!win) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
 
     return JS::UndefinedValue();
   }
 
-  if (!win->IsCurrentInnerWindow()) {
+  if (!win->HasActiveDocument()) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
 
     return JS::UndefinedValue();
   }
 
   nsCOMPtr<nsIDocument> doc =
     do_QueryInterface(win->GetExtantDoc());
   if (!doc) {
@@ -141,17 +141,17 @@ nsHistory::GetState(JSContext* aCx, Erro
 
   return JS::UndefinedValue();
 }
 
 void
 nsHistory::Go(int32_t aDelta, ErrorResult& aRv)
 {
   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
-  if (!win || !win->IsCurrentInnerWindow()) {
+  if (!win || !win->HasActiveDocument()) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
 
     return;
   }
 
   if (!aDelta) {
     nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(GetDocShell()));
 
@@ -197,17 +197,17 @@ nsHistory::Go(int32_t aDelta, ErrorResul
   // from GotoIndex() can lead to exceptions and a possible leak
   // of history length
 }
 
 void
 nsHistory::Back(ErrorResult& aRv)
 {
   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
-  if (!win || !win->IsCurrentInnerWindow()) {
+  if (!win || !win->HasActiveDocument()) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
 
     return;
   }
 
   nsCOMPtr<nsISHistory> sHistory = GetSessionHistory();
   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(sHistory));
   if (!webNav) {
@@ -218,17 +218,17 @@ nsHistory::Back(ErrorResult& aRv)
 
   webNav->GoBack();
 }
 
 void
 nsHistory::Forward(ErrorResult& aRv)
 {
   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
-  if (!win || !win->IsCurrentInnerWindow()) {
+  if (!win || !win->HasActiveDocument()) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
 
     return;
   }
 
   nsCOMPtr<nsISHistory> sHistory = GetSessionHistory();
   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(sHistory));
   if (!webNav) {
@@ -263,17 +263,17 @@ nsHistory::PushOrReplaceState(JSContext*
 {
   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
   if (!win) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
 
     return;
   }
 
-  if (!win->IsCurrentInnerWindow()) {
+  if (!win->HasActiveDocument()) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
 
     return;
   }
 
   // Check that PushState hasn't been pref'ed off.
   if (!Preferences::GetBool(aReplace ? sAllowReplaceStatePrefStr :
                             sAllowPushStatePrefStr, false)) {
--- a/dom/base/nsIJSEventListener.h
+++ b/dom/base/nsIJSEventListener.h
@@ -9,18 +9,18 @@
 #include "nsIScriptContext.h"
 #include "xpcpublic.h"
 #include "nsIDOMEventListener.h"
 #include "nsIAtom.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/EventHandlerBinding.h"
 
 #define NS_IJSEVENTLISTENER_IID \
-{ 0x92f9212b, 0xa6aa, 0x4867, \
-  { 0x93, 0x8a, 0x56, 0xbe, 0x17, 0x67, 0x4f, 0xd4 } }
+{ 0x5077b12a, 0x5a1f, 0x4583, \
+  { 0xbb, 0xa7, 0x78, 0x84, 0x94, 0x0e, 0x5e, 0xff } }
 
 class nsEventHandler
 {
 public:
   typedef mozilla::dom::EventHandlerNonNull EventHandlerNonNull;
   typedef mozilla::dom::OnBeforeUnloadEventHandlerNonNull
     OnBeforeUnloadEventHandlerNonNull;
   typedef mozilla::dom::OnErrorEventHandlerNonNull OnErrorEventHandlerNonNull;
@@ -167,32 +167,25 @@ private:
 //
 // Note, mTarget is a raw pointer and the owner of the nsIJSEventListener object
 // is expected to call Disconnect()!
 class nsIJSEventListener : public nsIDOMEventListener
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IJSEVENTLISTENER_IID)
 
-  nsIJSEventListener(nsIScriptContext* aContext, JSObject* aScopeObject,
+  nsIJSEventListener(JSObject* aScopeObject,
                      nsISupports *aTarget, nsIAtom* aType,
                      const nsEventHandler& aHandler)
-  : mContext(aContext), mScopeObject(aScopeObject), mEventName(aType),
-    mHandler(aHandler)
+  : mScopeObject(aScopeObject), mEventName(aType), mHandler(aHandler)
   {
     nsCOMPtr<nsISupports> base = do_QueryInterface(aTarget);
     mTarget = base.get();
   }
 
-  // Can return null if we already have a handler.
-  nsIScriptContext *GetEventContext() const
-  {
-    return mContext;
-  }
-
   nsISupports *GetEventTarget() const
   {
     return mTarget;
   }
 
   void Disconnect()
   {
     mTarget = nullptr;
@@ -221,21 +214,20 @@ public:
 
   nsIAtom* EventName() const
   {
     return mEventName;
   }
 
   // Set a handler for this event listener.  The handler must already
   // be bound to the right target.
-  void SetHandler(const nsEventHandler& aHandler, nsIScriptContext* aContext,
+  void SetHandler(const nsEventHandler& aHandler,
                   JS::Handle<JSObject*> aScopeObject)
   {
     mHandler.SetHandler(aHandler);
-    mContext = aContext;
     UpdateScopeObject(aScopeObject);
   }
   void SetHandler(mozilla::dom::EventHandlerNonNull* aHandler)
   {
     mHandler.SetHandler(aHandler);
   }
   void SetHandler(mozilla::dom::OnBeforeUnloadEventHandlerNonNull* aHandler)
   {
@@ -247,17 +239,16 @@ public:
   }
 
   virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
   {
     return 0;
 
     // Measurement of the following members may be added later if DMD finds it
     // is worthwhile:
-    // - mContext
     // - mTarget
     //
     // The following members are not measured:
     // - mScopeObject: because they're measured by the JS memory
     //   reporters
     // - mHandler: may be shared with others
     // - mEventName: shared with others
   }
@@ -272,26 +263,24 @@ protected:
   {
     NS_ASSERTION(!mTarget, "Should have called Disconnect()!");
   }
 
   // Update our mScopeObject; we have to make sure we properly handle
   // the hold/drop stuff, so have to do it in nsJSEventListener.
   virtual void UpdateScopeObject(JS::Handle<JSObject*> aScopeObject) = 0;
 
-  nsCOMPtr<nsIScriptContext> mContext;
   JS::Heap<JSObject*> mScopeObject;
   nsISupports* mTarget;
   nsCOMPtr<nsIAtom> mEventName;
   nsEventHandler mHandler;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIJSEventListener, NS_IJSEVENTLISTENER_IID)
 
 /* factory function.  aHandler must already be bound to aTarget.
    aContext is allowed to be null if aHandler is already set up.
  */
-nsresult NS_NewJSEventListener(nsIScriptContext *aContext,
-                               JSObject* aScopeObject, nsISupports* aTarget,
+nsresult NS_NewJSEventListener(JSObject* aScopeObject, nsISupports* aTarget,
                                nsIAtom* aType, const nsEventHandler& aHandler,
                                nsIJSEventListener **aReturn);
 
 #endif // nsIJSEventListener_h__
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -331,16 +331,27 @@ public:
   // window of that outer. Only call this on inner windows.
   bool IsCurrentInnerWindow() const
   {
     MOZ_ASSERT(IsInnerWindow(),
                "It doesn't make sense to call this on outer windows.");
     return mOuterWindow && mOuterWindow->GetCurrentInnerWindow() == this;
   }
 
+  // Returns true if the document of this window is the active document.  This
+  // is not identical to IsCurrentInnerWindow() because document.open() will
+  // keep the same document active but create a new window.
+  bool HasActiveDocument()
+  {
+    return IsCurrentInnerWindow() ||
+      (GetOuterWindow() &&
+       GetOuterWindow()->GetCurrentInnerWindow() &&
+       GetOuterWindow()->GetCurrentInnerWindow()->GetDoc() == mDoc);
+  }
+
   bool IsOuterWindow() const
   {
     return !IsInnerWindow();
   }
 
   virtual bool WouldReuseInnerWindow(nsIDocument *aNewDocument) = 0;
 
   /**
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -444,23 +444,16 @@ ReportGhostWindowsEnumerator(nsUint64Has
   if (NS_FAILED(rv) && NS_SUCCEEDED(data->rv)) {
     data->rv = rv;
   }
 
   return PL_DHASH_NEXT;
 }
 
 NS_IMETHODIMP
-nsWindowMemoryReporter::GetName(nsACString &aName)
-{
-  aName.AssignLiteral("window-objects");
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 nsWindowMemoryReporter::CollectReports(nsIMemoryReporterCallback* aCb,
                                        nsISupports* aClosure)
 {
   nsGlobalWindow::WindowByIdTable* windowsById =
     nsGlobalWindow::GetWindowsTable();
   NS_ENSURE_TRUE(windowsById, NS_OK);
 
   // Hold on to every window in memory so that window objects can't be
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -13,16 +13,17 @@ support-files =
 [test_document.all_unqualified.html]
 [test_domcursor.html]
 [test_domrequest.html]
 [test_e4x_for_each.html]
 [test_error.html]
 [test_gsp-qualified.html]
 [test_gsp-quirks.html]
 [test_gsp-standards.html]
+[test_history_document_open.html]
 [test_innersize_scrollport.html]
 [test_messageChannel.html]
 [test_messageChannel_cloning.html]
 [test_messageChannel_pingpong.html]
 [test_messageChannel_post.html]
 [test_messageChannel_pref.html]
 [test_messageChannel_start.html]
 [test_messageChannel_transferable.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_history_document_open.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=943418
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 943418</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for Bug 943418 **/
+  SimpleTest.waitForExplicitFinish();
+
+  function continueTest(f) {
+    // Make sure we're the entry script so errors get reported here
+    setTimeout(finishTest, 0, f);
+  }
+
+  function finishTest(f) {
+    f();
+    ok(true, "Got here");
+    SimpleTest.finish();
+  }
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=943418">Mozilla Bug 943418</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe src="data:text/html,<script>function f() { history.length; } window.onload = function() { var f = window.f; document.open(); document.close(); parent.continueTest(f); }</script>" </script>
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/dom/bindings/CallbackObject.cpp
+++ b/dom/bindings/CallbackObject.cpp
@@ -161,17 +161,17 @@ CallbackObject::CallSetup::ShouldRethrow
 }
 
 CallbackObject::CallSetup::~CallSetup()
 {
   // First things first: if we have a JSContext, report any pending
   // errors on it, unless we were told to re-throw them.
   if (mCx) {
     bool dealtWithPendingException = false;
-    if (mExceptionHandling == eRethrowContentExceptions ||
+    if ((mCompartment && mExceptionHandling == eRethrowContentExceptions) ||
         mExceptionHandling == eRethrowExceptions) {
       // Restore the old context options
       JS::ContextOptionsRef(mCx) = mSavedJSContextOptions;
       mErrorResult.MightThrowJSException();
       if (JS_IsExceptionPending(mCx)) {
         JS::Rooted<JS::Value> exn(mCx);
         if (JS_GetPendingException(mCx, &exn) &&
             ShouldRethrowException(exn)) {
--- a/dom/bluetooth/Makefile.in
+++ b/dom/bluetooth/Makefile.in
@@ -14,30 +14,22 @@
 
 VPATH += $(srcdir)/ipc
 
 ifneq (,$(MOZ_B2G_BT))
 
 ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 ifdef MOZ_B2G_BT_BLUEZ
 LOCAL_INCLUDES += $(MOZ_DBUS_CFLAGS)
-DEFINES += -DMOZ_B2G_BT_BLUEZ
-else
-ifdef MOZ_B2G_BT_BLUEDROID
-DEFINES += -DMOZ_B2G_BT_BLUEDROID
-endif #MOZ_B2G_BT_BLUEDROID
 endif #MOZ_B2G_BT_BLUEZ
 else
 ifdef MOZ_ENABLE_DBUS
 LOCAL_INCLUDES += $(MOZ_DBUS_CFLAGS)
 CFLAGS += $(MOZ_DBUS_GLIB_CFLAGS)
 CXXFLAGS += $(MOZ_DBUS_GLIB_CFLAGS) -DHAVE_PTHREADS
-DEFINES += -DMOZ_BLUETOOTH_DBUS
 endif #MOZ_ENABLE_DBUS
 endif #MOZ_WIDGET_TOOLKIT
 
 # Add VPATH to LOCAL_INCLUDES so we are going to include the correct backend
 # subdirectory.
 LOCAL_INCLUDES += $(VPATH:%=-I%)
 
 endif #MOZ_B2G_BT
-
-include $(topsrcdir)/config/rules.mk
--- a/dom/bluetooth/moz.build
+++ b/dom/bluetooth/moz.build
@@ -40,35 +40,38 @@ if CONFIG['MOZ_B2G_BT']:
                 'bluez/gonk/BluetoothGonkService.cpp',
                 'bluez/linux/BluetoothDBusService.cpp',
             ]
             LOCAL_INCLUDES += [
                 'bluez',
                 'bluez/gonk',
                 'bluez/linux',
             ]
+            DEFINES['MOZ_B2G_BT_BLUEZ'] = True
         elif CONFIG['MOZ_B2G_BT_BLUEDROID']:
             SOURCES += [
                 'bluedroid/BluetoothA2dpManager.cpp',
                 'bluedroid/BluetoothHfpManager.cpp',
                 'bluedroid/gonk/BluetoothServiceBluedroid.cpp',
             ]
             LOCAL_INCLUDES += [
                 'bluedroid',
                 'bluedroid/gonk',
             ]
+            DEFINES['MOZ_B2G_BT_BLUEDROID'] = True
     elif CONFIG['MOZ_ENABLE_DBUS']:
         SOURCES += [
             'bluez/BluetoothHfpManager.cpp',
             'bluez/linux/BluetoothDBusService.cpp',
         ]
         LOCAL_INCLUDES += [
             'bluez',
             'bluez/linux',
         ]
+        DEFINES['MOZ_BLUETOOTH_DBUS'] = True
 
     FINAL_LIBRARY = 'gklayout'
 
 EXPORTS.mozilla.dom.bluetooth.ipc += [
     'ipc/BluetoothMessageUtils.h',
 ]
 
 EXPORTS.mozilla.dom.bluetooth += [
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -38,17 +38,17 @@ interface nsIDOMFile;
 interface nsIFile;
 interface nsIDOMTouch;
 interface nsIDOMClientRect;
 interface nsIURI;
 interface nsIDOMEventTarget;
 interface nsIRunnable;
 interface nsICompositionStringSynthesizer;
 
-[scriptable, uuid(928356ff-26b2-434e-a7ce-c1a660162d81)]
+[scriptable, uuid(3772df78-905f-40cf-952f-e4954c63d0ec)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -648,16 +648,24 @@ interface nsIDOMWindowUtils : nsISupport
    * Returns the scroll position of the window's currently loaded document.
    *
    * @param aFlushLayout flushes layout if true. Otherwise, no flush occurs.
    * @see nsIDOMWindow::scrollX/Y
    */
   void getScrollXY(in boolean aFlushLayout, out long aScrollX, out long aScrollY);
 
   /**
+   * Returns the scroll position of the window's currently loaded document.
+   *
+   * @param aFlushLayout flushes layout if true. Otherwise, no flush occurs.
+   * @see nsIDOMWindow::scrollX/Y
+   */
+  void getScrollXYFloat(in boolean aFlushLayout, out float aScrollX, out float aScrollY);
+
+  /**
    * Sets the scroll position of the root scroll frame of the window.
    * Returns true on success, false on error (if the window didn't have a root
    * scroll frame).
    */
   boolean scrollToCSSPixelsApproximate(in float aX, in float aY);
 
   /**
    * Returns the scrollbar width of the window's scroll frame.
@@ -1039,17 +1047,17 @@ interface nsIDOMWindowUtils : nsISupport
   /**
    * True if the layer manager for the widget associated with this window is
    * forwarding layers to a remote compositor, false otherwise. Throws an
    * error if there is no widget associated with this window.
    */
   readonly attribute boolean layerManagerRemote;
 
   /**
-   * Record (and return) frame-intervals and paint-times for frames which were presented
+   * Record (and return) frame-intervals for frames which were presented
    *   between calling StartFrameTimeRecording and StopFrameTimeRecording.
    *
    * - Uses a cyclic buffer and serves concurrent consumers, so if Stop is called too late
    *     (elements were overwritten since Start), result is considered invalid and hence empty.
    * - Buffer is capable of holding 10 seconds @ 60fps (or more if frames were less frequent).
    *     Can be changed (up to 1 hour) via pref: toolkit.framesRecording.bufferSize.
    * - Note: the first frame-interval may be longer than expected because last frame
    *     might have been presented some time before calling StartFrameTimeRecording.
@@ -1061,17 +1069,16 @@ interface nsIDOMWindowUtils : nsISupport
    void startFrameTimeRecording([retval] out unsigned long startIndex);
 
   /**
    * Returns number of recorded frames since startIndex was issued,
    *   and allocates+populates 2 arraye with the recorded data.
    * - Allocation is infallible. Should be released even if size is 0.
    */
    void stopFrameTimeRecording(in unsigned long startIndex,
-                              [optional, array, size_is(frameCount)] out float paintTimes,
                               [optional] out unsigned long frameCount,
                               [retval, array, size_is(frameCount)] out float frameIntervals);
 
   /**
    * Signals that we're begining to tab switch. This is used by painting code to
    * determine total tab switch time.
    */
   void beginTabSwitch();
--- a/dom/ipc/Makefile.in
+++ b/dom/ipc/Makefile.in
@@ -1,21 +1,7 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 include $(topsrcdir)/config/rules.mk
 
-DEFINES += -DBIN_SUFFIX='"$(BIN_SUFFIX)"'
-
-ifeq ($(MOZ_WIDGET_TOOLKIT),$(findstring $(MOZ_WIDGET_TOOLKIT),android gtk2 gonk qt))
-DEFINES += -DMOZ_ENABLE_FREETYPE
-endif
-
-ifdef MOZ_PERMISSIONS
-DEFINES += -DMOZ_PERMISSIONS
-endif
-
-ifdef MOZ_CHILD_PERMISSIONS
-DEFINES += -DMOZ_CHILD_PERMISSIONS
-endif
-
 CXXFLAGS += $(TK_CFLAGS)
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -650,16 +650,18 @@ TabChild::HandlePossibleViewportChange()
     if (viewportInfo.GetDefaultZoom().scale < 0.01f) {
       viewportInfo.SetDefaultZoom(metrics.CalculateIntrinsicScale());
     }
 
     CSSToScreenScale defaultZoom = viewportInfo.GetDefaultZoom();
     MOZ_ASSERT(viewportInfo.GetMinZoom() <= defaultZoom &&
                defaultZoom <= viewportInfo.GetMaxZoom());
     metrics.mZoom = defaultZoom;
+
+    metrics.mScrollId = viewId;
   }
 
   metrics.mDisplayPort = AsyncPanZoomController::CalculatePendingDisplayPort(
     // The page must have been refreshed in some way such as a new document or
     // new CSS viewport, so we know that there's no velocity, acceleration, and
     // we have no idea how long painting will take.
     metrics, gfx::Point(0.0f, 0.0f), gfx::Point(0.0f, 0.0f), 0.0);
   metrics.mCumulativeResolution = metrics.mZoom / metrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
@@ -1554,78 +1556,71 @@ TabChild::RecvUpdateFrame(const FrameMet
 
 bool
 TabChild::ProcessUpdateFrame(const FrameMetrics& aFrameMetrics)
   {
     if (!mGlobal || !mTabChildGlobal) {
         return true;
     }
 
-    CSSRect cssCompositedRect = aFrameMetrics.CalculateCompositedRectInCssPixels();
+    nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
+
+    FrameMetrics newMetrics = aFrameMetrics;
+    APZCCallbackHelper::UpdateRootFrame(utils, newMetrics);
+
+    CSSRect cssCompositedRect = newMetrics.CalculateCompositedRectInCssPixels();
     // The BrowserElementScrolling helper must know about these updated metrics
     // for other functions it performs, such as double tap handling.
     // Note, %f must not be used because it is locale specific!
     nsCString data;
-    data.AppendPrintf("{ \"x\" : %d", NS_lround(aFrameMetrics.mScrollOffset.x));
-    data.AppendPrintf(", \"y\" : %d", NS_lround(aFrameMetrics.mScrollOffset.y));
+    data.AppendPrintf("{ \"x\" : %d", NS_lround(newMetrics.mScrollOffset.x));
+    data.AppendPrintf(", \"y\" : %d", NS_lround(newMetrics.mScrollOffset.y));
     data.AppendLiteral(", \"viewport\" : ");
         data.AppendLiteral("{ \"width\" : ");
-        data.AppendFloat(aFrameMetrics.mViewport.width);
+        data.AppendFloat(newMetrics.mViewport.width);
         data.AppendLiteral(", \"height\" : ");
-        data.AppendFloat(aFrameMetrics.mViewport.height);
+        data.AppendFloat(newMetrics.mViewport.height);
         data.AppendLiteral(" }");
     data.AppendLiteral(", \"displayPort\" : ");
         data.AppendLiteral("{ \"x\" : ");
-        data.AppendFloat(aFrameMetrics.mDisplayPort.x);
+        data.AppendFloat(newMetrics.mDisplayPort.x);
         data.AppendLiteral(", \"y\" : ");
-        data.AppendFloat(aFrameMetrics.mDisplayPort.y);
+        data.AppendFloat(newMetrics.mDisplayPort.y);
         data.AppendLiteral(", \"width\" : ");
-        data.AppendFloat(aFrameMetrics.mDisplayPort.width);
+        data.AppendFloat(newMetrics.mDisplayPort.width);
         data.AppendLiteral(", \"height\" : ");
-        data.AppendFloat(aFrameMetrics.mDisplayPort.height);
+        data.AppendFloat(newMetrics.mDisplayPort.height);
         data.AppendLiteral(" }");
     data.AppendLiteral(", \"compositionBounds\" : ");
-        data.AppendPrintf("{ \"x\" : %d", aFrameMetrics.mCompositionBounds.x);
-        data.AppendPrintf(", \"y\" : %d", aFrameMetrics.mCompositionBounds.y);
-        data.AppendPrintf(", \"width\" : %d", aFrameMetrics.mCompositionBounds.width);
-        data.AppendPrintf(", \"height\" : %d", aFrameMetrics.mCompositionBounds.height);
+        data.AppendPrintf("{ \"x\" : %d", newMetrics.mCompositionBounds.x);
+        data.AppendPrintf(", \"y\" : %d", newMetrics.mCompositionBounds.y);
+        data.AppendPrintf(", \"width\" : %d", newMetrics.mCompositionBounds.width);
+        data.AppendPrintf(", \"height\" : %d", newMetrics.mCompositionBounds.height);
         data.AppendLiteral(" }");
     data.AppendLiteral(", \"cssPageRect\" : ");
         data.AppendLiteral("{ \"x\" : ");
-        data.AppendFloat(aFrameMetrics.mScrollableRect.x);
+        data.AppendFloat(newMetrics.mScrollableRect.x);
         data.AppendLiteral(", \"y\" : ");
-        data.AppendFloat(aFrameMetrics.mScrollableRect.y);
+        data.AppendFloat(newMetrics.mScrollableRect.y);
         data.AppendLiteral(", \"width\" : ");
-        data.AppendFloat(aFrameMetrics.mScrollableRect.width);
+        data.AppendFloat(newMetrics.mScrollableRect.width);
         data.AppendLiteral(", \"height\" : ");
-        data.AppendFloat(aFrameMetrics.mScrollableRect.height);
+        data.AppendFloat(newMetrics.mScrollableRect.height);
         data.AppendLiteral(" }");
     data.AppendLiteral(", \"cssCompositedRect\" : ");
         data.AppendLiteral("{ \"width\" : ");
         data.AppendFloat(cssCompositedRect.width);
         data.AppendLiteral(", \"height\" : ");
         data.AppendFloat(cssCompositedRect.height);
         data.AppendLiteral(" }");
     data.AppendLiteral(" }");
 
     DispatchMessageManagerMessage(NS_LITERAL_STRING("Viewport:Change"), data);
 
-    nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
-
-    APZCCallbackHelper::UpdateRootFrame(utils, aFrameMetrics);
-
-    mLastMetrics = aFrameMetrics;
-
-    // ScrollWindowTo() can make some small adjustments to the offset before
-    // actually scrolling the window. To ensure that the scroll offset stored
-    // in mLastMetrics is the same as the offset stored in the window,
-    // re-query the latter.
-    CSSIntPoint actualScrollOffset;
-    utils->GetScrollXY(false, &actualScrollOffset.x, &actualScrollOffset.y);
-    mLastMetrics.mScrollOffset = actualScrollOffset;
+    mLastMetrics = newMetrics;
 
     return true;
 }
 
 bool
 TabChild::RecvHandleDoubleTap(const CSSIntPoint& aPoint)
 {
     if (!mGlobal || !mTabChildGlobal) {
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -103,8 +103,16 @@ LOCAL_INCLUDES += [
     '/layout/base',
     '/netwerk/base/src',
     '/toolkit/xre',
     '/uriloader/exthandler',
     '/widget/xpwidgets',
     '/xpcom/base',
 ]
 
+DEFINES['BIN_SUFFIX'] = '"%s"' % CONFIG['BIN_SUFFIX']
+
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk2', 'gonk', 'qt'):
+    DEFINES['MOZ_ENABLE_FREETYPE'] = True
+
+for var in ('MOZ_PERMISSIONS', 'MOZ_CHILD_PERMISSIONS'):
+    if CONFIG[var]:
+        DEFINES[var] = True
--- a/dom/locales/en-US/chrome/layout/css.properties
+++ b/dom/locales/en-US/chrome/layout/css.properties
@@ -61,28 +61,29 @@ PEAttSelNoClose=Expected ']' to terminat
 PEAttSelBadValue=Expected identifier or string for value in attribute selector but found '%1$S'.
 PEPseudoSelEOF=name of pseudo-class or pseudo-element
 PEPseudoSelBadName=Expected identifier for pseudo-class or pseudo-element but found '%1$S'.
 PEPseudoSelNonFunc=Function token for non-function pseudo-class or pseudo-element, or the other way around, when reading '%1$S'.
 PEPseudoSelNotPE=Expected pseudo-element but found '%1$S'.
 PEPseudoSelDoubleNot=Negation pseudo-class can't be negated '%1$S'.
 PEPseudoSelPEInNot=Pseudo-elements can't be negated '%1$S'.
 PEPseudoSelNewStyleOnly=This pseudo-element must use the "::" form: '%1$S'.
-PEPseudoSelTrailing=Found trailing token after pseudo-element, which must be the last part of a selector:  '%1$S'.
+PEPseudoSelTrailing=Expected end of selector or a user action pseudo-class after pseudo-element but found '%1$S'.
 PEPseudoSelMultiplePE=Extra pseudo-element '%1$S'.
 PEPseudoSelUnknown=Unknown pseudo-class or pseudo-element '%1$S'.
 PENegationEOF=selector within negation
 PENegationBadInner=Malformed simple selector as negation pseudo-class argument '%1$S'.
 PENegationNoClose=Missing closing ')' in negation pseudo-class '%1$S'.
 PENegationBadArg=Missing argument in negation pseudo-class '%1$S'.
 PEPseudoClassArgEOF=argument to pseudo-class selector
 PEPseudoClassArgNotIdent=Expected identifier for pseudo-class parameter but found '%1$S'.
 PEPseudoClassArgNotNth=Expected part of argument to pseudo-class but found '%1$S'.
 PEPseudoClassNoClose=Missing closing ')' in pseudo-class, found '%1$S' instead.
 PEPseudoClassNoArg=Missing argument in pseudo-class '%1$S'.
+PEPseudoClassNotUserAction=Expected end of selector or a user action pseudo-class after pseudo-element but found pseudo-class '%1$S'.
 PESelectorEOF=selector
 PEBadDeclBlockStart=Expected '{' to begin declaration block but found '%1$S'.
 PEColorEOF=color
 PEColorNotColor=Expected color but found '%1$S'.
 PEColorComponentEOF=color component
 PEExpectedPercent=Expected a percentage but found '%1$S'.
 PEExpectedInt=Expected an integer but found '%1$S'.
 PEColorBadRGBContents=Expected number or percentage in rgb() but found '%1$S'.
--- a/dom/plugins/ipc/hangui/Makefile.in
+++ b/dom/plugins/ipc/hangui/Makefile.in
@@ -1,20 +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/.
 
 OS_LIBS = $(call EXPAND_LIBNAME,comctl32)
 
 RCINCLUDE = HangUIDlg.rc
 
-DEFINES += \
-  -DNS_NO_XPCOM \
-  $(NULL)
-
 STL_FLAGS = \
   -D_HAS_EXCEPTIONS=0 \
   $(NULL)
 
 MOZ_GLUE_LDFLAGS =
 
 include $(topsrcdir)/config/rules.mk
 
--- a/dom/plugins/ipc/hangui/moz.build
+++ b/dom/plugins/ipc/hangui/moz.build
@@ -9,8 +9,9 @@ FAIL_ON_WARNINGS = True
 PROGRAM = 'plugin-hang-ui'
 
 UNIFIED_SOURCES += [
     'MiniShmChild.cpp',
     'PluginHangUIChild.cpp',
 ]
 include('/ipc/chromium/chromium-config.mozbuild')
 
+DEFINES['NS_NO_XPCOM'] = True
--- a/dom/src/events/nsJSEventListener.cpp
+++ b/dom/src/events/nsJSEventListener.cpp
@@ -37,22 +37,21 @@ static EventListenerCounter sEventListen
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 /*
  * nsJSEventListener implementation
  */
-nsJSEventListener::nsJSEventListener(nsIScriptContext *aContext,
-                                     JSObject* aScopeObject,
+nsJSEventListener::nsJSEventListener(JSObject* aScopeObject,
                                      nsISupports *aTarget,
                                      nsIAtom* aType,
                                      const nsEventHandler& aHandler)
-  : nsIJSEventListener(aContext, aScopeObject, aTarget, aType, aHandler)
+  : nsIJSEventListener(aScopeObject, aTarget, aType, aHandler)
 {
   if (mScopeObject) {
     mozilla::HoldJSObjects(this);
   }
 }
 
 nsJSEventListener::~nsJSEventListener() 
 {
@@ -76,31 +75,29 @@ nsJSEventListener::UpdateScopeObject(JS:
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSEventListener)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSEventListener)
   if (tmp->mScopeObject) {
     tmp->mScopeObject = nullptr;
     mozilla::DropJSObjects(tmp);
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
   }
   tmp->mHandler.ForgetHandler();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSEventListener)
   if (MOZ_UNLIKELY(cb.WantDebugInfo()) && tmp->mEventName) {
     nsAutoCString name;
     name.AppendLiteral("nsJSEventListener handlerName=");
     name.Append(
       NS_ConvertUTF16toUTF8(nsDependentAtomString(tmp->mEventName)).get());
     cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name.get());
   } else {
     NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsJSEventListener, tmp->mRefCnt.get())
   }
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mHandler.Ptr())
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSEventListener)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScopeObject)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
@@ -143,23 +140,17 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSEve
 bool
 nsJSEventListener::IsBlackForCC()
 {
   // We can claim to be black if all the things we reference are
   // effectively black already.
   if ((!mScopeObject || !xpc_IsGrayGCThing(mScopeObject)) &&
       (!mHandler.HasEventHandler() ||
        !mHandler.Ptr()->HasGrayCallable())) {
-    if (!mContext) {
-      // Well, we certainly won't be marking it, so move on!
-      return true;
-    }
-    nsIScriptGlobalObject* sgo =
-      static_cast<nsJSContext*>(mContext.get())->GetCachedGlobalObject();
-    return sgo && sgo->IsBlackForCC();
+    return true;
   }
   return false;
 }
 
 nsresult
 nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
 {
   nsCOMPtr<EventTarget> target = do_QueryInterface(mTarget);
@@ -259,23 +250,20 @@ nsJSEventListener::HandleEvent(nsIDOMEve
   return NS_OK;
 }
 
 /*
  * Factory functions
  */
 
 nsresult
-NS_NewJSEventListener(nsIScriptContext* aContext, JSObject* aScopeObject,
+NS_NewJSEventListener(JSObject* aScopeObject,
                       nsISupports*aTarget, nsIAtom* aEventType,
                       const nsEventHandler& aHandler,
                       nsIJSEventListener** aReturn)
 {
-  MOZ_ASSERT(aContext || aHandler.HasEventHandler(),
-             "Must have a handler if we don't have an nsIScriptContext");
   NS_ENSURE_ARG(aEventType || !NS_IsMainThread());
   nsJSEventListener* it =
-    new nsJSEventListener(aContext, aScopeObject, aTarget, aEventType,
-                          aHandler);
+    new nsJSEventListener(aScopeObject, aTarget, aEventType, aHandler);
   NS_ADDREF(*aReturn = it);
 
   return NS_OK;
 }
--- a/dom/src/events/nsJSEventListener.h
+++ b/dom/src/events/nsJSEventListener.h
@@ -16,19 +16,18 @@
 #include "nsIScriptContext.h"
 #include "nsCycleCollectionParticipant.h"
 
 // nsJSEventListener interface
 // misnamed - JS no longer has exclusive rights over this interface!
 class nsJSEventListener : public nsIJSEventListener
 {
 public:
-  nsJSEventListener(nsIScriptContext* aContext, JSObject* aScopeObject,
-                    nsISupports* aTarget, nsIAtom* aType,
-                    const nsEventHandler& aHandler);
+  nsJSEventListener(JSObject* aScopeObject, nsISupports* aTarget,
+                    nsIAtom* aType, const nsEventHandler& aHandler);
   virtual ~nsJSEventListener();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   // nsIDOMEventListener interface
   NS_DECL_NSIDOMEVENTLISTENER
 
   // nsIJSEventListener
--- a/dom/tests/mochitest/dom-level1-core/test_nodeappendchildchildexists.html
+++ b/dom/tests/mochitest/dom-level1-core/test_nodeappendchildchildexists.html
@@ -69,17 +69,16 @@ function loadComplete() {
   }
 }
 
 var docName = 'nodeappendchildchildexists';
 
 
 
 window.doc = window;  
-SimpleTest.expectAssertions(1); // Bug 892638
 SimpleTest.waitForExplicitFinish();
 addLoadEvent(setUpPage);
 
 
 /**
 * 
     If the "newChild" is already in the tree, it is first
     removed before the new one is appended.
--- a/dom/tests/mochitest/dom-level1-core/test_nodeinsertbeforenewchildexists.html
+++ b/dom/tests/mochitest/dom-level1-core/test_nodeinsertbeforenewchildexists.html
@@ -69,17 +69,16 @@ function loadComplete() {
   }
 }
 
 var docName = 'nodeinsertbeforenewchildexists';
 
 
 
 window.doc = window;  
-SimpleTest.expectAssertions(1); // Bug 892638
 SimpleTest.waitForExplicitFinish();
 addLoadEvent(setUpPage);
 
 
 /**
 * 
     If the "newChild" is already in the tree, the
     "insertBefore(newChild,refChild)" method must first
--- a/dom/tests/mochitest/dom-level1-core/test_nodereplacechildnewchildexists.html
+++ b/dom/tests/mochitest/dom-level1-core/test_nodereplacechildnewchildexists.html
@@ -69,17 +69,16 @@ function loadComplete() {
   }
 }
 
 var docName = 'nodereplacechildnewchildexists';
 
 
 
 window.doc = window;  
-SimpleTest.expectAssertions(1); // Bug 892638
 SimpleTest.waitForExplicitFinish();
 addLoadEvent(setUpPage);
 
 
 /**
 * 
     Retrieve the second employee and replace its TWELFTH 
     child(address) with its SECOND child(employeeId).   After the
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -15,20 +15,37 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 766694 **/
 
-// This is a list of all interfaces that are exposed to every webpage.  Please only
-// add things to this list with great care.
+// This is a list of all interfaces that are exposed to every webpage.
+// Please only add things to this list with great care and proper review
+// from the associated module peers.
 
-// IMPORTANT: Do not change this list without review from a JavaScript Engine peer!
+// This file lists global interfaces we want exposed and verifies they
+// are what we intend. Each entry in the arrays below can either be a
+// simple string with the interface name, or an object with a 'name'
+// property giving the interface name as a string, and additional
+// properties which quality the exposure of that interface. For example:
+//
+// [
+//   "AGlobalInterface",
+//   {name: "ExperimentalThing", release: false},
+//   {name: "OptionalThing", pref: "some.thing.enabled"},
+//   {name: "FancyControl", xbl: true},
+// ];
+//
+// See createInterfaceMap() below for a complete list of properties.
+
+// IMPORTANT: Do not change this list without review from
+//            a JavaScript Engine peer!
 var ecmaGlobals =
   [
     "Array",
     "ArrayBuffer",
     "Boolean",
     "DataView",
     "Date",
     "Error",
@@ -65,36 +82,37 @@ var ecmaGlobals =
     "TypeError",
     "Uint16Array",
     "Uint32Array",
     "Uint8Array",
     "Uint8ClampedArray",
     "URIError",
     "WeakMap",
   ];
-// IMPORTANT: Do not change this list without review from a JavaScript Engine peer!
+// IMPORTANT: Do not change the list above without review from
+//            a JavaScript Engine peer!
 
-// IMPORTANT: Do not change this list without review from a DOM peer, except to
-//            remove items from it!
+// IMPORTANT: Do not change the list below without review from a DOM peer,
+//            except to remove items from it!
 //
 // This is a list of interfaces that were prefixed with 'moz' instead of 'Moz'.
 // We should never to that again, interfaces in the DOM start with an uppercase
 // letter. If you think you need to add an interface here, DON'T. Rename your
 // interface.
 var legacyMozPrefixedInterfaces =
   [
     "mozContact",
     "mozRTCIceCandidate",
     "mozRTCPeerConnection",
     "mozRTCSessionDescription",
   ];
-// IMPORTANT: Do not change this list without review from a DOM peer, except to
-//            remove items from it!
+// IMPORTANT: Do not change the list above without review from a DOM peer,
+//            except to remove items from it!
 
-// IMPORTANT: Do not change this list without review from a DOM peer!
+// IMPORTANT: Do not change the list below without review from a DOM peer!
 var interfaceNamesInGlobalScope =
   [
     "AnalyserNode",
     "AnimationEvent",
     "ArchiveRequest",
     "Attr",
     "Audio",
     "AudioBuffer",
@@ -625,18 +643,18 @@ var interfaceNamesInGlobalScope =
     {name: "XULControlElement", xbl: true},
     {name: "XULControllers", xbl: true},
     {name: "XULDocument", xbl: true},
     {name: "XULElement", xbl: true},
     {name: "XULLabeledControlElement", xbl: true},
     {name: "XULPopupElement", xbl: true},
     {name: "XULTemplateBuilder", xbl: true},
     {name: "XULTreeBuilder", xbl: true},
-  ]
-// IMPORTANT: Do not change this list without review from a DOM peer!
+  ];
+// IMPORTANT: Do not change the list above without review from a DOM peer!
 
 function createInterfaceMap(isXBLScope) {
   var prefs = SpecialPowers.Services.prefs;
   var version = SpecialPowers.Cc["@mozilla.org/xre/app-info;1"].getService(SpecialPowers.Ci.nsIXULAppInfo).version;
   var isNightly = version.endsWith("a1");
   var isRelease = !version.contains("a");
   var isDesktop = !/Mobile|Tablet/.test(navigator.userAgent);
   var isB2G = !isDesktop && !navigator.userAgent.contains("Android");
--- a/dom/workers/Principal.cpp
+++ b/dom/workers/Principal.cpp
@@ -4,26 +4,25 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Principal.h"
 
 #include "jsapi.h"
 
 BEGIN_WORKERS_NAMESPACE
 
-namespace {
-
-JSPrincipals gPrincipal = {
-  1
-#ifdef DEBUG
-  , kJSPrincipalsDebugToken
-#endif
-};
-
-} // anonymous namespace
-
 JSPrincipals*
 GetWorkerPrincipal()
 {
-  return &gPrincipal;
+  static Atomic<uint32_t> sInitialized(0);
+  static JSPrincipals sPrincipal;
+
+  uint32_t isInitialized = sInitialized.exchange(1);
+  if (!isInitialized) {
+    sPrincipal.refcount = 1;
+#ifdef DEBUG
+    sPrincipal.debugToken = kJSPrincipalsDebugToken;
+#endif
+  }
+  return &sPrincipal;
 }
 
 END_WORKERS_NAMESPACE
--- a/embedding/tests/winEmbed/Makefile.in
+++ b/embedding/tests/winEmbed/Makefile.in
@@ -29,17 +29,16 @@
 
 RESFILE		= winEmbed.res
 
 LIBS = \
 	$(DEPTH)/profile/dirserviceprovider/standalone/$(LIB_PREFIX)profdirserviceprovidersa_s.$(LIB_SUFFIX) \
 	$(XPCOM_STANDALONE_GLUE_LDOPTS) \
 	$(NULL)
 
-DEFINES += -DXPCOM_GLUE
 STL_FLAGS=
 
 OS_LIBS		+= $(call EXPAND_LIBNAME,ole32 comdlg32 shell32 version)
 
 include $(topsrcdir)/config/rules.mk
 
 #
 # Control the default heap size.
--- a/embedding/tests/winEmbed/moz.build
+++ b/embedding/tests/winEmbed/moz.build
@@ -8,8 +8,10 @@ PROGRAM = 'winEmbed'
 
 SOURCES += [
     'WebBrowserChrome.cpp',
     'WindowCreator.cpp',
     'winEmbed.cpp',
 ]
 
 XPI_NAME = 'winembed'
+
+DEFINES['XPCOM_GLUE'] = True
--- a/extensions/spellcheck/hunspell/src/Makefile.in
+++ b/extensions/spellcheck/hunspell/src/Makefile.in
@@ -1,18 +1,12 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-ifndef MOZ_NATIVE_HUNSPELL
-# This variable is referenced in configure.in.  Make sure to change that file
-# too if you need to change this variable.
-DEFINES = -DHUNSPELL_STATIC
-endif
-
 include $(topsrcdir)/config/rules.mk
 
 INCLUDES        += -I$(topsrcdir)/extensions/spellcheck/src
 
 ifdef MOZ_NATIVE_HUNSPELL
 # MOZ_HUNSPELL_CFLAGS is extracted through pkgconfig during configure,
 # even though the variable doesn't show up in configure.in.
 CXXFLAGS += $(MOZ_HUNSPELL_CFLAGS)
--- a/extensions/spellcheck/hunspell/src/moz.build
+++ b/extensions/spellcheck/hunspell/src/moz.build
@@ -18,10 +18,13 @@ if not CONFIG['MOZ_NATIVE_HUNSPELL']:
         'filemgr.cpp',
         'hashmgr.cpp',
         'hunspell.cpp',
         'hunzip.cpp',
         'phonet.cpp',
         'replist.cpp',
         'suggestmgr.cpp',
     ]
+    # This variable is referenced in configure.in.  Make sure to change that file
+    # too if you need to change this variable.
+    DEFINES['HUNSPELL_STATIC'] = True
 
 FINAL_LIBRARY = 'spellchecker'
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -48,16 +48,17 @@ typedef struct CGContext *CGContextRef;
 namespace mozilla {
 
 namespace gfx {
 
 class SourceSurface;
 class DataSourceSurface;
 class DrawTarget;
 class DrawEventRecorder;
+class FilterNode;
 
 struct NativeSurface {
   NativeSurfaceType mType;
   SurfaceFormat mFormat;
   void *mSurface;
 };
 
 struct NativeFont {
@@ -351,17 +352,21 @@ public:
   virtual int32_t Stride() = 0;
 
   /*
    * This function is called after modifying the data on the source surface
    * directly through the data pointer.
    */
   virtual void MarkDirty() {}
 
-  virtual TemporaryRef<DataSourceSurface> GetDataSurface() { RefPtr<DataSourceSurface> temp = this; return temp.forget(); }
+  /*
+   * Returns a DataSourceSurface with the same data as this one, but
+   * guaranteed to have surface->GetType() == SURFACE_DATA.
+   */
+  virtual TemporaryRef<DataSourceSurface> GetDataSurface();
 };
 
 /* This is an abstract object that accepts path segments. */
 class PathSink : public RefCounted<PathSink>
 {
 public:
   virtual ~PathSink() {}
 
@@ -614,16 +619,29 @@ public:
    */
   virtual void DrawSurface(SourceSurface *aSurface,
                            const Rect &aDest,
                            const Rect &aSource,
                            const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(),
                            const DrawOptions &aOptions = DrawOptions()) = 0;
 
   /*
+   * Draw the output of a FilterNode to the DrawTarget.
+   *
+   * aNode FilterNode to draw
+   * aSourceRect Source rectangle in FilterNode space to draw
+   * aDestPoint Destination point on the DrawTarget to draw the
+   *            SourceRectangle of the filter output to
+   */
+  virtual void DrawFilter(FilterNode *aNode,
+                          const Rect &aSourceRect,
+                          const Point &aDestPoint,
+                          const DrawOptions &aOptions = DrawOptions()) = 0;
+
+  /*
    * Blend a surface to the draw target with a shadow. The shadow is drawn as a
    * gaussian blur using a specified sigma. The shadow is clipped to the size
    * of the input surface, so the input surface should contain a transparent
    * border the size of the approximate coverage of the blur (3 * aSigma).
    * NOTE: This function works in device space!
    *
    * aSurface Source surface to draw.
    * aDest Destination point that this drawing operation should draw to.
@@ -857,16 +875,24 @@ public:
    * aExtendNone This describes how to extend the stop color outside of the
    *             gradient area.
    */
   virtual TemporaryRef<GradientStops>
     CreateGradientStops(GradientStop *aStops,
                         uint32_t aNumStops,
                         ExtendMode aExtendMode = EXTEND_CLAMP) const = 0;
 
+  /*
+   * Create a FilterNode object that can be used to apply a filter to various
+   * inputs.
+   *
+   * aType Type of filter node to be created.
+   */
+  virtual TemporaryRef<FilterNode> CreateFilter(FilterType aType) = 0;
+
   const Matrix &GetTransform() const { return mTransform; }
 
   /*
    * Set a transform on the surface, this transform is applied at drawing time
    * to both the mask and source of the operation.
    */
   virtual void SetTransform(const Matrix &aTransform)
     { mTransform = aTransform; mTransformDirty = true; }
--- a/gfx/2d/Blur.cpp
+++ b/gfx/2d/Blur.cpp
@@ -388,21 +388,22 @@ AlphaBoxBlur::AlphaBoxBlur(const Rect& a
     if (size.isValid()) {
       mSurfaceAllocationSize = size.value();
     }
   }
 }
 
 AlphaBoxBlur::AlphaBoxBlur(const Rect& aRect,
                            int32_t aStride,
-                           float aSigma)
+                           float aSigmaX,
+                           float aSigmaY)
   : mRect(int32_t(aRect.x), int32_t(aRect.y),
           int32_t(aRect.width), int32_t(aRect.height)),
     mSpreadRadius(),
-    mBlurRadius(CalculateBlurRadius(Point(aSigma, aSigma))),
+    mBlurRadius(CalculateBlurRadius(Point(aSigmaX, aSigmaY))),
     mStride(aStride),
     mSurfaceAllocationSize(-1)
 {
   IntRect intRect;
   if (aRect.ToIntRect(&intRect)) {
     CheckedInt<int32_t> minDataSize = CheckedInt<int32_t>(intRect.width)*intRect.height;
     if (minDataSize.isValid()) {
       mSurfaceAllocationSize = minDataSize.value();
--- a/gfx/2d/Blur.h
+++ b/gfx/2d/Blur.h
@@ -61,17 +61,18 @@ public:
   AlphaBoxBlur(const Rect& aRect,
                const IntSize& aSpreadRadius,
                const IntSize& aBlurRadius,
                const Rect* aDirtyRect,
                const Rect* aSkipRect);
 
   AlphaBoxBlur(const Rect& aRect,
                int32_t aStride,
-               float aSigma);
+               float aSigmaX,
+               float aSigmaY);
 
   ~AlphaBoxBlur();
 
   /**
    * Return the size, in pixels, of the 8-bit alpha surface we'd use.
    */
   IntSize GetSize();
 
new file mode 100644
--- /dev/null
+++ b/gfx/2d/DataSourceSurface.cpp
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "2D.h"
+#include "DataSourceSurfaceWrapper.h"
+
+namespace mozilla {
+namespace gfx {
+
+TemporaryRef<DataSourceSurface>
+DataSourceSurface::GetDataSurface()
+{
+  RefPtr<DataSourceSurface> temp;
+  if (GetType() == SURFACE_DATA) {
+    temp = this;
+  } else {
+    temp = new DataSourceSurfaceWrapper(this);
+  }
+  return temp;
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/gfx/2d/DataSourceSurfaceWrapper.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_GFX_DATASOURCESURFACEWRAPPER_H_
+#define MOZILLA_GFX_DATASOURCESURFACEWRAPPER_H_
+
+#include "2D.h"
+
+namespace mozilla {
+namespace gfx {
+
+// Wraps a DataSourceSurface and forwards all methods except for GetType(),
+// from which it always returns SURFACE_DATA.
+class DataSourceSurfaceWrapper : public DataSourceSurface
+{
+public:
+  DataSourceSurfaceWrapper(DataSourceSurface *aSurface)
+   : mSurface(aSurface)
+  {}
+
+  virtual SurfaceType GetType() const MOZ_OVERRIDE { return SURFACE_DATA; }
+
+  virtual uint8_t *GetData() MOZ_OVERRIDE { return mSurface->GetData(); }
+  virtual int32_t Stride() MOZ_OVERRIDE { return mSurface->Stride(); }
+  virtual IntSize GetSize() const MOZ_OVERRIDE { return mSurface->GetSize(); }
+  virtual SurfaceFormat GetFormat() const MOZ_OVERRIDE { return mSurface->GetFormat(); }
+  virtual bool IsValid() const MOZ_OVERRIDE { return mSurface->IsValid(); }
+  virtual void MarkDirty() { mSurface->MarkDirty(); }
+
+private:
+  RefPtr<DataSourceSurface> mSurface;
+};
+
+}
+}
+
+#endif /* MOZILLA_GFX_DATASOURCESURFACEWRAPPER_H_ */
--- a/gfx/2d/DrawTargetCG.cpp
+++ b/gfx/2d/DrawTargetCG.cpp
@@ -6,16 +6,17 @@
 #include "DrawTargetCG.h"
 #include "SourceSurfaceCG.h"
 #include "Rect.h"
 #include "ScaledFontMac.h"
 #include "Tools.h"
 #include <vector>
 #include <algorithm>
 #include "MacIOSurface.h"
+#include "FilterNodeSoftware.h"
 
 using namespace std;
 
 //CG_EXTERN void CGContextSetCompositeOperation (CGContextRef, PrivateCGCompositeMode);
 
 // A private API that Cairo has been using for a long time
 CG_EXTERN void CGContextSetCTM(CGContextRef, CGAffineTransform);
 
@@ -203,26 +204,34 @@ DrawTargetCG::CreateSourceSurfaceFromDat
 
  if (!newSurf->InitFromData(aData, aSize, aStride, aFormat)) {
     return nullptr;
   }
 
   return newSurf;
 }
 
+// This function returns a retained CGImage that needs to be released after
+// use. The reason for this is that we want to either reuse an existing CGImage
+// or create a new one.
 static CGImageRef
-GetImageFromSourceSurface(SourceSurface *aSurface)
+GetRetainedImageFromSourceSurface(SourceSurface *aSurface)
 {
   if (aSurface->GetType() == SURFACE_COREGRAPHICS_IMAGE)
-    return static_cast<SourceSurfaceCG*>(aSurface)->GetImage();
+    return CGImageRetain(static_cast<SourceSurfaceCG*>(aSurface)->GetImage());
   else if (aSurface->GetType() == SURFACE_COREGRAPHICS_CGCONTEXT)
-    return static_cast<SourceSurfaceCGContext*>(aSurface)->GetImage();
-  else if (aSurface->GetType() == SURFACE_DATA)
-    return static_cast<DataSourceSurfaceCG*>(aSurface)->GetImage();
-  abort();
+    return CGImageRetain(static_cast<SourceSurfaceCGContext*>(aSurface)->GetImage());
+
+  if (aSurface->GetType() == SURFACE_DATA) {
+    DataSourceSurface* dataSource = static_cast<DataSourceSurface*>(aSurface);
+    return CreateCGImage(nullptr, dataSource->GetData(), dataSource->GetSize(),
+                         dataSource->Stride(), dataSource->GetFormat());
+  }
+
+  MOZ_CRASH("unsupported source surface");
 }
 
 TemporaryRef<SourceSurface>
 DrawTargetCG::OptimizeSourceSurface(SourceSurface *aSurface) const
 {
   return nullptr;
 }
 
@@ -274,52 +283,65 @@ void
 DrawTargetCG::DrawSurface(SourceSurface *aSurface,
                            const Rect &aDest,
                            const Rect &aSource,
                            const DrawSurfaceOptions &aSurfOptions,
                            const DrawOptions &aDrawOptions)
 {
   MarkChanged();
 
-  CGImageRef image;
-  CGImageRef subimage = nullptr;
   CGContextSaveGState(mCg);
 
   CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp));
   UnboundnessFixer fixer;
   CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp);
   CGContextSetAlpha(cg, aDrawOptions.mAlpha);
   CGContextSetShouldAntialias(cg, aDrawOptions.mAntialiasMode != AA_NONE);
 
   CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform));
-  image = GetImageFromSourceSurface(aSurface);
+  CGImageRef image = GetRetainedImageFromSourceSurface(aSurface);
+
   /* we have two options here:
    *  - create a subimage -- this is slower
    *  - fancy things with clip and different dest rects */
-  {
-    subimage = CGImageCreateWithImageInRect(image, RectToCGRect(aSource));
-    image = subimage;
-  }
+  CGImageRef subimage = CGImageCreateWithImageInRect(image, RectToCGRect(aSource));
+  CGImageRelease(image);
 
   CGContextScaleCTM(cg, 1, -1);
 
   CGRect flippedRect = CGRectMake(aDest.x, -(aDest.y + aDest.height),
                                   aDest.width, aDest.height);
 
   CGContextSetInterpolationQuality(cg, InterpolationQualityFromFilter(aSurfOptions.mFilter));
 
-  CGContextDrawImage(cg, flippedRect, image);
+  CGContextDrawImage(cg, flippedRect, subimage);
 
   fixer.Fix(mCg);
 
   CGContextRestoreGState(mCg);
 
   CGImageRelease(subimage);
 }
 
+TemporaryRef<FilterNode>
+DrawTargetCG::CreateFilter(FilterType aType)
+{
+  return FilterNodeSoftware::Create(aType);
+}
+
+void
+DrawTargetCG::DrawFilter(FilterNode *aNode,
+                         const Rect &aSourceRect,
+                         const Point &aDestPoint,
+                         const DrawOptions &aOptions)
+{
+  FilterNodeSoftware* filter = static_cast<FilterNodeSoftware*>(aNode);
+  filter->Draw(this, aSourceRect, aDestPoint, aOptions);
+}
+
 static CGColorRef ColorToCGColor(CGColorSpaceRef aColorSpace, const Color& aColor)
 {
   CGFloat components[4] = {aColor.r, aColor.g, aColor.b, aColor.a};
   return CGColorCreate(aColorSpace, components);
 }
 
 class GradientStopsCG : public GradientStops
 {
@@ -654,17 +676,17 @@ isGradient(const Pattern &aPattern)
 
 /* CoreGraphics patterns ignore the userspace transform so
  * we need to multiply it in */
 static CGPatternRef
 CreateCGPattern(const Pattern &aPattern, CGAffineTransform aUserSpace)
 {
   const SurfacePattern& pat = static_cast<const SurfacePattern&>(aPattern);
   // XXX: is .get correct here?
-  CGImageRef image = GetImageFromSourceSurface(pat.mSurface.get());
+  CGImageRef image = GetRetainedImageFromSourceSurface(pat.mSurface.get());
   CGFloat xStep, yStep;
   switch (pat.mExtendMode) {
     case EXTEND_CLAMP:
       // The 1 << 22 comes from Webkit see Pattern::createPlatformPattern() in PatternCG.cpp for more info
       xStep = static_cast<CGFloat>(1 << 22);
       yStep = static_cast<CGFloat>(1 << 22);
       break;
     case EXTEND_REFLECT:
@@ -691,17 +713,17 @@ CreateCGPattern(const Pattern &aPattern,
     {static_cast<CGFloat>(CGImageGetWidth(image)), static_cast<CGFloat>(CGImageGetHeight(image))}
   };
   CGAffineTransform transform =
       CGAffineTransformConcat(CGAffineTransformConcat(CGAffineTransformMakeScale(1,
                                                                                  -1),
                                                       GfxMatrixToCGAffineTransform(pat.mMatrix)),
                               aUserSpace);
   transform = CGAffineTransformTranslate(transform, 0, -static_cast<float>(CGImageGetHeight(image)));
-  return CGPatternCreate(CGImageRetain(image), bounds, transform, xStep, yStep, kCGPatternTilingConstantSpacing,
+  return CGPatternCreate(image, bounds, transform, xStep, yStep, kCGPatternTilingConstantSpacing,
                          true, &patternCallbacks);
 }
 
 static void
 SetFillFromPattern(CGContextRef cg, CGColorSpaceRef aColorSpace, const Pattern &aPattern)
 {
   assert(!isGradient(aPattern));
   if (aPattern.GetType() == PATTERN_COLOR) {
@@ -756,27 +778,26 @@ SetStrokeFromPattern(CGContextRef cg, CG
 void
 DrawTargetCG::MaskSurface(const Pattern &aSource,
                           SourceSurface *aMask,
                           Point aOffset,
                           const DrawOptions &aDrawOptions)
 {
   MarkChanged();
 
-  CGImageRef image;
   CGContextSaveGState(mCg);
 
   CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp));
   UnboundnessFixer fixer;
   CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp);
   CGContextSetAlpha(cg, aDrawOptions.mAlpha);
   CGContextSetShouldAntialias(cg, aDrawOptions.mAntialiasMode != AA_NONE);
 
   CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform));
-  image = GetImageFromSourceSurface(aMask);
+  CGImageRef image = GetRetainedImageFromSourceSurface(aMask);
 
   // use a negative-y so that the mask image draws right ways up
   CGContextScaleCTM(cg, 1, -1);
 
   IntSize size = aMask->GetSize();
 
   CGContextClipToMask(cg, CGRectMake(aOffset.x, -(aOffset.y + size.height), size.width, size.height), image);
 
@@ -785,16 +806,18 @@ DrawTargetCG::MaskSurface(const Pattern 
     // we shouldn't need to clip to an additional rectangle
     // as the cliping to the mask should be sufficient.
     DrawGradient(cg, aSource, CGRectMake(aOffset.x, aOffset.y, size.width, size.height));
   } else {
     SetFillFromPattern(cg, mColorSpace, aSource);
     CGContextFillRect(cg, CGRectMake(aOffset.x, aOffset.y, size.width, size.height));
   }
 
+  CGImageRelease(image);
+
   fixer.Fix(mCg);
 
   CGContextRestoreGState(mCg);
 }
 
 
 
 void
@@ -818,27 +841,28 @@ DrawTargetCG::FillRect(const Rect &aRect
     CGContextClipToRect(cg, RectToCGRect(aRect));
     DrawGradient(cg, aPattern, RectToCGRect(aRect));
   } else {
     if (aPattern.GetType() == PATTERN_SURFACE && static_cast<const SurfacePattern&>(aPattern).mExtendMode != EXTEND_REPEAT) {
       // SetFillFromPattern can handle this case but using CGContextDrawImage
       // should give us better performance, better output, smaller PDF and
       // matches what cairo does.
       const SurfacePattern& pat = static_cast<const SurfacePattern&>(aPattern);
-      CGImageRef image = GetImageFromSourceSurface(pat.mSurface.get());
+      CGImageRef image = GetRetainedImageFromSourceSurface(pat.mSurface.get());
       CGContextClipToRect(cg, RectToCGRect(aRect));
       CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(pat.mMatrix));
       CGContextTranslateCTM(cg, 0, CGImageGetHeight(image));
       CGContextScaleCTM(cg, 1, -1);
 
       CGRect imageRect = CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image));
 
       CGContextSetInterpolationQuality(cg, InterpolationQualityFromFilter(pat.mFilter));
 
       CGContextDrawImage(cg, imageRect, image);
+      CGImageRelease(image);
     } else {
       SetFillFromPattern(cg, mColorSpace, aPattern);
       CGContextFillRect(cg, RectToCGRect(aRect));
     }
   }
 
   fixer.Fix(mCg);
   CGContextRestoreGState(mCg);
@@ -1161,28 +1185,25 @@ CGContextResetClip(CGContextRef);
 
 void
 DrawTargetCG::CopySurface(SourceSurface *aSurface,
                           const IntRect& aSourceRect,
                           const IntPoint &aDestination)
 {
   MarkChanged();
 
-  CGImageRef image;
-  CGImageRef subimage = nullptr;
   if (aSurface->GetType() == SURFACE_COREGRAPHICS_IMAGE ||
       aSurface->GetType() == SURFACE_COREGRAPHICS_CGCONTEXT) {
-    image = GetImageFromSourceSurface(aSurface);
+    CGImageRef image = GetRetainedImageFromSourceSurface(aSurface);
+
     /* we have two options here:
      *  - create a subimage -- this is slower
      *  - fancy things with clip and different dest rects */
-    {