Merge m-c to fx-team
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 28 Nov 2013 14:35:04 +0100
changeset 172684 9edf20552d79e2bc4e7a281f8839fa85bdaaac9c
parent 172683 e95f769be558d11f00ff51f6240102522c050511 (current diff)
parent 172590 3ccec665a6aa1a0a44a12f42c144aa9fcda3dadf (diff)
child 172685 662e8032dccec26c23af53aaa6883178f27e4cc0
push id3224
push userlsblakk@mozilla.com
push dateTue, 04 Feb 2014 01:06:49 +0000
treeherdermozilla-beta@60c04d0987f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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(