Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Thu, 19 Jan 2012 14:27:47 -0800
changeset 105579 c81ee787fbff2de8a7d726aef2d85ee9fda47824
parent 105578 bb915c348132b3ab84243100f7d86223e80b5572 (current diff)
parent 84897 e5e66f40c35b6ccfe4a1c59f977fdbaca5dd6ecb (diff)
child 105580 43548b7da9d225c1769443f2a815f33bc7cb5ae2
push id23447
push userdanderson@mozilla.com
push dateTue, 11 Sep 2012 17:34:27 +0000
treeherderautoland@fdfaef738a00 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone12.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 from mozilla-central.
b2g/installer/package-manifest.in
browser/app/profile/firefox.js
browser/base/content/browser.js
browser/base/content/browser.xul
config/autoconf.mk.in
configure.in
content/base/src/nsXMLHttpRequest.cpp
content/events/public/nsEventNameList.h
content/events/public/nsIPrivateDOMEvent.h
content/events/src/nsDOMEvent.cpp
content/events/src/nsDOMEvent.h
content/events/src/nsDOMMouseEvent.cpp
content/events/src/nsDOMTouchEvent.cpp
content/events/src/nsDOMTouchEvent.h
content/events/src/nsDOMUIEvent.cpp
content/events/src/nsDOMUIEvent.h
content/events/src/nsEventDispatcher.cpp
content/events/test/Makefile.in
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsGenericHTMLElement.h
content/html/content/src/nsHTMLMediaElement.cpp
content/media/nsBuiltinDecoder.cpp
content/media/nsBuiltinDecoderStateMachine.cpp
content/media/nsBuiltinDecoderStateMachine.h
content/svg/content/src/Makefile.in
docshell/base/nsDocShell.cpp
dom/base/nsDOMWindowUtils.cpp
dom/base/nsGlobalWindow.cpp
dom/interfaces/base/nsIDOMWindowUtils.idl
dom/plugins/base/nsPluginInstanceOwner.cpp
dom/workers/WorkerScope.cpp
dom/workers/XMLHttpRequest.cpp
editor/libeditor/base/nsEditor.cpp
gfx/gl/GLContextProviderCGL.mm
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/thebes/gfxDWriteFontList.cpp
image/src/imgFrame.cpp
intl/uconv/src/nsScriptableUConv.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/Parser.h
js/src/ion/Bailouts.cpp
js/src/ion/Ion.cpp
js/src/ion/Ion.h
js/src/jsanalyze.cpp
js/src/jsanalyze.h
js/src/jsapi-tests/testConservativeGC.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsatominlines.h
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jsdbgapi.cpp
js/src/jsexn.cpp
js/src/jsfriendapi.cpp
js/src/jsfun.cpp
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsinterpinlines.h
js/src/jsiter.cpp
js/src/jsiter.h
js/src/jsnum.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsopcode.cpp
js/src/jsprobes.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsstr.cpp
js/src/jsstr.h
js/src/jstypedarray.cpp
js/src/jsutil.h
js/src/jsval.h
js/src/jswrapper.cpp
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/FastArithmetic.cpp
js/src/methodjit/FastOps.cpp
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/MethodJIT.h
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/methodjit/StubCalls.h
js/src/shell/js.cpp
js/src/vm/Debugger.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsChangeHint.h
layout/base/nsIPresShell.h
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/base/nsPresShell.cpp
layout/base/nsPresShell.h
layout/forms/nsTextControlFrame.cpp
layout/forms/nsTextControlFrame.h
layout/generic/crashtests/crashtests.list
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockFrame.h
layout/generic/nsFrame.cpp
layout/generic/nsFrame.h
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
layout/generic/nsIFrame.h
layout/generic/nsObjectFrame.cpp
layout/mathml/nsMathMLContainerFrame.cpp
layout/mathml/nsMathMLContainerFrame.h
layout/reftests/svg/reftest.list
layout/reftests/text/reftest.list
layout/style/nsStyleContext.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/tables/nsTableCellFrame.cpp
layout/tables/nsTableCellFrame.h
layout/tables/nsTableFrame.cpp
layout/tables/nsTableFrame.h
layout/xul/base/src/grid/nsGrid.cpp
layout/xul/base/src/grid/nsGridCell.cpp
layout/xul/base/src/grid/nsGridCell.h
layout/xul/base/src/grid/nsGridRow.cpp
layout/xul/base/src/grid/nsGridRow.h
layout/xul/base/src/grid/nsGridRowLeafLayout.cpp
layout/xul/base/src/nsBox.cpp
layout/xul/base/src/nsBox.h
layout/xul/base/src/nsBoxFrame.cpp
layout/xul/base/src/nsMenuFrame.cpp
layout/xul/base/src/nsSprocketLayout.cpp
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/xul/components/SessionStore.js
mozglue/android/APKOpen.cpp
netwerk/base/src/nsInputStreamPump.cpp
netwerk/protocol/http/nsHttpChannel.cpp
nsprpub/TAG-INFO
nsprpub/config/prdepend.h
parser/html/nsHtml5TreeOpExecutor.cpp
storage/src/mozStorageConnection.cpp
storage/src/mozStorageStatement.cpp
toolkit/components/aboutmemory/content/aboutMemory.js
toolkit/components/autocomplete/nsAutoCompleteController.cpp
toolkit/components/autocomplete/nsAutoCompleteController.h
toolkit/components/autocomplete/nsAutoCompleteSimpleResult.cpp
toolkit/components/filepicker/nsFileView.cpp
toolkit/components/places/SQLFunctions.cpp
toolkit/components/places/nsAnnotationService.cpp
toolkit/components/places/nsNavBookmarks.cpp
toolkit/components/places/tests/head_common.js
toolkit/components/telemetry/TelemetryHistograms.h
toolkit/components/viewsource/content/viewPartialSource.js
toolkit/crashreporter/CrashSubmit.jsm
toolkit/mozapps/extensions/AddonRepository.jsm
toolkit/mozapps/extensions/AddonUpdateChecker.jsm
toolkit/mozapps/extensions/XPIProvider.jsm
toolkit/mozapps/extensions/content/extensions.js
toolkit/mozapps/update/nsUpdateService.js
toolkit/mozapps/update/test/unit/data/complete_cc_log_success
toolkit/mozapps/update/test/unit/head_update.js.in
toolkit/mozapps/update/test/unit/test_0030_general.js
toolkit/mozapps/update/test/unit/test_0040_general.js
toolkit/mozapps/update/test/unit/test_0120_channelChange_complete.js
toolkit/mozapps/update/test_svc/unit/test_0120_channelChange_complete_svc.js
toolkit/xre/nsUpdateDriver.cpp
view/src/nsView.cpp
view/src/nsViewManager.cpp
widget/android/AndroidJNI.cpp
widget/android/nsWindow.cpp
widget/cocoa/nsAppShell.mm
widget/cocoa/nsChildView.mm
widget/nsGUIEvent.h
widget/windows/nsFilePicker.cpp
xpcom/base/nsMemoryReporterManager.cpp
xpcom/glue/nsDeque.cpp
xpcom/glue/nsDeque.h
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -196,16 +196,21 @@ var shell = {
     switch (evt.type) {
       case 'keypress':
         switch (evt.keyCode) {
           case evt.DOM_VK_HOME:
             this.sendEvent(this.home.contentWindow, 'home');
             break;
           case evt.DOM_VK_SLEEP:
             this.toggleScreen();
+
+            let details = {
+              'enabled': screen.mozEnabled
+            };
+            this.sendEvent(this.home.contentWindow, 'sleep', details);
             break;
           case evt.DOM_VK_ESCAPE:
             if (evt.defaultPrevented)
               return;
             this.doCommand('cmd_close');
             break;
         }
         break;
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -597,8 +597,10 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DL
 #ifdef XP_OS2
 @BINPATH@/MozSounds.cmd
 #endif
 
 [b2g]
 @BINPATH@/chrome/icons/
 @BINPATH@/chrome/chrome@JAREXT@
 @BINPATH@/chrome/chrome.manifest
+@BINPATH@/components/B2GComponents.manifest
+@BINPATH@/components/B2GComponents.xpt
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -276,30 +276,30 @@ pref("browser.urlbar.clickSelectsAll", f
 #else
 pref("browser.urlbar.clickSelectsAll", true);
 #endif
 #ifdef UNIX_BUT_NOT_MAC
 pref("browser.urlbar.doubleClickSelectsAll", true);
 #else
 pref("browser.urlbar.doubleClickSelectsAll", false);
 #endif
-pref("browser.urlbar.autoFill", false);
+pref("browser.urlbar.autoFill", true);
 // 0: Match anywhere (e.g., middle of words)
 // 1: Match on word boundaries and then try matching anywhere
 // 2: Match only on word boundaries (e.g., after / or .)
 // 3: Match at the beginning of the url or title
 pref("browser.urlbar.matchBehavior", 1);
 pref("browser.urlbar.filter.javascript", true);
 
 // the maximum number of results to show in autocomplete when doing richResults
 pref("browser.urlbar.maxRichResults", 12);
 // The amount of time (ms) to wait after the user has stopped typing
 // before starting to perform autocomplete.  50 is the default set in
 // autocomplete.xml.
-pref("browser.urlbar.delay", 50);
+pref("browser.urlbar.delay", 0);
 
 // The special characters below can be typed into the urlbar to either restrict
 // the search to visited history, bookmarked, tagged pages; or force a match on
 // just the title text or url.
 pref("browser.urlbar.restrict.history", "^");
 pref("browser.urlbar.restrict.bookmark", "*");
 pref("browser.urlbar.restrict.tag", "+");
 pref("browser.urlbar.restrict.openpage", "%");
--- a/browser/base/content/browser-fullZoom.js
+++ b/browser/base/content/browser-fullZoom.js
@@ -227,16 +227,22 @@ var FullZoom = {
     // Avoid the cps roundtrip and apply the default/global pref.
     if (aURI.spec == "about:blank") {
       this._applyPrefToSetting(undefined, aBrowser);
       return;
     }
 
     let browser = aBrowser || gBrowser.selectedBrowser;
 
+    // Image documents should always start at 1, and are not affected by prefs.
+    if (!aIsTabSwitch && browser.contentDocument instanceof ImageDocument) {
+      ZoomManager.setZoomForBrowser(browser, 1);
+      return;
+    }
+
     if (Services.contentPrefs.hasCachedPref(aURI, this.name)) {
       let zoomValue = Services.contentPrefs.getPref(aURI, this.name);
       this._applyPrefToSetting(zoomValue, browser);
     } else {
       var self = this;
       Services.contentPrefs.getPref(aURI, this.name, function (aResult) {
         // Check that we're still where we expect to be in case this took a while.
         // Null check currentURI, since the window may have been destroyed before
@@ -298,39 +304,40 @@ var FullZoom = {
    * one.
    **/
   _applyPrefToSetting: function FullZoom__applyPrefToSetting(aValue, aBrowser) {
     if ((!this.siteSpecific) || gInPrintPreviewMode)
       return;
 
     var browser = aBrowser || (gBrowser && gBrowser.selectedBrowser);
     try {
-      if (browser.contentDocument instanceof Ci.nsIImageDocument)
-        ZoomManager.setZoomForBrowser(browser, 1);
-      else if (typeof aValue != "undefined")
+      if (browser.contentDocument instanceof ImageDocument)
+        return;
+
+      if (typeof aValue != "undefined")
         ZoomManager.setZoomForBrowser(browser, this._ensureValid(aValue));
       else if (typeof this.globalValue != "undefined")
         ZoomManager.setZoomForBrowser(browser, this.globalValue);
       else
         ZoomManager.setZoomForBrowser(browser, 1);
     }
     catch(ex) {}
   },
 
   _applySettingToPref: function FullZoom__applySettingToPref() {
     if (!this.siteSpecific || gInPrintPreviewMode ||
-        content.document instanceof Ci.nsIImageDocument)
+        content.document instanceof ImageDocument)
       return;
 
     var zoomLevel = ZoomManager.zoom;
     Services.contentPrefs.setPref(gBrowser.currentURI, this.name, zoomLevel);
   },
 
   _removePref: function FullZoom__removePref() {
-    if (!(content.document instanceof Ci.nsIImageDocument))
+    if (!(content.document instanceof ImageDocument))
       Services.contentPrefs.removePref(gBrowser.currentURI, this.name);
   },
 
 
   //**************************************************************************//
   // Utilities
 
   _ensureValid: function FullZoom__ensureValid(aValue) {
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -8867,18 +8867,18 @@ function restoreLastSession() {
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].
            getService(Ci.nsISessionStore);
   ss.restoreLastSession();
 }
 
 var TabContextMenu = {
   contextTab: null,
   updateContextMenu: function updateContextMenu(aPopupMenu) {
-    this.contextTab = document.popupNode.localName == "tab" ?
-                      document.popupNode : gBrowser.selectedTab;
+    this.contextTab = aPopupMenu.triggerNode.localName == "tab" ?
+                      aPopupMenu.triggerNode : gBrowser.selectedTab;
     let disabled = gBrowser.tabs.length == 1;
 
     // Enable the "Close Tab" menuitem when the window doesn't close with the last tab.
     document.getElementById("context_closeTab").disabled =
       disabled && gBrowser.tabContainer._closeWindowWithLastTab;
 
     var menuItems = aPopupMenu.getElementsByAttribute("tbattr", "tabbrowser-multiple");
     for (var i = 0; i < menuItems.length; i++)
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -497,17 +497,17 @@
         </dummyobservertarget>
       </toolbaritem>
 
       <toolbaritem id="urlbar-container" align="center" flex="400" persist="width" combined="true"
                    title="&locationItem.title;" class="chromeclass-location" removable="true">
         <textbox id="urlbar" flex="1"
                  placeholder="&urlbar.placeholder;"
                  type="autocomplete"
-                 autocompletesearch="history"
+                 autocompletesearch="urlinline history"
                  autocompletesearchparam="enable-actions"
                  autocompletepopup="PopupAutoCompleteRichResult"
                  completeselectedindex="true"
                  tabscrolling="true"
                  showcommentcolumn="true"
                  showimagecolumn="true"
                  enablehistory="true"
                  maxrows="6"
--- a/browser/base/content/openLocation.xul
+++ b/browser/base/content/openLocation.xul
@@ -64,17 +64,17 @@
     <separator orient="vertical" class="thin"/>
     <vbox flex="1">
       <description>&enter.label;</description>
       <separator class="thin"/>
 
       <hbox align="center">
         <textbox id="dialog.input" flex="1" type="autocomplete"
                   completeselectedindex="true"
-                  autocompletesearch="history"
+                  autocompletesearch="urlinline history"
                   enablehistory="true"
                   class="uri-element"
                   oninput="doEnabling();"/>
         <button label="&chooseFile.label;" oncommand="onChooseFile();"/>
       </hbox>
       <hbox align="center">
         <label value="&openWhere.label;"/>
         <menulist id="openWhereList">
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -78,24 +78,25 @@ ifneq (gtk2,$(MOZ_WIDGET_TOOLKIT))
 		$(NULL)
 endif
 
 # The following tests are disabled because they are unreliable:
 #   browser_bug423833.js is bug 428712
 #   browser_sanitize-download-history.js is bug 432425
 #
 # browser_sanitizeDialog_treeView.js is disabled until the tree view is added
-# back to the clear recent history dialog (santize.xul), if it ever is (bug
+# back to the clear recent history dialog (sanitize.xul), if it ever is (bug
 # 480169)
 
 # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638.
 
 # browser_bug321000.js is disabled because newline handling is shaky (bug 592528)
 
 _BROWSER_FILES = \
+                 head.js \
                  browser_typeAheadFind.js \
                  browser_keywordSearch.js \
                  browser_allTabsPanel.js \
                  browser_alltabslistener.js \
                  browser_bug304198.js \
                  title_test.svg \
                  browser_bug329212.js \
                  browser_bug356571.js \
@@ -140,16 +141,17 @@ endif
                  browser_bug561623.js \
                  browser_bug561636.js \
                  browser_bug562649.js \
                  browser_bug563588.js \
                  browser_bug565575.js \
                  browser_bug567306.js \
                  browser_zbug569342.js \
                  browser_bug575561.js \
+                 browser_bug575830.js \
                  browser_bug577121.js \
                  browser_bug578534.js \
                  browser_bug579872.js \
                  browser_bug580638.js \
                  browser_bug580956.js \
                  browser_bug581242.js \
                  browser_bug581253.js \
                  browser_bug581947.js \
@@ -208,16 +210,17 @@ endif
                  browser_scope.js \
                  browser_selectTabAtIndex.js \
                  browser_tab_dragdrop.js \
                  browser_tab_dragdrop2.js \
                  browser_tab_dragdrop2_frame1.xul \
                  browser_tabfocus.js \
                  browser_tabs_isActive.js \
                  browser_tabs_owner.js \
+                 browser_urlbarAutoFillTrimURLs.js \
                  browser_urlbarCopying.js \
                  browser_urlbarEnter.js \
                  browser_urlbarTrimURLs.js \
                  browser_urlHighlight.js \
                  browser_visibleFindSelection.js \
                  browser_visibleTabs.js \
                  browser_visibleTabs_contextMenu.js \
                  browser_visibleTabs_bookmarkAllPages.js \
--- a/browser/base/content/test/browser_bug386835.js
+++ b/browser/base/content/test/browser_bug386835.js
@@ -49,22 +49,20 @@ function thirdPageLoaded() {
     load(gTab1, gTestImage, imageLoaded);
   });
 
   gBrowser.selectedTab = gTab2;
 }
 
 function imageLoaded() {
   zoomTest(gTab1, 1, "Zoom should be 1 when image was loaded in the background");
-  afterZoom(function() {
-    zoomTest(gTab1, 1, "Zoom should still be 1 when tab with image is selected");
+  gBrowser.selectedTab = gTab1;
+  zoomTest(gTab1, 1, "Zoom should still be 1 when tab with image is selected");
 
-    executeSoon(imageZoomSwitch);
-  });
-  gBrowser.selectedTab = gTab1;
+  executeSoon(imageZoomSwitch);
 }
 
 function imageZoomSwitch() {
   navigate(BACK, function () {
     navigate(FORWARD, function () {
       zoomTest(gTab1, 1, "Tab 1 should not be zoomed when an image loads");
 
       afterZoom(function() {
@@ -131,17 +129,15 @@ function navigate(direction, cb) {
 
   if (direction == BACK)
     gBrowser.goBack();
   else if (direction == FORWARD)
     gBrowser.goForward();
 }
 
 function afterZoom(cb) {
-  let oldAPTS = FullZoom._applyPrefToSetting;
-  FullZoom._applyPrefToSetting = function(value, browser) {
-    if (!value)
-      value = undefined;
-    oldAPTS.call(FullZoom, value, browser);
-    FullZoom._applyPrefToSetting = oldAPTS;
+  let oldSZFB = ZoomManager.setZoomForBrowser;
+  ZoomManager.setZoomForBrowser = function(browser, value) {
+    oldSZFB.call(ZoomManager, browser, value);
+    ZoomManager.setZoomForBrowser = oldSZFB;
     executeSoon(cb);
   };
 }
--- a/browser/base/content/test/browser_bug416661.js
+++ b/browser/base/content/test/browser_bug416661.js
@@ -45,19 +45,17 @@ function test() {
 function afterZoomAndLoad(cb) {
   let didLoad = didZoom = false;
   tabElm.linkedBrowser.addEventListener("load", function() {
     tabElm.linkedBrowser.removeEventListener("load", arguments.callee, true);
     didLoad = true;
     if (didZoom)
       executeSoon(cb);
   }, true);
-  let oldAPTS = FullZoom._applyPrefToSetting;
-  FullZoom._applyPrefToSetting = function(value, browser) {
-    if (!value)
-      value = undefined;
-    oldAPTS.call(FullZoom, value, browser);
-    FullZoom._applyPrefToSetting = oldAPTS;
+  let oldSZFB = ZoomManager.setZoomForBrowser;
+  ZoomManager.setZoomForBrowser = function(browser, value) {
+    oldSZFB.call(ZoomManager, browser, value);
+    ZoomManager.setZoomForBrowser = oldSZFB;
     didZoom = true;
     if (didLoad)
       executeSoon(cb);
   };
 }
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_bug575830.js
@@ -0,0 +1,37 @@
+/* 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/. */
+"use strict";
+
+function test() {
+  let tab1, tab2;
+  const TEST_IMAGE = "http://example.org/browser/browser/base/content/test/moz.png";
+
+  waitForExplicitFinish();
+  registerCleanupFunction(function cleanup() {
+    gBrowser.removeTab(tab1);
+    gBrowser.removeTab(tab2);
+  });
+
+  tab1 = gBrowser.addTab(TEST_IMAGE);
+  tab2 = gBrowser.addTab();
+  gBrowser.selectedTab = tab1;
+
+  tab1.linkedBrowser.addEventListener("load", function onload() {
+    tab1.linkedBrowser.removeEventListener("load", onload, true);
+    is(ZoomManager.zoom, 1, "initial zoom level for first should be 1");
+
+    FullZoom.enlarge();
+    let zoom = ZoomManager.zoom;
+    isnot(zoom, 1, "zoom level should have changed");
+
+    gBrowser.selectedTab = tab2;
+    is(ZoomManager.zoom, 1, "initial zoom level for second tab should be 1");
+
+    gBrowser.selectedTab = tab1;
+    is(ZoomManager.zoom, zoom, "zoom level for first tab should not have changed");
+
+    finish();
+  }, true);
+}
+
--- a/browser/base/content/test/browser_bug580956.js
+++ b/browser/base/content/test/browser_bug580956.js
@@ -1,17 +1,15 @@
 function numClosedTabs()
   Cc["@mozilla.org/browser/sessionstore;1"].
     getService(Ci.nsISessionStore).
     getClosedTabCount(window);
 
 function isUndoCloseEnabled() {
-  document.popupNode = gBrowser.tabs[0];
-  TabContextMenu.updateContextMenu(document.getElementById("tabContextMenu"));
-  TabContextMenu.contextTab = null;
+  updateTabContextMenu();
   return !document.getElementById("context_undoCloseTab").disabled;
 }
 
 function test() {
   waitForExplicitFinish();
 
   gPrefService.setIntPref("browser.sessionstore.max_tabs_undo", 0);
   gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo");
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_urlbarAutoFillTrimURLs.js
@@ -0,0 +1,85 @@
+/* This Source Code is subject to the terms of the Mozilla Public License
+ * version 2.0 (the "License"). You can obtain a copy of the License at
+ * http://mozilla.org/MPL/2.0/. */
+
+// This test ensures that autoFilled values are not trimmed, unless the user
+// selects from the autocomplete popup.
+
+function test() {
+  waitForExplicitFinish();
+
+  const PREF_TRIMURL = "browser.urlbar.trimURLs";
+  const PREF_AUTOFILL = "browser.urlbar.autoFill";
+
+  registerCleanupFunction(function () {
+    Services.prefs.clearUserPref(PREF_TRIMURL);
+    Services.prefs.clearUserPref(PREF_AUTOFILL);
+    URLBarSetURI();
+  });
+  Services.prefs.setBoolPref(PREF_TRIMURL, true);
+  Services.prefs.setBoolPref(PREF_AUTOFILL, true);
+
+  // Adding a tab would hit switch-to-tab, so it's safer to just add a visit.
+  let callback = {
+    handleError:  function () {},
+    handleResult: function () {},
+    handleCompletion: continue_test
+  };
+  let history = Cc["@mozilla.org/browser/history;1"]
+                  .getService(Ci.mozIAsyncHistory);
+  history.updatePlaces({ uri: NetUtil.newURI("http://www.autofilltrimurl.com/")
+                       , visits: [ { transitionType: Ci.nsINavHistoryService.TRANSITION_TYPED
+                                   , visitDate:      Date.now() * 1000
+                                   } ]
+                       }, callback);
+}
+
+function continue_test() {
+  function test_autoFill(aTyped, aExpected, aCallback) {
+    gURLBar.inputField.value = aTyped.substr(0, aTyped.length - 1);
+    gURLBar.focus();
+    gURLBar.selectionStart = aTyped.length - 1;
+    gURLBar.selectionEnd = aTyped.length - 1;
+
+    EventUtils.synthesizeKey(aTyped.substr(-1), {});
+    is(gURLBar.value, aExpected, "trim was applied correctly");
+
+    aCallback();
+  }
+
+  test_autoFill("http://", "http://", function () {
+    test_autoFill("http://a", "http://autofilltrimurl.com/", function () {
+      test_autoFill("http://www.autofilltrimurl.com", "http://www.autofilltrimurl.com/", function () {
+        // Now ensure selecting from the popup correctly trims.
+        waitForSearchComplete(function () {
+          EventUtils.synthesizeKey("VK_DOWN", {});
+          is(gURLBar.value, "www.autofilltrimurl.com", "trim was applied correctly");
+          gURLBar.closePopup();
+          waitForClearHistory(finish);
+        });
+      });
+    });
+  });
+}
+
+function waitForClearHistory(aCallback) {
+  Services.obs.addObserver(function observeCH(aSubject, aTopic, aData) {
+    Services.obs.removeObserver(observeCH, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
+    aCallback();
+  }, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false);
+  PlacesUtils.bhistory.removeAllPages();
+}
+
+function waitForSearchComplete(aCallback) {
+  info("Waiting for onSearchComplete");
+  let onSearchComplete = gURLBar.onSearchComplete;
+  registerCleanupFunction(function () {
+    gURLBar.onSearchComplete = onSearchComplete;
+  });
+  gURLBar.onSearchComplete = function () {
+    ok(gURLBar.popupOpen, "The autocomplete popup is correctly open");
+    is(gURLBar.controller.matchCount, 1, "Found the expected number of matches")
+    onSearchComplete.apply(gURLBar);
+    aCallback();
+  }
+}
--- a/browser/base/content/test/browser_visibleTabs_bookmarkAllTabs.js
+++ b/browser/base/content/test/browser_visibleTabs_bookmarkAllTabs.js
@@ -84,20 +84,16 @@ function test() {
     is(Disabled(), true, "Bookmark All Tabs should be hidden");
     is(gBrowser.selectedTab, origTab, "got the orig tab");
     is(origTab.hidden, false, "and it's not hidden -- visible!");
     finish();
   }, true);
 }
 
 function Disabled() {
-  document.popupNode = gBrowser.selectedTab;
-  TabContextMenu.updateContextMenu(document.getElementById("tabContextMenu"));
-  TabContextMenu.contextTab = null;
+  updateTabContextMenu();
   return document.getElementById("Browser:BookmarkAllTabs").getAttribute("disabled") == "true";
 }
 
 function Hidden() {
-  document.popupNode = gBrowser.selectedTab;
-  TabContextMenu.updateContextMenu(document.getElementById("tabContextMenu"));
-  TabContextMenu.contextTab = null;
+  updateTabContextMenu();
   return document.getElementById("context_bookmarkAllTabs").hidden;
 }
--- a/browser/base/content/test/browser_visibleTabs_contextMenu.js
+++ b/browser/base/content/test/browser_visibleTabs_contextMenu.js
@@ -38,50 +38,43 @@
 function test() {
   // There should be one tab when we start the test
   let [origTab] = gBrowser.visibleTabs;
   is(gBrowser.visibleTabs.length, 1, "there is one visible tab");
   let testTab = gBrowser.addTab();
   is(gBrowser.visibleTabs.length, 2, "there are now two visible tabs");
 
   // Check the context menu with two tabs
-  popup(origTab);
+  updateTabContextMenu(origTab);
   is(document.getElementById("context_closeTab").disabled, false, "Close Tab is enabled");
   is(document.getElementById("context_reloadAllTabs").disabled, false, "Reload All Tabs is enabled");
 
   // Hide the original tab.
   gBrowser.selectedTab = testTab;
   gBrowser.showOnlyTheseTabs([testTab]);
   is(gBrowser.visibleTabs.length, 1, "now there is only one visible tab");
   
   // Check the context menu with one tab.
-  popup(testTab);
+  updateTabContextMenu(testTab);
   is(document.getElementById("context_closeTab").disabled, false, "Close Tab is enabled when more than one tab exists");
   is(document.getElementById("context_reloadAllTabs").disabled, true, "Reload All Tabs is disabled");
   
   // Add a tab that will get pinned
   // So now there's one pinned tab, one visible unpinned tab, and one hidden tab
   let pinned = gBrowser.addTab();
   gBrowser.pinTab(pinned);
   is(gBrowser.visibleTabs.length, 2, "now there are two visible tabs");
 
   // Check the context menu on the unpinned visible tab
-  popup(testTab);
+  updateTabContextMenu(testTab);
   is(document.getElementById("context_closeOtherTabs").disabled, true, "Close Other Tabs is disabled");
 
   // Show all tabs
   let allTabs = [tab for each (tab in gBrowser.tabs)];
   gBrowser.showOnlyTheseTabs(allTabs);
 
   // Check the context menu now
-  popup(testTab);
+  updateTabContextMenu(testTab);
   is(document.getElementById("context_closeOtherTabs").disabled, false, "Close Other Tabs is enabled");
   
   gBrowser.removeTab(testTab);
   gBrowser.removeTab(pinned);
 }
-
-function popup(tab) {
-  document.popupNode = tab;
-  TabContextMenu.updateContextMenu(document.getElementById("tabContextMenu"));
-  is(TabContextMenu.contextTab, tab, "TabContextMenu context is the expected tab");
-  TabContextMenu.contextTab = null;
-}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/head.js
@@ -0,0 +1,8 @@
+function updateTabContextMenu(tab) {
+  let menu = document.getElementById("tabContextMenu");
+  if (!tab)
+    tab = gBrowser.selectedTab;
+  menu.openPopup(tab, "end_after", 0, 0, true, false, {target: tab});
+  is(TabContextMenu.contextTab, tab, "TabContextMenu context is the expected tab");
+  menu.hidePopup();
+}
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -662,17 +662,23 @@
 
       <property name="textValue"
                 onget="return this.value;">
         <setter>
           <![CDATA[
           try {
             val = losslessDecodeURI(makeURI(val));
           } catch (ex) { }
+
+          // Trim popup selected values, but never trim results coming from
+          // autofill.
+          if (this.popup.selectedIndex == -1)
+            this._disableTrim = true;
           this.value = val;
+          this._disableTrim = false;
 
           // Completing a result should simulate the user typing the result, so
           // fire an input event.
           let evt = document.createEvent("UIEvents");
           evt.initUIEvent("input", true, false, window, 0);
           this.mIgnoreInput = true;
           this.dispatchEvent(evt);
           this.mIgnoreInput = false;
--- a/browser/components/search/content/engineManager.js
+++ b/browser/components/search/content/engineManager.js
@@ -33,84 +33,73 @@
 # use your version of this file under the terms of the MPL, indicate your
 # decision by deleting the provisions above and replace them with the notice
 # and other provisions required by the GPL or the LGPL. If you do not delete
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
+Components.utils.import("resource://gre/modules/Services.jsm");
+
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 
 const ENGINE_FLAVOR = "text/x-moz-search-engine";
 
 const BROWSER_SUGGEST_PREF = "browser.search.suggest.enabled";
 
 var gEngineView = null;
 
 var gEngineManagerDialog = {
   init: function engineManager_init() {
     gEngineView = new EngineView(new EngineStore());
 
-    var prefService = Cc["@mozilla.org/preferences-service;1"].
-                      getService(Ci.nsIPrefBranch);
-    var suggestEnabled = prefService.getBoolPref(BROWSER_SUGGEST_PREF);
+    var suggestEnabled = Services.prefs.getBoolPref(BROWSER_SUGGEST_PREF);
     document.getElementById("enableSuggest").checked = suggestEnabled;
 
     var tree = document.getElementById("engineList");
     tree.view = gEngineView;
 
-    var os = Cc["@mozilla.org/observer-service;1"].
-             getService(Ci.nsIObserverService);
-    os.addObserver(this, "browser-search-engine-modified", false);
+    Services.obs.addObserver(this, "browser-search-engine-modified", false);
+  },
+
+  destroy: function engineManager_destroy() {
+    // Remove the observer
+    Services.obs.removeObserver(this, "browser-search-engine-modified");
   },
 
   observe: function engineManager_observe(aEngine, aTopic, aVerb) {
     if (aTopic == "browser-search-engine-modified") {
-      aEngine.QueryInterface(Ci.nsISearchEngine)
+      aEngine.QueryInterface(Ci.nsISearchEngine);
       switch (aVerb) {
       case "engine-added":
         gEngineView._engineStore.addEngine(aEngine);
         gEngineView.rowCountChanged(gEngineView.lastIndex, 1);
         break;
       case "engine-changed":
         gEngineView._engineStore.reloadIcons();
+        gEngineView.invalidate();
         break;
       case "engine-removed":
       case "engine-current":
         // Not relevant
-        return;
+        break;
       }
-      gEngineView.invalidate();
     }
   },
 
   onOK: function engineManager_onOK() {
-    // Remove the observer
-    var os = Cc["@mozilla.org/observer-service;1"].
-             getService(Ci.nsIObserverService);
-    os.removeObserver(this, "browser-search-engine-modified");
-
     // Set the preference
     var newSuggestEnabled = document.getElementById("enableSuggest").checked;
-    var prefService = Cc["@mozilla.org/preferences-service;1"].
-                      getService(Ci.nsIPrefBranch);
-    prefService.setBoolPref(BROWSER_SUGGEST_PREF, newSuggestEnabled);
+    Services.prefs.setBoolPref(BROWSER_SUGGEST_PREF, newSuggestEnabled);
 
     // Commit the changes
     gEngineView._engineStore.commit();
   },
-  
-  onCancel: function engineManager_onCancel() {
-    // Remove the observer
-    var os = Cc["@mozilla.org/observer-service;1"].
-             getService(Ci.nsIObserverService);
-    os.removeObserver(this, "browser-search-engine-modified");
-  },
 
   onRestoreDefaults: function engineManager_onRestoreDefaults() {
     var num = gEngineView._engineStore.restoreDefaultEngines();
     gEngineView.rowCountChanged(0, num);
     gEngineView.invalidate();
   },
 
   showRestoreDefaults: function engineManager_showRestoreDefaults(val) {
@@ -124,17 +113,17 @@ var gEngineManagerDialog = {
   },
 
   remove: function engineManager_remove() {
     gEngineView._engineStore.removeEngine(gEngineView.selectedEngine);
     var index = gEngineView.selectedIndex;
     gEngineView.rowCountChanged(index, -1);
     gEngineView.invalidate();
     gEngineView.selection.select(Math.min(index, gEngineView.lastIndex));
-    gEngineView.ensureRowIsVisible(Math.min(index, gEngineView.lastIndex));
+    gEngineView.ensureRowIsVisible(gEngineView.currentIndex);
     document.getElementById("engineList").focus();
   },
 
   /**
    * Moves the selected engine either up or down in the engine list
    * @param aDir
    *        -1 to move the selected engine down, +1 to move it up.
    */
@@ -151,81 +140,80 @@ var gEngineManagerDialog = {
     document.getElementById("engineList").focus();
   },
 
   editKeyword: function engineManager_editKeyword() {
     var selectedEngine = gEngineView.selectedEngine;
     if (!selectedEngine)
       return;
 
-    var prompt = Cc["@mozilla.org/embedcomp/prompt-service;1"].
-                 getService(Ci.nsIPromptService);
     var alias = { value: selectedEngine.alias };
     var strings = document.getElementById("engineManagerBundle");
     var title = strings.getString("editTitle");
     var msg = strings.getFormattedString("editMsg", [selectedEngine.name]);
 
-    while (prompt.prompt(window, title, msg, alias, null, { })) {
+    while (Services.prompt.prompt(window, title, msg, alias, null, {})) {
       var bduplicate = false;
       var eduplicate = false;
 
       if (alias.value != "") {
         try {
           let bmserv = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
                        getService(Ci.nsINavBookmarksService);
           if (bmserv.getURIForKeyword(alias.value))
             bduplicate = true;
         } catch(ex) {}
 
         // Check for duplicates in changes we haven't committed yet
         let engines = gEngineView._engineStore.engines;
         for each (let engine in engines) {
-          if (engine.alias == alias.value && 
+          if (engine.alias == alias.value &&
               engine.name != selectedEngine.name) {
             eduplicate = true;
             break;
           }
         }
       }
 
       // Notify the user if they have chosen an existing engine/bookmark keyword
       if (eduplicate || bduplicate) {
         var dtitle = strings.getString("duplicateTitle");
         var bmsg = strings.getString("duplicateBookmarkMsg");
         var emsg = strings.getFormattedString("duplicateEngineMsg",
                                               [engine.name]);
 
-        prompt.alert(window, dtitle, (eduplicate) ? emsg : bmsg);
+        Services.prompt.alert(window, dtitle, eduplicate ? emsg : bmsg);
       } else {
         gEngineView._engineStore.changeEngine(selectedEngine, "alias",
                                               alias.value);
         gEngineView.invalidate();
         break;
       }
     }
   },
 
   onSelect: function engineManager_onSelect() {
-    // buttons only work if an engine is selected and it's not the last engine
-    var disableButtons = (gEngineView.selectedIndex == -1) ||
-                         (gEngineView.lastIndex == 0);
+    // Buttons only work if an engine is selected and it's not the last engine,
+    // the latter is true when the selected is first and last at the same time.
     var lastSelected = (gEngineView.selectedIndex == gEngineView.lastIndex);
     var firstSelected = (gEngineView.selectedIndex == 0);
     var noSelection = (gEngineView.selectedIndex == -1);
 
-    document.getElementById("cmd_remove").setAttribute("disabled",
-                                                       disableButtons);
+    document.getElementById("cmd_remove")
+            .setAttribute("disabled", noSelection ||
+                                      (firstSelected && lastSelected));
 
-    document.getElementById("cmd_moveup").setAttribute("disabled",
-                                            disableButtons || firstSelected);
+    document.getElementById("cmd_moveup")
+            .setAttribute("disabled", noSelection || firstSelected);
 
-    document.getElementById("cmd_movedown").setAttribute("disabled",
-                                             disableButtons || lastSelected);
-    document.getElementById("cmd_editkeyword").setAttribute("disabled",
-                                                            noSelection);
+    document.getElementById("cmd_movedown")
+            .setAttribute("disabled", noSelection || lastSelected);
+
+    document.getElementById("cmd_editkeyword")
+            .setAttribute("disabled", noSelection);
   }
 };
 
 function onDragEngineStart(event) {
   var selectedIndex = gEngineView.selectedIndex;
   if (selectedIndex >= 0) {
     event.dataTransfer.setData(ENGINE_FLAVOR, selectedIndex.toString());
     event.dataTransfer.effectAllowed = "move";
@@ -238,50 +226,44 @@ function EngineMoveOp(aEngineClone, aNew
     throw new Error("bad args to new EngineMoveOp!");
   this._engine = aEngineClone.originalEngine;
   this._newIndex = aNewIndex;
 }
 EngineMoveOp.prototype = {
   _engine: null,
   _newIndex: null,
   commit: function EMO_commit() {
-    var searchService = Cc["@mozilla.org/browser/search-service;1"].
-                        getService(Ci.nsIBrowserSearchService);
-    searchService.moveEngine(this._engine, this._newIndex);
+    Services.search.moveEngine(this._engine, this._newIndex);
   }
 }
 
 function EngineRemoveOp(aEngineClone) {
   if (!aEngineClone)
     throw new Error("bad args to new EngineRemoveOp!");
   this._engine = aEngineClone.originalEngine;
 }
 EngineRemoveOp.prototype = {
   _engine: null,
   commit: function ERO_commit() {
-    var searchService = Cc["@mozilla.org/browser/search-service;1"].
-                        getService(Ci.nsIBrowserSearchService);
-    searchService.removeEngine(this._engine);
+    Services.search.removeEngine(this._engine);
   }
 }
 
 function EngineUnhideOp(aEngineClone, aNewIndex) {
   if (!aEngineClone)
     throw new Error("bad args to new EngineUnhideOp!");
   this._engine = aEngineClone.originalEngine;
   this._newIndex = aNewIndex;
 }
 EngineUnhideOp.prototype = {
   _engine: null,
   _newIndex: null,
   commit: function EUO_commit() {
     this._engine.hidden = false;
-    var searchService = Cc["@mozilla.org/browser/search-service;1"].
-                        getService(Ci.nsIBrowserSearchService);
-    searchService.moveEngine(this._engine, this._newIndex);
+    Services.search.moveEngine(this._engine, this._newIndex);
   }
 }
 
 function EngineChangeOp(aEngineClone, aProp, aValue) {
   if (!aEngineClone)
     throw new Error("bad args to new EngineChangeOp!");
 
   this._engine = aEngineClone.originalEngine;
@@ -293,20 +275,18 @@ EngineChangeOp.prototype = {
   _prop: null,
   _newValue: null,
   commit: function ECO_commit() {
     this._engine[this._prop] = this._newValue;
   }
 }
 
 function EngineStore() {
-  var searchService = Cc["@mozilla.org/browser/search-service;1"].
-                      getService(Ci.nsIBrowserSearchService);
-  this._engines = searchService.getVisibleEngines().map(this._cloneEngine);
-  this._defaultEngines = searchService.getDefaultEngines().map(this._cloneEngine);
+  this._engines = Services.search.getVisibleEngines().map(this._cloneEngine);
+  this._defaultEngines = Services.search.getDefaultEngines().map(this._cloneEngine);
 
   this._ops = [];
 
   // check if we need to disable the restore defaults button
   var someHidden = this._defaultEngines.some(function (e) e.hidden);
   gEngineManagerDialog.showRestoreDefaults(someHidden);
 }
 EngineStore.prototype = {
@@ -329,41 +309,39 @@ EngineStore.prototype = {
   _getEngineByName: function ES_getEngineByName(aName) {
     for each (var engine in this._engines)
       if (engine.name == aName)
         return engine;
 
     return null;
   },
 
-  _cloneEngine: function ES_cloneObj(aEngine) {
-    var newO=[];
+  _cloneEngine: function ES_cloneEngine(aEngine) {
+    var clonedObj={};
     for (var i in aEngine)
-      newO[i] = aEngine[i];
-    newO.originalEngine = aEngine;
-    return newO;
+      clonedObj[i] = aEngine[i];
+    clonedObj.originalEngine = aEngine;
+    return clonedObj;
   },
 
   // Callback for Array's some(). A thisObj must be passed to some()
   _isSameEngine: function ES_isSameEngine(aEngineClone) {
     return aEngineClone.originalEngine == this.originalEngine;
   },
 
   commit: function ES_commit() {
-    var searchService = Cc["@mozilla.org/browser/search-service;1"].
-                        getService(Ci.nsIBrowserSearchService);
-    var currentEngine = this._cloneEngine(searchService.currentEngine);
+    var currentEngine = this._cloneEngine(Services.search.currentEngine);
     for (var i = 0; i < this._ops.length; i++)
       this._ops[i].commit();
 
     // Restore currentEngine if it is a default engine that is still visible.
     // Needed if the user deletes currentEngine and then restores it.
     if (this._defaultEngines.some(this._isSameEngine, currentEngine) &&
         !currentEngine.originalEngine.hidden)
-      searchService.currentEngine = currentEngine.originalEngine;
+      Services.search.currentEngine = currentEngine.originalEngine;
   },
 
   addEngine: function ES_addEngine(aEngine) {
     this._engines.push(this._cloneEngine(aEngine));
   },
 
   moveEngine: function ES_moveEngine(aEngine, aNewIndex) {
     if (aNewIndex < 0 || aNewIndex > this._engines.length - 1)
@@ -381,17 +359,17 @@ EngineStore.prototype = {
 
     this._ops.push(new EngineMoveOp(aEngine, aNewIndex));
   },
 
   removeEngine: function ES_removeEngine(aEngine) {
     var index = this._getIndexForEngine(aEngine);
     if (index == -1)
       throw new Error("invalid engine?");
- 
+
     this._engines.splice(index, 1);
     this._ops.push(new EngineRemoveOp(aEngine));
     if (this._defaultEngines.some(this._isSameEngine, aEngine))
       gEngineManagerDialog.showRestoreDefaults(true);
   },
 
   restoreDefaultEngines: function ES_restoreDefaultEngines() {
     var added = 0;
@@ -437,18 +415,18 @@ EngineView.prototype = {
   tree: null,
 
   get lastIndex() {
     return this.rowCount - 1;
   },
   get selectedIndex() {
     var seln = this.selection;
     if (seln.getRangeCount() > 0) {
-      var min = { };
-      seln.getRangeAt(0, min, { });
+      var min = {};
+      seln.getRangeAt(0, min, {});
       return min.value;
     }
     return -1;
   },
   get selectedEngine() {
     return this._engineStore.engines[this.selectedIndex];
   },
 
@@ -491,37 +469,36 @@ EngineView.prototype = {
   setTree: function(tree) {
     this.tree = tree;
   },
 
   canDrop: function(targetIndex, orientation, dataTransfer) {
     var sourceIndex = this.getSourceIndexFromDrag(dataTransfer);
     return (sourceIndex != -1 &&
             sourceIndex != targetIndex &&
-            sourceIndex != (targetIndex + orientation));
+            sourceIndex != targetIndex + orientation);
   },
 
   drop: function(dropIndex, orientation, dataTransfer) {
     var sourceIndex = this.getSourceIndexFromDrag(dataTransfer);
     var sourceEngine = this._engineStore.engines[sourceIndex];
 
     if (dropIndex > sourceIndex) {
       if (orientation == Ci.nsITreeView.DROP_BEFORE)
         dropIndex--;
     } else {
       if (orientation == Ci.nsITreeView.DROP_AFTER)
-        dropIndex++;    
+        dropIndex++;
     }
 
     this._engineStore.moveEngine(sourceEngine, dropIndex);
     gEngineManagerDialog.showRestoreDefaults(true);
 
     // Redraw, and adjust selection
     this.invalidate();
-    this.selection.clearSelection();
     this.selection.select(dropIndex);
   },
 
   selection: null,
   getRowProperties: function(index, properties) { },
   getCellProperties: function(index, column, properties) { },
   getColumnProperties: function(column, properties) { },
   isContainer: function(index) { return false; },
--- a/browser/components/search/content/engineManager.xul
+++ b/browser/components/search/content/engineManager.xul
@@ -43,18 +43,18 @@
 <!DOCTYPE dialog SYSTEM "chrome://browser/locale/engineManager.dtd">
 
 <dialog id="engineManager"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         buttons="accept,cancel,extra2"
         buttonlabelextra2="&restoreDefaults.label;"
         buttonaccesskeyextra2="&restoreDefaults.accesskey;"
         onload="gEngineManagerDialog.init();"
+        onunload="gEngineManagerDialog.destroy();"
         ondialogaccept="gEngineManagerDialog.onOK();"
-        ondialogcancel="gEngineManagerDialog.onCancel();"
         ondialogextra2="gEngineManagerDialog.onRestoreDefaults();"
         title="&engineManager.title;"
         style="&engineManager.style;"
         persist="screenX screenY width height"
         windowtype="Browser:SearchManager">
 
   <script type="application/javascript"
           src="chrome://browser/content/search/engineManager.js"/>
@@ -83,47 +83,45 @@
   </stringbundleset>
 
   <description>&engineManager.intro;</description>
   <separator class="thin"/>
   <hbox flex="1">
     <tree id="engineList" flex="1" rows="10" hidecolumnpicker="true"
           seltype="single" onselect="gEngineManagerDialog.onSelect();">
       <treechildren id="engineChildren" flex="1"
-                    ondragstart="onDragEngineStart(event)"/>
+                    ondragstart="onDragEngineStart(event);"/>
       <treecols>
         <treecol id="engineName" flex="4" label="&columnLabel.name;"/>
         <treecol id="engineKeyword" flex="1" label="&columnLabel.keyword;"/>
       </treecols>
     </tree>
     <vbox>
       <spacer flex="1"/>
       <button id="edit"
               label="&edit.label;"
               accesskey="&edit.accesskey;"
               command="cmd_editkeyword"/>
       <button id="up"
               label="&up.label;"
               accesskey="&up.accesskey;"
               command="cmd_moveup"/>
-      <button id="dn"
+      <button id="down"
               label="&dn.label;"
               accesskey="&dn.accesskey;"
               command="cmd_movedown"/>
       <spacer flex="1"/>
       <button id="remove"
               label="&remove.label;"
               accesskey="&remove.accesskey;"
               command="cmd_remove"/>
     </vbox>
   </hbox>
   <hbox>
     <checkbox id="enableSuggest"
               label="&enableSuggest.label;"
               accesskey="&enableSuggest.accesskey;"/>
-    <spacer flex="1"/>
   </hbox>
   <hbox>
     <label id="addEngines" class="text-link" value="&addEngine.label;"
            onclick="if (event.button == 0) { gEngineManagerDialog.loadAddEngines(); }"/>
-    <spacer flex="1"/>
   </hbox>
 </dialog>
--- a/browser/components/tabview/test/browser_tabview_bug625195.js
+++ b/browser/components/tabview/test/browser_tabview_bug625195.js
@@ -42,14 +42,15 @@ function test() {
       finish();
     });
     let newGroup = contentWindow.GroupItems.newGroup();
     newGroup.newTab();
   });
 }
 
 function popup(tab) {
-  document.popupNode = tab;
-  TabContextMenu.updateContextMenu(document.getElementById("tabContextMenu"));
+  let menu = document.getElementById("tabContextMenu");
+  menu.openPopup(tab, "end_after", 0, 0, true, false, {target: tab});
+  TabContextMenu.updateContextMenu(menu);
   is(TabContextMenu.contextTab, tab, "TabContextMenu context is the expected tab");
-  TabContextMenu.contextTab = null;
+  menu.hidePopup();
 }
 
--- a/browser/components/tabview/test/browser_tabview_bug626525.js
+++ b/browser/components/tabview/test/browser_tabview_bug626525.js
@@ -133,19 +133,18 @@ function test3(win) {
   win.document.getElementById("context_tabViewNewGroup").doCommand();
 
   // close popups
   win.document.getElementById("context_tabViewMenuPopup").hidePopup();
   closeTabContextPopup(win);
 }
 
 function openTabContextPopup(win, tab) {
-  win.document.popupNode = tab;
   win.document.getElementById("tabContextMenu").openPopup(
-    tab, "end_after", 0, 0, true, false);
+    tab, "end_after", 0, 0, true, false, {target: tab});
 }
 
 function closeTabContextPopup(win) {
   win.document.getElementById("tabContextMenu").hidePopup();
 }
 
 function goToNextGroup(win) {
   let utils =
--- a/browser/components/tabview/test/browser_tabview_bug641802.js
+++ b/browser/components/tabview/test/browser_tabview_bug641802.js
@@ -1,16 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
   let openMoveToGroupPopup = function () {
     let tab = gBrowser.selectedTab;
-    document.popupNode = tab;
-    contextMenu.openPopup(tab, "end_after", 0, 0, true, false);
+    contextMenu.openPopup(tab, "end_after", 0, 0, true, false, {target: tab});
     tvMenuPopup.openPopup(tvMenu, "end_after", 0, 0, true, false);
   }
 
   let hideMoveToGroupPopup = function () {
     tvMenuPopup.hidePopup();
     contextMenu.hidePopup();
   }
 
--- a/browser/devtools/styleinspector/CssRuleView.jsm
+++ b/browser/devtools/styleinspector/CssRuleView.jsm
@@ -1266,17 +1266,17 @@ InplaceEditor.prototype = {
   /**
    * Size the editor to fit its current contents.
    */
   _updateSize: function InplaceEditor_updateSize()
   {
     // Replace spaces with non-breaking spaces.  Otherwise setting
     // the span's textContent will collapse spaces and the measurement
     // will be wrong.
-    this._measurement.textContent = this.input.value.replace(' ', '\u00a0', 'g');
+    this._measurement.textContent = this.input.value.replace(/ /g, '\u00a0');
 
     // We add a bit of padding to the end.  Should be enough to fit
     // any letter that could be typed, otherwise we'll scroll before
     // we get a chance to resize.  Yuck.
     let width = this._measurement.offsetWidth + 10;
 
     this.input.style.width = width + "px";
   },
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -218,17 +218,16 @@
 @BINPATH@/components/loginmgr.xpt
 @BINPATH@/components/parentalcontrols.xpt
 @BINPATH@/components/places.xpt
 @BINPATH@/components/plugin.xpt
 @BINPATH@/components/pref.xpt
 @BINPATH@/components/prefetch.xpt
 @BINPATH@/components/profile.xpt
 @BINPATH@/components/profiler.xpt
-@BINPATH@/components/proxyObject.xpt
 @BINPATH@/components/rdf.xpt
 @BINPATH@/components/satchel.xpt
 @BINPATH@/components/saxparser.xpt
 @BINPATH@/components/sessionstore.xpt
 @BINPATH@/components/services-crypto-component.xpt
 @BINPATH@/components/shellservice.xpt
 @BINPATH@/components/shistory.xpt
 @BINPATH@/components/spellchecker.xpt
--- a/browser/themes/gnomestripe/engineManager.css
+++ b/browser/themes/gnomestripe/engineManager.css
@@ -40,10 +40,10 @@
 #engineList treechildren::-moz-tree-image(engineName) {
   -moz-margin-end: 4px;
   -moz-margin-start: 1px;
   width: 16px;
   height: 16px;
 }
 
 #engineList treechildren::-moz-tree-row {
-  height: 20px !important;
+  height: 20px;
 }
--- a/browser/themes/pinstripe/engineManager.css
+++ b/browser/themes/pinstripe/engineManager.css
@@ -40,10 +40,10 @@
 #engineList treechildren::-moz-tree-image(engineName) {
   -moz-margin-end: 4px;
   -moz-margin-start: 1px;
   width: 16px;
   height: 16px;
 }
 
 #engineList treechildren::-moz-tree-row {
-  height: 20px !important;
+  height: 20px;
 }
--- a/browser/themes/winstripe/engineManager.css
+++ b/browser/themes/winstripe/engineManager.css
@@ -40,10 +40,10 @@
 #engineList treechildren::-moz-tree-image(engineName) {
   -moz-margin-end: 4px;
   -moz-margin-start: 1px;
   width: 16px;
   height: 16px;
 }
 
 #engineList treechildren::-moz-tree-row {
-  height: 20px !important;
+  height: 20px;
 }
--- a/build/macosx/mozconfig.leopard
+++ b/build/macosx/mozconfig.leopard
@@ -24,9 +24,9 @@ CXX="$CXX -arch $TARGET_CPU"
 NATIVE_CPU=`$topsrcdir/build/autoconf/config.guess | cut -f1 -d-`
 
 if test "$NATIVE_CPU" != "$TARGET_CPU" ; then
   CROSS_COMPILE=1
 fi
 
 # Note, the version (10) is used by libffi's configure.
 ac_add_options --target=i386-apple-darwin10
-ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk
+ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.6.sdk
--- a/build/macosx/universal/mozconfig.common
+++ b/build/macosx/universal/mozconfig.common
@@ -37,18 +37,17 @@
 mk_add_options MOZ_UNIFY_BDATE=1
 
 mk_add_options MOZ_POSTFLIGHT_ALL+=build/macosx/universal/flight.mk
 
 # Note, the version (10) is used by libffi's configure.
 ac_add_app_options i386 --target=i386-apple-darwin10
 ac_add_app_options x86_64 --target=x86_64-apple-darwin10
 
-ac_add_app_options i386 --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk
-ac_add_app_options x86_64 --with-macos-sdk=/Developer/SDKs/MacOSX10.6.sdk
+ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.6.sdk
 
 . $topsrcdir/build/macosx/common
 
 # $MOZ_BUILD_APP is only defined when sourced by configure.  That's not a
 # problem, because the variables it affects only need to be set for
 # configure.
 if test -n "$MOZ_BUILD_APP" ; then
 if test "$MOZ_BUILD_APP" = "i386" -o "$MOZ_BUILD_APP" = "x86_64"; then
new file mode 100755
--- /dev/null
+++ b/build/unix/build-toolchain/build-gcc.py
@@ -0,0 +1,167 @@
+#!/usr/bin/python
+
+import urllib
+import os
+import os.path
+import shutil
+import tarfile
+import subprocess
+
+def download_uri(uri):
+    fname = uri.split('/')[-1]
+    if (os.path.exists(fname)):
+        return fname
+    urllib.urlretrieve(uri, fname)
+    return fname
+
+def extract(tar, path):
+    t = tarfile.open(tar)
+    t.extractall(path)
+
+def check_run(args):
+    r = subprocess.call(args)
+    assert r == 0
+
+def run_in(path, args):
+    d = os.getcwd()
+    os.chdir(path)
+    check_run(args)
+    os.chdir(d)
+
+def patch(patch, plevel, srcdir):
+    patch = os.path.realpath(patch)
+    check_run(['patch', '-d', srcdir, '-p%s' % plevel, '-i', patch, '--fuzz=0',
+               '-s'])
+
+def build_package(package_source_dir, package_build_dir, configure_args):
+    os.mkdir(package_build_dir)
+    run_in(package_build_dir,
+           ["%s/configure" % package_source_dir] + configure_args)
+    run_in(package_build_dir, ["make", "-j8"])
+    run_in(package_build_dir, ["make", "install"])
+
+def build_binutils(base_dir, binutils_inst_dir):
+    binutils_build_dir = base_dir + '/binutils_build'
+    build_package(binutils_source_dir, binutils_build_dir,
+                  ["--prefix=%s" % binutils_inst_dir])
+
+# FIXME: factor this with build_binutils
+def build_tar(base_dir, tar_inst_dir):
+    tar_build_dir = base_dir + '/tar_build'
+    build_package(tar_source_dir, tar_build_dir,
+                  ["--prefix=%s" % tar_inst_dir])
+
+def build_one_stage(env, stage_dir):
+    old_env = os.environ.copy()
+    os.environ.update(env)
+    os.mkdir(stage_dir)
+
+    lib_inst_dir = stage_dir + '/libinst'
+
+    gmp_build_dir = stage_dir + '/gmp'
+    build_package(gmp_source_dir, gmp_build_dir,
+                  ["--prefix=%s" % lib_inst_dir, "--disable-shared"])
+    mpfr_build_dir = stage_dir + '/mpfr'
+    build_package(mpfr_source_dir, mpfr_build_dir,
+                  ["--prefix=%s" % lib_inst_dir, "--disable-shared",
+                   "--with-gmp=%s" % lib_inst_dir])
+    mpc_build_dir = stage_dir + '/mpc'
+    build_package(mpc_source_dir, mpc_build_dir,
+                  ["--prefix=%s" % lib_inst_dir, "--disable-shared",
+                   "--with-gmp=%s" % lib_inst_dir,
+                   "--with-mpfr=%s" % lib_inst_dir])
+
+    gcc_build_dir = stage_dir + '/gcc'
+    gcc_inst_dir = stage_dir + '/inst'
+    build_package(gcc_source_dir, gcc_build_dir,
+                  ["--prefix=%s" % gcc_inst_dir,
+                   "--enable-__cxa_atexit",
+                   "--with-gmp=%s" % lib_inst_dir,
+                   "--with-mpfr=%s" % lib_inst_dir,
+                   "--with-mpc=%s" % lib_inst_dir,
+                   "--enable-languages=c,c++",
+                   "--disable-bootstrap"])
+    os.environ.clear()
+    os.environ.update(old_env)
+
+def build_tar_package(tar, name, base, directory):
+    name = os.path.realpath(name)
+    run_in(base, [tar, "-cf", name, "--mtime=2012-01-01", "--owner=root",
+                  directory])
+
+##############################################
+
+source_dir = os.path.realpath('src')
+
+def build_source_dir(prefix, version):
+    return source_dir + '/' + prefix + version
+
+binutils_version = "2.21.1"
+tar_version = "1.26"
+gcc_version = "4.5.2"
+mpfr_version = "2.4.2"
+gmp_version = "5.0.1"
+mpc_version = "0.8.1"
+
+binutils_source_uri = "http://ftp.gnu.org/gnu/binutils/binutils-%sa.tar.bz2" % \
+    binutils_version
+tar_source_uri = "http://ftp.gnu.org/gnu/tar/tar-%s.tar.bz2" % \
+    tar_version
+gcc_source_uri = "http://ftp.gnu.org/gnu/gcc/gcc-%s/gcc-%s.tar.bz2" % \
+    (gcc_version, gcc_version)
+mpfr_source_uri = "http://www.mpfr.org/mpfr-%s/mpfr-%s.tar.bz2" % \
+    (mpfr_version, mpfr_version)
+gmp_source_uri = "http://ftp.gnu.org/gnu/gmp/gmp-%s.tar.bz2" % gmp_version
+mpc_source_uri = "http://www.multiprecision.org/mpc/download/mpc-%s.tar.gz" % \
+    mpc_version
+
+binutils_source_tar = download_uri(binutils_source_uri)
+tar_source_tar = download_uri(tar_source_uri)
+mpc_source_tar = download_uri(mpc_source_uri)
+mpfr_source_tar = download_uri(mpfr_source_uri)
+gmp_source_tar = download_uri(gmp_source_uri)
+gcc_source_tar = download_uri(gcc_source_uri)
+
+build_dir = os.path.realpath('build')
+
+binutils_source_dir  = build_source_dir('binutils-', binutils_version)
+tar_source_dir  = build_source_dir('tar-', tar_version)
+mpc_source_dir  = build_source_dir('mpc-', mpc_version)
+mpfr_source_dir = build_source_dir('mpfr-', mpfr_version)
+gmp_source_dir  = build_source_dir('gmp-', gmp_version)
+gcc_source_dir  = build_source_dir('gcc-', gcc_version)
+
+if not os.path.exists(source_dir):
+    os.mkdir(source_dir)
+    extract(binutils_source_tar, source_dir)
+    extract(tar_source_tar, source_dir)
+    extract(mpc_source_tar, source_dir)
+    extract(mpfr_source_tar, source_dir)
+    extract(gmp_source_tar, source_dir)
+    extract(gcc_source_tar, source_dir)
+    patch('plugin_finish_decl.diff', 0, gcc_source_dir)
+    patch('pr49911.diff', 1, gcc_source_dir)
+    patch('r159628-r163231-r171807.patch', 1, gcc_source_dir)
+
+if os.path.exists(build_dir):
+    shutil.rmtree(build_dir)
+os.mkdir(build_dir)
+
+tools_inst_dir = build_dir + '/tools_inst'
+build_binutils(build_dir, tools_inst_dir)
+build_tar(build_dir, tools_inst_dir)
+
+os.environ["AR"] = os.path.realpath('det-ar.sh')
+os.environ["MOZ_AR"] = tools_inst_dir + '/bin/ar'
+os.environ["RANLIB"] = "true"
+
+stage1_dir = build_dir + '/stage1'
+build_one_stage({"CC": "gcc", "CXX" : "g++"}, stage1_dir)
+
+stage1_gcc_inst_dir = stage1_dir + '/inst'
+stage2_dir = build_dir + '/stage2'
+build_one_stage({"CC"  : stage1_gcc_inst_dir + "/bin/gcc",
+                 "CXX" : stage1_gcc_inst_dir + "/bin/g++"}, stage2_dir)
+
+build_tar_package(tools_inst_dir + "/bin/tar",
+                  "toolchain.tar", stage2_dir, "inst")
new file mode 100755
--- /dev/null
+++ b/build/unix/build-toolchain/det-ar.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+shift
+echo $MOZ_AR "crD" "$@"
+exec $MOZ_AR "crD" "$@"
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -143,16 +143,17 @@ MOZ_UPDATER	= @MOZ_UPDATER@
 MOZ_UPDATE_CHANNEL	= @MOZ_UPDATE_CHANNEL@
 MOZ_UPDATE_PACKAGING	= @MOZ_UPDATE_PACKAGING@
 MOZ_DISABLE_PARENTAL_CONTROLS = @MOZ_DISABLE_PARENTAL_CONTROLS@
 NS_ENABLE_TSF = @NS_ENABLE_TSF@
 MOZ_SPELLCHECK = @MOZ_SPELLCHECK@
 MOZ_ANDROID_HISTORY = @MOZ_ANDROID_HISTORY@
 MOZ_WEBSMS_BACKEND = @MOZ_WEBSMS_BACKEND@
 MOZ_JAVA_COMPOSITOR = @MOZ_JAVA_COMPOSITOR@
+MOZ_TOUCH = @MOZ_TOUCH@
 MOZ_PROFILELOCKING = @MOZ_PROFILELOCKING@
 MOZ_FEEDS = @MOZ_FEEDS@
 MOZ_TOOLKIT_SEARCH = @MOZ_TOOLKIT_SEARCH@
 MOZ_PLACES = @MOZ_PLACES@
 MOZ_SAFE_BROWSING = @MOZ_SAFE_BROWSING@
 MOZ_URL_CLASSIFIER = @MOZ_URL_CLASSIFIER@
 MOZ_ZIPWRITER = @MOZ_ZIPWRITER@
 MOZ_OGG = @MOZ_OGG@
--- a/config/createprecomplete.py
+++ b/config/createprecomplete.py
@@ -1,32 +1,34 @@
 # Any copyright is dedicated to the Public Domain.
 # http://creativecommons.org/publicdomain/zero/1.0/
 
-# Creates the precomplete file containing the remove, remove-cc, and rmdir
-# application update instructions which is used to remove files and directories
-# that are no longer present in a complete update. The current working directory
-# is used for the location to enumerate and to create the precomplete file.
+# Creates the precomplete file containing the remove and rmdir application
+# update instructions which is used to remove files and directories that are no
+# longer present in a complete update. The current working directory is used for
+# the location to enumerate and to create the precomplete file.
 
 import sys
 import os
 
 def get_build_entries(root_path):
     """ Iterates through the root_path, creating a list for each file and
-        directory. Excludes any path starting with extensions or distribution.
+        directory. Excludes any path starting with extensions or distribution
+        and paths ending with channel-prefs.js.
     """
     rel_file_path_set = set()
     rel_dir_path_set = set()
     for root, dirs, files in os.walk(root_path):
         for file_name in files:
             parent_dir_rel_path = root[len(root_path)+1:]
             rel_path_file = os.path.join(parent_dir_rel_path, file_name)
             rel_path_file = rel_path_file.replace("\\", "/")
             if not (rel_path_file.startswith("distribution/") or
-                    rel_path_file.startswith("extensions/")):
+                    rel_path_file.startswith("extensions/") or
+                    rel_path_file.endswith("channel-prefs.js")):
                 rel_file_path_set.add(rel_path_file)
 
         for dir_name in dirs:
             parent_dir_rel_path = root[len(root_path)+1:]
             rel_path_dir = os.path.join(parent_dir_rel_path, dir_name)
             rel_path_dir = rel_path_dir.replace("\\", "/")+"/"
             if not (rel_path_dir.startswith("distribution/") or
                     rel_path_dir.startswith("extensions/")):
@@ -35,34 +37,31 @@ def get_build_entries(root_path):
     rel_file_path_list = list(rel_file_path_set)
     rel_file_path_list.sort(reverse=True)
     rel_dir_path_list = list(rel_dir_path_set)
     rel_dir_path_list.sort(reverse=True)
 
     return rel_file_path_list, rel_dir_path_list
 
 def generate_precomplete():
-    """ Creates the precomplete file containing the remove, remove-cc, and rmdir
+    """ Creates the precomplete file containing the remove and rmdir
         application update instructions. The current working directory is used
         for the location to enumerate and to create the precomplete file.
     """
     root_path = os.getcwd()
     # If inside a Mac bundle use the root of the bundle for the path.
     if os.path.basename(root_path) == "MacOS":
         root_path = os.path.abspath(os.path.join(root_path, '../../'))
 
     rel_file_path_list, rel_dir_path_list = get_build_entries(root_path)
     precomplete_file_path = os.path.join(root_path,"precomplete")
     # open in binary mode to prevent OS specific line endings.
     precomplete_file = open(precomplete_file_path, "wb")
     for rel_file_path in rel_file_path_list:
-        if rel_file_path.endswith("channel-prefs.js"):
-            precomplete_file.writelines("remove-cc \""+rel_file_path+"\"\n")
-        else:
-            precomplete_file.writelines("remove \""+rel_file_path+"\"\n")
+        precomplete_file.writelines("remove \""+rel_file_path+"\"\n")
 
     for rel_dir_path in rel_dir_path_list:
         precomplete_file.writelines("rmdir \""+rel_dir_path+"\"\n")
 
     precomplete_file.close()
 
 if __name__ == "__main__":
     generate_precomplete()
--- a/configure.in
+++ b/configure.in
@@ -561,16 +561,21 @@ if test -n "$CROSS_COMPILE" -a "$target"
     AC_CHECK_PROGS(AR, $AR "${target_alias}-ar" "${target}-ar", :)
     MOZ_PATH_PROGS(AS, $AS "${target_alias}-as" "${target}-as", :)
     AC_CHECK_PROGS(LD, $LD "${target_alias}-ld" "${target}-ld", :)
     AC_CHECK_PROGS(STRIP, $STRIP "${target_alias}-strip" "${target}-strip", :)
     AC_CHECK_PROGS(WINDRES, $WINDRES "${target_alias}-windres" "${target}-windres", :)
     AC_DEFINE(CROSS_COMPILE)
 else
     AC_PROG_CC
+    case "$target" in
+    *-mingw*)
+      # Work around the conftest.exe access problem on Windows
+      sleep 1
+    esac
     AC_PROG_CXX
     AC_PROG_RANLIB
     MOZ_PATH_PROGS(AS, $AS as, $CC)
     AC_CHECK_PROGS(AR, ar, :)
     AC_CHECK_PROGS(LD, ld, :)
     AC_CHECK_PROGS(STRIP, strip, :)
     AC_CHECK_PROGS(WINDRES, windres, :)
     if test -z "$HOST_CC"; then
@@ -4892,23 +4897,25 @@ cairo-uikit)
     CXXFLAGS="$CXXFLAGS $TK_CFLAGS"
     LIBXUL_LIBS='$(XPCOM_FROZEN_LDOPTS) $(LIBXUL_DIST)/bin/XUL'
     MOZ_USER_DIR="Mozilla"
     MOZ_FS_LAYOUT=bundle
     ;;
 
 cairo-android)
     AC_DEFINE(MOZ_WIDGET_ANDROID)
+    AC_DEFINE(MOZ_TOUCH)
     MOZ_WIDGET_TOOLKIT=android
     TK_CFLAGS='$(MOZ_CAIRO_CFLAGS)'
     TK_LIBS='$(MOZ_CAIRO_LIBS)'
     MOZ_WEBGL=1
     MOZ_PDF_PRINTING=1
     MOZ_INSTRUMENT_EVENT_LOOP=1
     MOZ_OLD_LINKER=1
+    MOZ_TOUCH=1
     ;;
 
 cairo-gonk)
     AC_DEFINE(MOZ_WIDGET_GONK)
     MOZ_WIDGET_TOOLKIT=gonk
     TK_CFLAGS='$(MOZ_CAIRO_CFLAGS)'
     TK_LIBS='$(MOZ_CAIRO_LIBS)'
     MOZ_WEBGL=1
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -99,16 +99,17 @@
 #include "nsChannelPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsAsyncRedirectVerifyHelper.h"
 #include "jstypedarray.h"
 #include "nsStringBuffer.h"
 #include "nsDOMFile.h"
 #include "nsIFileChannel.h"
 #include "mozilla/Telemetry.h"
+#include "sampler.h"
 
 using namespace mozilla;
 
 #define LOAD_STR "load"
 #define ERROR_STR "error"
 #define ABORT_STR "abort"
 #define LOADSTART_STR "loadstart"
 #define PROGRESS_STR "progress"
@@ -2012,16 +2013,17 @@ nsXMLHttpRequest::OnStartRequest(nsIRequ
 
   return NS_OK;
 }
 
 /* void onStopRequest (in nsIRequest request, in nsISupports ctxt, in nsresult status, in wstring statusArg); */
 NS_IMETHODIMP
 nsXMLHttpRequest::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult status)
 {
+  SAMPLE_LABEL("content", "nsXMLHttpRequest::OnStopRequest");
   if (!IsSameOrBaseChannel(request, mChannel)) {
     return NS_OK;
   }
 
   nsresult rv = NS_OK;
 
   // If we're loading a multipart stream of XML documents, we'll get
   // an OnStopRequest() for the last part in the stream, and then
--- a/content/base/test/test_bug166235.html
+++ b/content/base/test/test_bug166235.html
@@ -16,47 +16,46 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content" style="display: none">
   
 </div>
 <textarea id="input"></textarea>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 166235 **/
-
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+  var Cc = SpecialPowers.wrap(Components).classes;
 
-  var webnav = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                     .getInterface(Components.interfaces.nsIWebNavigation)
+  var webnav = SpecialPowers.wrap(window).QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                                         .getInterface(Components.interfaces.nsIWebNavigation)
 
   var docShell = webnav.QueryInterface(Components.interfaces.nsIDocShell);
 
   var documentViewer = docShell.contentViewer
                                .QueryInterface(Components.interfaces.nsIContentViewerEdit);
 
-  var clipboard = Components.classes["@mozilla.org/widget/clipboard;1"]
-                            .getService(Components.interfaces.nsIClipboard);
+  var clipboard = Cc["@mozilla.org/widget/clipboard;1"]
+                    .getService(Components.interfaces.nsIClipboard);
 
-  var textarea = document.getElementById('input');
+  var textarea = SpecialPowers.wrap(document).getElementById('input');
 
   function copyChildrenToClipboard(id) {
     textarea.blur();
     clipboard.emptyClipboard(1);
     window.getSelection().selectAllChildren(document.getElementById(id));
     documentViewer.copySelection();
 
     is(clipboard.hasDataMatchingFlavors(["text/unicode"], 1,1), true);
     is(clipboard.hasDataMatchingFlavors(["text/html"], 1,1), true);
   }
   function getClipboardData(mime) {
-    var transferable = Components.classes['@mozilla.org/widget/transferable;1']
-                                 .createInstance(Components.interfaces.nsITransferable);
+    var transferable = Cc['@mozilla.org/widget/transferable;1']
+                         .createInstance(Components.interfaces.nsITransferable);
     transferable.addDataFlavor(mime);
     clipboard.getData(transferable, 1);
-    var data = {};
+    var data = SpecialPowers.wrap({});
     transferable.getTransferData(mime, data, {}) ;
     return data;
   }
   function testClipboardValue(mime, expected, test) {
     var data = getClipboardData(mime);
     is (data.value == null ? data.value :
         data.value.QueryInterface(Components.interfaces.nsISupportsString).data,
       expected,
--- a/content/base/test/test_bug375314.html
+++ b/content/base/test/test_bug375314.html
@@ -14,83 +14,79 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 375314 **/
 
-netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-
 var lastContentType = -1;
 const testURL = window.location.href + "/this/is/the/test/url";
-const Cc = Components.classes;
+const Cc = SpecialPowers.wrap(Components).classes;
 const Ci = Components.interfaces;
 
 // Content policy / factory implementation for the test
-var policyID = Components.ID("{b80e19d0-878f-d41b-2654-194714a4115c}");
+var policyID = SpecialPowers.wrap(Components).ID("{b80e19d0-878f-d41b-2654-194714a4115c}");
 var policyName = "@mozilla.org/testpolicy;1";
 var policy = {
   // nsISupports implementation
   QueryInterface: function(iid) {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
+    iid = SpecialPowers.wrap(iid);
     if (iid.equals(Ci.nsISupports) ||
         iid.equals(Ci.nsIFactory) ||
         iid.equals(Ci.nsIContentPolicy))
       return this;
 
-    throw Components.results.NS_ERROR_NO_INTERFACE;
+    throw SpecialPowers.wrap(Components).results.NS_ERROR_NO_INTERFACE;
   },
 
   // nsIFactory implementation
   createInstance: function(outer, iid) {
     return this.QueryInterface(iid);
   },
 
   // nsIContentPolicy implementation
   shouldLoad: function(contentType, contentLocation, requestOrigin, context, mimeTypeGuess, extra) {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
     // Remember last content type seen for the test url
-    if (contentLocation.spec == testURL) {
+    if (SpecialPowers.wrap(contentLocation).spec == testURL) {
       lastContentType = contentType;
       return Ci.nsIContentPolicy.REJECT_REQUEST;
     }
 
     return Ci.nsIContentPolicy.ACCEPT;
   },
 
   shouldProcess: function(contentType, contentLocation, requestOrigin, context, mimeTypeGuess, extra) {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
     return Ci.nsIContentPolicy.ACCEPT;
   }
 }
 
 // Register content policy
-var componentManager = Components.manager
-                                 .QueryInterface(Ci.nsIComponentRegistrar);
+var componentManager = SpecialPowers.wrap(Components).manager
+                                                     .QueryInterface(Ci.nsIComponentRegistrar);
+
 componentManager.registerFactory(policyID, "Test content policy", policyName, policy);
 
 var categoryManager = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
 categoryManager.addCategoryEntry("content-policy", policyName, policyName, false, true);
 
 // Try creating different request types
 var tests = ["SCRIPT", "IMAGE", "STYLESHEET", "OBJECT", "DOCUMENT", "SUBDOCUMENT", "XBL", "XMLHTTPREQUEST"];
 var curTest = -1;
 
 var div;
 
 SimpleTest.waitForExplicitFinish();
 setTimeout(runNextTest, 0);
 
 function runNextTest() {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
   if (curTest >= 0) {
     var type = "TYPE_" + tests[curTest];
     is(lastContentType, Ci.nsIContentPolicy[type], "Content policies triggered for " + type);
 
     if (tests[curTest] == "XBL")
     {
       //XXX Removing binding to work-around a memory leak (bugs 478528, 499735).
@@ -108,17 +104,16 @@ function runNextTest() {
   }
   else {
     // Unregister content policy
     categoryManager.deleteCategoryEntry("content-policy", policyName, false);
 
     setTimeout(function() {
       // Component must be unregistered delayed, otherwise other content
       // policy will not be removed from the category correctly
-      netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
       componentManager.unregisterFactory(policyID, policy);
     }, 0);
 
     SimpleTest.finish();
   }
 }
 
 // Request creating functions
--- a/content/base/test/test_bug422403-1.html
+++ b/content/base/test/test_bug422403-1.html
@@ -18,44 +18,43 @@
 <script class="testbody" type="text/javascript">
 
 
 function loadFileContent(aFile, aCharset) {
     //if(aAsIso == undefined) aAsIso = false;
     if(aCharset == undefined)
         aCharset = 'UTF-8';
 
-    var baseUri = Components.classes['@mozilla.org/network/standard-url;1']
+    var baseUri = SpecialPowers.wrap(Components).classes['@mozilla.org/network/standard-url;1']
                    .createInstance(Components.interfaces.nsIURI);
     baseUri.spec = window.location.href;
 
-    var ios = Components.classes['@mozilla.org/network/io-service;1']
+    var ios = SpecialPowers.wrap(Components).classes['@mozilla.org/network/io-service;1']
             .getService(Components.interfaces.nsIIOService);
     var chann = ios.newChannel(aFile, aCharset, baseUri);
 
     var cis = Components.interfaces.nsIConverterInputStream;
 
-    var inputStream = Components.classes["@mozilla.org/intl/converter-input-stream;1"]
+    var inputStream = SpecialPowers.wrap(Components).classes["@mozilla.org/intl/converter-input-stream;1"]
                        .createInstance(cis);
     inputStream.init(chann.open(), aCharset, 1024, cis.DEFAULT_REPLACEMENT_CHARACTER);
     var str = {}, content = '';
     while (inputStream.readString(4096, str) != 0) {
         content += str.value;
     }
     return content;
 }
 
 
 function testHtmlSerializer_1 () {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   const de = Components.interfaces.nsIDocumentEncoder
-  var encoder = Components.classes["@mozilla.org/layout/documentEncoder;1?type=application/xhtml+xml"]
+  var encoder = SpecialPowers.wrap(Components).classes["@mozilla.org/layout/documentEncoder;1?type=application/xhtml+xml"]
                    .createInstance(Components.interfaces.nsIDocumentEncoder);
 
-  var doc = $("testframe").contentDocument;
+  var doc = SpecialPowers.wrap($("testframe")).contentDocument;
   var out, expected;
 
   // in the following tests, we must use the OutputLFLineBreak flag, to avoid
   // to have the default line break of the platform in the result, so the test
   // can pass on all platform
 
   //------------ no flags
   encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak);
--- a/content/events/public/nsEventNameList.h
+++ b/content/events/public/nsEventNameList.h
@@ -444,39 +444,39 @@ WINDOW_ONLY_EVENT(devicemotion,
                   EventNameType_None,
                   NS_EVENT)
 WINDOW_ONLY_EVENT(deviceorientation,
                   NS_DEVICE_ORIENTATION,
                   EventNameType_None,
                   NS_EVENT)
 
 TOUCH_EVENT(touchstart,
-            NS_USER_DEFINED_EVENT,
+            NS_TOUCH_START,
             EventNameType_All,
-            NS_INPUT_EVENT)
+            NS_TOUCH_EVENT)
 TOUCH_EVENT(touchend,
-            NS_USER_DEFINED_EVENT,
+            NS_TOUCH_END,
             EventNameType_All,
-            NS_INPUT_EVENT)
+            NS_TOUCH_EVENT)
 TOUCH_EVENT(touchmove,
-            NS_USER_DEFINED_EVENT,
+            NS_TOUCH_MOVE,
             EventNameType_All,
-            NS_INPUT_EVENT )
+            NS_TOUCH_EVENT )
 TOUCH_EVENT(touchenter,
-            NS_USER_DEFINED_EVENT,
+            NS_TOUCH_ENTER,
             EventNameType_All,
-            NS_INPUT_EVENT )
+            NS_TOUCH_EVENT )
 TOUCH_EVENT(touchleave,
-            NS_USER_DEFINED_EVENT,
+            NS_TOUCH_LEAVE,
             EventNameType_All,
-            NS_INPUT_EVENT)
+            NS_TOUCH_EVENT)
 TOUCH_EVENT(touchcancel,
-            NS_USER_DEFINED_EVENT,
+            NS_TOUCH_CANCEL,
             EventNameType_All,
-            NS_INPUT_EVENT)
+            NS_TOUCH_EVENT)
 
 DOCUMENT_ONLY_EVENT(readystatechange,
                     NS_READYSTATECHANGE,
                     EventNameType_HTMLXUL,
                     NS_EVENT_NULL)
 
 NON_IDL_EVENT(MozMouseHittest,
               NS_MOUSE_MOZHITTEST,
--- a/content/events/public/nsIPrivateDOMEvent.h
+++ b/content/events/public/nsIPrivateDOMEvent.h
@@ -136,17 +136,17 @@ nsresult
 NS_NewDOMTransitionEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsTransitionEvent* aEvent);
 nsresult
 NS_NewDOMAnimationEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsAnimationEvent* aEvent);
 nsresult
 NS_NewDOMCloseEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsEvent* aEvent);
 nsresult
 NS_NewDOMMozTouchEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsMozTouchEvent* aEvent);
 nsresult
-NS_NewDOMTouchEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsInputEvent *aEvent);
+NS_NewDOMTouchEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsTouchEvent *aEvent);
 nsresult
 NS_NewDOMCustomEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
 nsresult
 NS_NewDOMSmsEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
 nsresult
 NS_NewDOMPopStateEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
 nsresult
 NS_NewDOMHashChangeEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -58,16 +58,18 @@
 #include "nsContentUtils.h"
 #include "nsIURI.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScriptError.h"
 #include "nsDOMPopStateEvent.h"
 #include "mozilla/Preferences.h"
 #include "nsJSUtils.h"
 #include "DictionaryHelpers.h"
+#include "nsLayoutUtils.h"
+#include "nsIScrollableFrame.h"
 
 using namespace mozilla;
 
 static const char* const sEventNames[] = {
   "mousedown", "mouseup", "click", "dblclick", "mouseenter", "mouseleave", "mouseover",
   "mouseout", "MozMouseHittest", "mousemove", "contextmenu", "keydown", "keyup", "keypress",
   "focus", "blur", "load", "popstate", "beforescriptexecute",
   "afterscriptexecute", "beforeunload", "unload",
@@ -105,16 +107,22 @@ static const char* const sEventNames[] =
   "MozRotateGestureStart",
   "MozRotateGestureUpdate",
   "MozRotateGesture",
   "MozTapGesture",
   "MozPressTapGesture",
   "MozTouchDown",
   "MozTouchMove",
   "MozTouchUp",
+  "touchstart",
+  "touchend",
+  "touchmove",
+  "touchcancel",
+  "touchenter",
+  "touchleave",
   "MozScrolledAreaChanged",
   "transitionend",
   "animationstart",
   "animationend",
   "animationiteration",
   "devicemotion",
   "deviceorientation"
 };
@@ -897,16 +905,23 @@ NS_METHOD nsDOMEvent::DuplicatePrivateDa
     case NS_MOZTOUCH_EVENT:
     {
       newEvent = new nsMozTouchEvent(false, msg, nsnull,
                                      static_cast<nsMozTouchEvent*>(mEvent)->streamId);
       NS_ENSURE_TRUE(newEvent, NS_ERROR_OUT_OF_MEMORY);
       isInputEvent = true;
       break;
     }
+    case NS_TOUCH_EVENT:
+    {
+      newEvent = new nsTouchEvent(false, msg, nsnull);
+      NS_ENSURE_TRUE(newEvent, NS_ERROR_OUT_OF_MEMORY);
+      isInputEvent = true;
+      break;
+    }
     default:
     {
       NS_WARNING("Unknown event type!!!");
       return NS_ERROR_FAILURE;
     }
   }
 
   NS_ENSURE_TRUE(newEvent, NS_ERROR_OUT_OF_MEMORY);
@@ -1160,16 +1175,102 @@ nsDOMEvent::PopupAllowedEventsChanged()
 void
 nsDOMEvent::Shutdown()
 {
   if (sPopupAllowedEvents) {
     nsMemory::Free(sPopupAllowedEvents);
   }
 }
 
+nsIntPoint
+nsDOMEvent::GetScreenCoords(nsPresContext* aPresContext,
+                            nsEvent* aEvent,
+                            nsIntPoint aPoint)
+{
+  if (!aEvent || 
+       (aEvent->eventStructType != NS_MOUSE_EVENT &&
+        aEvent->eventStructType != NS_POPUP_EVENT &&
+        aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
+        aEvent->eventStructType != NS_MOZTOUCH_EVENT &&
+        aEvent->eventStructType != NS_TOUCH_EVENT &&
+        aEvent->eventStructType != NS_DRAG_EVENT &&
+        aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT)) {
+    return nsIntPoint(0, 0);
+  }
+
+  nsGUIEvent* guiEvent = static_cast<nsGUIEvent*>(aEvent);
+  if (!guiEvent->widget) {
+    return aPoint;
+  }
+
+  nsIntPoint offset = aPoint + guiEvent->widget->WidgetToScreenOffset();
+  nscoord factor = aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
+  return nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(offset.x * factor),
+                    nsPresContext::AppUnitsToIntCSSPixels(offset.y * factor));
+}
+
+//static
+nsIntPoint
+nsDOMEvent::GetPageCoords(nsPresContext* aPresContext,
+                          nsEvent* aEvent,
+                          nsIntPoint aPoint,
+                          nsIntPoint aDefaultPoint)
+{
+  nsIntPoint pagePoint = nsDOMEvent::GetClientCoords(aPresContext,
+                                                     aEvent,
+                                                     aPoint,
+                                                     aDefaultPoint);
+
+  // If there is some scrolling, add scroll info to client point.
+  if (aPresContext && aPresContext->GetPresShell()) {
+    nsIPresShell* shell = aPresContext->GetPresShell();
+    nsIScrollableFrame* scrollframe = shell->GetRootScrollFrameAsScrollable();
+    if (scrollframe) {
+      nsPoint pt = scrollframe->GetScrollPosition();
+      pagePoint += nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
+                              nsPresContext::AppUnitsToIntCSSPixels(pt.y));
+    }
+  }
+
+  return pagePoint;
+}
+
+// static
+nsIntPoint
+nsDOMEvent::GetClientCoords(nsPresContext* aPresContext,
+                            nsEvent* aEvent,
+                            nsIntPoint aPoint,
+                            nsIntPoint aDefaultPoint)
+{
+  if (!aEvent ||
+      (aEvent->eventStructType != NS_MOUSE_EVENT &&
+       aEvent->eventStructType != NS_POPUP_EVENT &&
+       aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
+       aEvent->eventStructType != NS_MOZTOUCH_EVENT &&
+       aEvent->eventStructType != NS_TOUCH_EVENT &&
+       aEvent->eventStructType != NS_DRAG_EVENT &&
+       aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
+      !aPresContext ||
+      !((nsGUIEvent*)aEvent)->widget) {
+    return aDefaultPoint;
+  }
+
+  nsPoint pt(0, 0);
+  nsIPresShell* shell = aPresContext->GetPresShell();
+  if (!shell) {
+    return nsIntPoint(0, 0);
+  }
+  nsIFrame* rootFrame = shell->GetRootFrame();
+  if (rootFrame)
+    pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, aPoint, rootFrame);
+
+  return nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
+                    nsPresContext::AppUnitsToIntCSSPixels(pt.y));
+}
+
 // To be called ONLY by nsDOMEvent::GetType (which has the additional
 // logic for handling user-defined events).
 // static
 const char* nsDOMEvent::GetEventName(PRUint32 aEventType)
 {
   switch(aEventType) {
   case NS_MOUSE_BUTTON_DOWN:
     return sEventNames[eDOMEvents_mousedown];
@@ -1342,16 +1443,28 @@ const char* nsDOMEvent::GetEventName(PRU
   case NS_SVG_ERROR:
     return sEventNames[eDOMEvents_SVGError];
   case NS_SVG_RESIZE:
     return sEventNames[eDOMEvents_SVGResize];
   case NS_SVG_SCROLL:
     return sEventNames[eDOMEvents_SVGScroll];
   case NS_SVG_ZOOM:
     return sEventNames[eDOMEvents_SVGZoom];
+  case NS_TOUCH_START:
+    return sEventNames[eDOMEvents_touchstart];
+  case NS_TOUCH_MOVE:
+    return sEventNames[eDOMEvents_touchmove];
+  case NS_TOUCH_END:
+    return sEventNames[eDOMEvents_touchend];
+  case NS_TOUCH_ENTER:
+    return sEventNames[eDOMEvents_touchenter];
+  case NS_TOUCH_LEAVE:
+    return sEventNames[eDOMEvents_touchleave];
+  case NS_TOUCH_CANCEL:
+    return sEventNames[eDOMEvents_touchcancel];
   case NS_SMIL_BEGIN:
     return sEventNames[eDOMEvents_beginEvent];
   case NS_SMIL_END:
     return sEventNames[eDOMEvents_endEvent];
   case NS_SMIL_REPEAT:
     return sEventNames[eDOMEvents_repeatEvent];
 #ifdef MOZ_MEDIA
   case NS_LOADSTART:
--- a/content/events/src/nsDOMEvent.h
+++ b/content/events/src/nsDOMEvent.h
@@ -190,16 +190,22 @@ public:
     eDOMEvents_MozRotateGestureStart,
     eDOMEvents_MozRotateGestureUpdate,
     eDOMEvents_MozRotateGesture,
     eDOMEvents_MozTapGesture,
     eDOMEvents_MozPressTapGesture,
     eDOMEvents_MozTouchDown,
     eDOMEvents_MozTouchMove,
     eDOMEvents_MozTouchUp,
+    eDOMEvents_touchstart,
+    eDOMEvents_touchend,
+    eDOMEvents_touchmove,
+    eDOMEvents_touchcancel,
+    eDOMEvents_touchenter,
+    eDOMEvents_touchleave,
     eDOMEvents_MozScrolledAreaChanged,
     eDOMEvents_transitionend,
     eDOMEvents_animationstart,
     eDOMEvents_animationend,
     eDOMEvents_animationiteration,
     eDOMEvents_devicemotion,
     eDOMEvents_deviceorientation
   };
@@ -237,16 +243,27 @@ public:
 
   static PopupControlState GetEventPopupControlState(nsEvent *aEvent);
 
   static void PopupAllowedEventsChanged();
 
   static void Shutdown();
 
   static const char* GetEventName(PRUint32 aEventType);
+  static nsIntPoint GetClientCoords(nsPresContext* aPresContext,
+                                    nsEvent* aEvent,
+                                    nsIntPoint aPoint,
+                                    nsIntPoint aDefaultPoint);
+  static nsIntPoint GetPageCoords(nsPresContext* aPresContext,
+                                  nsEvent* aEvent,
+                                  nsIntPoint aPoint,
+                                  nsIntPoint aDefaultPoint);
+  static nsIntPoint GetScreenCoords(nsPresContext* aPresContext,
+                                    nsEvent* aEvent,
+                                    nsIntPoint aPoint);
 protected:
 
   // Internal helper functions
   nsresult SetEventType(const nsAString& aEventTypeArg);
   already_AddRefed<nsIContent> GetTargetFromFrame();
 
   nsEvent*                    mEvent;
   nsRefPtr<nsPresContext>     mPresContext;
--- a/content/events/src/nsDOMMouseEvent.cpp
+++ b/content/events/src/nsDOMMouseEvent.cpp
@@ -231,41 +231,67 @@ nsDOMMouseEvent::GetRelatedTarget(nsIDOM
     CallQueryInterface(relatedTarget, aRelatedTarget);
   }
   return NS_OK;
 }
 
 NS_METHOD nsDOMMouseEvent::GetScreenX(PRInt32* aScreenX)
 {
   NS_ENSURE_ARG_POINTER(aScreenX);
+#ifdef MOZ_TOUCH
+  *aScreenX = nsDOMEvent::GetScreenCoords(mPresContext,
+                                          mEvent,
+                                          mEvent->refPoint).x;
+#else
   *aScreenX = GetScreenPoint().x;
+#endif
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMMouseEvent::GetScreenY(PRInt32* aScreenY)
 {
   NS_ENSURE_ARG_POINTER(aScreenY);
+#ifdef MOZ_TOUCH
+  *aScreenY = nsDOMEvent::GetScreenCoords(mPresContext,
+                                          mEvent,
+                                          mEvent->refPoint).y;
+#else
   *aScreenY = GetScreenPoint().y;
+#endif
   return NS_OK;
 }
 
 
 NS_METHOD nsDOMMouseEvent::GetClientX(PRInt32* aClientX)
 {
   NS_ENSURE_ARG_POINTER(aClientX);
+#ifdef MOZ_TOUCH
+  *aClientX = nsDOMEvent::GetClientCoords(mPresContext,
+                                          mEvent,
+                                          mEvent->refPoint,
+                                          mClientPoint).x;
+#else
   *aClientX = GetClientPoint().x;
+#endif
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMMouseEvent::GetClientY(PRInt32* aClientY)
 {
   NS_ENSURE_ARG_POINTER(aClientY);
+#ifdef MOZ_TOUCH
+  *aClientY = nsDOMEvent::GetClientCoords(mPresContext,
+                                          mEvent,
+                                          mEvent->refPoint,
+                                          mClientPoint).y;
+#else
   *aClientY = GetClientPoint().y;
+#endif
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMMouseEvent::GetAltKey(bool* aIsDown)
 {
   NS_ENSURE_ARG_POINTER(aIsDown);
   *aIsDown = ((nsInputEvent*)mEvent)->isAlt;
--- a/content/events/src/nsDOMTouchEvent.cpp
+++ b/content/events/src/nsDOMTouchEvent.cpp
@@ -37,16 +37,17 @@
 
 #include "nsDOMTouchEvent.h"
 #include "nsGUIEvent.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIClassInfo.h"
 #include "nsIXPCScriptable.h"
 #include "nsContentUtils.h"
 #include "mozilla/Preferences.h"
+#include "nsPresContext.h"
 
 using namespace mozilla;
 
 DOMCI_DATA(Touch, nsDOMTouch)
 
 NS_IMPL_CYCLE_COLLECTION_1(nsDOMTouch, mTarget)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMTouch)
@@ -70,66 +71,66 @@ nsDOMTouch::GetTarget(nsIDOMEventTarget*
 {
   NS_IF_ADDREF(*aTarget = mTarget);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMTouch::GetScreenX(PRInt32* aScreenX)
 {
-  *aScreenX = mScreenX;
+  *aScreenX = mScreenPoint.x;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMTouch::GetScreenY(PRInt32* aScreenY)
 {
-  *aScreenY = mScreenY;
+  *aScreenY = mScreenPoint.y;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMTouch::GetClientX(PRInt32* aClientX)
 {
-  *aClientX = mClientX;
+  *aClientX = mClientPoint.x;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMTouch::GetClientY(PRInt32* aClientY)
 {
-  *aClientY = mClientY;
+  *aClientY = mClientPoint.y;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMTouch::GetPageX(PRInt32* aPageX)
 {
-  *aPageX = mPageX;
+  *aPageX = mPagePoint.x;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMTouch::GetPageY(PRInt32* aPageY)
 {
-  *aPageY = mPageY;
+  *aPageY = mPagePoint.y;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMTouch::GetRadiusX(PRInt32* aRadiusX)
 {
-  *aRadiusX = mRadiusX;
+  *aRadiusX = mRadius.x;
   return NS_OK;
 }
                                              
 NS_IMETHODIMP
 nsDOMTouch::GetRadiusY(PRInt32* aRadiusY)
 {
-  *aRadiusY = mRadiusY;
+  *aRadiusY = mRadius.y;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMTouch::GetRotationAngle(float* aRotationAngle)
 {
   *aRotationAngle = mRotationAngle;
   return NS_OK;
@@ -137,88 +138,114 @@ nsDOMTouch::GetRotationAngle(float* aRot
 
 NS_IMETHODIMP
 nsDOMTouch::GetForce(float* aForce)
 {
   *aForce = mForce;
   return NS_OK;
 }
 
+bool
+nsDOMTouch::Equals(nsIDOMTouch* aTouch)
+{
+  float force;
+  float orientation;
+  PRInt32 radiusX, radiusY;
+  aTouch->GetForce(&force);
+  aTouch->GetRotationAngle(&orientation);
+  aTouch->GetRadiusX(&radiusX);
+  aTouch->GetRadiusY(&radiusY);
+  return mRefPoint != aTouch->mRefPoint ||
+         (mForce != force) ||
+         (mRotationAngle != orientation) ||
+         (mRadius.x != radiusX) || (mRadius.y != radiusY);
+}
+
 // TouchList
+nsDOMTouchList::nsDOMTouchList(nsTArray<nsCOMPtr<nsIDOMTouch> > &aTouches)
+{
+  mPoints.AppendElements(aTouches);
+}
 
 DOMCI_DATA(TouchList, nsDOMTouchList)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMTouchList)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMTouchList)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsIDOMTouchList)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(TouchList)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMTouchList)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mPoints)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_OF_NSCOMPTR(mPoints)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMTouchList)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mPoints)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mPoints)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMTouchList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMTouchList)
 
 NS_IMETHODIMP
 nsDOMTouchList::GetLength(PRUint32* aLength)
 {
-  *aLength = mPoints.Count();
+  *aLength = mPoints.Length();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMTouchList::Item(PRUint32 aIndex, nsIDOMTouch** aRetVal)
 {
-  NS_IF_ADDREF(*aRetVal = mPoints.SafeObjectAt(aIndex));
+  NS_IF_ADDREF(*aRetVal = mPoints.SafeElementAt(aIndex, nsnull));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMTouchList::IdentifiedTouch(PRInt32 aIdentifier, nsIDOMTouch** aRetVal)
 {
   *aRetVal = nsnull;
-  for (PRInt32 i = 0; i < mPoints.Count(); ++i) {
+  for (PRUint32 i = 0; i < mPoints.Length(); ++i) {
     nsCOMPtr<nsIDOMTouch> point = mPoints[i];
     PRInt32 identifier;
     if (point && NS_SUCCEEDED(point->GetIdentifier(&identifier)) &&
         aIdentifier == identifier) {
       point.swap(*aRetVal);
       break;
     }
   }
   return NS_OK;
 }
 
 // TouchEvent
 
 nsDOMTouchEvent::nsDOMTouchEvent(nsPresContext* aPresContext,
-                                 nsInputEvent* aEvent)
+                                 nsTouchEvent* aEvent)
   : nsDOMUIEvent(aPresContext, aEvent ? aEvent :
-                                        new nsInputEvent(false, 0, nsnull))
+                                        new nsTouchEvent(false, 0, nsnull))
 {
   if (aEvent) {
     mEventIsInternal = false;
+
+    for (PRUint32 i = 0; i < aEvent->touches.Length(); ++i) {
+      nsIDOMTouch *touch = aEvent->touches[i];
+      nsDOMTouch *domtouch = static_cast<nsDOMTouch*>(touch);
+      domtouch->InitializePoints(mPresContext, aEvent);
+    }
   } else {
     mEventIsInternal = true;
     mEvent->time = PR_Now();
   }
 }
 
 nsDOMTouchEvent::~nsDOMTouchEvent()
 {
   if (mEventIsInternal && mEvent) {
-    delete static_cast<nsInputEvent*>(mEvent);
+    delete static_cast<nsTouchEvent*>(mEvent);
     mEvent = nsnull;
   }
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMTouchEvent)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMTouchEvent, nsDOMUIEvent)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTouches)
@@ -252,48 +279,110 @@ nsDOMTouchEvent::InitTouchEvent(const ns
                                 bool aCtrlKey,
                                 bool aAltKey,
                                 bool aShiftKey,
                                 bool aMetaKey,
                                 nsIDOMTouchList* aTouches,
                                 nsIDOMTouchList* aTargetTouches,
                                 nsIDOMTouchList* aChangedTouches)
 {
-  nsresult rv = nsDOMUIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, aDetail);
+  nsresult rv = nsDOMUIEvent::InitUIEvent(aType,
+                                          aCanBubble,
+                                          aCancelable,
+                                          aView,
+                                          aDetail);
   NS_ENSURE_SUCCESS(rv, rv);
 
   static_cast<nsInputEvent*>(mEvent)->isControl = aCtrlKey;
   static_cast<nsInputEvent*>(mEvent)->isAlt = aAltKey;
   static_cast<nsInputEvent*>(mEvent)->isShift = aShiftKey;
   static_cast<nsInputEvent*>(mEvent)->isMeta = aMetaKey;
   mTouches = aTouches;
   mTargetTouches = aTargetTouches;
   mChangedTouches = aChangedTouches;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMTouchEvent::GetTouches(nsIDOMTouchList** aTouches)
 {
-  NS_IF_ADDREF(*aTouches = mTouches);
-  return NS_OK;
+  NS_ENSURE_ARG_POINTER(aTouches);
+  NS_ENSURE_STATE(mEvent);
+  nsRefPtr<nsDOMTouchList> t;
+
+  if (mTouches) {
+    return CallQueryInterface(mTouches, aTouches);
+  }
+
+  nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(mEvent);
+  if (mEvent->message == NS_TOUCH_END || mEvent->message == NS_TOUCH_CANCEL) {
+    // for touchend events, remove any changed touches from the touches array
+    nsTArray<nsCOMPtr<nsIDOMTouch> > unchangedTouches;
+    nsTArray<nsCOMPtr<nsIDOMTouch> > touches = touchEvent->touches;
+    for (PRUint32 i = 0; i < touches.Length(); ++i) {
+      if (!touches[i]->mChanged) {
+        unchangedTouches.AppendElement(touches[i]);
+      }
+    }
+    t = new nsDOMTouchList(unchangedTouches);
+  } else {
+    t = new nsDOMTouchList(touchEvent->touches);
+  }
+  mTouches = t;
+  return CallQueryInterface(mTouches, aTouches);
 }
 
 NS_IMETHODIMP
 nsDOMTouchEvent::GetTargetTouches(nsIDOMTouchList** aTargetTouches)
 {
-  NS_IF_ADDREF(*aTargetTouches = mTargetTouches);
-  return NS_OK;
+  NS_ENSURE_ARG_POINTER(aTargetTouches);
+  NS_ENSURE_STATE(mEvent);
+
+  if (mTargetTouches) {
+    return CallQueryInterface(mTargetTouches, aTargetTouches);
+  }
+
+  nsTArray<nsCOMPtr<nsIDOMTouch> > targetTouches;
+  nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(mEvent);
+  nsTArray<nsCOMPtr<nsIDOMTouch> > touches = touchEvent->touches;
+  for (PRUint32 i = 0; i < touches.Length(); ++i) {
+    // for touchend/cancel events, don't append to the target list if this is a
+    // touch that is ending
+    if ((mEvent->message != NS_TOUCH_END &&
+         mEvent->message != NS_TOUCH_CANCEL) || !touches[i]->mChanged) {
+      nsIDOMEventTarget* targetPtr = touches[i]->GetTarget();
+      if (targetPtr == mEvent->target) {
+        targetTouches.AppendElement(touches[i]);
+      }
+    }
+  }
+  mTargetTouches = new nsDOMTouchList(targetTouches);
+  return CallQueryInterface(mTargetTouches, aTargetTouches);
 }
 
 NS_IMETHODIMP
 nsDOMTouchEvent::GetChangedTouches(nsIDOMTouchList** aChangedTouches)
 {
-  NS_IF_ADDREF(*aChangedTouches = mChangedTouches);
-  return NS_OK;
+  NS_ENSURE_ARG_POINTER(aChangedTouches);
+  NS_ENSURE_STATE(mEvent);
+
+  if (mChangedTouches) {
+    return CallQueryInterface(mChangedTouches, aChangedTouches);
+  }
+
+  nsTArray<nsCOMPtr<nsIDOMTouch> > changedTouches;
+  nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(mEvent);
+  nsTArray<nsCOMPtr<nsIDOMTouch> > touches = touchEvent->touches;
+  for (PRUint32 i = 0; i < touches.Length(); ++i) {
+    if (touches[i]->mChanged) {
+      changedTouches.AppendElement(touches[i]);
+    }
+  }
+  mChangedTouches = new nsDOMTouchList(changedTouches);
+  return CallQueryInterface(mChangedTouches, aChangedTouches);
 }
 
 NS_IMETHODIMP
 nsDOMTouchEvent::GetAltKey(bool* aAltKey)
 {
   *aAltKey = static_cast<nsInputEvent*>(mEvent)->isAlt;
   return NS_OK;
 }
@@ -332,14 +421,14 @@ nsDOMTouchEvent::PrefEnabled()
     }
   }
   return sPrefValue;
 }
 
 nsresult
 NS_NewDOMTouchEvent(nsIDOMEvent** aInstancePtrResult,
                     nsPresContext* aPresContext,
-                    nsInputEvent *aEvent)
+                    nsTouchEvent *aEvent)
 {
   nsDOMTouchEvent* it = new nsDOMTouchEvent(aPresContext, aEvent);
 
   return CallQueryInterface(it, aInstancePtrResult);
 }
--- a/content/events/src/nsDOMTouchEvent.h
+++ b/content/events/src/nsDOMTouchEvent.h
@@ -35,89 +35,131 @@
  *
  * ***** END LICENSE BLOCK ***** */
 #ifndef nsDOMTouchEvent_h_
 #define nsDOMTouchEvent_h_
 
 #include "nsDOMUIEvent.h"
 #include "nsIDOMTouchEvent.h"
 #include "nsString.h"
-#include "nsCOMArray.h"
+#include "nsTArray.h"
 
 class nsDOMTouch : public nsIDOMTouch
 {
 public:
   nsDOMTouch(nsIDOMEventTarget* aTarget,
              PRInt32 aIdentifier,
              PRInt32 aPageX,
              PRInt32 aPageY,
              PRInt32 aScreenX,
              PRInt32 aScreenY,
              PRInt32 aClientX,
              PRInt32 aClientY,
              PRInt32 aRadiusX,
              PRInt32 aRadiusY,
              float aRotationAngle,
              float aForce)
-  : mTarget(aTarget),
-    mIdentifier(aIdentifier),
-    mPageX(aPageX),
-    mPageY(aPageY),
-    mScreenX(aScreenX),
-    mScreenY(aScreenY),
-    mClientX(aClientX),
-    mClientY(aClientY),
-    mRadiusX(aRadiusX),
-    mRadiusY(aRadiusY),
-    mRotationAngle(aRotationAngle),
-    mForce(aForce)
-    {}
+    {
+      mTarget = aTarget;
+      mIdentifier = aIdentifier;
+      mPagePoint = nsIntPoint(aPageX, aPageY);
+      mScreenPoint = nsIntPoint(aScreenX, aScreenY);
+      mClientPoint = nsIntPoint(aClientX, aClientY);
+      mRefPoint = nsIntPoint(0, 0);
+      mPointsInitialized = true;
+      mRadius.x = aRadiusX;
+      mRadius.y = aRadiusY;
+      mRotationAngle = aRotationAngle;
+      mForce = aForce;
+
+      mChanged = false;
+      mMessage = 0;
+    }
+  nsDOMTouch(PRInt32 aIdentifier,
+             nsIntPoint aPoint,
+             nsIntPoint aRadius,
+             float aRotationAngle,
+             float aForce)
+    {
+      mIdentifier = aIdentifier;
+      mPagePoint = nsIntPoint(0, 0);
+      mScreenPoint = nsIntPoint(0, 0);
+      mClientPoint = nsIntPoint(0, 0);
+      mRefPoint = aPoint;
+      mPointsInitialized = false;
+      mRadius = aRadius;
+      mRotationAngle = aRotationAngle;
+      mForce = aForce;
+
+      mChanged = false;
+      mMessage = 0;
+    }
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMTouch)
   NS_DECL_NSIDOMTOUCH
+  void InitializePoints(nsPresContext* aPresContext, nsEvent* aEvent)
+  {
+    if (mPointsInitialized) {
+      return;
+    }
+    mClientPoint = nsDOMEvent::GetClientCoords(aPresContext,
+                                               aEvent,
+                                               mRefPoint,
+                                               mClientPoint);
+    mPagePoint = nsDOMEvent::GetPageCoords(aPresContext,
+                                           aEvent,
+                                           mRefPoint,
+                                           mClientPoint);
+    mScreenPoint = nsDOMEvent::GetScreenCoords(aPresContext, aEvent, mRefPoint);
+    mPointsInitialized = true;
+  }
+  void SetTarget(nsIDOMEventTarget *aTarget)
+  {
+    mTarget = aTarget;
+  }
+  bool Equals(nsIDOMTouch* aTouch);
 protected:
-  nsCOMPtr<nsIDOMEventTarget> mTarget;
+  bool mPointsInitialized;
   PRInt32 mIdentifier;
-  PRInt32 mPageX;
-  PRInt32 mPageY;
-  PRInt32 mScreenX;
-  PRInt32 mScreenY;
-  PRInt32 mClientX;
-  PRInt32 mClientY;
-  PRInt32 mRadiusX;
-  PRInt32 mRadiusY;
+  nsIntPoint mPagePoint;
+  nsIntPoint mClientPoint;
+  nsIntPoint mScreenPoint;
+  nsIntPoint mRadius;
   float mRotationAngle;
   float mForce;
 };
 
 class nsDOMTouchList : public nsIDOMTouchList
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMTouchList)
   NS_DECL_NSIDOMTOUCHLIST
+
+  nsDOMTouchList() { }
+  nsDOMTouchList(nsTArray<nsCOMPtr<nsIDOMTouch> > &aTouches);
   
   void Append(nsIDOMTouch* aPoint)
   {
-    mPoints.AppendObject(aPoint);
+    mPoints.AppendElement(aPoint);
   }
 
   nsIDOMTouch* GetItemAt(PRUint32 aIndex)
   {
-    return mPoints.SafeObjectAt(aIndex);
+    return mPoints.SafeElementAt(aIndex, nsnull);
   }
 protected:
-  nsCOMArray<nsIDOMTouch> mPoints;
+  nsTArray<nsCOMPtr<nsIDOMTouch> > mPoints;
 };
 
 class nsDOMTouchEvent : public nsDOMUIEvent,
                         public nsIDOMTouchEvent
 {
 public:
-  nsDOMTouchEvent(nsPresContext* aPresContext, nsInputEvent* aEvent);
+  nsDOMTouchEvent(nsPresContext* aPresContext, nsTouchEvent* aEvent);
   virtual ~nsDOMTouchEvent();
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMTouchEvent, nsDOMUIEvent)
   NS_DECL_NSIDOMTOUCHEVENT
 
   NS_FORWARD_TO_NSDOMUIEVENT
 
--- a/content/events/src/nsDOMUIEvent.cpp
+++ b/content/events/src/nsDOMUIEvent.cpp
@@ -239,25 +239,47 @@ nsDOMUIEvent::GetPagePoint()
 
   return pagePoint;
 }
 
 NS_IMETHODIMP
 nsDOMUIEvent::GetPageX(PRInt32* aPageX)
 {
   NS_ENSURE_ARG_POINTER(aPageX);
+#ifdef MOZ_TOUCH
+  if (mPrivateDataDuplicated) {
+    *aPageX = mPagePoint.x;
+  } else {
+    *aPageX = nsDOMEvent::GetPageCoords(mPresContext,
+                                        mEvent,
+                                        mEvent->refPoint,
+                                        mClientPoint).x;
+  }
+#else
   *aPageX = GetPagePoint().x;
+#endif
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMUIEvent::GetPageY(PRInt32* aPageY)
 {
   NS_ENSURE_ARG_POINTER(aPageY);
+#ifdef MOZ_TOUCH
+  if (mPrivateDataDuplicated) {
+    *aPageY = mPagePoint.y;
+  } else {
+    *aPageY = nsDOMEvent::GetPageCoords(mPresContext,
+                                        mEvent,
+                                        mEvent->refPoint,
+                                        mClientPoint).y;
+  }
+#else
   *aPageY = GetPagePoint().y;
+#endif
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMUIEvent::GetWhich(PRUint32* aWhich)
 {
   return Which(aWhich);
 }
@@ -333,16 +355,17 @@ nsDOMUIEvent::SetCancelBubble(bool aCanc
 nsIntPoint
 nsDOMUIEvent::GetLayerPoint()
 {
   if (!mEvent ||
       (mEvent->eventStructType != NS_MOUSE_EVENT &&
        mEvent->eventStructType != NS_POPUP_EVENT &&
        mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
        mEvent->eventStructType != NS_MOZTOUCH_EVENT &&
+       mEvent->eventStructType != NS_TOUCH_EVENT &&
        mEvent->eventStructType != NS_DRAG_EVENT &&
        mEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
       !mPresContext ||
       mEventIsInternal) {
     return mLayerPoint;
   }
   // XXX I'm not really sure this is correct; it's my best shot, though
   nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget();
@@ -385,21 +408,37 @@ nsDOMUIEvent::GetIsChar(bool* aIsChar)
       *aIsChar = false;
       return NS_OK;
   }
 }
 
 NS_METHOD
 nsDOMUIEvent::DuplicatePrivateData()
 {
+#ifdef MOZ_TOUCH
+  mClientPoint = nsDOMEvent::GetClientCoords(mPresContext,
+                                             mEvent,
+                                             mEvent->refPoint,
+                                             mClientPoint);
+  mLayerPoint = GetLayerPoint();
+  mPagePoint = nsDOMEvent::GetPageCoords(mPresContext,
+                                         mEvent,
+                                         mEvent->refPoint,
+                                         mClientPoint);
+  // GetScreenPoint converts mEvent->refPoint to right coordinates.
+  nsIntPoint screenPoint = nsDOMEvent::GetScreenCoords(mPresContext,
+                                                       mEvent,
+                                                       mEvent->refPoint);
+#else
   mClientPoint = GetClientPoint();
   mLayerPoint = GetLayerPoint();
   mPagePoint = GetPagePoint();
   // GetScreenPoint converts mEvent->refPoint to right coordinates.
   nsIntPoint screenPoint = GetScreenPoint();
+#endif
   nsresult rv = nsDOMEvent::DuplicatePrivateData();
   if (NS_SUCCEEDED(rv)) {
     mEvent->refPoint = screenPoint;
   }
   return rv;
 }
 
 void
--- a/content/events/src/nsDOMUIEvent.h
+++ b/content/events/src/nsDOMUIEvent.h
@@ -63,18 +63,18 @@ public:
   NS_FORWARD_TO_NSDOMEVENT
 
   NS_FORWARD_NSIDOMNSEVENT(nsDOMEvent::)
 
   virtual nsresult InitFromCtor(const nsAString& aType,
                                 JSContext* aCx, jsval* aVal);
 protected:
   // Internal helper functions
+  nsIntPoint GetScreenPoint();
   nsIntPoint GetClientPoint();
-  nsIntPoint GetScreenPoint();
   nsIntPoint GetLayerPoint();
   nsIntPoint GetPagePoint();
 
   // Allow specializations.
   virtual nsresult Which(PRUint32* aWhich)
   {
     NS_ENSURE_ARG_POINTER(aWhich);
     // Usually we never reach here, as this is reimplemented for mouse and keyboard events.
--- a/content/events/src/nsEventDispatcher.cpp
+++ b/content/events/src/nsEventDispatcher.cpp
@@ -803,16 +803,19 @@ nsEventDispatcher::CreateEvent(nsPresCon
       return NS_NewDOMCommandEvent(aDOMEvent, aPresContext,
                                    static_cast<nsCommandEvent*>(aEvent));
     case NS_SIMPLE_GESTURE_EVENT:
       return NS_NewDOMSimpleGestureEvent(aDOMEvent, aPresContext,
                                          static_cast<nsSimpleGestureEvent*>(aEvent));
     case NS_MOZTOUCH_EVENT:
       return NS_NewDOMMozTouchEvent(aDOMEvent, aPresContext,
                                     static_cast<nsMozTouchEvent*>(aEvent));
+    case NS_TOUCH_EVENT:
+      return NS_NewDOMTouchEvent(aDOMEvent, aPresContext,
+                                 static_cast<nsTouchEvent*>(aEvent));
     case NS_TRANSITION_EVENT:
       return NS_NewDOMTransitionEvent(aDOMEvent, aPresContext,
                                       static_cast<nsTransitionEvent*>(aEvent));
     case NS_ANIMATION_EVENT:
       return NS_NewDOMAnimationEvent(aDOMEvent, aPresContext,
                                      static_cast<nsAnimationEvent*>(aEvent));
     }
 
--- a/content/events/test/Makefile.in
+++ b/content/events/test/Makefile.in
@@ -125,16 +125,22 @@ endif
 
 # bug 565245
 ifneq (Linux,$(OS_ARCH))
 _TEST_FILES += \
 		test_bug493251.html \
 		$(NULL)
 endif
 
+ifeq (android,$(MOZ_WIDGET_TOOLKIT))
+_TEST_FILES += \
+		test_bug603008.html \
+		$(NULL)
+endif
+
 _CHROME_FILES = \
 		test_bug336682_2.xul \
 		test_bug336682.js \
 		test_bug350471.xul \
 		test_bug586961.xul \
 		test_bug415498.xul \
 		bug415498-doc1.html \
 		bug415498-doc2.html \
new file mode 100644
--- /dev/null
+++ b/content/events/test/test_bug603008.html
@@ -0,0 +1,524 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=508906
+-->
+<head>
+  <title>Test for Bug 603008</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=508906">Mozilla Bug 603008</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script class="testbody" type="application/javascript;version=1.8">
+
+/** Test for Bug 306008 - Touch* Events **/
+
+let tests = [], testTarget, parent;
+
+let touch = {
+  id: 0,
+  point: {x: 0, y: 0},
+  radius: {x: 0, y: 0},
+  rotation: 0,
+  force: 0.5,
+  target: null
+}
+
+function nextTest() {
+  if (tests.length)
+    SimpleTest.executeSoon(tests.shift());
+}
+
+function random() {
+  return Math.floor(Math.random() * 100);
+}
+
+function checkEvent(aFakeEvent) {
+  return function(aEvent) {
+    is(aFakeEvent.ctrlKey, aEvent.ctrlKey, "Correct ctrlKey");
+    is(aFakeEvent.altKey, aEvent.altKey, "Correct altKey");
+    is(aFakeEvent.shiftKey, aEvent.shiftKey, "Correct shiftKey");
+    is(aFakeEvent.metaKey, aEvent.metaKey, "Correct metaKey");
+    checkTouches(aFakeEvent.touches, aEvent.touches);
+    checkTouches(aFakeEvent.targetTouches, aEvent.targetTouches);
+    checkTouches(aFakeEvent.changedTouches, aEvent.changedTouches);
+  }
+}
+
+function checkTouches(aTouches1, aTouches2) {
+  is(aTouches1.length, aTouches2.length, "Correct touches length");
+  for (var i = 0; i < aTouches1.length; i++) {
+    checkTouch(aTouches1[i], aTouches2[i]);
+  }
+}
+
+function checkTouch(aFakeTouch, aTouch) {
+  is(aFakeTouch.identifier, aTouch.identifier, "Touch has correct identifier");
+  is(aFakeTouch.target, aTouch.target, "Touch has correct target");
+  is(aFakeTouch.page.x, aTouch.pageX, "Touch has correct pageX");
+  is(aFakeTouch.page.y, aTouch.pageY, "Touch has correct pageY");
+  is(aFakeTouch.page.x + Math.round(window.mozInnerScreenX), aTouch.screenX, "Touch has correct screenX");
+  is(aFakeTouch.page.y + Math.round(window.mozInnerScreenY), aTouch.screenY, "Touch has correct screenY");
+  is(aFakeTouch.page.x, aTouch.clientX, "Touch has correct clientX");
+  is(aFakeTouch.page.y, aTouch.clientY, "Touch has correct clientY");
+  is(aFakeTouch.radius.x, aTouch.radiusX, "Touch has correct radiusX");
+  is(aFakeTouch.radius.y, aTouch.radiusY, "Touch has correct radiusY");
+  is(aFakeTouch.rotationAngle, aTouch.rotationAngle, "Touch has correct rotationAngle");
+  is(aFakeTouch.force, aTouch.force, "Touch has correct force");
+}
+
+function sendTouchEvent(windowUtils, aType, aEvent, aModifiers) {
+  var ids = [], xs=[], ys=[], rxs = [], rys = [],
+      rotations = [], forces = [];
+
+  for each (var touchType in ["touches", "changedTouches", "targetTouches"]) {
+    for (var i = 0; i < aEvent[touchType].length; i++) {
+      if (ids.indexOf(aEvent[touchType][i].identifier) == -1) {
+        ids.push(aEvent[touchType][i].identifier);
+        xs.push(aEvent[touchType][i].page.x);
+        ys.push(aEvent[touchType][i].page.y);
+        rxs.push(aEvent[touchType][i].radius.x);
+        rys.push(aEvent[touchType][i].radius.y);
+        rotations.push(aEvent[touchType][i].rotationAngle);
+        forces.push(aEvent[touchType][i].force);
+      }
+    }
+  }
+  return windowUtils.sendTouchEvent(aType,
+                                    ids, xs, ys, rxs, rys,
+                                    rotations, forces,
+                                    ids.length, aModifiers, 0);
+}
+
+function touchEvent(aOptions) {
+  if (!aOptions) {
+    aOptions = {};
+  }
+  this.ctrlKey = aOptions.ctrlKey || false;
+  this.altKey = aOptions.altKey || false;
+  this.shiftKey = aOptions.shiftKey || false;
+  this.metaKey = aOptions.metaKey || false;
+  this.touches = aOptions.touches || [];
+  this.targetTouches = aOptions.targetTouches || [];
+  this.changedTouches = aOptions.changedTouches || [];
+}
+
+function testtouch(aOptions) {
+  if (!aOptions)
+    aOptions = {};
+  this.identifier = aOptions.identifier || 0;
+  this.target = aOptions.target || 0;
+  this.page = aOptions.page || {x: 0, y: 0};
+  this.radius = aOptions.radius || {x: 0, y: 0};
+  this.rotationAngle = aOptions.rotationAngle || 0;
+  this.force = aOptions.force || 1;
+}
+
+function testSingleTouch(name) {
+  let cwu = SpecialPowers.getDOMWindowUtils(window);
+  let target = document.getElementById("testTarget");
+  let target2 = document.getElementById("testTarget2");
+  let bcr = target.getBoundingClientRect();
+  let bcr2 = target2.getBoundingClientRect();
+
+  let touch1 = new testtouch({
+    page: {x: Math.round(bcr.left + bcr.width/2),
+           y: Math.round(bcr.top  + bcr.height/2)},
+    target: target
+  });
+  let event = new touchEvent({
+    touches: [touch1],
+    targetTouches: [touch1],
+    changedTouches: [touch1]
+  });
+
+  // test touchstart event fires correctly
+  var checkFunction = checkEvent(event);
+  window.addEventListener("touchstart", checkFunction, false);
+  sendTouchEvent(cwu, "touchstart", event, 0);
+  window.removeEventListener("touchstart", checkFunction, false);
+
+  // test touchmove event fires correctly
+  event.touches[0].page.x -= 1;
+  event.targetTouches[0].page.x -= 1;
+  event.changedTouches[0].page.x -= 1;
+  checkFunction = checkEvent(event);
+  window.addEventListener("touchmove", checkFunction, false);
+  sendTouchEvent(cwu, "touchmove", event, 0);
+  window.removeEventListener("touchmove", checkFunction, false);
+
+  // test touchend event fires correctly
+  event.touches = [];
+  event.targetTouches = [];
+  checkFunction = checkEvent(event);
+  window.addEventListener("touchend", checkFunction, false);
+  sendTouchEvent(cwu, "touchend", event, 0);
+  window.removeEventListener("touchend", checkFunction, false);
+
+  nextTest();
+}
+
+function testSingleTouch2(name) {
+  // firing a touchstart that includes only one touch will evict any touches in the queue with touchend messages
+  let cwu = SpecialPowers.getDOMWindowUtils(window);
+  let target = document.getElementById("testTarget");
+  let target2 = document.getElementById("testTarget2");
+  let bcr = target.getBoundingClientRect();
+  let bcr2 = target2.getBoundingClientRect();
+
+  let touch1 = new testtouch({
+    identifier: 0,
+    page: {x: Math.round(bcr.left + bcr.width/2),
+           y: Math.round(bcr.top  + bcr.height/2)},
+    target: target
+  });
+  let event1 = new touchEvent({
+    touches: [touch1],
+    targetTouches: [touch1],
+    changedTouches: [touch1]
+  });
+  let touch2 = new testtouch({
+    identifier: 1,
+    page: {x: Math.round(bcr2.left + bcr2.width/2),
+           y: Math.round(bcr2.top  + bcr2.height/2)},
+    target: target2
+  });
+  let event2 = new touchEvent({
+    touches: [touch2],
+    targetTouches: [touch2],
+    changedTouches: [touch2]
+  });
+
+  // test touchstart event fires correctly
+  var checkFunction1 = checkEvent(event1);
+  window.addEventListener("touchstart", checkFunction1, false);
+  sendTouchEvent(cwu, "touchstart", event1, 0);
+  window.removeEventListener("touchstart", checkFunction1, false);
+
+  event1.touches = [];
+  event1.targetTouches = [];
+  checkFunction1 = checkEvent(event1);
+  var checkFunction2 = checkEvent(event2);
+
+  window.addEventListener("touchend", checkFunction1, false);
+  window.addEventListener("touchstart", checkFunction2, false);
+  sendTouchEvent(cwu, "touchstart", event2, 0);
+  window.removeEventListener("touchend", checkFunction1, false);
+  window.removeEventListener("touchstart", checkFunction2, false);
+
+  sendTouchEvent(cwu, "touchstart", event1, 0);
+
+  nextTest();
+}
+
+
+function testMultiTouch(name) {
+  let cwu = SpecialPowers.getDOMWindowUtils(window);
+  let target1 = document.getElementById("testTarget");
+  let target2 = document.getElementById("testTarget2");
+  let bcr = target1.getBoundingClientRect();
+  let bcr2 = target2.getBoundingClientRect();
+
+  let touch1 = new testtouch({
+    identifier: 0,
+    page: {x: Math.round(bcr.left + bcr.width/2),
+           y: Math.round(bcr.top  + bcr.height/2)},
+    target: target1
+  });
+  let touch2 = new testtouch({
+    identifier: 1,
+    page: {x: Math.round(bcr2.left + bcr2.width/2),
+           y: Math.round(bcr2.top  + bcr2.height/2)},
+    target: target2
+  });
+  let event = new touchEvent({
+    touches: [touch1],
+    targetTouches: [touch1],
+    changedTouches: [touch1]
+  });
+
+  // test touchstart event fires correctly
+  var checkFunction = checkEvent(event);
+  window.addEventListener("touchstart", checkFunction, false);
+  sendTouchEvent(cwu, "touchstart", event, 0);
+  window.removeEventListener("touchstart", checkFunction, false);
+
+  event.touches.push(touch2);
+  event.targetTouches = [touch2];
+  event.changedTouches = [touch2];
+  window.addEventListener("touchstart", checkFunction, false);
+  sendTouchEvent(cwu, "touchstart", event, 0);
+  window.removeEventListener("touchstart", checkFunction, false);
+
+  // test moving one touch point
+  event.touches[0].page.x -= 1;
+  event.targetTouches = [event.touches[0]];
+  event.changedTouches = [event.touches[0]];
+  window.addEventListener("touchmove", checkFunction, false);
+  sendTouchEvent(cwu, "touchmove", event, 0);
+  window.removeEventListener("touchmove", checkFunction, false);
+
+  // test moving both touch points -- two touchmove events should fire, one on each target
+  event.touches[0].page.x -= 1;
+  event.touches[1].page.x -= 1;
+  event.targetTouches = event.touches;
+  event.changedTouches = event.touches;
+  var touchMoveEvents = 0;
+  var checkFunction2 = function(aEvent) {
+    is(event.ctrlKey, aEvent.ctrlKey, "Correct ctrlKey");
+    is(event.altKey, aEvent.altKey, "Correct altKey");
+    is(event.shiftKey, aEvent.shiftKey, "Correct shiftKey");
+    is(event.metaKey, aEvent.metaKey, "Correct metaKey");
+    checkTouches(event.touches, aEvent.touches);
+    checkTouches(event.changedTouches, aEvent.changedTouches);
+    if (aEvent.targetTouches[0].target == target1) {
+      checkTouches([event.touches[0]], aEvent.targetTouches);
+    } else if (aEvent.targetTouches[0].target == target2) {
+      checkTouches([event.touches[1]], aEvent.targetTouches);
+    } else
+      ok(false, "Event target is incorrect: " + event.targetTouches[0].target.nodeName + "#" + event.targetTouches[0].target.id);
+    touchMoveEvents++;
+  };
+  window.addEventListener("touchmove", checkFunction2, false);
+  sendTouchEvent(cwu, "touchmove", event, 0);
+  ok(touchMoveEvents, 2, "Correct number of touchmove events fired");
+  window.removeEventListener("touchmove", checkFunction2, false);
+
+  // test removing just one finger
+  var expected = new touchEvent({
+    touches: [touch2],
+    targetTouches: [],
+    changedTouches: [touch1]
+  });
+  checkFunction = checkEvent(expected);
+
+  event.touches = [];
+  event.targetTouches = [];
+  event.changedTouches = [touch1];
+
+  // test removing the other finger
+  window.addEventListener("touchend", checkFunction, false);
+  sendTouchEvent(cwu, "touchend", event, 0);
+  window.removeEventListener("touchend", checkFunction, false);
+
+  event.touches = [];
+  event.targetTouches = [];
+  event.changedTouches = [touch2];
+  checkFunction = checkEvent(event);
+  window.addEventListener("touchend", checkFunction, false);
+  sendTouchEvent(cwu, "touchend", event, 0);
+  window.removeEventListener("touchend", checkFunction, false);
+
+  nextTest();
+}
+
+function testTouchChanged() {
+  let cwu = SpecialPowers.getDOMWindowUtils(window);
+  let target1 = document.getElementById("testTarget");
+  let bcr = target1.getBoundingClientRect();
+
+  let touch1 = new testtouch({
+    identifier: 0,
+    page: {x: Math.round(bcr.left + bcr.width/2),
+           y: Math.round(bcr.top  + bcr.height/2)},
+    target: target1
+  });
+  let event = new touchEvent({
+    touches: [touch1],
+    targetTouches: [touch1],
+    changedTouches: [touch1]
+  });
+
+  var checkFunction = checkEvent(event);
+  sendTouchEvent(cwu, "touchstart", event, 0);
+
+  var moveEvents = 0;
+  function onMove(aEvent) {
+    moveEvents++;
+  }
+
+  window.addEventListener("touchmove", onMove, false);
+
+  // changing nothing should not fire a touchmove event
+  sendTouchEvent(cwu, "touchmove", event, 0);
+
+  // test moving x
+  event.touches[0].page.x -= 1;
+  sendTouchEvent(cwu, "touchmove", event, 0);
+
+  // test moving y
+  event.touches[0].page.y -= 1;
+  sendTouchEvent(cwu, "touchmove", event, 0);
+
+  // test changing y radius
+  event.touches[0].radius.y += 1;
+  sendTouchEvent(cwu, "touchmove", event, 0);
+  
+  // test changing x radius
+  event.touches[0].radius.x += 1;
+  sendTouchEvent(cwu, "touchmove", event, 0);
+
+  // test changing rotationAngle
+  event.touches[0].rotationAngle += 1;
+  sendTouchEvent(cwu, "touchmove", event, 0);
+
+  // test changing force
+  event.touches[0].force += 1;
+  sendTouchEvent(cwu, "touchmove", event, 0);
+
+  // changing nothing again
+  sendTouchEvent(cwu, "touchmove", event, 0);
+  
+  is(moveEvents, 6, "Six move events fired");
+
+  window.removeEventListener("touchmove", onMove, false);
+  sendTouchEvent(cwu, "touchend", event, 0);
+  nextTest();
+}
+
+function testPreventDefault() {
+  let cwu = SpecialPowers.getDOMWindowUtils(window);
+  let target = document.getElementById("testTarget");
+  let target2 = document.getElementById("testTarget2");
+  let bcr = target.getBoundingClientRect();
+  let bcr2 = target2.getBoundingClientRect();
+
+  let touch1 = new testtouch({
+    page: {x: bcr.left + bcr.width/2,
+           y: bcr.top + bcr.height/2},
+    target: target
+  });
+  let event = new touchEvent({
+    touches: [touch1],
+    targetTouches: [touch1],
+    changedTouches: [touch1]
+  });
+
+  let preventFunction = function(aEvent) {
+    aEvent.preventDefault();
+  }
+  
+  let tests = [
+    [{ name: "touchstart", prevent: false },
+     { name: "touchmove", prevent: false },
+     { name: "touchmove", prevent: false },
+     { name: "touchend", prevent: false }],
+    [{ name: "touchstart", prevent: true, doPrevent: true },
+     { name: "touchmove", prevent: true },
+     { name: "touchmove", prevent: true },
+     { name: "touchend", prevent: true }],
+    [{ name: "touchstart", prevent: false },
+     { name: "touchmove", prevent: true, doPrevent: true },
+     { name: "touchmove", prevent: true },
+     { name: "touchend", prevent: true }],
+    [{ name: "touchstart", prevent: false },
+     { name: "touchmove", prevent: false },
+     { name: "touchmove", prevent: false, doPrevent: true },
+     { name: "touchend", prevent: false }],
+    [{ name: "touchstart", prevent: false },
+     { name: "touchmove", prevent: false },
+     { name: "touchmove", prevent: false },
+     { name: "touchend", prevent: false, doPrevent: true }]
+  ];
+
+  var dotest = function(aTest) {
+    if (aTest.doPrevent) {
+      target.addEventListener(aTest.name, preventFunction, false);
+    }
+
+    if (aTest.name == "touchmove") {
+      touch1.page.x++;
+      event.touches[0] = touch1;
+    }
+
+    is(sendTouchEvent(cwu, aTest.name, event, 0), aTest.prevent, "Got correct status");
+
+    if (aTest.doPrevent)
+      target.removeEventListener(aTest.name, preventFunction, false);
+  }
+
+  for (var i = 0; i < tests.length; i++) {
+    for (var j = 0; j < tests[i].length; j++) {
+      dotest(tests[i][j]);
+    }
+  } 
+
+  nextTest();
+}
+
+function testRemovingElement() {
+  let cwu = SpecialPowers.getDOMWindowUtils(window);
+  let target = document.getElementById("testTarget");
+  let bcr = document.getElementById("testTarget").getBoundingClientRect();
+
+  let touch1 = new testtouch({
+    page: {x: bcr.left + bcr.width/2,
+           y: bcr.top + bcr.height/2},
+  });
+  let e = new touchEvent({
+    touches: [touch1],
+    targetTouches: [touch1],
+    changedTouches: [touch1]
+  });
+
+  var touchEvents = 0;  
+  var removeTarget = function(aEvent) {
+    aEvent.target.parentNode.removeChild(aEvent.target);
+  };
+
+  var checkTarget = function(aEvent) {
+    is(aEvent.target, target, "Event has correct target");
+    touchEvents++;
+  };
+
+  target.addEventListener("touchstart", removeTarget, false);
+  target.addEventListener("touchmove", checkTarget, false);
+  target.addEventListener("touchend", checkTarget, false);
+
+  sendTouchEvent(cwu, "touchstart", e, 0);
+
+  e.touches[0].page.x++;
+  sendTouchEvent(cwu, "touchmove", e, 0);
+  sendTouchEvent(cwu, "touchend", e, 0);
+
+  target.removeEventListener("touchstart", removeTarget, false);
+  target.removeEventListener("touchmove", checkTarget, false);
+  target.removeEventListener("touchend", checkTarget, false);
+
+  is(touchEvents, 2, "Check target was called twice");
+
+  nextTest();
+}
+
+function doTest() {
+  tests.push(testSingleTouch);
+  tests.push(testSingleTouch2);
+  tests.push(testMultiTouch);
+  tests.push(testPreventDefault);
+  tests.push(testTouchChanged);
+  tests.push(testRemovingElement);
+
+  tests.push(function() {
+    SimpleTest.finish();
+  });
+
+  nextTest();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(doTest);
+
+</script>
+</pre>
+<div id="parent">
+  <span id="testTarget" style="padding: 5px; border: 1px solid black;">testTarget</span>
+  <span id="testTarget2" style="padding: 5px; border: 1px solid blue;">testTarget</span>
+</div>
+</body>
+</html>
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -1546,92 +1546,85 @@ nsGenericHTMLElement::GetFormControlFram
 nsGenericHTMLElement::GetPrimaryPresState(nsGenericHTMLElement* aContent,
                                           nsPresState** aPresState)
 {
   NS_ENSURE_ARG_POINTER(aPresState);
   *aPresState = nsnull;
 
   nsresult result = NS_OK;
 
-  nsCOMPtr<nsILayoutHistoryState> history;
   nsCAutoString key;
-  GetLayoutHistoryAndKey(aContent, false, getter_AddRefs(history), key);
+  nsCOMPtr<nsILayoutHistoryState> history = GetLayoutHistoryAndKey(aContent, false, key);
 
   if (history) {
     // Get the pres state for this key, if it doesn't exist, create one
     result = history->GetState(key, aPresState);
     if (!*aPresState) {
       *aPresState = new nsPresState();
       result = history->AddState(key, *aPresState);
     }
   }
 
   return result;
 }
 
 
-nsresult
+already_AddRefed<nsILayoutHistoryState>
 nsGenericHTMLElement::GetLayoutHistoryAndKey(nsGenericHTMLElement* aContent,
                                              bool aRead,
-                                             nsILayoutHistoryState** aHistory,
                                              nsACString& aKey)
 {
   //
   // Get the pres shell
   //
   nsCOMPtr<nsIDocument> doc = aContent->GetDocument();
   if (!doc) {
-    return NS_OK;
+    return nsnull;
   }
 
   //
   // Get the history (don't bother with the key if the history is not there)
   //
-  *aHistory = doc->GetLayoutHistoryState().get();
-  if (!*aHistory) {
-    return NS_OK;
+  nsCOMPtr<nsILayoutHistoryState> history = doc->GetLayoutHistoryState();
+  if (!history) {
+    return nsnull;
   }
 
-  if (aRead && !(*aHistory)->HasStates()) {
-    NS_RELEASE(*aHistory);
-    return NS_OK;
+  if (aRead && !history->HasStates()) {
+    return nsnull;
   }
 
   //
   // Get the state key
   //
   nsresult rv = nsContentUtils::GenerateStateKey(aContent, doc,
                                                  nsIStatefulFrame::eNoID,
                                                  aKey);
   if (NS_FAILED(rv)) {
-    NS_RELEASE(*aHistory);
-    return rv;
+    return nsnull;
   }
 
   // If the state key is blank, this is anonymous content or for
   // whatever reason we are not supposed to save/restore state.
   if (aKey.IsEmpty()) {
-    NS_RELEASE(*aHistory);
-    return NS_OK;
+    return nsnull;
   }
 
   // Add something unique to content so layout doesn't muck us up
   aKey += "-C";
 
-  return rv;
+  return history.forget();
 }
 
 bool
 nsGenericHTMLElement::RestoreFormControlState(nsGenericHTMLElement* aContent,
                                               nsIFormControl* aControl)
 {
-  nsCOMPtr<nsILayoutHistoryState> history;
   nsCAutoString key;
-  GetLayoutHistoryAndKey(aContent, true,
-                         getter_AddRefs(history), key);
+  nsCOMPtr<nsILayoutHistoryState> history = GetLayoutHistoryAndKey(aContent, true, key);
   if (!history) {
     return false;
   }
 
   nsPresState *state;
   // Get the pres state for this key
   nsresult rv = history->GetState(key, &state);
   if (NS_SUCCEEDED(rv) && state) {
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -466,20 +466,20 @@ public:
    * piece of content.
    *
    * @param aContent the content to generate the key for
    * @param aRead if true, won't return a layout history state (and won't
    *              generate a key) if the layout history state is empty.
    * @param aState the history state object (out param)
    * @param aKey the key (out param)
    */
-  static nsresult GetLayoutHistoryAndKey(nsGenericHTMLElement* aContent,
-                                         bool aRead,
-                                         nsILayoutHistoryState** aState,
-                                         nsACString& aKey);
+  static already_AddRefed<nsILayoutHistoryState>
+  GetLayoutHistoryAndKey(nsGenericHTMLElement* aContent,
+                         bool aRead,
+                         nsACString& aKey);
   /**
    * Restore the state for a form control.  Ends up calling
    * nsIFormControl::RestoreState().
    *
    * @param aContent an nsGenericHTMLElement* pointing to the form control
    * @param aControl an nsIFormControl* pointing to the form control
    * @return false if RestoreState() was not called, the return
    *         value of RestoreState() otherwise.
@@ -864,17 +864,17 @@ public:
   virtual void ClearForm(bool aRemoveFromForm);
 
   nsresult GetForm(nsIDOMHTMLFormElement** aForm);
 
   NS_IMETHOD SaveState()
   {
     return NS_OK;
   }
-  
+
   virtual bool RestoreState(nsPresState* aState)
   {
     return false;
   }
   virtual bool AllowDrop()
   {
     return true;
   }
--- a/content/mathml/content/src/Makefile.in
+++ b/content/mathml/content/src/Makefile.in
@@ -60,13 +60,12 @@ FORCE_STATIC_LIB = 1
 
 EXPORTS = \
 	$(NULL)
 
 
 include $(topsrcdir)/config/rules.mk
 
 INCLUDES += 	\
-		-I$(srcdir)/../../../shared/public \
 		-I$(srcdir)/../../../base/src \
 		$(NULL)
 
 DEFINES += -D_IMPL_NS_LAYOUT
--- a/content/media/nsBuiltinDecoderStateMachine.cpp
+++ b/content/media/nsBuiltinDecoderStateMachine.cpp
@@ -626,17 +626,16 @@ bool nsBuiltinDecoderStateMachine::IsPla
 }
 
 void nsBuiltinDecoderStateMachine::AudioLoop()
 {
   NS_ASSERTION(OnAudioThread(), "Should be on audio thread.");
   LOG(PR_LOG_DEBUG, ("%p Begun audio thread/loop", mDecoder.get()));
   PRInt64 audioDuration = 0;
   PRInt64 audioStartTime = -1;
-  PRInt64 framesWritten = 0;
   PRUint32 channels, rate;
   double volume = -1;
   bool setVolume;
   PRInt32 minWriteFrames = -1;
   {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
     mAudioCompleted = false;
     audioStartTime = mAudioStartTime;
@@ -741,16 +740,17 @@ void nsBuiltinDecoderStateMachine::Audio
       break;
     }
     PRInt64 missingFrames = 0;
     if (!AddOverflow(sampleTime, -playedFrames, missingFrames)) {
       NS_WARNING("Int overflow adding missingFrames");
       break;
     }
 
+    PRInt64 framesWritten = 0;
     if (missingFrames > 0) {
       // The next audio chunk begins some time after the end of the last chunk
       // we pushed to the audio hardware. We must push silence into the audio
       // hardware so that the next audio chunk begins playback at the correct
       // time.
       missingFrames = NS_MIN(static_cast<PRInt64>(PR_UINT32_MAX), missingFrames);
       framesWritten = PlaySilence(static_cast<PRUint32>(missingFrames),
                                   channels, playedFrames);
@@ -775,28 +775,32 @@ void nsBuiltinDecoderStateMachine::Audio
       mState != DECODER_STATE_SHUTDOWN &&
       !mStopAudioThread)
   {
     // Last frame pushed to audio hardware, wait for the audio to finish,
     // before the audio thread terminates.
     bool seeking = false;
     {
       ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-      if (framesWritten < minWriteFrames) {
-        // We've not written minWriteFrames in the last write, the audio
-        // may not start playing. Write silence to ensure we've got enough
-        // written to start playback.
-        PRInt64 minToWrite = minWriteFrames - framesWritten;
-        if (minToWrite < PR_UINT32_MAX / channels) {
+      PRInt64 unplayedFrames = audioDuration % minWriteFrames;
+      if (minWriteFrames > 1 && unplayedFrames > 0) {
+        // Sound is written by libsydneyaudio to the hardware in blocks of
+        // frames of size minWriteFrames. So if the number of frames we've
+        // written isn't an exact multiple of minWriteFrames, we'll have
+        // left over audio data which hasn't yet been written to the hardware,
+        // and so that audio will not start playing. Write silence to ensure
+        // the last block gets pushed to hardware, so that playback starts.
+        PRInt64 framesToWrite = minWriteFrames - unplayedFrames;
+        if (framesToWrite < PR_UINT32_MAX / channels) {
           // Write silence manually rather than using PlaySilence(), so that
           // the AudioAPI doesn't get a copy of the audio frames.
-          PRUint32 numSamples = minToWrite * channels;
+          PRUint32 numSamples = framesToWrite * channels;
           nsAutoArrayPtr<AudioDataValue> buf(new AudioDataValue[numSamples]);
           memset(buf.get(), 0, numSamples * sizeof(AudioDataValue));
-          mAudioStream->Write(buf, minToWrite);
+          mAudioStream->Write(buf, framesToWrite);
         }
       }
 
       PRInt64 oldPosition = -1;
       PRInt64 position = GetMediaTime();
       while (oldPosition != position &&
              mAudioEndTime - position > 0 &&
              mState != DECODER_STATE_SEEKING &&
--- a/content/svg/content/src/Makefile.in
+++ b/content/svg/content/src/Makefile.in
@@ -169,18 +169,16 @@ FORCE_STATIC_LIB = 1
 EXPORTS =  			\
 	nsSVGFeatures.h            \
 	nsSVGRect.h                \
 	$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
 INCLUDES += 	\
-		-I$(srcdir)/../../../shared/public \
-		-I$(srcdir)/../../../html/base/src \
 		-I$(srcdir)/../../../xml/content/src \
 		-I$(srcdir)/../../../../dom \
 		-I$(srcdir)/../../../base/src \
 		-I$(srcdir)/../../../../layout/generic \
 		-I$(srcdir)/../../../../layout/xul/base/src \
 		-I$(srcdir)/../../../../layout/svg/base/src \
 		-I$(srcdir)/../../../../layout/style \
 		-I$(srcdir)/../../../events/src \
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -219,16 +219,17 @@
 #include "nsContentErrors.h"
 #include "nsIChannelPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 
 #include "nsXULAppAPI.h"
 
 #include "nsDOMNavigationTiming.h"
 #include "nsITimedChannel.h"
+#include "mozilla/StartupTimeline.h"
 
 static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
                      NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
 
 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
 //#define DEBUG_DOCSHELL_FOCUS
 #define DEBUG_PAGE_CACHE
@@ -1219,16 +1220,21 @@ nsDocShell::LoadURI(nsIURI * aURI,
     bool ownerIsExplicit = false;
     bool sendReferrer = true;
     nsCOMPtr<nsISHEntry> shEntry;
     nsXPIDLString target;
     PRUint32 loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);    
 
     NS_ENSURE_ARG(aURI);
 
+    if (!StartupTimeline::HasRecord(StartupTimeline::FIRST_LOAD_URI) &&
+        mItemType == typeContent && !NS_IsAboutBlank(aURI)) {
+        StartupTimeline::RecordOnce(StartupTimeline::FIRST_LOAD_URI);
+    }
+
     // Extract the info from the DocShellLoadInfo struct...
     if (aLoadInfo) {
         aLoadInfo->GetReferrer(getter_AddRefs(referrer));
 
         nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
         aLoadInfo->GetLoadType(&lt);
         // Get the appropriate loadType from nsIDocShellLoadInfo type
         loadType = ConvertDocShellLoadInfoToLoadType(lt);
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -44,16 +44,18 @@
 #include "nsDOMWindowUtils.h"
 #include "nsQueryContentEventResult.h"
 #include "nsGlobalWindow.h"
 #include "nsIDocument.h"
 #include "nsFocusManager.h"
 #include "nsEventStateManager.h"
 #include "nsFrameManager.h"
 #include "nsRefreshDriver.h"
+#include "nsDOMTouchEvent.h"
+#include "nsIDOMTouchEvent.h"
 
 #include "nsIScrollableFrame.h"
 
 #include "nsContentUtils.h"
 #include "nsLayoutUtils.h"
 
 #include "nsIFrame.h"
 #include "nsIWidget.h"
@@ -545,16 +547,89 @@ nsDOMWindowUtils::SendMouseScrollEvent(c
   event.refPoint.y =
     NSAppUnitsToIntPixels(nsPresContext::CSSPixelsToAppUnits(aY) + offset.y,
                           appPerDev);
 
   nsEventStatus status;
   return widget->DispatchEvent(&event, status);
 }
 
+
+NS_IMETHODIMP
+nsDOMWindowUtils::SendTouchEvent(const nsAString& aType,
+                                 PRUint32 *aIdentifiers,
+                                 PRInt32 *aXs,
+                                 PRInt32 *aYs,
+                                 PRUint32 *aRxs,
+                                 PRUint32 *aRys,
+                                 float *aRotationAngles,
+                                 float *aForces,
+                                 PRUint32 aCount,
+                                 PRInt32 aModifiers,
+                                 bool aIgnoreRootScrollFrame,
+                                 bool *aPreventDefault)
+{
+  if (!IsUniversalXPConnectCapable()) {
+    return NS_ERROR_DOM_SECURITY_ERR;
+  }
+
+  // get the widget to send the event to
+  nsPoint offset;
+  nsCOMPtr<nsIWidget> widget = GetWidget(&offset);
+  if (!widget) {
+    return NS_ERROR_NULL_POINTER;
+  }
+  PRInt32 msg;
+  if (aType.EqualsLiteral("touchstart")) {
+    msg = NS_TOUCH_START;
+  } else if (aType.EqualsLiteral("touchmove")) {
+    msg = NS_TOUCH_MOVE;
+  } else if (aType.EqualsLiteral("touchend")) {
+    msg = NS_TOUCH_END;
+  } else if (aType.EqualsLiteral("touchcancel")) {
+    msg = NS_TOUCH_CANCEL;
+  } else {
+    return NS_ERROR_UNEXPECTED;
+  }
+  nsTouchEvent event(true, msg, widget);
+  event.isShift = (aModifiers & nsIDOMNSEvent::SHIFT_MASK) ? true : false;
+  event.isControl = (aModifiers & nsIDOMNSEvent::CONTROL_MASK) ? true : false;
+  event.isAlt = (aModifiers & nsIDOMNSEvent::ALT_MASK) ? true : false;
+  event.isMeta = (aModifiers & nsIDOMNSEvent::META_MASK) ? true : false;
+  event.widget = widget;
+  event.time = PR_Now();
+
+  nsPresContext* presContext = GetPresContext();
+  if (!presContext) {
+    return NS_ERROR_FAILURE;
+  }
+  event.touches.SetCapacity(aCount);
+  PRInt32 appPerDev = presContext->AppUnitsPerDevPixel();
+  for (int i = 0; i < aCount; ++i) {
+    nsIntPoint pt(0, 0);
+    pt.x =
+      NSAppUnitsToIntPixels(nsPresContext::CSSPixelsToAppUnits(aXs[i]) + offset.x,
+                            appPerDev);
+    pt.y =
+      NSAppUnitsToIntPixels(nsPresContext::CSSPixelsToAppUnits(aYs[i]) + offset.y,
+                            appPerDev);
+    nsCOMPtr<nsIDOMTouch> t(new nsDOMTouch(aIdentifiers[i],
+                                           pt,
+                                           nsIntPoint(aRxs[i], aRys[i]),
+                                           aRotationAngles[i],
+                                           aForces[i]));
+    event.touches.AppendElement(t);
+  }
+
+  nsEventStatus status;
+  nsresult rv = widget->DispatchEvent(&event, status);
+  *aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
+  return rv;
+}
+
 NS_IMETHODIMP
 nsDOMWindowUtils::SendKeyEvent(const nsAString& aType,
                                PRInt32 aKeyCode,
                                PRInt32 aCharCode,
                                PRInt32 aModifiers,
                                bool aPreventDefault,
                                bool* aDefaultActionTaken)
 {
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1335,18 +1335,18 @@ nsGlobalWindow::FreeInnerObjects(bool aC
 
   if (mDummyJavaPluginOwner) {
     // Tear down the dummy java plugin.
 
     // XXXjst: On a general note, should windows with java stuff in
     // them ever even make it into the fast-back cache?
 
     mDummyJavaPluginOwner->Destroy();
-
     mDummyJavaPluginOwner = nsnull;
+    mDidInitJavaProperties = false;
   }
 
   CleanupCachedXBLHandlers(this);
 
 #ifdef DEBUG
   nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
 #endif
 }
@@ -1476,16 +1476,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParentTarget)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFrameElement)
 
   // Unlink mDummyJavaPluginOwner
   if (tmp->mDummyJavaPluginOwner) {
     tmp->mDummyJavaPluginOwner->Destroy();
     NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDummyJavaPluginOwner)
+    tmp->mDidInitJavaProperties = false;
   }
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFocusedNode)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mPendingStorageEvents)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
@@ -2229,16 +2230,26 @@ nsGlobalWindow::SetNewDocument(nsIDocume
         newInnerWindow->mDoc = aDocument;
 
         // We're reusing the inner window for a new document. In this
         // case we don't clear the inner window's scope, but we must
         // make sure the cached document property gets updated.
 
         // XXXmarkh - tell other languages about this?
         ::JS_DeleteProperty(cx, currentInner->mJSObject, "document");
+
+        if (mDummyJavaPluginOwner) {
+          // Since we're reusing the inner window, tear down the
+          // dummy Java plugin we created for the old document in
+          // this window.
+          mDummyJavaPluginOwner->Destroy();
+          mDummyJavaPluginOwner = nsnull;
+
+          mDidInitJavaProperties = false;
+        }
       }
     } else {
       rv = newInnerWindow->InnerSetNewDocument(aDocument);
       NS_ENSURE_SUCCESS(rv, rv);
 
       // Initialize DOM classes etc on the inner window.
       rv = mContext->InitClasses(newInnerWindow->mJSObject);
       NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -63,18 +63,19 @@ interface nsIDOMElement;
 interface nsIDOMHTMLCanvasElement;
 interface nsIDOMEvent;
 interface nsITransferable;
 interface nsIQueryContentEventResult;
 interface nsIDOMWindow;
 interface nsIDOMBlob;
 interface nsIDOMFile;
 interface nsIFile;
+interface nsIDOMTouch;
 
-[scriptable, uuid(b9c1f815-c2f2-4607-a060-6a8566581927)]
+[scriptable, uuid(e01171b0-712a-47ce-8552-b7b2ef0a2507)]
 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.
@@ -222,16 +223,55 @@ interface nsIDOMWindowUtils : nsISupport
   void sendMouseEvent(in AString aType,
                       in float aX,
                       in float aY,
                       in long aButton,
                       in long aClickCount,
                       in long aModifiers,
                       [optional] in boolean aIgnoreRootScrollFrame);
 
+  /** Synthesize a touch event. The event types supported are:
+   *    touchstart, touchend, touchmove, and touchcancel
+   *
+   * Events are sent in coordinates offset by aX and aY from the window.
+   *
+   * Cannot be accessed from unprivileged context (not content-accessible)
+   * Will throw a DOM security error if called without UniversalXPConnect
+   * privileges.
+   *
+   * The event is dispatched via the toplevel window, so it could go to any
+   * window under the toplevel window, in some cases it could never reach this
+   * window at all.
+   *
+   * @param aType event type
+   * @param xs array of offsets in CSS pixels for each touch to be sent
+   * @param ys array of offsets in CSS pixels for each touch to be sent
+   * @param rxs array of radii in CSS pixels for each touch to be sent
+   * @param rys array of radii in CSS pixels for each touch to be sent
+   * @param rotationAngles array of angles in degrees for each touch to be sent
+   * @param forces array of forces (floats from 0 to 1) for each touch to be sent
+   * @param count number of touches in this set
+   * @param aModifiers modifiers pressed, using constants defined in nsIDOMNSEvent
+   * @param aIgnoreRootScrollFrame whether the event should ignore viewport bounds
+   *                           during dispatch
+   *
+   * returns true if the page called prevent default on this touch event
+   */
+  boolean sendTouchEvent(in AString aType,
+                         [array, size_is(count)] in PRUint32 aIdentifiers,
+                         [array, size_is(count)] in PRInt32 aXs,
+                         [array, size_is(count)] in PRInt32 aYs,
+                         [array, size_is(count)] in PRUint32 aRxs,
+                         [array, size_is(count)] in PRUint32 aRys,
+                         [array, size_is(count)] in float aRotationAngles,
+                         [array, size_is(count)] in float aForces,
+                         in PRUint32 count,
+                         in long aModifiers,
+                         [optional] in boolean aIgnoreRootScrollFrame);
+
   /** The same as sendMouseEvent but ensures that the event is dispatched to
    *  this DOM window or one of its children.
    */
   void sendMouseEventToWindow(in AString aType,
                               in float aX,
                               in float aY,
                               in long aButton,
                               in long aClickCount,
--- a/dom/interfaces/events/nsIDOMTouchEvent.idl
+++ b/dom/interfaces/events/nsIDOMTouchEvent.idl
@@ -31,36 +31,48 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsIDOMUIEvent.idl"
+%{C++
+#include "nsWeakPtr.h"
+#include "nsPoint.h"
+%}
 interface nsIVariant;
 
 /**
  * @see http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html
  */
 
-[scriptable, uuid(98bc0f7d-5bff-4387-9c42-58af54b48dd5)]
+[scriptable, builtinclass, uuid(98bc0f7d-5bff-4387-9c42-58af54b48dd5)]
 interface nsIDOMTouch : nsISupports {
   readonly attribute long              identifier;
   readonly attribute nsIDOMEventTarget target;
   readonly attribute long              pageX;
   readonly attribute long              pageY;
   readonly attribute long              screenX;
   readonly attribute long              screenY;
   readonly attribute long              clientX;
   readonly attribute long              clientY;
   readonly attribute long              radiusX;
   readonly attribute long              radiusY;
   readonly attribute float             rotationAngle;
   readonly attribute float             force;
+  %{C++
+    nsCOMPtr<nsIDOMEventTarget> mTarget;
+    nsIDOMEventTarget *GetTarget() { return mTarget; }
+    void SetTarget(nsIDOMEventTarget *target) { mTarget = target; }
+    nsIntPoint mRefPoint;
+    bool mChanged;
+    PRUint32 mMessage;
+  %}
 };
 
 [scriptable, uuid(60706eb7-d50d-4379-b01c-e78e6af84213)]
 interface nsIDOMTouchList : nsISupports {
   readonly attribute unsigned long length;
   nsIDOMTouch item(in unsigned long index);
   nsIDOMTouch identifiedTouch(in long identifier);
 };
--- a/dom/plugins/base/Makefile.in
+++ b/dom/plugins/base/Makefile.in
@@ -127,16 +127,20 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),qt)
 else
 	CPPSRCS += nsPluginNativeWindow.cpp
 endif
 endif
 endif
 endif
 endif
 
+ifdef MOZ_JAVA_COMPOSITOR
+DEFINES += -DMOZ_JAVA_COMPOSITOR
+endif
+
 LOCAL_INCLUDES += \
   -DSK_BUILD_FOR_ANDROID_NDK \
   -I$(topsrcdir)/xpcom/base/ \
   -I$(topsrcdir)/gfx/skia/include/core \
   -I$(topsrcdir)/gfx/skia/include/config \
   $(MOZ_CAIRO_CFLAGS) \
   $(NULL)
 
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -1678,27 +1678,50 @@ bool nsPluginInstanceOwner::AddPluginVie
 
   if (aRect.IsEqualEdges(mLastPluginRect)) {
     // Already added and in position, no work to do
     return true;
   }
 
   JNIEnv* env = GetJNIForThread();
   jclass cls = env->FindClass("org/mozilla/gecko/GeckoAppShell");
+
+#ifdef MOZ_JAVA_COMPOSITOR
+  nsAutoString metadata;
+  nsCOMPtr<nsIAndroidDrawMetadataProvider> metadataProvider =
+      AndroidBridge::Bridge()->GetDrawMetadataProvider();
+  metadataProvider->GetDrawMetadata(metadata);
+
+  jstring jMetadata = env->NewString(nsPromiseFlatString(metadata).get(), metadata.Length());
+
+  jmethodID method = env->GetStaticMethodID(cls,
+                                            "addPluginView",
+                                            "(Landroid/view/View;IIIILjava/lang/String;)V");
+
+  env->CallStaticVoidMethod(cls,
+                            method,
+                            javaSurface,
+                            (int)aRect.x,
+                            (int)aRect.y,
+                            (int)aRect.width,
+                            (int)aRect.height,
+                            jMetadata);
+#else
   jmethodID method = env->GetStaticMethodID(cls,
                                             "addPluginView",
                                             "(Landroid/view/View;DDDD)V");
 
   env->CallStaticVoidMethod(cls,
                             method,
                             javaSurface,
                             aRect.x,
                             aRect.y,
                             aRect.width,
                             aRect.height);
+#endif
 
   if (!mPluginViewAdded) {
     ANPEvent event;
     event.inSize = sizeof(ANPEvent);
     event.eventType = kLifecycle_ANPEventType;
     event.data.lifecycle.action = kOnScreen_ANPLifecycleAction;
     mInstance->HandleEvent(&event, nsnull);
 
--- a/dom/wifi/nsWifiWorker.js
+++ b/dom/wifi/nsWifiWorker.js
@@ -752,20 +752,20 @@ var WifiManager = (function() {
   manager.updateNetwork = function(config, callback) {
     manager.setNetworkConfiguration(config, callback);
   }
   manager.removeNetwork = function(netId, callback) {
     removeNetworkCommand(netId, callback);
   }
 
   function ipToString(n) {
-    return String((n & (0xff << 24)) >> 24) + "." +
-                 ((n & (0xff << 16)) >> 16) + "." +
-                 ((n & (0xff <<  8)) >>  8) + "." +
-                 ((n & (0xff <<  0)) >>  0);
+    return String((n >>  0) & 0xFF) + "." +
+                 ((n >>  8) & 0xFF) + "." +
+                 ((n >> 16) & 0xFF) + "." +
+                 ((n >> 24) & 0xFF);
   }
 
   manager.enableNetwork = function(netId, disableOthers, callback) {
     enableNetworkCommand(netId, disableOthers, callback);
   }
   manager.disableNetwork = function(netId, callback) {
     disableNetworkCommand(netId, callback);
   }
--- a/dom/workers/EventTarget.cpp
+++ b/dom/workers/EventTarget.cpp
@@ -37,16 +37,21 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "EventTarget.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "nsTraceRefcnt.h"
 
+// All the EventTarget subclasses have to be included here.
+#include "Worker.h"
+#include "WorkerScope.h"
+#include "XMLHttpRequest.h"
+
 #include "WorkerInlines.h"
 
 USING_WORKERS_NAMESPACE
 
 using mozilla::dom::workers::events::EventTarget;
 
 namespace {
 
@@ -59,16 +64,33 @@ namespace {
   };
 
 DECL_EVENTTARGET_CLASS(gClass, "EventTarget")
 DECL_EVENTTARGET_CLASS(gMainThreadClass, "WorkerEventTarget")
 
 #undef DECL_EVENTTARGET_CLASS
 
 inline
+bool
+EnsureObjectIsEventTarget(JSContext* aCx, JSObject* aObj, char* aFunctionName)
+{
+  JSClass* classPtr = JS_GET_CLASS(aCx, aObj);
+  if (classPtr &&
+      (ClassIsWorker(classPtr) || ClassIsWorkerGlobalScope(classPtr) ||
+       ClassIsXMLHttpRequest(classPtr))) {
+    return true;
+  }
+
+  JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
+                       "EventTarget", aFunctionName,
+                        classPtr ? classPtr->name : "object");
+  return false;
+}
+
+inline
 EventTarget*
 GetPrivate(JSContext* aCx, JSObject* aObj)
 {
   return GetJSPrivateSafeish<EventTarget>(aCx, aObj);
 }
 
 JSBool
 Construct(JSContext* aCx, uintN aArgc, jsval* aVp)
@@ -138,16 +160,20 @@ EventTarget::FromJSObject(JSContext* aCx
 JSBool
 EventTarget::AddEventListener(JSContext* aCx, uintN aArgc, jsval* aVp)
 {
   JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
   if (!obj) {
     return true;
   }
 
+  if (!EnsureObjectIsEventTarget(aCx, obj, "AddEventListener")) {
+    return false;
+  }
+
   EventTarget* self = GetPrivate(aCx, obj);
   if (!self) {
     return true;
   }
 
   JSString* type;
   JSObject* listener;
   JSBool capturing = false, wantsUntrusted = false;
@@ -169,16 +195,20 @@ EventTarget::AddEventListener(JSContext*
 JSBool
 EventTarget::RemoveEventListener(JSContext* aCx, uintN aArgc, jsval* aVp)
 {
   JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
   if (!obj) {
     return true;
   }
 
+  if (!EnsureObjectIsEventTarget(aCx, obj, "RemoveEventListener")) {
+    return false;
+  }
+
   EventTarget* self = GetPrivate(aCx, obj);
   if (!self) {
     return true;
   }
 
   JSString* type;
   JSObject* listener;
   JSBool capturing = false;
@@ -200,16 +230,20 @@ EventTarget::RemoveEventListener(JSConte
 JSBool
 EventTarget::DispatchEvent(JSContext* aCx, uintN aArgc, jsval* aVp)
 {
   JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
   if (!obj) {
     return true;
   }
 
+  if (!EnsureObjectIsEventTarget(aCx, obj, "DispatchEvent")) {
+    return false;
+  }
+
   EventTarget* self = GetPrivate(aCx, obj);
   if (!self) {
     return true;
   }
 
   JSObject* event;
   if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "o", &event)) {
     return false;
--- a/dom/workers/EventTarget.h
+++ b/dom/workers/EventTarget.h
@@ -42,16 +42,18 @@
 #include "jspubtd.h"
 
 #include "ListenerManager.h"
 
 BEGIN_WORKERS_NAMESPACE
 
 namespace events {
 
+// If you inherit this class then you need to add some way to compare the
+// JSClass for your subclass in EnsureObjectIsEventTarget().
 class EventTarget : public PrivatizableBase
 {
   ListenerManager mListenerManager;
 
 protected:
   EventTarget();
   ~EventTarget();
 
--- a/dom/workers/Worker.cpp
+++ b/dom/workers/Worker.cpp
@@ -494,9 +494,15 @@ bool
 InitClass(JSContext* aCx, JSObject* aGlobal, JSObject* aProto,
           bool aMainRuntime)
 {
   return !!ChromeWorker::InitClass(aCx, aGlobal, aProto, aMainRuntime);
 }
 
 } // namespace chromeworker
 
+bool
+ClassIsWorker(JSClass* aClass)
+{
+  return Worker::Class() == aClass || ChromeWorker::Class() == aClass;
+}
+
 END_WORKERS_NAMESPACE
--- a/dom/workers/Worker.h
+++ b/dom/workers/Worker.h
@@ -59,11 +59,14 @@ ClearPrivateSlot(JSContext* aCx, JSObjec
 namespace chromeworker {
 
 bool
 InitClass(JSContext* aCx, JSObject* aGlobal, JSObject* aProto,
           bool aMainRuntime);
 
 } // namespace chromeworker
 
+bool
+ClassIsWorker(JSClass* aClass);
+
 END_WORKERS_NAMESPACE
 
 #endif /* mozilla_dom_workers_worker_h__ */
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -932,9 +932,16 @@ CreateDedicatedWorkerGlobalScope(JSConte
 
   if (!JS_DefineProfilingFunctions(aCx, global)) {
     return NULL;
   }
 
   return global;
 }
 
+bool
+ClassIsWorkerGlobalScope(JSClass* aClass)
+{
+  return WorkerGlobalScope::Class() == aClass ||
+         DedicatedWorkerGlobalScope::Class() == aClass;
+}
+
 END_WORKERS_NAMESPACE
--- a/dom/workers/WorkerScope.h
+++ b/dom/workers/WorkerScope.h
@@ -43,11 +43,14 @@
 
 #include "jspubtd.h"
 
 BEGIN_WORKERS_NAMESPACE
 
 JSObject*
 CreateDedicatedWorkerGlobalScope(JSContext* aCx);
 
+bool
+ClassIsWorkerGlobalScope(JSClass* aClass);
+
 END_WORKERS_NAMESPACE
 
 #endif /* mozilla_dom_workers_workerscope_h__ */
--- a/dom/workers/XMLHttpRequest.cpp
+++ b/dom/workers/XMLHttpRequest.cpp
@@ -924,9 +924,16 @@ UpdateXHRState(JSContext* aCx, JSObject*
 {
   return aIsUpload ?
          XMLHttpRequestUpload::UpdateState(aCx, aObj, aNewState) :
          XMLHttpRequest::UpdateState(aCx, aObj, aNewState);
 }
 
 } // namespace xhr
 
+bool
+ClassIsXMLHttpRequest(JSClass* aClass)
+{
+  return XMLHttpRequest::Class() == aClass ||
+         XMLHttpRequestUpload::Class() == aClass;
+}
+
 END_WORKERS_NAMESPACE
--- a/dom/workers/XMLHttpRequest.h
+++ b/dom/workers/XMLHttpRequest.h
@@ -65,11 +65,14 @@ struct StateData
 };
 
 bool
 UpdateXHRState(JSContext* aCx, JSObject* aObj, bool aIsUpload,
                const StateData& aNewState);
 
 } // namespace xhr
 
+bool
+ClassIsXMLHttpRequest(JSClass* aClass);
+
 END_WORKERS_NAMESPACE
 
 #endif /* mozilla_dom_workers_xmlhttprequest_h__ */
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/base/crashtests/713427-1.html
@@ -0,0 +1,9 @@
+<span>
+<script contenteditable="true"></script>
+<blockquote>
+<input>
+<code style="display: table-row;">
+<html contenteditable="true">
+</blockquote>
+
+
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/base/crashtests/713427-2.xhtml
@@ -0,0 +1,28 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script>
+<![CDATA[
+
+function boom()
+{
+  while (document.documentElement.firstChild) {
+    document.documentElement.removeChild(document.documentElement.firstChild);
+  }
+
+  var td = document.createElementNS("http://www.w3.org/1999/xhtml", "td");
+  td.setAttributeNS(null, "contenteditable", "true");
+  (document.documentElement).appendChild(td);
+  var head = document.createElementNS("http://www.w3.org/1999/xhtml", "head");
+  (document.documentElement).appendChild(head);
+
+  head.appendChild(td);
+}
+
+window.addEventListener("load", boom, false);
+
+]]>
+</script>
+</head>
+
+<body></body>
+</html>
--- a/editor/libeditor/base/crashtests/crashtests.list
+++ b/editor/libeditor/base/crashtests/crashtests.list
@@ -3,8 +3,10 @@ load 382527-1.html
 load 402172-1.html
 load 407079-1.html
 load 407256-1.html
 load 430624-1.html
 load 459613.html
 load 475132-1.xhtml
 asserts-if(!Android,1) load 633709.xhtml # Bug 695364
 asserts-if(!Android,6) load 636074-1.html # Bug 439258, charged to the wrong test due to bug 635550
+load 713427-1.html
+load 713427-2.xhtml
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -3600,42 +3600,47 @@ IsElementVisible(dom::Element* aElement)
 {
   if (aElement->GetPrimaryFrame()) {
     // It's visible, for our purposes
     return true;
   }
 
   nsIContent *cur = aElement;
   for (; ;) {
+    // Walk up the tree looking for the nearest ancestor with a frame.
+    // The state of the child right below it will determine whether
+    // we might possibly have a frame or not.
+    bool haveLazyBitOnChild = cur->HasFlag(NODE_NEEDS_FRAME);
     cur = cur->GetFlattenedTreeParent();
     if (!cur) {
-      // None of our ancestors have lazy bits set, so we shouldn't have a frame
-      return false;
+      if (!haveLazyBitOnChild) {
+        // None of our ancestors have lazy bits set, so we shouldn't
+        // have a frame
+        return false;
+      }
+
+      // The root has a lazy frame construction bit.  We need to check
+      // our style.
+      break;
     }
 
     if (cur->GetPrimaryFrame()) {
-      // None of our ancestors up to the nearest ancestor with a frame have
-      // lazy bits; that means we won't get a frame
-      return false;
-    }
-
-    if (cur->HasFlag(NODE_NEEDS_FRAME)) {
-      // Double-check that the parent doesn't have a leaf frame
-      nsIContent *parent = cur->GetFlattenedTreeParent();
-      if (parent) {
-        NS_ASSERTION(parent->GetPrimaryFrame(),
-                     "Why does our parent not have a frame?");
-        if (parent->GetPrimaryFrame()->IsLeaf()) {
-          // No frame for us
-          return false;
-        }
+      if (!haveLazyBitOnChild) {
+        // Our ancestor directly under |cur| doesn't have lazy bits;
+        // that means we won't get a frame
+        return false;
       }
 
-      // |cur| will get a frame sometime.  What does that mean for us?
-      // |We have to figure that out!
+      if (cur->GetPrimaryFrame()->IsLeaf()) {
+        // Nothing under here will ever get frames
+        return false;
+      }
+
+      // Otherwise, we might end up with a frame when that lazy bit is
+      // processed.  Figure out our actual style.
       break;
     }
   }
 
   // Now it might be that we have no frame because we're in a
   // display:none subtree, or it might be that we're just dealing with
   // lazy frame construction and it hasn't happened yet.  Check which
   // one it is.
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -44,34 +44,40 @@
 #include "skia/SkBlurDrawLooper.h"
 #include "skia/SkBlurMaskFilter.h"
 #include "skia/SkColorFilter.h"
 #include "skia/SkLayerRasterizer.h"
 #include "skia/SkLayerDrawLooper.h"
 #include "skia/SkDashPathEffect.h"
 #include "Logging.h"
 #include "HelpersSkia.h"
-#include "gfxImageSurface.h"
 #include "Tools.h"
 #include <algorithm>
 
+#ifdef ANDROID
+# define USE_SOFT_CLIPPING false
+#else
+# define USE_SOFT_CLIPPING true
+#endif
+
 namespace mozilla {
 namespace gfx {
 
 SkColor ColorToSkColor(const Color &color, Float aAlpha)
 {
   //XXX: do a better job converting to int
   return SkColorSetARGB(color.a*aAlpha*255.0, color.r*255.0, color.g*255.0, color.b*255.0);
 }
 
 class GradientStopsSkia : public GradientStops
 {
 public:
-  GradientStopsSkia(const std::vector<GradientStop>& aStops, uint32_t aNumStops)
+  GradientStopsSkia(const std::vector<GradientStop>& aStops, uint32_t aNumStops, ExtendMode aExtendMode)
     : mCount(aNumStops)
+    , mExtendMode(aExtendMode)
   {
     if (mCount == 0) {
       return;
     }
 
     // Skia gradients always require a stop at 0.0 and 1.0, insert these if
     // we don't have them.
     uint32_t shift = 0;
@@ -98,16 +104,17 @@ public:
     }
   }
 
   BackendType GetBackendType() const { return BACKEND_SKIA; }
 
   std::vector<SkColor> mColors;
   std::vector<SkScalar> mPositions;
   int mCount;
+  ExtendMode mExtendMode;
 };
 
 SkXfermode::Mode
 GfxOpToSkiaOp(CompositionOp op)
 {
   switch (op)
   {
     case OP_OVER:
@@ -203,22 +210,99 @@ ExtendModeToTileMode(ExtendMode aMode)
     case EXTEND_REPEAT:
       return SkShader::kRepeat_TileMode;
     case EXTEND_REFLECT:
       return SkShader::kMirror_TileMode;
   }
   return SkShader::kClamp_TileMode;
 }
 
+void SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0)
+{
+  switch (aPattern.GetType()) {
+    case PATTERN_COLOR: {
+      Color color = static_cast<const ColorPattern&>(aPattern).mColor;
+      aPaint.setColor(ColorToSkColor(color, aAlpha));
+      break;
+    }
+    case PATTERN_LINEAR_GRADIENT: {
+      const LinearGradientPattern& pat = static_cast<const LinearGradientPattern&>(aPattern);
+      GradientStopsSkia *stops = static_cast<GradientStopsSkia*>(pat.mStops.get());
+      SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode);
+
+      if (stops->mCount >= 2) {
+        SkPoint points[2];
+        points[0] = SkPoint::Make(SkFloatToScalar(pat.mBegin.x), SkFloatToScalar(pat.mBegin.y));
+        points[1] = SkPoint::Make(SkFloatToScalar(pat.mEnd.x), SkFloatToScalar(pat.mEnd.y));
+
+        SkShader* shader = SkGradientShader::CreateLinear(points, 
+                                                          &stops->mColors.front(), 
+                                                          &stops->mPositions.front(), 
+                                                          stops->mCount, 
+                                                          mode);
+        SkMatrix mat;
+        GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
+        shader->setLocalMatrix(mat);
+        SkSafeUnref(aPaint.setShader(shader));
+      } else {
+        aPaint.setColor(SkColorSetARGB(0, 0, 0, 0));
+      }
+      break;
+    }
+    case PATTERN_RADIAL_GRADIENT: {
+      const RadialGradientPattern& pat = static_cast<const RadialGradientPattern&>(aPattern);
+      GradientStopsSkia *stops = static_cast<GradientStopsSkia*>(pat.mStops.get());
+      SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode);
+
+      if (stops->mCount >= 2) {
+        SkPoint points[2];
+        points[0] = SkPoint::Make(SkFloatToScalar(pat.mCenter1.x), SkFloatToScalar(pat.mCenter1.y));
+        points[1] = SkPoint::Make(SkFloatToScalar(pat.mCenter2.x), SkFloatToScalar(pat.mCenter2.y));
+
+        SkShader* shader = SkGradientShader::CreateTwoPointRadial(points[0], 
+                                                                  SkFloatToScalar(pat.mRadius1),
+                                                                  points[1], 
+                                                                  SkFloatToScalar(pat.mRadius2),
+                                                                  &stops->mColors.front(), 
+                                                                  &stops->mPositions.front(), 
+                                                                  stops->mCount, 
+                                                                  mode);
+        SkMatrix mat;
+        GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
+        shader->setLocalMatrix(mat);
+        SkSafeUnref(aPaint.setShader(shader));
+      } else {
+        aPaint.setColor(SkColorSetARGB(0, 0, 0, 0));
+      }
+      break;
+    }
+    case PATTERN_SURFACE: {
+      const SurfacePattern& pat = static_cast<const SurfacePattern&>(aPattern);
+      const SkBitmap& bitmap = static_cast<SourceSurfaceSkia*>(pat.mSurface.get())->GetBitmap();
+
+      SkShader::TileMode mode = ExtendModeToTileMode(pat.mExtendMode);
+      SkShader* shader = SkShader::CreateBitmapShader(bitmap, mode, mode);
+      SkMatrix mat;
+      GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
+      shader->setLocalMatrix(mat);
+      SkSafeUnref(aPaint.setShader(shader));
+      if (pat.mFilter == FILTER_POINT) {
+        aPaint.setFilterBitmap(false);
+      }
+      break;
+    }
+  }
+}
+
 struct AutoPaintSetup {
   AutoPaintSetup(SkCanvas *aCanvas, const DrawOptions& aOptions, const Pattern& aPattern)
     : mNeedsRestore(false), mAlpha(1.0)
   {
     Init(aCanvas, aOptions);
-    SetPattern(aPattern);
+    SetPaintPattern(mPaint, aPattern, mAlpha);
   }
 
   AutoPaintSetup(SkCanvas *aCanvas, const DrawOptions& aOptions)
     : mNeedsRestore(false), mAlpha(1.0)
   {
     Init(aCanvas, aOptions);
   }
 
@@ -256,70 +340,16 @@ struct AutoPaintSetup {
       mNeedsRestore = true;
     } else {
       mPaint.setAlpha(aOptions.mAlpha*255.0);
       mAlpha = aOptions.mAlpha;
     }
     mPaint.setFilterBitmap(true);
   }
 
-  void SetPattern(const Pattern& aPattern)
-  {
-    if (aPattern.GetType() == PATTERN_COLOR) {
-      Color color = static_cast<const ColorPattern&>(aPattern).mColor;
-      mPaint.setColor(ColorToSkColor(color, mAlpha));
-    } else if (aPattern.GetType() == PATTERN_LINEAR_GRADIENT) {
-      const LinearGradientPattern& pat = static_cast<const LinearGradientPattern&>(aPattern);
-      GradientStopsSkia *stops = static_cast<GradientStopsSkia*>(pat.mStops.get());
-
-      if (stops->mCount >= 2) {
-        SkPoint points[2];
-        points[0] = SkPoint::Make(SkFloatToScalar(pat.mBegin.x), SkFloatToScalar(pat.mBegin.y));
-        points[1] = SkPoint::Make(SkFloatToScalar(pat.mEnd.x), SkFloatToScalar(pat.mEnd.y));
-
-        SkShader* shader = SkGradientShader::CreateLinear(points, 
-                                                          &stops->mColors.front(), 
-                                                          &stops->mPositions.front(), 
-                                                          stops->mCount, 
-                                                          SkShader::kClamp_TileMode);
-        SkSafeUnref(mPaint.setShader(shader));
-      } else {
-        mPaint.setColor(SkColorSetARGB(0, 0, 0, 0));
-      }
-    } else if (aPattern.GetType() == PATTERN_RADIAL_GRADIENT) {
-      const RadialGradientPattern& pat = static_cast<const RadialGradientPattern&>(aPattern);
-      GradientStopsSkia *stops = static_cast<GradientStopsSkia*>(pat.mStops.get());
-
-      if (stops->mCount >= 2) {
-        SkPoint points[2];
-        points[0] = SkPoint::Make(SkFloatToScalar(pat.mCenter1.x), SkFloatToScalar(pat.mCenter1.y));
-        points[1] = SkPoint::Make(SkFloatToScalar(pat.mCenter2.x), SkFloatToScalar(pat.mCenter2.y));
-
-        SkShader* shader = SkGradientShader::CreateTwoPointRadial(points[0], 
-                                                                  SkFloatToScalar(pat.mRadius1),
-                                                                  points[1], 
-                                                                  SkFloatToScalar(pat.mRadius2),
-                                                                  &stops->mColors.front(), 
-                                                                  &stops->mPositions.front(), 
-                                                                  stops->mCount, 
-                                                                  SkShader::kClamp_TileMode);
-        SkSafeUnref(mPaint.setShader(shader));
-      } else {
-        mPaint.setColor(SkColorSetARGB(0, 0, 0, 0));
-      }
-    } else {
-      const SurfacePattern& pat = static_cast<const SurfacePattern&>(aPattern);
-      const SkBitmap& bitmap = static_cast<SourceSurfaceSkia*>(pat.mSurface.get())->GetBitmap();
-
-      SkShader::TileMode mode = ExtendModeToTileMode(pat.mExtendMode);
-      SkShader* shader = SkShader::CreateBitmapShader(bitmap, mode, mode);
-      SkSafeUnref(mPaint.setShader(shader));
-    }
-  }
-
   // TODO: Maybe add an operator overload to access this easier?
   SkPaint mPaint;
   bool mNeedsRestore;
   SkCanvas* mCanvas;
   Float mAlpha;
 };
 
 void
@@ -537,16 +567,46 @@ DrawTargetSkia::FillGlyphs(ScaledFont *a
     indices[i] = aBuffer.mGlyphs[i].mIndex;
     offsets[i].fX = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.x);
     offsets[i].fY = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.y);
   }
 
   mCanvas->drawPosText(&indices.front(), aBuffer.mNumGlyphs*2, &offsets.front(), paint.mPaint);
 }
 
+void
+DrawTargetSkia::Mask(const Pattern &aSource,
+                     const Pattern &aMask,
+                     const DrawOptions &aOptions)
+{
+  MarkChanged();
+  AutoPaintSetup paint(mCanvas.get(), aOptions, aSource);
+
+  SkPaint maskPaint;
+  SetPaintPattern(maskPaint, aMask);
+  
+  SkLayerRasterizer *raster = new SkLayerRasterizer();
+  raster->addLayer(maskPaint);
+  SkSafeUnref(paint.mPaint.setRasterizer(raster));
+
+  // Skia only uses the mask rasterizer when we are drawing a path/rect.
+  // Take our destination bounds and convert them into user space to use
+  // as the path to draw.
+  SkPath path;
+  path.addRect(SkRect::MakeWH(mSize.width, mSize.height));
+ 
+  Matrix temp = mTransform;
+  temp.Invert();
+  SkMatrix mat;
+  GfxMatrixToSkiaMatrix(temp, mat);
+  path.transform(mat);
+
+  mCanvas->drawPath(path, paint.mPaint);
+}
+
 TemporaryRef<SourceSurface>
 DrawTargetSkia::CreateSourceSurfaceFromData(unsigned char *aData,
                                              const IntSize &aSize,
                                              int32_t aStride,
                                              SurfaceFormat aFormat) const
 {
   RefPtr<SourceSurfaceSkia> newSurf = new SourceSurfaceSkia();
 
@@ -620,16 +680,31 @@ DrawTargetSkia::Init(const IntSize &aSiz
 
   mDevice = device.get();
   mCanvas = canvas.get();
   mFormat = aFormat;
   return true;
 }
 
 void
+DrawTargetSkia::Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat)
+{
+  mBitmap.setConfig(GfxFormatToSkiaConfig(aFormat), aSize.width, aSize.height, aStride);
+  mBitmap.setPixels(aData);
+  
+  SkAutoTUnref<SkDevice> device(new SkDevice(mBitmap));
+  SkAutoTUnref<SkCanvas> canvas(new SkCanvas(device.get()));
+  mSize = aSize;
+
+  mDevice = device.get();
+  mCanvas = canvas.get();
+  mFormat = aFormat;
+}
+
+void
 DrawTargetSkia::SetTransform(const Matrix& aTransform)
 {
   SkMatrix mat;
   GfxMatrixToSkiaMatrix(aTransform, mat);
   mCanvas->setMatrix(mat);
   mTransform = aTransform;
 }
 
@@ -641,33 +716,42 @@ DrawTargetSkia::CreatePathBuilder(FillRu
 }
 
 void
 DrawTargetSkia::ClearRect(const Rect &aRect)
 {
   MarkChanged();
   SkPaint paint;
   mCanvas->save();
-  mCanvas->clipRect(RectToSkRect(aRect), SkRegion::kIntersect_Op);
+  mCanvas->clipRect(RectToSkRect(aRect), SkRegion::kIntersect_Op, USE_SOFT_CLIPPING);
   paint.setColor(SkColorSetARGB(0, 0, 0, 0));
   paint.setXfermodeMode(SkXfermode::kSrc_Mode);
   mCanvas->drawPaint(paint);
   mCanvas->restore();
 }
 
 void
 DrawTargetSkia::PushClip(const Path *aPath)
 {
   if (aPath->GetBackendType() != BACKEND_SKIA) {
     return;
   }
 
   const PathSkia *skiaPath = static_cast<const PathSkia*>(aPath);
   mCanvas->save(SkCanvas::kClip_SaveFlag);
-  mCanvas->clipPath(skiaPath->GetPath());
+  mCanvas->clipPath(skiaPath->GetPath(), SkRegion::kIntersect_Op, USE_SOFT_CLIPPING);
+}
+
+void
+DrawTargetSkia::PushClipRect(const Rect& aRect)
+{
+  SkRect rect = RectToSkRect(aRect);
+
+  mCanvas->save(SkCanvas::kClip_SaveFlag);
+  mCanvas->clipRect(rect, SkRegion::kIntersect_Op, USE_SOFT_CLIPPING);
 }
 
 void
 DrawTargetSkia::PopClip()
 {
   mCanvas->restore();
 }
 
@@ -676,17 +760,17 @@ DrawTargetSkia::CreateGradientStops(Grad
 {
   std::vector<GradientStop> stops;
   stops.resize(aNumStops);
   for (uint32_t i = 0; i < aNumStops; i++) {
     stops[i] = aStops[i];
   }
   std::stable_sort(stops.begin(), stops.end());
   
-  return new GradientStopsSkia(stops, aNumStops);
+  return new GradientStopsSkia(stops, aNumStops, aExtendMode);
 }
 
 void
 DrawTargetSkia::AppendSnapshot(SourceSurfaceSkia* aSnapshot)
 {
   mSnapshots.push_back(aSnapshot);
 }
 
--- a/gfx/2d/DrawTargetSkia.h
+++ b/gfx/2d/DrawTargetSkia.h
@@ -96,35 +96,35 @@ public:
                     const Pattern &aPattern,
                     const DrawOptions &aOptions = DrawOptions());
   virtual void FillGlyphs(ScaledFont *aFont,
                           const GlyphBuffer &aBuffer,
                           const Pattern &aPattern,
                           const DrawOptions &aOptions = DrawOptions());
   virtual void Mask(const Pattern &aSource,
                     const Pattern &aMask,
-                    const DrawOptions &aOptions = DrawOptions())
-  { return; }
+                    const DrawOptions &aOptions = DrawOptions());
   virtual void PushClip(const Path *aPath);
-  virtual void PushClipRect(const Rect &aRect) { }
+  virtual void PushClipRect(const Rect& aRect);
   virtual void PopClip();
   virtual TemporaryRef<SourceSurface> CreateSourceSurfaceFromData(unsigned char *aData,
                                                             const IntSize &aSize,
                                                             int32_t aStride,
                                                             SurfaceFormat aFormat) const;
   virtual TemporaryRef<SourceSurface> OptimizeSourceSurface(SourceSurface *aSurface) const;
   virtual TemporaryRef<SourceSurface>
     CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const;
   virtual TemporaryRef<DrawTarget>
     CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const;
   virtual TemporaryRef<PathBuilder> CreatePathBuilder(FillRule aFillRule = FILL_WINDING) const;
   virtual TemporaryRef<GradientStops> CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, ExtendMode aExtendMode = EXTEND_CLAMP) const;
   virtual void SetTransform(const Matrix &aTransform);
 
   bool Init(const IntSize &aSize, SurfaceFormat aFormat);
+  void Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat);
   
   operator std::string() const {
     std::stringstream stream;
     stream << "DrawTargetSkia(" << this << ")";
     return stream.str();
   }
 private:
   friend class SourceSurfaceSkia;
@@ -133,14 +133,13 @@ private:
 
   void MarkChanged();
 
   IntSize mSize;
   SkBitmap mBitmap;
   SkRefPtr<SkCanvas> mCanvas;
   SkRefPtr<SkDevice> mDevice;
   nsRefPtr<gfxImageSurface> mImageSurface;
-  SurfaceFormat mFormat;
   vector<SourceSurfaceSkia*> mSnapshots;
 };
 
 }
 }
--- a/gfx/2d/SourceSurfaceSkia.cpp
+++ b/gfx/2d/SourceSurfaceSkia.cpp
@@ -69,24 +69,24 @@ SourceSurfaceSkia::GetFormat() const
 }
 
 bool 
 SourceSurfaceSkia::InitFromData(unsigned char* aData,
                                 const IntSize &aSize,
                                 int32_t aStride,
                                 SurfaceFormat aFormat)
 {
-  mBitmap.setConfig(GfxFormatToSkiaConfig(aFormat), aSize.width, aSize.height, aStride);
-  if (!mBitmap.allocPixels()) {
+  SkBitmap temp;
+  temp.setConfig(GfxFormatToSkiaConfig(aFormat), aSize.width, aSize.height, aStride);
+  temp.setPixels(aData);
+
+  if (!temp.copyTo(&mBitmap, GfxFormatToSkiaConfig(aFormat))) {
     return false;
   }
   
-  if (!mBitmap.copyPixelsFrom(aData, mBitmap.getSafeSize(), aStride)) {
-    return false;
-  }
   mSize = aSize;
   mFormat = aFormat;
   mStride = aStride;
   return true;
 }
 
 bool
 SourceSurfaceSkia::InitWithBitmap(const SkBitmap& aBitmap,
--- a/gfx/gl/GLContextProviderCGL.mm
+++ b/gfx/gl/GLContextProviderCGL.mm
@@ -42,16 +42,17 @@
 #include <AppKit/NSOpenGL.h>
 #include "gfxASurface.h"
 #include "gfxImageSurface.h"
 #include "gfxQuartzSurface.h"
 #include "gfxPlatform.h"
 #include "gfxFailure.h"
 #include "prenv.h"
 #include "mozilla/Preferences.h"
+#include "sampler.h"
 
 namespace mozilla {
 namespace gl {
 
 static bool gUseDoubleBufferedWindows = true;
 
 class CGLLibrary
 {
@@ -190,16 +191,17 @@ public:
 
     bool SupportsRobustness()
     {
         return false;
     }
 
     bool SwapBuffers()
     {
+      SAMPLE_LABEL("GLContext", "SwapBuffers");
       [mContext flushBuffer];
       return true;
     }
 
     bool BindTex2DOffscreen(GLContext *aOffscreen);
     void UnbindTex2DOffscreen(GLContext *aOffscreen);
     bool ResizeOffscreen(const gfxIntSize& aNewSize);
 
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -59,16 +59,18 @@
 #include "GLContext.h"
 #include "GLContextProvider.h"
 
 #include "nsIServiceManager.h"
 #include "nsIConsoleService.h"
 
 #include "gfxCrashReporterUtils.h"
 
+#include "sampler.h"
+
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gl;
 
 #ifdef CHECK_CURRENT_PROGRAM
 int LayerManagerOGLProgram::sCurrentProgramKey = 0;
 #endif
@@ -753,16 +755,17 @@ LayerManagerOGL::BindAndDrawQuadWithText
     }
     mGLContext->fDisableVertexAttribArray(texCoordAttribIndex);
   }
 }
 
 void
 LayerManagerOGL::Render()
 {
+  SAMPLE_LABEL("LayerManagerOGL", "Render");
   if (mDestroyed) {
     NS_WARNING("Call on destroyed layer manager");
     return;
   }
 
   nsIntRect rect;
   mWidget->GetClientBounds(rect);
   WorldTransformRect(rect);
--- a/gfx/skia/Makefile.in
+++ b/gfx/skia/Makefile.in
@@ -303,34 +303,33 @@ EXPORTS_skia += \
 CPPSRCS += \
 	SkFontHost_mac_coretext.cpp \
 	SkTime_Unix.cpp \
 	$(NULL)
 endif
 
 ifeq (android,$(MOZ_WIDGET_TOOLKIT))
 CPPSRCS += \
-	SkFontHost_FreeType.cpp \
-	SkFontHost_android.cpp \
-	SkFontHost_gamma.cpp \
+	SkFontHost_none.cpp \
 	SkMMapStream.cpp \
 	SkTime_Unix.cpp \
 	$(NULL)
 
 DEFINES += -DSK_BUILD_FOR_ANDROID_NDK
 OS_CXXFLAGS += $(CAIRO_FT_CFLAGS)
 endif
 
 ifeq (windows,$(MOZ_WIDGET_TOOLKIT))
 EXPORTS_skia += \
 	include/config/sk_stdint.h \
 	include/ports/SkTypeface_win.h \
 	$(NULL)
 CPPSRCS += \
 	SkFontHost_win.cpp \
+	SkFontHost_sandbox_none.cpp \
 	SkTime_win.cpp \
 	$(NULL)
 endif
 
 ifneq (,$(INTEL_ARCHITECTURE))
 CPPSRCS += \
 	SkBitmapProcState_opts_SSE2.cpp \
 	SkBlitRow_opts_SSE2.cpp \
new file mode 100644
--- /dev/null
+++ b/gfx/skia/README_MOZILLA
@@ -0,0 +1,5 @@
+The source from this directory was copied from the skia subversion trunk
+using the update.sh script. The changes made were those applied by update.sh,
+the addition/update of Makefile.in files for the Mozilla build system.
+
+The subversion revision used was r2980.
--- a/gfx/skia/fix-gradient-clamp.patch
+++ b/gfx/skia/fix-gradient-clamp.patch
@@ -1,30 +1,30 @@
 diff --git a/gfx/skia/src/effects/SkGradientShader.cpp b/gfx/skia/src/effects/SkGradientShader.cpp
 --- a/gfx/skia/src/effects/SkGradientShader.cpp
 +++ b/gfx/skia/src/effects/SkGradientShader.cpp
-@@ -165,16 +165,17 @@ private:
+@@ -167,16 +167,17 @@ private:
  
      mutable uint16_t*   fCache16;   // working ptr. If this is NULL, we need to recompute the cache values
      mutable SkPMColor*  fCache32;   // working ptr. If this is NULL, we need to recompute the cache values
  
      mutable uint16_t*   fCache16Storage;    // storage for fCache16, allocated on demand
      mutable SkMallocPixelRef* fCache32PixelRef;
      mutable unsigned    fCacheAlpha;        // the alpha value we used when we computed the cache. larger than 8bits so we can store uninitialized value
  
 +    static SkPMColor PremultiplyColor(SkColor c0, U8CPU alpha);
      static void Build16bitCache(uint16_t[], SkColor c0, SkColor c1, int count);
      static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
                                  U8CPU alpha);
      void setCacheAlpha(U8CPU alpha) const;
+     void initCommon();
  
      typedef SkShader INHERITED;
  };
- 
-@@ -505,16 +506,31 @@ static inline U8CPU dither_fixed_to_8(Sk
+@@ -512,16 +513,31 @@ static inline U8CPU dither_fixed_to_8(Sk
   *  For dithering with premultiply, we want to ceiling the alpha component,
   *  to ensure that it is always >= any color component.
   */
  static inline U8CPU dither_ceil_fixed_to_8(SkFixed n) {
      n >>= 8;
      return ((n << 1) - (n | (n >> 8))) >> 8;
  }
  
@@ -46,17 +46,17 @@ diff --git a/gfx/skia/src/effects/SkGrad
  void Gradient_Shader::Build32bitCache(SkPMColor cache[], SkColor c0, SkColor c1,
                                        int count, U8CPU paintAlpha) {
      SkASSERT(count > 1);
  
      // need to apply paintAlpha to our two endpoints
      SkFixed a = SkMulDiv255Round(SkColorGetA(c0), paintAlpha);
      SkFixed da;
      {
-@@ -606,24 +622,24 @@ const uint16_t* Gradient_Shader::getCach
+@@ -613,24 +629,24 @@ const uint16_t* Gradient_Shader::getCach
          }
      }
      return fCache16;
  }
  
  const SkPMColor* Gradient_Shader::getCache32() const {
      if (fCache32 == NULL) {
          // double the count for dither entries
@@ -73,17 +73,17 @@ diff --git a/gfx/skia/src/effects/SkGrad
          if (fColorCount == 2) {
              Build32bitCache(fCache32, fOrigColors[0], fOrigColors[1],
                              kCache32Count, fCacheAlpha);
          } else {
              Rec* rec = fRecs;
              int prevIndex = 0;
              for (int i = 1; i < fColorCount; i++) {
                  int nextIndex = SkFixedToFFFF(rec[i].fPos) >> (16 - kCache32Bits);
-@@ -637,28 +653,31 @@ const SkPMColor* Gradient_Shader::getCac
+@@ -644,28 +660,31 @@ const SkPMColor* Gradient_Shader::getCac
              }
              SkASSERT(prevIndex == kCache32Count - 1);
          }
  
          if (fMapper) {
              SkMallocPixelRef* newPR = SkNEW_ARGS(SkMallocPixelRef,
                                                   (NULL, allocSize, NULL));
              SkPMColor* linear = fCache32;           // just computed linear data
@@ -107,85 +107,86 @@ diff --git a/gfx/skia/src/effects/SkGrad
      return fCache32;
  }
  
  /*
   *  Because our caller might rebuild the same (logically the same) gradient
   *  over and over, we'd like to return exactly the same "bitmap" if possible,
   *  allowing the client to utilize a cache of our bitmap (e.g. with a GPU).
   *  To do that, we maintain a private cache of built-bitmaps, based on our
-@@ -866,29 +885,37 @@ void Linear_Gradient::shadeSpan(int x, i
+@@ -875,28 +894,38 @@ void Linear_Gradient::shadeSpan(int x, i
              dx = dxStorage[0];
          } else {
              SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
              dx = SkScalarToFixed(fDstToIndex.getScaleX());
          }
  
          if (SkFixedNearlyZero(dx)) {
              // we're a vertical gradient, so no change in a span
--            unsigned fi = proc(fx);
--            SkASSERT(fi <= 0xFFFF);
--            // TODO: dither version
--            sk_memset32(dstC, cache[fi >> (16 - kCache32Bits)], count);
+-            unsigned fi = proc(fx) >> (16 - kCache32Bits);
+-            sk_memset32_dither(dstC, cache[toggle + fi],
+-                                     cache[(toggle ^ TOGGLE_MASK) + fi], count);
 +            if (proc == clamp_tileproc) {
 +                if (fx < 0) {
 +                    sk_memset32(dstC, cache[-1], count);
 +                } else if (fx > 0xFFFF) {
 +                    sk_memset32(dstC, cache[kCache32Count * 2], count);
 +                } else {
-+                    sk_memset32(dstC, cache[fx >> (16 - kCache32Bits)], count);
++                    unsigned fi = proc(fx) >> (16 - kCache32Bits);
++                    sk_memset32_dither(dstC, cache[toggle + fi],
++                                       cache[(toggle ^ TOGGLE_MASK) + fi], count);
 +                }
 +            } else {
-+                unsigned fi = proc(fx);
-+                SkASSERT(fi <= 0xFFFF);
-+                // TODO: dither version
-+                sk_memset32(dstC, cache[fi >> (16 - kCache32Bits)], count);
++                unsigned fi = proc(fx) >> (16 - kCache32Bits);
++                sk_memset32_dither(dstC, cache[toggle + fi],
++                                   cache[(toggle ^ TOGGLE_MASK) + fi], count);
 +            }
          } else if (proc == clamp_tileproc) {
              SkClampRange range;
-             range.init(fx, dx, count, 0, 0xFF);
+-            range.init(fx, dx, count, 0, 0xFF);
++            range.init(fx, dx, count, cache[-1], cache[kCache32Count * 2]);
  
              if ((count = range.fCount0) > 0) {
 -                sk_memset32_dither(dstC,
 -                                   cache[toggle + range.fV0],
 -                                   cache[(toggle ^ TOGGLE_MASK) + range.fV0],
 -                                   count);
-+                // Do we really want to dither the clamp values?
-+                sk_memset32(dstC, cache[-1], count);
++                 // Do we really want to dither the clamp values?
++                 sk_memset32(dstC, range.fV0, count);
                  dstC += count;
              }
              if ((count = range.fCount1) > 0) {
                  int unroll = count >> 3;
                  fx = range.fFx1;
                  for (int i = 0; i < unroll; i++) {
                      NO_CHECK_ITER;  NO_CHECK_ITER;
                      NO_CHECK_ITER;  NO_CHECK_ITER;
-@@ -897,20 +924,17 @@ void Linear_Gradient::shadeSpan(int x, i
+@@ -905,20 +934,17 @@ void Linear_Gradient::shadeSpan(int x, i
                  }
                  if ((count &= 7) > 0) {
                      do {
                          NO_CHECK_ITER;
                      } while (--count != 0);
                  }
              }
              if ((count = range.fCount2) > 0) {
 -                sk_memset32_dither(dstC,
 -                                   cache[toggle + range.fV1],
 -                                   cache[(toggle ^ TOGGLE_MASK) + range.fV1],
 -                                   count);
-+                sk_memset32(dstC, cache[kCache32Count * 2], count);
++                sk_memset32(dstC, range.fV1, count);
              }
          } else if (proc == mirror_tileproc) {
              do {
                  unsigned fi = mirror_8bits(fx >> 8);
                  SkASSERT(fi <= 0xFF);
                  fx += dx;
                  *dstC++ = cache[toggle + fi];
                  toggle ^= TOGGLE_MASK;
-@@ -1662,19 +1686,24 @@ public:
+@@ -1670,19 +1699,24 @@ public:
              }
              SkScalar b = (SkScalarMul(fDiff.fX, fx) +
                           SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
              SkScalar db = (SkScalarMul(fDiff.fX, dx) +
                            SkScalarMul(fDiff.fY, dy)) * 2;
              if (proc == clamp_tileproc) {
                  for (; count > 0; --count) {
                      SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, posRoot);
@@ -203,22 +204,8 @@ diff --git a/gfx/skia/src/effects/SkGrad
                      fx += dx;
                      fy += dy;
                      b += db;
                  }
              } else if (proc == mirror_tileproc) {
                  for (; count > 0; --count) {
                      SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, posRoot);
                      SkFixed index = mirror_tileproc(t);
-diff --git a/gfx/skia/update.sh b/gfx/skia/update.sh
---- a/gfx/skia/update.sh
-+++ b/gfx/skia/update.sh
-@@ -90,9 +90,10 @@ if [ -n "$rev" ]; then
-   version=$rev
-   sed -i "" "s/r[0-9][0-9][0-9][0-9]/r$version/" README_MOZILLA
- else
-   echo "Remember to update README_MOZILLA with the version details."
- fi
- 
- # Patch to get arm opts to build with frame pointers enabled. Bug 689069
- patch -p3 < arm-opts.patch
-+patch -p3
- 
new file mode 100644
--- /dev/null
+++ b/gfx/skia/getpostextpath.patch
@@ -0,0 +1,70 @@
+diff --git a/gfx/skia/include/core/SkPaint.h b/gfx/skia/include/core/SkPaint.h
+--- a/gfx/skia/include/core/SkPaint.h
++++ b/gfx/skia/include/core/SkPaint.h
+@@ -836,16 +836,19 @@ public:
+ 
+     /** Return the path (outline) for the specified text.
+         Note: just like SkCanvas::drawText, this will respect the Align setting
+               in the paint.
+     */
+     void getTextPath(const void* text, size_t length, SkScalar x, SkScalar y,
+                      SkPath* path) const;
+ 
++    void getPosTextPath(const void* text, size_t length, 
++                        const SkPoint pos[], SkPath* path) const;
++
+ #ifdef SK_BUILD_FOR_ANDROID
+     const SkGlyph& getUnicharMetrics(SkUnichar);
+     const void* findImage(const SkGlyph&);
+ 
+     uint32_t getGenerationID() const;
+ #endif
+ 
+     // returns true if the paint's settings (e.g. xfermode + alpha) resolve to
+diff --git a/gfx/skia/src/core/SkPaint.cpp b/gfx/skia/src/core/SkPaint.cpp
+--- a/gfx/skia/src/core/SkPaint.cpp
++++ b/gfx/skia/src/core/SkPaint.cpp
+@@ -1242,16 +1242,43 @@ void SkPaint::getTextPath(const void* te
+     const SkPath*   iterPath;
+     while ((iterPath = iter.next(&xpos)) != NULL) {
+         matrix.postTranslate(xpos - prevXPos, 0);
+         path->addPath(*iterPath, matrix);
+         prevXPos = xpos;
+     }
+ }
+ 
++void SkPaint::getPosTextPath(const void* textData, size_t length,
++                             const SkPoint pos[], SkPath* path) const {
++    SkASSERT(length == 0 || textData != NULL);
++
++    const char* text = (const char*)textData;
++    if (text == NULL || length == 0 || path == NULL) {
++        return;
++    }
++
++    SkTextToPathIter    iter(text, length, *this, false, true);
++    SkMatrix            matrix;
++    SkPoint             prevPos;
++    prevPos.set(0, 0);
++
++    matrix.setScale(iter.getPathScale(), iter.getPathScale());
++    path->reset();
++
++    unsigned int    i = 0;
++    const SkPath*   iterPath;
++    while ((iterPath = iter.next(NULL)) != NULL) {
++        matrix.postTranslate(pos[i].fX - prevPos.fX, pos[i].fY - prevPos.fY);
++        path->addPath(*iterPath, matrix);
++        prevPos = pos[i];
++        i++;
++    }
++}
++
+ static void add_flattenable(SkDescriptor* desc, uint32_t tag,
+                             SkFlattenableWriteBuffer* buffer) {
+     buffer->flatten(desc->addEntry(tag, buffer->size(), NULL));
+ }
+ 
+ // SkFontHost can override this choice in FilterRec()
+ static SkMask::Format computeMaskFormat(const SkPaint& paint) {
+     uint32_t flags = paint.getFlags();
--- a/gfx/skia/include/config/SkUserConfig.h
+++ b/gfx/skia/include/config/SkUserConfig.h
@@ -88,28 +88,28 @@
 
 
 /*  Some compilers don't support long long for 64bit integers. If yours does
     not, define this to the appropriate type.
  */
 //#define SkLONGLONG int64_t
 
 
-/*  Some envorinments do not suport writable globals (eek!). If yours does not,
-    define this flag.
- */
-//#define SK_USE_RUNTIME_GLOBALS
-
-
 /*  To write debug messages to a console, skia will call SkDebugf(...) following
     printf conventions (e.g. const char* format, ...). If you want to redirect
     this to something other than printf, define yours here
  */
 //#define SkDebugf(...)  MyFunction(__VA_ARGS__)
 
+/*
+ *  To specify a different default font cache limit, define this. If this is
+ *  undefined, skia will use a built-in value.
+ */
+//#define SK_DEFAULT_FONT_CACHE_LIMIT   (1024 * 1024)
+
 /* If defined, use CoreText instead of ATSUI on OS X.
 */
 //#define SK_USE_MAC_CORE_TEXT
 
 
 /*  If zlib is available and you want to support the flate compression
     algorithm (used in PDF generation), define SK_ZLIB_INCLUDE to be the
     include path.
@@ -140,16 +140,18 @@
 /*  If SK_DEBUG is defined, then you can optionally define SK_SUPPORT_UNITTEST
     which will run additional self-tests at startup. These can take a long time,
     so this flag is optional.
  */
 #ifdef SK_DEBUG
 //#define SK_SUPPORT_UNITTEST
 #endif
 
+/*  Don't dither 32bit gradients, to match what the canvas test suite expects.
+ */
 #define SK_DISABLE_DITHER_32BIT_GRADIENT
 
 /* If your system embeds skia and has complex event logging, define this
    symbol to name a file that maps the following macros to your system's
    equivalents:
        SK_TRACE_EVENT0(event)
        SK_TRACE_EVENT1(event, name1, value1)
        SK_TRACE_EVENT2(event, name1, value1, name2, value2)
@@ -163,13 +165,15 @@
  */
 #ifdef SK_SAMPLES_FOR_X
         #define SK_R32_SHIFT    16
         #define SK_G32_SHIFT    8
         #define SK_B32_SHIFT    0
         #define SK_A32_SHIFT    24
 #endif
 
+/*  Don't include stdint.h on windows as it conflicts with our build system.
+ */
 #ifdef SK_BUILD_FOR_WIN32 
-        #define SK_IGNORE_STDINT_DOT_H 
- #endif 
+    #define SK_IGNORE_STDINT_DOT_H 
+#endif 
 
 #endif
--- a/gfx/skia/include/core/SkBitmap.h
+++ b/gfx/skia/include/core/SkBitmap.h
@@ -153,16 +153,29 @@ public:
         size.setMul(fHeight, fRowBytes);
         return size;
     }
 
     /** Same as getSafeSize(), but does not truncate the answer to 32bits.
     */
     Sk64 getSafeSize64() const ;
 
+    /** Returns true if this bitmap is marked as immutable, meaning that the
+        contents of its pixels will not change for the lifetime of the bitmap.
+    */
+    bool isImmutable() const;
+
+    /** Marks this bitmap as immutable, meaning that the contents of its
+        pixels will not change for the lifetime of the bitmap and of the
+        underlying pixelref. This state can be set, but it cannot be 
+        cleared once it is set. This state propagates to all other bitmaps
+        that share the same pixelref.
+    */
+    void setImmutable();
+
     /** Returns true if the bitmap is opaque (has no translucent/transparent pixels).
     */
     bool isOpaque() const;
 
     /** Specify if this bitmap's pixels are all opaque or not. Is only meaningful for configs
         that support per-pixel alpha (RGB32, A1, A8).
     */
     void setIsOpaque(bool);
@@ -220,51 +233,35 @@ public:
         @param pixels   Address for the pixels, managed by the caller.
         @param ctable   ColorTable (or null) that matches the specified pixels
     */
     void setPixels(void* p, SkColorTable* ctable = NULL);
 
     /** Copies the bitmap's pixels to the location pointed at by dst and returns
         true if possible, returns false otherwise.
 
-        In the event that the bitmap's stride is equal to dstRowBytes, and if
-        it is greater than strictly required by the bitmap's current config
-        (this may happen if the bitmap is an extracted subset of another), then
-        this function will copy bytes past the eand of each row, excluding the
-        last row. No copies are made outside of the declared size of dst,
-        however.
+        In the case when the dstRowBytes matches the bitmap's rowBytes, the copy
+        may be made faster by copying over the dst's per-row padding (for all
+        rows but the last). By setting preserveDstPad to true the caller can
+        disable this optimization and ensure that pixels in the padding are not
+        overwritten.
 
         Always returns false for RLE formats.
 
         @param dst      Location of destination buffer.
         @param dstSize  Size of destination buffer. Must be large enough to hold
                         pixels using indicated stride.
         @param dstRowBytes  Width of each line in the buffer. If -1, uses
                             bitmap's internal stride.
+        @param preserveDstPad Must we preserve padding in the dst
     */
-    bool copyPixelsTo(void* const dst, size_t dstSize, int dstRowBytes = -1)
+    bool copyPixelsTo(void* const dst, size_t dstSize, int dstRowBytes = -1,
+                      bool preserveDstPad = false)
          const;
 
-    /** Copies the pixels at location src to the bitmap's pixel buffer.
-        Returns true if copy if possible (bitmap buffer is large enough),
-        false otherwise.
-
-        Like copyPixelsTo, this function may write values beyond the end of
-        each row, although never outside the defined buffer.
-
-        Always returns false for RLE formats.
-
-        @param src      Location of the source buffer.
-        @param srcSize  Height of source buffer in pixels.
-        @param srcRowBytes  Width of each line in the buffer. If -1, uses i
-                            bitmap's internal stride.
-    */
-    bool copyPixelsFrom(const void* const src, size_t srcSize,
-                        int srcRowBytes = -1);
-
     /** Use the standard HeapAllocator to create the pixelref that manages the
         pixel memory. It will be sized based on the current width/height/config.
         If this is called multiple times, a new pixelref object will be created
         each time.
 
         If the bitmap retains a reference to the colortable (assuming it is
         not null) it will take care of incrementing the reference count.
 
@@ -473,29 +470,39 @@ public:
         returned and dst will be untouched.
         @param dst  The bitmap that will be set to a subset of this bitmap
         @param subset The rectangle of pixels in this bitmap that dst will
                       reference.
         @return true if the subset copy was successfully made.
     */
     bool extractSubset(SkBitmap* dst, const SkIRect& subset) const;
 
-    /** Makes a deep copy of this bitmap, respecting the requested config.
-        Returns false if either there is an error (i.e. the src does not have
-        pixels) or the request cannot be satisfied (e.g. the src has per-pixel
-        alpha, and the requested config does not support alpha).
-        @param dst The bitmap to be sized and allocated
-        @param c The desired config for dst
-        @param allocator Allocator used to allocate the pixelref for the dst
-                         bitmap. If this is null, the standard HeapAllocator
-                         will be used.
-        @return true if the copy could be made.
-    */
+    /** Makes a deep copy of this bitmap, respecting the requested config,
+     *  and allocating the dst pixels on the cpu.
+     *  Returns false if either there is an error (i.e. the src does not have
+     *  pixels) or the request cannot be satisfied (e.g. the src has per-pixel
+     *  alpha, and the requested config does not support alpha).
+     *  @param dst The bitmap to be sized and allocated
+     *  @param c The desired config for dst
+     *  @param allocator Allocator used to allocate the pixelref for the dst
+     *                   bitmap. If this is null, the standard HeapAllocator
+     *                   will be used.
+     *  @return true if the copy could be made.
+     */
     bool copyTo(SkBitmap* dst, Config c, Allocator* allocator = NULL) const;
 
+    /** Makes a deep copy of this bitmap, respecting the requested config, and
+     *  with custom allocation logic that will keep the copied pixels
+     *  in the same domain as the source: If the src pixels are allocated for
+     *  the cpu, then so will the dst. If the src pixels are allocated on the
+     *  gpu (typically as a texture), the it will do the same for the dst.
+     *  If the request cannot be fulfilled, returns false and dst is unmodified.
+     */
+    bool deepCopyTo(SkBitmap* dst, Config c) const;
+
     /** Returns true if this bitmap can be deep copied into the requested config
         by calling copyTo().
      */
     bool canCopyTo(Config newConfig) const;
 
     bool hasMipMap() const;
     void buildMipMap(bool forceRebuild = false);
     void freeMipMap();
@@ -590,18 +597,19 @@ private:
     mutable void*       fPixels;
     mutable SkColorTable* fColorTable;    // only meaningful for kIndex8
     // When there is no pixel ref (setPixels was called) we still need a
     // gen id for SkDevice implementations that may cache a copy of the
     // pixels (e.g. as a gpu texture)
     mutable int         fRawPixelGenerationID;
 
     enum Flags {
-        kImageIsOpaque_Flag = 0x01,
-        kImageIsVolatile_Flag     = 0x02
+        kImageIsOpaque_Flag     = 0x01,
+        kImageIsVolatile_Flag   = 0x02,
+        kImageIsImmutable_Flag  = 0x04
     };
 
     uint32_t    fRowBytes;
     uint32_t    fWidth;
     uint32_t    fHeight;
     uint8_t     fConfig;
     uint8_t     fFlags;
     uint8_t     fBytesPerPixel; // based on config
--- a/gfx/skia/include/core/SkBlitter.h
+++ b/gfx/skia/include/core/SkBlitter.h
@@ -12,55 +12,76 @@
 
 #include "SkBitmap.h"
 #include "SkMatrix.h"
 #include "SkPaint.h"
 #include "SkRefCnt.h"
 #include "SkRegion.h"
 #include "SkMask.h"
 
+/** SkBlitter and its subclasses are responsible for actually writing pixels
+    into memory. Besides efficiency, they handle clipping and antialiasing.
+*/
 class SkBlitter {
 public:
     virtual ~SkBlitter();
 
+    /// Blit a horizontal run of one or more pixels.
     virtual void blitH(int x, int y, int width);
-    virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
-                           const int16_t* runs);
+    /// Blit a horizontal run of antialiased pixels; runs[] is a *sparse*
+    /// zero-terminated run-length encoding of spans of constant alpha values.
+    virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
+                           const int16_t runs[]);
+    /// Blit a vertical run of pixels with a constant alpha value.
     virtual void blitV(int x, int y, int height, SkAlpha alpha);
+    /// Blit a solid rectangle one or more pixels wide.
     virtual void blitRect(int x, int y, int width, int height);
+    /** Blit a rectangle with one alpha-blended column on the left,
+        width (zero or more) opaque pixels, and one alpha-blended column
+        on the right.
+        The result will always be at least two pixels wide.
+    */
+    virtual void blitAntiRect(int x, int y, int width, int height,
+                              SkAlpha leftAlpha, SkAlpha rightAlpha);
+    /// Blit a pattern of pixels defined by a rectangle-clipped mask;
+    /// typically used for text.
     virtual void blitMask(const SkMask&, const SkIRect& clip);
 
-    /*  If the blitter just sets a single value for each pixel, return the
+    /** If the blitter just sets a single value for each pixel, return the
         bitmap it draws into, and assign value. If not, return NULL and ignore
         the value parameter.
     */
     virtual const SkBitmap* justAnOpaqueColor(uint32_t* value);
 
-    // not virtual, just helpers
+    ///@name non-virtual helpers
     void blitMaskRegion(const SkMask& mask, const SkRegion& clip);
     void blitRectRegion(const SkIRect& rect, const SkRegion& clip);
     void blitRegion(const SkRegion& clip);
+    ///@}
 
-    // factories
+    /** @name Factories
+        Return the correct blitter to use given the specified context.
+     */
     static SkBlitter* Choose(const SkBitmap& device,
                              const SkMatrix& matrix,
                              const SkPaint& paint) {
         return Choose(device, matrix, paint, NULL, 0);
     }
 
     static SkBlitter* Choose(const SkBitmap& device,
                              const SkMatrix& matrix,
                              const SkPaint& paint,
                              void* storage, size_t storageSize);
 
     static SkBlitter* ChooseSprite(const SkBitmap& device,
                                    const SkPaint&,
                                    const SkBitmap& src,
                                    int left, int top,
                                    void* storage, size_t storageSize);
+    ///@}
 
 private:
 };
 
 /** This blitter silently never draws anything.
 */
 class SkNullBlitter : public SkBlitter {
 public:
@@ -80,56 +101,62 @@ public:
 class SkRectClipBlitter : public SkBlitter {
 public:
     void init(SkBlitter* blitter, const SkIRect& clipRect) {
         SkASSERT(!clipRect.isEmpty());
         fBlitter = blitter;
         fClipRect = clipRect;
     }
 
-    // overrides
     virtual void blitH(int x, int y, int width) SK_OVERRIDE;
     virtual void blitAntiH(int x, int y, const SkAlpha[],
                            const int16_t runs[]) SK_OVERRIDE;
     virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE;
     virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE;
+    virtual void blitAntiRect(int x, int y, int width, int height,
+                     SkAlpha leftAlpha, SkAlpha rightAlpha) SK_OVERRIDE;
     virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE;
     virtual const SkBitmap* justAnOpaqueColor(uint32_t* value) SK_OVERRIDE;
 
 private:
     SkBlitter*  fBlitter;
     SkIRect     fClipRect;
 };
 
 /** Wraps another (real) blitter, and ensures that the real blitter is only
-called with coordinates that have been clipped by the specified clipRgn.
-This means the caller need not perform the clipping ahead of time.
+    called with coordinates that have been clipped by the specified clipRgn.
+    This means the caller need not perform the clipping ahead of time.
 */
 class SkRgnClipBlitter : public SkBlitter {
 public:
     void init(SkBlitter* blitter, const SkRegion* clipRgn) {
         SkASSERT(clipRgn && !clipRgn->isEmpty());
         fBlitter = blitter;
         fRgn = clipRgn;
     }
 
-    // overrides
     virtual void blitH(int x, int y, int width) SK_OVERRIDE;
     virtual void blitAntiH(int x, int y, const SkAlpha[],
                            const int16_t runs[]) SK_OVERRIDE;
     virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE;
     virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE;
+    virtual void blitAntiRect(int x, int y, int width, int height,
+                     SkAlpha leftAlpha, SkAlpha rightAlpha) SK_OVERRIDE;
     virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE;
     virtual const SkBitmap* justAnOpaqueColor(uint32_t* value) SK_OVERRIDE;
 
 private:
     SkBlitter*      fBlitter;
     const SkRegion* fRgn;
 };
 
+/** Factory to set up the appropriate most-efficient wrapper blitter
+    to apply a clip. Returns a pointer to a member, so lifetime must
+    be managed carefully.
+*/
 class SkBlitterClipper {
 public:
     SkBlitter*  apply(SkBlitter* blitter, const SkRegion* clip,
                       const SkIRect* bounds = NULL);
 
 private:
     SkNullBlitter       fNullBlitter;
     SkRectClipBlitter   fRectBlitter;
--- a/gfx/skia/include/core/SkCanvas.h
+++ b/gfx/skia/include/core/SkCanvas.h
@@ -56,16 +56,23 @@ public:
         @param bitmap   Specifies a bitmap for the canvas to draw into. Its
                         structure are copied to the canvas.
     */
     explicit SkCanvas(const SkBitmap& bitmap);
     virtual ~SkCanvas();
 
     ///////////////////////////////////////////////////////////////////////////
 
+    /**
+     *  Return the width/height of the underlying device. The current drawable
+     *  area may be small (due to clipping or saveLayer). For a canvas with
+     *  no device, 0,0 will be returned.
+     */
+    SkISize getDeviceSize() const;
+
     /** Return the canvas' device object, which may be null. The device holds
         the bitmap of the pixels that the canvas draws into. The reference count
         of the returned device is not changed by this call.
     */
     SkDevice* getDevice() const;
 
     /** Specify a device for this canvas to draw into. If it is not null, its
         reference count is incremented. If the canvas was already holding a
@@ -94,33 +101,116 @@ public:
      */
     SkDevice* createCompatibleDevice(SkBitmap::Config config, 
                                     int width, int height,
                                     bool isOpaque);
 
     ///////////////////////////////////////////////////////////////////////////
 
     /**
-     *  Copy the pixels from the device into bitmap. Returns true on success.
-     *  If false is returned, then the bitmap parameter is left unchanged.
-     *  The bitmap parameter is treated as output-only, and will be completely
-     *  overwritten (if the method returns true).
+     * This enum can be used with read/writePixels to perform a pixel ops to or
+     * from an 8888 config other than Skia's native config (SkPMColor). There
+     * are three byte orders supported: native, BGRA, and RGBA. Each has a
+     * premultiplied and unpremultiplied variant.
+     *
+     * Components of a 8888 pixel can be packed/unpacked from a 32bit word using
+     * either byte offsets or shift values. Byte offsets are endian-invariant
+     * while shifts are not. BGRA and RGBA configs are defined by byte
+     * orderings. The native config is defined by shift values (SK_A32_SHIFT,
+     * ..., SK_B32_SHIFT).
+     */
+    enum Config8888 {
+        /**
+         * Skia's native order specified by:
+         *      SK_A32_SHIFT, SK_R32_SHIFT, SK_G32_SHIFT, and SK_B32_SHIFT
+         *
+         * kNative_Premul_Config8888 is equivalent to SkPMColor
+         * kNative_Unpremul_Config8888 has the same component order as SkPMColor
+         * but is not premultiplied.
+         */
+        kNative_Premul_Config8888,
+        kNative_Unpremul_Config8888,
+        /**
+         * low byte to high byte: B, G, R, A.
+         */
+        kBGRA_Premul_Config8888,
+        kBGRA_Unpremul_Config8888,
+        /**
+         * low byte to high byte: R, G, B, A.
+         */
+        kRGBA_Premul_Config8888,
+        kRGBA_Unpremul_Config8888,
+    };
+
+    /**
+     *  On success (returns true), copy the canvas pixels into the bitmap.
+     *  On failure, the bitmap parameter is left unchanged and false is
+     *  returned.
+     *
+     *  The canvas' pixels are converted to the bitmap's config. The only
+     *  supported config is kARGB_8888_Config, though this is likely to be
+     *  relaxed in  the future. The meaning of config kARGB_8888_Config is
+     *  modified by the enum param config8888. The default value interprets
+     *  kARGB_8888_Config as SkPMColor
+     *
+     *  If the bitmap has pixels already allocated, the canvas pixels will be
+     *  written there. If not, bitmap->allocPixels() will be called 
+     *  automatically. If the bitmap is backed by a texture readPixels will
+     *  fail.
+     *
+     *  The actual pixels written is the intersection of the canvas' bounds, and
+     *  the rectangle formed by the bitmap's width,height and the specified x,y.
+     *  If bitmap pixels extend outside of that intersection, they will not be
+     *  modified.
+     *
+     *  Other failure conditions:
+     *    * If the canvas is backed by a non-raster device (e.g. PDF) then
+     *       readPixels will fail.
+     *    * If bitmap is texture-backed then readPixels will fail. (This may be
+     *       relaxed in the future.)
+     *
+     *  Example that reads the entire canvas into a bitmap using the native
+     *  SkPMColor:
+     *    SkISize size = canvas->getDeviceSize();
+     *    bitmap->setConfig(SkBitmap::kARGB_8888_Config, size.fWidth,
+     *                                                   size.fHeight);
+     *    if (canvas->readPixels(bitmap, 0, 0)) {
+     *       // use the pixels
+     *    }
+     */
+    bool readPixels(SkBitmap* bitmap,
+                    int x, int y,
+                    Config8888 config8888 = kNative_Premul_Config8888);
+
+    /**
+     * DEPRECATED: This will be removed as soon as webkit is no longer relying
+     * on it. The bitmap is resized to the intersection of srcRect and the
+     * canvas bounds. New pixels are always allocated on success. Bitmap is
+     * unmodified on failure.
      */
     bool readPixels(const SkIRect& srcRect, SkBitmap* bitmap);
-    bool readPixels(SkBitmap* bitmap);
 
     /**
      *  Similar to draw sprite, this method will copy the pixels in bitmap onto
-     *  the device, with the top/left corner specified by (x, y). The pixel
-     *  values in the device are completely replaced: there is no blending.
+     *  the canvas, with the top/left corner specified by (x, y). The canvas'
+     *  pixel values are completely replaced: there is no blending.
+     *
+     *  Currently if bitmap is backed by a texture this is a no-op. This may be
+     *  relaxed in the future.
+     *
+     *  If the bitmap has config kARGB_8888_Config then the config8888 param
+     *  will determines how the pixel valuess are intepreted. If the bitmap is
+     *  not kARGB_8888_Config then this parameter is ignored.
      *
      *  Note: If you are recording drawing commands on this canvas to
      *  SkPicture, writePixels() is ignored!
      */
-    void writePixels(const SkBitmap& bitmap, int x, int y);
+    void writePixels(const SkBitmap& bitmap,
+                     int x, int y,
+                     Config8888 config8888 = kNative_Premul_Config8888);
 
     ///////////////////////////////////////////////////////////////////////////
 
     enum SaveFlags {
         /** save the matrix state, restoring it on restore() */
         kMatrix_SaveFlag            = 0x01,
         /** save the clip state, restoring it on restore() */
         kClip_SaveFlag              = 0x02,
@@ -192,16 +282,21 @@ public:
 
     /** Efficient way to pop any calls to save() that happened after the save
         count reached saveCount. It is an error for saveCount to be less than
         getSaveCount()
         @param saveCount    The number of save() levels to restore from
     */
     void restoreToCount(int saveCount);
 
+    /** Returns true if drawing is currently going to a layer (from saveLayer)
+     *  rather than to the root device.
+     */
+    bool isDrawingToLayer() const;
+
     /** Preconcat the current matrix with the specified translation
         @param dx   The distance to translate in X
         @param dy   The distance to translate in Y
         returns true if the operation succeeded (e.g. did not overflow)
     */
     virtual bool translate(SkScalar dx, SkScalar dy);
 
     /** Preconcat the current matrix with the specified scale.
@@ -641,17 +736,17 @@ public:
         @param matrix       (may be null) Applied to the text before it is
                             mapped onto the path
         @param paint        The paint used for the text
         */
     virtual void drawTextOnPath(const void* text, size_t byteLength,
                                 const SkPath& path, const SkMatrix* matrix,
                                 const SkPaint& paint);
 
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
     /** Draw the text on path, with each character/glyph origin specified by the pos[]
         array. The origin is interpreted by the Align setting in the paint.
         @param text The text to be drawn
         @param byteLength   The number of bytes to read from the text parameter
         @param pos      Array of positions, used to position each character
         @param paint    The paint used for the text (e.g. color, size, style)
         @param path The path to draw on
         @param matrix The canvas matrix
@@ -837,16 +932,17 @@ private:
     SkDeque     fMCStack;
     // points to top of stack
     MCRec*      fMCRec;
     // the first N recs that can fit here mean we won't call malloc
     uint32_t    fMCRecStorage[32];
 
     SkBounder*  fBounder;
     SkDevice*   fLastDeviceToGainFocus;
+    int         fLayerCount;    // number of successful saveLayer calls
 
     void prepareForDeviceDraw(SkDevice*, const SkMatrix&, const SkRegion&,
                               const SkClipStack& clipStack);
 
     bool fDeviceCMDirty;            // cleared by updateDeviceCMCache()
     void updateDeviceCMCache();
 
     friend class SkDrawIter;    // needs setupDrawForLayerDevice()
--- a/gfx/skia/include/core/SkColorFilter.h
+++ b/gfx/skia/include/core/SkColorFilter.h
@@ -18,16 +18,41 @@ class SK_API SkColorFilter : public SkFl
 public:
     /**
      *  If the filter can be represented by a source color plus Mode, this
      *  returns true, and sets (if not NULL) the color and mode appropriately.
      *  If not, this returns false and ignores the parameters.
      */
     virtual bool asColorMode(SkColor* color, SkXfermode::Mode* mode);
 
+    /**
+     *  If the filter can be represented by a 5x4 matrix, this
+     *  returns true, and sets the matrix appropriately.
+     *  If not, this returns false and ignores the parameter.
+     */
+    virtual bool asColorMatrix(SkScalar matrix[20]);
+
+    /**
+     *  If the filter can be represented by per-component table, return true,
+     *  and if table is not null, copy the bitmap containing the table into it.
+     *
+     *  The table bitmap will be in SkBitmap::kA8_Config. Each row corresponding
+     *  to each component in ARGB order. e.g. row[0] == alpha, row[1] == red,
+     *  etc. To transform a color, you (logically) perform the following:
+     *
+     *      a' = *table.getAddr8(a, 0);
+     *      r' = *table.getAddr8(r, 1);
+     *      g' = *table.getAddr8(g, 2);
+     *      b' = *table.getAddr8(b, 3);
+     *
+     *  The original component value is the horizontal index for a given row,
+     *  and the stored value at that index is the new value for that component.
+     */
+    virtual bool asComponentTable(SkBitmap* table);
+
     /** Called with a scanline of colors, as if there was a shader installed.
         The implementation writes out its filtered version into result[].
         Note: shader and result may be the same buffer.
         @param src      array of colors, possibly generated by a shader
         @param count    the number of entries in the src[] and result[] arrays
         @param result   written by the filter
     */
     virtual void filterSpan(const SkPMColor src[], int count,
@@ -87,17 +112,18 @@ public:
                                            SkXfermodeProc16 proc16 = NULL);
 
     /** Create a colorfilter that multiplies the RGB channels by one color, and
         then adds a second color, pinning the result for each component to
         [0..255]. The alpha components of the mul and add arguments
         are ignored.
     */
     static SkColorFilter* CreateLightingFilter(SkColor mul, SkColor add);
-
+    
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
 protected:
     SkColorFilter() {}
     SkColorFilter(SkFlattenableReadBuffer& rb) : INHERITED(rb) {}
 
 private:
     typedef SkFlattenable INHERITED;
 };
 
--- a/gfx/skia/include/core/SkColorShader.h
+++ b/gfx/skia/include/core/SkColorShader.h
@@ -27,40 +27,42 @@ public:
     /** Create a ColorShader that ignores the color in the paint, and uses the
         specified color. Note: like all shaders, at draw time the paint's alpha
         will be respected, and is applied to the specified color.
     */
     SkColorShader(SkColor c);
 
     virtual ~SkColorShader();
 
-    virtual uint32_t getFlags() { return fFlags; }
-    virtual uint8_t getSpan16Alpha() const;
+    virtual uint32_t getFlags() SK_OVERRIDE;
+    virtual uint8_t getSpan16Alpha() const SK_OVERRIDE;
+    virtual bool isOpaque() const SK_OVERRIDE;
     virtual bool setContext(const SkBitmap& device, const SkPaint& paint,
-                            const SkMatrix& matrix);
-    virtual void shadeSpan(int x, int y, SkPMColor span[], int count);
-    virtual void shadeSpan16(int x, int y, uint16_t span[], int count);
-    virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count);
+                            const SkMatrix& matrix) SK_OVERRIDE;
+    virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE;
+    virtual void shadeSpan16(int x, int y, uint16_t span[], int count) SK_OVERRIDE;
+    virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) SK_OVERRIDE;
 
     // we return false for this, use asAGradient
     virtual BitmapType asABitmap(SkBitmap* outTexture,
                                  SkMatrix* outMatrix,
                                  TileMode xy[2],
-                                 SkScalar* twoPointRadialParams) const;
+                                 SkScalar* twoPointRadialParams) const SK_OVERRIDE;
 
-    virtual GradientType asAGradient(GradientInfo* info) const;
+    virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE;
 
 protected:
-    SkColorShader(SkFlattenableReadBuffer& );
-    virtual void flatten(SkFlattenableWriteBuffer& );
-    virtual Factory getFactory() { return CreateProc; }
+    SkColorShader(SkFlattenableReadBuffer&);
+
+    virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+    virtual Factory getFactory() SK_OVERRIDE;
+
 private:
-    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
-        return SkNEW_ARGS(SkColorShader, (buffer));
-    }
+    static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
+
     SkColor     fColor;         // ignored if fInheritColor is true
     SkPMColor   fPMColor;       // cached after setContext()
     uint32_t    fFlags;         // cached after setContext()
     uint16_t    fColor16;       // cached after setContext()
     SkBool8     fInheritColor;
 
     typedef SkShader INHERITED;
 };
--- a/gfx/skia/include/core/SkDevice.h
+++ b/gfx/skia/include/core/SkDevice.h
@@ -102,47 +102,51 @@ public:
         to access the bitmap, as it notifies the subclass to perform any flushing
         etc. before you examine the pixels.
         @param changePixels set to true if the caller plans to change the pixels
         @return the device's bitmap
     */
     const SkBitmap& accessBitmap(bool changePixels);
 
     /**
-     *  Copy the pixels from the device into bitmap. Returns true on success.
-     *  If false is returned, then the bitmap parameter is left unchanged.
-     *  The bitmap parameter is treated as output-only, and will be completely
-     *  overwritten (if the method returns true).
-     */
-    virtual bool readPixels(const SkIRect& srcRect, SkBitmap* bitmap);
-
-    /**
+     *  DEPRECATED: This will be made protected once WebKit stops using it.
+     *              Instead use Canvas' writePixels method.
+     *
      *  Similar to draw sprite, this method will copy the pixels in bitmap onto
      *  the device, with the top/left corner specified by (x, y). The pixel
      *  values in the device are completely replaced: there is no blending.
+     *
+     *  Currently if bitmap is backed by a texture this is a no-op. This may be
+     *  relaxed in the future.
+     *
+     *  If the bitmap has config kARGB_8888_Config then the config8888 param
+     *  will determines how the pixel valuess are intepreted. If the bitmap is
+     *  not kARGB_8888_Config then this parameter is ignored.
      */
-    virtual void writePixels(const SkBitmap& bitmap, int x, int y);
+    virtual void writePixels(const SkBitmap& bitmap, int x, int y,
+                             SkCanvas::Config8888 config8888 = SkCanvas::kNative_Premul_Config8888);
 
     /**
      * Return the device's associated gpu render target, or NULL.
      */
     virtual SkGpuRenderTarget* accessRenderTarget() { return NULL; }
 
-protected:
-    enum Usage {
-       kGeneral_Usage,
-       kSaveLayer_Usage, // <! internal use only
-    };
 
     /**
      *  Return the device's origin: its offset in device coordinates from
      *  the default origin in its canvas' matrix/clip
      */
     const SkIPoint& getOrigin() const { return fOrigin; }
 
+protected:
+    enum Usage {
+       kGeneral_Usage,
+       kSaveLayer_Usage, // <! internal use only
+    };
+
     struct TextFlags {
         uint32_t            fFlags;     // SkPaint::getFlags()
         SkPaint::Hinting    fHinting;
     };
 
     /**
      *  Device may filter the text flags for drawing text here. If it wants to
      *  make a change to the specified values, it should write them into the
@@ -221,59 +225,115 @@ protected:
     virtual void drawText(const SkDraw&, const void* text, size_t len,
                           SkScalar x, SkScalar y, const SkPaint& paint);
     virtual void drawPosText(const SkDraw&, const void* text, size_t len,
                              const SkScalar pos[], SkScalar constY,
                              int scalarsPerPos, const SkPaint& paint);
     virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len,
                                 const SkPath& path, const SkMatrix* matrix,
                                 const SkPaint& paint);
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
     virtual void drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len,
                                    const SkPoint pos[], const SkPaint& paint,
                                    const SkPath& path, const SkMatrix* matrix);
 #endif
     virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount,
                               const SkPoint verts[], const SkPoint texs[],
                               const SkColor colors[], SkXfermode* xmode,
                               const uint16_t indices[], int indexCount,
                               const SkPaint& paint);
     /** The SkDevice passed will be an SkDevice which was returned by a call to
         onCreateCompatibleDevice on this device with kSaveLayer_Usage.
      */
     virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
                             const SkPaint&);
 
+    /**
+     *  On success (returns true), copy the device pixels into the bitmap.
+     *  On failure, the bitmap parameter is left unchanged and false is
+     *  returned.
+     *
+     *  The device's pixels are converted to the bitmap's config. The only
+     *  supported config is kARGB_8888_Config, though this is likely to be
+     *  relaxed in  the future. The meaning of config kARGB_8888_Config is
+     *  modified by the enum param config8888. The default value interprets
+     *  kARGB_8888_Config as SkPMColor
+     *
+     *  If the bitmap has pixels already allocated, the device pixels will be
+     *  written there. If not, bitmap->allocPixels() will be called 
+     *  automatically. If the bitmap is backed by a texture readPixels will
+     *  fail.
+     *
+     *  The actual pixels written is the intersection of the device's bounds,
+     *  and the rectangle formed by the bitmap's width,height and the specified
+     *  x,y. If bitmap pixels extend outside of that intersection, they will not
+     *  be modified.
+     *
+     *  Other failure conditions:
+     *    * If the device is not a raster device (e.g. PDF) then readPixels will
+     *      fail.
+     *    * If bitmap is texture-backed then readPixels will fail. (This may be
+     *      relaxed in the future.)
+     */
+    bool readPixels(SkBitmap* bitmap,
+                    int x, int y,
+                    SkCanvas::Config8888 config8888);
+
     ///////////////////////////////////////////////////////////////////////////
 
     /** Update as needed the pixel value in the bitmap, so that the caller can access
         the pixels directly. Note: only the pixels field should be altered. The config/width/height/rowbytes
         must remain unchanged.
     */
     virtual void onAccessBitmap(SkBitmap*);
 
     SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); }
     // just for subclasses, to assign a custom pixelref
     SkPixelRef* setPixelRef(SkPixelRef* pr, size_t offset) {
         fBitmap.setPixelRef(pr, offset);
         return pr;
     }
+    
+    /**
+     * Implements readPixels API. The caller will ensure that:
+     *  1. bitmap has pixel config kARGB_8888_Config.
+     *  2. bitmap has pixels.
+     *  3. The rectangle (x, y, x + bitmap->width(), y + bitmap->height()) is
+     *     contained in the device bounds.
+     */
+    virtual bool onReadPixels(const SkBitmap& bitmap,
+                              int x, int y,
+                              SkCanvas::Config8888 config8888);
 
     /** Called when this device is installed into a Canvas. Balanaced by a call
         to unlockPixels() when the device is removed from a Canvas.
     */
     virtual void lockPixels();
     virtual void unlockPixels();
 
+    /**
+     *  Override and return true for filters that the device handles
+     *  intrinsically. Returning false means call the filter.
+     *  Default impl returns false.
+     */
+    virtual bool filterImage(SkImageFilter*, const SkBitmap& src,
+                             const SkMatrix& ctm,
+                             SkBitmap* result, SkIPoint* offset);
+
+    // This is equal kBGRA_Premul_Config8888 or kRGBA_Premul_Config8888 if 
+    // either is identical to kNative_Premul_Config8888. Otherwise, -1.
+    static const SkCanvas::Config8888 kPMColorAlias;
+
 private:
     friend class SkCanvas;
     friend struct DeviceCM; //for setMatrixClip
     friend class SkDraw;
     friend class SkDrawIter;
     friend class SkDeviceFilteredPaint;
+    friend class DeviceImageFilterProxy;
 
     // just called by SkCanvas when built as a layer
     void setOrigin(int x, int y) { fOrigin.set(x, y); }
     // just called by SkCanvas for saveLayer
     SkDevice* createCompatibleDeviceForSaveLayer(SkBitmap::Config config, 
                                                  int width, int height,
                                                  bool isOpaque);
 
--- a/gfx/skia/include/core/SkDraw.h
+++ b/gfx/skia/include/core/SkDraw.h
@@ -50,17 +50,17 @@ public:
     void    drawSprite(const SkBitmap&, int x, int y, const SkPaint&) const;
     void    drawText(const char text[], size_t byteLength, SkScalar x,
                      SkScalar y, const SkPaint& paint) const;
     void    drawPosText(const char text[], size_t byteLength,
                         const SkScalar pos[], SkScalar constY,
                         int scalarsPerPosition, const SkPaint& paint) const;
     void    drawTextOnPath(const char text[], size_t byteLength,
                         const SkPath&, const SkMatrix*, const SkPaint&) const;
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
     void    drawPosTextOnPath(const char text[], size_t byteLength,
                               const SkPoint pos[], const SkPaint& paint,
                               const SkPath& path, const SkMatrix* matrix) const;
 #endif
     void    drawVertices(SkCanvas::VertexMode mode, int count,
                          const SkPoint vertices[], const SkPoint textures[],
                          const SkColor colors[], SkXfermode* xmode,
                          const uint16_t indices[], int ptCount,
@@ -144,13 +144,14 @@ private:
     SkFixed         fPrevAdvance;
     const char*     fText;
     const char*     fStop;
     SkMeasureCacheProc fGlyphCacheProc;
 
     const SkPath*   fPath;      // returned in next
     SkScalar        fXPos;      // accumulated xpos, returned in next
     SkAutoKern      fAutoKern;
+    int             fXYIndex;   // cache for horizontal -vs- vertical text
 };
 
 #endif
 
 
--- a/gfx/skia/include/core/SkEmptyShader.h
+++ b/gfx/skia/include/core/SkEmptyShader.h
@@ -10,32 +10,34 @@
 
 #ifndef SkEmptyShader_DEFINED
 #define SkEmptyShader_DEFINED
 
 #include "SkShader.h"
 
 /**
  *  \class SkEmptyShader
- *  A Shader that always draws nothing.
+ *  A Shader that always draws nothing. Its setContext always returns false,
+ *  so it never expects that its shadeSpan() methods will get called.
  */
 class SK_API SkEmptyShader : public SkShader {
 public:
-    SkEmptyShader();
+    SkEmptyShader() {}
 
-    virtual uint32_t getFlags();
-    virtual uint8_t getSpan16Alpha() const;
-    virtual bool setContext(const SkBitmap& device, const SkPaint& paint,
-                            const SkMatrix& matrix);
-    virtual void shadeSpan(int x, int y, SkPMColor span[], int count);
-    virtual void shadeSpan16(int x, int y, uint16_t span[], int count);
-    virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count);
+    virtual uint32_t getFlags() SK_OVERRIDE;
+    virtual uint8_t getSpan16Alpha() const SK_OVERRIDE;
+    virtual bool setContext(const SkBitmap&, const SkPaint&,
+                            const SkMatrix&) SK_OVERRIDE;
+    virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE;
+    virtual void shadeSpan16(int x, int y, uint16_t span[], int count) SK_OVERRIDE;
+    virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) SK_OVERRIDE;
 
 protected:
     SkEmptyShader(SkFlattenableReadBuffer&);
-    virtual Factory getFactory();
-    virtual void flatten(SkFlattenableWriteBuffer&);
+
+    virtual Factory getFactory() SK_OVERRIDE;
+    virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
 
 private:
     typedef SkShader INHERITED;
 };
 
 #endif
--- a/gfx/skia/include/core/SkEndian.h
+++ b/gfx/skia/include/core/SkEndian.h
@@ -75,11 +75,24 @@ static inline void SkEndianSwap32s(uint3
     #define SkEndian_SwapLE32(n)    (n)
 #else   // SK_CPU_BENDIAN
     #define SkEndian_SwapBE16(n)    (n)
     #define SkEndian_SwapBE32(n)    (n)
     #define SkEndian_SwapLE16(n)    SkEndianSwap16(n)
     #define SkEndian_SwapLE32(n)    SkEndianSwap32(n)
 #endif
 
+// When a bytestream is embedded in a 32-bit word, how far we need to
+// shift the word to extract each byte from the low 8 bits by anding with 0xff.
+#ifdef SK_CPU_LENDIAN
+    #define SkEndian_Byte0Shift 0
+    #define SkEndian_Byte1Shift 8
+    #define SkEndian_Byte2Shift 16
+    #define SkEndian_Byte3Shift 24
+#else   // SK_CPU_BENDIAN
+    #define SkEndian_Byte0Shift 24
+    #define SkEndian_Byte1Shift 16
+    #define SkEndian_Byte2Shift 8
+    #define SkEndian_Byte3Shift 0
+#endif
 
 #endif
 
--- a/gfx/skia/include/core/SkFlattenable.h
+++ b/gfx/skia/include/core/SkFlattenable.h
@@ -15,16 +15,50 @@
 #include "SkReader32.h"
 #include "SkTDArray.h"
 #include "SkWriter32.h"
 
 class SkFlattenableReadBuffer;
 class SkFlattenableWriteBuffer;
 class SkString;
 
+#if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+
+#define SK_DECLARE_FLATTENABLE_REGISTRAR() 
+
+#define SK_DEFINE_FLATTENABLE_REGISTRAR(flattenable) \
+    static SkFlattenable::Registrar g##flattenable##Reg(#flattenable, \
+                                                      flattenable::CreateProc);
+                                                      
+#define SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(flattenable)
+#define SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(flattenable) \
+    static SkFlattenable::Registrar g##flattenable##Reg(#flattenable, \
+                                                      flattenable::CreateProc);
+#define SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
+
+#else
+
+#define SK_DECLARE_FLATTENABLE_REGISTRAR() static void Init();
+
+#define SK_DEFINE_FLATTENABLE_REGISTRAR(flattenable) \
+    void flattenable::Init() { \
+        SkFlattenable::Registrar(#flattenable, CreateProc); \
+    }
+
+#define SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(flattenable) \
+    void flattenable::Init() {
+    
+#define SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(flattenable) \
+        SkFlattenable::Registrar(#flattenable, flattenable::CreateProc);
+    
+#define SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END \
+    }
+
+#endif
+
 /** \class SkFlattenable
  
  SkFlattenable is the base class for objects that need to be flattened
  into a data stream for either transport or as part of the key to the
  font cache.
  */
 class SK_API SkFlattenable : public SkRefCnt {
 public:
@@ -56,16 +90,23 @@ public:
     public:
         Registrar(const char name[], Factory factory) {
             SkFlattenable::Register(name, factory);
         }
     };
     
 protected:
     SkFlattenable(SkFlattenableReadBuffer&) {}
+
+private:
+#if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+    static void InitializeFlattenables();
+#endif
+
+    friend class SkGraphics;
 };
 
 // helpers for matrix and region
 
 class SkMatrix;
 extern void SkReadMatrix(SkReader32*, SkMatrix*);
 extern void SkWriteMatrix(SkWriter32*, const SkMatrix&);
 
--- a/gfx/skia/include/core/SkFloatingPoint.h
+++ b/gfx/skia/include/core/SkFloatingPoint.h
@@ -53,22 +53,34 @@ static inline float sk_float_copysign(fl
     #define sk_float_ceil(x)        ceilf(x)
 #ifdef SK_BUILD_FOR_MAC
     #define sk_float_acos(x)        static_cast<float>(acos(x))
     #define sk_float_asin(x)        static_cast<float>(asin(x))
 #else
     #define sk_float_acos(x)        acosf(x)
     #define sk_float_asin(x)        asinf(x)
 #endif
-    #define sk_float_atan2(y,x) atan2f(y,x)
+    #define sk_float_atan2(y,x)     atan2f(y,x)
     #define sk_float_abs(x)         fabsf(x)
     #define sk_float_mod(x,y)       fmodf(x,y)
     #define sk_float_exp(x)         expf(x)
     #define sk_float_log(x)         logf(x)
-    #define sk_float_isNaN(x)       _isnan(x)
+#endif
+
+#ifdef SK_BUILD_FOR_WIN
+    #define sk_float_isfinite(x)    _finite(x)
+    #define sk_float_isnan(x)       _isnan(x)
+    static inline int sk_float_isinf(float x) {
+        int32_t bits = SkFloat2Bits(x);
+        return (bits << 1) == (0xFF << 24);
+    }
+#else
+    #define sk_float_isfinite(x)    isfinite(x)
+    #define sk_float_isnan(x)       isnan(x)
+    #define sk_float_isinf(x)       isinf(x)
 #endif
 
 #ifdef SK_USE_FLOATBITS
     #define sk_float_floor2int(x)   SkFloatToIntFloor(x)
     #define sk_float_round2int(x)   SkFloatToIntRound(x)
     #define sk_float_ceil2int(x)    SkFloatToIntCeil(x)
 #else
     #define sk_float_floor2int(x)   (int)sk_float_floor(x)
--- a/gfx/skia/include/core/SkFontHost.h
+++ b/gfx/skia/include/core/SkFontHost.h
@@ -227,30 +227,19 @@ public:
                 offset > the table's size, or tag is not a valid table,
                 then 0 is returned.
      */
     static size_t GetTableData(SkFontID fontID, SkFontTableTag tag,
                                size_t offset, size_t length, void* data);
 
     ///////////////////////////////////////////////////////////////////////////
 
-    /** Return the number of bytes (approx) that should be purged from the font
-        cache. The input parameter is the cache's estimate of how much as been
-        allocated by the cache so far.
-        To purge (basically) everything, return the input parameter.
-        To purge nothing, return 0
-    */
-    static size_t ShouldPurgeFontCache(size_t sizeAllocatedSoFar);
+    /** DEPRECATED -- only called by SkFontHost_FreeType internally
 
-    /** Return SkScalerContext gamma flag, or 0, based on the paint that will be
-        used to draw something with antialiasing.
-    */
-    static int ComputeGammaFlag(const SkPaint& paint);
-
-    /** Return NULL or a pointer to 256 bytes for the black (table[0]) and
+        Return NULL or a pointer to 256 bytes for the black (table[0]) and
         white (table[1]) gamma tables.
     */
     static void GetGammaTables(const uint8_t* tables[2]);
 
     ///////////////////////////////////////////////////////////////////////////
 
     /** LCDs either have their color elements arranged horizontally or
         vertically. When rendering subpixel glyphs we need to know which way
@@ -281,22 +270,30 @@ public:
         kRGB_LCDOrder = 0,    //!< this is the default
         kBGR_LCDOrder = 1,
         kNONE_LCDOrder = 2,
     };
 
     static void SetSubpixelOrder(LCDOrder order);
     static LCDOrder GetSubpixelOrder();
 
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
     ///////////////////////////////////////////////////////////////////////////
 
     /**
      * Return the number of font units per em.
      *
      * @param fontID the font to query.
      * @return the number of font units per em or 0 on error.
      */
     static uint32_t GetUnitsPerEm(SkFontID fontID);
 #endif
+
+    /** If Skia is running in a constrained environment and the typeface
+        implementation is handle based, the typeface data may become
+        unavailable asynchronously. If a font host or scaler context method is
+        unable to access font data, it may call this function as a request to
+        make the handle contained in the typeface useable.
+    */
+    static void EnsureTypefaceAccessible(const SkTypeface& typeface);
 };
 
 #endif
--- a/gfx/skia/include/core/SkGraphics.h
+++ b/gfx/skia/include/core/SkGraphics.h
@@ -9,34 +9,67 @@
 
 #ifndef SkGraphics_DEFINED
 #define SkGraphics_DEFINED
 
 #include "SkTypes.h"
 
 class SkGraphics {
 public:
+    /**
+     *  Call this at process initialization time if your environment does not
+     *  permit static global initializers that execute code. Note that 
+     *  Init() is not thread-safe.
+     */
     static void Init();
+
+    /**
+     *  Call this to release any memory held privately, such as the font cache.
+     */
     static void Term();
 
-    /** Return the (approximate) number of bytes used by the font cache.
-    */
-    static size_t GetFontCacheUsed();
-    
-    /** Attempt to purge the font cache until <= the specified amount remains
-        in the cache. Specifying 0 will attempt to purge the entire cache.
-        Returns true if some amount was purged from the font cache.
-    */
-    static bool SetFontCacheUsed(size_t usageInBytes);
-
-    /** Return the version numbers for the library. If the parameter is not
-        null, it is set to the version number.
+    /**
+     *  Return the version numbers for the library. If the parameter is not
+     *  null, it is set to the version number.
      */
     static void GetVersion(int32_t* major, int32_t* minor, int32_t* patch);
 
+    /**
+     *  Return the max number of bytes that should be used by the font cache.
+     *  If the cache needs to allocate more, it will purge previous entries.
+     *  This max can be changed by calling SetFontCacheLimit().
+     */
+    static size_t GetFontCacheLimit();
+    
+    /**
+     *  Specify the max number of bytes that should be used by the font cache.
+     *  If the cache needs to allocate more, it will purge previous entries.
+     *
+     *  This function returns the previous setting, as if GetFontCacheLimit()
+     *  had be called before the new limit was set.
+     */
+    static size_t SetFontCacheLimit(size_t bytes);
+
+    /**
+     *  For debugging purposes, this will attempt to purge the font cache. It
+     *  does not change the limit, but will cause subsequent font measures and
+     *  draws to be recreated, since they will no longer be in the cache.
+     */
+    static void PurgeFontCache();
+    
+    /**
+     *  Applications with command line options may pass optional state, such
+     *  as cache sizes, here, for instance:
+     *  font-cache-limit=12345678
+     *
+     *  The flags format is name=value[;name=value...] with no spaces.
+     *  This format is subject to change.
+     */
+    static void SetFlags(const char* flags);
+    
 private:
     /** This is automatically called by SkGraphics::Init(), and must be
         implemented by the host OS. This allows the host OS to register a callback
         with the C++ runtime to call SkGraphics::FreeCaches()
     */
     static void InstallNewHandler();
 };
 
--- a/gfx/skia/include/core/SkImageFilter.h
+++ b/gfx/skia/include/core/SkImageFilter.h
@@ -5,36 +5,92 @@
  * found in the LICENSE file.
  */
 
 #ifndef SkImageFilter_DEFINED
 #define SkImageFilter_DEFINED
 
 #include "SkFlattenable.h"
 
-class SkImageFilter : public SkFlattenable {
+class SkBitmap;
+class SkDevice;
+class SkMatrix;
+struct SkPoint;
+
+/**
+ *  Experimental.
+ *
+ *  Base class for image filters. If one is installed in the paint, then
+ *  all drawing occurs as usual, but it is as if the drawing happened into an
+ *  offscreen (before the xfermode is applied). This offscreen bitmap will
+ *  then be handed to the imagefilter, who in turn creates a new bitmap which
+ *  is what will finally be drawn to the device (using the original xfermode).
+ *
+ *  THIS SIGNATURE IS TEMPORARY
+ *
+ *  There are several weaknesses in this function signature:
+ *  1. Does not expose the destination/target device, so filters that can draw
+ *     directly to it are unable to take advantage of that optimization.
+ *  2. Does not expose a way to create a "compabitible" image (i.e. gpu -> gpu)
+ *  3. As with #1, the filter is unable to "read" the dest (which would be slow)
+ *
+ *  Therefore, we should not create any real dependencies on this API yet -- it
+ *  is being checked in as a check-point so we can explore these and other
+ *  considerations.
+ */
+class SK_API SkImageFilter : public SkFlattenable {
 public:
+    class Proxy {
+    public:
+        virtual SkDevice* createDevice(int width, int height) = 0;
+        
+        // returns true if the proxy handled the filter itself. if this returns
+        // false then the filter's code will be called.
+        virtual bool filterImage(SkImageFilter*, const SkBitmap& src,
+                                 const SkMatrix& ctm,
+                                 SkBitmap* result, SkIPoint* offset) = 0;
+    };
 
     /**
      *  Request a new (result) image to be created from the src image.
      *  If the src has no pixels (isNull()) then the request just wants to
      *  receive the config and width/height of the result.
      *
      *  The matrix is the current matrix on the canvas.
      *
      *  Offset is the amount to translate the resulting image relative to the
      *  src when it is drawn. 
      *
      *  If the result image cannot be created, return false, in which case both
      *  the result and offset parameters will be ignored by the caller.
      */
-    bool filterImage(const SkBitmap& src, const SkMatrix&,
-                     SkBitmap* result, SkPoint* offset);
+    bool filterImage(Proxy*, const SkBitmap& src, const SkMatrix& ctm,
+                     SkBitmap* result, SkIPoint* offset);
+
+    /**
+     *  Given the src bounds of an image, this returns the bounds of the result
+     *  image after the filter has been applied.
+     */
+    bool filterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst);
+
+    /**
+     *  Experimental.
+     *
+     *  If the filter can be expressed as a gaussian-blur, return true and
+     *  set the sigma to the values for horizontal and vertical.
+     */
+    virtual bool asABlur(SkSize* sigma) const;
 
 protected:
-    virtual bool onFilterImage(const SkBitmap& src, const SkMatrix&
-                               SkBitmap* result, SkPoint* offset) = 0;
+    SkImageFilter() {}
+    explicit SkImageFilter(SkFlattenableReadBuffer& rb) : INHERITED(rb) {}
+
+    // Default impl returns false
+    virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
+                               SkBitmap* result, SkIPoint* offset);
+    // Default impl copies src into dst and returns true
+    virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*);
 
 private:
     typedef SkFlattenable INHERITED;
 };
 
 #endif
--- a/gfx/skia/include/core/SkMMapStream.h
+++ b/gfx/skia/include/core/SkMMapStream.h
@@ -14,17 +14,16 @@
 
 class SkMMAPStream : public SkMemoryStream {
 public:
     SkMMAPStream(const char filename[]);
     virtual ~SkMMAPStream();
 
     virtual void setMemory(const void* data, size_t length, bool);
 private:
-    int     fFildes;
     void*   fAddr;
     size_t  fSize;
     
     void closeMMap();
     
     typedef SkMemoryStream INHERITED;
 };
 
--- a/gfx/skia/include/core/SkMallocPixelRef.h
+++ b/gfx/skia/include/core/SkMallocPixelRef.h
@@ -32,16 +32,17 @@ public:
     virtual void flatten(SkFlattenableWriteBuffer&) const;
     virtual Factory getFactory() const {
         return Create;
     }
     static SkPixelRef* Create(SkFlattenableReadBuffer& buffer) {
         return SkNEW_ARGS(SkMallocPixelRef, (buffer));
     }
 
+    SK_DECLARE_PIXEL_REF_REGISTRAR()
 protected:
     // overrides from SkPixelRef
     virtual void* onLockPixels(SkColorTable**);
     virtual void onUnlockPixels();
 
     SkMallocPixelRef(SkFlattenableReadBuffer& buffer);
 
 private:
--- a/gfx/skia/include/core/SkOSFile.h
+++ b/gfx/skia/include/core/SkOSFile.h
@@ -8,17 +8,17 @@
 
 
 // 
 #ifndef SkOSFile_DEFINED
 #define SkOSFile_DEFINED
 
 #include "SkString.h"
 
-#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
+#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
     #include <dirent.h>
 #endif
 
 struct SkFILE;
 
 enum SkFILE_Flags {
     kRead_SkFILE_Flag   = 0x01,
     kWrite_SkFILE_Flag  = 0x02
@@ -53,17 +53,17 @@ public:
             interleaved on a single iterator.
         */
         bool next(SkString* name, bool getDir = false);
 
     private:
 #ifdef SK_BUILD_FOR_WIN
         HANDLE      fHandle;
         uint16_t*   fPath16;
-#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
+#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
         DIR*        fDIR;
         SkString    fPath, fSuffix;
 #endif
     };
 };
 
 class SkUTF16_Str {
 public:
--- a/gfx/skia/include/core/SkPaint.h
+++ b/gfx/skia/include/core/SkPaint.h
@@ -16,16 +16,17 @@
 class SkAutoGlyphCache;
 class SkColorFilter;
 class SkDescriptor;
 class SkFlattenableReadBuffer;
 class SkFlattenableWriteBuffer;
 struct SkGlyph;
 struct SkRect;
 class SkGlyphCache;
+class SkImageFilter;
 class SkMaskFilter;
 class SkMatrix;
 class SkPath;
 class SkPathEffect;
 class SkRasterizer;
 class SkShader;
 class SkDrawLooper;
 class SkTypeface;
@@ -93,19 +94,17 @@ public:
         kStrikeThruText_Flag  = 0x10,   //!< mask to enable strike-thru text
         kFakeBoldText_Flag    = 0x20,   //!< mask to enable fake-bold text
         kLinearText_Flag      = 0x40,   //!< mask to enable linear-text
         kSubpixelText_Flag    = 0x80,   //!< mask to enable subpixel text positioning
         kDevKernText_Flag     = 0x100,  //!< mask to enable device kerning text
         kLCDRenderText_Flag   = 0x200,  //!< mask to enable subpixel glyph renderering
         kEmbeddedBitmapText_Flag = 0x400, //!< mask to enable embedded bitmap strikes
         kAutoHinting_Flag     = 0x800,  //!< mask to force Freetype's autohinter
-
-        // experimental/private
-        kForceAAText_Flag     = 0x1000,
+        kVerticalText_Flag    = 0x1000,
 
         // when adding extra flags, note that the fFlags member is specified
         // with a bit-width and you'll have to expand it.
 
         kAllFlags = 0x1FFF
     };
 
     /** Return the paint's flags. Use the Flag enum to test flag values.
@@ -197,16 +196,30 @@ public:
 
     /** Helper for setFlags(), setting or clearing the kAutoHinting_Flag bit
         @param useAutohinter true to set the kEmbeddedBitmapText bit in the
                                   paint's flags,
                              false to clear it.
     */
     void setAutohinted(bool useAutohinter);
 
+    bool isVerticalText() const {
+        return SkToBool(this->getFlags() & kVerticalText_Flag);
+    }
+    
+    /**
+     *  Helper for setting or clearing the kVerticalText_Flag bit in
+     *  setFlags(...).
+     *
+     *  If this bit is set, then advances are treated as Y values rather than
+     *  X values, and drawText will places its glyphs vertically rather than
+     *  horizontally.
+     */
+    void setVerticalText(bool);
+
     /** Helper for getFlags(), returning true if kUnderlineText_Flag bit is set
         @return true if the underlineText bit is set in the paint's flags.
     */
     bool isUnderlineText() const {
         return SkToBool(this->getFlags() & kUnderlineText_Flag);
     }
 
     /** Helper for setFlags(), setting or clearing the kUnderlineText_Flag bit
@@ -590,16 +603,19 @@ public:
         decremented. If rasterizer is not NULL, its reference count is
         incremented.
         @param rasterizer May be NULL. The new rasterizer to be installed in
                           the paint.
         @return           rasterizer
     */
     SkRasterizer* setRasterizer(SkRasterizer* rasterizer);
 
+    SkImageFilter* getImageFilter() const { return fImageFilter; }
+    SkImageFilter* setImageFilter(SkImageFilter*);
+
     /**
      *  Return the paint's SkDrawLooper (if any). Does not affect the looper's
      *  reference count.
      */
     SkDrawLooper* getLooper() const { return fLooper; }
 
     /**
      *  Set or clear the looper object.
@@ -738,33 +754,39 @@ public:
         This looks at the current TextEncoding field of the paint. If you also
         want to have the text converted into glyph IDs, call textToGlyphs
         instead.
     */
     int countText(const void* text, size_t byteLength) const {
         return this->textToGlyphs(text, byteLength, NULL);
     }
 
-    /** Return the width of the text.
-        @param text         The text to be measured
-        @param length       Number of bytes of text to measure
-        @param bounds       If not NULL, returns the bounds of the text,
-                            relative to (0, 0).
-        @param scale        If not 0, return width as if the canvas were scaled
-                            by this value
-        @return             The advance width of the text
-    */
+    /** Return the width of the text. This will return the vertical measure
+     *  if isVerticalText() is true, in which case the returned value should
+     *  be treated has a height instead of a width.
+     *
+     *  @param text         The text to be measured
+     *  @param length       Number of bytes of text to measure
+     *  @param bounds       If not NULL, returns the bounds of the text,
+     *                      relative to (0, 0).
+     *  @param scale        If not 0, return width as if the canvas were scaled
+     *                      by this value
+     *  @return             The advance width of the text
+     */
     SkScalar measureText(const void* text, size_t length,
                          SkRect* bounds, SkScalar scale = 0) const;
 
-    /** Return the width of the text.
-        @param text         Address of the text
-        @param length       Number of bytes of text to measure
-        @return The width of the text
-    */
+    /** Return the width of the text. This will return the vertical measure
+     *  if isVerticalText() is true, in which case the returned value should
+     *  be treated has a height instead of a width.
+     *
+     *  @param text     Address of the text
+     *  @param length   Number of bytes of text to measure
+     *  @return         The width of the text
+     */
     SkScalar measureText(const void* text, size_t length) const {
         return this->measureText(text, length, NULL, 0);
     }
 
     /** Specify the direction the text buffer should be processed in breakText()
     */
     enum TextBufferDirection {
         /** When measuring text for breakText(), begin at the start of the text
@@ -772,57 +794,62 @@ public:
         */
         kForward_TextBufferDirection,
         /** When measuring text for breakText(), begin at the end of the text
             buffer and proceed backwards through the data.
         */
         kBackward_TextBufferDirection
     };
 
-    /** Return the width of the text.
-        @param text     The text to be measured
-        @param length   Number of bytes of text to measure
-        @param maxWidth Maximum width. Only the subset of text whose accumulated
-                        widths are <= maxWidth are measured.
-        @param measuredWidth Optional. If non-null, this returns the actual
-                        width of the measured text.
-        @param tbd      Optional. The direction the text buffer should be
-                        traversed during measuring.
-        @return         The number of bytes of text that were measured. Will be
-                        <= length.
-    */
+    /** Return the number of bytes of text that were measured. If
+     *  isVerticalText() is true, then the vertical advances are used for
+     *  the measurement.
+     *  
+     *  @param text     The text to be measured
+     *  @param length   Number of bytes of text to measure
+     *  @param maxWidth Maximum width. Only the subset of text whose accumulated
+     *                  widths are <= maxWidth are measured.
+     *  @param measuredWidth Optional. If non-null, this returns the actual
+     *                  width of the measured text.
+     *  @param tbd      Optional. The direction the text buffer should be
+     *                  traversed during measuring.
+     *  @return         The number of bytes of text that were measured. Will be
+     *                  <= length.
+     */
     size_t  breakText(const void* text, size_t length, SkScalar maxWidth,
                       SkScalar* measuredWidth = NULL,
                       TextBufferDirection tbd = kForward_TextBufferDirection)
                       const;
 
-    /** Return the advance widths for the characters in the string.
-        @param text         the text
-        @param byteLength   number of bytes to of text
-        @param widths       If not null, returns the array of advance widths of
-                            the glyphs. If not NULL, must be at least a large
-                            as the number of unichars in the specified text.
-        @param bounds       If not null, returns the bounds for each of
-                            character, relative to (0, 0)
-        @return the number of unichars in the specified text.
-    */
+    /** Return the advances for the text. These will be vertical advances if
+     *  isVerticalText() returns true.
+     *
+     *  @param text         the text
+     *  @param byteLength   number of bytes to of text
+     *  @param widths       If not null, returns the array of advances for
+     *                      the glyphs. If not NULL, must be at least a large
+     *                      as the number of unichars in the specified text.
+     *  @param bounds       If not null, returns the bounds for each of
+     *                      character, relative to (0, 0)
+     *  @return the number of unichars in the specified text.
+     */
     int getTextWidths(const void* text, size_t byteLength, SkScalar widths[],
                       SkRect bounds[] = NULL) const;
 
     /** Return the path (outline) for the specified text.
         Note: just like SkCanvas::drawText, this will respect the Align setting
               in the paint.
     */
     void getTextPath(const void* text, size_t length, SkScalar x, SkScalar y,
                      SkPath* path) const;
 
     void getPosTextPath(const void* text, size_t length, 
                         const SkPoint pos[], SkPath* path) const;
 
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
     const SkGlyph& getUnicharMetrics(SkUnichar);
     const void* findImage(const SkGlyph&);
 
     uint32_t getGenerationID() const;
 #endif
 
     // returns true if the paint's settings (e.g. xfermode + alpha) resolve to
     // mean that we need not draw at all (e.g. SrcOver + 0-alpha)
@@ -836,30 +863,28 @@ private:
 
     SkPathEffect*   fPathEffect;
     SkShader*       fShader;
     SkXfermode*     fXfermode;
     SkMaskFilter*   fMaskFilter;
     SkColorFilter*  fColorFilter;
     SkRasterizer*   fRasterizer;
     SkDrawLooper*   fLooper;
+    SkImageFilter*  fImageFilter;
 
     SkColor         fColor;
     SkScalar        fWidth;
     SkScalar        fMiterLimit;
-    unsigned        fFlags : 13;
+    unsigned        fFlags : 14;
     unsigned        fTextAlign : 2;
     unsigned        fCapType : 2;
     unsigned        fJoinType : 2;
     unsigned        fStyle : 2;
     unsigned        fTextEncoding : 2;  // 3 values
     unsigned        fHinting : 2;
-#ifdef ANDROID
-    uint32_t        fGenerationID;
-#endif
 
     SkDrawCacheProc    getDrawCacheProc() const;
     SkMeasureCacheProc getMeasureCacheProc(TextBufferDirection dir,
                                            bool needFullMetrics) const;
 
     SkScalar measure_text(SkGlyphCache*, const char* text, size_t length,
                           int* count, SkRect* bounds) const;
 
@@ -875,16 +900,22 @@ private:
     enum {
         kCanonicalTextSizeForPaths = 64
     };
     friend class SkAutoGlyphCache;
     friend class SkCanvas;
     friend class SkDraw;
     friend class SkPDFDevice;
     friend class SkTextToPathIter;
+
+#ifdef SK_BUILD_FOR_ANDROID
+    // In order for the == operator to work properly this must be the last field
+    // in the struct so that we can do a memcmp to this field's offset.
+    uint32_t        fGenerationID;
+#endif
 };
 
 ///////////////////////////////////////////////////////////////////////////////
 
 #include "SkPathEffect.h"
 
 /** \class SkStrokePathEffect
 
--- a/gfx/skia/include/core/SkPath.h
+++ b/gfx/skia/include/core/SkPath.h
@@ -8,17 +8,17 @@
 
 
 #ifndef SkPath_DEFINED
 #define SkPath_DEFINED
 
 #include "SkMatrix.h"
 #include "SkTDArray.h"
 
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
 #define GEN_ID_INC              fGenerationID++
 #define GEN_ID_PTR_INC(ptr)     ptr->fGenerationID++
 #else
 #define GEN_ID_INC
 #define GEN_ID_PTR_INC(ptr)
 #endif
 
 class SkReader32;
@@ -33,17 +33,17 @@ class SkString;
 */
 class SK_API SkPath {
 public:
     SkPath();
     SkPath(const SkPath&);
     ~SkPath();
 
     SkPath& operator=(const SkPath&);
-    
+
     friend bool operator==(const SkPath&, const SkPath&);
     friend bool operator!=(const SkPath& a, const SkPath& b) {
         return !(a == b);
     }
 
     enum FillType {
         /** Specifies that "inside" is computed by a non-zero sum of signed
             edge crossings
@@ -65,17 +65,17 @@ public:
         computed. The default value is kWinding_FillType.
 
         @return the path's fill type
     */
     FillType getFillType() const { return (FillType)fFillType; }
 
     /** Set the path's fill type. This is used to define how "inside" is
         computed. The default value is kWinding_FillType.
-     
+
         @param ft The new fill type for this path
     */
     void setFillType(FillType ft) {
         fFillType = SkToU8(ft);
         GEN_ID_INC;
     }
 
     /** Returns true if the filltype is one of the Inverse variants */
@@ -175,16 +175,45 @@ public:
     void rewind();
 
     /** Returns true if the path is empty (contains no lines or curves)
 
         @return true if the path is empty (contains no lines or curves)
     */
     bool isEmpty() const;
 
+    /** Test a line for zero length
+
+        @return true if the line is of zero length; otherwise false.
+    */
+    static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2) {
+        return p1.equalsWithinTolerance(p2, SK_ScalarNearlyZero);
+    }
+
+    /** Test a quad for zero length
+
+        @return true if the quad is of zero length; otherwise false.
+    */
+    static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
+                                 const SkPoint& p3) {
+        return p1.equalsWithinTolerance(p2, SK_ScalarNearlyZero) &&
+               p2.equalsWithinTolerance(p3, SK_ScalarNearlyZero);
+    }
+
+    /** Test a cubic curve for zero length
+
+        @return true if the cubic is of zero length; otherwise false.
+    */
+    static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
+                                  const SkPoint& p3, const SkPoint& p4) {
+        return p1.equalsWithinTolerance(p2, SK_ScalarNearlyZero) &&
+               p2.equalsWithinTolerance(p3, SK_ScalarNearlyZero) &&
+               p3.equalsWithinTolerance(p4, SK_ScalarNearlyZero);
+    }
+
     /** Returns true if the path specifies a rectangle. If so, and if rect is
         not null, set rect to the bounds of the path. If the path does not
         specify a rectangle, return false and ignore rect.
      
         @param rect If not null, returns the bounds of the path if it specifies
                     a rectangle
         @return true if the path specifies a rectangle
     */
@@ -589,83 +618,115 @@ public:
         kQuad_Verb,     //!< iter.next returns 3 points
         kCubic_Verb,    //!< iter.next returns 4 points
         kClose_Verb,    //!< iter.next returns 1 point (contour's moveTo pt)
         kDone_Verb      //!< iter.next returns 0 points
     };
 
     /** Iterate through all of the segments (lines, quadratics, cubics) of
         each contours in a path.
+
+        The iterator cleans up the segments along the way, removing degenerate
+        segments and adding close verbs where necessary. When the forceClose
+        argument is provided, each contour (as defined by a new starting
+        move command) will be completed with a close verb regardless of the
+        contour's contents.
     */
     class SK_API Iter {
     public:
-                Iter();
-                Iter(const SkPath&, bool forceClose);
+        Iter();
+        Iter(const SkPath&, bool forceClose);
 
         void setPath(const SkPath&, bool forceClose);
 
         /** Return the next verb in this iteration of the path. When all
             segments have been visited, return kDone_Verb.
-         
+
             @param  pts The points representing the current verb and/or segment
             @return The verb for the current segment
         */
         Verb next(SkPoint pts[4]);
 
         /** If next() returns kLine_Verb, then this query returns true if the
             line was the result of a close() command (i.e. the end point is the
             initial moveto for this contour). If next() returned a different
             verb, this returns an undefined value.
-         
+
             @return If the last call to next() returned kLine_Verb, return true
                     if it was the result of an explicit close command.
         */
         bool isCloseLine() const { return SkToBool(fCloseLine); }
-        
+
         /** Returns true if the current contour is closed (has a kClose_Verb)
             @return true if the current contour is closed (has a kClose_Verb)
         */
         bool isClosedContour() const;
 
     private:
         const SkPoint*  fPts;
         const uint8_t*  fVerbs;
         const uint8_t*  fVerbStop;
         SkPoint         fMoveTo;
         SkPoint         fLastPt;
         SkBool8         fForceClose;
         SkBool8         fNeedClose;
-        SkBool8         fNeedMoveTo;
         SkBool8         fCloseLine;
+        SkBool8         fSegmentState;
 
         bool cons_moveTo(SkPoint pts[1]);
         Verb autoClose(SkPoint pts[2]);
+        void consumeDegenerateSegments();
+    };
+
+    /** Iterate through the verbs in the path, providing the associated points.
+    */
+    class SK_API RawIter {
+    public:
+        RawIter();
+        RawIter(const SkPath&);
+
+        void setPath(const SkPath&);
+
+        /** Return the next verb in this iteration of the path. When all
+            segments have been visited, return kDone_Verb.
+         
+            @param  pts The points representing the current verb and/or segment
+            @return The verb for the current segment
+        */
+        Verb next(SkPoint pts[4]);
+
+    private:
+        const SkPoint*  fPts;
+        const uint8_t*  fVerbs;
+        const uint8_t*  fVerbStop;
+        SkPoint         fMoveTo;
+        SkPoint         fLastPt;
     };
 
     void dump(bool forceClose, const char title[] = NULL) const;
     void dump() const;
 
     void flatten(SkWriter32&) const;
     void unflatten(SkReader32&);
 
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
     uint32_t getGenerationID() const;
 #endif
 
     SkDEBUGCODE(void validate() const;)
 
 private:
     SkTDArray<SkPoint>  fPts;
     SkTDArray<uint8_t>  fVerbs;
     mutable SkRect      fBounds;
     uint8_t             fFillType;
     uint8_t             fSegmentMask;
     mutable uint8_t     fBoundsIsDirty;
     mutable uint8_t     fConvexity;
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
     uint32_t            fGenerationID;
 #endif
 
     // called, if dirty, by getBounds()
     void computeBounds() const;
 
     friend class Iter;
     void cons_moveto();
@@ -683,9 +744,8 @@ private:
     */
     void reversePathTo(const SkPath&);
 
     friend const SkPoint* sk_get_path_points(const SkPath&, int index);
     friend class SkAutoPathBoundsUpdate;
 };
 
 #endif
-
--- a/gfx/skia/include/core/SkPathEffect.h
+++ b/gfx/skia/include/core/SkPathEffect.h
@@ -29,16 +29,17 @@ public:
     /** Given a src path and a width value, return true if the patheffect
         has produced a new path (dst) and a new width value. If false is returned,
         ignore dst and width.
         On input, width >= 0 means the src should be stroked
         On output, width >= 0 means the dst should be stroked
     */
     virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width) = 0;
 
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
 private:
     // illegal
     SkPathEffect(const SkPathEffect&);
     SkPathEffect& operator=(const SkPathEffect&);
 };
 
 /** \class SkPairPathEffect
 
--- a/gfx/skia/include/core/SkPixelRef.h
+++ b/gfx/skia/include/core/SkPixelRef.h
@@ -5,29 +5,48 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
 
 
 #ifndef SkPixelRef_DEFINED
 #define SkPixelRef_DEFINED
 
+#include "SkBitmap.h"
 #include "SkRefCnt.h"
 #include "SkString.h"
 
-class SkBitmap;
 class SkColorTable;
 struct SkIRect;
 class SkMutex;
 class SkFlattenableReadBuffer;
 class SkFlattenableWriteBuffer;
 
 // this is an opaque class, not interpreted by skia
 class SkGpuTexture;
 
+#if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+
+#define SK_DECLARE_PIXEL_REF_REGISTRAR() 
+
+#define SK_DEFINE_PIXEL_REF_REGISTRAR(pixelRef) \
+    static SkPixelRef::Registrar g##pixelRef##Reg(#pixelRef, \
+                                                  pixelRef::Create);
+                                                      
+#else
+
+#define SK_DECLARE_PIXEL_REF_REGISTRAR() static void Init();
+
+#define SK_DEFINE_PIXEL_REF_REGISTRAR(pixelRef) \
+    void pixelRef::Init() { \
+        SkPixelRef::Registrar(#pixelRef, Create); \
+    }
+
+#endif
+
 /** \class SkPixelRef
 
     This class is the smart container for pixel memory, and is used with
     SkBitmap. A pixelref is installed into a bitmap, and then the bitmap can
     access the actual pixel memory by calling lockPixels/unlockPixels.
 
     This class can be shared/accessed between multiple threads.
 */
@@ -112,24 +131,30 @@ public:
     void setURI(const SkString& uri) { fURI = uri; }
 
     /** Are we really wrapping a texture instead of a bitmap?
      */
     virtual SkGpuTexture* getTexture() { return NULL; }
 
     bool readPixels(SkBitmap* dst, const SkIRect* subset = NULL);
 
+    /** Makes a deep copy of this PixelRef, respecting the requested config.
+        Returns NULL if either there is an error (e.g. the destination could
+        not be created with the given config), or this PixelRef does not 
+        support deep copies.  */
+    virtual SkPixelRef* deepCopy(SkBitmap::Config config) { return NULL; }
+
     // serialization
 
     typedef SkPixelRef* (*Factory)(SkFlattenableReadBuffer&);
 
     virtual Factory getFactory() const { return NULL; }
     virtual void flatten(SkFlattenableWriteBuffer&) const;
 
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
     /**
      *  Acquire a "global" ref on this object.
      *  The default implementation just calls ref(), but subclasses can override
      *  this method to implement additional behavior.
      */
     virtual void globalRef(void* data=NULL);
 
     /**
@@ -176,22 +201,28 @@ protected:
     /** Return the mutex associated with this pixelref. This value is assigned
         in the constructor, and cannot change during the lifetime of the object.
     */
     SkMutex* mutex() const { return fMutex; }
 
     SkPixelRef(SkFlattenableReadBuffer&, SkMutex*);
 
 private:
+#if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+    static void InitializeFlattenables();
+#endif
+
     SkMutex*        fMutex; // must remain in scope for the life of this object
     void*           fPixels;
     SkColorTable*   fColorTable;    // we do not track ownership, subclass does
     int             fLockCount;
 
     mutable uint32_t fGenerationID;
 
     SkString    fURI;
 
     // can go from false to true, but never from true to false
     bool    fIsImmutable;
+
+    friend class SkGraphics;
 };
 
 #endif
--- a/gfx/skia/include/core/SkPoint.h
+++ b/gfx/skia/include/core/SkPoint.h
@@ -310,16 +310,23 @@ struct SK_API SkPoint {
     friend bool operator==(const SkPoint& a, const SkPoint& b) {
         return a.fX == b.fX && a.fY == b.fY;
     }
 
     friend bool operator!=(const SkPoint& a, const SkPoint& b) {
         return a.fX != b.fX || a.fY != b.fY;
     }
 
+    /** Return true if this and the given point are componentwise within tol.
+    */
+    bool equalsWithinTolerance(const SkPoint& v, SkScalar tol) const {
+        return SkScalarNearlyZero(fX - v.fX, tol)
+               && SkScalarNearlyZero(fY - v.fY, tol);
+    }
+
     /** Returns a new point whose coordinates are the difference between
         a's and b's (a - b)
     */
     friend SkPoint operator-(const SkPoint& a, const SkPoint& b) {
         SkPoint v;
         v.set(a.fX - b.fX, a.fY - b.fY);
         return v;
     }
--- a/gfx/skia/include/core/SkPostConfig.h
+++ b/gfx/skia/include/core/SkPostConfig.h
@@ -51,31 +51,57 @@
         #error "all or none of the 32bit SHIFT amounts must be defined"
     #endif
 #else
     #if defined(SK_R32_SHIFT) || defined(SK_G32_SHIFT) || defined(SK_B32_SHIFT)
         #error "all or none of the 32bit SHIFT amounts must be defined"
     #endif
 #endif
 
+#if !defined(SK_HAS_COMPILER_FEATURE)
+    #if defined(__has_feature)
+        #define SK_HAS_COMPILER_FEATURE(x) __has_feature(x)
+    #else
+        #define SK_HAS_COMPILER_FEATURE(x) 0
+    #endif
+#endif
+
+/**
+ * The clang static analyzer likes to know that when the program is not
+ * expected to continue (crash, assertion failure, etc). It will notice that
+ * some combination of parameters lead to a function call that does not return.
+ * It can then make appropriate assumptions about the parameters in code
+ * executed only if the non-returning function was *not* called.
+ */
+#if !defined(SkNO_RETURN_HINT)
+    #if SK_HAS_COMPILER_FEATURE(attribute_analyzer_noreturn)
+        namespace {
+            inline void SkNO_RETURN_HINT() __attribute__((analyzer_noreturn));
+            void SkNO_RETURN_HINT() {}
+        }
+    #else
+        #define SkNO_RETURN_HINT() do {} while (false)
+    #endif
+#endif
+
 ///////////////////////////////////////////////////////////////////////////////
 
 #ifndef SkNEW
     #define SkNEW(type_name)                new type_name
     #define SkNEW_ARGS(type_name, args)     new type_name args
     #define SkNEW_ARRAY(type_name, count)   new type_name[count]
     #define SkDELETE(obj)                   delete obj
     #define SkDELETE_ARRAY(array)           delete[] array
 #endif
 
 #ifndef SK_CRASH
 #if 1   // set to 0 for infinite loop, which can help connecting gdb
-    #define SK_CRASH() *(int *)(uintptr_t)0xbbadbeef = 0
+    #define SK_CRASH() do { SkNO_RETURN_HINT(); *(int *)(uintptr_t)0xbbadbeef = 0; } while (false)
 #else
-    #define SK_CRASH()  do {} while (true)
+    #define SK_CRASH() do { SkNO_RETURN_HINT(); } while (true)
 #endif
 #endif
 
 ///////////////////////////////////////////////////////////////////////////////
 
 #if defined(SK_SOFTWARE_FLOAT) && defined(SK_SCALAR_IS_FLOAT)
     // if this is defined, we convert floats to 2scompliment ints for compares
     #ifndef SK_SCALAR_SLOW_COMPARES
@@ -95,17 +121,17 @@
 
     #include <windows.h>
 
     #ifdef WIN32_IS_MEAN_WAS_LOCALLY_DEFINED
         #undef WIN32_LEAN_AND_MEAN
     #endif
 
     #ifndef SK_DEBUGBREAK
-        #define SK_DEBUGBREAK(cond)     do { if (!(cond)) __debugbreak(); } while (false)
+        #define SK_DEBUGBREAK(cond)     do { if (!(cond)) { SkNO_RETURN_HINT(); __debugbreak(); }} while (false)
     #endif
 
     #ifndef SK_A32_SHIFT
         #define SK_A32_SHIFT 24
         #define SK_R32_SHIFT 16
         #define SK_G32_SHIFT 8
         #define SK_B32_SHIFT 0
     #endif
@@ -260,8 +286,13 @@
 // but it doesn't work.
 #define SK_OVERRIDE override
 #else
 // Linux GCC ignores "__attribute__((override))" and rejects "override".
 #define SK_OVERRIDE
 #endif
 #endif
 
+//////////////////////////////////////////////////////////////////////
+
+#ifndef SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+#define SK_ALLOW_STATIC_GLOBAL_INITIALIZERS 1
+#endif
--- a/gfx/skia/include/core/SkPreConfig.h
+++ b/gfx/skia/include/core/SkPreConfig.h
@@ -11,44 +11,54 @@
 #define SkPreConfig_DEFINED
 
 #ifdef WEBKIT_VERSION_MIN_REQUIRED
     #include "config.h"
 #endif
 
 //////////////////////////////////////////////////////////////////////
 
-#if !defined(SK_BUILD_FOR_ANDROID_NDK) && !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_PALM) && !defined(SK_BUILD_FOR_WINCE) && !defined(SK_BUILD_FOR_WIN32) && !defined(SK_BUILD_FOR_SYMBIAN) && !defined(SK_BUILD_FOR_UNIX) && !defined(SK_BUILD_FOR_MAC) && !defined(SK_BUILD_FOR_SDL) && !defined(SK_BUILD_FOR_BREW)
+#if !defined(SK_BUILD_FOR_ANDROID) && !defined(SK_BUILD_FOR_ANDROID_NDK) && !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_PALM) && !defined(SK_BUILD_FOR_WINCE) && !defined(SK_BUILD_FOR_WIN32) && !defined(SK_BUILD_FOR_SYMBIAN) && !defined(SK_BUILD_FOR_UNIX) && !defined(SK_BUILD_FOR_MAC) && !defined(SK_BUILD_FOR_SDL) && !defined(SK_BUILD_FOR_BREW)
 
     #ifdef __APPLE__
         #include "TargetConditionals.h"
     #endif
 
     #if defined(PALMOS_SDK_VERSION)
         #define SK_BUILD_FOR_PALM
     #elif defined(UNDER_CE)
         #define SK_BUILD_FOR_WINCE
     #elif defined(WIN32)
         #define SK_BUILD_FOR_WIN32
     #elif defined(__SYMBIAN32__)
         #define SK_BUILD_FOR_WIN32
-    #elif defined(linux) || defined(__OpenBSD_)
+    #elif defined(linux) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
+          defined(__sun) || defined(__NetBSD__) || defined(__DragonFly__)
         #define SK_BUILD_FOR_UNIX
     #elif TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
         #define SK_BUILD_FOR_IOS
     #elif defined(ANDROID_NDK)
         #define SK_BUILD_FOR_ANDROID_NDK
-    #elif defined(ANROID)
+    #elif defined(ANDROID)
         #define SK_BUILD_FOR_ANDROID
     #else
         #define SK_BUILD_FOR_MAC
     #endif
 
 #endif
 
+/* Even if the user only defined the NDK variant we still need to build
+ * the default Android code. Therefore, when attempting to include/exclude
+ * something from the NDK variant check first that we are building for 
+ * Android then check the status of the NDK define.
+ */
+#if defined(SK_BUILD_FOR_ANDROID_NDK) && !defined(SK_BUILD_FOR_ANDROID)
+    #define SK_BUILD_FOR_ANDROID
+#endif
+
 //////////////////////////////////////////////////////////////////////
 
 #if !defined(SK_DEBUG) && !defined(SK_RELEASE)
     #ifdef NDEBUG
         #define SK_RELEASE
     #else
         #define SK_DEBUG
     #endif
--- a/gfx/skia/include/core/SkRect.h
+++ b/gfx/skia/include/core/SkRect.h
@@ -330,20 +330,44 @@ struct SK_API SkRect {
     }
 
     static SkRect MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) {
         SkRect r;
         r.set(x, y, x + w, y + h);
         return r;
     }
 
-    /** Return true if the rectangle's width or height are <= 0
-    */
-    bool        isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
-    bool        hasValidCoordinates() const;
+    /**
+     *  Return true if the rectangle's width or height are <= 0
+     */
+    bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
+    
+    /**
+     *  Returns true iff all values in the rect are finite. If any are
+     *  infinite or NaN (or SK_FixedNaN when SkScalar is fixed) then this
+     *  returns false.
+     */
+    bool isFinite() const {
+#ifdef SK_SCALAR_IS_FLOAT
+        // x * 0 will be NaN iff x is infinity or NaN.
+        // a + b will be NaN iff either a or b is NaN.
+        float value = fLeft * 0 + fTop * 0 + fRight * 0 + fBottom * 0;
+        
+        // value is either NaN or it is finite (zero).
+        // value==value will be true iff value is not NaN
+        return value == value;
+#else
+        // use bit-or for speed, since we don't care about short-circuting the
+        // tests, and we expect the common case will be that we need to check all.
+        int isNaN = (SK_FixedNaN == fLeft)  | (SK_FixedNaN == fTop) |
+                    (SK_FixedNaN == fRight) | (SK_FixedNaN == fBottom);
+        return !isNaN;
+#endif
+    }
+
     SkScalar    left() const { return fLeft; }
     SkScalar    top() const { return fTop; }
     SkScalar    right() const { return fRight; }
     SkScalar    bottom() const { return fBottom; }
     SkScalar    width() const { return fRight - fLeft; }
     SkScalar    height() const { return fBottom - fTop; }
     SkScalar    centerX() const { return SkScalarHalf(fLeft + fRight); }
     SkScalar    centerY() const { return SkScalarHalf(fTop + fBottom); }
--- a/gfx/skia/include/core/SkRegion.h
+++ b/gfx/skia/include/core/SkRegion.h
@@ -81,19 +81,19 @@ public:
 
     /**
      *  Return the bounds of this region. If the region is empty, returns an
      *  empty rectangle.
      */
     const SkIRect& getBounds() const { return fBounds; }
 
     /**
-     *  Returns true if the region is non-empty, and if so, sets the specified
-     *  path to the boundary(s) of the region. If the region is empty, then
-     *  this returns false, and path is left unmodified.
+     *  Returns true if the region is non-empty, and if so, appends the
+     *  boundary(s) of the region to the specified path.
+     *  If the region is empty, returns false, and path is left unmodified.
      */
     bool getBoundaryPath(SkPath* path) const;
 
     /**
      *  Set the region to be empty, and return false, since the resulting
      *  region is empty
      */
     bool setEmpty();
@@ -278,17 +278,17 @@ public:
 
     /**
      *  Set this region to the result of applying the Op to the specified
      *  regions: this = (rgna op rgnb).
      *  Return true if the resulting region is non-empty.
      */
     bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op);
 
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
     /** Returns a new char* containing the list of rectangles in this region
      */
     char* toString();
 #endif
 
     /**
      *  Returns the sequence of rectangles, sorted in Y and X, that make up
      *  this region.
--- a/gfx/skia/include/core/SkScalar.h
+++ b/gfx/skia/include/core/SkScalar.h
@@ -87,17 +87,17 @@
     static inline float SkIntToScalar(float param) {
         /* If the parameter passed into SkIntToScalar is a float,
          * one of two things has happened:
          * 1. the parameter was an SkScalar (which is typedef'd to float)
          * 2. the parameter was a float instead of an int
          *
          * Either way, it's not good.
          */
-        SkASSERT(!"looks like you passed an SkScalar into SkIntToScalar");
+        SkDEBUGFAIL("looks like you passed an SkScalar into SkIntToScalar");
         return (float)0;
     }
 #else  // not SK_DEBUG
     /** SkIntToScalar(n) returns its integer argument as an SkScalar
     */
     #define SkIntToScalar(n)        ((float)(n))
 #endif // not SK_DEBUG
     /** SkFixedToScalar(n) returns its SkFixed argument as an SkScalar
@@ -114,17 +114,17 @@
     #define SkDoubleToScalar(n)      (float)(n)
 
     /** SkScalarFraction(x) returns the signed fractional part of the argument
     */
     #define SkScalarFraction(x)     sk_float_mod(x, 1.0f)
 
     #define SkScalarFloorToScalar(x)    sk_float_floor(x)
     #define SkScalarCeilToScalar(x)     sk_float_ceil(x)
-    #define SkScalarRoundToScalar(x)    sk_float_round(x)
+    #define SkScalarRoundToScalar(x)    sk_float_floor((x) + 0.5f)
 
     #define SkScalarFloorToInt(x)       sk_float_floor2int(x)
     #define SkScalarCeilToInt(x)        sk_float_ceil2int(x)
     #define SkScalarRoundToInt(x)       sk_float_round2int(x)
 
     /** Returns the absolute value of the specified SkScalar
     */
     #define SkScalarAbs(x)          sk_float_abs(x)
--- a/gfx/skia/include/core/SkScalerContext.h
+++ b/gfx/skia/include/core/SkScalerContext.h
@@ -152,43 +152,46 @@ struct SkGlyph {
     }
 
     void toMask(SkMask* mask) const;
 };
 
 class SkScalerContext {
 public:
     enum Flags {
-        kFrameAndFill_Flag  = 0x01,
-        kDevKernText_Flag   = 0x02,
-        kGammaForBlack_Flag = 0x04, // illegal to set both Gamma flags
-        kGammaForWhite_Flag = 0x08, // illegal to set both Gamma flags
+        kFrameAndFill_Flag        = 0x0001,
+        kDevKernText_Flag         = 0x0002,
+        kEmbeddedBitmapText_Flag  = 0x0004,
+        kEmbolden_Flag            = 0x0008,
+        kSubpixelPositioning_Flag = 0x0010,
+        kAutohinting_Flag         = 0x0020,
+        kVertical_Flag            = 0x0040,
 
         // together, these two flags resulting in a two bit value which matches
         // up with the SkPaint::Hinting enum.
-        kHintingBit1_Flag   = 0x10,
-        kHintingBit2_Flag   = 0x20,
-
-        kEmbeddedBitmapText_Flag = 0x40,
-        kEmbolden_Flag      = 0x80,
-        kSubpixelPositioning_Flag = 0x100,
-        kAutohinting_Flag   = 0x200,
+        kHinting_Shift            = 7, // to shift into the other flags above
+        kHintingBit1_Flag         = 0x0080,
+        kHintingBit2_Flag         = 0x0100,
 
         // these should only ever be set if fMaskFormat is LCD16 or LCD32
-        kLCD_Vertical_Flag  = 0x400,    // else Horizontal
-        kLCD_BGROrder_Flag  = 0x800,    // else RGB order
+        kLCD_Vertical_Flag        = 0x0200,    // else Horizontal
+        kLCD_BGROrder_Flag        = 0x0400,    // else RGB order
 
-        // experimental
-        kForceAA_Flag       = 0x1000
+        // luminance : 0 for black text, kLuminance_Max for white text
+        kLuminance_Shift          = 11, // to shift into the other flags above
+        kLuminance_Bits           = 3,  // ensure Flags doesn't exceed 16bits
     };
-private:
+    
+    // computed values
     enum {
-        kHintingMask = kHintingBit1_Flag | kHintingBit2_Flag
+        kHinting_Mask   = kHintingBit1_Flag | kHintingBit2_Flag,
+        kLuminance_Max  = (1 << kLuminance_Bits) - 1,
+        kLuminance_Mask = kLuminance_Max << kLuminance_Shift,
     };
-public:
+
     struct Rec {
         uint32_t    fOrigFontID;
         uint32_t    fFontID;
         SkScalar    fTextSize, fPreScaleX, fPreSkewX;
         SkScalar    fPost2x2[2][2];
         SkScalar    fFrameWidth, fMiterLimit;
         uint8_t     fMaskFormat;
         uint8_t     fStrokeJoin;
@@ -198,46 +201,68 @@ public:
         // multiples of four and this structure is put in an SkDescriptor in
         // SkPaint::MakeRec.
 
         void    getMatrixFrom2x2(SkMatrix*) const;
         void    getLocalMatrix(SkMatrix*) const;
         void    getSingleMatrix(SkMatrix*) const;
 
         SkPaint::Hinting getHinting() const {
-            return static_cast<SkPaint::Hinting>((fFlags & kHintingMask) >> 4);
+            unsigned hint = (fFlags & kHinting_Mask) >> kHinting_Shift;
+            return static_cast<SkPaint::Hinting>(hint);
         }
 
         void setHinting(SkPaint::Hinting hinting) {
-            fFlags = (fFlags & ~kHintingMask) | (hinting << 4);
+            fFlags = (fFlags & ~kHinting_Mask) | (hinting << kHinting_Shift);
+        }
+
+        unsigned getLuminanceBits() const {
+            return (fFlags & kLuminance_Mask) >> kLuminance_Shift;
+        }
+        
+        void setLuminanceBits(unsigned lum) {
+            SkASSERT(lum <= kLuminance_Max);
+            fFlags = (fFlags & ~kLuminance_Mask) | (lum << kLuminance_Shift);
+        }
+
+        U8CPU getLuminanceByte() const {
+            SkASSERT(3 == kLuminance_Bits);
+            unsigned lum = this->getLuminanceBits();
+            lum |= (lum << kLuminance_Bits);
+            lum |= (lum << kLuminance_Bits*2);
+            return lum >> (4*kLuminance_Bits - 8);
         }
 
         SkMask::Format getFormat() const {
             return static_cast<SkMask::Format>(fMaskFormat);
         }
     };
 
     SkScalerContext(const SkDescriptor* desc);
     virtual ~SkScalerContext();
 
     SkMask::Format getMaskFormat() const {
         return (SkMask::Format)fRec.fMaskFormat;
     }
 
+    bool isSubpixel() const {
+        return SkToBool(fRec.fFlags & kSubpixelPositioning_Flag);
+    }
+    
     // remember our glyph offset/base
     void setBaseGlyphCount(unsigned baseGlyphCount) {
         fBaseGlyphCount = baseGlyphCount;
     }
 
     /** Return the corresponding glyph for the specified unichar. Since contexts
         may be chained (under the hood), the glyphID that is returned may in
         fact correspond to a different font/context. In that case, we use the
         base-glyph-count to know how to translate back into local glyph space.
      */
-    uint16_t    charToGlyphID(SkUnichar uni);
+    uint16_t charToGlyphID(SkUnichar uni);
 
     /** Map the glyphID to its glyph index, and then to its char code. Unmapped
         glyphs return zero.
     */
     SkUnichar glyphIDToChar(uint16_t glyphID);
 
     unsigned    getGlyphCount() { return this->generateGlyphCount(); }
     void        getAdvance(SkGlyph*);
--- a/gfx/skia/include/core/SkShader.h
+++ b/gfx/skia/include/core/SkShader.h
@@ -92,16 +92,25 @@ public:
      *  alpha your shader will return. The default implementation returns 0.
      *  Your subclass should override if it can (even sometimes) report a
      *  non-zero value, since that will enable various blitters to perform
      *  faster.
      */
     virtual uint32_t getFlags() { return 0; }
 
     /**
+     *  Returns true if the shader is guaranteed to produce only opaque
+     *  colors, subject to the SkPaint using the shader to apply an opaque
+     *  alpha value. Subclasses should override this to allow some
+     *  optimizations.  isOpaque() can be called at any time, unlike getFlags,
+     *  which only works properly when the context is set.
+     */
+    virtual bool isOpaque() const { return false; }
+
+    /**
      *  Return the alpha associated with the data returned by shadeSpan16(). If
      *  kHasSpan16_Flag is not set, this value is meaningless.
      */
     virtual uint8_t getSpan16Alpha() const { return fPaintAlpha; }
 
     /**
      *  Called once before drawing, with the current paint and device matrix.
      *  Return true if your shader supports these parameters, or false if not.
--- a/gfx/skia/include/core/SkShape.h
+++ b/gfx/skia/include/core/SkShape.h
@@ -33,16 +33,18 @@ public:
 
     // overrides
     virtual Factory getFactory();
     virtual void flatten(SkFlattenableWriteBuffer&);
 
     // public for Registrar
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
 
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
+
 protected:
     virtual void onDraw(SkCanvas*);
 
     SkShape(SkFlattenableReadBuffer&);
 
 private:
 
     typedef SkFlattenable INHERITED;
--- a/gfx/skia/include/core/SkTArray.h
+++ b/gfx/skia/include/core/SkTArray.h
@@ -294,30 +294,30 @@ protected:
      */
     template <int N>
     SkTArray(const T* array, int count, SkAlignedSTStorage<N,T>* storage) {
         this->init(array, count, storage->get(), N);
     }
 
     void init(const T* array, int count,
                void* preAllocStorage, int preAllocOrReserveCount) {
-        GrAssert(count >= 0);
-        GrAssert(preAllocOrReserveCount >= 0);
+        SkASSERT(count >= 0);
+        SkASSERT(preAllocOrReserveCount >= 0);
         fCount              = count;
         fReserveCount       = (preAllocOrReserveCount > 0) ?
                                     preAllocOrReserveCount :
                                     gMIN_ALLOC_COUNT;
         fPreAllocMemArray   = preAllocStorage;
         if (fReserveCount >= fCount &&
             NULL != preAllocStorage) {
             fAllocCount = fReserveCount;
             fMemArray = preAllocStorage;
         } else {
-            fAllocCount = GrMax(fCount, fReserveCount);
-            fMemArray = GrMalloc(fAllocCount * sizeof(T));
+            fAllocCount = SkMax32(fCount, fReserveCount);
+            fMemArray = sk_malloc_throw(fAllocCount * sizeof(T));
         }
 
         SkTArrayExt::copy(this, array);
     }
 
 private:
 
     static const int gMIN_ALLOC_COUNT = 8;
--- a/gfx/skia/include/core/SkTDArray.h
+++ b/gfx/skia/include/core/SkTDArray.h
@@ -86,17 +86,27 @@ public:
         T* array = fArray;
         fArray = NULL;
         fReserve = fCount = 0;
         SkDEBUGCODE(fData = NULL;)
         return array;
     }
 
     bool isEmpty() const { return fCount == 0; }
+
+    /**
+     *  Return the number of elements in the array
+     */
     int count() const { return fCount; }
+
+    /**
+     *  return the number of bytes in the array: count * sizeof(T)
+     */
+    size_t bytes() const { return fCount * sizeof(T); }
+
     T*  begin() const { return fArray; }
     T*  end() const { return fArray ? fArray + fCount : NULL; }
     T&  operator[](int index) const {
         SkASSERT((unsigned)index < fCount);
         return fArray[index];
     }
 
     void reset() {
--- a/gfx/skia/include/core/SkTRegistry.h
+++ b/gfx/skia/include/core/SkTRegistry.h
@@ -16,17 +16,17 @@
     and provides a function-pointer. This can be used to auto-register a set of
     services, e.g. a set of image codecs.
  */
 template <typename T, typename P> class SkTRegistry : SkNoncopyable {
 public:
     typedef T (*Factory)(P);
 
     SkTRegistry(Factory fact) {
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
         // work-around for double-initialization bug
         {
             SkTRegistry* reg = gHead;
             while (reg) {
                 if (reg == this) {
                     return;
                 }
                 reg = reg->fChain;
--- a/gfx/skia/include/core/SkThread_platform.h
+++ b/gfx/skia/include/core/SkThread_platform.h
@@ -5,17 +5,17 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
 
 
 #ifndef SkThread_platform_DEFINED
 #define SkThread_platform_DEFINED
 
-#if defined(ANDROID) && !defined(SK_BUILD_FOR_ANDROID_NDK)
+#if defined(SK_BUILD_FOR_ANDROID) && !defined(SK_BUILD_FOR_ANDROID_NDK)
 
 #include <utils/threads.h>
 #include <utils/Atomic.h>
 
 #define sk_atomic_inc(addr)     android_atomic_inc(addr)
 #define sk_atomic_dec(addr)     android_atomic_dec(addr)
 
 class SkMutex : android::Mutex {
--- a/gfx/skia/include/core/SkTypes.h
+++ b/gfx/skia/include/core/SkTypes.h
@@ -88,24 +88,26 @@ inline void operator delete(void* p) {
 #define SK_INIT_TO_AVOID_WARNING    = 0
 
 #ifndef SkDebugf
     void SkDebugf(const char format[], ...);
 #endif
 
 #ifdef SK_DEBUG
     #define SkASSERT(cond)              SK_DEBUGBREAK(cond)
+    #define SkDEBUGFAIL(message)        SkASSERT(false && message)
     #define SkDEBUGCODE(code)           code
     #define SkDECLAREPARAM(type, var)   , type var
     #define SkPARAM(var)                , var
 //  #define SkDEBUGF(args       )       SkDebugf##args
     #define SkDEBUGF(args       )       SkDebugf args
     #define SkAssertResult(cond)        SkASSERT(cond)
 #else
     #define SkASSERT(cond)
+    #define SkDEBUGFAIL(message)
     #define SkDEBUGCODE(code)
     #define SkDEBUGF(args)
     #define SkDECLAREPARAM(type, var)
     #define SkPARAM(var)
 
     // unlike SkASSERT, this guy executes its condition in the non-debug build
     #define SkAssertResult(cond)        cond
 #endif
@@ -211,16 +213,18 @@ static inline bool SkIsU16(long x) {
 
 /** Returns x rounded up to a multiple of 2
 */
 #define SkAlign2(x)     (((x) + 1) >> 1 << 1)
 /** Returns x rounded up to a multiple of 4
 */
 #define SkAlign4(x)     (((x) + 3) >> 2 << 2)
 
+#define SkIsAlign4(x) (((x) & 3) == 0)
+
 typedef uint32_t SkFourByteTag;
 #define SkSetFourByteTag(a, b, c, d)    (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
 
 /** 32 bit integer to hold a unicode value
 */
 typedef int32_t SkUnichar;
 /** 32 bit value to hold a millisecond count
 */
--- a/gfx/skia/include/core/SkUtils.h
+++ b/gfx/skia/include/core/SkUtils.h
@@ -27,17 +27,17 @@ SkMemset16Proc SkMemset16GetPlatformProc
     @param buffer   The memory to have value copied into it
     @param value    The 32bit value to be copied into buffer
     @param count    The number of times value should be copied into the buffer.
 */
 void sk_memset32_portable(uint32_t dst[], uint32_t value, int count);
 typedef void (*SkMemset32Proc)(uint32_t dst[], uint32_t value, int count);
 SkMemset32Proc SkMemset32GetPlatformProc();
 
-#if defined(ANDROID) && !defined(SK_BUILD_FOR_ANDROID_NDK)
+#if defined(SK_BUILD_FOR_ANDROID) && !defined(SK_BUILD_FOR_ANDROID_NDK)
     #include "cutils/memory.h"
     
     #define sk_memset16(dst, value, count)    android_memset16(dst, value, (count) << 1)
     #define sk_memset32(dst, value, count)    android_memset32(dst, value, (count) << 2)
 #endif
 
 #ifndef sk_memset16
 extern SkMemset16Proc sk_memset16;
@@ -86,16 +86,31 @@ int SkUTF16_CountUnichars(const uint16_t
 SkUnichar SkUTF16_NextUnichar(const uint16_t**);
 // this guy backs up to the previus unichar value, and returns it (*--p)
 SkUnichar SkUTF16_PrevUnichar(const uint16_t**);
 size_t SkUTF16_FromUnichar(SkUnichar uni, uint16_t utf16[] = NULL);
 
 size_t SkUTF16_ToUTF8(const uint16_t utf16[], int numberOf16BitValues,
                            char utf8[] = NULL);
 
+inline bool SkUnichar_IsVariationSelector(SkUnichar uni) {
+/*  The 'true' ranges are:
+ *      0x180B  <= uni <=  0x180D
+ *      0xFE00  <= uni <=  0xFE0F
+ *      0xE0100 <= uni <= 0xE01EF
+ */
+    if (uni < 0x180B || uni > 0xE01EF) {
+        return false;
+    }
+    if ((uni > 0x180D && uni < 0xFE00) || (uni > 0xFE0F && uni < 0xE0100)) {
+        return false;
+    }
+    return true;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 class SkAutoTrace {
 public:
     /** NOTE: label contents are not copied, just the ptr is
         retained, so DON'T DELETE IT.
     */
     SkAutoTrace(const char label[]) : fLabel(label) {
--- a/gfx/skia/include/core/SkXfermode.h
+++ b/gfx/skia/include/core/SkXfermode.h
@@ -126,16 +126,28 @@ public:
     virtual bool asMode(Mode* mode);
 
     /**
      *  The same as calling xfermode->asMode(mode), except that this also checks
      *  if the xfermode is NULL, and if so, treats its as kSrcOver_Mode.
      */
     static bool AsMode(SkXfermode*, Mode* mode);
 
+    /**
+     *  Returns true if the xfermode claims to be the specified Mode. This works
+     *  correctly even if the xfermode is NULL (which equates to kSrcOver.) Thus
+     *  you can say this without checking for a null...
+     *
+     *  If (SkXfermode::IsMode(paint.getXfermode(),
+     *                         SkXfermode::kDstOver_Mode)) {
+     *      ...
+     *  }
+     */
+    static bool IsMode(SkXfermode* xfer, Mode mode);
+
     /** Return an SkXfermode object for the specified mode.
      */
     static SkXfermode* Create(Mode mode);
 
     /** Return a function pointer to a routine that applies the specified
         porter-duff transfer mode.
      */
     static SkXfermodeProc GetProc(Mode mode);
@@ -155,16 +167,17 @@ public:
      */
     static bool ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst);
 
     // DEPRECATED: call AsMode(...)
     static bool IsMode(SkXfermode* xfer, Mode* mode) {
         return AsMode(xfer, mode);
     }
 
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
 protected:
     SkXfermode(SkFlattenableReadBuffer& rb) : SkFlattenable(rb) {}
 
     /** The default implementation of xfer32/xfer16/xferA8 in turn call this
         method, 1 color at a time (upscaled to a SkPMColor). The default
         implmentation of this method just returns dst. If performance is
         important, your subclass should override xfer32/xfer16/xferA8 directly.
 
--- a/gfx/skia/include/effects/Sk1DPathEffect.h
+++ b/gfx/skia/include/effects/Sk1DPathEffect.h
@@ -52,31 +52,33 @@ public:
         @param advance The space between instances of path
         @param phase distance (mod advance) along path for its initial position
         @param style how to transform path at each point (based on the current
                      position and tangent)
     */
     SkPath1DPathEffect(const SkPath& path, SkScalar advance, SkScalar phase, Style);
 
     // override from SkPathEffect
-    virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width);
+    virtual bool filterPath(SkPath*, const SkPath&, SkScalar* width) SK_OVERRIDE;
 
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
         return SkNEW_ARGS(SkPath1DPathEffect, (buffer));
     }
 
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
+
 protected:
     SkPath1DPathEffect(SkFlattenableReadBuffer& buffer);
 
     // overrides from Sk1DPathEffect
-    virtual SkScalar begin(SkScalar contourLength);
-    virtual SkScalar next(SkPath* dst, SkScalar distance, SkPathMeasure&);
+    virtual SkScalar begin(SkScalar contourLength) SK_OVERRIDE;
+    virtual SkScalar next(SkPath*, SkScalar distance, SkPathMeasure&) SK_OVERRIDE;
     // overrides from SkFlattenable
-    virtual void flatten(SkFlattenableWriteBuffer& );
-    virtual Factory getFactory() { return CreateProc; }
+    virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+    virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
     
 private:
     SkPath      fPath;          // copied from constructor
     SkScalar    fAdvance;       // copied from constructor
     SkScalar    fInitialOffset; // computed from phase
     Style       fStyle;         // copied from constructor
 
     typedef Sk1DPathEffect INHERITED;
--- a/gfx/skia/include/effects/Sk2DPathEffect.h
+++ b/gfx/skia/include/effects/Sk2DPathEffect.h
@@ -14,21 +14,21 @@
 #include "SkPathEffect.h"
 #include "SkMatrix.h"
 
 class Sk2DPathEffect : public SkPathEffect {
 public:
     Sk2DPathEffect(const SkMatrix& mat);
 
     // overrides
-    virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width);
+    virtual bool filterPath(SkPath*, const SkPath&, SkScalar* width) SK_OVERRIDE;
 
     // overrides from SkFlattenable
-    virtual void flatten(SkFlattenableWriteBuffer&);
-    virtual Factory getFactory();
+    virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+    virtual Factory getFactory() SK_OVERRIDE;
 
 protected:
     /** New virtual, to be overridden by subclasses.
         This is called once from filterPath, and provides the
         uv parameter bounds for the path. Subsequent calls to
         next() will receive u and v values within these bounds,
         and then a call to end() will signal the end of processing.
     */
@@ -42,16 +42,18 @@ protected:
     */
     virtual void nextSpan(int u, int v, int ucount, SkPath* dst);
 
     const SkMatrix& getMatrix() const { return fMatrix; }
 
     // protected so that subclasses can call this during unflattening
     Sk2DPathEffect(SkFlattenableReadBuffer&);
 
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
+
 private:
     SkMatrix    fMatrix, fInverse;
     // illegal
     Sk2DPathEffect(const Sk2DPathEffect&);
     Sk2DPathEffect& operator=(const Sk2DPathEffect&);
 
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
 
@@ -64,22 +66,24 @@ public:
     /**
      *  Stamp the specified path to fill the shape, using the matrix to define
      *  the latice.
      */
     SkPath2DPathEffect(const SkMatrix&, const SkPath&);
     
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
 
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
+
 protected:
     SkPath2DPathEffect(SkFlattenableReadBuffer& buffer);
 
-    virtual void flatten(SkFlattenableWriteBuffer&);
-    virtual Factory getFactory();
-    virtual void next(const SkPoint& loc, int u, int v, SkPath* dst);
+    virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+    virtual Factory getFactory() SK_OVERRIDE;
+    virtual void next(const SkPoint&, int u, int v, SkPath* dst) SK_OVERRIDE;
 
 private:
     SkPath  fPath;
 
     typedef Sk2DPathEffect INHERITED;
 };
 
 
new file mode 100644
--- /dev/null
+++ b/gfx/skia/include/effects/SkArithmeticMode.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkArithmeticMode_DEFINED
+#define SkArithmeticMode_DEFINED
+
+#include "SkXfermode.h"
+
+class SkArithmeticMode : public SkXfermode {
+public:
+    /**
+     *  result = clamp[k1 * src * dst + k2 * src + k3 * dst + k4]
+     *
+     *  src and dst are treated as being [0.0 .. 1.0]. The polynomial is
+     *  evaluated on their unpremultiplied components.
+     *
+     *  k1=k2=k3=0, k4=1.0 results in returning opaque white
+     *  k1=k3=k4=0, k2=1.0 results in returning the src
+     *  k1=k2=k4=0, k3=1.0 results in returning the dst
+     */
+    static SkXfermode* Create(SkScalar k1, SkScalar k2,
+                              SkScalar k3, SkScalar k4);
+};
+
+#endif
+
--- a/gfx/skia/include/effects/SkAvoidXfermode.h
+++ b/gfx/skia/include/effects/SkAvoidXfermode.h
@@ -38,32 +38,34 @@ public:
                 are similar to the op-color
                 Tolerance near 0: draw only on colors that are nearly identical to the op-color
                 Tolerance near 255: draw on any colors even remotely similar to the op-color
      */
     SkAvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode);
 
     // overrides from SkXfermode
     virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
-                        const SkAlpha aa[]);
+                        const SkAlpha aa[]) SK_OVERRIDE;
     virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count,
-                        const SkAlpha aa[]);
+                        const SkAlpha aa[]) SK_OVERRIDE;
     virtual void xfer4444(uint16_t dst[], const SkPMColor src[], int count,
-                          const SkAlpha aa[]);
+                          const SkAlpha aa[]) SK_OVERRIDE;
     virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count,
-                        const SkAlpha aa[]);
+                        const SkAlpha aa[]) SK_OVERRIDE;
 
     // overrides from SkFlattenable
-    virtual Factory getFactory();
-    virtual void flatten(SkFlattenableWriteBuffer&);
+    virtual Factory getFactory() SK_OVERRIDE;
+    virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
 
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
         return SkNEW_ARGS(SkAvoidXfermode, (buffer));
     }
 
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
+
 protected:
     SkAvoidXfermode(SkFlattenableReadBuffer&);
 
 private:
     SkColor     fOpColor;
     uint32_t    fDistMul;   // x.14
     Mode        fMode;
 
--- a/gfx/skia/include/effects/SkBlurDrawLooper.h
+++ b/gfx/skia/include/effects/SkBlurDrawLooper.h
@@ -43,16 +43,17 @@ public:
     // overrides from SkDrawLooper
     virtual void init(SkCanvas*);
     virtual bool next(SkCanvas*, SkPaint* paint);
 
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
         return SkNEW_ARGS(SkBlurDrawLooper, (buffer));
     }
 
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
 
 protected:
     SkBlurDrawLooper(SkFlattenableReadBuffer&);
     // overrides from SkFlattenable
     virtual void flatten(SkFlattenableWriteBuffer& );
     virtual Factory getFactory() { return CreateProc; }
 
 private:
new file mode 100644
--- /dev/null
+++ b/gfx/skia/include/effects/SkBlurImageFilter.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2011 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SkBlurImageFilter_DEFINED
+#define SkBlurImageFilter_DEFINED
+
+#include "SkImageFilter.h"
+
+class SK_API SkBlurImageFilter : public SkImageFilter {
+public:
+    SkBlurImageFilter(SkScalar sigmaX, SkScalar sigmaY);
+
+    virtual bool asABlur(SkSize* sigma) const SK_OVERRIDE;
+
+    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+        return SkNEW_ARGS(SkBlurImageFilter, (buffer));
+    }
+
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
+
+protected:
+    explicit SkBlurImageFilter(SkFlattenableReadBuffer& buffer);
+
+    virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
+                               SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
+    virtual void flatten(SkFlattenableWriteBuffer& buffer) SK_OVERRIDE;
+    virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
+
+private:
+    SkSize   fSigma;
+    typedef SkImageFilter INHERITED;
+};
+
+#endif
+
--- a/gfx/skia/include/effects/SkBlurMaskFilter.h
+++ b/gfx/skia/include/effects/SkBlurMaskFilter.h
@@ -50,14 +50,16 @@ public:
         @param specular     coefficient for specular highlights (e.g. 8)
         @param blurRadius   amount to blur before applying lighting (e.g. 3)
         @return the emboss maskfilter
     */
     static SkMaskFilter* CreateEmboss(  const SkScalar direction[3],
                                         SkScalar ambient, SkScalar specular,
                                         SkScalar blurRadius);
 
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
+
 private:
     SkBlurMaskFilter(); // can't be instantiated
 };
 
 #endif
 
--- a/gfx/skia/include/effects/SkColorMatrixFilter.h
+++ b/gfx/skia/include/effects/SkColorMatrixFilter.h
@@ -18,31 +18,34 @@ public:
     SkColorMatrixFilter();
     explicit SkColorMatrixFilter(const SkColorMatrix&);
     SkColorMatrixFilter(const SkScalar array[20]);
 
     void setMatrix(const SkColorMatrix&);
     void setArray(const SkScalar array[20]);
 
     // overrides from SkColorFilter
-    virtual void filterSpan(const SkPMColor src[], int count, SkPMColor[]);
-    virtual void filterSpan16(const uint16_t src[], int count, uint16_t[]);
-    virtual uint32_t getFlags();
+    virtual void filterSpan(const SkPMColor src[], int count, SkPMColor[]) SK_OVERRIDE;
+    virtual void filterSpan16(const uint16_t src[], int count, uint16_t[]) SK_OVERRIDE;
+    virtual uint32_t getFlags() SK_OVERRIDE;
+    virtual bool asColorMatrix(SkScalar matrix[20]) SK_OVERRIDE;
 
     // overrides for SkFlattenable
-    virtual void flatten(SkFlattenableWriteBuffer& buffer);
+    virtual void flatten(SkFlattenableWriteBuffer& buffer) SK_OVERRIDE;
 
     struct State {
         int32_t fArray[20];
         int     fShift;
         int32_t fResult[4];
     };
 
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer);
 
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
+
 protected:
     // overrides for SkFlattenable
     virtual Factory getFactory();
 
     SkColorMatrixFilter(SkFlattenableReadBuffer& buffer);
 
 private:
 
--- a/gfx/skia/include/effects/SkCornerPathEffect.h
+++ b/gfx/skia/include/effects/SkCornerPathEffect.h
@@ -32,16 +32,18 @@ public:
     // overrides for SkFlattenable
     //  This method is not exported to java.
     virtual Factory getFactory();
     //  This method is not exported to java.
     virtual void flatten(SkFlattenableWriteBuffer&);
 
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
 
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
+
 protected:
     SkCornerPathEffect(SkFlattenableReadBuffer&);
 
 private:
     SkScalar    fRadius;
     
     typedef SkPathEffect INHERITED;
 };
--- a/gfx/skia/include/effects/SkDashPathEffect.h
+++ b/gfx/skia/include/effects/SkDashPathEffect.h
@@ -34,16 +34,18 @@ public:
     // overrides for SkFlattenable
     //  This method is not exported to java.
     virtual Factory getFactory();
     //  This method is not exported to java.
     virtual void flatten(SkFlattenableWriteBuffer&);
 
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
 
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
+
 protected:
     SkDashPathEffect(SkFlattenableReadBuffer&);
     
 private:
     SkScalar*   fIntervals;
     int32_t     fCount;
     // computed from phase
     SkScalar    fInitialDashLength;
--- a/gfx/skia/include/effects/SkDiscretePathEffect.h
+++ b/gfx/skia/include/effects/SkDiscretePathEffect.h
@@ -31,16 +31,18 @@ public:
     // overrides for SkFlattenable
     //  This method is not exported to java.
     virtual Factory getFactory();
     //  This method is not exported to java.
     virtual void flatten(SkFlattenableWriteBuffer&);
 
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
 
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
+
 protected:
     SkDiscretePathEffect(SkFlattenableReadBuffer&);
 
 private:
     SkScalar fSegLength, fPerterb;
     
     typedef SkPathEffect INHERITED;
 };
new file mode 100644
--- /dev/null
+++ b/gfx/skia/include/effects/SkEffects.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkEffects_DEFINED
+#define SkEffects_DEFINED
+
+class SkEffects {
+public:
+    static void Init();
+};
+
+#endif
--- a/gfx/skia/include/effects/SkEmbossMaskFilter.h
+++ b/gfx/skia/include/effects/SkEmbossMaskFilter.h
@@ -36,16 +36,18 @@ public:
 
     // overrides from SkFlattenable
 
     //  This method is not exported to java.
     virtual Factory getFactory();
     //  This method is not exported to java.
     virtual void flatten(SkFlattenableWriteBuffer&);
 
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
+
 protected:
     SkEmbossMaskFilter(SkFlattenableReadBuffer&);
 
 private:
     Light       fLight;
     SkScalar    fBlurRadius;
 
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
--- a/gfx/skia/include/effects/SkGradientShader.h
+++ b/gfx/skia/include/effects/SkGradientShader.h
@@ -107,12 +107,14 @@ public:
                         If this is not null, the values must begin with 0, end with 1.0, and
                         intermediate values must be strictly increasing.
         @param  count   Must be >= 2. The number of colors (and pos if not NULL) entries
         @param  mapper  May be NULL. Callback to modify the spread of the colors.
     */
     static SkShader* CreateSweep(SkScalar cx, SkScalar cy,
                                  const SkColor colors[], const SkScalar pos[],
                                  int count, SkUnitMapper* mapper = NULL);
+
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
 };
 
 #endif
 
--- a/gfx/skia/include/effects/SkGroupShape.h
+++ b/gfx/skia/include/effects/SkGroupShape.h
@@ -133,16 +133,18 @@ public:
 
     // overrides
     virtual Factory getFactory();
     virtual void flatten(SkFlattenableWriteBuffer&);
 
     // public for Registrar
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
 
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
+
 protected:
     // overrides
     virtual void onDraw(SkCanvas*);
 
     SkGroupShape(SkFlattenableReadBuffer&);
 
 private:
     struct Rec {
--- a/gfx/skia/include/effects/SkLayerDrawLooper.h
+++ b/gfx/skia/include/effects/SkLayerDrawLooper.h
@@ -17,28 +17,37 @@ class SK_API SkLayerDrawLooper : public 
 public:
             SkLayerDrawLooper();
     virtual ~SkLayerDrawLooper();
 
     /**
      *  Bits specifies which aspects of the layer's paint should replace the
      *  corresponding aspects on the draw's paint.
      *  kEntirePaint_Bits means use the layer's paint completely.
-     *  0 means ignore the layer's paint.
+     *  0 means ignore the layer's paint... except that LayerInfo's fFlagsMask
+     *  and fColorMode are always applied.
      */
     enum Bits {
         kStyle_Bit      = 1 << 0,   //!< use this layer's Style/stroke settings
         kTextSkewX_Bit  = 1 << 1,   //!< use this layer's textskewx
         kPathEffect_Bit = 1 << 2,   //!< use this layer's patheffect
         kMaskFilter_Bit = 1 << 3,   //!< use this layer's maskfilter
         kShader_Bit     = 1 << 4,   //!< use this layer's shader
         kColorFilter_Bit = 1 << 5,  //!< use this layer's colorfilter
         kXfermode_Bit   = 1 << 6,   //!< use this layer's xfermode
         
-        kEntirePaint_Bits = -1,      //!< use this layer's paint entirely
+        /**
+         *  Use the layer's paint entirely, with these exceptions:
+         *  - We never override the draw's paint's text_encoding, since that is
+         *    used to interpret the text/len parameters in draw[Pos]Text.
+         *  - Flags and Color are always computed using the LayerInfo's
+         *    fFlagsMask and fColorMode.
+         */
+        kEntirePaint_Bits = -1,
+        
     };
     typedef int32_t BitFlags;
 
     /**
      *  Info for how to apply the layer's paint and offset.
      *
      *  fFlagsMask selects which flags in the layer's paint should be applied.
      *      result = (draw-flags & ~fFlagsMask) | (layer-flags & fFlagsMask)
@@ -92,16 +101,18 @@ public:
     virtual void init(SkCanvas*);
     virtual bool next(SkCanvas*, SkPaint* paint);
 
     // must be public for Registrar :(
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
         return SkNEW_ARGS(SkLayerDrawLooper, (buffer));
     }
     
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
+
 protected:
     SkLayerDrawLooper(SkFlattenableReadBuffer&);
 
     // overrides from SkFlattenable
     virtual void flatten(SkFlattenableWriteBuffer& );
     virtual Factory getFactory() { return CreateProc; }
     
 private:
--- a/gfx/skia/include/effects/SkLayerRasterizer.h
+++ b/gfx/skia/include/effects/SkLayerRasterizer.h
@@ -33,16 +33,18 @@ public:
     void addLayer(const SkPaint& paint, SkScalar dx, SkScalar dy);
 
     // overrides from SkFlattenable
     virtual Factory getFactory();
     virtual void    flatten(SkFlattenableWriteBuffer&);
 
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
 
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
+
 protected:
     SkLayerRasterizer(SkFlattenableReadBuffer&);
 
     // override from SkRasterizer
     virtual bool onRasterize(const SkPath& path, const SkMatrix& matrix,
                              const SkIRect* clipBounds,
                              SkMask* mask, SkMask::CreateMode mode);
 
--- a/gfx/skia/include/effects/SkPixelXorXfermode.h
+++ b/gfx/skia/include/effects/SkPixelXorXfermode.h
@@ -24,16 +24,18 @@ public:
     // override from SkFlattenable
     virtual Factory getFactory();
     virtual void flatten(SkFlattenableWriteBuffer&);
 
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
         return SkNEW_ARGS(SkPixelXorXfermode, (buffer));
     }
 
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
+
 protected:
     // override from SkXfermode
     virtual SkPMColor xferColor(SkPMColor src, SkPMColor dst);
 
 private:
     SkColor fOpColor;
 
     SkPixelXorXfermode(SkFlattenableReadBuffer& rb);
--- a/gfx/skia/include/effects/SkPorterDuff.h
+++ b/gfx/skia/include/effects/SkPorterDuff.h
@@ -40,17 +40,17 @@ public:
         kSrcATop_Mode,  //!< [Da, Sc * Da + (1 - Sa) * Dc]
         kDstATop_Mode,  //!< [Sa, Sa * Dc + Sc * (1 - Da)]
         kXor_Mode,      //!< [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
         kDarken_Mode,   //!< [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)]
         kLighten_Mode,  //!< [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)]
         kMultiply_Mode, //!< [Sa * Da, Sc * Dc]
         kScreen_Mode,   //!< [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc]
         kAdd_Mode,      //!< Saturate(S + D)
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
         kOverlay_Mode,
 #endif
 
         kModeCount
     };
 
     /** Return an SkXfermode object for the specified mode.
     */
--- a/gfx/skia/include/effects/SkRectShape.h
+++ b/gfx/skia/include/effects/SkRectShape.h
@@ -42,16 +42,18 @@ public:
 
     // overrides
     virtual Factory getFactory();
     virtual void flatten(SkFlattenableWriteBuffer&);
 
     // public for Registrar
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
 
+    SK_DECLARE_FLATTENABLE_REGISTRAR()
+
 protected:
     SkRectShape(SkFlattenableReadBuffer&);
 
     // overrides
     virtual void onDraw(SkCanvas*);
 
 private:
     SkRect  fBounds;
new file mode 100644
--- /dev/null
+++ b/gfx/skia/include/effects/SkTableColorFilter.h
@@ -0,0 +1,34 @@
+
+#ifndef SkTableColorFilter_DEFINED
+#define SkTableColorFilter_DEFINED
+
+#include "SkColorFilter.h"
+
+class SkTableColorFilter {
+public:
+    /**
+     *  Create a table colorfilter, copying the table into the filter, and
+     *  applying it to all 4 components.
+     *      a' = table[a];
+     *      r' = table[r];
+     *      g' = table[g];
+     *      b' = table[b];
+     *  Compoents are operated on in unpremultiplied space. If the incomming
+     *  colors are premultiplied, they are temporarily unpremultiplied, then
+     *  the table is applied, and then the result is remultiplied.
+     */
+    static SkColorFilter* Create(const uint8_t table[256]);
+    
+    /**
+     *  Create a table colorfilter, with a different table for each
+     *  component [A, R, G, B]. If a given table is NULL, then it is
+     *  treated as identity, with the component left unchanged. If a table
+     *  is not null, then its contents are copied into the filter.
+     */
+    static SkColorFilter* CreateARGB(const uint8_t tableA[256],
+                                     const uint8_t tableR[256],
+                                     const uint8_t tableG[256],
+                                     const uint8_t tableB[256]);
+};
+
+#endif
new file mode 100755
--- /dev/null
+++ b/gfx/skia/include/effects/SkTestImageFilters.h
@@ -0,0 +1,157 @@
+
+#ifndef _SkTestImageFilters_h
+#define _SkTestImageFilters_h
+
+#include "SkImageFilter.h"
+
+class SkOffsetImageFilter : public SkImageFilter {
+public:
+    SkOffsetImageFilter(SkScalar dx, SkScalar dy) {
+        fOffset.set(dx, dy);
+    }
+
+    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+        return SkNEW_ARGS(SkOffsetImageFilter, (buffer));
+    }
+
+protected:
+    SkOffsetImageFilter(SkFlattenableReadBuffer& buffer);
+
+    virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
+                               SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
+    virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) SK_OVERRIDE;
+    // overrides from SkFlattenable
+    virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+    virtual Factory getFactory() SK_OVERRIDE;
+
+private:
+    SkVector fOffset;
+
+    typedef SkImageFilter INHERITED;
+};
+
+class SkComposeImageFilter : public SkImageFilter {
+public:
+    SkComposeImageFilter(SkImageFilter* outer, SkImageFilter* inner) {
+        fOuter = outer;
+        fInner = inner;
+        SkSafeRef(outer);
+        SkSafeRef(inner);
+    }
+    virtual ~SkComposeImageFilter();
+
+    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+        return SkNEW_ARGS(SkComposeImageFilter, (buffer));
+    }
+    
+protected:
+    SkComposeImageFilter(SkFlattenableReadBuffer& buffer);
+    
+    virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
+                               SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
+    virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) SK_OVERRIDE;
+    // overrides from SkFlattenable
+    virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+    virtual Factory getFactory() SK_OVERRIDE;
+    
+private:
+    SkImageFilter*  fOuter;
+    SkImageFilter*  fInner;
+    
+    typedef SkImageFilter INHERITED;
+};
+
+#include "SkXfermode.h"
+
+class SkMergeImageFilter : public SkImageFilter {
+public:
+    SkMergeImageFilter(SkImageFilter* first, SkImageFilter* second,
+                       SkXfermode::Mode = SkXfermode::kSrcOver_Mode);
+    SkMergeImageFilter(SkImageFilter* const filters[], int count,
+                       const SkXfermode::Mode modes[] = NULL);
+    virtual ~SkMergeImageFilter();
+    
+    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+        return SkNEW_ARGS(SkMergeImageFilter, (buffer));
+    }
+    
+protected:
+    SkMergeImageFilter(SkFlattenableReadBuffer& buffer);
+    
+    virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
+                               SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
+    virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) SK_OVERRIDE;
+    // overrides from SkFlattenable
+    virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+    virtual Factory getFactory() SK_OVERRIDE;
+    
+private:
+    SkImageFilter**     fFilters;
+    uint8_t*            fModes; // SkXfermode::Mode
+    int                 fCount;
+
+    // private storage, to avoid dynamically allocating storage for our copy
+    // of the filters and modes (unless fCount is so large we can't fit).
+    intptr_t    fStorage[16];
+
+    void initAlloc(int count, bool hasModes);
+    void init(SkImageFilter* const [], int count, const SkXfermode::Mode []);
+    
+    typedef SkImageFilter INHERITED;
+};
+
+class SkColorFilter;
+
+class SkColorFilterImageFilter : public SkImageFilter {
+public:
+    SkColorFilterImageFilter(SkColorFilter* cf) : fColorFilter(cf) {
+        SkSafeRef(cf);
+    }
+    virtual ~SkColorFilterImageFilter();
+
+    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+        return SkNEW_ARGS(SkColorFilterImageFilter, (buffer));
+    }
+    
+protected:
+    SkColorFilterImageFilter(SkFlattenableReadBuffer& buffer);
+    
+    virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
+                               SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
+    // overrides from SkFlattenable
+    virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+    virtual Factory getFactory() SK_OVERRIDE;
+    
+private:
+    SkColorFilter*  fColorFilter;
+    
+    typedef SkImageFilter INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+// Fun mode that scales down (only) and then scales back up to look pixelated
+class SkDownSampleImageFilter : public SkImageFilter {
+public:
+    SkDownSampleImageFilter(SkScalar scale) : fScale(scale) {}
+    
+    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+        return SkNEW_ARGS(SkDownSampleImageFilter, (buffer));
+    }
+    
+protected:
+    SkDownSampleImageFilter(SkFlattenableReadBuffer& buffer);
+    
+    virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
+                               SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
+    // overrides from SkFlattenable
+    virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+    virtual Factory getFactory()  SK_OVERRIDE;
+    
+private:
+    SkScalar fScale;
+    
+    typedef SkImageFilter INHERITED;
+};
+
+#endif
--- a/gfx/skia/include/effects/SkTransparentShader.h
+++ b/gfx/skia/include/effects/SkTransparentShader.h
@@ -10,29 +10,28 @@
 #ifndef SkTransparentShader_DEFINED
 #define SkTransparentShader_DEFINED
 
 #include "SkShader.h"
 
 class SkTransparentShader : public SkShader {
 public:
     SkTransparentShader() {}
-    virtual uint32_t getFlags();
+
+    virtual uint32_t getFlags() SK_OVERRIDE;
     virtual bool    setContext( const SkBitmap& device,
                                 const SkPaint& paint,
-                                const SkMatrix& matrix);
-    virtual void    shadeSpan(int x, int y, SkPMColor[], int count);
-    virtual void    shadeSpan16(int x, int y, uint16_t span[], int count);
+                                const SkMatrix& matrix) SK_OVERRIDE;
+    virtual void    shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE;
+    virtual void    shadeSpan16(int x, int y, uint16_t span[], int count) SK_OVERRIDE;
 
     // overrides for SkFlattenable
-    virtual Factory getFactory() { return Create; }
-    virtual void flatten(SkFlattenableWriteBuffer& buffer) {
-        this->INHERITED::flatten(buffer);
-    }
-        
+    virtual Factory getFactory() SK_OVERRIDE;
+    virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+
 private:
     // these are a cache from the call to setContext()
     const SkBitmap* fDevice;
     uint8_t         fAlpha;
 
     SkTransparentShader(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
     
     static SkFlattenable* Create(SkFlattenableReadBuffer& buffer) {
--- a/gfx/skia/include/gpu/GrColor.h
+++ b/gfx/skia/include/gpu/GrColor.h
@@ -14,25 +14,22 @@
 #include "GrTypes.h"
 
 /**
  *  GrColor is 4 bytes for R, G, B, A, in a compile-time specific order. The
  *  components are stored premultiplied.
  */
 typedef uint32_t GrColor;
 
-// indices for address a GrColor as an array of bytes
 
-#define GrColor_INDEX_R     0
-#define GrColor_INDEX_G     1
-#define GrColor_INDEX_B     2
-#define GrColor_INDEX_A     3
-
-// shfit amount to assign a component to a GrColor int
-
+// shift amount to assign a component to a GrColor int<