Merge cvs-trunk-mirror to mozilla-central.
authorjorendorff@mozilla.com
Fri, 21 Sep 2007 09:55:35 -0400
changeset 6190 324afbcccb719746cc5e3cb36d870b4fbf8b2d1c
parent 6143 a51e9fb65b8a5e3c3325eb117dbac8b6e41f56e0 (current diff)
parent 6189 d58d4affa7cdda598379ce011dbd4f8538112588 (diff)
child 6191 ad1c1a85d0bbf87ca3fbbe8c3a1b3b237ce469c7
push idunknown
push userunknown
push dateunknown
milestone1.9a8pre
Merge cvs-trunk-mirror to mozilla-central.
gfx/cairo/clone-similar-fallback.patch
gfx/cairo/scaled-font-create-deadlock.patch
gfx/cairo/win32-no-printer-bitblt.patch
gfx/cairo/win32-scaled-font-size.patch
js/src/jsgc.cpp
js/src/jsinterp.cpp
js/src/jsnum.cpp
js/src/jsstr.cpp
xpcom/ds/nsTextFormatter.cpp
xpcom/ds/nsTextFormatter.h
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -2296,79 +2296,91 @@ nsAccessible::GetFinalState(PRUint32 *aS
 
   nsresult rv = GetState(aState, aExtraState);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Apply ARIA states to be sure accessible states will be overriden.
   *aState |= GetARIAState();
 
   // Set additional states which presence depends on another states.
-  if (aExtraState) {
-    if (!(*aState & nsIAccessibleStates::STATE_UNAVAILABLE)) {
-      *aExtraState |= nsIAccessibleStates::EXT_STATE_ENABLED |
-                      nsIAccessibleStates::EXT_STATE_SENSITIVE;
+  if (!aExtraState)
+    return NS_OK;
+
+  if (!(*aState & nsIAccessibleStates::STATE_UNAVAILABLE)) {
+    *aExtraState |= nsIAccessibleStates::EXT_STATE_ENABLED |
+                    nsIAccessibleStates::EXT_STATE_SENSITIVE;
+  }
+
+  const PRUint32 kExpandCollapseStates =
+    nsIAccessibleStates::STATE_COLLAPSED | nsIAccessibleStates::STATE_EXPANDED;
+  if (*aState & kExpandCollapseStates) {
+    *aExtraState |= nsIAccessibleStates::EXT_STATE_EXPANDABLE;
+    if ((*aState & kExpandCollapseStates) == kExpandCollapseStates) {
+      // Cannot be both expanded and collapsed -- this happens 
+      // in ARIA expanded combobox because of limitation of nsARIAMap
+      // XXX Perhaps we will be able to make this less hacky if 
+      // we support extended states in nsARIAMap, e.g. derive
+      // COLLAPSED from EXPANDABLE && !EXPANDED
+      *aExtraState &= ~nsIAccessibleStates::STATE_COLLAPSED;
     }
-
-    const PRUint32 kExpandCollapseStates =
-      nsIAccessibleStates::STATE_COLLAPSED | nsIAccessibleStates::STATE_EXPANDED;
-    if (*aState & kExpandCollapseStates) {
-      *aExtraState |= nsIAccessibleStates::EXT_STATE_EXPANDABLE;
-      if ((*aState & kExpandCollapseStates) == kExpandCollapseStates) {
-        // Cannot be both expanded and collapsed -- this happens 
-        // in ARIA expanded combobox because of limitation of nsARIAMap
-        // XXX Perhaps we will be able to make this less hacky if 
-        // we support extended states in nsARIAMap, e.g. derive
-        // COLLAPSED from EXPANDABLE && !EXPANDED
-        *aExtraState &= ~nsIAccessibleStates::STATE_COLLAPSED;
-      } 
+  }
+
+  PRUint32 role;
+  rv = GetFinalRole(&role);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (role == nsIAccessibleRole::ROLE_ENTRY ||
+      role == nsIAccessibleRole::ROLE_PASSWORD_TEXT ||
+      role == nsIAccessibleRole::ROLE_COMBOBOX) {
+
+    nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
+    NS_ENSURE_STATE(content);
+
+    nsAutoString autocomplete;
+    if (content->GetAttr(kNameSpaceID_WAIProperties,
+                         nsAccessibilityAtoms::autocomplete, autocomplete) &&
+        (autocomplete.EqualsIgnoreCase("inline") ||
+         autocomplete.EqualsIgnoreCase("list") ||
+         autocomplete.EqualsIgnoreCase("both"))) {
+      *aExtraState |= nsIAccessibleStates::EXT_STATE_SUPPORTS_AUTOCOMPLETION;
     }
-    nsIFrame *frame = GetFrame();
-    if (frame) {
-      const nsStyleDisplay* display = frame->GetStyleDisplay();
-      if (display && display->mOpacity == 1.0f &&
-          !(*aState & nsIAccessibleStates::STATE_INVISIBLE)) {
-        *aExtraState |= nsIAccessibleStates::EXT_STATE_OPAQUE;
+
+    // XXX We can remove this hack once we support RDF-based role & state maps
+    if (mRoleMapEntry && mRoleMapEntry->role == nsIAccessibleRole::ROLE_ENTRY) {
+      if (content->AttrValueIs(kNameSpaceID_WAIProperties,
+                               nsAccessibilityAtoms::multiline,
+                               nsAccessibilityAtoms::_true, eCaseMatters)) {
+        *aExtraState |= nsIAccessibleStates::EXT_STATE_MULTI_LINE;
       }
-
-      const nsStyleXUL *xulStyle = frame->GetStyleXUL();
-      if (xulStyle) {
-        // In XUL all boxes are either vertical or horizontal
-        if (xulStyle->mBoxOrient == NS_STYLE_BOX_ORIENT_VERTICAL) {
-          *aExtraState |= nsIAccessibleStates::EXT_STATE_VERTICAL;
-        }
-        else {
-          *aExtraState |= nsIAccessibleStates::EXT_STATE_HORIZONTAL;
-        }
+      else {
+        *aExtraState |= nsIAccessibleStates::EXT_STATE_SINGLE_LINE;
       }
     }
-
-    PRUint32 role;
-    GetFinalRole(&role);
-    if (role == nsIAccessibleRole::ROLE_ENTRY ||
-        role == nsIAccessibleRole::ROLE_PASSWORD_TEXT ||
-        role == nsIAccessibleRole::ROLE_COMBOBOX) {
-      nsIContent *content = frame->GetContent();
-      NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
-      nsAutoString autocomplete;
-      if (content->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::autocomplete, autocomplete) &&
-          (autocomplete.EqualsIgnoreCase("inline") ||
-           autocomplete.EqualsIgnoreCase("list") ||
-           autocomplete.EqualsIgnoreCase("both"))) {
-        *aExtraState |= nsIAccessibleStates::EXT_STATE_SUPPORTS_AUTOCOMPLETION;
-      }
-      // XXX We can remove this hack once we support RDF-based role & state maps
-      if (mRoleMapEntry && mRoleMapEntry->role == nsIAccessibleRole::ROLE_ENTRY) {
-        if (content->AttrValueIs(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::multiline,
-                                 nsAccessibilityAtoms::_true, eCaseMatters)) {
-          *aExtraState |= nsIAccessibleStates::EXT_STATE_MULTI_LINE;
-        }
-        else {
-          *aExtraState |= nsIAccessibleStates::EXT_STATE_SINGLE_LINE;
-        }
-      }
+  }
+
+  // For some reasons DOM node may have not a frame. We tract such accessibles
+  // as invisible.
+  nsIFrame *frame = GetFrame();
+  if (!frame)
+    return NS_OK;
+
+  const nsStyleDisplay* display = frame->GetStyleDisplay();
+  if (display && display->mOpacity == 1.0f &&
+      !(*aState & nsIAccessibleStates::STATE_INVISIBLE)) {
+    *aExtraState |= nsIAccessibleStates::EXT_STATE_OPAQUE;
+  }
+
+  const nsStyleXUL *xulStyle = frame->GetStyleXUL();
+  if (xulStyle) {
+    // In XUL all boxes are either vertical or horizontal
+    if (xulStyle->mBoxOrient == NS_STYLE_BOX_ORIENT_VERTICAL) {
+      *aExtraState |= nsIAccessibleStates::EXT_STATE_VERTICAL;
+    }
+    else {
+      *aExtraState |= nsIAccessibleStates::EXT_STATE_HORIZONTAL;
     }
   }
 
   return NS_OK;
 }
 
 PRUint32
 nsAccessible::GetARIAState()
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -5360,24 +5360,27 @@ HistoryMenu.populateUndoSubmenu = functi
   }
 
   // enable menu
   undoPopup.parentNode.removeAttribute("disabled");
 
   // populate menu
   var undoItems = eval("(" + ss.getClosedTabData(window) + ")");
   for (var i = 0; i < undoItems.length; i++) {
-    var m = undoPopup.appendChild(document.createElement("menuitem"));
+    var m = document.createElement("menuitem");
     m.setAttribute("label", undoItems[i].title);
     if (undoItems[i].image)
       m.setAttribute("image", undoItems[i].image);
     m.setAttribute("class", "menuitem-iconic bookmark-item");
     m.setAttribute("value", i);
     m.setAttribute("oncommand", "undoCloseTab(" + i + ");");
     m.addEventListener("click", undoCloseMiddleClick, false);
+    if (i == 0)
+      m.setAttribute("key", "key_undoCloseTab");
+    undoPopup.appendChild(m);
   }
 
   // "Open All in Tabs"
   var strings = gNavigatorBundle;
   undoPopup.appendChild(document.createElement("menuseparator"));
   m = undoPopup.appendChild(document.createElement("menuitem"));
   m.setAttribute("label", strings.getString("menuOpenAllInTabs.label"));
   m.setAttribute("accesskey", strings.getString("menuOpenAllInTabs.accesskey"));
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -38,19 +38,21 @@ DEPTH		= ../../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = browser/base/content/test
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
-_TEST_FILES = 	test_feed_discovery.html \
-	   feed_discovery.html \
-    $(NULL)
+_TEST_FILES =	test_feed_discovery.html \
+		feed_discovery.html \
+		test_bug395533.html \
+		bug395533-data.txt \
+		$(NULL)
 
 _BROWSER_FILES = browser_bug321000.js \
     $(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
 
 libs::	$(_BROWSER_FILES)
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/bug395533-data.txt
@@ -0,0 +1,6 @@
+<rss version="2.0">
+  <channel>
+    <link>http://example.org/</link>
+    <title>t</title>
+  </channel>
+</rss>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/test_bug395533.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=395533
+-->
+<head>
+  <title>Test for Bug 395533</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <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=395533">Mozilla Bug 395533</a>
+<p id="display"><iframe id="testFrame" src="bug395533-data.txt"></iframe></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 395533 **/
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(function() {
+  // Need privs because the feed seems to have an about:feeds principal or some
+  // such.  It's not same-origin with us in any case.
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
+  is($("testFrame").contentDocument.documentElement.id, "feedHandler",
+     "Text didn't get sniffed as a feed?");
+});
+addLoadEvent(SimpleTest.finish);
+
+
+
+
+</script>
+</pre>
+</body>
+</html>
+
--- a/browser/components/places/content/places.xul
+++ b/browser/components/places/content/places.xul
@@ -18,16 +18,17 @@
 # The Initial Developer of the Original Code is Google Inc.
 # Portions created by the Initial Developer are Copyright (C) 2005-2006
 # the Initial Developer. All Rights Reserved.
 #
 # Contributor(s):
 #   Ben Goodger <beng@google.com>
 #   Annie Sullivan <annie.sullivan@gmail.com>
 #   Asaf Romano <mano@mozilla.com>
+#   Ehsan Akhgari <ehsan.akhgari@gmail.com>
 #
 # Alternatively, the contents of this file may be used under the terms of
 # either the GNU General Public License Version 2 or later (the "GPL"), or
 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 # in which case the provisions of the GPL or the LGPL are applicable instead
 # of those above. If you wish to allow use of your version of this file only
 # under the terms of either the GPL or the LGPL, and not to allow others to
 # use your version of this file under the terms of the MPL, indicate your
@@ -271,17 +272,17 @@
         <menupopup id="viewMenuPopup">
           <menuitem id="viewDetails"
                     type="radio"
 #ifdef MACOSX
                     label="&view.detailsMacOSX.label;"
 #else
                     label="&view.details.label;"
 #endif
-                    accesskey="&view.details.label;">
+                    accesskey="&view.details.accesskey;">
           </menuitem>
 
           <menuseparator id="addonsSeparator"/>
 
           <!--
           <menuitem id="viewAddons"
                     command=""
                     label="&view.addons.label;"
--- a/browser/components/places/content/utils.js
+++ b/browser/components/places/content/utils.js
@@ -1474,17 +1474,18 @@ var PlacesUtils = {
    * Set the POST data associated with a URI, if any.
    * Used by POST keywords.
    *   @param aURI
    *   @returns string of POST data
    */
   setPostDataForURI: function PU_setPostDataForURI(aURI, aPostData) {
     const annos = this.annotations;
     if (aPostData)
-      annos.setPageAnnotation(aURI, POST_DATA_ANNO, aPostData, 0, 0);
+      annos.setPageAnnotation(aURI, POST_DATA_ANNO, aPostData, 
+                              0, Ci.nsIAnnotationService.EXPIRE_NEVER);
     else if (annos.pageHasAnnotation(aURI, POST_DATA_ANNO))
       annos.removePageAnnotation(aURI, POST_DATA_ANNO);
   },
 
   /**
    * Get the POST data associated with a bookmark, if any.
    * @param aURI
    * @returns string of POST data if set for aURI. null otherwise.
--- a/browser/components/preferences/applications.js
+++ b/browser/components/preferences/applications.js
@@ -694,20 +694,25 @@ var feedHandlerInfo = {
 //****************************************************************************//
 // Prefpane Controller
 
 var gApplicationsPane = {
   // The set of types the app knows how to handle.  A hash of HandlerInfoWrapper
   // objects, indexed by type.
   _handledTypes: {},
 
-  _brandBundle  : null,
-  _prefsBundle  : null,
-  _list         : null,
-  _filter       : null,
+
+  //**************************************************************************//
+  // Convenience & Performance Shortcuts
+
+  // These get defined by init().
+  _brandShortName : null,
+  _prefsBundle    : null,
+  _list           : null,
+  _filter         : null,
 
   // Retrieve this as nsIPrefBranch and then immediately QI to nsIPrefBranch2
   // so both interfaces are available to callers.
   _prefSvc      : Cc["@mozilla.org/preferences-service;1"].
                   getService(Ci.nsIPrefBranch).
                   QueryInterface(Ci.nsIPrefBranch2),
 
   _mimeSvc      : Cc["@mozilla.org/uriloader/external-helper-app-service;1"].
@@ -722,18 +727,19 @@ var gApplicationsPane = {
   _ioSvc        : Cc["@mozilla.org/network/io-service;1"].
                   getService(Ci.nsIIOService),
 
 
   //**************************************************************************//
   // Initialization & Destruction
 
   init: function() {
-    // Initialize shortcuts to some commonly accessed elements.
-    this._brandBundle = document.getElementById("bundleBrand");
+    // Initialize shortcuts to some commonly accessed elements & values.
+    this._brandShortName =
+      document.getElementById("bundleBrand").getString("brandShortName");
     this._prefsBundle = document.getElementById("bundlePreferences");
     this._list = document.getElementById("handlersView");
     this._filter = document.getElementById("filter");
 
     // Observe preferences that influence what we display so we can rebuild
     // the view when they change.
     this._prefSvc.addObserver(PREF_SHOW_PLUGINS_IN_LIST, this, false);
     this._prefSvc.addObserver(PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS, this, false);
@@ -758,17 +764,16 @@ var gApplicationsPane = {
     // to an appropriate size before we add a bunch of items to the list.
     // Otherwise, if there are many items, and the Applications prefpane
     // is the one that gets displayed when the user first opens the dialog,
     // the dialog might stretch too much in an attempt to fit them all in.
     // XXX Shouldn't we perhaps just set a max-height on the richlistbox?
     var _delayedPaneLoad = function(self) {
       self._loadData();
       self.rebuildView();
-      self._list.focus();
     }
     setTimeout(_delayedPaneLoad, 0, this);
   },
 
   destroy: function() {
     window.removeEventListener("unload", this, false);
     this._prefSvc.removeObserver(PREF_SHOW_PLUGINS_IN_LIST, this);
     this._prefSvc.removeObserver(PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS, this);
@@ -987,29 +992,31 @@ var gApplicationsPane = {
    *                                      is being described
    */
   _describePreferredAction: function(aHandlerInfo) {
     // alwaysAskBeforeHandling overrides the preferred action, so if that flag
     // is set, then describe that behavior instead.  Currently we hide all types
     // with alwaysAskBeforeHandling except for the feed type, so here we use
     // a feed-specific message to describe the behavior.
     if (aHandlerInfo.alwaysAskBeforeHandling)
-      return this._prefsBundle.getString("alwaysAskAboutFeed");
+      return this._prefsBundle.getFormattedString("previewInApp",
+                                                  [this._brandShortName]);
 
     switch (aHandlerInfo.preferredAction) {
       case Ci.nsIHandlerInfo.saveToDisk:
         return this._prefsBundle.getString("saveToDisk");
 
       case Ci.nsIHandlerInfo.useHelperApp:
         return aHandlerInfo.preferredApplicationHandler.name;
 
       case Ci.nsIHandlerInfo.handleInternally:
         // For the feed type, handleInternally means live bookmarks.
         if (aHandlerInfo.type == TYPE_MAYBE_FEED)
-          return this._prefsBundle.getString("liveBookmarks");
+          return this._prefsBundle.getFormattedString("liveBookmarksInApp",
+                                                      [this._brandShortName]);
 
         // For other types, handleInternally looks like either useHelperApp
         // or useSystemDefault depending on whether or not there's a preferred
         // handler app.
         if (this.isValidHandlerApp(aHandlerInfo.preferredApplicationHandler))
           return aHandlerInfo.preferredApplicationHandler.name;
 
         return aHandlerInfo.defaultDescription;
@@ -1018,20 +1025,19 @@ var gApplicationsPane = {
         // Is it because the app can't actually do that?  But if that's true,
         // then why would a preferredAction ever get set to this value
         // in the first place?
 
       case Ci.nsIHandlerInfo.useSystemDefault:
         return aHandlerInfo.defaultDescription;
 
       case kActionUsePlugin:
-        let brandShortName = this._brandBundle.getString("brandShortName");
         return this._prefsBundle.getFormattedString("pluginName",
                                                     [aHandlerInfo.plugin.name,
-                                                     brandShortName]);
+                                                     this._brandShortName]);
     }
   },
 
   /**
    * Whether or not the given handler app is valid.
    *
    * @param aHandlerApp {nsIHandlerApp} the handler app in question
    *
@@ -1069,25 +1075,28 @@ var gApplicationsPane = {
     // Clear out existing items.
     while (menuPopup.hasChildNodes())
       menuPopup.removeChild(menuPopup.lastChild);
 
     // If this is the feed type, add Preview in Firefox and Live Bookmarks items.
     if (handlerInfo.type == TYPE_MAYBE_FEED) {
       let menuItem = document.createElementNS(kXULNS, "menuitem");
       menuItem.setAttribute("alwaysAsk", "true");
-      menuItem.setAttribute("label",
-                            this._prefsBundle.getString("alwaysAskAboutFeed"));
+      let label = this._prefsBundle.getFormattedString("previewInApp",
+                                                       [this._brandShortName]);
+      menuItem.setAttribute("label", label);
       menuPopup.appendChild(menuItem);
       if (handlerInfo.alwaysAskBeforeHandling)
         menu.selectedItem = menuItem;
 
       menuItem = document.createElementNS(kXULNS, "menuitem");
       menuItem.setAttribute("action", Ci.nsIHandlerInfo.handleInternally);
-      menuItem.setAttribute("label", this._prefsBundle.getString("liveBookmarks"));
+      label = this._prefsBundle.getFormattedString("liveBookmarksInApp",
+                                                   [this._brandShortName]);
+      menuItem.setAttribute("label", label);
       menuItem.setAttribute("image", "chrome://browser/skin/page-livemarks.png");
       menuPopup.appendChild(menuItem);
       if (handlerInfo.preferredAction == Ci.nsIHandlerInfo.handleInternally)
         menu.selectedItem = menuItem;
 
       // Add a separator to distinguish these items from the helper app items
       // that follow them.
       menuItem = document.createElementNS(kXULNS, "menuseparator");
@@ -1137,20 +1146,19 @@ var gApplicationsPane = {
           preferredApp.equals(possibleApp))
         menu.selectedItem = menuItem;
     }
 
     // Create a menu item for the plugin.
     if (handlerInfo.plugin) {
       let menuItem = document.createElementNS(kXULNS, "menuitem");
       menuItem.setAttribute("action", kActionUsePlugin);
-      let brandShortName = this._brandBundle.getString("brandShortName");
       let label = this._prefsBundle.getFormattedString("pluginName",
                                                        [handlerInfo.plugin.name,
-                                                        brandShortName]);
+                                                        this._brandShortName]);
       menuItem.setAttribute("label", label);
       menuPopup.appendChild(menuItem);
       if (handlerInfo.preferredAction == kActionUsePlugin)
         menu.selectedItem = menuItem;
     }
 
     // Create a menu item for saving to disk.
     // Note: this option isn't available to protocol types, since we don't know
--- a/browser/locales/en-US/chrome/browser/places/places.dtd
+++ b/browser/locales/en-US/chrome/browser/places/places.dtd
@@ -173,17 +173,17 @@
 
 <!ENTITY cmd.find.key  "f">
 
 <!ENTITY feed.subscribe.label    "Feed">
 <!ENTITY feed.subscribe.tooltip  "Subscribe">
 
 <!ENTITY view.detailsMacOSX.label  "List">
 <!ENTITY view.details.label        "Details">
-<!ENTITY view.details.accesskey    "">
+<!ENTITY view.details.accesskey    "D">
 
 <!ENTITY view.addons.label   "Get View Add-ons">
 <!ENTITY view.columns.label  "Columns">
 
 <!ENTITY maintenance.label   "Import and Backup">
 
 <!ENTITY backCmd.label       "Back">
 <!ENTITY backCmd.accesskey   "B">
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.properties
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.properties
@@ -45,23 +45,27 @@ chooseDownloadFolderTitle=Choose Downloa
 
 #### Applications
 
 fileEnding=%S file
 saveToDisk=Save to Disk
 chooseApp=Choose application...
 fpTitleChooseApp=Select Helper Application
 webFeed=Web Feed
-alwaysAskAboutFeed=Show me a preview and ask me which Feed Reader to use
-liveBookmarks=Live Bookmarks
+
 # LOCALIZATION NOTE (pluginName):
 # %1$S = plugin name (for example "QuickTime Plugin-in 7.2")
 # %2$S = brandShortName from brand.properties (for example "Minefield")
 pluginName=%S (in %S)
 
+# LOCALIZATION NOTE (previewInApp, liveBookmarksInApp): %S = brandShortName
+previewInApp=Preview in %S
+liveBookmarksInApp=Live Bookmarks in %S
+
+
 #### Cookie Viewer
 
 hostColon=Host:
 domainColon=Domain:
 forSecureOnly=Encrypted connections only
 forAnyConnection=Any type of connection
 AtEndOfSession = at end of session
 can=Allow
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1705,41 +1705,43 @@ nsDocument::ElementFromPoint(PRInt32 aX,
     CallQueryInterface(ptContent, aReturn);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocument::GetElementsByClassName(const nsAString& aClasses,
                                    nsIDOMNodeList** aReturn)
 {
-  return GetElementsByClassNameHelper(mRootContent, aClasses, aReturn);
+  return GetElementsByClassNameHelper(this, aClasses, aReturn);
 }
 
 
 // static GetElementsByClassName helpers
 nsresult
-nsDocument::GetElementsByClassNameHelper(nsIContent* aContent,
+nsDocument::GetElementsByClassNameHelper(nsINode* aRootNode,
                                          const nsAString& aClasses,
                                          nsIDOMNodeList** aReturn)
 {
+  NS_PRECONDITION(aRootNode, "Must have root node");
+  
   nsAttrValue attrValue;
   attrValue.ParseAtomArray(aClasses);
   // nsAttrValue::Equals is sensitive to order, so we'll send an array
   nsCOMArray<nsIAtom>* classes = new nsCOMArray<nsIAtom>;
   NS_ENSURE_TRUE(classes, NS_ERROR_OUT_OF_MEMORY);
 
   if (attrValue.Type() == nsAttrValue::eAtomArray) {
     classes->AppendObjects(*(attrValue.GetAtomArrayValue()));
   } else if (!attrValue.IsEmptyString()) {
     classes->AppendObject(attrValue.GetAtomValue());
   }
   
   nsBaseContentList* elements;
-  if (classes->Count() > 0 && aContent) {
-    elements = new nsContentList(aContent, MatchClassNames,
+  if (classes->Count() > 0) {
+    elements = new nsContentList(aRootNode, MatchClassNames,
                                  DestroyClassNameArray, classes);
   } else {
     elements = new nsBaseContentList();
   }
   if (!elements) {
     delete classes;
     return NS_ERROR_OUT_OF_MEMORY;
   }
@@ -2844,18 +2846,23 @@ nsDocument::DispatchContentLoadedEvents(
       tmp->GetSameTypeParent(getter_AddRefs(docShellParent));
     }
   }
 }
 
 void
 nsDocument::EndLoad()
 {
-  // Drop the ref to our parser, if any
-  mParser = nsnull;
+  // Drop the ref to our parser, if any, but keep hold of the sink so that we
+  // can flush it from FlushPendingNotifications as needed.  We might have to
+  // do that to get a StartLayout() to happen.
+  if (mParser) {
+    mWeakSink = do_GetWeakReference(mParser->GetContentSink());
+    mParser = nsnull;
+  }
   
   NS_DOCUMENT_NOTIFY_OBSERVERS(EndLoad, (this));
 
   DispatchContentLoadedEvents();
   UnblockOnload(PR_TRUE);
 }
 
 void
@@ -4835,23 +4842,26 @@ nsDocument::CreateEventGroup(nsIDOMEvent
   NS_ADDREF(*aInstancePtrResult);
 
   return NS_OK;
 }
 
 void
 nsDocument::FlushPendingNotifications(mozFlushType aType)
 {
+  nsCOMPtr<nsIContentSink> sink;
+  if (mParser) {
+    sink = mParser->GetContentSink();
+  } else {
+    sink = do_QueryReferent(mWeakSink);
+  }
   // Determine if it is safe to flush the sink notifications
   // by determining if it safe to flush all the presshells.
-  if (mParser && (aType == Flush_Content || IsSafeToFlush())) {
-    nsCOMPtr<nsIContentSink> sink = mParser->GetContentSink();
-    if (sink) {
-      sink->FlushPendingNotifications(aType);
-    }
+  if (sink && (aType == Flush_Content || IsSafeToFlush())) {
+    sink->FlushPendingNotifications(aType);
   }
 
   // Should we be flushing pending binding constructors in here?
 
   nsPIDOMWindow *window = GetWindow();
 
   if (aType <= Flush_ContentAndNotify || !window) {
     // Nothing to do here
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -644,19 +644,20 @@ public:
                                                    nsIDOMNodeList** aResult);
   virtual NS_HIDDEN_(nsresult) GetContentListFor(nsIContent* aContent,
                                                  nsIDOMNodeList** aResult);
   virtual NS_HIDDEN_(void) FlushSkinBindings();
 
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDocument, nsIDocument)
 
   /**
-   * Utility method for getElementsByClassName
+   * Utility method for getElementsByClassName.  aRootNode is the node (either
+   * document or element), which getElementsByClassName was called on.
    */
-  static nsresult GetElementsByClassNameHelper(nsIContent* aContent,
+  static nsresult GetElementsByClassNameHelper(nsINode* aRootNode,
                                                const nsAString& aClasses,
                                                nsIDOMNodeList** aReturn);
 protected:
 
   /**
    * Check that aId is not empty and log a message to the console
    * service if it is.
    * @returns PR_TRUE if aId looks correct, PR_FALSE otherwise.
@@ -722,16 +723,21 @@ protected:
 
   // Array of owning references to all children
   nsAttrAndChildArray mChildren;
 
   // Pointer to our parser if we're currently in the process of being
   // parsed into.
   nsCOMPtr<nsIParser> mParser;
 
+  // Weak reference to our sink for in case we no longer have a parser.  This
+  // will allow us to flush out any pending stuff from the sink even if
+  // EndLoad() has already happened.
+  nsWeakPtr mWeakSink;
+
   nsCOMArray<nsIStyleSheet> mStyleSheets;
   nsCOMArray<nsIStyleSheet> mCatalogSheets;
 
   // Array of observers
   nsTObserverArray<nsIDocumentObserver> mObservers;
 
   // The document's script global object, the object from which the
   // document can get its script context and scope. This is the
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -78,16 +78,17 @@
 #include "nsIScriptSecurityManager.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsMutationEvent.h"
 #include "nsNodeUtils.h"
 #include "nsDocument.h"
 #ifdef MOZ_XUL
 #include "nsXULElement.h"
 #endif /* MOZ_XUL */
+#include "nsFrameManager.h"
 
 #include "nsBindingManager.h"
 #include "nsXBLBinding.h"
 #include "nsIDOMCSSStyleDeclaration.h"
 #include "nsIDOMViewCSS.h"
 #include "nsIXBLService.h"
 #include "nsPIDOMWindow.h"
 #include "nsIBoxObject.h"
@@ -689,29 +690,24 @@ nsNSElementTearoff::GetElementsByClassNa
                                            nsIDOMNodeList** aReturn)
 {
   return nsDocument::GetElementsByClassNameHelper(mContent, aClasses, aReturn);
 }
 
 static nsPoint
 GetOffsetFromInitialContainingBlock(nsIFrame* aFrame)
 {
-  nsPresContext* presContext = aFrame->PresContext();
-  nsIPresShell* shell = presContext->PresShell();
-  nsIFrame* rootScrollFrame = shell->GetRootScrollFrame();
+  nsIFrame* rootFrame = aFrame->PresContext()->FrameManager()->GetRootFrame();
   nsPoint pt(0,0);
-  nsIFrame* child = aFrame;
-  for (nsIFrame* p = aFrame->GetParent(); p && p != rootScrollFrame;
-       p = p->GetParent()) {
-    pt += p->GetPositionOfChildIgnoringScrolling(child);
+  for (nsIFrame* p = aFrame; p != rootFrame; p = p->GetParent()) {
     // coordinates of elements inside a foreignobject are relative to the top-left
     // of the nearest foreignobject
-    if (p->IsFrameOfType(nsIFrame::eSVGForeignObject))
+    if (p->IsFrameOfType(nsIFrame::eSVGForeignObject) && p != aFrame)
       return pt;
-    child = p;
+    pt += p->GetPosition();
   }
   return pt;
 }
 
 static double
 RoundFloat(double aValue)
 {
   return floor(aValue + 0.5);
@@ -2084,17 +2080,18 @@ nsGenericElement::BindToTree(nsIDocument
 
 void
 nsGenericElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
 {
   NS_PRECONDITION(aDeep || (!GetCurrentDoc() && !GetBindingParent()),
                   "Shallow unbind won't clear document and binding parent on "
                   "kids!");
   // Make sure to unbind this node before doing the kids
-  nsIDocument *document = GetCurrentDoc();
+  nsIDocument *document =
+    HasFlag(NODE_FORCE_XBL_BINDINGS) ? GetOwnerDoc() : GetCurrentDoc();
   if (document) {
     // Notify XBL- & nsIAnonymousContentCreator-generated
     // anonymous content that the document is changing.
     document->BindingManager()->ChangeDocumentFor(this, document, nsnull);
 
     if (HasAttr(kNameSpaceID_XLink, nsGkAtoms::href)) {
       document->ForgetLink(this);
     }
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -82,17 +82,19 @@ include $(topsrcdir)/config/rules.mk
 		test_bug371576-3.html \
 		test_bug371576-4.html \
 		test_bug371576-5.html \
 		test_bug372086.html \
 		test_bug373181.xhtml \
 		test_bug375314.html \
 		test_bug382113.html \
 		test_bug390735.html \
+		test_bug392318.html \
 		test_bug392511.html \
+		test_bug395915.html \
 		bug382113_object.html \
 		test_CrossSiteXHR.html \
 		file_CrossSiteXHR_fail1.xml \
 		file_CrossSiteXHR_fail2.xml \
 		file_CrossSiteXHR_fail2.xml^headers^ \
 		file_CrossSiteXHR_fail3.xml \
 		file_CrossSiteXHR_fail4.xml \
 		file_CrossSiteXHR_pass1.xml \
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug392318.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=392318
+-->
+<head>
+  <title>Test for Bug 392318</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+  <script class="testbody" type="text/javascript">
+  /** Test for Bug 392318 **/
+  
+  SimpleTest.waitForExplicitFinish();
+  var testRan = false;
+  
+  function runTest() {
+    isnot($("t").offsetWidth, 0, "Unexpected offsetWidth");
+    testRan = true;
+  }
+  
+  document.addEventListener("DOMContentLoaded", runTest, false);
+  
+  addLoadEvent(function() {
+    is(testRan, true, "Onload firing too early");
+  });
+  
+  addLoadEvent(SimpleTest.finish);
+  </script>
+  <!-- IMPORTANT: This sheet must come after the test that sets up the
+       DOMContentLoaded handler and before the <body> -->
+  <link rel="stylesheet" type="text/css" href="data:text/css;%20charset=utf-8,%23t%20%7B%0Awidth%3A%20200px%3B%0Aborder%3A%201px%20solid%20black%3B%0Aheight%3A%20100px%3B%0A%7D">
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=392318">Mozilla Bug 392318</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<div id="t"></div>
+</pre>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug395915.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html class="A b">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=395915
+-->
+<head>
+  <title>Test for Bug 395915</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <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=395915">Mozilla Bug 395915</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 395915 **/
+is(document.getElementsByClassName("a").length, 0,
+   "Class names are case-sensitive");
+is(document.getElementsByClassName("A").length, 1,
+   "Have one node of class A");
+is(document.getElementsByClassName("A")[0], document.documentElement,
+   "Root is class A");
+
+is(document.getElementsByClassName("a b").length, 0,
+   "Class names are case-sensitive two");
+is(document.getElementsByClassName("A B").length, 0,
+   "Class names are case-sensitive three");
+is(document.getElementsByClassName("a B").length, 0,
+   "Class names are case-sensitive four");
+is(document.getElementsByClassName("A b").length, 1,
+   "Have one node of class 'A b'");
+is(document.getElementsByClassName("A b")[0], document.documentElement,
+   "Root is class 'A b'");
+
+</script>
+</pre>
+</body>
+</html>
+
--- a/content/html/content/test/test_bug389797.html
+++ b/content/html/content/test/test_bug389797.html
@@ -248,23 +248,19 @@ for each (var tag in allTags) {
     is(node instanceof Components.interfaces[iface], true,
        tagName(tag) + " does not QI to " + iface);
   }
 
   // Now see what classinfo reports
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   var nodeClassInfo = node.QueryInterface(Components.interfaces.nsIClassInfo);
   var count = {};
-  var classInfoInterfaces = nodeClassInfo.getInterfaces(count);
-
-  // Stringify them
-  for (var idx = 0; idx < classInfoInterfaces.length; ++idx) {
-    classInfoInterfaces[idx] =
-      Components.interfacesByID[classInfoInterfaces[idx]].toString();
-  }
+  var classInfoInterfaces =
+    nodeClassInfo.getInterfaces(count).
+    map(function(id) { return Components.interfacesByID[id].toString(); });
 
   // Make sure that we know about all the things classinfo claims
   for each (var classInfoInterface in classInfoInterfaces) {
     isnot(interfaces[tag].indexOf(classInfoInterface), -1,
           "Should know about " + tagName(tag) + " implementing " +
           classInfoInterface);
   }
 
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -3619,19 +3619,21 @@ NS_IMETHODIMP
 nsDocShell::SetPositionAndSize(PRInt32 x, PRInt32 y, PRInt32 cx,
                                PRInt32 cy, PRBool fRepaint)
 {
     mBounds.x = x;
     mBounds.y = y;
     mBounds.width = cx;
     mBounds.height = cy;
 
-    if (mContentViewer) {
+    // Hold strong ref, since SetBounds can make us null out mContentViewer
+    nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
+    if (viewer) {
         //XXX Border figured in here or is that handled elsewhere?
-        NS_ENSURE_SUCCESS(mContentViewer->SetBounds(mBounds), NS_ERROR_FAILURE);
+        NS_ENSURE_SUCCESS(viewer->SetBounds(mBounds), NS_ERROR_FAILURE);
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetPositionAndSize(PRInt32 * x, PRInt32 * y, PRInt32 * cx,
                                PRInt32 * cy)
--- a/docshell/build/nsDocShellModule.cpp
+++ b/docshell/build/nsDocShellModule.cpp
@@ -75,22 +75,26 @@ Initialize(nsIModule* aSelf)
 {
   NS_PRECONDITION(!gInitialized, "docshell module already initialized");
   if (gInitialized) {
     return NS_OK;
   }
   gInitialized = PR_TRUE;
 
   nsresult rv = nsSHistory::Startup();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = nsSHEntry::Startup();
   return rv;
 }
 
 PR_STATIC_CALLBACK(void)
 Shutdown(nsIModule* aSelf)
 {
+  nsSHEntry::Shutdown();
   gInitialized = PR_FALSE;
 }
 
 // docshell
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsWebShell, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDefaultURIFixup)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsWebNavigationInfo, Init)
 
--- a/docshell/shistory/public/nsISHistoryInternal.idl
+++ b/docshell/shistory/public/nsISHistoryInternal.idl
@@ -41,22 +41,23 @@
 #include "nsISHEntry.idl"
 #include "nsISHTransaction.idl"
 
 interface nsISHistoryListener;
 interface nsIDocShell;
 
 %{C++
 #define NS_SHISTORY_INTERNAL_CID \
-{0x5b4cba4c, 0xbf67, 0x499a, {0xae, 0x2c, 0x3f, 0x76, 0x65, 0x6f, 0x4a, 0x4e}}
+{ 0x9c47c121, 0x1c6e, 0x4d8f, \
+  { 0xb9, 0x04, 0x3a, 0xc9, 0x68, 0x11, 0x6e, 0x88 } }
 
 #define NS_SHISTORY_INTERNAL_CONTRACTID "@mozilla.org/browser/shistory-internal;1"
 %}
 
-[scriptable, uuid(df8788d6-c0ed-4517-b47e-c719afc94284)]
+[scriptable, uuid(9c47c121-1c6e-4d8f-b904-3ac968116e88)]
 interface nsISHistoryInternal: nsISupports
 {
   /**
    * Add a new Entry to the History List
    * @param aEntry - The entry to add
    * @param aPersist - If true this specifies that the entry should persist
    * in the list.  If false, this means that when new entries are added
    * this element will not appear in the session history list.
@@ -93,9 +94,15 @@ interface nsISHistoryInternal: nsISuppor
   /**
    * Evict content viewers until the number of content viewers per tab
    * is no more than gHistoryMaxViewers.  Also, count
    * total number of content viewers globally and evict one if we are over
    * our total max.  This is always called in Show(), after we destroy
    * the previous viewer.
    */
    void evictContentViewers(in long previousIndex, in long index);
+   
+   /**
+    * Evict the content viewer associated with a session history entry
+    * that has timed out.
+    */
+   void evictExpiredContentViewerForEntry(in nsISHEntry aEntry);
 };
--- a/docshell/shistory/src/nsSHEntry.cpp
+++ b/docshell/shistory/src/nsSHEntry.cpp
@@ -46,24 +46,63 @@
 #include "nsXPIDLString.h"
 #include "nsReadableUtils.h"
 #include "nsIDocShellLoadInfo.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsAutoPtr.h"
 #include "nsThreadUtils.h"
+#include "nsIWebNavigation.h"
+#include "nsISHistory.h"
+#include "nsISHistoryInternal.h"
 
+// Hardcode this to time out unused content viewers after 30 minutes
+#define CONTENT_VIEWER_TIMEOUT_SECONDS 30*60
+
+typedef nsExpirationTracker<nsSHEntry,3> HistoryTrackerBase;
+class HistoryTracker : public HistoryTrackerBase {
+public:
+  // Expire cached contentviewers after 20-30 minutes in the cache.
+  HistoryTracker() : HistoryTrackerBase((CONTENT_VIEWER_TIMEOUT_SECONDS/2)*1000) {}
+  
+protected:
+  virtual void NotifyExpired(nsSHEntry* aObj) {
+    RemoveObject(aObj);
+    aObj->Expire();
+  }
+};
 
+static HistoryTracker *gHistoryTracker = nsnull;
 static PRUint32 gEntryID = 0;
 
+nsresult nsSHEntry::Startup()
+{
+  gHistoryTracker = new HistoryTracker();
+  return gHistoryTracker ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+}
+
+void nsSHEntry::Shutdown()
+{
+  delete gHistoryTracker;
+  gHistoryTracker = nsnull;
+}
+
+static void StopTrackingEntry(nsSHEntry *aEntry)
+{
+  if (aEntry->GetExpirationState()->IsTracked()) {
+    gHistoryTracker->RemoveObject(aEntry);
+  }
+}
+
 //*****************************************************************************
 //***    nsSHEntry: Object Management
 //*****************************************************************************
 
+
 nsSHEntry::nsSHEntry() 
   : mLoadType(0)
   , mID(gEntryID++)
   , mPageIdentifier(mID)
   , mScrollPositionX(0)
   , mScrollPositionY(0)
   , mIsFrameNavigation(PR_FALSE)
   , mSaveLayoutState(PR_TRUE)
@@ -104,16 +143,18 @@ ClearParentPtr(nsISHEntry* aEntry, void*
   if (aEntry) {
     aEntry->SetParent(nsnull);
   }
   return PR_TRUE;
 }
 
 nsSHEntry::~nsSHEntry()
 {
+  StopTrackingEntry(this);
+
   // Since we never really remove kids from SHEntrys, we need to null
   // out the mParent pointers on all our kids.
   mChildren.EnumerateForwards(ClearParentPtr, nsnull);
   mChildren.Clear();
 
   nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
   DropPresentationState();
   if (viewer) {
@@ -188,16 +229,18 @@ nsSHEntry::SetContentViewer(nsIContentVi
     mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
     // Store observed document in strong pointer in case it is removed from
     // the contentviewer
     mDocument = do_QueryInterface(domDoc);
     if (mDocument) {
       mDocument->SetShellsHidden(PR_TRUE);
       mDocument->AddMutationObserver(this);
     }
+    
+    gHistoryTracker->AddObject(this);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSHEntry::GetContentViewer(nsIContentViewer **aResult)
 {
@@ -632,24 +675,50 @@ nsSHEntry::DropPresentationState()
   if (mDocument) {
     mDocument->SetShellsHidden(PR_FALSE);
     mDocument->RemoveMutationObserver(this);
     mDocument = nsnull;
   }
   if (mContentViewer)
     mContentViewer->ClearHistoryEntry();
 
+  StopTrackingEntry(this);
   mContentViewer = nsnull;
   mSticky = PR_TRUE;
   mWindowState = nsnull;
   mViewerBounds.SetRect(0, 0, 0, 0);
   mChildShells.Clear();
   mRefreshURIList = nsnull;
 }
 
+void
+nsSHEntry::Expire()
+{
+  // This entry has timed out. If we still have a content viewer, we need to
+  // get it evicted.
+  if (!mContentViewer)
+    return;
+  nsCOMPtr<nsISupports> container;
+  mContentViewer->GetContainer(getter_AddRefs(container));
+  nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(container);
+  if (!treeItem)
+    return;
+  // We need to find the root DocShell since only that object has an
+  // SHistory and we need the SHistory to evict content viewers
+  nsCOMPtr<nsIDocShellTreeItem> root;
+  treeItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
+  nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(root);
+  nsCOMPtr<nsISHistory> history;
+  webNav->GetSessionHistory(getter_AddRefs(history));
+  nsCOMPtr<nsISHistoryInternal> historyInt = do_QueryInterface(history);
+  if (!historyInt)
+    return;
+  historyInt->EvictExpiredContentViewerForEntry(this);
+}
+
 //*****************************************************************************
 //    nsSHEntry: nsIMutationObserver
 //*****************************************************************************
 
 void
 nsSHEntry::NodeWillBeDestroyed(const nsINode* aNode)
 {
   NS_NOTREACHED("Document destroyed while we're holding a strong ref to it");
--- a/docshell/shistory/src/nsSHEntry.h
+++ b/docshell/shistory/src/nsSHEntry.h
@@ -53,16 +53,17 @@
 #include "nsISHEntry.h"
 #include "nsISHContainer.h"
 #include "nsIURI.h"
 #include "nsIEnumerator.h"
 #include "nsIHistoryEntry.h"
 #include "nsRect.h"
 #include "nsSupportsArray.h"
 #include "nsIMutationObserver.h"
+#include "nsExpirationTracker.h"
 
 class nsSHEntry : public nsISHEntry,
                   public nsISHContainer,
                   public nsIMutationObserver
 {
 public: 
   nsSHEntry();
   nsSHEntry(const nsSHEntry &other);
@@ -70,16 +71,23 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIHISTORYENTRY
   NS_DECL_NSISHENTRY
   NS_DECL_NSISHCONTAINER
   NS_DECL_NSIMUTATIONOBSERVER
 
   void DropPresentationState();
 
+  void Expire();
+  
+  nsExpirationState *GetExpirationState() { return &mExpirationState; }
+  
+  static nsresult Startup();
+  static void Shutdown();
+  
 private:
   ~nsSHEntry();
   void DocumentMutated();
 
   nsCOMPtr<nsIURI>                mURI;
   nsCOMPtr<nsIURI>                mReferrerURI;
   nsCOMPtr<nsIContentViewer>      mContentViewer;
   nsCOMPtr<nsIDocument>           mDocument; // document currently being observed
@@ -99,11 +107,12 @@ private:
   nsCString                       mContentType;
   nsCOMPtr<nsISupports>           mCacheKey;
   nsISHEntry *                    mParent;  // weak reference
   nsCOMPtr<nsISupports>           mWindowState;
   nsRect                          mViewerBounds;
   nsCOMArray<nsIDocShellTreeItem> mChildShells;
   nsCOMPtr<nsISupportsArray>      mRefreshURIList;
   nsCOMPtr<nsISupports>           mOwner;
+  nsExpirationState               mExpirationState;
 };
 
 #endif /* nsSHEntry_h */
--- a/docshell/shistory/src/nsSHistory.cpp
+++ b/docshell/shistory/src/nsSHistory.cpp
@@ -784,21 +784,27 @@ nsSHistory::EvictWindowContentViewers(PR
     startIndex = PR_MAX(0, aFromIndex - gHistoryMaxViewers);
   } else { // going backward
     startIndex = aToIndex + gHistoryMaxViewers + 1;
     if (startIndex >= mLength) {
       return;
     }
     endIndex = PR_MIN(mLength, aFromIndex + gHistoryMaxViewers);
   }
+  
+  EvictContentViewersInRange(startIndex, endIndex);
+}
 
+void
+nsSHistory::EvictContentViewersInRange(PRInt32 aStart, PRInt32 aEnd)
+{
   nsCOMPtr<nsISHTransaction> trans;
-  GetTransactionAtIndex(startIndex, getter_AddRefs(trans));
+  GetTransactionAtIndex(aStart, getter_AddRefs(trans));
 
-  for (PRInt32 i = startIndex; i < endIndex; ++i) {
+  for (PRInt32 i = aStart; i < aEnd; ++i) {
     nsCOMPtr<nsISHEntry> entry;
     trans->GetSHEntry(getter_AddRefs(entry));
     nsCOMPtr<nsIContentViewer> viewer;
     nsCOMPtr<nsISHEntry> ownerEntry;
     entry->GetAnyContentViewer(getter_AddRefs(ownerEntry),
                                getter_AddRefs(viewer));
     if (viewer) {
       NS_ASSERTION(ownerEntry,
@@ -936,16 +942,56 @@ nsSHistory::EvictGlobalContentViewer()
       }
     } else {
       // couldn't find a content viewer to evict, so we are done
       shouldTryEviction = PR_FALSE;
     }
   }  // while shouldTryEviction
 }
 
+NS_IMETHODIMP
+nsSHistory::EvictExpiredContentViewerForEntry(nsISHEntry *aEntry)
+{
+  PRInt32 startIndex = PR_MAX(0, mIndex - gHistoryMaxViewers);
+  PRInt32 endIndex = PR_MIN(mLength - 1,
+                            mIndex + gHistoryMaxViewers);
+  nsCOMPtr<nsISHTransaction> trans;
+  GetTransactionAtIndex(startIndex, getter_AddRefs(trans));
+
+  PRInt32 i;
+  for (i = startIndex; i <= endIndex; ++i) {
+    nsCOMPtr<nsISHEntry> entry;
+    trans->GetSHEntry(getter_AddRefs(entry));
+    if (entry == aEntry)
+      break;
+
+    nsISHTransaction *temp = trans;
+    temp->GetNext(getter_AddRefs(trans));
+  }
+  if (i > endIndex)
+    return NS_OK;
+  
+  NS_ASSERTION(i != mIndex, "How did the current session entry expire?");
+  if (i == mIndex)
+    return NS_OK;
+  
+  // We evict content viewers for the expired entry and any other entries that
+  // we would have to go through the expired entry to get to (i.e. the entries
+  // that have the expired entry between them and the current entry). Those
+  // other entries should have timed out already, actually, but this is just
+  // to be on the safe side.
+  if (i < mIndex) {
+    EvictContentViewersInRange(startIndex, i + 1);
+  } else {
+    EvictContentViewersInRange(i, endIndex + 1);
+  }
+  
+  return NS_OK;
+}
+
 // Evicts all content viewers in all history objects.  This is very
 // inefficient, because it requires a linear search through all SHistory
 // objects for each viewer to be evicted.  However, this method is called
 // infrequently -- only when the disk or memory cache is cleared.
 
 //static
 void
 nsSHistory::EvictAllContentViewers()
--- a/docshell/shistory/src/nsSHistory.h
+++ b/docshell/shistory/src/nsSHistory.h
@@ -94,16 +94,17 @@ protected:
    nsresult InitiateLoad(nsISHEntry * aFrameEntry, nsIDocShell * aFrameDS, long aLoadType);
 
    NS_IMETHOD LoadEntry(PRInt32 aIndex, long aLoadType, PRUint32 histCmd);
 	
 #ifdef DEBUG
    nsresult PrintHistory();
 #endif
 
+  void EvictContentViewersInRange(PRInt32 aStartIndex, PRInt32 aEndIndex);
   void EvictWindowContentViewers(PRInt32 aFromIndex, PRInt32 aToIndex);
   static void EvictGlobalContentViewer();
   static void EvictAllContentViewers();
 
   // Calculates a max number of total
   // content viewers to cache, based on amount of total memory
   static PRUint32 CalcMaxTotalViewers();
 
--- a/dom/tests/mochitest/bugs/Makefile.in
+++ b/dom/tests/mochitest/bugs/Makefile.in
@@ -43,16 +43,17 @@ relativesrcdir	= dom/tests/mochitest/bug
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES	= \
 		test_bug159849.html \
 		test_bug291377.html \
 		test_bug308856.html \
+		test_bug317448.html \
 		test_bug333983.html \
 		test_bug342448.html \
 		test_bug345521.html \
 		test_bug351601.html \
 		test_bug370098.html \
 		test_bug377539.html \
 		test_bug384122.html \
 		test_bug393974.html \
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/bugs/test_bug317448.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=317448
+-->
+<head>
+  <title>Test for Bug 317448</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <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=317448">Mozilla Bug 317448</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 317448 **/
+var x = new XMLHttpRequest();
+x.open("GET", document.location.href);
+x.send("");
+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+is(x.channel.notificationCallbacks instanceof
+     Components.interfaces.nsIInterfaceRequestor,
+   true, "Must be interface requestor");
+
+var count = {};
+var interfaces = x.channel.notificationCallbacks.
+                 QueryInterface(Components.interfaces.nsIClassInfo).
+                 getInterfaces(count).
+                 map(function(id) {
+                            return Components.interfacesByID[id].toString();
+                     });
+isnot(interfaces.indexOf("nsIInterfaceRequestor"), "-1",
+      "Must have interface requestor classinfo");
+</script>
+</pre>
+</body>
+</html>
+
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -631,33 +631,44 @@ static const char kTypeSign = '%';
 static const char kMatchTypeHost[] = "host";
 
 nsresult
 nsPermissionManager::Read()
 {
   nsresult rv;
   
   PRBool readingOldFile = PR_FALSE;
+  nsCOMPtr<nsIInputStream> fileInputStream;
 
-  nsCOMPtr<nsIInputStream> fileInputStream;
-  rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream), mPermissionsFile);
-  if (rv == NS_ERROR_FILE_NOT_FOUND) {
+  PRBool fileExists = PR_FALSE;
+  rv = mPermissionsFile->Exists(&fileExists);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (fileExists) {
+    rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream),
+                                    mPermissionsFile);
+  } else {
     // Try finding the old-style file
 
     nsCOMPtr<nsIFile> oldPermissionsFile;
-    rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(oldPermissionsFile));
+    rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
+                                getter_AddRefs(oldPermissionsFile));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = oldPermissionsFile->AppendNative(NS_LITERAL_CSTRING(kOldPermissionsFileName));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream), oldPermissionsFile);
-
-    readingOldFile = PR_TRUE;
-
+    rv = oldPermissionsFile->Exists(&fileExists);
+    if (NS_SUCCEEDED(rv) && fileExists) {
+      rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream),
+                                      oldPermissionsFile);
+      readingOldFile = PR_TRUE;
+    } else {
+      rv = NS_ERROR_FILE_NOT_FOUND;
+    }
     /* old format is:
      * host \t number permission \t number permission ... \n
      * if this format isn't respected we move onto the next line in the file.
      * permission is T or F for accept or deny, otherwise a lowercase letter,
      * with a=0, b=1 etc
      */
   }
   // An error path is expected when cookperm.txt is not found either, or when
--- a/extensions/spellcheck/src/mozInlineSpellChecker.cpp
+++ b/extensions/spellcheck/src/mozInlineSpellChecker.cpp
@@ -68,17 +68,16 @@
 #include "mozInlineSpellWordUtil.h"
 #include "mozISpellI18NManager.h"
 #include "nsCOMPtr.h"
 #include "nsCRT.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentRange.h"
 #include "nsIDOMElement.h"
-#include "nsPIDOMWindow.h"
 #include "nsIDOMEventTarget.h"
 #include "nsPIDOMEventTarget.h"
 #include "nsIDOMMouseEvent.h"
 #include "nsIDOMKeyEvent.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMNodeList.h"
 #include "nsIDOMNSRange.h"
 #include "nsIDOMRange.h"
@@ -500,17 +499,16 @@ public:
     return NS_OK;
   }
 };
 
 
 NS_INTERFACE_MAP_BEGIN(mozInlineSpellChecker)
 NS_INTERFACE_MAP_ENTRY(nsIInlineSpellChecker)
 NS_INTERFACE_MAP_ENTRY(nsIEditActionListener)
-NS_INTERFACE_MAP_ENTRY(nsIDOMFocusListener)
 NS_INTERFACE_MAP_ENTRY(nsIDOMMouseListener)
 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMKeyListener)
 NS_INTERFACE_MAP_ENTRY(nsIDOMKeyListener)
 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener, nsIDOMKeyListener)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(mozInlineSpellChecker)
@@ -621,34 +619,21 @@ mozInlineSpellChecker::RegisterEventList
 {
   nsCOMPtr<nsIEditor> editor (do_QueryReferent(mEditor));
   NS_ENSURE_TRUE(editor, NS_ERROR_NULL_POINTER);
 
   editor->AddEditActionListener(this);
 
   nsCOMPtr<nsIDOMDocument> doc;
   nsresult rv = editor->GetDocument(getter_AddRefs(doc));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIDocument> doc2 = do_QueryInterface(doc);
-  NS_ENSURE_TRUE(doc2, nsnull);
-  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(doc2->GetWindow());
-  nsPIDOMEventTarget* chromeEventHandler = nsnull;
-  if (win)
-    chromeEventHandler = win->GetChromeEventHandler();
-
-  nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(chromeEventHandler, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ENSURE_SUCCESS(rv, rv); 
 
   nsCOMPtr<nsPIDOMEventTarget> piTarget = do_QueryInterface(doc, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ENSURE_SUCCESS(rv, rv); 
 
-  target->AddEventListener(NS_LITERAL_STRING("blur"),
-                           static_cast<nsIDOMFocusListener *>(this),
-                           PR_TRUE);
   piTarget->AddEventListenerByIID(static_cast<nsIDOMMouseListener*>(this),
                                   NS_GET_IID(nsIDOMMouseListener));
   piTarget->AddEventListenerByIID(static_cast<nsIDOMKeyListener*>(this),
                                   NS_GET_IID(nsIDOMKeyListener));
 
   return NS_OK;
 }
 
@@ -664,30 +649,16 @@ mozInlineSpellChecker::UnregisterEventLi
 
   nsCOMPtr<nsIDOMDocument> doc;
   editor->GetDocument(getter_AddRefs(doc));
   NS_ENSURE_TRUE(doc, NS_ERROR_NULL_POINTER);
   
   nsCOMPtr<nsPIDOMEventTarget> piTarget = do_QueryInterface(doc);
   NS_ENSURE_TRUE(piTarget, NS_ERROR_NULL_POINTER);
 
-  nsCOMPtr<nsIDocument> doc2 = do_QueryInterface(doc);
-  NS_ENSURE_TRUE(doc2, nsnull);
-  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(doc2->GetWindow());
-  nsPIDOMEventTarget* chromeEventHandler = nsnull;
-  if (win)
-    chromeEventHandler = win->GetChromeEventHandler();
-
-  nsresult rv;
-  nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(chromeEventHandler, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  target->RemoveEventListener(NS_LITERAL_STRING("blur"),
-                              static_cast<nsIDOMFocusListener *>(this),
-                              PR_TRUE);
   piTarget->RemoveEventListenerByIID(static_cast<nsIDOMMouseListener*>(this),
                                      NS_GET_IID(nsIDOMMouseListener));
   piTarget->RemoveEventListenerByIID(static_cast<nsIDOMKeyListener*>(this),
                                      NS_GET_IID(nsIDOMKeyListener));
   
   return NS_OK;
 }
 
@@ -1675,28 +1646,16 @@ mozInlineSpellChecker::HandleNavigationE
   return NS_OK;
 }
 
 NS_IMETHODIMP mozInlineSpellChecker::HandleEvent(nsIDOMEvent* aEvent)
 {
   return NS_OK;
 }
 
-NS_IMETHODIMP mozInlineSpellChecker::Focus(nsIDOMEvent* aEvent)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP mozInlineSpellChecker::Blur(nsIDOMEvent* aEvent)
-{
-  // force spellcheck on blur, for instance when tabbing out of a textbox
-  HandleNavigationEvent(aEvent, PR_TRUE);
-  return NS_OK;
-}
-
 NS_IMETHODIMP mozInlineSpellChecker::MouseClick(nsIDOMEvent *aMouseEvent)
 {
   nsCOMPtr<nsIDOMMouseEvent>mouseEvent = do_QueryInterface(aMouseEvent);
   NS_ENSURE_TRUE(mouseEvent, NS_OK);
 
   // ignore any errors from HandleNavigationEvent as we don't want to prevent 
   // anyone else from seeing this event.
   PRUint16 button;
--- a/extensions/spellcheck/src/mozInlineSpellChecker.h
+++ b/extensions/spellcheck/src/mozInlineSpellChecker.h
@@ -43,17 +43,16 @@
 #include "nsIDOMRange.h"
 #include "nsIEditorSpellCheck.h"
 #include "nsIEditActionListener.h"
 #include "nsIInlineSpellChecker.h"
 #include "nsITextServicesDocument.h"
 #include "nsIDOMTreeWalker.h"
 #include "nsWeakReference.h"
 #include "nsIEditor.h"
-#include "nsIDOMFocusListener.h"
 #include "nsIDOMMouseListener.h"
 #include "nsIDOMKeyListener.h"
 #include "nsWeakReference.h"
 #include "mozISpellI18NUtil.h"
 
 class nsIDOMDocumentRange;
 class nsIDOMMouseEventListener;
 class mozInlineSpellWordUtil;
@@ -134,17 +133,17 @@ protected:
   nsresult FillNoCheckRangeFromAnchor(mozInlineSpellWordUtil& aWordUtil);
 
   nsresult GetDocumentRange(nsIDOMDocumentRange** aDocRange);
   nsresult PositionToCollapsedRange(nsIDOMDocumentRange* aDocRange,
                                     nsIDOMNode* aNode, PRInt32 aOffset,
                                     nsIDOMRange** aRange);
 };
 
-class mozInlineSpellChecker : public nsIInlineSpellChecker, nsIEditActionListener, nsIDOMFocusListener, nsIDOMMouseListener, nsIDOMKeyListener,
+class mozInlineSpellChecker : public nsIInlineSpellChecker, nsIEditActionListener, nsIDOMMouseListener, nsIDOMKeyListener,
                                      nsSupportsWeakReference
 {
 private:
   friend class mozInlineSpellStatus;
 
   // Access with CanEnableInlineSpellChecking
   enum SpellCheckingState { SpellCheck_Uninitialized = -1,
                             SpellCheck_NotAvailable = 0,
@@ -220,21 +219,16 @@ public:
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIEDITACTIONLISTENER
   NS_DECL_NSIINLINESPELLCHECKER
 
   // returns true if it looks likely that we can enable real-time spell checking
   static PRBool CanEnableInlineSpellChecking();
 
-  /*BEGIN implementations of focus event handler interface*/
-  NS_IMETHOD Focus(nsIDOMEvent* aEvent);
-  NS_IMETHOD Blur(nsIDOMEvent* aEvent);
-  /*END implementations of focus event handler interface*/
-
   /*BEGIN implementations of mouseevent handler interface*/
   NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
   NS_IMETHOD MouseDown(nsIDOMEvent* aMouseEvent);
   NS_IMETHOD MouseUp(nsIDOMEvent* aMouseEvent);
   NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent);
   NS_IMETHOD MouseDblClick(nsIDOMEvent* aMouseEvent);
   NS_IMETHOD MouseOver(nsIDOMEvent* aMouseEvent);
   NS_IMETHOD MouseOut(nsIDOMEvent* aMouseEvent);
--- a/gfx/cairo/README
+++ b/gfx/cairo/README
@@ -2,49 +2,26 @@ Snapshots of cairo and glitz for mozilla
 
 We only include the relevant parts of each release (generally, src/*.[ch]),
 as we have Makefile.in's that integrate into the Mozilla build system.  For
 documentation and similar, please see the official tarballs at
 http://www.cairographics.org/.
 
 VERSIONS:
 
-  cairo (1.5.x - c0a7d33ac6c81dd74ee2a9daaa3749a346ef4897)
-  pixman (0.9.3 - 0c80a0cd84f30616563cef5910df9deb4f8ed687)
+  cairo (1.5.x - d8b0de01d67cdf73d8266a73f54ba1ac42fee3c9)
+  pixman (0.9.x - 3be35594c99b7abd2af43b66349ca53bfa1462d6)
   glitz 0.5.2 (cvs - 2006-01-10)
 
 ***** NOTE FOR VISUAL C++ 6.0 *****
 
 VC6 is not supported.  Please upgrade to VC8.
 
 ==== Patches ====
 
-All patches in the cairo tree are surrounded by "MOZILLA_CAIRO_NOT_DEFINED"
-(which should obviously not be defined).
-
 Some specific things:
 
 max-font-size.patch: Clamp freetype font size to 1000 to avoid overflow issues
 
-win32-scaled-font-size.patch: Add cairo_win32_font_face_create_for_logfontw_hfont,
-allow win32 scaled_fonts to rescale themselves properly to the required CTM
-and only use the font_face's hfont if we're sure it's appropriate
-
 win32-logical-font-scale.patch: set CAIRO_WIN32_LOGICAL_FONT_SCALE to 1
 
-win32-no-printer-bitblt.patch: If we need to BitBlt from a DC (to do
-fallback), only bother trying if the IS_DISPLAY flag is set -- many
-printers lie about their support for BitBlt, and we end up getting
-black instead of what we want.
-
 nonfatal-assertions.patch: Make assertions non-fatal
 
-clone-similar-fallback.patch: Implement fallback for clone_similar.
-
-scaled-font-create-deadlock.patch: the "poor man's mutex" that is provided
-for CAIRO_NO_MUTEX will deadlock if a recursive mutex lock occurs.
-It's also just a bunch of useless assignments for applications that makes
-all cairo calls from a single thread.  An example of where a deadlock occurs
-is the cairo_scaled_font_destroy() call from win32_scaled_font_create(),
-which is a bug, but it illustrates the dangers of that "poor man's mutex".
-The patch makes all mutex operations do nothing under CAIRO_NO_MUTEX and
-it fixes the bug in win32_scaled_font_create().
-See  https://bugzilla.mozilla.org/show_bug.cgi?id=378716
--- a/gfx/cairo/cairo/src/Makefile.in
+++ b/gfx/cairo/cairo/src/Makefile.in
@@ -118,17 +118,18 @@ CSRCS   = \
         cairo-wideint.c \
         $(NULL)
 
 EXPORTS = cairo.h cairo-features.h cairo-platform.h cairo-deprecated.h cairo-rename.h
 
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 CSRCS   += cairo-win32-font.c \
-           cairo-win32-surface.c
+           cairo-win32-surface.c \
+	   cairo-win32-printing-surface.c
 EXPORTS += cairo-win32.h
 CSRCS   += cairo-base85-stream.c \
            cairo-pdf-surface.c \
 	   cairo-type1-fallback.c \
 	   cairo-truetype-subset.c \
 	   cairo-cff-subset.c
 EXPORTS += cairo-pdf.h
 endif
--- a/gfx/cairo/cairo/src/cairo-analysis-surface-private.h
+++ b/gfx/cairo/cairo/src/cairo-analysis-surface-private.h
@@ -1,10 +1,9 @@
-/* $Id: cairo-analysis-surface-private.h,v 1.12 2007/08/09 18:54:18 vladimir%pobox.com Exp $
- *
+/*
  * Copyright © 2005 Keith Packard
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
  * License version 2.1 as published by the Free Software Foundation
  * (the "LGPL") or, at your option, under the terms of the Mozilla
  * Public License Version 1.1 (the "MPL"). If you do not alter this
  * notice, a recipient may use your version of this file under either
@@ -45,11 +44,14 @@ cairo_private cairo_surface_t *
 
 cairo_private cairo_region_t *
 _cairo_analysis_surface_get_supported (cairo_surface_t *surface);
 
 cairo_private cairo_region_t *
 _cairo_analysis_surface_get_unsupported (cairo_surface_t *unsupported);
 
 cairo_private cairo_bool_t
+_cairo_analysis_surface_has_supported (cairo_surface_t *unsupported);
+
+cairo_private cairo_bool_t
 _cairo_analysis_surface_has_unsupported (cairo_surface_t *unsupported);
 
 #endif /* CAIRO_ANALYSIS_SURFACE_H */
--- a/gfx/cairo/cairo/src/cairo-analysis-surface.c
+++ b/gfx/cairo/cairo/src/cairo-analysis-surface.c
@@ -1,10 +1,11 @@
 /*
  * Copyright © 2006 Keith Packard
+ * Copyright © 2007 Adrian Johnson
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
  * License version 2.1 as published by the Free Software Foundation
  * (the "LGPL") or, at your option, under the terms of the Mozilla
  * Public License Version 1.1 (the "MPL"). If you do not alter this
  * notice, a recipient may use your version of this file under either
  * the MPL or the LGPL.
@@ -25,193 +26,523 @@
  * the specific language governing rights and limitations.
  *
  * The Original Code is the cairo graphics library.
  *
  * The Initial Developer of the Original Code is Keith Packard
  *
  * Contributor(s):
  *      Keith Packard <keithp@keithp.com>
+ *      Adrian Johnson <ajohnson@redneon.com>
  */
 
 #include "cairoint.h"
 
 #include "cairo-analysis-surface-private.h"
 #include "cairo-paginated-private.h"
+#include "cairo-region-private.h"
+#include "cairo-meta-surface-private.h"
 
 typedef struct {
     cairo_surface_t base;
     int width;
     int height;
 
     cairo_surface_t	*target;
 
-    cairo_bool_t fallback;
+    cairo_bool_t has_supported;
+    cairo_bool_t has_unsupported;
+
+    cairo_region_t supported_region;
+    cairo_region_t fallback_region;
+    cairo_rectangle_int_t current_clip;
+
 } cairo_analysis_surface_t;
 
 static cairo_int_status_t
+_cairo_analysis_surface_analyze_meta_surface_pattern (cairo_analysis_surface_t *surface,
+						      cairo_pattern_t	       *pattern)
+{
+    cairo_surface_pattern_t *surface_pattern;
+    cairo_surface_t *meta_surface;
+    cairo_surface_t *analysis;
+    cairo_status_t status;
+
+    assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
+    surface_pattern = (cairo_surface_pattern_t *) pattern;
+    assert (_cairo_surface_is_meta (surface_pattern->surface));
+
+    meta_surface = surface_pattern->surface;
+    analysis = _cairo_analysis_surface_create (surface->target,
+					       surface->width, surface->height);
+    if (analysis == NULL)
+	return CAIRO_STATUS_NO_MEMORY;
+
+    status = _cairo_meta_surface_replay_analyze_meta_pattern (meta_surface, analysis);
+    if (status == CAIRO_STATUS_SUCCESS)
+	    status = analysis->status;
+    cairo_surface_destroy (analysis);
+
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_analysis_surface_add_operation  (cairo_analysis_surface_t *surface,
+					cairo_rectangle_int_t    *rect,
+					cairo_int_status_t        backend_status)
+{
+    cairo_int_status_t status;
+
+    if (rect->width == 0 || rect->height == 0)
+	return CAIRO_STATUS_SUCCESS;
+
+    /* If the operation is completely enclosed within the fallback
+     * region there is no benefit in emitting a native operation as
+     * the fallback image will be painted on top.
+     */
+    if (_cairo_region_contains_rectangle (&surface->fallback_region, rect) == PIXMAN_REGION_IN)
+	return CAIRO_INT_STATUS_IMAGE_FALLBACK;
+
+    if (backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) {
+	/* A status of CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY indicates
+	 * that the backend only supports this operation if the
+	 * transparency removed. If the extents of this operation does
+	 * not intersect any other native operation, the operation is
+	 * natively supported and the backend will blend the
+	 * transparency into the white background.
+	 */
+	if (_cairo_region_contains_rectangle (&surface->supported_region, rect) == PIXMAN_REGION_OUT)
+	    backend_status = CAIRO_STATUS_SUCCESS;
+    }
+
+    if (backend_status == CAIRO_STATUS_SUCCESS) {
+	/* Add the operation to the supported region. Operations in
+	 * this region will be emitted as native operations.
+	 */
+	surface->has_supported = TRUE;
+	status = _cairo_region_union_rect (&surface->supported_region,
+					   &surface->supported_region,
+					   rect);
+	return status;
+    }
+
+    /* Add the operation to the unsupported region. This region will
+     * be painted as an image after all native operations have been
+     * emitted.
+     */
+    surface->has_unsupported = TRUE;
+    status = _cairo_region_union_rect (&surface->fallback_region,
+				       &surface->fallback_region,
+				       rect);
+
+    /* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate
+     * unsupported operations to the meta surface as using
+     * CAIRO_INT_STATUS_UNSUPPORTED would cause cairo-surface to
+     * invoke the cairo-surface-fallback path then return
+     * CAIRO_STATUS_SUCCESS.
+     */
+    if (status == CAIRO_STATUS_SUCCESS)
+	return CAIRO_INT_STATUS_IMAGE_FALLBACK;
+    else
+	return status;
+}
+
+static cairo_status_t
+_cairo_analysis_surface_finish (void *abstract_surface)
+{
+    cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
+
+    _cairo_region_fini (&surface->supported_region);
+    _cairo_region_fini (&surface->fallback_region);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_analysis_surface_intersect_clip_path (void		*abstract_surface,
+					     cairo_path_fixed_t *path,
+					     cairo_fill_rule_t   fill_rule,
+					     double		 tolerance,
+					     cairo_antialias_t   antialias)
+{
+    cairo_analysis_surface_t *surface = abstract_surface;
+    double                    x1, y1, x2, y2;
+    cairo_rectangle_int_t   extent;
+    cairo_status_t	      status;
+
+    if (path == NULL) {
+	surface->current_clip.x = 0;
+	surface->current_clip.y = 0;
+	surface->current_clip.width = surface->width;
+	surface->current_clip.height = surface->height;
+	status = CAIRO_STATUS_SUCCESS;
+    } else {
+	status = _cairo_path_fixed_bounds (path, &x1, &y1, &x2, &y2);
+	if (status)
+	    return status;
+
+	extent.x = floor (x1);
+	extent.y = floor (y1);
+	extent.width = ceil (x2) - extent.x;
+	extent.height = ceil (y2) - extent.y;
+
+	_cairo_rectangle_intersect (&surface->current_clip, &extent);
+    }
+
+    return status;
+}
+
+static cairo_int_status_t
 _cairo_analysis_surface_get_extents (void	 		*abstract_surface,
 				     cairo_rectangle_int_t	*rectangle)
 {
     cairo_analysis_surface_t *surface = abstract_surface;
 
     return _cairo_surface_get_extents (surface->target, rectangle);
 }
 
 static cairo_int_status_t
 _cairo_analysis_surface_paint (void			*abstract_surface,
 			      cairo_operator_t		op,
 			      cairo_pattern_t		*source)
 {
     cairo_analysis_surface_t *surface = abstract_surface;
-    cairo_status_t	     status;
+    cairo_status_t	     status, backend_status;
+    cairo_rectangle_int_t  extents;
 
     if (!surface->target->backend->paint)
-	status = CAIRO_INT_STATUS_UNSUPPORTED;
+	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
     else
-	status = (*surface->target->backend->paint) (surface->target, op,
-						     source);
-    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
-	surface->fallback = TRUE;
-	status = CAIRO_STATUS_SUCCESS;
+	backend_status = (*surface->target->backend->paint) (surface->target, op,
+                                                             source);
+
+    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
+	backend_status = _cairo_analysis_surface_analyze_meta_surface_pattern (surface,
+									       source);
+
+    status = _cairo_surface_get_extents (&surface->base, &extents);
+    if (status)
+	return status;
+
+    if (_cairo_operator_bounded_by_source (op)) {
+	cairo_rectangle_int_t source_extents;
+	status = _cairo_pattern_get_extents (source, &source_extents);
+	if (status)
+	    return status;
+
+	_cairo_rectangle_intersect (&extents, &source_extents);
     }
+
+    _cairo_rectangle_intersect (&extents, &surface->current_clip);
+
+    status = _cairo_analysis_surface_add_operation (surface, &extents, backend_status);
+
     return status;
 }
 
 static cairo_int_status_t
 _cairo_analysis_surface_mask (void		*abstract_surface,
 			      cairo_operator_t	 op,
 			      cairo_pattern_t	*source,
 			      cairo_pattern_t	*mask)
 {
     cairo_analysis_surface_t *surface = abstract_surface;
-    cairo_status_t	     status;
+    cairo_status_t	      status, backend_status;
+    cairo_rectangle_int_t   extents;
 
     if (!surface->target->backend->mask)
-	status = CAIRO_INT_STATUS_UNSUPPORTED;
+	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
     else
-	status = (*surface->target->backend->mask) (surface->target, op,
-						    source, mask);
-    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
-	surface->fallback = TRUE;
-	status = CAIRO_STATUS_SUCCESS;
+	backend_status = (*surface->target->backend->mask) (surface->target, op,
+                                                            source, mask);
+
+    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN) {
+	if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
+	    cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source;
+	    if (_cairo_surface_is_meta (surface_pattern->surface))
+		backend_status = _cairo_analysis_surface_analyze_meta_surface_pattern (surface,
+										       source);
+	    if (backend_status != CAIRO_STATUS_SUCCESS &&
+		backend_status != CAIRO_INT_STATUS_IMAGE_FALLBACK)
+		return backend_status;
+	}
+
+	if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
+	    cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask;
+	    if (_cairo_surface_is_meta (surface_pattern->surface))
+		backend_status = _cairo_analysis_surface_analyze_meta_surface_pattern (surface,
+										       mask);
+	    if (backend_status != CAIRO_STATUS_SUCCESS &&
+		backend_status != CAIRO_INT_STATUS_IMAGE_FALLBACK)
+		return backend_status;
+	}
     }
+
+    status = _cairo_surface_get_extents (&surface->base, &extents);
+    if (status)
+	return status;
+
+    if (_cairo_operator_bounded_by_source (op)) {
+	cairo_rectangle_int_t source_extents;
+	status = _cairo_pattern_get_extents (source, &source_extents);
+	if (status)
+	    return status;
+
+	_cairo_rectangle_intersect (&extents, &source_extents);
+
+	status = _cairo_pattern_get_extents (mask, &source_extents);
+	if (status)
+	    return status;
+
+	_cairo_rectangle_intersect (&extents, &source_extents);
+    }
+
+    _cairo_rectangle_intersect (&extents, &surface->current_clip);
+
+    status = _cairo_analysis_surface_add_operation (surface, &extents, backend_status);
+
     return status;
 }
 
 static cairo_int_status_t
 _cairo_analysis_surface_stroke (void			*abstract_surface,
 				cairo_operator_t	 op,
 				cairo_pattern_t		*source,
 				cairo_path_fixed_t	*path,
 				cairo_stroke_style_t	*style,
 				cairo_matrix_t		*ctm,
 				cairo_matrix_t		*ctm_inverse,
 				double			 tolerance,
 				cairo_antialias_t	 antialias)
 {
     cairo_analysis_surface_t *surface = abstract_surface;
-    cairo_status_t	     status;
+    cairo_status_t	     status, backend_status;
+    cairo_traps_t            traps;
+    cairo_box_t              box;
+    cairo_rectangle_int_t  extents;
 
     if (!surface->target->backend->stroke)
-	status = CAIRO_INT_STATUS_UNSUPPORTED;
+	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
     else
-	status = (*surface->target->backend->stroke) (surface->target, op,
-						      source, path, style,
-						      ctm, ctm_inverse,
-						      tolerance, antialias);
-    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
-	surface->fallback = TRUE;
-	status = CAIRO_STATUS_SUCCESS;
+	backend_status = (*surface->target->backend->stroke) (surface->target, op,
+							      source, path, style,
+							      ctm, ctm_inverse,
+							      tolerance, antialias);
+
+    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
+	backend_status = _cairo_analysis_surface_analyze_meta_surface_pattern (surface,
+									       source);
+
+    status = _cairo_surface_get_extents (&surface->base, &extents);
+    if (status)
+	return status;
+
+    if (_cairo_operator_bounded_by_source (op)) {
+	cairo_rectangle_int_t source_extents;
+	status = _cairo_pattern_get_extents (source, &source_extents);
+	if (status)
+	    return status;
+
+	_cairo_rectangle_intersect (&extents, &source_extents);
     }
+
+    _cairo_rectangle_intersect (&extents, &surface->current_clip);
+
+    if (_cairo_operator_bounded_by_mask (op)) {
+	box.p1.x = _cairo_fixed_from_int (extents.x);
+	box.p1.y = _cairo_fixed_from_int (extents.y);
+	box.p2.x = _cairo_fixed_from_int (extents.x + extents.width);
+	box.p2.y = _cairo_fixed_from_int (extents.y + extents.height);
+
+	_cairo_traps_init (&traps);
+	_cairo_traps_limit (&traps, &box);
+	status = _cairo_path_fixed_stroke_to_traps (path,
+						    style,
+						    ctm, ctm_inverse,
+						    tolerance,
+						    &traps);
+
+	if (status) {
+	    _cairo_traps_fini (&traps);
+	    return status;
+	}
+
+	_cairo_traps_extents (&traps, &box);
+	extents.x = _cairo_fixed_integer_floor (box.p1.x);
+	extents.y = _cairo_fixed_integer_floor (box.p1.y);
+	extents.width = _cairo_fixed_integer_ceil (box.p2.x) - extents.x;
+	extents.height = _cairo_fixed_integer_ceil (box.p2.y) - extents.y;
+	_cairo_traps_fini (&traps);
+    }
+
+    status = _cairo_analysis_surface_add_operation (surface, &extents, backend_status);
+
     return status;
 }
 
 static cairo_int_status_t
 _cairo_analysis_surface_fill (void			*abstract_surface,
 			      cairo_operator_t		 op,
 			      cairo_pattern_t		*source,
 			      cairo_path_fixed_t	*path,
 			      cairo_fill_rule_t	 	 fill_rule,
 			      double			 tolerance,
 			      cairo_antialias_t	 	 antialias)
 {
     cairo_analysis_surface_t *surface = abstract_surface;
-    cairo_status_t	     status;
+    cairo_status_t	     status, backend_status;
+    cairo_traps_t            traps;
+    cairo_box_t              box;
+    cairo_rectangle_int_t  extents;
 
     if (!surface->target->backend->fill)
-	status = CAIRO_INT_STATUS_UNSUPPORTED;
+	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
     else
-	status = (*surface->target->backend->fill) (surface->target, op,
+	backend_status = (*surface->target->backend->fill) (surface->target, op,
 						    source, path, fill_rule,
 						    tolerance, antialias);
-    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
-	surface->fallback = TRUE;
-	status = CAIRO_STATUS_SUCCESS;
+
+    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
+	backend_status = _cairo_analysis_surface_analyze_meta_surface_pattern (surface,
+									       source);
+
+    status = _cairo_surface_get_extents (&surface->base, &extents);
+    if (status)
+	return status;
+
+    if (_cairo_operator_bounded_by_source (op)) {
+	cairo_rectangle_int_t source_extents;
+	status = _cairo_pattern_get_extents (source, &source_extents);
+	if (status)
+	    return status;
+
+	_cairo_rectangle_intersect (&extents, &source_extents);
     }
+
+    _cairo_rectangle_intersect (&extents, &surface->current_clip);
+
+    if (_cairo_operator_bounded_by_mask (op)) {
+	box.p1.x = _cairo_fixed_from_int (extents.x);
+	box.p1.y = _cairo_fixed_from_int (extents.y);
+	box.p2.x = _cairo_fixed_from_int (extents.x + extents.width);
+	box.p2.y = _cairo_fixed_from_int (extents.y + extents.height);
+
+	_cairo_traps_init (&traps);
+	_cairo_traps_limit (&traps, &box);
+	status = _cairo_path_fixed_fill_to_traps (path,
+						  fill_rule,
+						  tolerance,
+						  &traps);
+
+	if (status) {
+	    _cairo_traps_fini (&traps);
+	    return status;
+	}
+
+	_cairo_traps_extents (&traps, &box);
+	extents.x = _cairo_fixed_integer_floor (box.p1.x);
+	extents.y = _cairo_fixed_integer_floor (box.p1.y);
+	extents.width = _cairo_fixed_integer_ceil (box.p2.x) - extents.x;
+	extents.height = _cairo_fixed_integer_ceil (box.p2.y) - extents.y;
+
+	_cairo_traps_fini (&traps);
+    }
+
+    status = _cairo_analysis_surface_add_operation (surface, &extents, backend_status);
+
     return status;
 }
 
 static cairo_int_status_t
 _cairo_analysis_surface_show_glyphs (void		  *abstract_surface,
 				     cairo_operator_t	   op,
 				     cairo_pattern_t	  *source,
 				     cairo_glyph_t	  *glyphs,
 				     int		   num_glyphs,
 				     cairo_scaled_font_t  *scaled_font)
 {
     cairo_analysis_surface_t *surface = abstract_surface;
-    cairo_status_t	     status;
+    cairo_status_t	     status, backend_status;
+    cairo_rectangle_int_t    extents, glyph_extents;
 
     if (!surface->target->backend->show_glyphs)
-	status = CAIRO_INT_STATUS_UNSUPPORTED;
+	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
     else
-	status = (*surface->target->backend->show_glyphs) (surface->target, op,
+	backend_status = (*surface->target->backend->show_glyphs) (surface->target, op,
 							   source,
 							   glyphs, num_glyphs,
 							   scaled_font);
-    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
-	surface->fallback = TRUE;
-	status = CAIRO_STATUS_SUCCESS;
+
+    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
+	backend_status = _cairo_analysis_surface_analyze_meta_surface_pattern (surface,
+									       source);
+
+    status = _cairo_surface_get_extents (&surface->base, &extents);
+    if (status)
+	return status;
+
+    if (_cairo_operator_bounded_by_source (op)) {
+	cairo_rectangle_int_t source_extents;
+	status = _cairo_pattern_get_extents (source, &source_extents);
+	if (status)
+	    return status;
+
+	_cairo_rectangle_intersect (&extents, &source_extents);
     }
+
+    _cairo_rectangle_intersect (&extents, &surface->current_clip);
+
+    if (_cairo_operator_bounded_by_mask (op)) {
+	status = _cairo_scaled_font_glyph_device_extents (scaled_font,
+							  glyphs,
+							  num_glyphs,
+							  &glyph_extents);
+	if (status)
+	    return status;
+
+	_cairo_rectangle_intersect (&extents, &glyph_extents);
+    }
+
+    status = _cairo_analysis_surface_add_operation (surface, &extents, backend_status);
+
     return status;
 }
 
 static const cairo_surface_backend_t cairo_analysis_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
     NULL, /* create_similar */
-    NULL, /* finish_surface */
+    _cairo_analysis_surface_finish,
     NULL, /* acquire_source_image */
     NULL, /* release_source_image */
     NULL, /* acquire_dest_image */
     NULL, /* release_dest_image */
     NULL, /* clone_similar */
     NULL, /* composite */
     NULL, /* fill_rectangles */
     NULL, /* composite_trapezoids */
     NULL, /* copy_page */
     NULL, /* show_page */
     NULL, /* set_clip_region */
-    NULL, /* clip_path */
+    _cairo_analysis_surface_intersect_clip_path,
     _cairo_analysis_surface_get_extents,
     NULL, /* old_show_glyphs */
     NULL, /* get_font_options */
     NULL, /* flush */
     NULL, /* mark_dirty_rectangle */
     NULL, /* scaled_font_fini */
     NULL, /* scaled_glyph_fini */
     _cairo_analysis_surface_paint,
     _cairo_analysis_surface_mask,
     _cairo_analysis_surface_stroke,
     _cairo_analysis_surface_fill,
     _cairo_analysis_surface_show_glyphs,
     NULL, /* snapshot */
 };
 
-cairo_private cairo_surface_t *
+cairo_surface_t *
 _cairo_analysis_surface_create (cairo_surface_t		*target,
 				int			 width,
 				int			 height)
 {
     cairo_analysis_surface_t *surface;
 
     surface = malloc (sizeof (cairo_analysis_surface_t));
     if (surface == NULL)
@@ -221,37 +552,55 @@ cairo_private cairo_surface_t *
      * sure nothing will ever use this value. */
     _cairo_surface_init (&surface->base, &cairo_analysis_surface_backend,
 			 CAIRO_CONTENT_COLOR_ALPHA);
 
     surface->width = width;
     surface->height = height;
 
     surface->target = target;
-    surface->fallback = FALSE;
+    surface->has_supported = FALSE;
+    surface->has_unsupported = FALSE;
+    _cairo_region_init (&surface->supported_region);
+    _cairo_region_init (&surface->fallback_region);
+
+    surface->current_clip.x = 0;
+    surface->current_clip.y = 0;
+    surface->current_clip.width = width;
+    surface->current_clip.height = height;
 
     return &surface->base;
 FAIL:
     _cairo_error (CAIRO_STATUS_NO_MEMORY);
     return NULL;
 }
 
-cairo_private cairo_region_t *
+cairo_region_t *
 _cairo_analysis_surface_get_supported (cairo_surface_t *abstract_surface)
 {
-    /* XXX */
-    return NULL;
+    cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
+
+    return &surface->supported_region;
 }
 
-cairo_private cairo_region_t *
+cairo_region_t *
 _cairo_analysis_surface_get_unsupported (cairo_surface_t *abstract_surface)
 {
-    /* XXX */
-    return NULL;
+    cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
+
+    return &surface->fallback_region;
 }
 
-cairo_private cairo_bool_t
+cairo_bool_t
+_cairo_analysis_surface_has_supported (cairo_surface_t *abstract_surface)
+{
+    cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
+
+    return surface->has_supported;
+}
+
+cairo_bool_t
 _cairo_analysis_surface_has_unsupported (cairo_surface_t *abstract_surface)
 {
     cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
 
-    return surface->fallback;
+    return surface->has_unsupported;
 }
--- a/gfx/cairo/cairo/src/cairo-atsui-font.c
+++ b/gfx/cairo/cairo/src/cairo-atsui-font.c
@@ -725,18 +725,18 @@ static cairo_status_t
     CGContextShowGlyphsAtPoint (drawingContext, 0, 0,  
 				&theGlyph, 1);
 
     CGContextRelease (drawingContext);
 
     /* correct for difference between cairo and quartz 
      * coordinate systems.
      */
-    cairo_surface_set_device_offset ((cairo_surface_t *)surface, left, 
-				    -bbox.size.height - bottom);
+    cairo_surface_set_device_offset ((cairo_surface_t *)surface,
+				     -left, (bbox.size.height + bottom));
     _cairo_scaled_glyph_set_surface (scaled_glyph,
 				     &base,
 				     surface);
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
--- a/gfx/cairo/cairo/src/cairo-cff-subset.c
+++ b/gfx/cairo/cairo/src/cairo-cff-subset.c
@@ -153,17 +153,17 @@ encode_integer (unsigned char *p, int i)
     } else if (i >= 108 && i <= 1131) {
         i -= 108;
         *p++ = (i >> 8)+ 247;
         *p++ = i & 0xff;
     } else if (i >= -1131 && i <= -108) {
         i = -i - 108;
         *p++ = (i >> 8)+ 251;
         *p++ = i & 0xff;
-    } else if (i >= -1131 && i <= -108) {
+    } else if (i >= -32768 && i <= 32767) {
         *p++ = 28;
         *p++ = (i >> 8)  & 0xff;
         *p++ = i & 0xff;
     } else {
         p = encode_integer_max (p, i);
     }
     return p;
 }
--- a/gfx/cairo/cairo/src/cairo-clip.c
+++ b/gfx/cairo/cairo/src/cairo-clip.c
@@ -649,17 +649,16 @@ cairo_private cairo_rectangle_list_t*
             if (!_cairo_clip_int_rect_to_user(gstate, &clip_rect, &rectangles[i])) {
 		_cairo_region_boxes_fini (&clip->region, boxes);
 		free (rectangles);
 		return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
 	    }
         }
 
 	_cairo_region_boxes_fini (&clip->region, boxes);
-
     } else {
         cairo_rectangle_int_t extents;
 
 	n_boxes = 1;
 
 	rectangles = malloc(sizeof (cairo_rectangle_t));
 	if (rectangles == NULL)
 	    return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
--- a/gfx/cairo/cairo/src/cairo-directfb-surface.c
+++ b/gfx/cairo/cairo/src/cairo-directfb-surface.c
@@ -1279,18 +1279,18 @@ static cairo_status_t
             case CAIRO_FORMAT_A8:
                 break;
             default:
                 D_DEBUG_AT (Cairo_DirectFB,
                             "Unsupported font format %d!\n", img->format);
                 return CAIRO_INT_STATUS_UNSUPPORTED;
         }
         
-        points[n].x = _cairo_lround (glyphs[i].x + img->base.device_transform.x0);
-        points[n].y = _cairo_lround (glyphs[i].y + img->base.device_transform.y0);
+        points[n].x = _cairo_lround (glyphs[i].x - img->base.device_transform.x0);
+        points[n].y = _cairo_lround (glyphs[i].y - img->base.device_transform.y0);
         
         if (points[n].x >= surface->width  ||
             points[n].y >= surface->height ||
             points[n].x+img->width  <= 0   ||
             points[n].y+img->height <= 0)
             continue;
         
         if (!scaled_glyph->surface_private) {
--- a/gfx/cairo/cairo/src/cairo-ft-font.c
+++ b/gfx/cairo/cairo/src/cairo-ft-font.c
@@ -551,16 +551,17 @@ FT_Face
     }
     _cairo_ft_unscaled_font_map_unlock ();
 
     if (FT_New_Face (font_map->ft_library,
 		     unscaled->filename,
 		     unscaled->id,
 		     &face) != FT_Err_Ok)
     {
+	unscaled->lock_count--;
 	CAIRO_MUTEX_UNLOCK (unscaled->mutex);
 	_cairo_error (CAIRO_STATUS_NO_MEMORY);
 	return NULL;
     }
 
     unscaled->face = face;
 
     font_map->num_open_faces++;
@@ -582,17 +583,16 @@ void
 }
 slim_hidden_def (cairo_ft_scaled_font_unlock_face);
 
 static void
 _compute_transform (cairo_ft_font_transform_t *sf,
 		    cairo_matrix_t      *scale)
 {
     cairo_matrix_t normalized = *scale;
-    double tx, ty;
 
     /* The font matrix has x and y "scale" components which we extract and
      * use as character scale values. These influence the way freetype
      * chooses hints, as well as selecting different bitmaps in
      * hand-rendered fonts. We also copy the normalized matrix to
      * freetype's transformation.
      */
 
@@ -601,17 +601,17 @@ static void
 					 /* XXX */ 1);
 
     if (sf->x_scale != 0 && sf->y_scale != 0) {
 	cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale);
 
 	_cairo_matrix_get_affine (&normalized,
 				  &sf->shape[0][0], &sf->shape[0][1],
 				  &sf->shape[1][0], &sf->shape[1][1],
-				  &tx, &ty);
+				  NULL, NULL);
     } else {
 	sf->shape[0][0] = sf->shape[1][1] = 1.0;
 	sf->shape[0][1] = sf->shape[1][0] = 0.0;
     }
 }
 
 /* Temporarily scales an unscaled font to the give scale. We catch
  * scaling to the same size, since changing a FT_Face is expensive.
@@ -743,16 +743,22 @@ static cairo_status_t
     int width, height, stride;
     unsigned char *data;
     int format = CAIRO_FORMAT_A8;
     cairo_bool_t subpixel = FALSE;
 
     width = bitmap->width;
     height = bitmap->rows;
 
+    if (width == 0 || height == 0) {
+	*surface = (cairo_image_surface_t *)
+	    cairo_image_surface_create_for_data (NULL, format, 0, 0, 0);
+	return (*surface)->base.status;
+    }
+
     switch (bitmap->pixel_mode) {
     case FT_PIXEL_MODE_MONO:
 	stride = (((width + 31) & ~31) >> 3);
 	if (own_buffer) {
 	    data = bitmap->buffer;
 	    assert (stride == bitmap->pitch);
 	} else {
 	    data = _cairo_malloc_ab (height, stride);
@@ -1065,21 +1071,23 @@ static cairo_status_t
 
 	status = _get_bitmap_surface (&bitmap, TRUE, font_options, surface);
 	if (status)
 	    return status;
     }
 
     /*
      * Note: the font's coordinate system is upside down from ours, so the
-     * Y coordinate of the control box needs to be negated.
+     * Y coordinate of the control box needs to be negated.  Moreover, device
+     * offsets are position of glyph origin relative to top left while xMin
+     * and yMax are offsets of top left relative to origin.  Another negation.
      */
     cairo_surface_set_device_offset (&(*surface)->base,
-				     floor ((double) cbox.xMin / 64.0),
-				     floor (-(double) cbox.yMax / 64.0));
+				     floor (-(double) cbox.xMin / 64.0),
+				     floor (+(double) cbox.yMax / 64.0));
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 /* Converts a bitmap (or other) FT_GlyphSlot into an image */
 static cairo_status_t
 _render_glyph_bitmap (FT_Face		      face,
 		      cairo_font_options_t   *font_options,
@@ -1092,89 +1100,94 @@ static cairo_status_t
     /* According to the FreeType docs, glyphslot->format could be
      * something other than FT_GLYPH_FORMAT_OUTLINE or
      * FT_GLYPH_FORMAT_BITMAP. Calling FT_Render_Glyph gives FreeType
      * the opportunity to convert such to
      * bitmap. FT_GLYPH_FORMAT_COMPOSITE will not be encountered since
      * we avoid the FT_LOAD_NO_RECURSE flag.
      */
     error = FT_Render_Glyph (glyphslot, FT_RENDER_MODE_NORMAL);
-    if (error) {
+    /* XXX ignoring all other errors for now.  They are not fatal, typically
+     * just a glyph-not-found. */
+    if (error == FT_Err_Out_Of_Memory) {
 	_cairo_error (CAIRO_STATUS_NO_MEMORY);
 	return CAIRO_STATUS_NO_MEMORY;
     }
 
     status = _get_bitmap_surface (&glyphslot->bitmap, FALSE, font_options, surface);
     if (status)
 	return status;
 
     /*
      * Note: the font's coordinate system is upside down from ours, so the
-     * Y coordinate of the control box needs to be negated.
+     * Y coordinate of the control box needs to be negated.  Moreover, device
+     * offsets are position of glyph origin relative to top left while
+     * bitmap_left and bitmap_top are offsets of top left relative to origin.
+     * Another negation.
      */
     cairo_surface_set_device_offset (&(*surface)->base,
-				     glyphslot->bitmap_left,
-				     -glyphslot->bitmap_top);
+				     -glyphslot->bitmap_left,
+				     +glyphslot->bitmap_top);
 
     return status;
 }
 
 static cairo_status_t
 _transform_glyph_bitmap (cairo_matrix_t         * shape,
 			 cairo_image_surface_t ** surface)
 {
     cairo_matrix_t original_to_transformed;
     cairo_matrix_t transformed_to_original;
     cairo_image_surface_t *old_image;
     cairo_surface_t *image;
     double x[4], y[4];
     double origin_x, origin_y;
-    int origin_width, origin_height;
+    int orig_width, orig_height;
     int i;
     int x_min, y_min, x_max, y_max;
     int width, height;
     cairo_status_t status;
     cairo_surface_pattern_t pattern;
 
     /* We want to compute a transform that takes the origin
      * (device_x_offset, device_y_offset) to 0,0, then applies
      * the "shape" portion of the font transform
      */
     original_to_transformed = *shape;
     
     cairo_surface_get_device_offset (&(*surface)->base, &origin_x, &origin_y);
-    origin_width = cairo_image_surface_get_width (&(*surface)->base);
-    origin_height = cairo_image_surface_get_height (&(*surface)->base);
+    orig_width = cairo_image_surface_get_width (&(*surface)->base);
+    orig_height = cairo_image_surface_get_height (&(*surface)->base);
 
     cairo_matrix_translate (&original_to_transformed,
-			    origin_x, origin_y);
+			    -origin_x, -origin_y);
 
     /* Find the bounding box of the original bitmap under that
      * transform
      */
-    x[0] = 0;            y[0] = 0;
-    x[1] = origin_width; y[1] = 0;
-    x[2] = origin_width; y[2] = origin_height;
-    x[3] = 0;            y[3] = origin_height;
+    x[0] = 0;          y[0] = 0;
+    x[1] = orig_width; y[1] = 0;
+    x[2] = orig_width; y[2] = orig_height;
+    x[3] = 0;          y[3] = orig_height;
 
     for (i = 0; i < 4; i++)
       cairo_matrix_transform_point (&original_to_transformed,
 				    &x[i], &y[i]);
 
     x_min = floor (x[0]);   y_min = floor (y[0]);
     x_max =  ceil (x[0]);   y_max =  ceil (y[0]);
 
     for (i = 1; i < 4; i++) {
 	if (x[i] < x_min)
 	    x_min = floor (x[i]);
-	if (x[i] > x_max)
+	else if (x[i] > x_max)
 	    x_max = ceil (x[i]);
 	if (y[i] < y_min)
 	    y_min = floor (y[i]);
-	if (y[i] > y_max)
+	else if (y[i] > y_max)
 	    y_max = ceil (y[i]);
     }
 
     /* Adjust the transform so that the bounding box starts at 0,0 ...
      * this gives our final transform from original bitmap to transformed
      * bitmap.
      */
     original_to_transformed.x0 -= x_min;
@@ -1223,28 +1236,26 @@ static cairo_status_t
     if (status) {
 	cairo_surface_destroy (image);
 	return status;
     }
 
     /* Now update the cache entry for the new bitmap, recomputing
      * the origin based on the final transform.
      */
-    origin_x = - origin_x;
-    origin_y = - origin_y;
     cairo_matrix_transform_point (&original_to_transformed,
 				  &origin_x, &origin_y);
 
     old_image = (*surface);
     (*surface) = (cairo_image_surface_t *)image;
     cairo_surface_destroy (&old_image->base);
 
     cairo_surface_set_device_offset (&(*surface)->base,
-				     - _cairo_lround (origin_x),
-				     - _cairo_lround (origin_y));
+				     _cairo_lround (origin_x),
+				     _cairo_lround (origin_y));
     return status;
 }
 
 static const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend = {
     _cairo_ft_unscaled_font_destroy,
 #if 0
     _cairo_ft_unscaled_font_create_glyph
 #endif
@@ -1886,18 +1897,19 @@ static cairo_int_status_t
     if (load_flags & FT_LOAD_VERTICAL_LAYOUT) {
 	load_flags &= ~FT_LOAD_VERTICAL_LAYOUT;
 	vertical_layout = TRUE;
     }
 
     error = FT_Load_Glyph (scaled_font->unscaled->face,
 			   _cairo_scaled_glyph_index(scaled_glyph),
 			   load_flags);
-
-    if (error) {
+    /* XXX ignoring all other errors for now.  They are not fatal, typically
+     * just a glyph-not-found. */
+    if (error == FT_Err_Out_Of_Memory) {
 	status = CAIRO_STATUS_NO_MEMORY;
 	goto FAIL;
     }
 
     glyph = face->glyph;
 
 #if HAVE_FT_GLYPHSLOT_EMBOLDEN
     /*
@@ -2037,18 +2049,19 @@ static cairo_int_status_t
 	/*
 	 * A kludge -- the above code will trash the outline,
 	 * so reload it. This will probably never occur though
 	 */
 	if ((info & CAIRO_SCALED_GLYPH_INFO_SURFACE) != 0) {
 	    error = FT_Load_Glyph (face,
 				   _cairo_scaled_glyph_index(scaled_glyph),
 				   load_flags | FT_LOAD_NO_BITMAP);
-
-	    if (error) {
+	    /* XXX ignoring all other errors for now.  They are not fatal, typically
+	     * just a glyph-not-found. */
+	    if (error == FT_Err_Out_Of_Memory) {
 		_cairo_ft_unscaled_font_unlock_face (unscaled);
 		_cairo_error (CAIRO_STATUS_NO_MEMORY);
 		return CAIRO_STATUS_NO_MEMORY;
 	    }
 #if HAVE_FT_GLYPHSLOT_EMBOLDEN
 	    /*
 	     * embolden glyphs if requested
 	     */
--- a/gfx/cairo/cairo/src/cairo-glitz-surface.c
+++ b/gfx/cairo/cairo/src/cairo-glitz-surface.c
@@ -152,17 +152,17 @@ static cairo_bool_t
 
 static glitz_box_t *
 _cairo_glitz_get_boxes_from_region (cairo_region_t *region, int *nboxes)
 {
     cairo_box_int_t *cboxes;
     glitz_box_t *gboxes;
     int n, i;
 
-    if (_cairo_region_get_boxes (&surface->clip, &n, &cboxes) != CAIRO_STATUS_SUCCESS)
+    if (_cairo_region_get_boxes (region, &n, &cboxes) != CAIRO_STATUS_SUCCESS)
         return NULL;
 
     *nboxes = n;
     if (n == 0)
         return NULL;
 
     gboxes = _cairo_malloc_ab (n, sizeof(glitz_box_t));
     if (gboxes == NULL)
@@ -171,17 +171,17 @@ static glitz_box_t *
     for (i = 0; i < n; i++) {
         gboxes[i].x1 = cboxes[i].p1.x;
         gboxes[i].y1 = cboxes[i].p1.y;
         gboxes[i].x2 = cboxes[i].p2.x;
         gboxes[i].y2 = cboxes[i].p2.y;
     }
 
 done:
-    _cairo_region_boxes_fini (&sruface->clip, &cboxes);
+    _cairo_region_boxes_fini (region, cboxes);
     return gboxes;
 }
 
 static cairo_status_t
 _cairo_glitz_surface_get_image (cairo_glitz_surface_t   *surface,
 				cairo_rectangle_int_t   *interest,
 				cairo_image_surface_t  **image_out,
 				cairo_rectangle_int_t   *rect_out)
@@ -798,20 +798,20 @@ static cairo_int_status_t
 	    glitz_buffer_destroy (buffer);
 	    free (data);
 	    return CAIRO_STATUS_NO_MEMORY;
 	}
 
 	for (i = 0; i < gradient->n_stops; i++)
 	{
 	    pixels[i] =
-		(((int) (gradient->stops[i].color.alpha >> 8)) << 24) |
-		(((int) (gradient->stops[i].color.red   >> 8)) << 16) |
-		(((int) (gradient->stops[i].color.green >> 8)) << 8)  |
-		(((int) (gradient->stops[i].color.blue  >> 8)));
+		(((int) (gradient->stops[i].color.alpha_short >> 8)) << 24) |
+		(((int) (gradient->stops[i].color.red_short   >> 8)) << 16) |
+		(((int) (gradient->stops[i].color.green_short >> 8)) << 8)  |
+		(((int) (gradient->stops[i].color.blue_short  >> 8)));
 
 	    params[n_base_params + 3 * i + 0] = gradient->stops[i].x;
 	    params[n_base_params + 3 * i + 1] = i << 16;
 	    params[n_base_params + 3 * i + 2] = 0;
 	}
 
 	glitz_set_pixels (src->surface, 0, 0, gradient->n_stops, 1,
 			  (glitz_pixel_format_t *)&format, buffer);
@@ -829,20 +829,20 @@ static cairo_int_status_t
 	    attr->filter = GLITZ_FILTER_LINEAR_GRADIENT;
 	}
 	else
 	{
 	    cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern;
 
 	    params[0] = grad->c1.x;
 	    params[1] = grad->c1.y;
-	    params[2] = grad->radius1;
+	    params[2] = grad->r1;
 	    params[3] = grad->c2.x;
 	    params[4] = grad->c2.y;
-	    params[5] = grad->radius2;
+	    params[5] = grad->r2;
 	    attr->filter = GLITZ_FILTER_RADIAL_GRADIENT;
 	}
 
 	switch (pattern->extend) {
 	case CAIRO_EXTEND_NONE:
 	    attr->fill = GLITZ_FILL_TRANSPARENT;
 	    break;
 	case CAIRO_EXTEND_REPEAT:
@@ -1425,22 +1425,21 @@ static cairo_int_status_t
     if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
 _cairo_glitz_surface_set_clip_region (void		*abstract_surface,
-                                      cairo_region_t	*region);
+                                      cairo_region_t	*region)
 {
     cairo_glitz_surface_t *surface = abstract_surface;
 
     if (region)
-
     {
 	glitz_box_t *box;
 	int	    n;
 
 	if (!surface->has_clip) {
             _cairo_region_init (&surface->clip);
             surface->has_clip = TRUE;
         }
@@ -2198,18 +2197,18 @@ static cairo_int_status_t
 	{
 	    remaining_glyps--;
 
 	    if (glyph_private->area->width)
 	    {
 		x_offset = scaled_glyphs[i]->surface->base.device_transform.x0;
 		y_offset = scaled_glyphs[i]->surface->base.device_transform.y0;
 
-		x1 = _cairo_lround (glyphs[i].x) + x_offset;
-		y1 = _cairo_lround (glyphs[i].y) + y_offset;
+		x1 = _cairo_lround (glyphs[i].x - x_offset);
+		y1 = _cairo_lround (glyphs[i].y - y_offset);
 		x2 = x1 + glyph_private->area->width;
 		y2 = y1 + glyph_private->area->height;
 
 		WRITE_BOX (vertices, x1, y1, x2, y2,
 			   &glyph_private->p1, &glyph_private->p2);
 
 		glyph_private->locked = TRUE;
 
@@ -2242,18 +2241,18 @@ static cairo_int_status_t
 							glyph_height,
 							(cairo_surface_t **)
 							&clone);
 		if (status)
 		    goto UNLOCK;
 
 		x_offset = scaled_glyphs[i]->surface->base.device_transform.x0;
 		y_offset = scaled_glyphs[i]->surface->base.device_transform.y0;
-		x1 = _cairo_lround (glyphs[i].x) + x_offset;
-		y1 = _cairo_lround (glyphs[i].y) + y_offset;
+		x1 = _cairo_lround (glyphs[i].x - x_offset);
+		y1 = _cairo_lround (glyphs[i].y - y_offset);
 
 		glitz_composite (_glitz_operator (op),
 				 src->surface,
 				 clone->surface,
 				 dst->surface,
 				 src_x + attributes.base.x_offset + x1,
 				 src_y + attributes.base.y_offset + y1,
 				 0, 0,
--- a/gfx/cairo/cairo/src/cairo-gstate.c
+++ b/gfx/cairo/cairo/src/cairo-gstate.c
@@ -742,18 +742,19 @@ void
 void
 _cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate,
                                          double *x1, double *y1,
                                          double *x2, double *y2,
                                          cairo_bool_t *is_tight)
 {
     cairo_matrix_t matrix_inverse;
 
-    cairo_matrix_multiply (&matrix_inverse, &gstate->ctm_inverse,
-                           &gstate->target->device_transform_inverse);
+    cairo_matrix_multiply (&matrix_inverse,
+                           &gstate->target->device_transform_inverse,
+			   &gstate->ctm_inverse);
     _cairo_matrix_transform_bounding_box (&matrix_inverse,
 					  x1, y1, x2, y2, is_tight);
 }
 
 /* XXX: NYI
 cairo_status_t
 _cairo_gstate_stroke_to_path (cairo_gstate_t *gstate)
 {
@@ -1081,23 +1082,23 @@ BAIL:
     _cairo_traps_fini (&traps);
 
     return status;
 }
 
 cairo_status_t
 _cairo_gstate_copy_page (cairo_gstate_t *gstate)
 {
-    return _cairo_surface_copy_page (gstate->target);
+    return cairo_surface_copy_page (gstate->target);
 }
 
 cairo_status_t
 _cairo_gstate_show_page (cairo_gstate_t *gstate)
 {
-    return _cairo_surface_show_page (gstate->target);
+    return cairo_surface_show_page (gstate->target);
 }
 
 static void
 _cairo_gstate_traps_extents_to_user_rectangle (cairo_gstate_t	  *gstate,
                                                cairo_traps_t      *traps,
                                                double *x1, double *y1,
                                                double *x2, double *y2)
 {
@@ -1391,23 +1392,24 @@ cairo_status_t
  * called the "font matrix" which describes the user's most recent
  * font-scaling or font-transforming request. This is kept in terms of an
  * abstract scale factor, composed with the CTM and used to set the font's
  * pixel size. So if the user asks to "scale the font by 12", the matrix
  * is:
  *
  *   [ 12.0, 0.0, 0.0, 12.0, 0.0, 0.0 ]
  *
- * It is an affine matrix, like all cairo matrices, but its tx and ty
- * components are always set to zero; we don't permit "nudging" fonts
- * around.
+ * It is an affine matrix, like all cairo matrices, where its tx and ty
+ * components are used to "nudging" fonts around and are handled in gstate
+ * and then ignored by the "scaled-font" layer.
  *
  * In order to perform any action on a font, we must build an object
  * called a cairo_font_scale_t; this contains the central 2x2 matrix
- * resulting from "font matrix * CTM".
+ * resulting from "font matrix * CTM" (sans the font matrix translation
+ * components as stated in the previous paragraph).
  *
  * We pass this to the font when making requests of it, which causes it to
  * reply for a particular [user request, device] combination, under the CTM
  * (to accommodate the "zoom in" == "bigger fonts" issue above).
  *
  * The other terms in our communication with the font are therefore in
  * device space. When we ask it to perform text->glyph conversion, it will
  * produce a glyph string in device space. Glyph vectors we pass to it for
--- a/gfx/cairo/cairo/src/cairo-image-surface.c
+++ b/gfx/cairo/cairo/src/cairo-image-surface.c
@@ -53,137 +53,305 @@ static const cairo_image_surface_t _cair
 	{ 1.0, 0.0,
 	  0.0, 1.0,
 	  0.0, 0.0
 	},				/* device_transform */
 	{ 1.0, 0.0,
 	  0.0, 1.0,
 	  0.0, 0.0
 	},				/* device_transform_inverse */
+	0.0,				/* x_resolution */
+	0.0,				/* y_resolution */
 	0.0,				/* x_fallback_resolution */
 	0.0,				/* y_fallback_resolution */
 	NULL,				/* clip */
 	0,				/* next_clip_serial */
 	0,				/* current_clip_serial */
 	FALSE,				/* is_snapshot */
 	FALSE,				/* has_font_options */
 	{ CAIRO_ANTIALIAS_DEFAULT,
 	  CAIRO_SUBPIXEL_ORDER_DEFAULT,
 	  CAIRO_HINT_STYLE_DEFAULT,
 	  CAIRO_HINT_METRICS_DEFAULT
 	}				/* font_options */
     },					/* base */
+    PIXMAN_a8r8g8b8,			/* pixman_format */
     CAIRO_FORMAT_ARGB32,		/* format */
     NULL,				/* data */
     FALSE,				/* owns_data */
     FALSE,				/* has_clip */
     0,					/* width */
     0,					/* height */
     0,					/* stride */
     0,					/* depth */
     NULL				/* pixman_image */
 };
 
+static cairo_format_t
+_cairo_format_from_pixman_format (pixman_format_code_t pixman_format)
+{
+    switch (pixman_format) {
+    case PIXMAN_a8r8g8b8:
+	return CAIRO_FORMAT_ARGB32;
+    case PIXMAN_x8r8g8b8:
+	return CAIRO_FORMAT_RGB24;
+    case PIXMAN_a8:
+	return CAIRO_FORMAT_A8;
+    case PIXMAN_a1:
+	return CAIRO_FORMAT_A1;
+    case PIXMAN_a8b8g8r8: case PIXMAN_x8b8g8r8: case PIXMAN_r8g8b8:
+    case PIXMAN_b8g8r8:   case PIXMAN_r5g6b5:   case PIXMAN_b5g6r5:
+    case PIXMAN_a1r5g5b5: case PIXMAN_x1r5g5b5: case PIXMAN_a1b5g5r5:
+    case PIXMAN_x1b5g5r5: case PIXMAN_a4r4g4b4: case PIXMAN_x4r4g4b4:
+    case PIXMAN_a4b4g4r4: case PIXMAN_x4b4g4r4: case PIXMAN_r3g3b2:
+    case PIXMAN_b2g3r3:   case PIXMAN_a2r2g2b2: case PIXMAN_a2b2g2r2:
+    case PIXMAN_c8:       case PIXMAN_g8:       case PIXMAN_x4a4:
+    case PIXMAN_a4:       case PIXMAN_r1g2b1:   case PIXMAN_b1g2r1:
+    case PIXMAN_a1r1g1b1: case PIXMAN_a1b1g1r1: case PIXMAN_c4:
+    case PIXMAN_g4:       case PIXMAN_g1:
+    default:
+	return CAIRO_FORMAT_INVALID;
+    }
+
+    return CAIRO_FORMAT_INVALID;
+}
+
+static cairo_content_t
+_cairo_content_from_pixman_format (pixman_format_code_t pixman_format)
+{
+    switch (pixman_format) {
+    case PIXMAN_a8r8g8b8:
+    case PIXMAN_a8b8g8r8:
+    case PIXMAN_a1r5g5b5:
+    case PIXMAN_a1b5g5r5:
+    case PIXMAN_a4r4g4b4:
+    case PIXMAN_a4b4g4r4:
+    case PIXMAN_a2r2g2b2:
+    case PIXMAN_a2b2g2r2:
+    case PIXMAN_a1r1g1b1:
+    case PIXMAN_a1b1g1r1:
+	return CAIRO_CONTENT_COLOR_ALPHA;
+    case PIXMAN_x8r8g8b8:
+    case PIXMAN_x8b8g8r8:
+    case PIXMAN_r8g8b8:
+    case PIXMAN_b8g8r8:
+    case PIXMAN_r5g6b5:
+    case PIXMAN_b5g6r5:
+    case PIXMAN_x1r5g5b5:
+    case PIXMAN_x1b5g5r5:
+    case PIXMAN_x4r4g4b4:
+    case PIXMAN_x4b4g4r4:
+    case PIXMAN_r3g3b2:
+    case PIXMAN_b2g3r3:
+    case PIXMAN_c8:
+    case PIXMAN_g8:
+    case PIXMAN_r1g2b1:
+    case PIXMAN_b1g2r1:
+    case PIXMAN_c4:
+    case PIXMAN_g4:
+    case PIXMAN_g1:
+	return CAIRO_CONTENT_COLOR;
+    case PIXMAN_a8:
+    case PIXMAN_a1:
+    case PIXMAN_x4a4:
+    case PIXMAN_a4:
+	return CAIRO_CONTENT_ALPHA;
+    }
+
+    return CAIRO_CONTENT_COLOR_ALPHA;
+}
 
 cairo_surface_t *
-_cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
-					      cairo_format_t  format)
+_cairo_image_surface_create_for_pixman_image (pixman_image_t		*pixman_image,
+					      pixman_format_code_t	 pixman_format)
 {
     cairo_image_surface_t *surface;
 
     surface = malloc (sizeof (cairo_image_surface_t));
     if (surface == NULL) {
 	_cairo_error (CAIRO_STATUS_NO_MEMORY);
 	return (cairo_surface_t*) &_cairo_surface_nil;
     }
 
     _cairo_surface_init (&surface->base, &cairo_image_surface_backend,
-			 _cairo_content_from_format (format));
+			 _cairo_content_from_pixman_format (pixman_format));
 
     surface->pixman_image = pixman_image;
 
-    surface->format = format;
+    surface->pixman_format = pixman_format;
+    surface->format = _cairo_format_from_pixman_format (pixman_format);
     surface->data = (unsigned char *) pixman_image_get_data (pixman_image);
     surface->owns_data = FALSE;
     surface->has_clip = FALSE;
 
     surface->width = pixman_image_get_width (pixman_image);
     surface->height = pixman_image_get_height (pixman_image);
     surface->stride = pixman_image_get_stride (pixman_image);
     surface->depth = pixman_image_get_depth (pixman_image);
 
     return &surface->base;
 }
 
-static cairo_bool_t
-_CAIRO_MASK_FORMAT (cairo_format_masks_t *masks, cairo_format_t *format)
+/* XXX: This function should really live inside pixman. */
+pixman_format_code_t
+_pixman_format_from_masks (cairo_format_masks_t *masks)
 {
-    /* XXX: many formats are simply not supported by pixman, so this function
-     * converts the masks into something we know will be supported.
-     */
     switch (masks->bpp) {
     case 32:
 	if (masks->alpha_mask == 0xff000000 &&
-	    masks->red_mask == 0x00ff0000 &&
+	    masks->red_mask   == 0x00ff0000 &&
+	    masks->green_mask == 0x0000ff00 &&
+	    masks->blue_mask  == 0x000000ff)
+	{
+	    return PIXMAN_a8r8g8b8;
+	}
+	if (masks->alpha_mask == 0x00000000 &&
+	    masks->red_mask   == 0x00ff0000 &&
 	    masks->green_mask == 0x0000ff00 &&
-	    masks->blue_mask == 0x000000ff)
+	    masks->blue_mask  == 0x000000ff)
 	{
-	    *format = CAIRO_FORMAT_ARGB32;
-	    return TRUE;
+	    return PIXMAN_x8r8g8b8;
+	}
+	if (masks->alpha_mask == 0xff000000 &&
+	    masks->red_mask   == 0x000000ff &&
+	    masks->green_mask == 0x0000ff00 &&
+	    masks->blue_mask  == 0x00ff0000)
+	{
+	    return PIXMAN_a8b8g8r8;
 	}
 	if (masks->alpha_mask == 0x00000000 &&
-	    masks->red_mask == 0x00ff0000 &&
+	    masks->red_mask   == 0x000000ff &&
 	    masks->green_mask == 0x0000ff00 &&
-	    masks->blue_mask == 0x000000ff)
+	    masks->blue_mask  == 0x00ff0000)
 	{
-	    *format = CAIRO_FORMAT_RGB24;
-	    return TRUE;
+	    return PIXMAN_x8b8g8r8;
+	}
+	break;
+    case 16:
+	if (masks->alpha_mask == 0x0000 &&
+	    masks->red_mask   == 0xf800 &&
+	    masks->green_mask == 0x07e0 &&
+	    masks->blue_mask  == 0x001f)
+	{
+	    return PIXMAN_r5g6b5;
+	}
+	if (masks->alpha_mask == 0x0000 &&
+	    masks->red_mask   == 0x7c00 &&
+	    masks->green_mask == 0x03e0 &&
+	    masks->blue_mask  == 0x001f)
+	{
+	    return PIXMAN_x1r5g5b5;
 	}
 	break;
     case 8:
 	if (masks->alpha_mask == 0xff)
 	{
-	    *format = CAIRO_FORMAT_A8;
-	    return TRUE;
+	    return PIXMAN_a8;
 	}
 	break;
     case 1:
 	if (masks->alpha_mask == 0x1)
 	{
-	    *format = CAIRO_FORMAT_A1;
-	    return TRUE;
+	    return PIXMAN_a1;
 	}
 	break;
     }
-    return FALSE;
+
+    fprintf (stderr,
+	     "Error: Cairo " PACKAGE_VERSION " does not yet support the requested image format:\n"
+	     "\tDepth: %d\n"
+	     "\tAlpha mask: 0x%08lx\n"
+	     "\tRed   mask: 0x%08lx\n"
+	     "\tGreen mask: 0x%08lx\n"
+	     "\tBlue  mask: 0x%08lx\n"
+	     "Please file an enhancement request (quoting the above) at:\n"
+	     PACKAGE_BUGREPORT "\n",
+	     masks->bpp, masks->alpha_mask,
+	     masks->red_mask, masks->green_mask, masks->blue_mask);
+
+    ASSERT_NOT_REACHED;
+    return 0;
 }
 
+/* XXX: This function should really live inside pixman. */
+void
+_pixman_format_to_masks (pixman_format_code_t	 pixman_format,
+			 uint32_t		*bpp,
+			 uint32_t		*red,
+			 uint32_t		*green,
+			 uint32_t		*blue)
+{
+    *red = 0x0;
+    *green = 0x0;
+    *blue = 0x0;
+
+    switch (pixman_format)
+    {
+    case PIXMAN_a8r8g8b8:
+    case PIXMAN_x8r8g8b8:
+    default:
+	*bpp   = 32;
+	*red   = 0x00ff0000;
+	*green = 0x0000ff00;
+	*blue  = 0x000000ff;
+	break;
+
+    case PIXMAN_a8b8g8r8:
+    case PIXMAN_x8b8g8r8:
+	*bpp   = 32;
+	*red   = 0x000000ff;
+	*green = 0x0000ff00;
+	*blue  = 0x00ff0000;
+	break;
+
+    case PIXMAN_r5g6b5:
+	*bpp   = 16;
+	*red   = 0xf800;
+	*green = 0x07e0;
+	*blue  = 0x001f;
+	break;
+
+    case PIXMAN_x1r5g5b5:
+	*bpp   = 16;
+	*red   = 0x7c00;
+	*green = 0x03e0;
+	*blue  = 0x001f;
+	break;
+
+    case PIXMAN_a8:
+	*bpp = 8;
+	break;
+
+    case PIXMAN_a1:
+	*bpp = 1;
+	break;
+    }
+}
+
+
 /* XXX: This function really should be eliminated. We don't really
  * want to advertise a cairo image surface that supports any possible
  * format. A minimal step would be to replace this function with one
  * that accepts a cairo_internal_format_t rather than mask values. */
 cairo_surface_t *
 _cairo_image_surface_create_with_masks (unsigned char	       *data,
 					cairo_format_masks_t   *masks,
 					int			width,
 					int			height,
 					int			stride)
 {
-    cairo_format_t format;
+    pixman_format_code_t pixman_format;
     
-    if (!_CAIRO_MASK_FORMAT (masks, &format)) {
-	_cairo_error (CAIRO_STATUS_INVALID_FORMAT);
-	return (cairo_surface_t*) &_cairo_surface_nil;
-    }
+    pixman_format = _pixman_format_from_masks (masks);
 
-    return cairo_image_surface_create_for_data (data,
-						format,
-						width,
-						height,
-						stride);
+    return _cairo_image_surface_create_with_pixman_format (data,
+							   pixman_format,
+							   width,
+							   height,
+							   stride);
 }
 
 static pixman_format_code_t 
 _cairo_format_to_pixman_format_code (cairo_format_t format)
 {
     int ret = 0;
     switch (format) {
     case CAIRO_FORMAT_A1:
@@ -199,16 +367,43 @@ static pixman_format_code_t
     default:
 	ret = PIXMAN_a8r8g8b8;
 	break;
     }
     assert (ret);
     return ret;
 }
 
+cairo_surface_t *
+_cairo_image_surface_create_with_pixman_format (unsigned char		*data,
+						pixman_format_code_t	 pixman_format,
+						int			 width,
+						int			 height,
+						int			 stride)
+{
+    cairo_surface_t *surface;
+    pixman_image_t *pixman_image;
+
+    pixman_image = pixman_image_create_bits (pixman_format, width, height,
+					     (uint32_t *) data, stride);
+
+    if (pixman_image == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_surface_t*) &_cairo_surface_nil;
+    }
+
+    surface = _cairo_image_surface_create_for_pixman_image (pixman_image,
+							    pixman_format);
+    if (cairo_surface_status (surface)) {
+	pixman_image_unref (pixman_image);
+    }
+
+    return surface;
+}
+
 /**
  * cairo_image_surface_create:
  * @format: format of pixels in the surface to create
  * @width: width of the surface, in pixels
  * @height: height of the surface, in pixels
  *
  * Creates an image surface of the specified format and
  * dimensions. Initially the surface contents are all
@@ -226,36 +421,26 @@ static pixman_format_code_t
  **/
 cairo_surface_t *
 cairo_image_surface_create (cairo_format_t	format,
 			    int			width,
 			    int			height)
 {
     cairo_surface_t	*surface;
     pixman_format_code_t pixman_format;
-    pixman_image_t	*pixman_image;
 
     if (! CAIRO_FORMAT_VALID (format)) {
 	_cairo_error (CAIRO_STATUS_INVALID_FORMAT);
 	return (cairo_surface_t*) &_cairo_image_surface_nil_invalid_format;
     }
 
     pixman_format = _cairo_format_to_pixman_format_code (format);
-    
-    pixman_image = pixman_image_create_bits (pixman_format, width, height,
-					     NULL, -1);
-    if (pixman_image == NULL) {
-	_cairo_error (CAIRO_STATUS_NO_MEMORY);
-	return (cairo_surface_t*) &_cairo_surface_nil;
-    }
 
-    surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format);
-    if (cairo_surface_status (surface)) {
-	pixman_image_unref (pixman_image);
-    }
+    return _cairo_image_surface_create_with_pixman_format (NULL, pixman_format,
+							   width, height, -1);
 
     return surface;
 }
 slim_hidden_def (cairo_image_surface_create);
 
 cairo_surface_t *
 _cairo_image_surface_create_with_content (cairo_content_t	content,
 					  int			width,
@@ -300,39 +485,25 @@ cairo_surface_t *
  **/
 cairo_surface_t *
 cairo_image_surface_create_for_data (unsigned char     *data,
 				     cairo_format_t	format,
 				     int		width,
 				     int		height,
 				     int		stride)
 {
-    cairo_surface_t	*surface;
     pixman_format_code_t pixman_format;
-    pixman_image_t	*pixman_image;
 
     if (! CAIRO_FORMAT_VALID (format))
 	return (cairo_surface_t*) &_cairo_surface_nil;
 
     pixman_format = _cairo_format_to_pixman_format_code (format);
 
-    pixman_image = pixman_image_create_bits (pixman_format, width, height,
-					     (uint32_t *) data, stride);
-    
-    if (pixman_image == NULL) {
-	_cairo_error (CAIRO_STATUS_NO_MEMORY);
-	return (cairo_surface_t*) &_cairo_surface_nil;
-    }
-
-    surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format);
-    if (cairo_surface_status (surface)) {
-	pixman_image_unref (pixman_image);
-    }
-
-    return surface;
+    return _cairo_image_surface_create_with_pixman_format (data, pixman_format,
+							   width, height, stride);
 }
 slim_hidden_def (cairo_image_surface_create_for_data);
 
 cairo_surface_t *
 _cairo_image_surface_create_for_data_with_content (unsigned char	*data,
 						   cairo_content_t	 content,
 						   int			 width,
 						   int			 height,
@@ -481,30 +652,20 @@ cairo_format_t
 
     ASSERT_NOT_REACHED;
     return CAIRO_FORMAT_ARGB32;
 }
 
 cairo_content_t
 _cairo_content_from_format (cairo_format_t format)
 {
-    /* XXX: Use an int to avoid the warnings from mixed cairo_format_t
-     * and cairo_internal_format_t values. The warnings are extremely
-     * valuable since mixing enums can lead to subtle bugs. It's just
-     * that cairo_internal_format_t is an interim approach to getting
-     * bug #7294 fixed so we can release cairo 1.2.2 . */
-    int f = format;
-
-    switch (f) {
+    switch (format) {
     case CAIRO_FORMAT_ARGB32:
-    case CAIRO_INTERNAL_FORMAT_ABGR32:
 	return CAIRO_CONTENT_COLOR_ALPHA;
     case CAIRO_FORMAT_RGB24:
-    case CAIRO_INTERNAL_FORMAT_RGB16_565:
-    case CAIRO_INTERNAL_FORMAT_BGR24:
 	return CAIRO_CONTENT_COLOR;
     case CAIRO_FORMAT_A8:
     case CAIRO_FORMAT_A1:
 	return CAIRO_CONTENT_ALPHA;
     }
 
     ASSERT_NOT_REACHED;
     return CAIRO_CONTENT_COLOR_ALPHA;
@@ -622,17 +783,17 @@ static cairo_status_t
     _cairo_matrix_to_pixman_matrix (matrix, &pixman_transform);
 
     if (!pixman_image_set_transform (surface->pixman_image, &pixman_transform))
 	return CAIRO_STATUS_NO_MEMORY;
 
     return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_status_t
+static void
 _cairo_image_surface_set_filter (cairo_image_surface_t *surface, cairo_filter_t filter)
 {
     pixman_filter_t pixman_filter;
 
     switch (filter) {
     case CAIRO_FILTER_FAST:
 	pixman_filter = PIXMAN_FILTER_FAST;
 	break;
@@ -654,21 +815,19 @@ static cairo_status_t
 	 * API. We could fix this by officially deprecating it, or
 	 * else inventing semantics and providing an actual
 	 * implementation for it. */
     default:
 	pixman_filter = PIXMAN_FILTER_BEST;
     }
 
     pixman_image_set_filter (surface->pixman_image, pixman_filter, NULL, 0);
-
-    return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_int_status_t
+static cairo_status_t
 _cairo_image_surface_set_attributes (cairo_image_surface_t      *surface,
 				     cairo_surface_attributes_t *attributes)
 {
     cairo_int_status_t status;
 
     status = _cairo_image_surface_set_matrix (surface, &attributes->matrix);
     if (status)
 	return status;
@@ -683,19 +842,19 @@ static cairo_int_status_t
     case CAIRO_EXTEND_REFLECT:
         pixman_image_set_repeat (surface->pixman_image, PIXMAN_REPEAT_REFLECT);
 	break;
     case CAIRO_EXTEND_PAD:
         pixman_image_set_repeat (surface->pixman_image, PIXMAN_REPEAT_PAD);
 	break;
     }
 
-    status = _cairo_image_surface_set_filter (surface, attributes->filter);
+    _cairo_image_surface_set_filter (surface, attributes->filter);
 
-    return status;
+    return CAIRO_STATUS_SUCCESS;
 }
 
 /* XXX: I think we should fix pixman to match the names/order of the
  * cairo operators, but that will likely be better done at the same
  * time the X server is ported to pixman, (which will change a lot of
  * things in pixman I think).
  */
 static pixman_op_t
@@ -898,16 +1057,19 @@ static cairo_int_status_t
     pixman_format_code_t	 format;
     uint32_t			*mask_data;
     pixman_trapezoid_t		 stack_traps[STACK_TRAPS_LEN];
     pixman_trapezoid_t		*pixman_traps = stack_traps;
     int				 mask_stride;
     int				 mask_bpp;
     int				 ret, i;
 
+    if (height == 0 || width == 0)
+	return CAIRO_STATUS_SUCCESS;
+
     /* Convert traps to pixman traps */
     if (num_traps > ARRAY_LENGTH(stack_traps)) {
 	pixman_traps = _cairo_malloc_ab (num_traps, sizeof(pixman_trapezoid_t));
 	if (pixman_traps == NULL)
 	    return CAIRO_STATUS_NO_MEMORY;
     }
 
     for (i = 0; i < num_traps; i++) {
@@ -919,17 +1081,17 @@ static cairo_int_status_t
 	pixman_traps[i].left.p2.y = _cairo_fixed_to_16_16 (traps[i].left.p2.y);
 	pixman_traps[i].right.p1.x = _cairo_fixed_to_16_16 (traps[i].right.p1.x);
 	pixman_traps[i].right.p1.y = _cairo_fixed_to_16_16 (traps[i].right.p1.y);
 	pixman_traps[i].right.p2.x = _cairo_fixed_to_16_16 (traps[i].right.p2.x);
 	pixman_traps[i].right.p2.y = _cairo_fixed_to_16_16 (traps[i].right.p2.y);
     }
 
     /* Special case adding trapezoids onto a mask surface; we want to avoid
-     * creating an intermediate temporary mask unecessarily.
+     * creating an intermediate temporary mask unnecessarily.
      *
      * We make the assumption here that the portion of the trapezoids
      * contained within the surface is bounded by [dst_x,dst_y,width,height];
      * the Cairo core code passes bounds based on the trapezoid extents.
      *
      * Currently the check surface->has_clip is needed for correct
      * functioning, since pixman_add_trapezoids() doesn't obey the
      * surface clip, which is a libpixman bug , but there's no harm in
@@ -1069,18 +1231,17 @@ static void
 
 static cairo_status_t
 _cairo_image_surface_reset (void *abstract_surface)
 {
     cairo_image_surface_t *surface = abstract_surface;
     cairo_status_t status;
 
     status = _cairo_image_surface_set_clip_region (surface, NULL);
-    if (status)
-	return status;
+    assert (status == CAIRO_STATUS_SUCCESS);
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 /**
  * _cairo_surface_is_image:
  * @surface: a #cairo_surface_t
  *
@@ -1110,25 +1271,25 @@ const cairo_surface_backend_t cairo_imag
     NULL, /* show_page */
     _cairo_image_surface_set_clip_region,
     NULL, /* intersect_clip_path */
     _cairo_image_surface_get_extents,
     NULL, /* old_show_glyphs */
     _cairo_image_surface_get_font_options,
     NULL, /* flush */
     NULL, /* mark_dirty_rectangle */
-    NULL, //* font_fini */
-    NULL, //* glyph_fini */
+    NULL, /* font_fini */
+    NULL, /* glyph_fini */
 
     NULL, /* paint */
     NULL, /* mask */
     NULL, /* stroke */
     NULL, /* fill */
     NULL, /* show_glyphs */
-    NULL,  /* snapshot */
+    NULL, /* snapshot */
     NULL, /* is_similar */
 
     _cairo_image_surface_reset
 };
 
 /* A convenience function for when one needs to coerce an image
  * surface to an alternate format. */
 cairo_image_surface_t *
@@ -1138,20 +1299,20 @@ cairo_image_surface_t *
     cairo_image_surface_t *clone;
     cairo_t *cr;
     double x, y;
 
     clone = (cairo_image_surface_t *)
 	cairo_image_surface_create (format,
 				    surface->width, surface->height);
 
-    /* Use _cairo_surface_composite directly */
+    cairo_surface_get_device_offset (&surface->base, &x, &y);
+    cairo_surface_set_device_offset (&clone->base, x, y);
+
+    /* XXX Use _cairo_surface_composite directly */
     cr = cairo_create (&clone->base);
-    cairo_surface_get_device_offset (&surface->base, &x, &y);
-    cairo_set_source_surface (cr, &surface->base, x, y);
+    cairo_set_source_surface (cr, &surface->base, 0, 0);
     cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
     cairo_paint (cr);
     cairo_destroy (cr);
 
-    cairo_surface_set_device_offset (&clone->base, x, y);
-
     return clone;
 }
--- a/gfx/cairo/cairo/src/cairo-meta-surface-private.h
+++ b/gfx/cairo/cairo/src/cairo-meta-surface-private.h
@@ -26,16 +26,17 @@
  * the specific language governing rights and limitations.
  *
  * The Original Code is the cairo graphics library.
  *
  * The Initial Developer of the Original Code is Red Hat, Inc.
  *
  * Contributor(s):
  *	Kristian Høgsberg <krh@redhat.com>
+ *	Adrian Johnson <ajohnson@redneon.com>
  */
 
 #ifndef CAIRO_META_SURFACE_H
 #define CAIRO_META_SURFACE_H
 
 #include "cairoint.h"
 #include "cairo-path-fixed-private.h"
 
@@ -52,71 +53,82 @@ typedef enum {
      * basic drawing operations (which we implement already so the
      * fallbacks should never get triggered). So the plan is to
      * eliminate as many of these as possible. */
 
     CAIRO_COMMAND_INTERSECT_CLIP_PATH
 
 } cairo_command_type_t;
 
+typedef enum {
+    CAIRO_META_REGION_ALL,
+    CAIRO_META_REGION_NATIVE,
+    CAIRO_META_REGION_IMAGE_FALLBACK,
+} cairo_meta_region_type_t;
+
+typedef struct _cairo_command_header {
+    cairo_command_type_t	 type;
+    cairo_meta_region_type_t     region;
+} cairo_command_header_t;
+
 typedef struct _cairo_command_paint {
-    cairo_command_type_t	 type;
+    cairo_command_header_t       header;
     cairo_operator_t		 op;
     cairo_pattern_union_t	 source;
 } cairo_command_paint_t;
 
 typedef struct _cairo_command_mask {
-    cairo_command_type_t	 type;
+    cairo_command_header_t       header;
     cairo_operator_t		 op;
     cairo_pattern_union_t	 source;
     cairo_pattern_union_t	 mask;
 } cairo_command_mask_t;
 
 typedef struct _cairo_command_stroke {
-    cairo_command_type_t	 type;
+    cairo_command_header_t       header;
     cairo_operator_t		 op;
     cairo_pattern_union_t	 source;
     cairo_path_fixed_t		 path;
     cairo_stroke_style_t	 style;
     cairo_matrix_t		 ctm;
     cairo_matrix_t		 ctm_inverse;
     double			 tolerance;
     cairo_antialias_t		 antialias;
 } cairo_command_stroke_t;
 
 typedef struct _cairo_command_fill {
-    cairo_command_type_t	 type;
+    cairo_command_header_t       header;
     cairo_operator_t		 op;
     cairo_pattern_union_t	 source;
     cairo_path_fixed_t		 path;
     cairo_fill_rule_t		 fill_rule;
     double			 tolerance;
     cairo_antialias_t		 antialias;
 } cairo_command_fill_t;
 
 typedef struct _cairo_command_show_glyphs {
-    cairo_command_type_t	 type;
+    cairo_command_header_t       header;
     cairo_operator_t		 op;
     cairo_pattern_union_t	 source;
     cairo_glyph_t		*glyphs;
     unsigned int		 num_glyphs;
     cairo_scaled_font_t		*scaled_font;
 } cairo_command_show_glyphs_t;
 
 typedef struct _cairo_command_intersect_clip_path {
-    cairo_command_type_t	type;
+    cairo_command_header_t      header;
     cairo_path_fixed_t	       *path_pointer;
     cairo_path_fixed_t		path;
     cairo_fill_rule_t		fill_rule;
     double			tolerance;
     cairo_antialias_t		antialias;
 } cairo_command_intersect_clip_path_t;
 
 typedef union _cairo_command {
-    cairo_command_type_t			type;
+    cairo_command_header_t      header;
 
     /* The 5 basic drawing operations. */
     cairo_command_paint_t			paint;
     cairo_command_mask_t			mask;
     cairo_command_stroke_t			stroke;
     cairo_command_fill_t			fill;
     cairo_command_show_glyphs_t			show_glyphs;
 
@@ -146,12 +158,24 @@ cairo_private cairo_surface_t *
 _cairo_meta_surface_create (cairo_content_t	content,
 			    int			width_pixels,
 			    int			height_pixels);
 
 cairo_private cairo_status_t
 _cairo_meta_surface_replay (cairo_surface_t *surface,
 			    cairo_surface_t *target);
 
+cairo_private cairo_status_t
+_cairo_meta_surface_replay_analyze_meta_pattern (cairo_surface_t *surface,
+						 cairo_surface_t *target);
+
+cairo_private cairo_status_t
+_cairo_meta_surface_replay_and_create_regions (cairo_surface_t *surface,
+					       cairo_surface_t *target);
+cairo_private cairo_status_t
+_cairo_meta_surface_replay_region (cairo_surface_t          *surface,
+				   cairo_surface_t          *target,
+				   cairo_meta_region_type_t  region);
+
 cairo_private cairo_bool_t
 _cairo_surface_is_meta (const cairo_surface_t *surface);
 
 #endif /* CAIRO_META_SURFACE_H */
--- a/gfx/cairo/cairo/src/cairo-meta-surface.c
+++ b/gfx/cairo/cairo/src/cairo-meta-surface.c
@@ -1,11 +1,12 @@
 /* cairo - a vector graphics library with display and print output
  *
  * Copyright © 2005 Red Hat, Inc
+ * Copyright © 2007 Adrian Johnson
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
  * License version 2.1 as published by the Free Software Foundation
  * (the "LGPL") or, at your option, under the terms of the Mozilla
  * Public License Version 1.1 (the "MPL"). If you do not alter this
  * notice, a recipient may use your version of this file under either
  * the MPL or the LGPL.
@@ -27,16 +28,17 @@
  *
  * The Original Code is the cairo graphics library.
  *
  * The Initial Developer of the Original Code is Red Hat, Inc.
  *
  * Contributor(s):
  *	Kristian Høgsberg <krh@redhat.com>
  *	Carl Worth <cworth@cworth.org>
+ *	Adrian Johnson <ajohnson@redneon.com>
  */
 
 /* A meta surface is a surface that records all drawing operations at
  * the highest level of the surface backend interface, (that is, the
  * level of paint, mask, stroke, fill, and show_glyphs). The meta
  * surface can then be "replayed" against any target surface with:
  *
  *	_cairo_meta_surface_replay (meta, target);
@@ -52,16 +54,22 @@
  * various objects. For example, it would be nice to have a
  * copy-on-write implementation for _cairo_surface_snapshot.
  */
 
 #include "cairoint.h"
 #include "cairo-meta-surface-private.h"
 #include "cairo-clip-private.h"
 
+typedef enum {
+    CAIRO_META_REPLAY,
+    CAIRO_META_CREATE_REGIONS,
+    CAIRO_META_ANALYZE_META_PATTERN
+} cairo_meta_replay_type_t;
+
 static const cairo_surface_backend_t cairo_meta_surface_backend;
 
 /* Currently all meta surfaces do have a size which should be passed
  * in as the maximum size of any target surface against which the
  * meta-surface will ever be replayed.
  *
  * XXX: The naming of "pixels" in the size here is a misnomer. It's
  * actually a size in whatever device-space units are desired (again,
@@ -118,17 +126,17 @@ static cairo_status_t
 	cairo_surface_destroy (meta->commands_owner);
 	return CAIRO_STATUS_SUCCESS;
     }
 
     num_elements = meta->commands.num_elements;
     elements = _cairo_array_index (&meta->commands, 0);
     for (i = 0; i < num_elements; i++) {
 	command = elements[i];
-	switch (command->type) {
+	switch (command->header.type) {
 
 	/* 5 basic drawing operations */
 
 	case CAIRO_COMMAND_PAINT:
 	    _cairo_pattern_fini (&command->paint.source.base);
 	    free (command);
 	    break;
 
@@ -179,19 +187,19 @@ static cairo_status_t
 _cairo_meta_surface_acquire_source_image (void			 *abstract_surface,
 					  cairo_image_surface_t	**image_out,
 					  void			**image_extra)
 {
     cairo_status_t status;
     cairo_meta_surface_t *surface = abstract_surface;
     cairo_surface_t *image;
 
-    image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-					surface->width_pixels,
-					surface->height_pixels);
+    image = _cairo_image_surface_create_with_content (surface->content,
+						      surface->width_pixels,
+						      surface->height_pixels);
 
     status = _cairo_meta_surface_replay (&surface->base, image);
     if (status) {
 	cairo_surface_destroy (image);
 	return status;
     }
 
     *image_out = (cairo_image_surface_t *) image;
@@ -238,37 +246,38 @@ static cairo_int_status_t
 _cairo_meta_surface_paint (void			*abstract_surface,
 			   cairo_operator_t	 op,
 			   cairo_pattern_t	*source)
 {
     cairo_status_t status;
     cairo_meta_surface_t *meta = abstract_surface;
     cairo_command_paint_t *command;
 
-    /* An optimisation that takes care to not replay what was done
-     * before surface is cleared. We don't erase recorded commands
-     * since we may have earlier snapshots of this surface. */
-    if (op == CAIRO_OPERATOR_CLEAR && !meta->is_clipped)
-	meta->replay_start_idx = meta->commands.num_elements;
-
     command = malloc (sizeof (cairo_command_paint_t));
     if (command == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
 
-    command->type = CAIRO_COMMAND_PAINT;
+    command->header.type = CAIRO_COMMAND_PAINT;
+    command->header.region = CAIRO_META_REGION_ALL;
     command->op = op;
 
     status = _init_pattern_with_snapshot (&command->source.base, source);
     if (status)
 	goto CLEANUP_COMMAND;
 
     status = _cairo_array_append (&meta->commands, &command);
     if (status)
 	goto CLEANUP_SOURCE;
 
+    /* An optimisation that takes care to not replay what was done
+     * before surface is cleared. We don't erase recorded commands
+     * since we may have earlier snapshots of this surface. */
+    if (op == CAIRO_OPERATOR_CLEAR && !meta->is_clipped)
+	meta->replay_start_idx = meta->commands.num_elements;
+
     return CAIRO_STATUS_SUCCESS;
 
   CLEANUP_SOURCE:
     _cairo_pattern_fini (&command->source.base);
   CLEANUP_COMMAND:
     free (command);
     return status;
 }
@@ -282,17 +291,18 @@ static cairo_int_status_t
     cairo_status_t status;
     cairo_meta_surface_t *meta = abstract_surface;
     cairo_command_mask_t *command;
 
     command = malloc (sizeof (cairo_command_mask_t));
     if (command == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
 
-    command->type = CAIRO_COMMAND_MASK;
+    command->header.type = CAIRO_COMMAND_MASK;
+    command->header.region = CAIRO_META_REGION_ALL;
     command->op = op;
 
     status = _init_pattern_with_snapshot (&command->source.base, source);
     if (status)
 	goto CLEANUP_COMMAND;
 
     status = _init_pattern_with_snapshot (&command->mask.base, mask);
     if (status)
@@ -327,17 +337,18 @@ static cairo_int_status_t
     cairo_status_t status;
     cairo_meta_surface_t *meta = abstract_surface;
     cairo_command_stroke_t *command;
 
     command = malloc (sizeof (cairo_command_stroke_t));
     if (command == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
 
-    command->type = CAIRO_COMMAND_STROKE;
+    command->header.type = CAIRO_COMMAND_STROKE;
+    command->header.region = CAIRO_META_REGION_ALL;
     command->op = op;
 
     status = _init_pattern_with_snapshot (&command->source.base, source);
     if (status)
 	goto CLEANUP_COMMAND;
 
     status = _cairo_path_fixed_init_copy (&command->path, path);
     if (status)
@@ -381,17 +392,18 @@ static cairo_int_status_t
     cairo_status_t status;
     cairo_meta_surface_t *meta = abstract_surface;
     cairo_command_fill_t *command;
 
     command = malloc (sizeof (cairo_command_fill_t));
     if (command == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
 
-    command->type = CAIRO_COMMAND_FILL;
+    command->header.type = CAIRO_COMMAND_FILL;
+    command->header.region = CAIRO_META_REGION_ALL;
     command->op = op;
 
     status = _init_pattern_with_snapshot (&command->source.base, source);
     if (status)
 	goto CLEANUP_COMMAND;
 
     status = _cairo_path_fixed_init_copy (&command->path, path);
     if (status)
@@ -427,17 +439,18 @@ static cairo_int_status_t
     cairo_status_t status;
     cairo_meta_surface_t *meta = abstract_surface;
     cairo_command_show_glyphs_t *command;
 
     command = malloc (sizeof (cairo_command_show_glyphs_t));
     if (command == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
 
-    command->type = CAIRO_COMMAND_SHOW_GLYPHS;
+    command->header.type = CAIRO_COMMAND_SHOW_GLYPHS;
+    command->header.region = CAIRO_META_REGION_ALL;
     command->op = op;
 
     status = _init_pattern_with_snapshot (&command->source.base, source);
     if (status)
 	goto CLEANUP_COMMAND;
 
     command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
     if (command->glyphs == NULL) {
@@ -516,17 +529,18 @@ static cairo_int_status_t
     cairo_meta_surface_t *meta = dst;
     cairo_command_intersect_clip_path_t *command;
     cairo_status_t status;
 
     command = malloc (sizeof (cairo_command_intersect_clip_path_t));
     if (command == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
 
-    command->type = CAIRO_COMMAND_INTERSECT_CLIP_PATH;
+    command->header.type = CAIRO_COMMAND_INTERSECT_CLIP_PATH;
+    command->header.region = CAIRO_META_REGION_ALL;
 
     if (path) {
 	status = _cairo_path_fixed_init_copy (&command->path, path);
 	if (status) {
 	    free (command);
 	    return status;
 	}
 	command->path_pointer = &command->path;
@@ -617,36 +631,38 @@ static const cairo_surface_backend_t cai
     _cairo_meta_surface_show_glyphs,
 
     _cairo_meta_surface_snapshot
 };
 
 static cairo_path_fixed_t *
 _cairo_command_get_path (cairo_command_t *command)
 {
-    switch (command->type) {
+    switch (command->header.type) {
     case CAIRO_COMMAND_PAINT:
     case CAIRO_COMMAND_MASK:
     case CAIRO_COMMAND_SHOW_GLYPHS:
 	return NULL;
     case CAIRO_COMMAND_STROKE:
 	return &command->stroke.path;
     case CAIRO_COMMAND_FILL:
 	return &command->fill.path;
     case CAIRO_COMMAND_INTERSECT_CLIP_PATH:
 	return command->intersect_clip_path.path_pointer;
     }
 
     ASSERT_NOT_REACHED;
     return NULL;
 }
 
-cairo_status_t
-_cairo_meta_surface_replay (cairo_surface_t *surface,
-			    cairo_surface_t *target)
+static cairo_status_t
+_cairo_meta_surface_replay_internal (cairo_surface_t	     *surface,
+				     cairo_surface_t	     *target,
+				     cairo_meta_replay_type_t type,
+				     cairo_meta_region_type_t region)
 {
     cairo_meta_surface_t *meta;
     cairo_command_t *command, **elements;
     int i, num_elements;
     cairo_int_status_t status;
     cairo_clip_t clip;
     cairo_bool_t has_device_transform = _cairo_surface_has_device_transform (target);
     cairo_matrix_t *device_transform = &target->device_transform;
@@ -660,34 +676,39 @@ cairo_status_t
 
     _cairo_clip_init (&clip, target);
 
     num_elements = meta->commands.num_elements;
     elements = _cairo_array_index (&meta->commands, 0);
     for (i = meta->replay_start_idx; i < num_elements; i++) {
 	command = elements[i];
 
+	if (type == CAIRO_META_REPLAY && region != CAIRO_META_REGION_ALL) {
+	    if (command->header.region != region)
+		continue;
+        }
+
 	/* For all commands except intersect_clip_path, we have to
 	 * ensure the current clip gets set on the surface. */
-	if (command->type != CAIRO_COMMAND_INTERSECT_CLIP_PATH) {
+	if (command->header.type != CAIRO_COMMAND_INTERSECT_CLIP_PATH) {
 	    status = _cairo_surface_set_clip (target, &clip);
 	    if (status)
 		break;
 	}
 
 	dev_path = _cairo_command_get_path (command);
 	if (dev_path && has_device_transform) {
 	    status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
 	    if (status)
 		break;
 	    _cairo_path_fixed_device_transform (&path_copy, device_transform);
 	    dev_path = &path_copy;
 	}
 
-	switch (command->type) {
+	switch (command->header.type) {
 	case CAIRO_COMMAND_PAINT:
 	    status = _cairo_surface_paint (target,
 					   command->paint.op,
 					   &command->paint.source.base);
 	    break;
 	case CAIRO_COMMAND_MASK:
 	    status = _cairo_surface_mask (target,
 					  command->mask.op,
@@ -715,24 +736,64 @@ cairo_status_t
 					    &command->stroke.style,
 					    &dev_ctm,
 					    &dev_ctm_inverse,
 					    command->stroke.tolerance,
 					    command->stroke.antialias);
 	    break;
 	}
 	case CAIRO_COMMAND_FILL:
-	    status = _cairo_surface_fill (target,
-					  command->fill.op,
-					  &command->fill.source.base,
-					  dev_path,
-					  command->fill.fill_rule,
-					  command->fill.tolerance,
-					  command->fill.antialias);
+	{
+	    cairo_command_t *stroke_command;
+
+	    stroke_command = (i < num_elements - 1) ? elements[i + 1] : NULL;
+
+	    if (stroke_command != NULL &&
+		stroke_command->header.type == CAIRO_COMMAND_STROKE &&
+		_cairo_path_fixed_is_equal (dev_path, _cairo_command_get_path (stroke_command))) {
+		cairo_matrix_t dev_ctm;
+		cairo_matrix_t dev_ctm_inverse;
+		cairo_matrix_t tmp;
+
+		dev_ctm = stroke_command->stroke.ctm;
+		dev_ctm_inverse = stroke_command->stroke.ctm_inverse;
+
+		if (has_device_transform) {
+		    cairo_matrix_multiply (&dev_ctm, &dev_ctm, device_transform);
+		    tmp = surface->device_transform;
+		    status = cairo_matrix_invert (&tmp);
+		    assert (status == CAIRO_STATUS_SUCCESS);
+		    cairo_matrix_multiply (&dev_ctm_inverse, &tmp, &dev_ctm_inverse);
+		}
+
+		status = _cairo_surface_fill_stroke (target,
+						     command->fill.op,
+						     &command->fill.source.base,
+						     command->fill.fill_rule,
+						     command->fill.tolerance,
+						     command->fill.antialias,
+						     dev_path,
+						     stroke_command->stroke.op,
+						     &stroke_command->stroke.source.base,
+						     &stroke_command->stroke.style,
+						     &dev_ctm,
+						     &dev_ctm_inverse,
+						     stroke_command->stroke.tolerance,
+						     stroke_command->stroke.antialias);
+		i++;
+	    } else
+		status = _cairo_surface_fill (target,
+					      command->fill.op,
+					      &command->fill.source.base,
+					      dev_path,
+					      command->fill.fill_rule,
+					      command->fill.tolerance,
+					      command->fill.antialias);
 	    break;
+	}
 	case CAIRO_COMMAND_SHOW_GLYPHS:
 	{
 	    cairo_glyph_t *glyphs = command->show_glyphs.glyphs;
 	    cairo_glyph_t *dev_glyphs = glyphs;
 	    int i, num_glyphs = command->show_glyphs.num_glyphs;
 
 	    if (has_device_transform) {
 		dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
@@ -765,24 +826,86 @@ cairo_status_t
 	    if (dev_path == NULL)
 		_cairo_clip_reset (&clip);
 	    else
 		status = _cairo_clip_clip (&clip, dev_path,
 					   command->intersect_clip_path.fill_rule,
 					   command->intersect_clip_path.tolerance,
 					   command->intersect_clip_path.antialias,
 					   target);
+            assert (status == 0);
 	    break;
 	default:
 	    ASSERT_NOT_REACHED;
 	}
 
 	if (dev_path == &path_copy)
 	    _cairo_path_fixed_fini (&path_copy);
 
+	if (type == CAIRO_META_CREATE_REGIONS) {
+	    if (status == CAIRO_STATUS_SUCCESS) {
+		command->header.region = CAIRO_META_REGION_NATIVE;
+	    } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) {
+		command->header.region = CAIRO_META_REGION_IMAGE_FALLBACK;
+		status = CAIRO_STATUS_SUCCESS;
+	    }
+	}
+
+	if (type == CAIRO_META_ANALYZE_META_PATTERN) {
+	    if (status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
+		status = CAIRO_STATUS_SUCCESS;
+	}
+
 	if (status)
 	    break;
     }
 
     _cairo_clip_reset (&clip);
 
     return status;
 }
+
+cairo_status_t
+_cairo_meta_surface_replay (cairo_surface_t *surface,
+			    cairo_surface_t *target)
+{
+    return _cairo_meta_surface_replay_internal (surface,
+						target,
+						CAIRO_META_REPLAY,
+						CAIRO_META_REGION_ALL);
+}
+
+cairo_status_t
+_cairo_meta_surface_replay_analyze_meta_pattern (cairo_surface_t *surface,
+						 cairo_surface_t *target)
+{
+    return _cairo_meta_surface_replay_internal (surface,
+						target,
+						CAIRO_META_ANALYZE_META_PATTERN,
+						CAIRO_META_REGION_ALL);
+}
+
+/* Replay meta to surface. When the return status of each operation is
+ * one of CAIRO_STATUS_SUCCESS, CAIRO_INT_STATUS_UNSUPPORTED, or
+ * CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY the status of each operation
+ * will be stored in the meta surface. Any other status will abort the
+ * replay and return the status.
+ */
+cairo_status_t
+_cairo_meta_surface_replay_and_create_regions (cairo_surface_t *surface,
+					       cairo_surface_t *target)
+{
+    return _cairo_meta_surface_replay_internal (surface,
+						target,
+						CAIRO_META_CREATE_REGIONS,
+						CAIRO_META_REGION_ALL);
+}
+
+cairo_status_t
+_cairo_meta_surface_replay_region (cairo_surface_t          *surface,
+				   cairo_surface_t          *target,
+				   cairo_meta_region_type_t  region)
+{
+    return _cairo_meta_surface_replay_internal (surface,
+						target,
+						CAIRO_META_REPLAY,
+						region);
+}
--- a/gfx/cairo/cairo/src/cairo-mutex-type-private.h
+++ b/gfx/cairo/cairo/src/cairo-mutex-type-private.h
@@ -44,19 +44,16 @@
 #if HAVE_CONFIG_H
 #include "config.h"
 #endif
 
 #include <cairo-features.h>
 
 CAIRO_BEGIN_DECLS
 
-#ifndef MOZILLA_CAIRO_NOT_DEFINED
-#define CAIRO_NO_MUTEX 1
-#endif
 
 /* A fully qualified no-operation statement */
 #define CAIRO_MUTEX_NOOP	do {/*no-op*/} while (0)
 /* And one that evaluates it's argument once */
 #define CAIRO_MUTEX_NOOP1(expr)        do { if (expr) ; } while (0)
 
 
 /* Cairo mutex implementation:
@@ -139,34 +136,23 @@ CAIRO_BEGIN_DECLS
  * - That is all.  If for any reason you think the above API is
  *   not enough to implement cairo_mutex_t on your system, please
  *   stop and write to the cairo mailing list about it.  DO NOT
  *   poke around cairo-mutex-private.h for possible solutions.
  */
 
 #if CAIRO_NO_MUTEX
 
-/* No mutex at all */
+/* No mutexes */
 
   typedef int cairo_mutex_t;
 
 # define CAIRO_MUTEX_INITIALIZE() CAIRO_MUTEX_NOOP
-# define CAIRO_MUTEX_LOCK(mutex) CAIRO_MUTEX_NOOP
-# define CAIRO_MUTEX_UNLOCK(mutex) CAIRO_MUTEX_NOOP
-# define CAIRO_MUTEX_NIL_INITIALIZER 0
-
-#elif CAIRO_POOR_MAN_MUTEX
-
-/* A poor man's mutex */
-
-  typedef int cairo_mutex_t;
-
-# define CAIRO_MUTEX_INITIALIZE() CAIRO_MUTEX_NOOP
-# define CAIRO_MUTEX_LOCK(mutex) do { while (mutex) ; (mutex) = 1; } while (0)
-# define CAIRO_MUTEX_UNLOCK(mutex) (mutex) = 0
+# define CAIRO_MUTEX_LOCK(mutex) CAIRO_MUTEX_NOOP1(mutex)
+# define CAIRO_MUTEX_UNLOCK(mutex) CAIRO_MUTEX_NOOP1(mutex)
 # define CAIRO_MUTEX_NIL_INITIALIZER 0
 
 #elif HAVE_PTHREAD_H /*******************************************************/
 
 # include <pthread.h>
 
   typedef pthread_mutex_t cairo_mutex_t;
 
--- a/gfx/cairo/cairo/src/cairo-os2-private.h
+++ b/gfx/cairo/cairo/src/cairo-os2-private.h
@@ -45,17 +45,17 @@
 #define INCL_GPI
 #ifdef __WATCOMC__
 # include <os2.h>
 #else
 # include <os2emx.h>
 #endif
 
 #include <cairo-os2.h>
-#include <cairoint.h>
+#include "cairoint.h"
 
 typedef struct _cairo_os2_surface
 {
     cairo_surface_t        base;
 
     /* Mutex semaphore to protect private fields from concurrent access */
     HMTX                   hmtx_use_private_fields;
     /* Private fields: */
--- a/gfx/cairo/cairo/src/cairo-paginated-private.h
+++ b/gfx/cairo/cairo/src/cairo-paginated-private.h
@@ -128,9 +128,14 @@ cairo_private cairo_surface_t *
 				 const cairo_paginated_surface_backend_t	*backend);
 
 cairo_private cairo_surface_t *
 _cairo_paginated_surface_get_target (cairo_surface_t *surface);
 
 cairo_private cairo_bool_t
 _cairo_surface_is_paginated (cairo_surface_t *surface);
 
+cairo_private cairo_status_t
+_cairo_paginated_surface_set_size (cairo_surface_t 	*surface,
+				   int			 width,
+				   int			 height);
+
 #endif /* CAIRO_PAGINATED_H */
--- a/gfx/cairo/cairo/src/cairo-paginated-surface.c
+++ b/gfx/cairo/cairo/src/cairo-paginated-surface.c
@@ -1,11 +1,12 @@
 /* cairo - a vector graphics library with display and print output
  *
  * Copyright © 2005 Red Hat, Inc
+ * Copyright © 2007 Adrian Johnson
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
  * License version 2.1 as published by the Free Software Foundation
  * (the "LGPL") or, at your option, under the terms of the Mozilla
  * Public License Version 1.1 (the "MPL"). If you do not alter this
  * notice, a recipient may use your version of this file under either
  * the MPL or the LGPL.
@@ -27,16 +28,17 @@
  *
  * The Original Code is the cairo graphics library.
  *
  * The Initial Developer of the Original Code is Red Hat, Inc.
  *
  * Contributor(s):
  *	Carl Worth <cworth@cworth.org>
  *	Keith Packard <keithp@keithp.com>
+ *	Adrian Johnson <ajohnson@redneon.com>
  */
 
 /* The paginated surface layer exists to provide as much code sharing
  * as possible for the various paginated surface backends in cairo
  * (PostScript, PDF, etc.). See cairo-paginated-private.h for
  * more details on how it works and how to use it.
  */
 
@@ -58,16 +60,17 @@ static cairo_surface_t *
 					 int			 width,
 					 int			 height)
 {
     cairo_paginated_surface_t *surface = abstract_surface;
     return cairo_surface_create_similar (surface->target, content,
 					 width, height);
 }
 
+/* XXX The integer width,height here should be doubles and all uses updated */
 cairo_surface_t *
 _cairo_paginated_surface_create (cairo_surface_t				*target,
 				 cairo_content_t				 content,
 				 int						 width,
 				 int						 height,
 				 const cairo_paginated_surface_backend_t	*backend)
 {
     cairo_paginated_surface_t *surface;
@@ -120,16 +123,39 @@ cairo_surface_t *
 
     assert (_cairo_surface_is_paginated (surface));
 
     paginated_surface = (cairo_paginated_surface_t *) surface;
 
     return paginated_surface->target;
 }
 
+cairo_status_t
+_cairo_paginated_surface_set_size (cairo_surface_t 	*surface,
+				   int			 width,
+				   int			 height)
+{
+    cairo_paginated_surface_t *paginated_surface;
+
+    assert (_cairo_surface_is_paginated (surface));
+
+    paginated_surface = (cairo_paginated_surface_t *) surface;
+
+    paginated_surface->width = width;
+    paginated_surface->height = height;
+
+    cairo_surface_destroy (paginated_surface->meta);
+    paginated_surface->meta = _cairo_meta_surface_create (paginated_surface->content,
+							  width, height);
+    if (cairo_surface_status (paginated_surface->meta))
+	return cairo_surface_status (paginated_surface->meta);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
 static cairo_status_t
 _cairo_paginated_surface_finish (void *abstract_surface)
 {
     cairo_paginated_surface_t *surface = abstract_surface;
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
     if (surface->page_is_blank == FALSE || surface->page_num == 1)
 	status = _cairo_paginated_surface_show_page (abstract_surface);
@@ -204,68 +230,152 @@ static void
 _cairo_paginated_surface_release_source_image (void	  *abstract_surface,
 					       cairo_image_surface_t *image,
 					       void	       *image_extra)
 {
     cairo_surface_destroy (&image->base);
 }
 
 static cairo_int_status_t
+_paint_fallback_image (cairo_paginated_surface_t *surface,
+		       cairo_box_int_t           *box)
+{
+    double x_scale = surface->base.x_fallback_resolution / surface->base.x_resolution;
+    double y_scale = surface->base.y_fallback_resolution / surface->base.y_resolution;
+    cairo_matrix_t matrix;
+    int x, y, width, height;
+    cairo_status_t status;
+    cairo_surface_t *image;
+    cairo_pattern_t *pattern;
+
+    x = box->p1.x;
+    y = box->p1.y;
+    width = box->p2.x - x;
+    height = box->p2.y - y;
+    image = _cairo_paginated_surface_create_image_surface (surface,
+							   width  * x_scale,
+							   height * y_scale);
+    _cairo_surface_set_device_scale (image, x_scale, y_scale);
+    /* set_device_offset just sets the x0/y0 components of the matrix;
+     * so we have to do the scaling manually. */
+    cairo_surface_set_device_offset (image, -x*x_scale, -y*y_scale);
+
+    status = _cairo_meta_surface_replay (surface->meta, image);
+    if (status)
+	goto CLEANUP_IMAGE;
+
+    pattern = cairo_pattern_create_for_surface (image);
+    cairo_matrix_init (&matrix, x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale);
+    cairo_pattern_set_matrix (pattern, &matrix);
+
+    status = _cairo_surface_paint (surface->target,
+				   CAIRO_OPERATOR_SOURCE,
+				   pattern);
+
+    cairo_pattern_destroy (pattern);
+CLEANUP_IMAGE:
+    cairo_surface_destroy (image);
+
+    return status;
+}
+
+static cairo_int_status_t
 _paint_page (cairo_paginated_surface_t *surface)
 {
     cairo_surface_t *analysis;
-    cairo_surface_t *image;
-    cairo_pattern_t *pattern;
     cairo_status_t status;
+    cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback;
 
     analysis = _cairo_analysis_surface_create (surface->target,
 					       surface->width, surface->height);
     if (analysis == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
 
     surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_ANALYZE);
-    status = _cairo_meta_surface_replay (surface->meta, analysis);
+    status = _cairo_meta_surface_replay_and_create_regions (surface->meta, analysis);
     surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_RENDER);
 
     if (status || analysis->status) {
 	if (status == CAIRO_STATUS_SUCCESS)
 	    status = analysis->status;
 	cairo_surface_destroy (analysis);
 	return status;
     }
 
-    if (_cairo_analysis_surface_has_unsupported (analysis))
-    {
-	double x_scale = surface->base.x_fallback_resolution / 72.0;
-	double y_scale = surface->base.y_fallback_resolution / 72.0;
-	cairo_matrix_t matrix;
+    /* Finer grained fallbacks are currently only supported for some
+     * surface types */
+    switch (surface->target->type) {
+        case CAIRO_SURFACE_TYPE_PDF:
+        case CAIRO_SURFACE_TYPE_PS:
+        case CAIRO_SURFACE_TYPE_WIN32_PRINTING:
+            has_supported = _cairo_analysis_surface_has_supported (analysis);
+            has_page_fallback = FALSE;
+            has_finegrained_fallback = _cairo_analysis_surface_has_unsupported (analysis);
+            break;
 
-	image = _cairo_paginated_surface_create_image_surface (surface,
-							       surface->width  * x_scale,
-							       surface->height * y_scale);
-	_cairo_surface_set_device_scale (image, x_scale, y_scale);
+        default:
+            if (_cairo_analysis_surface_has_unsupported (analysis)) {
+                has_supported = FALSE;
+                has_page_fallback = TRUE;
+            } else {
+                has_supported = TRUE;
+                has_page_fallback = FALSE;
+            }
+            has_finegrained_fallback = FALSE;
+            break;
+    }
 
-	status = _cairo_meta_surface_replay (surface->meta, image);
+    if (has_supported) {
+	status = _cairo_meta_surface_replay_region (surface->meta,
+						    surface->target,
+						    CAIRO_META_REGION_NATIVE);
 	if (status)
-	    goto CLEANUP_IMAGE;
+	    return status;
+    }
+
+    if (has_page_fallback)
+    {
+	cairo_box_int_t box;
 
-	pattern = cairo_pattern_create_for_surface (image);
-	cairo_matrix_init_scale (&matrix, x_scale, y_scale);
-	cairo_pattern_set_matrix (pattern, &matrix);
+	box.p1.x = 0;
+	box.p1.y = 0;
+	box.p2.x = surface->width;
+	box.p2.y = surface->height;
+	status = _paint_fallback_image (surface, &box);
+	if (status)
+	    return status;
+    }
 
-	status = _cairo_surface_paint (surface->target, CAIRO_OPERATOR_SOURCE, pattern);
+    if (has_finegrained_fallback)
+    {
+        cairo_region_t *region;
+        cairo_box_int_t *boxes;
+        int num_boxes, i;
 
-	cairo_pattern_destroy (pattern);
+	/* Reset clip region before drawing the fall back images */
+	status = _cairo_surface_intersect_clip_path (surface->target,
+						     NULL,
+						     CAIRO_FILL_RULE_WINDING,
+						     CAIRO_GSTATE_TOLERANCE_DEFAULT,
+						     CAIRO_ANTIALIAS_DEFAULT);
+	if (status)
+	    return status;
 
-     CLEANUP_IMAGE:
-	cairo_surface_destroy (image);
-    }
-    else
-    {
-	status = _cairo_meta_surface_replay (surface->meta, surface->target);
+	region = _cairo_analysis_surface_get_unsupported (analysis);
+	status = _cairo_region_get_boxes (region, &num_boxes, &boxes);
+	if (status)
+	    return status;
+	for (i = 0; i < num_boxes; i++) {
+	    status = _paint_fallback_image (surface, &boxes[i]);
+	    if (status) {
+                _cairo_region_boxes_fini (region, boxes);
+		return status;
+            }
+	}
+        _cairo_region_boxes_fini (region, boxes);
     }
 
     cairo_surface_destroy (analysis);
 
     return status;
 }
 
 static cairo_status_t
@@ -289,41 +399,40 @@ static cairo_int_status_t
 
     status = _paint_page (surface);
     if (status)
 	return status;
 
     surface->page_num++;
 
     /* XXX: It might make sense to add some suport here for calling
-     * _cairo_surface_copy_page on the target surface. It would be an
-     * optimization for the output, (so that PostScript could include
-     * copypage, for example), but the interaction with image
+     * cairo_surface_copy_page on the target surface. It would be an
+     * optimization for the output, but the interaction with image
      * fallbacks gets tricky. For now, we just let the target see a
      * show_page and we implement the copying by simply not destroying
      * the meta-surface. */
 
-    return _cairo_surface_show_page (surface->target);
+    return cairo_surface_show_page (surface->target);
 }
 
 static cairo_int_status_t
 _cairo_paginated_surface_show_page (void *abstract_surface)
 {
     cairo_status_t status;
     cairo_paginated_surface_t *surface = abstract_surface;
 
     status = _start_page (surface);
     if (status)
 	return status;
 
     status = _paint_page (surface);
     if (status)
 	return status;
 
-    status = _cairo_surface_show_page (surface->target);
+    status = cairo_surface_show_page (surface->target);
     if (status)
 	return status;
 
     if (cairo_surface_status (surface->meta))
 	return cairo_surface_status (surface->meta);
 
     cairo_surface_destroy (surface->meta);
 
--- a/gfx/cairo/cairo/src/cairo-path-fixed-private.h
+++ b/gfx/cairo/cairo/src/cairo-path-fixed-private.h
@@ -31,23 +31,24 @@
  *
  * Contributor(s):
  *	Carl D. Worth <cworth@redhat.com>
  */
 
 #ifndef CAIRO_PATH_FIXED_PRIVATE_H
 #define CAIRO_PATH_FIXED_PRIVATE_H
 
-typedef enum cairo_path_op {
+enum cairo_path_op {
     CAIRO_PATH_OP_MOVE_TO = 0,
     CAIRO_PATH_OP_LINE_TO = 1,
     CAIRO_PATH_OP_CURVE_TO = 2,
     CAIRO_PATH_OP_CLOSE_PATH = 3
-} __attribute__ ((packed)) cairo_path_op_t; /* Don't want 32 bits if we can avoid it. */
-/* XXX Shall we just not use char instead of hoping for __attribute__ working? */
+};
+/* we want to make sure a single byte is used for thie enum */
+typedef char cairo_path_op_t;
 
 /* make cairo_path_fixed fit a 512 bytes.  about 50 items */
 #define CAIRO_PATH_BUF_SIZE ((512 - 12 * sizeof (void*)) \
 			   / (sizeof (cairo_point_t) + sizeof (cairo_path_op_t)))
 
 typedef struct _cairo_path_buf {
     struct _cairo_path_buf *next, *prev;
     int num_ops;
--- a/gfx/cairo/cairo/src/cairo-path-fixed.c
+++ b/gfx/cairo/cairo/src/cairo-path-fixed.c
@@ -508,27 +508,23 @@ static void
 				    cairo_fixed_t scalex,
 				    cairo_fixed_t scaley)
 {
     cairo_path_buf_t *buf = path->buf_head;
     int i;
 
     while (buf) {
 	 for (i = 0; i < buf->num_points; i++) {
-	     if (scalex == CAIRO_FIXED_ONE) {
-		 buf->points[i].x += offx;
-	     } else {
-		 buf->points[i].x = _cairo_fixed_mul (buf->points[i].x + offx, scalex);
-	     }
+	     if (scalex != CAIRO_FIXED_ONE)
+		 buf->points[i].x = _cairo_fixed_mul (buf->points[i].x, scalex);
+	     buf->points[i].x += offx;
 
-	     if (scaley == CAIRO_FIXED_ONE) {
-		 buf->points[i].y += offy;
-	     } else {
-		 buf->points[i].y = _cairo_fixed_mul (buf->points[i].y + offy, scaley);
-	     }
+	     if (scaley != CAIRO_FIXED_ONE)
+		 buf->points[i].y = _cairo_fixed_mul (buf->points[i].y, scaley);
+	     buf->points[i].y += offy;
 	 }
 
 	 buf = buf->next;
     }
 }
 
 
 /**
@@ -541,18 +537,43 @@ static void
  * given matrix has no rotation or shear elements, (that is, xy and yx
  * are 0.0).
  **/
 void
 _cairo_path_fixed_device_transform (cairo_path_fixed_t	*path,
 				    cairo_matrix_t	*device_transform)
 {
     assert (device_transform->yx == 0.0 && device_transform->xy == 0.0);
-    /* XXX: FRAGILE: I'm not really sure whether we're doing the
-     * "right" thing here if there is both scaling and translation in
-     * the matrix. But for now, the internals guarantee that we won't
-     * really ever have both going on. */
+    /* XXX: Support freeform matrices someday (right now, only translation and scale
+     * work. */
     _cairo_path_fixed_offset_and_scale (path,
 					_cairo_fixed_from_double (device_transform->x0),
 					_cairo_fixed_from_double (device_transform->y0),
 					_cairo_fixed_from_double (device_transform->xx),
 					_cairo_fixed_from_double (device_transform->yy));
 }
+
+cairo_bool_t
+_cairo_path_fixed_is_equal (cairo_path_fixed_t *path,
+			    cairo_path_fixed_t *other)
+{
+    cairo_path_buf_t *path_buf, *other_buf;
+
+    if (path->current_point.x != other->current_point.x ||
+	path->current_point.y != other->current_point.y ||
+	path->has_current_point != other->has_current_point ||
+	path->has_curve_to != other->has_curve_to ||
+	path->last_move_point.x != other->last_move_point.x ||
+	path->last_move_point.y != other->last_move_point.y)
+	return FALSE;
+
+    other_buf = other->buf_head;
+    for (path_buf = path->buf_head; path_buf != NULL; path_buf = path_buf->next) {
+	if (other_buf == NULL ||
+	    path_buf->num_ops != other_buf->num_ops ||
+	    path_buf->num_points != other_buf->num_points ||
+	    memcmp (path_buf->op, other_buf->op, path_buf->num_ops) != 0 ||
+	    memcmp (path_buf->points, other_buf->points, path_buf->num_points != 0))
+	    return FALSE;
+	other_buf = other_buf->next;
+    }
+    return TRUE;
+}
--- a/gfx/cairo/cairo/src/cairo-path-stroke.c
+++ b/gfx/cairo/cairo/src/cairo-path-stroke.c
@@ -232,31 +232,23 @@ static cairo_status_t
     case CAIRO_LINE_JOIN_ROUND: {
 	int i;
 	int start, step, stop;
 	cairo_point_t tri[3];
 	cairo_pen_t *pen = &stroker->pen;
 
 	tri[0] = in->point;
 	if (clockwise) {
-	    status = _cairo_pen_find_active_ccw_vertex_index (pen, &in->dev_vector, &start);
-	    if (status)
-		return status;
+	    _cairo_pen_find_active_ccw_vertex_index (pen, &in->dev_vector, &start);
 	    step = -1;
-	    status = _cairo_pen_find_active_ccw_vertex_index (pen, &out->dev_vector, &stop);
-	    if (status)
-		return status;
+	    _cairo_pen_find_active_ccw_vertex_index (pen, &out->dev_vector, &stop);
 	} else {
-	    status = _cairo_pen_find_active_cw_vertex_index (pen, &in->dev_vector, &start);
-	    if (status)
-		return status;
+	    _cairo_pen_find_active_cw_vertex_index (pen, &in->dev_vector, &start);
 	    step = +1;
-	    status = _cairo_pen_find_active_cw_vertex_index (pen, &out->dev_vector, &stop);
-	    if (status)
-		return status;
+	    _cairo_pen_find_active_cw_vertex_index (pen, &out->dev_vector, &stop);
 	}
 
 	i = start;
 	tri[1] = *inpt;
 	while (i != stop) {
 	    tri[2] = in->point;
 	    _translate_point (&tri[2], &pen->vertices[i].point);
 	    status = _cairo_traps_tessellate_triangle (stroker->traps, tri);
@@ -389,24 +381,20 @@ static cairo_status_t
     case CAIRO_LINE_CAP_ROUND: {
 	int i;
 	int start, stop;
 	cairo_slope_t slope;
 	cairo_point_t tri[3];
 	cairo_pen_t *pen = &stroker->pen;
 
 	slope = f->dev_vector;
-	status = _cairo_pen_find_active_cw_vertex_index (pen, &slope, &start);
-	if (status)
-	    return status;
+	_cairo_pen_find_active_cw_vertex_index (pen, &slope, &start);
 	slope.dx = -slope.dx;
 	slope.dy = -slope.dy;
-	status = _cairo_pen_find_active_cw_vertex_index (pen, &slope, &stop);
-	if (status)
-	    return status;
+	_cairo_pen_find_active_cw_vertex_index (pen, &slope, &stop);
 
 	tri[0] = f->point;
 	tri[1] = f->cw;
 	for (i=start; i != stop; i = (i+1) % pen->num_vertices) {
 	    tri[2] = f->point;
 	    _translate_point (&tri[2], &pen->vertices[i].point);
 	    status = _cairo_traps_tessellate_triangle (stroker->traps, tri);
 	    if (status)
--- a/gfx/cairo/cairo/src/cairo-pattern.c
+++ b/gfx/cairo/cairo/src/cairo-pattern.c
@@ -180,17 +180,19 @@ cairo_status_t
 
 	status = _cairo_gradient_pattern_init_copy (dst, src);
 	if (status)
 	    return status;
 
     } break;
     }
 
+    /* The reference count and user_data array are unique to the copy. */
     pattern->ref_count = 1;
+    _cairo_user_data_array_init (&pattern->user_data);
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 void
 _cairo_pattern_fini (cairo_pattern_t *pattern)
 {
     _cairo_user_data_array_fini (&pattern->user_data);
@@ -1205,17 +1207,17 @@ static cairo_int_status_t
 
     if (pixman_image == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
 
     if (_cairo_surface_is_image (dst))
     {
 	image = (cairo_image_surface_t *)
 	    _cairo_image_surface_create_for_pixman_image (pixman_image,
-							  CAIRO_FORMAT_ARGB32);
+							  PIXMAN_a8r8g8b8);
 	if (image->base.status)
 	{
 	    pixman_image_unref (pixman_image);
 	    return CAIRO_STATUS_NO_MEMORY;
 	}
 
 	attr->x_offset = attr->y_offset = 0;
 	attr->matrix = pattern->base.matrix;
@@ -1670,48 +1672,16 @@ static cairo_int_status_t
 		height = MIN (extents.height, ceil (y2) + 1) - y;
 	    }
 	    x += tx;
 	    y += ty;
 	}
 
 	status = _cairo_surface_clone_similar (dst, pattern->surface,
 					       x, y, width, height, out);
-
-	if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
-
-	    cairo_t *cr;
-
-	    *out = cairo_surface_create_similar (dst, dst->content,
-						 width, height);
-	    status = cairo_surface_status (*out);
-	    if (status) {
-		cairo_surface_destroy (*out);
-		*out = NULL;
-		return status;
-	    }
-
-	    (*out)->device_transform = pattern->surface->device_transform;
-	    (*out)->device_transform_inverse = pattern->surface->device_transform_inverse;
-
-	    /* XXX Use _cairo_surface_composite directly */
-	    cr = cairo_create (*out);
-
-	    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
-	    cairo_set_source_surface (cr, pattern->surface, -x, -y);
-	    cairo_paint (cr);
-
-	    status = cairo_status (cr);
-	    cairo_destroy (cr);
-
-	    if (status) {
-		cairo_surface_destroy (*out);
-		*out = NULL;
-	    }
-	}
     }
 
     return status;
 }
 
 /**
  * _cairo_pattern_acquire_surface:
  * @pattern: a #cairo_pattern_t
@@ -1972,18 +1942,18 @@ cairo_status_t
 	cairo_bool_t set = FALSE;
 
 	status = _cairo_surface_get_extents (surface, &surface_extents);
 	if (status)
 	    return status;
 
 	imatrix = pattern->matrix;
 	status = cairo_matrix_invert (&imatrix);
-	if (status)
-	    return status;
+	/* cairo_pattern_set_matrix ensures the matrix is invertible */
+	assert (status == CAIRO_STATUS_SUCCESS);
 
 	/* XXX Use _cairo_matrix_transform_bounding_box here */
 	for (sy = 0; sy <= 1; sy++) {
 	    for (sx = 0; sx <= 1; sx++) {
 		x = surface_extents.x + sx * surface_extents.width;
 		y = surface_extents.y + sy * surface_extents.height;
 		cairo_matrix_transform_point (&imatrix, &x, &y);
 		if (x < 0) x = 0;
--- a/gfx/cairo/cairo/src/cairo-pdf-surface-private.h
+++ b/gfx/cairo/cairo/src/cairo-pdf-surface-private.h
@@ -1,12 +1,13 @@
 /* cairo - a vector graphics library with display and print output
  *
  * Copyright © 2004 Red Hat, Inc
  * Copyright © 2006 Red Hat, Inc
+ * Copyright © 2007 Adrian Johnson
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
  * License version 2.1 as published by the Free Software Foundation
  * (the "LGPL") or, at your option, under the terms of the Mozilla
  * Public License Version 1.1 (the "MPL"). If you do not alter this
  * notice, a recipient may use your version of this file under either
  * the MPL or the LGPL.
@@ -29,77 +30,102 @@
  * The Original Code is the cairo graphics library.
  *
  * The Initial Developer of the Original Code is University of Southern
  * California.
  *
  * Contributor(s):
  *	Kristian Høgsberg <krh@redhat.com>
  *	Carl Worth <cworth@cworth.org>
+ *	Adrian Johnson <ajohnson@redneon.com>
  */
 
 #ifndef CAIRO_PDF_SURFACE_PRIVATE_H
 #define CAIRO_PDF_SURFACE_PRIVATE_H
 
 #include "cairo-pdf.h"
 
 #include "cairo-surface-private.h"
 
 typedef struct _cairo_pdf_resource {
     unsigned int id;
 } cairo_pdf_resource_t;
 
+typedef struct _cairo_pdf_group_resources {
+    cairo_array_t alphas;
+    cairo_array_t smasks;
+    cairo_array_t patterns;
+    cairo_array_t xobjects;
+    cairo_array_t fonts;
+} cairo_pdf_group_resources_t;
+
 typedef struct _cairo_pdf_surface cairo_pdf_surface_t;
 
 struct _cairo_pdf_surface {
     cairo_surface_t base;
 
     /* Prefer the name "output" here to avoid confusion over the
      * structure within a PDF document known as a "stream". */
     cairo_output_stream_t *output;
 
     double width;
     double height;
     cairo_matrix_t cairo_to_pdf;
 
     cairo_array_t objects;
     cairo_array_t pages;
-    cairo_array_t patterns;
-    cairo_array_t xobjects;
-    cairo_array_t streams;
-    cairo_array_t alphas;
-    cairo_array_t smasks;
     cairo_array_t rgb_linear_functions;
     cairo_array_t alpha_linear_functions;
+    cairo_array_t knockout_group;
+    cairo_array_t content_group;
 
     cairo_scaled_font_subsets_t *font_subsets;
     cairo_array_t fonts;
 
     cairo_pdf_resource_t next_available_resource;
     cairo_pdf_resource_t pages_resource;
 
     struct {
 	cairo_bool_t active;
 	cairo_pdf_resource_t self;
 	cairo_pdf_resource_t length;
 	long start_offset;
-        cairo_bool_t compressed;
-        cairo_output_stream_t *old_output;
-    } current_stream;
+	cairo_bool_t compressed;
+	cairo_output_stream_t *old_output;
+    } pdf_stream;
+
+    struct {
+	cairo_bool_t active;
+	cairo_output_stream_t *stream;
+	cairo_output_stream_t *old_output;
+	cairo_pdf_group_resources_t resources;
+	cairo_bool_t is_knockout;
+	cairo_pdf_resource_t first_object;
+    } group_stream;
 
     struct {
-        cairo_pattern_type_t type;
-        double red;
-        double green;
-        double blue;
-        int alpha;
-        cairo_pdf_resource_t smask;
-        cairo_pdf_resource_t pattern;
+	cairo_bool_t active;
+	cairo_output_stream_t *stream;
+	cairo_output_stream_t *old_output;
+	cairo_pdf_group_resources_t resources;
+    } content_stream;
+
+    struct {
+	cairo_pattern_type_t type;
+	double red;
+	double green;
+	double blue;
+	double alpha;
+	cairo_pdf_resource_t smask;
+	cairo_pdf_resource_t pattern;
     } emitted_pattern;
 
-    cairo_bool_t has_clip;
+    cairo_array_t *current_group;
+    cairo_pdf_group_resources_t *current_resources;
 
     cairo_paginated_mode_t paginated_mode;
 
     cairo_bool_t force_fallbacks;
+
+    cairo_surface_t *paginated_surface;
 };
 
 #endif /* CAIRO_PDF_SURFACE_PRIVATE_H */
--- a/gfx/cairo/cairo/src/cairo-pdf-surface.c
+++ b/gfx/cairo/cairo/src/cairo-pdf-surface.c
@@ -1,12 +1,13 @@
 /* cairo - a vector graphics library with display and print output
  *
  * Copyright © 2004 Red Hat, Inc
  * Copyright © 2006 Red Hat, Inc
+ * Copyright © 2007 Adrian Johnson
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
  * License version 2.1 as published by the Free Software Foundation
  * (the "LGPL") or, at your option, under the terms of the Mozilla
  * Public License Version 1.1 (the "MPL"). If you do not alter this
  * notice, a recipient may use your version of this file under either
  * the MPL or the LGPL.
@@ -29,67 +30,162 @@
  * The Original Code is the cairo graphics library.
  *
  * The Initial Developer of the Original Code is University of Southern
  * California.
  *
  * Contributor(s):
  *	Kristian Høgsberg <krh@redhat.com>
  *	Carl Worth <cworth@cworth.org>
+ *	Adrian Johnson <ajohnson@redneon.com>
  */
 
 #include "cairoint.h"
 #include "cairo-pdf.h"
 #include "cairo-pdf-surface-private.h"
 #include "cairo-scaled-font-subsets-private.h"
 #include "cairo-paginated-private.h"
 #include "cairo-path-fixed-private.h"
 #include "cairo-output-stream-private.h"
+#include "cairo-meta-surface-private.h"
 
 #include <time.h>
 #include <zlib.h>
 
 /* Issues:
  *
- * - Why doesn't pages inherit /alpha%d GS dictionaries from the Pages
- *   object?
- *
  * - We embed an image in the stream each time it's composited.  We
  *   could add generation counters to surfaces and remember the stream
  *   ID for a particular generation for a particular surface.
  *
- * - Clipping: must be able to reset clipping
- *
  * - Images of other formats than 8 bit RGBA.
  *
  * - Backend specific meta data.
  *
  * - Surface patterns.
  *
  * - Should/does cairo support drawing into a scratch surface and then
  *   using that as a fill pattern?  For this backend, that would involve
  *   using a tiling pattern (4.6.2).  How do you create such a scratch
  *   surface?  cairo_surface_create_similar() ?
  *
  * - What if you create a similar surface and does show_page and then
  *   does show_surface on another surface?
  *
- * - Output TM so page scales to the right size - PDF default user
- *   space has 1 unit = 1 / 72 inch.
- *
  * - Add test case for RGBA images.
  *
  * - Add test case for RGBA gradients.
  *
  * - Coordinate space for create_similar() args?
+ */
+
+/*
+ * Page Structure of the Generated PDF:
  *
- * - Investigate /Matrix entry in content stream dicts for pages
- *   instead of outputting the cm operator in every page.
+ * Each page requiring fallbacks images contains a knockout group at
+ * the top level. The first operation of the knockout group paints a
+ * group containing all the supported drawing operations. Fallback
+ * images (if any) are painted in the knockout group. This ensures
+ * that fallback images do not composite with any content under the
+ * fallback images.
+ *
+ * The group containing the supported operations (content_group_list
+ * in the example below) does not do any drawing directly. Instead it
+ * paints groups containing the drawing operations and performs
+ * clipping. The reason for this is that clipping operations performed
+ * in a group do not affect the parent group.
+ *
+ * Example PDF Page Structure:
+ *
+ *   Page Content
+ *   ------------
+ *     /knockout_group Do
+ *
+ *   knockout_group
+ *   --------------
+ *     /content_group_list Do
+ *     /fallback_image_1 Do
+ *     /fallback_image_2 Do
+ *     ...
+ *
+ *   content_group_list
+ *   ------------------
+ *     q
+ *     /content_group_1 Do
+ *     /content_group_2 Do
+ *     10 10 m 10 20 l 20 20 l 20 10 l h W  # clip
+ *     /content_group_3 Do
+ *     Q q                                  # reset clip
+ *     /content_group_4 Do
+ *     Q
+ *
+ *
+ * Streams:
+ *
+ * This PDF surface has three types of streams:
+ *  - PDF Stream
+ *  - Content Stream
+ *  - Group Stream
+ *
+ * Calling _cairo_output_stream_printf (surface->output, ...) will
+ * write to the currently open stream.
+ *
+ * PDF Stream:
+ *   A PDF Stream may be opened and closed with the following functions:
+ *     _cairo_pdf_surface_open_stream ()
+ *     _cairo_pdf_surface_close_stream ()
+ *
+ *   PDF Streams are written directly to the PDF file. They are used for
+ *   fonts, images and patterns.
+ *
+ * Content Stream:
+ *   The Content Stream is opened and closed with the following functions:
+ *     _cairo_pdf_surface_start_content_stream ()
+ *     _cairo_pdf_surface_stop_content_stream ()
+ *
+ *   The Content Stream is written to content_group_n groups (as shown
+ *   in the page structure example). The Content Stream may be paused
+ *   and resumed with the following functions:
+ *     _cairo_pdf_surface_pause_content_stream ()
+ *     _cairo_pdf_surface_resume_content_stream ()
+ *
+ *   When the Content Stream is paused, a PDF Stream or Group Stream
+ *   may be opened. After closing the PDF Stream or Group Stream the
+ *   Content Stream may be resumed.
+ *
+ *   The Content Stream contains the text and graphics operators. When
+ *   a pattern is required the Content Stream is paused, a PDF Stream
+ *   is opened, the pattern is written to a PDF Stream, the PDF Stream
+ *   is closed, then the Content Stream is resumed.
+ *
+ *   Each group comprising the Content Stream is stored in memory
+ *   until the stream is closed or the maximum group size is
+ *   exceeded. This is due to the need to list all resources used in
+ *   the group in the group's stream dictionary.
+ *
+ * Group Stream:
+ *   A Group Stream may be opened and closed with the following functions:
+ *     _cairo_pdf_surface_open_group ()
+ *     _cairo_pdf_surface_close_group ()
+ *
+ *   A Group Stream is written to a separate group in the PDF file
+ *   that is not part of the Content Stream. Group Streams are also
+ *   stored in memory until the stream is closed due to the need to
+ *   list the resources used in the group in the group's stream
+ *   dictionary.
+ *
+ *   Group Streams are used for short sequences of graphics operations
+ *   that need to be in a separate group from the Content Stream.
  */
 
+/* The group stream length is checked after each operation. When this
+ * limit is exceeded the group is written out to the pdf stream and a
+ * new group is created. */
+#define GROUP_STREAM_LIMIT 65536
+
 typedef struct _cairo_pdf_object {
     long offset;
 } cairo_pdf_object_t;
 
 typedef struct _cairo_pdf_font {
     unsigned int font_id;
     unsigned int subset_id;
     cairo_pdf_resource_t subset_resource;
@@ -102,47 +198,70 @@ typedef struct _cairo_pdf_rgb_linear_fun
 } cairo_pdf_rgb_linear_function_t;
 
 typedef struct _cairo_pdf_alpha_linear_function {
     cairo_pdf_resource_t resource;
     double               alpha1;
     double               alpha2;
 } cairo_pdf_alpha_linear_function_t;
 
+typedef enum group_element_type {
+    ELEM_GROUP,
+    ELEM_CLIP
+} group_element_type_t;
+
+typedef struct _cairo_pdf_group_element {
+    group_element_type_t  type;
+    cairo_pdf_resource_t  group;
+    cairo_path_fixed_t   *clip_path;
+    cairo_fill_rule_t     fill_rule;
+} cairo_pdf_group_element_t;
+
+
 static cairo_pdf_resource_t
 _cairo_pdf_surface_new_object (cairo_pdf_surface_t *surface);
 
 static void
+_cairo_pdf_group_element_array_finish (cairo_array_t *array);
+
+static void
 _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface);
 
+static void
+_cairo_pdf_group_resources_init (cairo_pdf_group_resources_t *res);
+
 static cairo_pdf_resource_t
 _cairo_pdf_surface_open_stream (cairo_pdf_surface_t	*surface,
                                 cairo_bool_t             compressed,
 				const char		*fmt,
 				...) CAIRO_PRINTF_FORMAT(3, 4);
 static cairo_status_t
 _cairo_pdf_surface_close_stream (cairo_pdf_surface_t	*surface);
 
 static cairo_status_t
-_cairo_pdf_surface_add_stream (cairo_pdf_surface_t	*surface,
-			       cairo_pdf_resource_t	 stream);
+_cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface);
 
 static void
 _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface);
 
 static cairo_pdf_resource_t
 _cairo_pdf_surface_write_info (cairo_pdf_surface_t *surface);
 
 static cairo_pdf_resource_t
 _cairo_pdf_surface_write_catalog (cairo_pdf_surface_t *surface);
 
 static long
 _cairo_pdf_surface_write_xref (cairo_pdf_surface_t *surface);
 
 static cairo_status_t
+_cairo_pdf_surface_emit_clip (cairo_pdf_surface_t  *surface,
+			      cairo_path_fixed_t   *path,
+			      cairo_fill_rule_t	    fill_rule);
+
+static cairo_status_t
 _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface);
 
 static cairo_status_t
 _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface);
 
 static const cairo_surface_backend_t cairo_pdf_surface_backend;
 static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend;
 
@@ -172,70 +291,22 @@ static void
 				  cairo_pdf_resource_t	 resource)
 {
     cairo_pdf_object_t *object;
 
     object = _cairo_array_index (&surface->objects, resource.id - 1);
     object->offset = _cairo_output_stream_get_position (surface->output);
 }
 
-static cairo_status_t
-_cairo_pdf_surface_add_stream (cairo_pdf_surface_t	*surface,
-			       cairo_pdf_resource_t	 stream)
-{
-    return _cairo_array_append (&surface->streams, &stream);
-}
-
-static cairo_status_t
-_cairo_pdf_surface_add_pattern (cairo_pdf_surface_t	*surface,
-				cairo_pdf_resource_t	 pattern)
-{
-    return _cairo_array_append (&surface->patterns, &pattern);
-}
-
-static cairo_status_t
-_cairo_pdf_surface_add_smask (cairo_pdf_surface_t  *surface,
-                              cairo_pdf_resource_t  smask)
-{
-    return _cairo_array_append (&surface->smasks, &smask);
-}
-
-static cairo_status_t
-_cairo_pdf_surface_add_alpha (cairo_pdf_surface_t *surface, double alpha, int *index)
-{
-    int num_alphas, i;
-    double other;
-    cairo_status_t status;
-
-    num_alphas = _cairo_array_num_elements (&surface->alphas);
-    for (i = 0; i < num_alphas; i++) {
-        _cairo_array_copy_element (&surface->alphas, i, &other);
-        if (alpha == other) {
-            *index = i;
-            return CAIRO_STATUS_SUCCESS;
-        }
-    }
-
-    status = _cairo_array_append (&surface->alphas, &alpha);
-    if (status)
-	return status;
-
-    *index = _cairo_array_num_elements (&surface->alphas) - 1;
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
 static cairo_surface_t *
 _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t	*output,
 					       double			 width,
 					       double			 height)
 {
     cairo_pdf_surface_t *surface;
-    cairo_status_t status;
-    int alpha;
 
     surface = malloc (sizeof (cairo_pdf_surface_t));
     if (surface == NULL) {
 	_cairo_error (CAIRO_STATUS_NO_MEMORY);
 	return (cairo_surface_t*) &_cairo_surface_nil;
     }
 
     _cairo_surface_init (&surface->base, &cairo_pdf_surface_backend,
@@ -244,67 +315,63 @@ static cairo_surface_t *
     surface->output = output;
 
     surface->width = width;
     surface->height = height;
     cairo_matrix_init (&surface->cairo_to_pdf, 1, 0, 0, -1, 0, height);
 
     _cairo_array_init (&surface->objects, sizeof (cairo_pdf_object_t));
     _cairo_array_init (&surface->pages, sizeof (cairo_pdf_resource_t));
-    _cairo_array_init (&surface->patterns, sizeof (cairo_pdf_resource_t));
-    _cairo_array_init (&surface->xobjects, sizeof (cairo_pdf_resource_t));
-    _cairo_array_init (&surface->streams, sizeof (cairo_pdf_resource_t));
-    _cairo_array_init (&surface->alphas, sizeof (double));
-    _cairo_array_init (&surface->smasks, sizeof (cairo_pdf_resource_t));
     _cairo_array_init (&surface->rgb_linear_functions, sizeof (cairo_pdf_rgb_linear_function_t));
     _cairo_array_init (&surface->alpha_linear_functions, sizeof (cairo_pdf_alpha_linear_function_t));
-
-
-    /* Add alpha=1 as the first element in the list of alpha values as
-     * this is the most frequently referenced value. */
-    status = _cairo_pdf_surface_add_alpha (surface, 1, &alpha);
-    if (status) {
-	_cairo_error (status);
-        goto fail1;
-    }
+    _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_font_t));
+    _cairo_array_init (&surface->knockout_group, sizeof (cairo_pdf_group_element_t));
+    _cairo_array_init (&surface->content_group, sizeof (cairo_pdf_group_element_t));
+
+    _cairo_pdf_group_resources_init (&surface->group_stream.resources);
+    _cairo_pdf_group_resources_init (&surface->content_stream.resources);
 
     surface->font_subsets = _cairo_scaled_font_subsets_create_composite ();
     if (! surface->font_subsets) {
 	_cairo_error (CAIRO_STATUS_NO_MEMORY);
-        goto fail2;
+	goto fail;
     }
 
-    _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_font_t));
-
     surface->next_available_resource.id = 1;
     surface->pages_resource = _cairo_pdf_surface_new_object (surface);
 
-    surface->current_stream.active = FALSE;
-
-    surface->has_clip = FALSE;
+    surface->pdf_stream.active = FALSE;
+    surface->content_stream.active = FALSE;
+    surface->content_stream.stream = NULL;
+    surface->group_stream.active = FALSE;
+    surface->group_stream.stream = NULL;
+
+    surface->current_group = NULL;
+    surface->current_resources = NULL;
 
     surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
 
     surface->force_fallbacks = FALSE;
 
     /* Document header */
     _cairo_output_stream_printf (surface->output,
 				 "%%PDF-1.4\r\n");
     _cairo_output_stream_printf (surface->output,
 				 "%%%c%c%c%c\r\n", 181, 237, 174, 251);
 
-    return _cairo_paginated_surface_create (&surface->base,
-					    CAIRO_CONTENT_COLOR_ALPHA,
-					    width, height,
-					    &cairo_pdf_surface_paginated_backend);
-
-fail1:
+    surface->paginated_surface = _cairo_paginated_surface_create (&surface->base,
+								  CAIRO_CONTENT_COLOR_ALPHA,
+								  width, height,
+								  &cairo_pdf_surface_paginated_backend);
+    return surface->paginated_surface;
+
+fail:
     free (surface);
-fail2:
-	return (cairo_surface_t*) &_cairo_surface_nil;
+
+    return (cairo_surface_t*) &_cairo_surface_nil;
 }
 
 /**
  * cairo_pdf_surface_create_for_stream:
  * @write_func: a #cairo_write_func_t to accept the output data
  * @closure: the closure argument for @write_func
  * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
  * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
@@ -441,113 +508,567 @@ cairo_pdf_surface_set_size (cairo_surfac
     status = _extract_pdf_surface (surface, &pdf_surface);
     if (status) {
 	_cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
 	return;
     }
 
     pdf_surface->width = width_in_points;
     pdf_surface->height = height_in_points;
+    cairo_matrix_init (&pdf_surface->cairo_to_pdf, 1, 0, 0, -1, 0, height_in_points);
+    status = _cairo_paginated_surface_set_size (pdf_surface->paginated_surface,
+						width_in_points,
+						height_in_points);
+    if (status)
+	_cairo_surface_set_error (surface, status);
 }
 
 static void
 _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
 {
-    _cairo_array_truncate (&surface->streams, 0);
+    _cairo_pdf_group_element_array_finish (&surface->content_group);
+    _cairo_pdf_group_element_array_finish (&surface->knockout_group);
+    _cairo_array_truncate (&surface->content_group, 0);
+    _cairo_array_truncate (&surface->knockout_group, 0);
+}
+
+static void
+_cairo_pdf_group_resources_init (cairo_pdf_group_resources_t *res)
+{
+    _cairo_array_init (&res->alphas, sizeof (double));
+    _cairo_array_init (&res->smasks, sizeof (cairo_pdf_resource_t));
+    _cairo_array_init (&res->patterns, sizeof (cairo_pdf_resource_t));
+    _cairo_array_init (&res->xobjects, sizeof (cairo_pdf_resource_t));
+    _cairo_array_init (&res->fonts, sizeof (cairo_pdf_font_t));
+}
+
+static void
+_cairo_pdf_group_resources_fini (cairo_pdf_group_resources_t *res)
+{
+    _cairo_array_fini (&res->alphas);
+    _cairo_array_fini (&res->smasks);
+    _cairo_array_fini (&res->patterns);
+    _cairo_array_fini (&res->xobjects);
+    _cairo_array_fini (&res->fonts);
+}
+
+static void
+_cairo_pdf_group_resources_clear (cairo_pdf_group_resources_t *res)
+{
+    _cairo_array_truncate (&res->alphas, 0);
+    _cairo_array_truncate (&res->smasks, 0);
+    _cairo_array_truncate (&res->patterns, 0);
+    _cairo_array_truncate (&res->xobjects, 0);
+    _cairo_array_truncate (&res->fonts, 0);
+}
+
+static cairo_status_t
+_cairo_pdf_surface_add_alpha (cairo_pdf_surface_t *surface,
+			      double               alpha,
+			      int                 *index)
+{
+    int num_alphas, i;
+    double other;
+    cairo_status_t status;
+    cairo_pdf_group_resources_t *res = surface->current_resources;
+
+    num_alphas = _cairo_array_num_elements (&res->alphas);
+    for (i = 0; i < num_alphas; i++) {
+	_cairo_array_copy_element (&res->alphas, i, &other);
+	if (alpha == other) {
+	    *index = i;
+	    return CAIRO_STATUS_SUCCESS;
+	}
+    }
+
+    status = _cairo_array_append (&res->alphas, &alpha);
+    if (status)
+	return status;
+
+    *index = _cairo_array_num_elements (&res->alphas) - 1;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_add_smask (cairo_pdf_surface_t  *surface,
+			      cairo_pdf_resource_t  smask)
+{
+    return _cairo_array_append (&surface->current_resources->smasks, &smask);
+}
+
+static cairo_status_t
+_cairo_pdf_surface_add_pattern (cairo_pdf_surface_t  *surface,
+				cairo_pdf_resource_t  pattern)
+{
+    return _cairo_array_append (&surface->current_resources->patterns, &pattern);
+}
+
+static cairo_status_t
+_cairo_pdf_surface_add_xobject (cairo_pdf_surface_t  *surface,
+				cairo_pdf_resource_t  xobject)
+{
+    return _cairo_array_append (&surface->current_resources->xobjects, &xobject);
+}
+
+static cairo_status_t
+_cairo_pdf_surface_add_font (cairo_pdf_surface_t *surface,
+			     unsigned int         font_id,
+			     unsigned int         subset_id)
+{
+    cairo_pdf_font_t font;
+    int num_fonts, i;
+    cairo_status_t status;
+    cairo_pdf_group_resources_t *res = surface->current_resources;
+
+    num_fonts = _cairo_array_num_elements (&surface->fonts);
+    for (i = 0; i < num_fonts; i++) {
+	_cairo_array_copy_element (&surface->fonts, i, &font);
+	if (font.font_id == font_id &&
+	    font.subset_id == subset_id) {
+	    status = _cairo_array_append (&res->fonts, &font);
+	    return CAIRO_STATUS_SUCCESS;
+	}
+    }
+
+    font.font_id = font_id;
+    font.subset_id = subset_id;
+    font.subset_resource = _cairo_pdf_surface_new_object (surface);
+
+    status = _cairo_array_append (&res->fonts, &font);
+    if (status)
+	return status;
+
+    status = _cairo_array_append (&surface->fonts, &font);
+
+    return status;
+}
+
+static cairo_pdf_resource_t
+_cairo_pdf_surface_get_font_resource (cairo_pdf_surface_t *surface,
+				      unsigned int         font_id,
+				      unsigned int         subset_id)
+{
+    cairo_pdf_font_t font;
+    int num_fonts, i;
+    cairo_pdf_resource_t resource;
+
+    num_fonts = _cairo_array_num_elements (&surface->fonts);
+    for (i = 0; i < num_fonts; i++) {
+	_cairo_array_copy_element (&surface->fonts, i, &font);
+	if (font.font_id == font_id && font.subset_id == subset_id)
+	    return font.subset_resource;
+    }
+    resource.id = 0;
+
+    return resource;
+}
+
+static void
+_cairo_pdf_surface_emit_group_resources (cairo_pdf_surface_t         *surface,
+					 cairo_pdf_group_resources_t *res)
+{
+    int num_alphas, num_smasks, num_resources, i;
+    double alpha;
+    cairo_pdf_resource_t *smask, *pattern, *xobject;
+    cairo_pdf_font_t *font;
+
+    _cairo_output_stream_printf (surface->output, "   /Resources <<\r\n");
+
+    num_alphas = _cairo_array_num_elements (&res->alphas);
+    num_smasks = _cairo_array_num_elements (&res->smasks);
+    if (num_alphas > 0 || num_smasks > 0) {
+	_cairo_output_stream_printf (surface->output,
+				     "      /ExtGState <<\r\n");
+
+	for (i = 0; i < num_alphas; i++) {
+	    _cairo_array_copy_element (&res->alphas, i, &alpha);
+	    _cairo_output_stream_printf (surface->output,
+					 "         /a%d << /CA %f /ca %f >>\r\n",
+					 i, alpha, alpha);
+	}
+
+	for (i = 0; i < num_smasks; i++) {
+	    smask = _cairo_array_index (&res->smasks, i);
+	    _cairo_output_stream_printf (surface->output,
+					 "         /s%d %d 0 R\r\n",
+					 smask->id, smask->id);
+	}
+
+	_cairo_output_stream_printf (surface->output,
+				     "      >>\r\n");
+    }
+
+    num_resources = _cairo_array_num_elements (&res->patterns);
+    if (num_resources > 0) {
+	_cairo_output_stream_printf (surface->output,
+				     "      /Pattern <<");
+	for (i = 0; i < num_resources; i++) {
+	    pattern = _cairo_array_index (&res->patterns, i);
+	    _cairo_output_stream_printf (surface->output,
+					 " /p%d %d 0 R",
+					 pattern->id, pattern->id);
+	}
+
+	_cairo_output_stream_printf (surface->output,
+				     " >>\r\n");
+    }
+
+    num_resources = _cairo_array_num_elements (&res->xobjects);
+    if (num_resources > 0) {
+	_cairo_output_stream_printf (surface->output,
+				     "      /XObject <<");
+
+	for (i = 0; i < num_resources; i++) {
+	    xobject = _cairo_array_index (&res->xobjects, i);
+	    _cairo_output_stream_printf (surface->output,
+					 " /x%d %d 0 R",
+					 xobject->id, xobject->id);
+	}
+
+	_cairo_output_stream_printf (surface->output,
+				     " >>\r\n");
+    }
+
+    num_resources = _cairo_array_num_elements (&res->fonts);
+    if (num_resources > 0) {
+	_cairo_output_stream_printf (surface->output,"      /Font <<\r\n");
+	for (i = 0; i < num_resources; i++) {
+	    font = _cairo_array_index (&res->fonts, i);
+	    _cairo_output_stream_printf (surface->output,
+					 "         /f-%d-%d %d 0 R\r\n",
+					 font->font_id,
+					 font->subset_id,
+					 font->subset_resource.id);
+	}
+	_cairo_output_stream_printf (surface->output, "      >>\r\n");
+    }
+
+    _cairo_output_stream_printf (surface->output,
+				 "   >>\r\n");
 }
 
 static cairo_pdf_resource_t
 _cairo_pdf_surface_open_stream (cairo_pdf_surface_t	*surface,
-                                cairo_bool_t             compressed,
+				cairo_bool_t             compressed,
 				const char		*fmt,
 				...)
 {
     va_list ap;
 
-    surface->current_stream.active = TRUE;
-    surface->current_stream.self = _cairo_pdf_surface_new_object (surface);
-    surface->current_stream.length = _cairo_pdf_surface_new_object (surface);
-    surface->current_stream.compressed = compressed;
+    surface->pdf_stream.active = TRUE;
+    surface->pdf_stream.self = _cairo_pdf_surface_new_object (surface);
+    surface->pdf_stream.length = _cairo_pdf_surface_new_object (surface);
+    surface->pdf_stream.compressed = compressed;
 
     _cairo_output_stream_printf (surface->output,
 				 "%d 0 obj\r\n"
 				 "<< /Length %d 0 R\r\n",
-				 surface->current_stream.self.id,
-				 surface->current_stream.length.id);
+				 surface->pdf_stream.self.id,
+				 surface->pdf_stream.length.id);
     if (compressed)
-        _cairo_output_stream_printf (surface->output,
-                                     "   /Filter /FlateDecode\r\n");
+	_cairo_output_stream_printf (surface->output,
+				     "   /Filter /FlateDecode\r\n");
 
     if (fmt != NULL) {
 	va_start (ap, fmt);
 	_cairo_output_stream_vprintf (surface->output, fmt, ap);
 	va_end (ap);
     }
 
     _cairo_output_stream_printf (surface->output,
 				 ">>\r\n"
 				 "stream\r\n");
 
-    surface->current_stream.start_offset = _cairo_output_stream_get_position (surface->output);
+    surface->pdf_stream.start_offset = _cairo_output_stream_get_position (surface->output);
 
     if (compressed) {
-        surface->current_stream.old_output = surface->output;
-        surface->output = _cairo_deflate_stream_create (surface->output);
+	surface->pdf_stream.old_output = surface->output;
+	surface->output = _cairo_deflate_stream_create (surface->output);
     }
 
-    return surface->current_stream.self;
+    return surface->pdf_stream.self;
 }
 
 static cairo_status_t
 _cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface)
 {
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
     long length;
 
-    if (! surface->current_stream.active)
+    if (! surface->pdf_stream.active)
 	return CAIRO_STATUS_SUCCESS;
 
-    if (surface->current_stream.compressed) {
-        status = _cairo_output_stream_destroy (surface->output);
-        surface->output = surface->current_stream.old_output;
-        _cairo_output_stream_printf (surface->output,
-                                     "\r\n");
+    if (surface->pdf_stream.compressed) {
+	status = _cairo_output_stream_destroy (surface->output);
+	surface->output = surface->pdf_stream.old_output;
+	_cairo_output_stream_printf (surface->output,
+				     "\r\n");
     }
 
     length = _cairo_output_stream_get_position (surface->output) -
-	surface->current_stream.start_offset;
+	surface->pdf_stream.start_offset;
     _cairo_output_stream_printf (surface->output,
 				 "endstream\r\n"
 				 "endobj\r\n");
 
     _cairo_pdf_surface_update_object (surface,
-				      surface->current_stream.length);
+				      surface->pdf_stream.length);
     _cairo_output_stream_printf (surface->output,
 				 "%d 0 obj\r\n"
 				 "   %ld\r\n"
 				 "endobj\r\n",
-				 surface->current_stream.length.id,
+				 surface->pdf_stream.length.id,
 				 length);
 
-    surface->current_stream.active = FALSE;
+    surface->pdf_stream.active = FALSE;
 
     return status;
 }
 
+static cairo_pdf_resource_t
+_cairo_pdf_surface_write_memory_stream (cairo_pdf_surface_t         *surface,
+					cairo_output_stream_t       *mem_stream,
+					cairo_pdf_group_resources_t *resources,
+					cairo_bool_t                 is_knockout_group)
+{
+    cairo_pdf_resource_t group;
+
+    group = _cairo_pdf_surface_new_object (surface);
+    _cairo_output_stream_printf (surface->output,
+				 "%d 0 obj\r\n"
+				 "<< /Type /XObject\r\n"
+				 "   /Length %d\r\n"
+				 "   /Subtype /Form\r\n"
+				 "   /BBox [ 0 0 %f %f ]\r\n"
+				 "   /Group <<\r\n"
+				 "      /Type /Group\r\n"
+				 "      /S /Transparency\r\n"
+				 "      /CS /DeviceRGB\r\n",
+				 group.id,
+				 _cairo_memory_stream_length (mem_stream),
+				 surface->width,
+				 surface->height);
+
+    if (is_knockout_group)
+	_cairo_output_stream_printf (surface->output,
+				     "      /K true\r\n");
+
+    _cairo_output_stream_printf (surface->output,
+				 "   >>\r\n");
+    _cairo_pdf_surface_emit_group_resources (surface, resources);
+    _cairo_output_stream_printf (surface->output,
+				 ">>\r\n"
+				 "stream\r\n");
+    _cairo_memory_stream_copy (mem_stream, surface->output);
+    _cairo_output_stream_printf (surface->output,
+				 "endstream\r\n"
+				 "endobj\r\n");
+
+    return group;
+}
+
+static void
+_cairo_pdf_surface_open_group (cairo_pdf_surface_t *surface)
+{
+    assert (surface->pdf_stream.active == FALSE);
+    assert (surface->content_stream.active == FALSE);
+    assert (surface->group_stream.active == FALSE);
+
+    surface->group_stream.active = TRUE;
+    surface->group_stream.stream = _cairo_memory_stream_create ();
+    surface->group_stream.old_output = surface->output;
+    surface->output = surface->group_stream.stream;
+    _cairo_pdf_group_resources_clear (&surface->group_stream.resources);
+    surface->current_resources = &surface->group_stream.resources;
+    surface->group_stream.is_knockout = FALSE;
+}
+
+static void
+_cairo_pdf_surface_open_knockout_group (cairo_pdf_surface_t  *surface,
+					cairo_pdf_resource_t *first_object)
+{
+    _cairo_pdf_surface_open_group (surface);
+    surface->group_stream.is_knockout = TRUE;
+    surface->group_stream.first_object = *first_object;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface,
+				cairo_pdf_resource_t *group)
+{
+    assert (surface->pdf_stream.active == FALSE);
+    assert (surface->group_stream.active == TRUE);
+
+    surface->output = surface->group_stream.old_output;
+    surface->group_stream.active = FALSE;
+    *group = _cairo_pdf_surface_write_memory_stream (surface,
+						     surface->group_stream.stream,
+						     &surface->group_stream.resources,
+						     surface->group_stream.is_knockout);
+    return _cairo_output_stream_close (surface->group_stream.stream);
+}
+
+static void
+_cairo_pdf_surface_write_group_list (cairo_pdf_surface_t  *surface,
+				     cairo_array_t        *group_list)
+{
+    int i, len;
+    cairo_pdf_group_element_t *elem;
+
+    _cairo_output_stream_printf (surface->output, "q\r\n");
+    if (surface->group_stream.is_knockout) {
+	_cairo_output_stream_printf (surface->output,
+				     "/x%d Do\r\n",
+				     surface->group_stream.first_object.id);
+	_cairo_pdf_surface_add_xobject (surface, surface->group_stream.first_object);
+    }
+    len = _cairo_array_num_elements (group_list);
+    for (i = 0; i < len; i++) {
+	elem = _cairo_array_index (group_list, i);
+	if (elem->type == ELEM_GROUP) {
+	    _cairo_output_stream_printf (surface->output,
+					 "/x%d Do\r\n",
+					 elem->group.id);
+	    _cairo_pdf_surface_add_xobject (surface, elem->group);
+	} else if (elem->type == ELEM_CLIP) {
+	    _cairo_pdf_surface_emit_clip (surface, elem->clip_path, elem->fill_rule);
+	}
+    }
+    _cairo_output_stream_printf (surface->output, "Q\r\n");
+}
+
+static void
+_cairo_pdf_surface_start_content_stream (cairo_pdf_surface_t *surface)
+{
+    if (surface->content_stream.active) {
+        return;
+    }
+    assert (surface->pdf_stream.active == FALSE);
+    assert (surface->content_stream.active == FALSE);
+    assert (surface->group_stream.active == FALSE);
+
+    surface->content_stream.active = TRUE;
+    surface->content_stream.stream = _cairo_memory_stream_create ();
+    surface->content_stream.old_output = surface->output;
+    surface->output = surface->content_stream.stream;
+    _cairo_pdf_group_resources_clear (&surface->content_stream.resources);
+    surface->current_resources = &surface->content_stream.resources;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_add_group_to_content_stream (cairo_pdf_surface_t   *surface,
+                                                cairo_pdf_resource_t   group)
+{
+    cairo_pdf_group_element_t elem;
+
+    memset (&elem, 0, sizeof elem);
+    elem.type = ELEM_GROUP;
+    elem.group = group;
+
+    return _cairo_array_append (surface->current_group, &elem);
+}
+
+static void
+_cairo_pdf_surface_pause_content_stream (cairo_pdf_surface_t *surface)
+{
+    assert (surface->pdf_stream.active == FALSE);
+
+    if (surface->content_stream.active == FALSE)
+	return;
+
+    surface->output = surface->content_stream.old_output;
+    surface->content_stream.active = FALSE;
+}
+
+static void
+_cairo_pdf_surface_resume_content_stream (cairo_pdf_surface_t *surface)
+{
+    assert (surface->pdf_stream.active == FALSE);
+
+    if (surface->content_stream.active == TRUE)
+	return;
+
+    surface->output = surface->content_stream.stream;
+    surface->current_resources = &surface->content_stream.resources;
+    surface->content_stream.active = TRUE;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_stop_content_stream (cairo_pdf_surface_t *surface)
+{
+    cairo_pdf_resource_t group;
+
+    assert (surface->pdf_stream.active == FALSE);
+    assert (surface->content_stream.active == TRUE);
+
+    surface->output = surface->content_stream.old_output;
+    surface->content_stream.active = FALSE;
+    if (_cairo_memory_stream_length (surface->content_stream.stream) > 0) {
+	group = _cairo_pdf_surface_write_memory_stream (surface,
+							surface->content_stream.stream,
+							&surface->content_stream.resources,
+							FALSE);
+	_cairo_pdf_surface_add_group_to_content_stream (surface, group);
+    }
+    surface->content_stream.active = FALSE;
+
+    return _cairo_output_stream_close (surface->content_stream.stream);
+}
+
+static cairo_status_t
+_cairo_pdf_surface_check_content_stream_size (cairo_pdf_surface_t *surface)
+{
+    cairo_status_t status;
+
+    if (surface->content_stream.active == FALSE)
+	return CAIRO_STATUS_SUCCESS;
+
+    if (_cairo_memory_stream_length (surface->content_stream.stream) > GROUP_STREAM_LIMIT) {
+	status = _cairo_pdf_surface_stop_content_stream (surface);
+	if (status)
+	    return status;
+	_cairo_pdf_surface_start_content_stream (surface);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_pdf_group_element_array_finish (cairo_array_t *array)
+{
+    int i, len;
+    cairo_pdf_group_element_t *elem;
+
+    len = _cairo_array_num_elements (array);
+    for (i = 0; i < len; i++) {
+	elem = _cairo_array_index (array, i);
+	if (elem->type == ELEM_CLIP && elem->clip_path)
+	    _cairo_path_fixed_destroy (elem->clip_path);
+    }
+}
+
+static cairo_surface_t *
+_cairo_pdf_surface_create_similar (void			*abstract_surface,
+				   cairo_content_t	 content,
+				   int			 width,
+				   int			 height)
+{
+    return _cairo_meta_surface_create (content, width, height);
+}
+
 static cairo_status_t
 _cairo_pdf_surface_finish (void *abstract_surface)
 {
     cairo_status_t status, status2;
     cairo_pdf_surface_t *surface = abstract_surface;
     long offset;
     cairo_pdf_resource_t info, catalog;
 
-    status = _cairo_pdf_surface_close_stream (surface);
-
-    _cairo_pdf_surface_emit_font_subsets (surface);
+    status = _cairo_pdf_surface_emit_font_subsets (surface);
 
     _cairo_pdf_surface_write_pages (surface);
 
     info = _cairo_pdf_surface_write_info (surface);
     catalog = _cairo_pdf_surface_write_catalog (surface);
     offset = _cairo_pdf_surface_write_xref (surface);
 
     _cairo_output_stream_printf (surface->output,
@@ -567,138 +1088,78 @@ static cairo_status_t
 				 offset);
 
     status2 = _cairo_output_stream_destroy (surface->output);
     if (status == CAIRO_STATUS_SUCCESS)
 	status = status2;
 
     _cairo_array_fini (&surface->objects);
     _cairo_array_fini (&surface->pages);
-    _cairo_array_fini (&surface->patterns);
-    _cairo_array_fini (&surface->xobjects);
-    _cairo_array_fini (&surface->streams);
-    _cairo_array_fini (&surface->alphas);
-    _cairo_array_fini (&surface->smasks);
     _cairo_array_fini (&surface->rgb_linear_functions);
     _cairo_array_fini (&surface->alpha_linear_functions);
+    _cairo_array_fini (&surface->fonts);
+
+    _cairo_pdf_group_resources_fini (&surface->group_stream.resources);
+    _cairo_pdf_group_resources_fini (&surface->content_stream.resources);
+
+    _cairo_pdf_group_element_array_finish (&surface->knockout_group);
+    _cairo_array_fini (&surface->knockout_group);
+
+    _cairo_pdf_group_element_array_finish (&surface->content_group);
+    _cairo_array_fini (&surface->content_group);
 
     if (surface->font_subsets) {
 	_cairo_scaled_font_subsets_destroy (surface->font_subsets);
 	surface->font_subsets = NULL;
     }
 
-    _cairo_array_fini (&surface->fonts);
-
     return status;
 }
 
-static cairo_status_t
-_cairo_pdf_surface_pause_content_stream (cairo_pdf_surface_t *surface)
-{
-    return _cairo_pdf_surface_close_stream (surface);
-}
-
-static cairo_status_t
-_cairo_pdf_surface_resume_content_stream (cairo_pdf_surface_t *surface)
-{
-    cairo_pdf_resource_t stream;
-
-    stream = _cairo_pdf_surface_open_stream (surface,
-                                             TRUE,
-					     "   /Type /XObject\r\n"
-					     "   /Subtype /Form\r\n"
-					     "   /BBox [ 0 0 %f %f ]\r\n",
-					     surface->width,
-					     surface->height);
-
-    return _cairo_pdf_surface_add_stream (surface, stream);
-}
-
-static cairo_status_t
-_cairo_pdf_surface_begin_group (cairo_pdf_surface_t *surface, cairo_pdf_resource_t *group)
-{
-    cairo_pdf_resource_t g;
-    cairo_status_t status;
-
-    _cairo_pdf_surface_pause_content_stream (surface);
-    g = _cairo_pdf_surface_open_stream (surface,
-                                        TRUE,
-                                        "   /Type /XObject\r\n"
-                                        "   /Subtype /Form\r\n"
-                                        "   /BBox [ 0 0 %f %f ]\r\n"
-                                        "   /Group <<\r\n"
-                                        "      /Type /Group\r\n"
-                                        "      /S /Transparency\r\n"
-                                        "      /CS /DeviceRGB\r\n"
-                                        "   >>\r\n",
-                                        surface->width,
-                                        surface->height);
-
-    status = _cairo_array_append (&surface->xobjects, &g);
-    *group = g;
-
-    return status;
-}
-
-static void
-_cairo_pdf_surface_end_group (cairo_pdf_surface_t *surface)
-{
-    _cairo_pdf_surface_close_stream (surface);
-    _cairo_pdf_surface_resume_content_stream (surface);
-}
-
 static cairo_int_status_t
 _cairo_pdf_surface_start_page (void *abstract_surface)
 {
-    cairo_status_t status;
     cairo_pdf_surface_t *surface = abstract_surface;
-    cairo_pdf_resource_t stream;
-
-    stream = _cairo_pdf_surface_open_stream (surface,
-                                             TRUE,
-					     "   /Type /XObject\r\n"
-					     "   /Subtype /Form\r\n"
-					     "   /BBox [ 0 0 %f %f ]\r\n",
-					     surface->width,
-					     surface->height);
-
-    status = _cairo_pdf_surface_add_stream (surface, stream);
-    if (status)
-	return status;
+
+    surface->current_group = &surface->content_group;
+    _cairo_pdf_surface_start_content_stream (surface);
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static void *
 compress_dup (const void *data, unsigned long data_size,
 	      unsigned long *compressed_size)
 {
     void *compressed;
 
     /* Bound calculation taken from zlib. */
     *compressed_size = data_size + (data_size >> 12) + (data_size >> 14) + 11;
     compressed = malloc (*compressed_size);
     if (compressed == NULL)
 	return NULL;
 
-    compress (compressed, compressed_size, data, data_size);
+    if (compress (compressed, compressed_size, data, data_size) != Z_OK) {
+	free (compressed);
+	compressed = NULL;
+    }
 
     return compressed;
 }
 
 /* Emit alpha channel from the image into the given data, providing
  * an id that can be used to reference the resulting SMask object.
  *
  * In the case that the alpha channel happens to be all opaque, then
  * no SMask object will be emitted and *id_ret will be set to 0.
  */
 static cairo_status_t
-_cairo_pdf_surface_emit_smask (cairo_pdf_surface_t		*surface,
-	    cairo_image_surface_t	*image,
-	    cairo_pdf_resource_t	*stream_ret)
+_cairo_pdf_surface_emit_smask (cairo_pdf_surface_t	*surface,
+			       cairo_image_surface_t	*image,
+			       cairo_pdf_resource_t	*stream_ret)
 {
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
     char *alpha, *alpha_compressed;
     unsigned long alpha_size, alpha_compressed_size;
     uint32_t *pixel;
     int i, x, y;
     cairo_bool_t opaque;
     uint8_t a;
@@ -861,141 +1322,239 @@ static cairo_status_t
 						     image->width, image->height);
 
 #undef IMAGE_DICTIONARY
 
     _cairo_output_stream_write (surface->output, compressed, compressed_size);
     _cairo_output_stream_printf (surface->output, "\r\n");
     status = _cairo_pdf_surface_close_stream (surface);
 
- CLEANUP_COMPRESSED:
+CLEANUP_COMPRESSED:
     free (compressed);
- CLEANUP_RGB:
+CLEANUP_RGB:
     free (rgb);
- CLEANUP:
+CLEANUP:
     return status;
 }
 
 static cairo_status_t
-_cairo_pdf_surface_emit_solid_pattern (cairo_pdf_surface_t   *surface,
-                                       cairo_solid_pattern_t *pattern)
+_cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t     *surface,
+				       cairo_surface_pattern_t *pattern,
+				       cairo_pdf_resource_t    *resource,
+				       int                     *width,
+				       int                     *height)
 {
-    int alpha;
-    cairo_status_t status;
-
-    status = _cairo_pdf_surface_add_alpha (surface, pattern->color.alpha, &alpha);
-    if (status)
-	return status;
-
-    surface->emitted_pattern.type = CAIRO_PATTERN_TYPE_SOLID;
-    surface->emitted_pattern.red = pattern->color.red;
-    surface->emitted_pattern.green = pattern->color.green;
-    surface->emitted_pattern.blue = pattern->color.blue;
-    surface->emitted_pattern.alpha = alpha;
-    surface->emitted_pattern.smask.id = 0;
-    surface->emitted_pattern.pattern.id = 0;
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t	 *surface,
-                                         cairo_surface_pattern_t *pattern)
-{
-    cairo_pdf_resource_t stream;
     cairo_surface_t *pat_surface;
     cairo_surface_attributes_t pat_attr;
     cairo_image_surface_t *image;
     void *image_extra;
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
-    cairo_pdf_resource_t image_resource = {0}; /* squelch bogus compiler warning */
-    cairo_matrix_t cairo_p2d, pdf_p2d;
-    cairo_extend_t extend = cairo_pattern_get_extend (&pattern->base);
-    double xstep, ystep;
-    cairo_rectangle_int_t surface_extents;
-
-    /* XXX: Should do something clever here for PDF source surfaces ? */
-
-    status = _cairo_pdf_surface_pause_content_stream (surface);
-    if (status)
-	return status;
 
     status = _cairo_pattern_acquire_surface ((cairo_pattern_t *)pattern,
 					     (cairo_surface_t *)surface,
 					     0, 0, -1, -1,
 					     &pat_surface, &pat_attr);
     if (status)
 	return status;
 
     status = _cairo_surface_acquire_source_image (pat_surface, &image, &image_extra);
     if (status)
 	goto BAIL2;
 
-    status = _cairo_pdf_surface_emit_image (surface, image, &image_resource);
+    status = _cairo_pdf_surface_emit_image (surface, image, resource);
     if (status)
 	goto BAIL;
 
+    *width = image->width;
+    *height = image->height;
+
+BAIL:
+    _cairo_surface_release_source_image (pat_surface, image, image_extra);
+BAIL2:
+    _cairo_pattern_release_surface ((cairo_pattern_t *)pattern, pat_surface, &pat_attr);
+
+    return status;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t  *surface,
+				      cairo_surface_t      *meta_surface,
+				      cairo_pdf_resource_t *resource)
+{
+    cairo_array_t group;
+    cairo_array_t *old_group;
+    double old_width, old_height;
+    cairo_matrix_t old_cairo_to_pdf;
+    cairo_rectangle_int16_t meta_extents;
+    cairo_status_t status;
+    int alpha = 0;
+
+    status = _cairo_surface_get_extents (meta_surface, &meta_extents);
+    if (status)
+	return status;
+
+    _cairo_pdf_surface_resume_content_stream (surface);
+    _cairo_pdf_surface_stop_content_stream (surface);
+
+    _cairo_array_init (&group, sizeof (cairo_pdf_group_element_t));
+    old_group = surface->current_group;
+    old_width = surface->width;
+    old_height = surface->height;
+    old_cairo_to_pdf = surface->cairo_to_pdf;
+    surface->current_group = &group;
+    surface->width = meta_extents.width;
+    surface->height = meta_extents.height;
+    cairo_matrix_init (&surface->cairo_to_pdf, 1, 0, 0, -1, 0, surface->height);
+
+    _cairo_pdf_surface_start_content_stream (surface);
+
+    if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
+	status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
+	if (status)
+	    return status;
+	_cairo_output_stream_printf (surface->output,
+				     "q /a%d gs 0 0 0 rg 0 0 %f %f re f Q\r\n",
+				     alpha,
+				     surface->width,
+				     surface->height);
+    }
+
+    status = _cairo_meta_surface_replay (meta_surface, &surface->base);
+    if (status)
+	return status;
+    _cairo_pdf_surface_stop_content_stream (surface);
+
+    _cairo_pdf_surface_open_group (surface);
+    _cairo_pdf_surface_write_group_list (surface, &group);
+    _cairo_pdf_surface_close_group (surface, resource);
+
+    surface->current_group = old_group;
+    surface->width = old_width;
+    surface->height = old_height;
+    surface->cairo_to_pdf = old_cairo_to_pdf;
+
+    _cairo_pdf_surface_start_content_stream (surface);
+
+    _cairo_pdf_group_element_array_finish (&group);
+    _cairo_array_fini (&group);
+
+    _cairo_pdf_surface_pause_content_stream (surface);
+
+    return 0;
+}
+
+static void
+_cairo_pdf_surface_emit_solid_pattern (cairo_pdf_surface_t   *surface,
+				       cairo_solid_pattern_t *pattern)
+{
+    surface->emitted_pattern.type = CAIRO_PATTERN_TYPE_SOLID;
+    surface->emitted_pattern.red = pattern->color.red;
+    surface->emitted_pattern.green = pattern->color.green;
+    surface->emitted_pattern.blue = pattern->color.blue;
+    surface->emitted_pattern.alpha = pattern->color.alpha;
+    surface->emitted_pattern.smask.id = 0;
+    surface->emitted_pattern.pattern.id = 0;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t	 *surface,
+					 cairo_surface_pattern_t *pattern)
+{
+    cairo_pdf_resource_t stream;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+    cairo_pdf_resource_t pattern_resource = {0}; /* squelch bogus compiler warning */
+    cairo_matrix_t cairo_p2d, pdf_p2d;
+    cairo_extend_t extend = cairo_pattern_get_extend (&pattern->base);
+    double xstep, ystep;
+    cairo_rectangle_int16_t surface_extents;
+    int pattern_width = 0; /* squelch bogus compiler warning */
+    int pattern_height = 0; /* squelch bogus compiler warning */
+
+    _cairo_pdf_surface_pause_content_stream (surface);
+
+    if (_cairo_surface_is_meta (pattern->surface)) {
+	cairo_surface_t *meta_surface = pattern->surface;
+	cairo_rectangle_int16_t pattern_extents;
+
+	status = _cairo_pdf_surface_emit_meta_surface (surface,
+						       meta_surface,
+						       &pattern_resource);
+	status = _cairo_surface_get_extents (meta_surface, &pattern_extents);
+	if (status)
+	    return status;
+	pattern_width = pattern_extents.width;
+	pattern_height = pattern_extents.height;
+    } else {
+	status = _cairo_pdf_surface_emit_image_surface (surface,
+							pattern,
+							&pattern_resource,
+							&pattern_width,
+							&pattern_height);
+    }
+    if (status)
+	return status;
+
     status = _cairo_surface_get_extents (&surface->base, &surface_extents);
     if (status)
-	goto BAIL;
+	return status;
 
     switch (extend) {
-    /* We implement EXTEND_PAD like EXTEND_NONE for now */
+	/* We implement EXTEND_PAD like EXTEND_NONE for now */
     case CAIRO_EXTEND_PAD:
     case CAIRO_EXTEND_NONE:
-        {
-	    /* In PS/PDF, (as far as I can tell), all patterns are
-	     * repeating. So we support cairo's EXTEND_NONE semantics
-	     * by setting the repeat step size to a size large enough
-	     * to guarantee that no more than a single occurrence will
-	     * be visible.
-	     *
-	     * First, map the surface extents into pattern space (since
-	     * xstep and ystep are in pattern space).  Then use an upper
-	     * bound on the length of the diagonal of the pattern image
-	     * and the surface as repeat size.  This guarantees to never
-	     * repeat visibly.
-	     */
-	    double x1 = 0.0, y1 = 0.0;
-	    double x2 = surface->width, y2 = surface->height;
-	    _cairo_matrix_transform_bounding_box (&pattern->base.matrix,
-						  &x1, &y1, &x2, &y2,
-						  NULL);
-
-	    /* Rather than computing precise bounds of the union, just
-	     * add the surface extents unconditionally. We only
-	     * required an answer that's large enough, we don't really
-	     * care if it's not as tight as possible.*/
-	    xstep = ystep = ceil ((x2 - x1) + (y2 - y1) +
-				  image->width + image->height);
-	}
-	break;
+    {
+	/* In PS/PDF, (as far as I can tell), all patterns are
+	 * repeating. So we support cairo's EXTEND_NONE semantics
+	 * by setting the repeat step size to a size large enough
+	 * to guarantee that no more than a single occurrence will
+	 * be visible.
+	 *
+	 * First, map the surface extents into pattern space (since
+	 * xstep and ystep are in pattern space).  Then use an upper
+	 * bound on the length of the diagonal of the pattern image
+	 * and the surface as repeat size.  This guarantees to never
+	 * repeat visibly.
+	 */
+	double x1 = 0.0, y1 = 0.0;
+	double x2 = surface->width, y2 = surface->height;
+	_cairo_matrix_transform_bounding_box (&pattern->base.matrix,
+					      &x1, &y1, &x2, &y2,
+					      NULL);
+
+	/* Rather than computing precise bounds of the union, just
+	 * add the surface extents unconditionally. We only
+	 * required an answer that's large enough, we don't really
+	 * care if it's not as tight as possible.*/
+	xstep = ystep = ceil ((x2 - x1) + (y2 - y1) +
+			      pattern_width + pattern_height);
+    }
+    break;
     case CAIRO_EXTEND_REPEAT:
     case CAIRO_EXTEND_REFLECT:
-	xstep = image->width;
-	ystep = image->height;
+	xstep = pattern_width;
+	ystep = pattern_height;
 	break;
-    /* All the rest (if any) should have been analyzed away, so this
-     * case should be unreachable. */
+	/* All the rest (if any) should have been analyzed away, so this
+	 * case should be unreachable. */
     default:
 	ASSERT_NOT_REACHED;
 	xstep = 0;
 	ystep = 0;
     }
 
     /* At this point, (that is, within the surface backend interface),
      * the pattern's matrix maps from cairo's device space to cairo's
      * pattern space, (both with their origin at the upper-left, and
      * cairo's pattern space of size width,height).
      *
      * Then, we must emit a PDF pattern object that maps from its own
      * pattern space, (which has a size that we establish in the BBox
      * dictionary entry), to the PDF page's *initial* space, (which
      * does not benefit from the Y-axis flipping matrix that we emit
-     * on each page). So the PDF patterns patrix maps from a
+     * on each page). So the PDF patterns matrix maps from a
      * (width,height) pattern space to a device space with the origin
      * in the lower-left corner.
      *
      * So to handle all of that, we start with an identity matrix for
      * the PDF pattern to device matrix. We translate it up by the
      * image height then flip it in the Y direction, (moving us from
      * the PDF origin to cairo's origin). We then multiply in the
      * inverse of the cairo pattern matrix, (since it maps from device
@@ -1012,65 +1571,58 @@ static cairo_status_t
     status = cairo_matrix_invert (&cairo_p2d);
     /* cairo_pattern_set_matrix ensures the matrix is invertible */
     assert (status == CAIRO_STATUS_SUCCESS);
 
     cairo_matrix_init_identity (&pdf_p2d);
     cairo_matrix_translate (&pdf_p2d, 0.0, surface_extents.height);
     cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
     cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &pdf_p2d);
-    cairo_matrix_translate (&pdf_p2d, 0.0, image->height);
+    cairo_matrix_translate (&pdf_p2d, 0.0, pattern_height);
     cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
 
     stream = _cairo_pdf_surface_open_stream (surface,
-                                             FALSE,
+					     FALSE,
 					     "   /BBox [0 0 %d %d]\r\n"
 					     "   /XStep %f\r\n"
 					     "   /YStep %f\r\n"
 					     "   /PatternType 1\r\n"
 					     "   /TilingType 1\r\n"
 					     "   /PaintType 1\r\n"
 					     "   /Matrix [ %f %f %f %f %f %f ]\r\n"
-					     "   /Resources << /XObject << /res%d %d 0 R >> >>\r\n",
-					     image->width, image->height,
+					     "   /Resources << /XObject << /x%d %d 0 R >> >>\r\n",
+					     pattern_width, pattern_height,
 					     xstep, ystep,
 					     pdf_p2d.xx, pdf_p2d.yx,
 					     pdf_p2d.xy, pdf_p2d.yy,
 					     pdf_p2d.x0, pdf_p2d.y0,
-					     image_resource.id,
-					     image_resource.id);
-
-    _cairo_output_stream_printf (surface->output,
-				 "q %d 0 0 %d 0 0 cm /res%d Do Q\r\n",
-				 image->width, image->height,
-				 image_resource.id);
+					     pattern_resource.id,
+					     pattern_resource.id);
+
+    if (_cairo_surface_is_meta (pattern->surface)) {
+	_cairo_output_stream_printf (surface->output,
+				     "/x%d Do\r\n",
+				     pattern_resource.id);
+    } else {
+	_cairo_output_stream_printf (surface->output,
+				     "q %d 0 0 %d 0 0 cm /x%d Do Q\r\n",
+				     pattern_width, pattern_height,
+				     pattern_resource.id);
+    }
 
     status = _cairo_pdf_surface_close_stream (surface);
     if (status)
-	goto BAIL;
-
-    status = _cairo_pdf_surface_resume_content_stream (surface);
-    if (status)
-	goto BAIL;
-
-    status = _cairo_pdf_surface_add_pattern (surface, stream);
-    if (status)
-	goto BAIL;
-
-    status = _cairo_pdf_surface_add_alpha (surface, 1.0, &surface->emitted_pattern.alpha);
-    if (status)
-	goto BAIL;
+	return status;
+
+    _cairo_pdf_surface_resume_content_stream (surface);
+
     surface->emitted_pattern.type = CAIRO_PATTERN_TYPE_SURFACE;
     surface->emitted_pattern.smask.id = 0;
     surface->emitted_pattern.pattern = stream;
-
- BAIL:
-    _cairo_surface_release_source_image (pat_surface, image, image_extra);
- BAIL2:
-    _cairo_pattern_release_surface ((cairo_pattern_t *)pattern, pat_surface, &pat_attr);
+    surface->emitted_pattern.alpha = 1.0;
 
     return status;
 }
 
 typedef struct _cairo_pdf_color_stop {
     double offset;
     double color[4];
     cairo_pdf_resource_t resource;
@@ -1184,19 +1736,19 @@ static cairo_status_t
     cairo_pdf_resource_t res;
     unsigned int i;
     cairo_status_t status;
 
     /* emit linear gradients between pairs of subsequent stops... */
     for (i = 0; i < n_stops-1; i++) {
         if (is_alpha) {
             status = cairo_pdf_surface_emit_alpha_linear_function (surface,
-                                                             &stops[i],
-                                                             &stops[i+1],
-                                                             &stops[i].resource);
+                                                                   &stops[i],
+                                                                   &stops[i+1],
+                                                                   &stops[i].resource);
             if (status)
                 return status;
         } else {
             status = cairo_pdf_surface_emit_rgb_linear_function (surface,
                                                                  &stops[i],
                                                                  &stops[i+1],
                                                                  &stops[i].resource);
             if (status)
@@ -1204,18 +1756,20 @@ static cairo_status_t
         }
     }
 
     /* ... and stitch them together */
     res = _cairo_pdf_surface_new_object (surface);
     _cairo_output_stream_printf (surface->output,
 				 "%d 0 obj\r\n"
 				 "<< /FunctionType 3\r\n"
-				 "   /Domain [ 0 1 ]\r\n",
-				 res.id);
+				 "   /Domain [ %f %f ]\r\n",
+				 res.id,
+                                 stops[0].offset,
+                                 stops[n_stops - 1].offset);
 
     _cairo_output_stream_printf (surface->output,
 				 "   /Functions [ ");
     for (i = 0; i < n_stops-1; i++)
         _cairo_output_stream_printf (surface->output,
                                      "%d 0 R ", stops[i].resource.id);
     _cairo_output_stream_printf (surface->output,
 		    		 "]\r\n");
@@ -1265,42 +1819,25 @@ static cairo_status_t
     allstops = _cairo_malloc_ab ((pattern->n_stops + 2), sizeof (cairo_pdf_color_stop_t));
     if (allstops == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
 
     stops = &allstops[1];
     n_stops = pattern->n_stops;
 
     for (i = 0; i < n_stops; i++) {
-	stops[i].color[0] = pattern->stops[i].color.red / 65535.0;
-	stops[i].color[1] = pattern->stops[i].color.green / 65535.0;
-	stops[i].color[2] = pattern->stops[i].color.blue / 65535.0;
-	stops[i].color[3] = pattern->stops[i].color.alpha / 65535.0;
+	stops[i].color[0] = pattern->stops[i].color.red;
+	stops[i].color[1] = pattern->stops[i].color.green;
+	stops[i].color[2] = pattern->stops[i].color.blue;
+	stops[i].color[3] = pattern->stops[i].color.alpha;
         if (!CAIRO_ALPHA_IS_OPAQUE (stops[i].color[3]))
             emit_alpha = TRUE;
 	stops[i].offset = _cairo_fixed_to_double (pattern->stops[i].x);
     }
 
-    /* make sure first offset is 0.0 and last offset is 1.0. (Otherwise Acrobat
-     * Reader chokes.) */
-    if (stops[0].offset > COLOR_STOP_EPSILON) {
-	    memcpy (allstops, stops, sizeof (cairo_pdf_color_stop_t));
-	    stops = allstops;
-	    n_stops++;
-    }
-    stops[0].offset = 0.0;
-
-    if (stops[n_stops-1].offset < 1.0 - COLOR_STOP_EPSILON) {
-	    memcpy (&stops[n_stops],
-		    &stops[n_stops - 1],
-		    sizeof (cairo_pdf_color_stop_t));
-	    n_stops++;
-    }
-    stops[n_stops-1].offset = 1.0;
-
     if (n_stops == 2) {
         /* no need for stitched function */
         status = cairo_pdf_surface_emit_rgb_linear_function (surface,
                                                              &stops[0],
                                                              &stops[1],
                                                              color_function);
         if (status)
             goto BAIL;
@@ -1352,48 +1889,47 @@ cairo_pdf_surface_emit_transparency_grou
                                                     "   /Subtype /Form\r\n"
                                                     "   /FormType 1\r\n"
                                                     "   /BBox [ 0 0 %f %f ]\r\n"
                                                     "   /Resources\r\n"
                                                     "      << /ExtGState\r\n"
                                                     "            << /a0 << /ca 1 /CA 1 >>"
                                                     "      >>\r\n"
                                                     "         /Pattern\r\n"
-                                                    "            << /res%d %d 0 R >>\r\n"
+                                                    "            << /p%d %d 0 R >>\r\n"
                                                     "      >>\r\n"
                                                     "   /Group\r\n"
                                                     "      << /Type /Group\r\n"
                                                     "         /S /Transparency\r\n"
                                                     "         /CS /DeviceGray\r\n"
                                                     "      >>\r\n",
                                                     surface->width,
                                                     surface->height,
                                                     gradient_mask.id,
                                                     gradient_mask.id);
 
     _cairo_output_stream_printf (surface->output,
                                  "q\r\n"
                                  "/a0 gs\r\n"
-                                 "/Pattern cs /res%d scn\r\n"
+                                 "/Pattern cs /p%d scn\r\n"
                                  "0 0 %f %f re\r\n"
                                  "f\r\n"
                                  "Q\r\n",
                                  gradient_mask.id,
                                  surface->width,
                                  surface->height);
 
     _cairo_pdf_surface_close_stream (surface);
 
     smask_resource = _cairo_pdf_surface_new_object (surface);
     _cairo_output_stream_printf (surface->output,
                                  "%d 0 obj\r\n"
                                  "<< /Type /Mask\r\n"
                                  "   /S /Luminosity\r\n"
                                  "   /G %d 0 R\r\n"
-                                 "   /BC [ 0.0 ]\r\n"
                                  ">>\r\n"
                                  "endobj\r\n",
                                  smask_resource.id,
                                  xobj_resource.id);
 
     /* Create GState which uses the transparency group as an SMask. */
     gstate_resource = _cairo_pdf_surface_new_object (surface);
     _cairo_output_stream_printf (surface->output,
@@ -1403,71 +1939,100 @@ cairo_pdf_surface_emit_transparency_grou
                                  "   /ca 1\r\n"
                                  "   /CA 1\r\n"
                                  "   /AIS false\r\n"
                                  ">>\r\n"
                                  "endobj\r\n",
                                  gstate_resource.id,
                                  smask_resource.id);
 
-    _cairo_pdf_surface_add_smask (surface, gstate_resource);
-
     return gstate_resource;
 }
 
 static cairo_status_t
 _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t    *surface,
                                         cairo_linear_pattern_t *pattern)
 {
     cairo_pdf_resource_t pattern_resource, smask;
     cairo_pdf_resource_t color_function, alpha_function;
     double x1, y1, x2, y2;
     cairo_matrix_t pat_to_pdf;
     cairo_extend_t extend;
     cairo_status_t status;
+    cairo_gradient_pattern_t *gradient = &pattern->base;
+    double first_stop, last_stop;
 
     extend = cairo_pattern_get_extend (&pattern->base.base);
-    status = _cairo_pdf_surface_pause_content_stream (surface);
-    if (status)
-	return status;
-
+    _cairo_pdf_surface_pause_content_stream (surface);
     status = _cairo_pdf_surface_emit_pattern_stops (surface,
                                                     &pattern->base,
                                                     &color_function,
                                                     &alpha_function);
     if (status)
 	return status;
 
     pat_to_pdf = pattern->base.base.matrix;
     status = cairo_matrix_invert (&pat_to_pdf);
-    if (status)
-	return status;
+    /* cairo_pattern_set_matrix ensures the matrix is invertible */
+    assert (status == CAIRO_STATUS_SUCCESS);
 
     cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf);
     x1 = _cairo_fixed_to_double (pattern->p1.x);
     y1 = _cairo_fixed_to_double (pattern->p1.y);
     x2 = _cairo_fixed_to_double (pattern->p2.x);
     y2 = _cairo_fixed_to_double (pattern->p2.y);
 
+    first_stop = _cairo_fixed_to_double (gradient->stops[0].x);
+    last_stop = _cairo_fixed_to_double (gradient->stops[gradient->n_stops - 1].x);
+
+    /* PDF requires the first and last stop to be the same as the line
+     * coordinates. If this is not a repeating pattern move the line
+     * coordinates to the location of first and last stop. */
+
+    if (pattern->base.base.extend == CAIRO_EXTEND_NONE ||
+	pattern->base.base.extend == CAIRO_EXTEND_PAD) {
+	double _x1, _y1, _x2, _y2;
+
+	_x1 = x1 + (x2 - x1)*first_stop;
+	_y1 = y1 + (y2 - y1)*first_stop;
+	_x2 = x1 + (x2 - x1)*last_stop;
+	_y2 = y1 + (y2 - y1)*last_stop;
+
+	x1 = _x1;
+	x2 = _x2;
+	y1 = _y1;
+	y2 = _y2;
+    }
+
+    if (gradient->n_stops == 2) {
+	/* If only two stops the Type 2 function is used by itself
+	 * without a Stitching function. Type 2 functions always have
+	 * the domain [0 1] */
+	first_stop = 0.0;
+	last_stop = 1.0;
+    }
+
     pattern_resource = _cairo_pdf_surface_new_object (surface);
     _cairo_output_stream_printf (surface->output,
                                  "%d 0 obj\r\n"
                                  "<< /Type /Pattern\r\n"
                                  "   /PatternType 2\r\n"
                                  "   /Matrix [ %f %f %f %f %f %f ]\r\n"
                                  "   /Shading\r\n"
                                  "      << /ShadingType 2\r\n"
                                  "         /ColorSpace /DeviceRGB\r\n"
                                  "         /Coords [ %f %f %f %f ]\r\n"
+                                 "         /Domain [ %f %f ]\r\n"
                                  "         /Function %d 0 R\r\n",
                                  pattern_resource.id,
                                  pat_to_pdf.xx, pat_to_pdf.yx,
                                  pat_to_pdf.xy, pat_to_pdf.yy,
                                  pat_to_pdf.x0, pat_to_pdf.y0,
                                  x1, y1, x2, y2,
+                                 first_stop, last_stop,
                                  color_function.id);
 
     if (extend == CAIRO_EXTEND_PAD) {
         _cairo_output_stream_printf (surface->output,
                                      "         /Extend [ true true ]\r\n");
     } else {
         _cairo_output_stream_printf (surface->output,
                                      "         /Extend [ false false ]\r\n");
@@ -1518,55 +2083,49 @@ static cairo_status_t
         if (status)
             return status;
 
         smask = cairo_pdf_surface_emit_transparency_group (surface, mask_resource);
         surface->emitted_pattern.smask = smask;
     }
 
     surface->emitted_pattern.type = CAIRO_PATTERN_TYPE_LINEAR;
-    status = _cairo_pdf_surface_add_alpha (surface, 1, &surface->emitted_pattern.alpha);
-    if (status)
-        return status;
-
     surface->emitted_pattern.pattern = pattern_resource;
-    status = _cairo_pdf_surface_add_pattern (surface, pattern_resource);
-    if (status)
-        return status;
-
-    return _cairo_pdf_surface_resume_content_stream (surface);
+    surface->emitted_pattern.alpha = 1.0;
+
+    _cairo_pdf_surface_resume_content_stream (surface);
+
+    return status;
 }
 
 static cairo_status_t
 _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t    *surface,
                                         cairo_radial_pattern_t *pattern)
 {
     cairo_pdf_resource_t pattern_resource, smask;
     cairo_pdf_resource_t color_function, alpha_function;
     double x1, y1, x2, y2, r1, r2;
     cairo_matrix_t pat_to_pdf;
     cairo_extend_t extend;
     cairo_status_t status;
 
     extend = cairo_pattern_get_extend (&pattern->base.base);
-    status = _cairo_pdf_surface_pause_content_stream (surface);
-    if (status)
-	return status;
+    _cairo_pdf_surface_pause_content_stream (surface);
 
     status = _cairo_pdf_surface_emit_pattern_stops (surface,
                                                     &pattern->base,
                                                     &color_function,
                                                     &alpha_function);
     if (status)
 	return status;
 
     pat_to_pdf = pattern->base.base.matrix;
     status = cairo_matrix_invert (&pat_to_pdf);
-    if (status)
-	return status;
+    /* cairo_pattern_set_matrix ensures the matrix is invertible */
+    assert (status == CAIRO_STATUS_SUCCESS);
 
     cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf);
     x1 = _cairo_fixed_to_double (pattern->c1.x);
     y1 = _cairo_fixed_to_double (pattern->c1.y);
     r1 = _cairo_fixed_to_double (pattern->r1);
     x2 = _cairo_fixed_to_double (pattern->c2.x);
     y2 = _cairo_fixed_to_double (pattern->c2.y);
     r2 = _cairo_fixed_to_double (pattern->r2);
@@ -1639,36 +2198,31 @@ static cairo_status_t
                                      ">>\r\n"
                                      "endobj\r\n");
 
         smask = cairo_pdf_surface_emit_transparency_group (surface, mask_resource);
         surface->emitted_pattern.smask = smask;
     }
 
     surface->emitted_pattern.type = CAIRO_PATTERN_TYPE_RADIAL;
-
-    status = _cairo_pdf_surface_add_alpha (surface, 1.0, &surface->emitted_pattern.alpha);
-    if (status)
-	return status;
-
     surface->emitted_pattern.pattern = pattern_resource;
-
-    status = _cairo_pdf_surface_add_pattern (surface, pattern_resource);
-    if (status)
-	return status;
-
-    return _cairo_pdf_surface_resume_content_stream (surface);
+    surface->emitted_pattern.alpha = 1.0;
+
+     _cairo_pdf_surface_resume_content_stream (surface);
+
+     return status;
 }
 
 static cairo_status_t
 _cairo_pdf_surface_emit_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
 {
     switch (pattern->type) {
     case CAIRO_PATTERN_TYPE_SOLID:
-	return _cairo_pdf_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
+	_cairo_pdf_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
+        return CAIRO_STATUS_SUCCESS;
 
     case CAIRO_PATTERN_TYPE_SURFACE:
 	return _cairo_pdf_surface_emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern);
 
     case CAIRO_PATTERN_TYPE_LINEAR:
 	return _cairo_pdf_surface_emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern);
 
     case CAIRO_PATTERN_TYPE_RADIAL:
@@ -1678,66 +2232,77 @@ static cairo_status_t
     ASSERT_NOT_REACHED;
     return CAIRO_STATUS_PATTERN_TYPE_MISMATCH;
 }
 
 static cairo_status_t
 _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface,
                                    cairo_bool_t         is_stroke)
 {
+    cairo_status_t status;
+    int alpha;
+
+    status = _cairo_pdf_surface_add_alpha (surface, surface->emitted_pattern.alpha, &alpha);
+    if (status)
+	return status;
     if (surface->emitted_pattern.type == CAIRO_PATTERN_TYPE_SOLID) {
 	_cairo_output_stream_printf (surface->output,
                                      "%f %f %f ",
                                      surface->emitted_pattern.red,
                                      surface->emitted_pattern.green,
                                      surface->emitted_pattern.blue);
 
         if (is_stroke)
             _cairo_output_stream_printf (surface->output, "RG ");
         else
             _cairo_output_stream_printf (surface->output, "rg ");
 
         _cairo_output_stream_printf (surface->output,
                                      "/a%d gs\r\n",
-                                     surface->emitted_pattern.alpha);
+                                     alpha);
     } else {
         if (is_stroke) {
             _cairo_output_stream_printf (surface->output,
-                                         "/Pattern CS /res%d SCN ",
-                                         surface->emitted_pattern.pattern);
+                                         "/Pattern CS /p%d SCN ",
+                                         surface->emitted_pattern.pattern.id);
         } else {
             _cairo_output_stream_printf (surface->output,
-                                         "/Pattern cs /res%d scn ",
-                                         surface->emitted_pattern.pattern);
+                                         "/Pattern cs /p%d scn ",
+                                         surface->emitted_pattern.pattern.id);
         }
+        _cairo_pdf_surface_add_pattern (surface, surface->emitted_pattern.pattern);
 
         _cairo_output_stream_printf (surface->output,
                                      "/a%d gs ",
-                                     surface->emitted_pattern.alpha );
+                                     alpha);
 
         _cairo_output_stream_printf (surface->output, "\r\n");
     }
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
 _cairo_pdf_surface_copy_page (void *abstract_surface)
 {
     cairo_pdf_surface_t *surface = abstract_surface;
 
+    _cairo_pdf_surface_stop_content_stream (surface);
+
     return _cairo_pdf_surface_write_page (surface);
 }
 
 static cairo_int_status_t
 _cairo_pdf_surface_show_page (void *abstract_surface)
 {
     cairo_pdf_surface_t *surface = abstract_surface;
     cairo_int_status_t status;
 
+    _cairo_pdf_surface_stop_content_stream (surface);
+
     status = _cairo_pdf_surface_write_page (surface);
     if (status)
 	return status;
 
     _cairo_pdf_surface_clear (surface);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1839,68 +2404,62 @@ static cairo_status_t
     pdf_path_info_t *info = closure;
 
     _cairo_output_stream_printf (info->output,
 				 "h\r\n");
 
     return CAIRO_STATUS_SUCCESS;
 }
 
+static cairo_status_t
+_cairo_pdf_surface_add_clip (cairo_pdf_surface_t  *surface,
+			     cairo_path_fixed_t	  *path,
+			     cairo_fill_rule_t     fill_rule)
+{
+    cairo_pdf_group_element_t elem;
+    cairo_status_t status;
+
+    memset (&elem, 0, sizeof elem);
+    elem.type = ELEM_CLIP;
+
+    if (path == NULL) {
+	elem.clip_path = NULL;
+    } else {
+	elem.clip_path = _cairo_path_fixed_create ();
+	if (elem.clip_path == NULL)
+	    return CAIRO_STATUS_NO_MEMORY;
+	status = _cairo_path_fixed_init_copy (elem.clip_path, path);
+	if (status)
+	    return status;
+    }
+    elem.fill_rule = fill_rule;
+
+    status = _cairo_pdf_surface_stop_content_stream (surface);
+    if (status)
+	return status;
+
+    status = _cairo_array_append (surface->current_group, &elem);
+    if (status)
+	return status;
+
+    _cairo_pdf_surface_start_content_stream (surface);
+
+    return status;
+}
+
 static cairo_int_status_t
 _cairo_pdf_surface_intersect_clip_path (void			*abstract_surface,
 					cairo_path_fixed_t	*path,
 					cairo_fill_rule_t	fill_rule,
 					double			tolerance,
 					cairo_antialias_t	antialias)
 {
     cairo_pdf_surface_t *surface = abstract_surface;
-    cairo_status_t status;
-    const char *pdf_operator;
-    pdf_path_info_t info;
-
-    if (path == NULL) {
-	if (surface->has_clip)
-	    _cairo_output_stream_printf (surface->output, "Q\r\n");
-	surface->has_clip = FALSE;
-	return CAIRO_STATUS_SUCCESS;
-    }
-
-    if (!surface->has_clip) {
-	_cairo_output_stream_printf (surface->output, "q ");
-	surface->has_clip = TRUE;
-    }
-
-    info.output = surface->output;
-    info.cairo_to_pdf = &surface->cairo_to_pdf;
-    info.ctm_inverse = NULL;
-
-    status = _cairo_path_fixed_interpret (path,
-					  CAIRO_DIRECTION_FORWARD,
-					  _cairo_pdf_path_move_to,
-					  _cairo_pdf_path_line_to,
-					  _cairo_pdf_path_curve_to,
-					  _cairo_pdf_path_close_path,
-					  &info);
-
-    switch (fill_rule) {
-    case CAIRO_FILL_RULE_WINDING:
-	pdf_operator = "W";
-	break;
-    case CAIRO_FILL_RULE_EVEN_ODD:
-	pdf_operator = "W*";
-	break;
-    default:
-	ASSERT_NOT_REACHED;
-    }
-
-    _cairo_output_stream_printf (surface->output,
-				 "%s n\r\n",
-				 pdf_operator);
-
-    return status;
+
+    return _cairo_pdf_surface_add_clip (surface, path, fill_rule);
 }
 
 static void
 _cairo_pdf_surface_get_font_options (void                  *abstract_surface,
 				     cairo_font_options_t  *options)
 {
     _cairo_font_options_init_default (options);
 
@@ -1926,21 +2485,18 @@ static cairo_pdf_resource_t
                                  cairo_version_string ());
 
     return info;
 }
 
 static void
 _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface)
 {
-    cairo_pdf_resource_t page, *res, smask;
-    cairo_pdf_font_t font;
-    int num_pages, num_fonts, i;
-    int num_alphas, num_smasks, num_resources;
-    double alpha;
+    cairo_pdf_resource_t page;
+    int num_pages, i;
 
     _cairo_pdf_surface_update_object (surface, surface->pages_resource);
     _cairo_output_stream_printf (surface->output,
 				 "%d 0 obj\r\n"
 				 "<< /Type /Pages\r\n"
 				 "   /Kids [ ",
 				 surface->pages_resource.id);
 
@@ -1948,90 +2504,16 @@ static void
     for (i = 0; i < num_pages; i++) {
 	_cairo_array_copy_element (&surface->pages, i, &page);
 	_cairo_output_stream_printf (surface->output, "%d 0 R ", page.id);
     }
 
     _cairo_output_stream_printf (surface->output, "]\r\n");
     _cairo_output_stream_printf (surface->output, "   /Count %d\r\n", num_pages);
 
-    _cairo_output_stream_printf (surface->output, "   /Resources <<\r\n");
-
-    num_alphas =  _cairo_array_num_elements (&surface->alphas);
-    num_smasks =  _cairo_array_num_elements (&surface->smasks);
-    if (num_alphas > 0 || num_smasks > 0) {
-	_cairo_output_stream_printf (surface->output,
-				     "      /ExtGState <<\r\n");
-
-	for (i = 0; i < num_alphas; i++) {
-	    _cairo_array_copy_element (&surface->alphas, i, &alpha);
-	    _cairo_output_stream_printf (surface->output,
-					 "         /a%d << /CA %f /ca %f >>\r\n",
-					 i, alpha, alpha);
-	}
-
-        for (i = 0; i < num_smasks; i++) {
-	    _cairo_array_copy_element (&surface->smasks, i, &smask);
-	    _cairo_output_stream_printf (surface->output,
-					 "         /sm%d %d 0 R\r\n",
-					 smask.id, smask.id);
-	}
-
-	_cairo_output_stream_printf (surface->output,
-				     "      >>\r\n");
-    }
-
-    num_resources = _cairo_array_num_elements (&surface->patterns);
-    if (num_resources > 0) {
-	_cairo_output_stream_printf (surface->output,
-				     "      /Pattern <<");
-	for (i = 0; i < num_resources; i++) {
-	    res = _cairo_array_index (&surface->patterns, i);
-	    _cairo_output_stream_printf (surface->output,
-					 " /res%d %d 0 R",
-					 res->id, res->id);
-	}
-
-	_cairo_output_stream_printf (surface->output,
-				     " >>\r\n");
-    }
-
-    num_resources = _cairo_array_num_elements (&surface->xobjects);
-    if (num_resources > 0) {
-	_cairo_output_stream_printf (surface->output,
-				     "      /XObject <<");
-
-	for (i = 0; i < num_resources; i++) {
-	    res = _cairo_array_index (&surface->xobjects, i);
-	    _cairo_output_stream_printf (surface->output,
-					 " /res%d %d 0 R",
-					 res->id, res->id);
-	}
-
-	_cairo_output_stream_printf (surface->output,
-				     " >>\r\n");
-    }
-
-    num_fonts = _cairo_array_num_elements (&surface->fonts);
-    if (num_fonts > 0) {
-        _cairo_output_stream_printf (surface->output,"      /Font <<\r\n");
-        num_fonts = _cairo_array_num_elements (&surface->fonts);
-        for (i = 0; i < num_fonts; i++) {
-            _cairo_array_copy_element (&surface->fonts, i, &font);
-            _cairo_output_stream_printf (surface->output,
-                                         "         /CairoFont-%d-%d %d 0 R\r\n",
-                                         font.font_id,
-                                         font.subset_id,
-                                         font.subset_resource.id);
-        }
-        _cairo_output_stream_printf (surface->output, "      >>\r\n");
-    }
-
-    _cairo_output_stream_printf (surface->output,
-				 "   >>\r\n");
 
     /* TODO: Figure out wich other defaults to be inherited by /Page
      * objects. */
     _cairo_output_stream_printf (surface->output,
 				 ">>\r\n"
 				 "endobj\r\n");
 }
 
@@ -2206,17 +2688,20 @@ static cairo_status_t
 				     " %d",
 				     subset->widths[i]);
 
     _cairo_output_stream_printf (surface->output,
                                  " ]]\r\n"
 				 ">>\r\n"
 				 "endobj\r\n");
 
-    subset_resource = _cairo_pdf_surface_new_object (surface);
+    subset_resource = _cairo_pdf_surface_get_font_resource (surface,
+							    font_subset->font_id,
+							    font_subset->subset_id);
+    _cairo_pdf_surface_update_object (surface, subset_resource);
     _cairo_output_stream_printf (surface->output,
 				 "%d 0 obj\r\n"
 				 "<< /Type /Font\r\n"
 				 "   /Subtype /Type0\r\n"
 				 "   /BaseFont /%s\r\n"
                                  "   /Encoding /Identity-H\r\n"
 				 "   /DescendantFonts [ %d 0 R]\r\n",
 				 subset_resource.id,
@@ -2344,17 +2829,20 @@ static cairo_status_t
 				 subset->x_min,
 				 subset->y_min,
 				 subset->x_max,
 				 subset->y_max,
 				 subset->ascent,
 				 subset->descent,
 				 stream.id);
 
-    subset_resource = _cairo_pdf_surface_new_object (surface);
+    subset_resource = _cairo_pdf_surface_get_font_resource (surface,
+							    font_subset->font_id,
+							    font_subset->subset_id);
+    _cairo_pdf_surface_update_object (surface, subset_resource);
     _cairo_output_stream_printf (surface->output,
 				 "%d 0 obj\r\n"
 				 "<< /Type /Font\r\n"
 				 "   /Subtype /Type1\r\n"
 				 "   /BaseFont /%s\r\n"
 				 "   /FirstChar 0\r\n"
 				 "   /LastChar %d\r\n"
 				 "   /FontDescriptor %d 0 R\r\n"
@@ -2524,17 +3012,20 @@ static cairo_status_t
                                      " %ld",
                                      (long)(subset.widths[i]*PDF_UNITS_PER_EM));
 
     _cairo_output_stream_printf (surface->output,
                                  " ]]\r\n"
 				 ">>\r\n"
 				 "endobj\r\n");
 
-    subset_resource = _cairo_pdf_surface_new_object (surface);
+    subset_resource = _cairo_pdf_surface_get_font_resource (surface,
+							    font_subset->font_id,
+							    font_subset->subset_id);
+    _cairo_pdf_surface_update_object (surface, subset_resource);
     _cairo_output_stream_printf (surface->output,
 				 "%d 0 obj\r\n"
 				 "<< /Type /Font\r\n"
 				 "   /Subtype /Type0\r\n"
 				 "   /BaseFont /%s\r\n"
                                  "   /Encoding /Identity-H\r\n"
 				 "   /DescendantFonts [ %d 0 R]\r\n",
 				 subset_resource.id,
@@ -2787,17 +3278,20 @@ static cairo_status_t
     _cairo_output_stream_printf (surface->output,
 				 ">>\r\n"
 				 "endobj\r\n");
 
     free (glyphs);
 
     to_unicode_stream = _cairo_pdf_surface_emit_to_unicode_stream (surface, font_subset, FALSE);
 
-    subset_resource = _cairo_pdf_surface_new_object (surface);
+    subset_resource = _cairo_pdf_surface_get_font_resource (surface,
+							    font_subset->font_id,
+							    font_subset->subset_id);
+    _cairo_pdf_surface_update_object (surface, subset_resource);
     matrix = font_subset->scaled_font->scale;
     status = cairo_matrix_invert (&matrix);
     /* _cairo_scaled_font_init ensures the matrix is invertible */
     assert (status == CAIRO_STATUS_SUCCESS);
     _cairo_output_stream_printf (surface->output,
 				 "%d 0 obj\r\n"
 				 "<< /Type /Font\r\n"
 				 "   /Subtype /Type3\r\n"
@@ -2949,76 +3443,137 @@ static long
 	_cairo_output_stream_printf (surface->output,
 				     "%s 00000 n\r\n", buffer);
     }
 
     return offset;
 }
 
 static cairo_status_t
+_cairo_pdf_surface_emit_clip (cairo_pdf_surface_t  *surface,
+			      cairo_path_fixed_t   *path,
+			      cairo_fill_rule_t	    fill_rule)
+{
+    cairo_status_t status;
+    const char *pdf_operator;
+    pdf_path_info_t info;
+
+    if (path == NULL) {
+	_cairo_output_stream_printf (surface->output, "Q q\r\n");
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    info.output = surface->output;
+    info.cairo_to_pdf = &surface->cairo_to_pdf;
+    info.ctm_inverse = NULL;
+
+    status = _cairo_path_fixed_interpret (path,
+					  CAIRO_DIRECTION_FORWARD,
+					  _cairo_pdf_path_move_to,
+					  _cairo_pdf_path_line_to,
+					  _cairo_pdf_path_curve_to,
+					  _cairo_pdf_path_close_path,
+					  &info);
+
+    switch (fill_rule) {
+    case CAIRO_FILL_RULE_WINDING:
+	pdf_operator = "W";
+	break;
+    case CAIRO_FILL_RULE_EVEN_ODD:
+	pdf_operator = "W*";
+	break;
+    default:
+	ASSERT_NOT_REACHED;
+    }
+
+    _cairo_output_stream_printf (surface->output,
+				 "%s n\r\n",
+				 pdf_operator);
+
+    return status;
+}
+
+static cairo_status_t
 _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
 {
     cairo_status_t status;
     cairo_pdf_resource_t page;
-    cairo_pdf_resource_t stream;
-    int num_streams, i;
-
-    if (surface->has_clip) {
-	_cairo_output_stream_printf (surface->output, "Q\r\n");
-	surface->has_clip = FALSE;
+    cairo_pdf_resource_t content_group, knockout_group, page_content;
+    cairo_bool_t has_fallback_images = FALSE;
+
+    if (_cairo_array_num_elements (&surface->knockout_group) > 0)
+	has_fallback_images = TRUE;
+
+    _cairo_pdf_surface_open_group (surface);
+    _cairo_pdf_surface_write_group_list (surface, &surface->content_group);
+    _cairo_pdf_surface_close_group (surface, &content_group);
+
+    if (has_fallback_images) {
+	_cairo_pdf_surface_open_knockout_group (surface, &content_group);
+	_cairo_pdf_surface_write_group_list (surface, &surface->knockout_group);
+	_cairo_pdf_surface_close_group (surface, &knockout_group);
     }
 
-    status = _cairo_pdf_surface_close_stream (surface);
-    if (status)
-	return status;
+    page_content = _cairo_pdf_surface_open_stream (surface,
+						   TRUE,
+						   "   /Type /XObject\r\n"
+						   "   /Subtype /Form\r\n"
+						   "   /BBox [ 0 0 %f %f ]\r\n"
+						   "   /Group <<\r\n"
+						   "      /Type /Group\r\n"
+						   "      /S /Transparency\r\n"
+						   "      /CS /DeviceRGB\r\n"
+						   "   >>\r\n",
+						   surface->width,
+						   surface->height);
+    _cairo_output_stream_printf (surface->output,
+				 "/x%d Do\r\n",
+				 has_fallback_images ? knockout_group.id : content_group.id);
+    _cairo_pdf_surface_close_stream (surface);
 
     page = _cairo_pdf_surface_new_object (surface);
     _cairo_output_stream_printf (surface->output,
 				 "%d 0 obj\r\n"
 				 "<< /Type /Page\r\n"
-				 "   /Parent %d 0 R\r\n",
+				 "   /Parent %d 0 R\r\n"
+				 "   /MediaBox [ 0 0 %f %f ]\r\n"
+				 "   /Contents [ %d 0 R ]\r\n"
+				 "   /Group <<\r\n"
+				 "      /Type /Group\r\n"
+				 "      /S /Transparency\r\n"
+				 "      /CS /DeviceRGB\r\n"
+				 "   >>\r\n"
+				 "   /Resources <<\r\n"
+				 "      /XObject << /x%d %d 0 R >>\r\n"
+				 "   >>\r\n"
+				 ">>\r\n"
+				 "endobj\r\n",
 				 page.id,
-				 surface->pages_resource.id);
-
-    _cairo_output_stream_printf (surface->output,
-				 "   /MediaBox [ 0 0 %f %f ]\r\n",
+				 surface->pages_resource.id,
 				 surface->width,
-				 surface->height);
-
-    _cairo_output_stream_printf (surface->output,
-				 "   /Contents [");
-    num_streams = _cairo_array_num_elements (&surface->streams);
-    for (i = 0; i < num_streams; i++) {
-	_cairo_array_copy_element (&surface->streams, i, &stream);
-	_cairo_output_stream_printf (surface->output,
-				     " %d 0 R",
-				     stream.id);
-    }
-    _cairo_output_stream_printf (surface->output,
-				 " ]\r\n"
-                                 "   /Group <<\r\n"
-                                 "      /Type /Group\r\n"
-                                 "      /S /Transparency\r\n"
-                                 "      /CS /DeviceRGB\r\n"
-                                 "   >>\r\n"
-				 ">>\r\n"
-				 "endobj\r\n");
+				 surface->height,
+				 page_content.id,
+				 has_fallback_images ? knockout_group.id : content_group.id,
+				 has_fallback_images ? knockout_group.id : content_group.id);
 
     status = _cairo_array_append (&surface->pages, &page);
     if (status)
 	return status;
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_bool_t
 _surface_pattern_supported (cairo_surface_pattern_t *pattern)
 {
     cairo_extend_t extend;
 
+    if (_cairo_surface_is_meta (pattern->surface))
+	return TRUE;
+
     if (pattern->surface->backend->acquire_source_image == NULL)
 	return FALSE;
 
     /* Does an ALPHA-only source surface even make sense? Maybe, but I
      * don't think it's worth the extra code to support it. */
 
 /* XXX: Need to write this function here...
     content = cairo_surface_get_content (pattern->surface);
@@ -3087,113 +3642,264 @@ static cairo_bool_t
 
     if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
 	return _surface_pattern_supported ((cairo_surface_pattern_t *) pattern);
 
     return FALSE;
 }
 
 static cairo_int_status_t
-_cairo_pdf_surface_operation_supported (cairo_pdf_surface_t *surface,
-		      cairo_operator_t op,
-		      cairo_pattern_t *pattern)
+_cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t  *surface,
+				      cairo_operator_t      op,
+				      cairo_pattern_t      *pattern)
 {
-    if (surface->force_fallbacks)
-	return FALSE;
+    if (surface->force_fallbacks && surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     if (! _pattern_supported (pattern))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if (op == CAIRO_OPERATOR_OVER) {
+	if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+	    cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
+	    if ( _cairo_surface_is_meta (surface_pattern->surface))
+	    return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
+	}
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    /* The SOURCE operator is only supported for the fallback images. */
+    if (op == CAIRO_OPERATOR_SOURCE &&
+	surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER)
+	return CAIRO_STATUS_SUCCESS;
+
+    return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_bool_t
+_cairo_pdf_surface_operation_supported (cairo_pdf_surface_t  *surface,
+					cairo_operator_t      op,
+					cairo_pattern_t      *pattern)
+{
+    if (_cairo_pdf_surface_analyze_operation (surface, op, pattern) != CAIRO_INT_STATUS_UNSUPPORTED)
+	return TRUE;
+    else
 	return FALSE;
-
-    /* XXX: We can probably support a fair amount more than just OVER,
-     * but this should cover many common cases at least. */
-    if (op == CAIRO_OPERATOR_OVER)
-	return TRUE;
-
-    return FALSE;
 }
 
 static cairo_int_status_t
-_cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface,
-		    cairo_operator_t op,
-		    cairo_pattern_t *pattern)
+_cairo_pdf_surface_set_operator (cairo_pdf_surface_t *surface,
+				 cairo_operator_t op)
 {
-    if (_cairo_pdf_surface_operation_supported (surface, op, pattern))
+    if (op == CAIRO_OPERATOR_OVER)
 	return CAIRO_STATUS_SUCCESS;
-    else
-	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if (op == CAIRO_OPERATOR_SOURCE) {
+	surface->current_group = &surface->knockout_group;
+	_cairo_pdf_surface_stop_content_stream (surface);
+	_cairo_pdf_surface_start_content_stream (surface);
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    return CAIRO_INT_STATUS_UNSUPPORTED;
 }
 
 static cairo_int_status_t
 _cairo_pdf_surface_paint (void			*abstract_surface,
 			  cairo_operator_t	 op,
 			  cairo_pattern_t	*source)
 {
     cairo_pdf_surface_t *surface = abstract_surface;
-    cairo_pdf_resource_t group = {0}; /* squelch bogus compiler warning */
+    cairo_pdf_resource_t smask_group = {0}; /* squelch bogus compiler warning */
     cairo_status_t status;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_pdf_surface_analyze_operation (surface, op, source);
 
-    /* XXX: It would be nice to be able to assert this condition
-     * here. But, we actually allow one 'cheat' that is used when
-     * painting the final image-based fallbacks. The final fallbacks
-     * do have alpha which we support by blending with white. This is
-     * possible only because there is nothing between the fallback
-     * images and the paper, nor is anything painted above. */
-    /*
-    assert (_cairo_pdf_surface_operation_supported (op, source));
-    */
+    assert (_cairo_pdf_surface_operation_supported (surface, op, source));
 
     status = _cairo_pdf_surface_emit_pattern (surface, source);
     if (status)
 	return status;
 
+    status = _cairo_pdf_surface_set_operator (surface, op);
+    if (status)
+	return status;
+
     if (surface->emitted_pattern.smask.id != 0) {
-	status = _cairo_pdf_surface_begin_group (surface, &group);
-        if (status)
-            return status;
+	_cairo_pdf_surface_pause_content_stream (surface);
+	_cairo_pdf_surface_open_group (surface);
     } else {
-        _cairo_output_stream_printf (surface->output, "q ");
+	_cairo_output_stream_printf (surface->output, "q ");
     }
 
     _cairo_pdf_surface_select_pattern (surface, FALSE);
 
     _cairo_output_stream_printf (surface->output,
 				 "0 0 %f %f re f\r\n",
 				 surface->width, surface->height);
 
     if (surface->emitted_pattern.smask.id != 0) {
-        _cairo_pdf_surface_end_group (surface);
-
-        _cairo_output_stream_printf (surface->output,
-                                     "q /sm%d gs /res%d Do Q\r\n",
-                                     surface->emitted_pattern.smask,
-                                     group.id);
+	_cairo_pdf_surface_close_group (surface, &smask_group);
+	_cairo_pdf_surface_resume_content_stream (surface);
+	_cairo_output_stream_printf (surface->output,
+				     "q /s%d gs /x%d Do Q\r\n",
+				     surface->emitted_pattern.smask,
+				     smask_group.id);
+	status = _cairo_pdf_surface_add_smask (surface, surface->emitted_pattern.smask);
+	if (status)
+	    return status;
+	status = _cairo_pdf_surface_add_xobject (surface, smask_group);
+	if (status)
+	    return status;
     } else {
-        _cairo_output_stream_printf (surface->output, "Q\r\n");
+	_cairo_output_stream_printf (surface->output, "Q\r\n");
     }
 
-    return _cairo_output_stream_get_status (surface->output);
+    status = _cairo_output_stream_get_status (surface->output);
+    if (status)
+        return status;
+
+    return _cairo_pdf_surface_check_content_stream_size (surface);
 }
 
 static cairo_int_status_t
 _cairo_pdf_surface_mask	(void			*abstract_surface,
 			 cairo_operator_t	 op,
 			 cairo_pattern_t	*source,
 			 cairo_pattern_t	*mask)
 {
     cairo_pdf_surface_t *surface = abstract_surface;
-
-    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    ASSERT_NOT_REACHED;
-
-    return CAIRO_INT_STATUS_UNSUPPORTED;
+    cairo_pdf_resource_t mask_group;
+    cairo_pdf_resource_t group = {0}; /* squelch bogus compiler warning */
+    cairo_pdf_resource_t source_group;
+    cairo_pdf_resource_t smask;
+    cairo_pdf_resource_t gstate;
+    cairo_status_t status, status2;
+
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+	status = _cairo_pdf_surface_analyze_operation (surface, op, source);
+	if (status != CAIRO_STATUS_SUCCESS &&
+	    status != CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
+	    return status;
+
+	status2 = _cairo_pdf_surface_analyze_operation (surface, op, mask);
+	if (status2 != CAIRO_STATUS_SUCCESS)
+	    return status2;
+
+	return status;
+    }
+
+    assert (_cairo_pdf_surface_operation_supported (surface, op, source));
+    assert (_cairo_pdf_surface_operation_supported (surface, op, mask));
+
+    status = _cairo_pdf_surface_set_operator (surface, op);
+    if (status)
+	return status;
+
+    /* Create mask group */
+    status = _cairo_pdf_surface_emit_pattern (surface, mask);
+    if (status)
+	return status;
+
+    _cairo_pdf_surface_pause_content_stream (surface);
+
+    _cairo_pdf_surface_open_group (surface);
+    _cairo_pdf_surface_select_pattern (surface, FALSE);
+    _cairo_output_stream_printf (surface->output,
+				 "0 0 %f %f re f\r\n",
+				 surface->width, surface->height);
+    _cairo_pdf_surface_close_group (surface, &mask_group);
+
+    if (surface->emitted_pattern.smask.id != 0) {
+	group = mask_group;
+	_cairo_pdf_surface_open_group (surface);
+	_cairo_output_stream_printf (surface->output,
+				     "/s%d gs /x%d Do\r\n",
+				     surface->emitted_pattern.smask,
+				     group.id);
+	status = _cairo_pdf_surface_add_smask (surface, surface->emitted_pattern.smask);
+	if (status)
+	    return status;
+	status = _cairo_pdf_surface_add_xobject (surface, group);
+	if (status)
+	    return status;
+	_cairo_pdf_surface_close_group (surface, &mask_group);
+    }
+
+    /* Create source group */
+    status = _cairo_pdf_surface_emit_pattern (surface, source);
+    if (status)
+	return status;
+
+    _cairo_pdf_surface_pause_content_stream (surface);
+
+    _cairo_pdf_surface_open_group (surface);
+    _cairo_pdf_surface_select_pattern (surface, FALSE);
+    _cairo_output_stream_printf (surface->output,
+				 "0 0 %f %f re f\r\n",
+				 surface->width, surface->height);
+    _cairo_pdf_surface_close_group (surface, &source_group);
+
+    if (surface->emitted_pattern.smask.id != 0) {
+	group = source_group;
+	_cairo_pdf_surface_open_group (surface);
+	_cairo_output_stream_printf (surface->output,
+				     "/s%d gs /x%d Do\r\n",
+				     surface->emitted_pattern.smask,
+				     group.id);
+	status = _cairo_pdf_surface_add_smask (surface, surface->emitted_pattern.smask);
+	if (status)
+	    return status;
+	status = _cairo_pdf_surface_add_xobject (surface, group);
+	if (status)
+	    return status;
+	_cairo_pdf_surface_close_group (surface, &source_group);
+    }
+
+    /* Create an smask based on the alpha component of mask_group */
+    smask = _cairo_pdf_surface_new_object (surface);
+    _cairo_output_stream_printf (surface->output,
+				 "%d 0 obj\r\n"
+				 "<< /Type /Mask\r\n"
+				 "   /S /Alpha\r\n"
+				 "   /G %d 0 R\r\n"
+				 ">>\r\n"
+				 "endobj\r\n",
+				 smask.id,
+				 mask_group.id);
+
+    /* Create a GState that uses the smask */
+    gstate = _cairo_pdf_surface_new_object (surface);
+    _cairo_output_stream_printf (surface->output,
+				 "%d 0 obj\r\n"
+				 "<< /Type /ExtGState\r\n"
+				 "   /SMask %d 0 R\r\n"
+				 "   /ca 1\r\n"
+				 "   /CA 1\r\n"
+				 "   /AIS false\r\n"
+				 ">>\r\n"
+				 "endobj\r\n",
+				 gstate.id,
+				 smask.id);
+
+    /* Select the GState then draw the source */
+    _cairo_pdf_surface_resume_content_stream (surface);
+    _cairo_output_stream_printf (surface->output,
+				 "q /s%d gs /x%d Do Q\r\n",
+				 gstate.id,
+				 source_group.id);
+    status = _cairo_pdf_surface_add_smask (surface, gstate);
+    if (status)
+	return status;
+    status = _cairo_pdf_surface_add_xobject (surface, source_group);
+    if (status)
+	return status;
+
+    return _cairo_output_stream_get_status (surface->output);
 }
 
 static int
 _cairo_pdf_line_cap (cairo_line_cap_t cap)
 {
     switch (cap) {
     case CAIRO_LINE_CAP_BUTT:
 	return 0;
@@ -3264,36 +3970,35 @@ static cairo_int_status_t
 			   cairo_path_fixed_t	*path,
 			   cairo_stroke_style_t	*style,
 			   cairo_matrix_t	*ctm,
 			   cairo_matrix_t	*ctm_inverse,
 			   double		 tolerance,
 			   cairo_antialias_t	 antialias)
 {
     cairo_pdf_surface_t *surface = abstract_surface;
-    cairo_pdf_resource_t group = {0}; /* squelch bogus compiler warning */
+    cairo_pdf_resource_t smask_group = {0}; /* squelch bogus compiler warning */
     pdf_path_info_t info;
     cairo_status_t status;
     cairo_matrix_t m;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_pdf_surface_analyze_operation (surface, op, source);
 
     assert (_cairo_pdf_surface_operation_supported (surface, op, source));
 
     status = _cairo_pdf_surface_emit_pattern (surface, source);
     if (status)
 	return status;
 
     if (surface->emitted_pattern.smask.id != 0) {
-	status = _cairo_pdf_surface_begin_group (surface, &group);
-        if (status)
-            return status;
+	_cairo_pdf_surface_pause_content_stream (surface);
+	_cairo_pdf_surface_open_group (surface);
     } else {
-        _cairo_output_stream_printf (surface->output, "q ");
+	_cairo_output_stream_printf (surface->output, "q ");
     }
 
     _cairo_pdf_surface_select_pattern (surface, TRUE);
 
     status = _cairo_pdf_surface_emit_stroke_style (surface,
 						   style);
     if (status)
 	return status;
@@ -3314,59 +4019,72 @@ static cairo_int_status_t
 					  _cairo_pdf_path_line_to,
 					  _cairo_pdf_path_curve_to,
 					  _cairo_pdf_path_close_path,
 					  &info);
 
     _cairo_output_stream_printf (surface->output, "S Q\r\n");
 
     if (surface->emitted_pattern.smask.id != 0) {
-        _cairo_pdf_surface_end_group (surface);
-
-        _cairo_output_stream_printf (surface->output,
-                                     "q /sm%d gs /res%d Do Q\r\n",
-                                     surface->emitted_pattern.smask,
-                                     group.id);
+	_cairo_pdf_surface_close_group (surface, &smask_group);
+	_cairo_pdf_surface_resume_content_stream (surface);
+	_cairo_output_stream_printf (surface->output,
+				     "q /s%d gs /x%d Do Q\r\n",
+				     surface->emitted_pattern.smask,
+				     smask_group.id);
+	status = _cairo_pdf_surface_add_smask (surface, surface->emitted_pattern.smask);
+	if (status)
+	    return status;
+	status = _cairo_pdf_surface_add_xobject (surface, smask_group);
+	if (status)
+	    return status;
     } else {
-        _cairo_output_stream_printf (surface->output, "Q\r\n");
+	_cairo_output_stream_printf (surface->output, "Q\r\n");
     }
 
-    return status;
+    status = _cairo_output_stream_get_status (surface->output);
+    if (status)
+	return status;
+
+    return _cairo_pdf_surface_check_content_stream_size (surface);
 }
 
 static cairo_int_status_t
 _cairo_pdf_surface_fill (void			*abstract_surface,
 			 cairo_operator_t	 op,
 			 cairo_pattern_t	*source,
 			 cairo_path_fixed_t	*path,
 			 cairo_fill_rule_t	 fill_rule,
 			 double			 tolerance,
 			 cairo_antialias_t	 antialias)
 {
     cairo_pdf_surface_t *surface = abstract_surface;
-    cairo_pdf_resource_t group = {0}; /* squelch bogus compiler warning */
+    cairo_pdf_resource_t smask_group = {0}; /* squelch bogus compiler warning */
     const char *pdf_operator;
     cairo_status_t status;
     pdf_path_info_t info;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_pdf_surface_analyze_operation (surface, op, source);
 
     assert (_cairo_pdf_surface_operation_supported (surface, op, source));
 
+    status = _cairo_pdf_surface_set_operator (surface, op);
+    if (status)
+	return status;
+
     status = _cairo_pdf_surface_emit_pattern (surface, source);
     if (status)
 	return status;
 
     if (surface->emitted_pattern.smask.id != 0) {
-	status = _cairo_pdf_surface_begin_group (surface, &group);
-        if (status)
-            return status;
+	_cairo_pdf_surface_pause_content_stream (surface);
+	_cairo_pdf_surface_open_group (surface);
     } else {
-        _cairo_output_stream_printf (surface->output, "q ");
+	_cairo_output_stream_printf (surface->output, "q ");
     }
 
     _cairo_pdf_surface_select_pattern (surface, FALSE);
     info.output = surface->output;
     info.cairo_to_pdf = &surface->cairo_to_pdf;
     info.ctm_inverse = NULL;
     status = _cairo_path_fixed_interpret (path,
 					  CAIRO_DIRECTION_FORWARD,
@@ -3387,41 +4105,51 @@ static cairo_int_status_t
 	ASSERT_NOT_REACHED;
     }
 
     _cairo_output_stream_printf (surface->output,
 				 "%s\r\n",
 				 pdf_operator);
 
     if (surface->emitted_pattern.smask.id != 0) {
-        _cairo_pdf_surface_end_group (surface);
-
-        _cairo_output_stream_printf (surface->output,
-                                     "q /sm%d gs /res%d Do Q\r\n",
-                                     surface->emitted_pattern.smask,
-                                     group.id);
+	_cairo_pdf_surface_close_group (surface, &smask_group);
+	_cairo_pdf_surface_resume_content_stream (surface);
+	_cairo_output_stream_printf (surface->output,
+				     "q /s%d gs /x%d Do Q\r\n",
+				     surface->emitted_pattern.smask,
+				     smask_group.id);
+	status = _cairo_pdf_surface_add_smask (surface, surface->emitted_pattern.smask);
+	if (status)
+	    return status;
+	status = _cairo_pdf_surface_add_xobject (surface, smask_group);
+	if (status)
+	    return status;
     } else {
-        _cairo_output_stream_printf (surface->output, "Q\r\n");
+	_cairo_output_stream_printf (surface->output, "Q\r\n");
     }
 
-    return status;
+    status = _cairo_output_stream_get_status (surface->output);
+    if (status)
+	return status;
+
+    return _cairo_pdf_surface_check_content_stream_size (surface);
 }
 
 #define GLYPH_POSITION_TOLERANCE 0.001
 
 static cairo_int_status_t
 _cairo_pdf_surface_show_glyphs (void			*abstract_surface,
 				cairo_operator_t	 op,
 				cairo_pattern_t		*source,
 				cairo_glyph_t		*glyphs,
 				int			 num_glyphs,
 				cairo_scaled_font_t	*scaled_font)
 {
     cairo_pdf_surface_t *surface = abstract_surface;
-    cairo_pdf_resource_t group = {0}; /* squelch bogus compiler warning */
+    cairo_pdf_resource_t smask_group = {0}; /* squelch bogus compiler warning */
     unsigned int current_subset_id = (unsigned int)-1;
     cairo_scaled_font_subsets_glyph_t subset_glyph;
     cairo_bool_t diagonal, in_TJ;
     cairo_status_t status;
     double Tlm_x = 0, Tlm_y = 0;
     double Tm_x = 0, y;
     int i, hex_width;
 
@@ -3430,21 +4158,20 @@ static cairo_int_status_t
 
     assert (_cairo_pdf_surface_operation_supported (surface, op, source));
 
     status = _cairo_pdf_surface_emit_pattern (surface, source);
     if (status)
 	return status;
 
     if (surface->emitted_pattern.smask.id != 0) {
-	status = _cairo_pdf_surface_begin_group (surface, &group);
-        if (status)
-            return status;
+	_cairo_pdf_surface_pause_content_stream (surface);
+	_cairo_pdf_surface_open_group (surface);
     } else {
-        _cairo_output_stream_printf (surface->output, "q ");
+	_cairo_output_stream_printf (surface->output, "q ");
     }
 
     _cairo_pdf_surface_select_pattern (surface, FALSE);
 
     _cairo_output_stream_printf (surface->output,
 				 "BT\r\n");
 
     if (scaled_font->scale.xy == 0.0 &&
@@ -3473,20 +4200,23 @@ static cairo_int_status_t
                                              &y);
         }
 
 	if (subset_glyph.subset_id != current_subset_id) {
             if (in_TJ) {
                 _cairo_output_stream_printf (surface->output, ">] TJ\r\n");
                 in_TJ = FALSE;
             }
-            _cairo_output_stream_printf (surface->output,
-                                         "/CairoFont-%d-%d 1 Tf\r\n",
-                                         subset_glyph.font_id,
-                                         subset_glyph.subset_id);
+	    _cairo_output_stream_printf (surface->output,
+					 "/f-%d-%d 1 Tf\r\n",
+					 subset_glyph.font_id,
+					 subset_glyph.subset_id);
+	    _cairo_pdf_surface_add_font (surface,
+					 subset_glyph.font_id,
+					 subset_glyph.subset_id);
         }
 
         if (subset_glyph.subset_id != current_subset_id || !diagonal) {
             _cairo_output_stream_printf (surface->output,
                                          "%f %f %f %f %f %f Tm\r\n",
                                          scaled_font->scale.xx,
                                          -scaled_font->scale.yx,
                                          -scaled_font->scale.xy,
@@ -3578,41 +4308,52 @@ static cairo_int_status_t
                                          subset_glyph.subset_glyph_index);
         }
     }
 
     _cairo_output_stream_printf (surface->output,
 				 "ET\r\n");
 
     if (surface->emitted_pattern.smask.id != 0) {
-        _cairo_pdf_surface_end_group (surface);
-
-        _cairo_output_stream_printf (surface->output,
-                                     "q /sm%d gs /res%d Do Q\r\n",
-                                     surface->emitted_pattern.smask,
-                                     group.id);
+	_cairo_pdf_surface_close_group (surface, &smask_group);
+	_cairo_pdf_surface_resume_content_stream (surface);
+
+	_cairo_output_stream_printf (surface->output,
+				     "q /s%d gs /x%d Do Q\r\n",
+				     surface->emitted_pattern.smask,
+				     smask_group.id);
+	status = _cairo_pdf_surface_add_smask (surface, surface->emitted_pattern.smask);
+	if (status)
+	    return status;
+	status = _cairo_pdf_surface_add_xobject (surface, smask_group);
+	if (status)
+	    return status;
     } else {
-        _cairo_output_stream_printf (surface->output, "Q\r\n");
+	_cairo_output_stream_printf (surface->output, "Q\r\n");
     }
 
-    return _cairo_output_stream_get_status (surface->output);
+    status = _cairo_output_stream_get_status (surface->output);
+    if (status)
+	return status;
+
+    return _cairo_pdf_surface_check_content_stream_size (surface);
 }
 
 static void
 _cairo_pdf_surface_set_paginated_mode (void			*abstract_surface,
 				       cairo_paginated_mode_t	 paginated_mode)
 {
     cairo_pdf_surface_t *surface = abstract_surface;
 
     surface->paginated_mode = paginated_mode;
 }
 
 static const cairo_surface_backend_t cairo_pdf_surface_backend = {
     CAIRO_SURFACE_TYPE_PDF,
-    NULL, /* create_similar */
+    _cairo_pdf_surface_create_similar,
     _cairo_pdf_surface_finish,
     NULL, /* acquire_source_image */
     NULL, /* release_source_image */
     NULL, /* acquire_dest_image */
     NULL, /* release_dest_image */
     NULL, /* clone_similar */
     NULL, /* composite */
     NULL, /* fill_rectangles */
--- a/gfx/cairo/cairo/src/cairo-pen.c
+++ b/gfx/cairo/cairo/src/cairo-pen.c
@@ -37,17 +37,17 @@
 #include "cairoint.h"
 
 static int
 _cairo_pen_vertices_needed (double tolerance, double radius, cairo_matrix_t *matrix);
 
 static void
 _cairo_pen_compute_slopes (cairo_pen_t *pen);
 
-static cairo_status_t
+static void
 _cairo_pen_stroke_spline_half (cairo_pen_t *pen, cairo_spline_t *spline, cairo_direction_t dir, cairo_polygon_t *polygon);
 
 void
 _cairo_pen_init_empty (cairo_pen_t *pen)
 {
     pen->radius = 0;
     pen->tolerance = 0;
     pen->vertices = NULL;
@@ -303,42 +303,40 @@ static void
  * NOTE: The behavior of this function is sensitive to the sense of
  * the inequality within _cairo_slope_clockwise/_cairo_slope_counter_clockwise.
  *
  * The issue is that the slope_ccw member of one pen vertex will be
  * equivalent to the slope_cw member of the next pen vertex in a
  * counterclockwise order. However, for this function, we care
  * strongly about which vertex is returned.
  */
-cairo_status_t
+void
 _cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen,
 					cairo_slope_t *slope,
 					int *active)
 {
     int i;
 
     for (i=0; i < pen->num_vertices; i++) {
 	if (_cairo_slope_clockwise (slope, &pen->vertices[i].slope_ccw)
 	    && _cairo_slope_counter_clockwise (slope, &pen->vertices[i].slope_cw))
 	    break;
     }
 
     assert (i < pen->num_vertices);
 
     *active = i;
-
-    return CAIRO_STATUS_SUCCESS;
 }
 
 /* Find active pen vertex for counterclockwise edge of stroke at the given slope.
  *
  * NOTE: The behavior of this function is sensitive to the sense of
  * the inequality within _cairo_slope_clockwise/_cairo_slope_counter_clockwise.
  */
-cairo_status_t
+void
 _cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen,
 					 cairo_slope_t *slope,
 					 int *active)
 {
     int i;
     cairo_slope_t slope_reverse;
 
     slope_reverse = *slope;
@@ -347,28 +345,25 @@ cairo_status_t
 
     for (i=pen->num_vertices-1; i >= 0; i--) {
 	if (_cairo_slope_counter_clockwise (&pen->vertices[i].slope_ccw, &slope_reverse)
 	    && _cairo_slope_clockwise (&pen->vertices[i].slope_cw, &slope_reverse))
 	    break;
     }
 
     *active = i;
-
-    return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_status_t
+static void
 _cairo_pen_stroke_spline_half (cairo_pen_t *pen,
 			       cairo_spline_t *spline,
 			       cairo_direction_t dir,
 			       cairo_polygon_t *polygon)
 {
     int i;
-    cairo_status_t status;
     int start, stop, step;
     int active = 0;
     cairo_point_t hull_point;
     cairo_slope_t slope, initial_slope, final_slope;
     cairo_point_t *point = spline->points;
     int num_points = spline->num_points;
 
     if (dir == CAIRO_DIRECTION_FORWARD) {
@@ -384,21 +379,19 @@ static cairo_status_t
 	initial_slope = spline->final_slope;
 	initial_slope.dx = -initial_slope.dx;
 	initial_slope.dy = -initial_slope.dy;
 	final_slope = spline->initial_slope;
 	final_slope.dx = -final_slope.dx;
 	final_slope.dy = -final_slope.dy;
     }
 
-    status = _cairo_pen_find_active_cw_vertex_index (pen,
-	                                             &initial_slope,
-						     &active);
-    if (status)
-	return status;
+    _cairo_pen_find_active_cw_vertex_index (pen,
+	                                    &initial_slope,
+					    &active);
 
     i = start;
     while (i != stop) {
 	hull_point.x = point[i].x + pen->vertices[active].point.x;
 	hull_point.y = point[i].y + pen->vertices[active].point.y;
 
 	_cairo_polygon_line_to (polygon, &hull_point);
 
@@ -411,18 +404,16 @@ static cairo_status_t
 		active = 0;
 	} else if (_cairo_slope_clockwise (&slope, &pen->vertices[active].slope_cw)) {
 	    if (--active == -1)
 		active = pen->num_vertices - 1;
 	} else {
 	    i += step;
 	}
     }
-
-    return CAIRO_STATUS_SUCCESS;
 }
 
 /* Compute outline of a given spline using the pen.
    The trapezoids needed to fill that outline will be added to traps
 */
 cairo_status_t
 _cairo_pen_stroke_spline (cairo_pen_t		*pen,
 			  cairo_spline_t	*spline,
@@ -438,23 +429,19 @@ cairo_status_t
 	return CAIRO_STATUS_SUCCESS;
 
     _cairo_polygon_init (&polygon);
 
     status = _cairo_spline_decompose (spline, tolerance);
     if (status)
 	goto BAIL;
 
-    status = _cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_FORWARD, &polygon);
-    if (status)
-	goto BAIL;
+    _cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_FORWARD, &polygon);
 
-    status = _cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_REVERSE, &polygon);
-    if (status)
-	goto BAIL;
+    _cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_REVERSE, &polygon);
 
     _cairo_polygon_close (&polygon);
     status = _cairo_polygon_status (&polygon);
     if (status)
 	goto BAIL;
 
     status = _cairo_bentley_ottmann_tessellate_polygon (traps, &polygon, CAIRO_FILL_RULE_WINDING);
 BAIL:
--- a/gfx/cairo/cairo/src/cairo-platform.h
+++ b/gfx/cairo/cairo/src/cairo-platform.h
@@ -88,9 +88,11 @@
 #include "cairo-rename.h"
 #endif
 
 #if defined(IS_BIG_ENDIAN)
 #define WORDS_BIGENDIAN
 #define FLOAT_WORDS_BIGENDIAN
 #endif
 
+#define CAIRO_NO_MUTEX 1
+
 #endif /* CAIRO_PLATFORM_H */
--- a/gfx/cairo/cairo/src/cairo-png.c
+++ b/gfx/cairo/cairo/src/cairo-png.c
@@ -109,39 +109,41 @@ write_png (cairo_surface_t	*surface,
 {
     int i;
     volatile cairo_status_t status = CAIRO_STATUS_SUCCESS;
     cairo_image_surface_t *image;
     void *image_extra;
     png_struct *png;
     png_info *info;
     png_time pt;
-    png_byte **rows;
+    png_byte **rows = NULL;
     png_color_16 white;
     int png_color_type;
     int depth;
 
     status = _cairo_surface_acquire_source_image (surface,
 						  &image,
 						  &image_extra);
 
     if (status == CAIRO_STATUS_NO_MEMORY)
         return CAIRO_STATUS_NO_MEMORY;
     else if (status != CAIRO_STATUS_SUCCESS)
 	return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
 
-    rows = _cairo_malloc_ab (image->height, sizeof(png_byte*));
-    if (rows == NULL) {
-        status = CAIRO_STATUS_NO_MEMORY;
-	goto BAIL1;
+    if (image->height && image->width) {
+	rows = _cairo_malloc_ab (image->height, sizeof(png_byte*));
+	if (rows == NULL) {
+	    status = CAIRO_STATUS_NO_MEMORY;
+	    goto BAIL1;
+	}
+
+	for (i = 0; i < image->height; i++)
+	    rows[i] = (png_byte *) image->data + i * image->stride;
     }
 
-    for (i = 0; i < image->height; i++)
-	rows[i] = (png_byte *) image->data + i * image->stride;
-
     png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL,
 	                           png_simple_error_callback,
 	                           png_simple_warning_callback);
     if (png == NULL) {
 	status = CAIRO_STATUS_NO_MEMORY;
 	goto BAIL2;
     }
 
@@ -203,17 +205,18 @@ write_png (cairo_surface_t	*surface,
 
     if (image->format == CAIRO_FORMAT_ARGB32)
 	png_set_write_user_transform_fn (png, unpremultiply_data);
     else if (image->format == CAIRO_FORMAT_RGB24)
 	png_set_write_user_transform_fn (png, convert_data_to_bytes);
     if (image->format == CAIRO_FORMAT_RGB24)
 	png_set_filler (png, 0, PNG_FILLER_AFTER);
 
-    png_write_image (png, rows);
+    if (rows)
+	png_write_image (png, rows);
     png_write_end (png, info);
 
 BAIL3:
     png_destroy_write_struct (&png, &info);
 BAIL2:
     free (rows);
 BAIL1:
     _cairo_surface_release_source_image (surface, image, image_extra);
--- a/gfx/cairo/cairo/src/cairo-ps-surface-private.h
+++ b/gfx/cairo/cairo/src/cairo-ps-surface-private.h
@@ -70,11 +70,13 @@ typedef struct cairo_ps_surface {
 
     cairo_scaled_font_subsets_t *font_subsets;
 
     cairo_array_t dsc_header_comments;
     cairo_array_t dsc_setup_comments;
     cairo_array_t dsc_page_setup_comments;
 
     cairo_array_t *dsc_comment_target;
+
+    cairo_surface_t *paginated_surface;
 } cairo_ps_surface_t;
 
 #endif /* CAIRO_PS_SURFACE_PRIVATE_H */
--- a/gfx/cairo/cairo/src/cairo-ps-surface.c
+++ b/gfx/cairo/cairo/src/cairo-ps-surface.c
@@ -44,16 +44,18 @@
 #include "cairo-paginated-private.h"
 #include "cairo-meta-surface-private.h"
 #include "cairo-output-stream-private.h"
 
 #include <ctype.h>
 #include <time.h>
 #include <zlib.h>
 
+#define DEBUG_PS 0
+
 static const cairo_surface_backend_t cairo_ps_surface_backend;
 static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend;
 
 /* A word wrap stream can be used as a filter to do word wrapping on
  * top of an existing output stream. The word wrapping is quite
  * simple, using isspace to determine characters that separate
  * words. Any word that will cause the column count exceed the given
  * max_column will have a '\n' character emitted before it.
@@ -173,17 +175,17 @@ static cairo_status_t
 _cairo_ps_surface_path_move_to (void *closure, cairo_point_t *point)
 {
     ps_path_info_t *path_info = closure;
 
     path_info->last_move_to_point = *point;
     path_info->has_sub_path = FALSE;
 
     _cairo_output_stream_printf (path_info->stream,
-				 "%f %f moveto ",
+				 "%f %f M ",
 				 _cairo_fixed_to_double (point->x),
 				 _cairo_fixed_to_double (point->y));
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
 _cairo_ps_surface_path_line_to (void *closure, cairo_point_t *point)
@@ -196,17 +198,17 @@ static cairo_status_t
 	point->y == path_info->last_move_to_point.y)
     {
 	return CAIRO_STATUS_SUCCESS;
     }
 
     path_info->has_sub_path = TRUE;
 
     _cairo_output_stream_printf (path_info->stream,
-				 "%f %f lineto ",
+				 "%f %f L ",
 				 _cairo_fixed_to_double (point->x),
 				 _cairo_fixed_to_double (point->y));
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
 _cairo_ps_surface_path_curve_to (void          *closure,
@@ -214,17 +216,17 @@ static cairo_status_t
 				 cairo_point_t *c,
 				 cairo_point_t *d)
 {
     ps_path_info_t *path_info = closure;
 
     path_info->has_sub_path = TRUE;
 
     _cairo_output_stream_printf (path_info->stream,
-				 "%f %f %f %f %f %f curveto ",
+				 "%f %f %f %f %f %f C ",
 				 _cairo_fixed_to_double (b->x),
 				 _cairo_fixed_to_double (b->y),
 				 _cairo_fixed_to_double (c->x),
 				 _cairo_fixed_to_double (c->y),
 				 _cairo_fixed_to_double (d->x),
 				 _cairo_fixed_to_double (d->y));
 
     return CAIRO_STATUS_SUCCESS;
@@ -237,17 +239,17 @@ static cairo_status_t
 
     if (path_info->line_cap != CAIRO_LINE_CAP_ROUND &&
 	! path_info->has_sub_path)
     {
 	return CAIRO_STATUS_SUCCESS;
     }
 
     _cairo_output_stream_printf (path_info->stream,
-				 "closepath\n");
+				 "P\n");
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 /* The line cap value is needed to workaround the fact that PostScript
  * semantics for stroking degenerate sub-paths do not match cairo
  * semantics. (PostScript draws something for any line cap value,
  * while cairo draws something only for round caps).
@@ -374,18 +376,20 @@ static cairo_status_t
     snprintf (name, sizeof name, "CairoFont-%d-%d",
 	      font_subset->font_id, font_subset->subset_id);
     status = _cairo_type1_subset_init (&subset, name, font_subset, TRUE);
     if (status)
 	return status;
 
     /* FIXME: Figure out document structure convention for fonts */
 
+#if DEBUG_PS
     _cairo_output_stream_printf (surface->final_stream,
 				 "%% _cairo_ps_surface_emit_type1_font_subset\n");
+#endif
 
     length = subset.header_length + subset.data_length + subset.trailer_length;
     _cairo_output_stream_write (surface->final_stream, subset.data, length);
 
     _cairo_type1_subset_fini (&subset);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -403,18 +407,20 @@ static cairo_status_t
     snprintf (name, sizeof name, "CairoFont-%d-%d",
 	      font_subset->font_id, font_subset->subset_id);
     status = _cairo_type1_fallback_init_hex (&subset, name, font_subset);
     if (status)
 	return status;
 
     /* FIXME: Figure out document structure convention for fonts */
 
+#if DEBUG_PS
     _cairo_output_stream_printf (surface->final_stream,
 				 "%% _cairo_ps_surface_emit_type1_font_fallback\n");
+#endif
 
     length = subset.header_length + subset.data_length + subset.trailer_length;
     _cairo_output_stream_write (surface->final_stream, subset.data, length);
 
     _cairo_type1_fallback_fini (&subset);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -430,18 +436,20 @@ static cairo_status_t
     unsigned int i, begin, end;
 
     status = _cairo_truetype_subset_init (&subset, font_subset);
     if (status)
 	return status;
 
     /* FIXME: Figure out document structure convention for fonts */
 
+#if DEBUG_PS
     _cairo_output_stream_printf (surface->final_stream,
 				 "%% _cairo_ps_surface_emit_truetype_font_subset\n");
+#endif
 
     _cairo_output_stream_printf (surface->final_stream,
 				 "11 dict begin\n"
 				 "/FontType 42 def\n"
 				 "/FontName /CairoFont-%d-%d def\n"
 				 "/PaintType 0 def\n"
 				 "/FontMatrix [ 1 0 0 1 0 0 ] def\n"
 				 "/FontBBox [ 0 0 0 0 ] def\n"
@@ -569,22 +577,22 @@ static cairo_int_status_t
 				 "   /ImageType 1\n"
 				 "   /Width %d\n"
 				 "   /Height %d\n"
 				 "   /ImageMatrix [%f %f %f %f %f %f]\n"
 				 "   /Decode [1 0]\n"
 				 "   /BitsPerComponent 1\n",
 				 image->width,
 				 image->height,
-				 image->base.device_transform_inverse.xx,
-				 image->base.device_transform_inverse.yx,
-				 image->base.device_transform_inverse.xy,
-				 image->base.device_transform_inverse.yy,
-				 image->base.device_transform_inverse.x0,
-				 image->base.device_transform_inverse.y0);
+				 image->base.device_transform.xx,
+				 image->base.device_transform.yx,
+				 image->base.device_transform.xy,
+				 image->base.device_transform.yy,
+				 image->base.device_transform.x0,
+				 image->base.device_transform.y0);
 
     _cairo_output_stream_printf (surface->final_stream,
 				 "   /DataSource   {<");
     for (row = image->data, rows = image->height; rows; row += image->stride, rows--) {
 	for (byte = row, cols = (image->width + 7) / 8; cols; byte++, cols--) {
 	    unsigned char output_byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte);
 	    _cairo_output_stream_printf (surface->final_stream, "%02x ", output_byte);
 	}
@@ -637,18 +645,20 @@ static cairo_status_t
 					  cairo_scaled_font_subset_t	*font_subset)
 
 
 {
     cairo_status_t status;
     cairo_matrix_t matrix;
     unsigned int i;
 
+#if DEBUG_PS
     _cairo_output_stream_printf (surface->final_stream,
 				 "%% _cairo_ps_surface_emit_type3_font_subset\n");
+#endif
 
     _cairo_output_stream_printf (surface->final_stream,
 				 "/CairoFont-%d-%d <<\n",
 				 font_subset->font_id,
 				 font_subset->subset_id);
 
     matrix = font_subset->scaled_font->scale;
     status = cairo_matrix_invert (&matrix);
@@ -719,18 +729,20 @@ static void
 	return;
 }
 
 static cairo_status_t
 _cairo_ps_surface_emit_font_subsets (cairo_ps_surface_t *surface)
 {
     cairo_status_t status;
 
+#if DEBUG_PS
     _cairo_output_stream_printf (surface->final_stream,
 				 "%% _cairo_ps_surface_emit_font_subsets\n");
+#endif
 
     status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets,
                                                           _cairo_ps_surface_emit_unscaled_font_subset,
                                                           surface);
     status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
                                                         _cairo_ps_surface_emit_scaled_font_subset,
                                                         surface);
     _cairo_scaled_font_subsets_destroy (surface->font_subsets);
@@ -800,20 +812,21 @@ static cairo_surface_t *
     surface->num_pages = 0;
 
     _cairo_array_init (&surface->dsc_header_comments, sizeof (char *));
     _cairo_array_init (&surface->dsc_setup_comments, sizeof (char *));
     _cairo_array_init (&surface->dsc_page_setup_comments, sizeof (char *));
 
     surface->dsc_comment_target = &surface->dsc_header_comments;
 
-    return _cairo_paginated_surface_create (&surface->base,
-					    CAIRO_CONTENT_COLOR_ALPHA,
-					    width, height,
-					    &cairo_ps_surface_paginated_backend);
+    surface->paginated_surface = _cairo_paginated_surface_create (&surface->base,
+								   CAIRO_CONTENT_COLOR_ALPHA,
+								   width, height,
+								   &cairo_ps_surface_paginated_backend);
+    return surface->paginated_surface;
 
  CLEANUP_OUTPUT_STREAM:
     status = _cairo_output_stream_destroy (surface->stream);
     /* Ignore status---we're already on a failure path. */
  CLEANUP_TMPFILE:
     fclose (surface->tmpfile);
  CLEANUP_SURFACE:
     free (surface);
@@ -971,16 +984,21 @@ cairo_ps_surface_set_size (cairo_surface
     status = _extract_ps_surface (surface, &ps_surface);
     if (status) {
 	_cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
 	return;
     }
 
     ps_surface->width = width_in_points;
     ps_surface->height = height_in_points;
+    status = _cairo_paginated_surface_set_size (ps_surface->paginated_surface,
+						width_in_points,
+						height_in_points);
+    if (status)
+	_cairo_surface_set_error (surface, status);
 }
 
 /**
  * cairo_ps_surface_dsc_comment:
  * @surface: a PostScript cairo_surface_t
  * @comment: a comment string to be emitted into the PostScript output
  *
  * Emit a comment into the PostScript output for the given surface.
@@ -1250,17 +1268,17 @@ static cairo_int_status_t
 
     _cairo_output_stream_printf (surface->stream,
 				 "%%%%PageBoundingBox: %d %d %d %d\n",
 				 0, 0,
 				 (int) ceil (surface->width),
 				 (int) ceil (surface->height));
 
     _cairo_output_stream_printf (surface->stream,
-				 "gsave %f %f translate 1.0 -1.0 scale \n",
+				 "gsave %f %f translate 1.0 -1.0 scale gsave\n",
 				 0.0, surface->height);
 
     _cairo_output_stream_printf (surface->stream,
 				 "%%%%EndPageSetup\n");
 
     if (surface->width > surface->max_width)
 	surface->max_width = surface->width;
     if (surface->height > surface->max_height)
@@ -1268,29 +1286,17 @@ static cairo_int_status_t
 
     return _cairo_output_stream_get_status (surface->stream);
 }
 
 static void
 _cairo_ps_surface_end_page (cairo_ps_surface_t *surface)
 {
     _cairo_output_stream_printf (surface->stream,
-				 "grestore\n");
-}
-
-static cairo_int_status_t
-_cairo_ps_surface_copy_page (void *abstract_surface)
-{
-    cairo_ps_surface_t *surface = abstract_surface;
-
-    _cairo_ps_surface_end_page (surface);
-
-    _cairo_output_stream_printf (surface->stream, "copypage\n");
-
-    return CAIRO_STATUS_SUCCESS;
+				 "grestore grestore\n");
 }
 
 static cairo_int_status_t
 _cairo_ps_surface_show_page (void *abstract_surface)
 {
     cairo_ps_surface_t *surface = abstract_surface;
 
     _cairo_ps_surface_end_page (surface);
@@ -1354,44 +1360,63 @@ pattern_supported (const cairo_pattern_t
 
     if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
 	return surface_pattern_supported ((const cairo_surface_pattern_t *) pattern);
 
     return FALSE;
 }
 
 static cairo_int_status_t
-_cairo_ps_surface_operation_supported (cairo_ps_surface_t *surface,
-		      cairo_operator_t op,
-		      const cairo_pattern_t *pattern)
+_cairo_ps_surface_analyze_operation (cairo_ps_surface_t    *surface,
+				     cairo_operator_t       op,
+				     const cairo_pattern_t *pattern)
 {
-    if (surface->force_fallbacks)
-	return FALSE;
+    if (surface->force_fallbacks && surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     if (! pattern_supported (pattern))
-	return FALSE;
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if (op == CAIRO_OPERATOR_SOURCE)
+	return CAIRO_STATUS_SUCCESS;
+
+    if (op != CAIRO_OPERATOR_OVER)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    /* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If
+     * the pattern contains transparency, we return
+     * CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY to the analysis
+     * surface. If the analysis surface determines that there is
+     * anything drawn under this operation, a fallback image will be
+     * used. Otherwise the operation will be replayed during the
+     * render stage and we blend the transarency into the white
+     * background to convert the pattern to opaque.
+     */
 
     if (_cairo_operator_always_opaque (op))
-	return TRUE;
+	return CAIRO_STATUS_SUCCESS;
 
     if (_cairo_operator_always_translucent (op))
-	return FALSE;
+	return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
 
-    return _cairo_pattern_is_opaque (pattern);
+    if (_cairo_pattern_is_opaque (pattern))
+	return CAIRO_STATUS_SUCCESS;
+    else
+	return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
 }
 
-static cairo_int_status_t
-_cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
-		    cairo_operator_t op,
-		    const cairo_pattern_t *pattern)
+static cairo_bool_t
+_cairo_ps_surface_operation_supported (cairo_ps_surface_t    *surface,
+				       cairo_operator_t       op,
+				       const cairo_pattern_t *pattern)
 {
-    if (_cairo_ps_surface_operation_supported (surface, op, pattern))
-	return CAIRO_STATUS_SUCCESS;
+    if (_cairo_ps_surface_analyze_operation (surface, op, pattern) != CAIRO_INT_STATUS_UNSUPPORTED)
+	return TRUE;
     else
-	return CAIRO_INT_STATUS_UNSUPPORTED;
+	return FALSE;
 }
 
 /* The "standard" implementation limit for PostScript string sizes is
  * 65535 characters (see PostScript Language Reference, Appendix
  * B). We go one short of that because we sometimes need two
  * characters in a string to represent a single ASCII85 byte, (for the
  * escape sequences "\\", "\(", and "\)") and we must not split these
  * across two strings. So we'd be in trouble if we went right to the
@@ -1509,18 +1534,18 @@ static cairo_output_stream_t *
     return &stream->base;
 }
 
 /* PS Output - this section handles output of the parts of the meta
  * surface we can render natively in PS. */
 
 static cairo_status_t
 _cairo_ps_surface_emit_image (cairo_ps_surface_t    *surface,
-	    cairo_image_surface_t *image,
-	    const char		  *name)
+			      cairo_image_surface_t *image,
+			      const char	    *name)
 {
     cairo_status_t status, status2;
     unsigned char *rgb, *compressed;
     unsigned long rgb_size, compressed_size;
     cairo_surface_t *opaque;
     cairo_image_surface_t *opaque_image;
     cairo_pattern_union_t pattern;
     int x, y, i;
@@ -1654,34 +1679,47 @@ static cairo_status_t
  bail1:
     if (opaque_image != image)
 	cairo_surface_destroy (opaque);
  bail0:
     return status;
 }
 
 static void
-_cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface,
-		    cairo_solid_pattern_t *pattern)
+_cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t    *surface,
+				      cairo_solid_pattern_t *pattern)
 {
-    if (color_is_gray (&pattern->color))
+    cairo_color_t *color = &pattern->color;
+    double red, green, blue;
+
+    red = color->red;
+    green = color->green;
+    blue = color->blue;
+
+    if (!CAIRO_COLOR_IS_OPAQUE(color)) {
+	uint8_t one_minus_alpha = 255 - (color->alpha_short >> 8);
+
+	red   = ((color->red_short   >> 8) + one_minus_alpha) / 255.0;
+	green = ((color->green_short >> 8) + one_minus_alpha) / 255.0;
+	blue  = ((color->blue_short  >> 8) + one_minus_alpha) / 255.0;
+    }
+
+    if (color_is_gray (color))
 	_cairo_output_stream_printf (surface->stream,
 				     "%f G\n",
-				     pattern->color.red);
+				     red);
     else
 	_cairo_output_stream_printf (surface->stream,
 				     "%f %f %f R\n",
-				     pattern->color.red,
-				     pattern->color.green,
-				     pattern->color.blue);
+				     red, green, blue);
 }
 
 static cairo_status_t
-_cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
-		      cairo_surface_pattern_t *pattern)
+_cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t      *surface,
+					cairo_surface_pattern_t *pattern)
 {
     cairo_status_t status;
     double bbox_width, bbox_height;
     double xstep, ystep;
     cairo_matrix_t inverse = pattern->base.matrix;
 
     status = cairo_matrix_invert (&inverse);
     /* cairo_pattern_set_matrix ensures the matrix is invertible */
@@ -1841,21 +1879,23 @@ static cairo_int_status_t
     cairo_ps_surface_t *surface = abstract_surface;
     cairo_output_stream_t *stream = surface->stream;
     cairo_status_t status;
     const char *ps_operator;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return CAIRO_STATUS_SUCCESS;
 
+#if DEBUG_PS
     _cairo_output_stream_printf (stream,
 				 "%% _cairo_ps_surface_intersect_clip_path\n");
+#endif
 
     if (path == NULL) {
-	_cairo_output_stream_printf (stream, "initclip\n");
+	_cairo_output_stream_printf (stream, "grestore gsave\n");
 	return CAIRO_STATUS_SUCCESS;
     }
 
     /* We're "filling" not stroking, so we pass CAIRO_LINE_CAP_ROUND. */
     status = _cairo_ps_surface_emit_path (surface, stream, path,
 					  CAIRO_LINE_CAP_ROUND);
 
     switch (fill_rule) {
@@ -1914,28 +1954,22 @@ static cairo_int_status_t
     cairo_ps_surface_t *surface = abstract_surface;
     cairo_output_stream_t *stream = surface->stream;
     cairo_rectangle_int_t extents, pattern_extents;
     cairo_status_t status;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_ps_surface_analyze_operation (surface, op, source);
 
-    /* XXX: It would be nice to be able to assert this condition
-     * here. But, we actually allow one 'cheat' that is used when
-     * painting the final image-based fallbacks. The final fallbacks
-     * do have alpha which we support by blending with white. This is
-     * possible only because there is nothing between the fallback
-     * images and the paper, nor is anything painted above. */
-    /*
-    assert (_cairo_ps_surface_operation_supported (op, source));
-    */
+    assert (_cairo_ps_surface_operation_supported (surface, op, source));
 
+#if DEBUG_PS
     _cairo_output_stream_printf (stream,
 				 "%% _cairo_ps_surface_paint\n");
+#endif
 
     status = _cairo_surface_get_extents (&surface->base, &extents);
     if (status)
 	return status;
 
     status = _cairo_pattern_get_extents (source, &pattern_extents);
     if (status)
 	return status;
@@ -2012,19 +2046,20 @@ static cairo_int_status_t
     int num_dashes = style->num_dashes;
     double dash_offset = style->dash_offset;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_ps_surface_analyze_operation (surface, op, source);
 
     assert (_cairo_ps_surface_operation_supported (surface, op, source));
 
-
+#if DEBUG_PS
     _cairo_output_stream_printf (stream,
 				 "%% _cairo_ps_surface_stroke\n");
+#endif
 
     /* PostScript has "special needs" when it comes to zero-length
      * dash segments with butt caps. It apparently (at least
      * according to ghostscript) draws hairlines for this
      * case. That's not what the cairo semantics want, so we first
      * touch up the array to eliminate any 0.0 values that will
      * result in "on" segments.
      */
@@ -2143,18 +2178,20 @@ static cairo_int_status_t
     cairo_int_status_t status;
     const char *ps_operator;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_ps_surface_analyze_operation (surface, op, source);
 
     assert (_cairo_ps_surface_operation_supported (surface, op, source));
 
+#if DEBUG_PS
     _cairo_output_stream_printf (stream,
 				 "%% _cairo_ps_surface_fill\n");
+#endif
 
     _cairo_ps_surface_emit_pattern (surface, source);
 
     /* We're filling not stroking, so we pass CAIRO_LINE_CAP_ROUND. */
     status = _cairo_ps_surface_emit_path (surface, stream, path,
 					  CAIRO_LINE_CAP_ROUND);
 
     switch (fill_rule) {
@@ -2201,18 +2238,20 @@ static cairo_int_status_t
     cairo_bool_t vertical, horizontal;
     cairo_output_stream_t *word_wrap;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_ps_surface_analyze_operation (surface, op, source);
 
     assert (_cairo_ps_surface_operation_supported (surface, op, source));
 
+#if DEBUG_PS
     _cairo_output_stream_printf (stream,
 				 "%% _cairo_ps_surface_show_glyphs\n");
+#endif
 
     if (num_glyphs <= 0)
         return CAIRO_STATUS_SUCCESS;
 
     num_glyphs_unsigned = num_glyphs;
 
     _cairo_ps_surface_emit_pattern (surface, source);
     glyph_ids = _cairo_malloc_ab (num_glyphs_unsigned, sizeof (cairo_ps_glyph_id_t));
@@ -2228,19 +2267,18 @@ static cairo_int_status_t
         glyph_ids[i].subset_id = subset_glyph.subset_id;
         glyph_ids[i].glyph_id = subset_glyph.subset_glyph_index;
     }
 
     i = 0;
     while (i < num_glyphs_unsigned) {
         if (glyph_ids[i].subset_id != current_subset_id) {
             _cairo_output_stream_printf (surface->stream,
-                                         "/CairoFont-%d-%d findfont\n"
-                                         "[ %f %f %f %f 0 0 ] makefont\n"
-                                         "setfont\n",
+                                         "/CairoFont-%d-%d "
+                                         "[ %f %f %f %f 0 0 ] selectfont\n",
                                          subset_glyph.font_id,
                                          glyph_ids[i].subset_id,
                                          scaled_font->scale.xx,
                                          scaled_font->scale.yx,
                                          -scaled_font->scale.xy,
                                          -scaled_font->scale.yy);
             current_subset_id = glyph_ids[i].subset_id;
         }
@@ -2338,17 +2376,17 @@ static const cairo_surface_backend_t cai
     NULL, /* acquire_source_image */
     NULL, /* release_source_image */
     NULL, /* acquire_dest_image */
     NULL, /* release_dest_image */
     NULL, /* clone_similar */
     NULL, /* composite */
     NULL, /* fill_rectangles */
     NULL, /* composite_trapezoids */
-    _cairo_ps_surface_copy_page,
+    NULL, /* cairo_ps_surface_copy_page */
     _cairo_ps_surface_show_page,
     NULL, /* set_clip_region */
     _cairo_ps_surface_intersect_clip_path,
     _cairo_ps_surface_get_extents,
     NULL, /* old_show_glyphs */
     _cairo_ps_surface_get_font_options,
     NULL, /* flush */
     NULL, /* mark_dirty_rectangle */
--- a/gfx/cairo/cairo/src/cairo-quartz-private.h
+++ b/gfx/cairo/cairo/src/cairo-quartz-private.h
@@ -33,17 +33,17 @@
  * Contributor(s):
  *    Calum Robinson <calumr@mac.com>
  *    Vladimir Vukicevic <vladimir@mozilla.com>
  */
 
 #ifndef CAIRO_QUARTZ_PRIVATE_H
 #define CAIRO_QUARTZ_PRIVATE_H
 
-#include <cairoint.h>
+#include "cairoint.h"
 
 #ifdef CAIRO_HAS_QUARTZ_SURFACE
 #include <cairo-quartz.h>
 
 typedef struct cairo_quartz_surface {
     cairo_surface_t base;
 
     void *imageData;
--- a/gfx/cairo/cairo/src/cairo-quartz-surface.c
+++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c
@@ -1676,24 +1676,16 @@ cairo_quartz_surface_create (cairo_forma
     cairo_quartz_surface_t *surf;
     CGContextRef cgc;
     CGColorSpaceRef cgColorspace;
     CGBitmapInfo bitinfo;
     void *imageData;
     int stride;
     int bitsPerComponent;
 
-    unsigned int realWidth = width;
-    unsigned int realHeight = height;
-
-    if (width == 0)
-	width = 1;
-    if (height == 0)
-	height = 1;
-
     if (format == CAIRO_FORMAT_ARGB32) {
 	cgColorspace = CGColorSpaceCreateDeviceRGB();
 	stride = width * 4;
 	bitinfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
 	bitsPerComponent = 8;
     } else if (format == CAIRO_FORMAT_RGB24) {
 	cgColorspace = CGColorSpaceCreateDeviceRGB();
 	stride = width * 4;
@@ -1740,17 +1732,17 @@ cairo_quartz_surface_create (cairo_forma
 	return (cairo_surface_t*) &_cairo_surface_nil;
     }
 
     /* flip the Y axis */
     CGContextTranslateCTM (cgc, 0.0, height);
     CGContextScaleCTM (cgc, 1.0, -1.0);
 
     surf = _cairo_quartz_surface_create_internal (cgc, _cairo_content_from_format (format),
-						  realWidth, realHeight);
+						   width, height);
     if (!surf) {
 	CGContextRelease (cgc);
 	// create_internal will have set an error
 	return (cairo_surface_t*) &_cairo_surface_nil;
     }
 
     surf->imageData = imageData;
 
--- a/gfx/cairo/cairo/src/cairo-region-private.h
+++ b/gfx/cairo/cairo/src/cairo-region-private.h
@@ -32,21 +32,17 @@
  *
  * Contributor(s):
  *	Vladimir Vukicevic <vladimir@pobox.com>
  */
 
 #ifndef CAIRO_REGION_PRIVATE_H
 #define CAIRO_REGION_PRIVATE_H
 
-#ifdef MOZ_TREE_CAIRO
-#include "pixman.h"
-#else
-#include <pixman/pixman.h>
-#endif
+#include <pixman.h>
 
 /* cairo_region_t is defined in cairoint.h */
 
 struct _cairo_region {
     pixman_region16_t rgn;
 };
 
 cairo_private void
@@ -101,9 +97,13 @@ cairo_private cairo_int_status_t
 
 cairo_private cairo_bool_t
 _cairo_region_not_empty (cairo_region_t *region);
 
 cairo_private void
 _cairo_region_translate (cairo_region_t *region,
 			 int x, int y);
 
+cairo_private pixman_region_overlap_t
+_cairo_region_contains_rectangle (cairo_region_t *region, cairo_rectangle_int_t *box);
+
+
 #endif /* CAIRO_REGION_PRIVATE_H */
--- a/gfx/cairo/cairo/src/cairo-region.c
+++ b/gfx/cairo/cairo/src/cairo-region.c
@@ -202,8 +202,21 @@ cairo_bool_t
 }
 
 void
 _cairo_region_translate (cairo_region_t *region,
 			 int x, int y)
 {
     pixman_region_translate (&region->rgn, x, y);
 }
+
+pixman_region_overlap_t
+_cairo_region_contains_rectangle (cairo_region_t *region, cairo_rectangle_int_t *rect)
+{
+    pixman_box16_t pbox;
+
+    pbox.x1 = rect->x;
+    pbox.y1 = rect->y;
+    pbox.x2 = rect->x + rect->width;
+    pbox.y2 = rect->y + rect->height;
+
+    return pixman_region_contains_rectangle (&region->rgn, &pbox);
+}
--- a/gfx/cairo/cairo/src/cairo-rename.h
+++ b/gfx/cairo/cairo/src/cairo-rename.h
@@ -1,9 +1,8 @@
-#define _cairo_image_surface_nil_invalid_format __moz__cairo_image_surface_nil_invalid_format
 #define cairo_append_path _moz_cairo_append_path
 #define cairo_arc _moz_cairo_arc
 #define cairo_arc_negative _moz_cairo_arc_negative
 #define cairo_arc_to _moz_cairo_arc_to
 #define cairo_atsui_font_face_create_for_atsu_font_id _moz_cairo_atsui_font_face_create_for_atsu_font_id
 #define cairo_beos_surface_create _moz_cairo_beos_surface_create
 #define cairo_beos_surface_create_for_bitmap _moz_cairo_beos_surface_create_for_bitmap
 #define cairo_clip _moz_cairo_clip
@@ -215,32 +214,34 @@
 #define cairo_show_page _moz_cairo_show_page
 #define cairo_show_text _moz_cairo_show_text
 #define cairo_status _moz_cairo_status
 #define cairo_status_to_string _moz_cairo_status_to_string
 #define cairo_stroke _moz_cairo_stroke
 #define cairo_stroke_extents _moz_cairo_stroke_extents
 #define cairo_stroke_preserve _moz_cairo_stroke_preserve
 #define cairo_stroke_to_path _moz_cairo_stroke_to_path
+#define cairo_surface_copy_page _moz_cairo_surface_copy_page
 #define cairo_surface_create_similar _moz_cairo_surface_create_similar
 #define cairo_surface_destroy _moz_cairo_surface_destroy
 #define cairo_surface_finish _moz_cairo_surface_finish
 #define cairo_surface_flush _moz_cairo_surface_flush
 #define cairo_surface_get_content _moz_cairo_surface_get_content
 #define cairo_surface_get_device_offset _moz_cairo_surface_get_device_offset
 #define cairo_surface_get_font_options _moz_cairo_surface_get_font_options
 #define cairo_surface_get_reference_count _moz_cairo_surface_get_reference_count
 #define cairo_surface_get_type _moz_cairo_surface_get_type
 #define cairo_surface_get_user_data _moz_cairo_surface_get_user_data
 #define cairo_surface_mark_dirty _moz_cairo_surface_mark_dirty
 #define cairo_surface_mark_dirty_rectangle _moz_cairo_surface_mark_dirty_rectangle
 #define cairo_surface_reference _moz_cairo_surface_reference
 #define cairo_surface_set_device_offset _moz_cairo_surface_set_device_offset
 #define cairo_surface_set_fallback_resolution _moz_cairo_surface_set_fallback_resolution
 #define cairo_surface_set_user_data _moz_cairo_surface_set_user_data
+#define cairo_surface_show_page _moz_cairo_surface_show_page
 #define cairo_surface_status _moz_cairo_surface_status
 #define cairo_surface_write_to_png _moz_cairo_surface_write_to_png
 #define cairo_surface_write_to_png_stream _moz_cairo_surface_write_to_png_stream
 #define cairo_svg_get_versions _moz_cairo_svg_get_versions
 #define cairo_svg_surface_create _moz_cairo_svg_surface_create
 #define cairo_svg_surface_create_for_stream _moz_cairo_svg_surface_create_for_stream
 #define cairo_svg_surface_restrict_to_version _moz_cairo_svg_surface_restrict_to_version
 #define cairo_svg_version_to_string _moz_cairo_svg_version_to_string
--- a/gfx/cairo/cairo/src/cairo-scaled-font.c
+++ b/gfx/cairo/cairo/src/cairo-scaled-font.c
@@ -29,21 +29,127 @@
  *
  * The Initial Developer of the Original Code is Keith Packard
  *
  * Contributor(s):
  *      Keith Packard <keithp@keithp.com>
  *	Carl D. Worth <cworth@cworth.org>
  *      Graydon Hoare <graydon@redhat.com>
  *      Owen Taylor <otaylor@redhat.com>
+ *      Behdad Esfahbod <behdad@behdad.org>
  */
 
 #include "cairoint.h"
 #include "cairo-scaled-font-private.h"
 
+/*
+ *  NOTES:
+ *
+ *  To store rasterizations of glyphs, we use an image surface and the
+ *  device offset to represent the glyph origin.
+ *
+ *  A device_transform converts from device space (a conceptual space) to
+ *  surface space.  For simple cases of translation only, it's called a
+ *  device_offset and is public API (cairo_surface_[gs]et_device_offset).
+ *  A possibly better name for those functions could have been
+ *  cairo_surface_[gs]et_origing.  So, that's what they do: they set where
+ *  the device-space origin (0,0) is in the surface.  If the origin is inside
+ *  the surface, device_offset values are positive.  It may look like this:
+ *
+ *  Device space:
+ *        (-x,-y) <-- negative numbers
+ *           +----------------+
+ *           |      .         |
+ *           |      .         |
+ *           |......(0,0) <---|-- device-space origin
+ *           |                |
+ *           |                |
+ *           +----------------+
+ *                    (width-x,height-y)
+ *
+ *  Surface space:
+ *         (0,0) <-- surface-space origin
+ *           +---------------+
+ *           |      .        |
+ *           |      .        |
+ *           |......(x,y) <--|-- device_offset
+ *           |               |
+ *           |               |
+ *           +---------------+
+ *                     (width,height)
+ *
+ *  In other words: device_offset is the coordinates of the device-space
+ *  origin relative to the top-left of the surface.
+ *
+ *  We use device offsets in a couple of places:
+ *
+ *    - Public API: To let toolkits like Gtk+ give user a surface that
+ *      only represents part of the final destination (say, the expose
+ *      area), but has the same device space as the destination.  In these
+ *      cases device_offset is typically negative.  Example:
+ *
+ *           application window
+ *           +---------------+
+ *           |      .        |
+ *           | (x,y).        |
+ *           |......+---+    |
+ *           |      |   | <--|-- expose area
+ *           |      +---+    |
+ *           +---------------+
+ *
+ *      In this case, the user of cairo API can set the device_space on
+ *      the expose area to (-x,-y) to move the device space origin to that
+ *      of the application window, such that drawing in the expose area
+ *      surface and painting it in the application window has the same
+ *      effect as drawing in the application window directly.  Gtk+ has
+ *      been using this feature.
+ *
+ *    - Glyph surfaces: In most font rendering systems, glyph surfaces
+ *      have an origin at (0,0) and a bounding box that is typically
+ *      represented as (x_bearing,y_bearing,width,height).  Depending on
+ *      which way y progresses in the system, y_bearing may typically be
+ *      negative (for systems similar to cairo, with origin at top left),
+ *      or be positive (in systems like PDF with origin at bottom left).
+ *      No matter which is the case, it is important to note that
+ *      (x_bearing,y_bearing) is the coordinates of top-left of the glyph
+ *      relative to the glyph origin.  That is, for example:
+ *
+ *      Scaled-glyph space:
+ *
+ *        (x_bearing,y_bearing) <-- negative numbers
+ *           +----------------+
+ *           |      .         |
+ *           |      .         |
+ *           |......(0,0) <---|-- glyph origin
+ *           |                |
+ *           |                |
+ *           +----------------+
+ *                    (width+x_bearing,height+y_bearing)
+ *
+ *      Note the similarity of the origin to the device space.  That is
+ *      exactly how we use the device_offset to represent scaled glyphs:
+ *      to use the device-space origin as the glyph origin.
+ *
+ *  Now compare the scaled-glyph space to device-space and surface-space
+ *  and convince yourself that:
+ *
+ *  	(x_bearing,y_bearing) = (-x,-y) = - device_offset
+ *
+ *  That's right.  If you are not convinced yet, contrast the definition
+ *  of the two:
+ *
+ *  	"(x_bearing,y_bearing) is the coordinates of top-left of the
+ *  	 glyph relative to the glyph origin."
+ *
+ *  	"In other words: device_offset is the coordinates of the
+ *  	 device-space origin relative to the top-left of the surface."
+ *
+ *  and note that glyph origin = device-space origin.
+ */
+
 static cairo_bool_t
 _cairo_scaled_glyph_keys_equal (const void *abstract_key_a, const void *abstract_key_b)
 {
     const cairo_scaled_glyph_t *key_a = abstract_key_a;
     const cairo_scaled_glyph_t *key_b = abstract_key_b;
 
     return (_cairo_scaled_glyph_index (key_a) ==
 	    _cairo_scaled_glyph_index (key_b));
@@ -292,24 +398,26 @@ static void
 			     const cairo_font_options_t *options)
 {
     uint32_t hash = FNV1_32_INIT;
 
     scaled_font->status = CAIRO_STATUS_SUCCESS;
     scaled_font->font_face = font_face;
     scaled_font->font_matrix = *font_matrix;
     scaled_font->ctm = *ctm;
+    /* ignore translation values in the ctm */
+    scaled_font->ctm.x0 = 0.;
+    scaled_font->ctm.y0 = 0.;
     scaled_font->options = *options;
 
-    /* We do a bytewise hash on the font matrices, ignoring the
-     * translation values in the ctm */
+    /* We do a bytewise hash on the font matrices */
     hash = _hash_bytes_fnv ((unsigned char *)(&scaled_font->font_matrix.xx),
 			    sizeof(cairo_matrix_t), hash);
     hash = _hash_bytes_fnv ((unsigned char *)(&scaled_font->ctm.xx),
-			    sizeof(double) * 4, hash);
+			    sizeof(cairo_matrix_t), hash);
 
     hash ^= (unsigned long) scaled_font->font_face;
 
     hash ^= cairo_font_options_hash (&scaled_font->options);
 
     scaled_font->hash_entry.hash = hash;
 }
 
@@ -1103,20 +1211,18 @@ cairo_status_t
 	    if (glyph_surface->format == CAIRO_FORMAT_ARGB32)
 		pixman_image_set_component_alpha (((cairo_image_surface_t*) mask)->
 						  pixman_image, TRUE);
 
 	}
 
 	/* round glyph locations to the nearest pixel */
 	/* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
-	x = _cairo_lround (glyphs[i].x +
-                           glyph_surface->base.device_transform.x0);
-	y = _cairo_lround (glyphs[i].y +
-                           glyph_surface->base.device_transform.y0);
+	x = _cairo_lround (glyphs[i].x - glyph_surface->base.device_transform.x0);
+	y = _cairo_lround (glyphs[i].y - glyph_surface->base.device_transform.y0);
 
 	_cairo_pattern_init_for_surface (&glyph_pattern, &glyph_surface->base);
 
 	status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
 					   &glyph_pattern.base,
 					   NULL,
 					   mask,
 					   0, 0,
@@ -1281,17 +1387,17 @@ static cairo_status_t
 
     bytes_per_row = (a1_mask->width + 7) / 8;
     for (y = 0, row = a1_mask->data, rows = a1_mask->height; rows; row += a1_mask->stride, rows--, y++) {
 	for (x = 0, byte_ptr = row, cols = (a1_mask->width + 7) / 8; cols; byte_ptr++, cols--) {
 	    byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte_ptr);
 	    for (bit = 7; bit >= 0 && x < a1_mask->width; bit--, x++) {
 		if (byte & (1 << bit)) {
 		    status = _add_unit_rectangle_to_path (path,
-							  x + xoff, y + yoff);
+							  x - xoff, y - yoff);
 		    if (status)
 			return status;
 		}
 	    }
 	}
     }
 
     if (a1_mask != mask)
--- a/gfx/cairo/cairo/src/cairo-surface-fallback.c
+++ b/gfx/cairo/cairo/src/cairo-surface-fallback.c
@@ -1066,17 +1066,17 @@ cairo_surface_t *
 
     _cairo_pattern_fini (&pattern.base);
     if (status) {
 	cairo_surface_destroy (snapshot);
 	return (cairo_surface_t *) &_cairo_surface_nil;
     }
 
     _cairo_surface_release_source_image (surface,
-					 image, &image_extra);
+					 image, image_extra);
 
     snapshot->device_transform = surface->device_transform;
     snapshot->device_transform_inverse = surface->device_transform_inverse;
 
     snapshot->is_snapshot = TRUE;
 
     return snapshot;
 }
@@ -1259,37 +1259,41 @@ cairo_status_t
 				       cairo_surface_t	*src,
 				       int		 src_x,
 				       int		 src_y,
 				       int		 width,
 				       int		 height,
 				       cairo_surface_t **clone_out)
 {
     cairo_status_t status;
-    cairo_pattern_union_t src_pattern;
     cairo_surface_t *new_surface = NULL;
+    cairo_t *cr;
 
     new_surface = _cairo_surface_create_similar_scratch (surface,
 							 cairo_surface_get_content (src),
 							 width, height);
     if (new_surface->status)
 	return new_surface->status;
 
-    _cairo_pattern_init_for_surface (&src_pattern.surface, src);
+    /* We have to copy these here, so that the coordinate spaces are correct */
+    new_surface->device_transform = src->device_transform;
+    new_surface->device_transform_inverse = src->device_transform_inverse;
 
-    status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
-				       &src_pattern.base,
-				       NULL,
-				       new_surface,
-				       src_x, src_y,
-				       0, 0,
-				       0, 0,
-				       width, height);
-
-    _cairo_pattern_fini (&src_pattern.base);
+    /* We can't use _cairo_composite directly, because backends that
+     * implement the "high-level" API may not have it implemented.
+     * (For example, SVG.)  We can fix this by either checking if the
+     * destination supports composite first, or we can make clone a
+     * required "high-level" operation.
+     */
+    cr = cairo_create (new_surface);
+    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+    cairo_set_source_surface (cr, src, -src_x, -src_y);
+    cairo_paint (cr);
+    status = cairo_status (cr);
+    cairo_destroy (cr);
 
     if (status == CAIRO_STATUS_SUCCESS)
 	*clone_out = new_surface;
-    else if (new_surface)
+    else
 	cairo_surface_destroy (new_surface);
 
     return status;
 }
--- a/gfx/cairo/cairo/src/cairo-surface-private.h
+++ b/gfx/cairo/cairo/src/cairo-surface-private.h
@@ -55,16 +55,24 @@ struct _cairo_surface {
     unsigned int ref_count;
     cairo_status_t status;
     cairo_bool_t finished;
     cairo_user_data_array_t user_data;
 
     cairo_matrix_t device_transform;
     cairo_matrix_t device_transform_inverse;
 
+    /* The actual resolution of the device, in dots per inch. */
+    double x_resolution;
+    double y_resolution;
+
+    /* The resolution that should be used when generating image-based
+     * fallback; generally only used by the analysis/paginated
+     * surfaces
+     */
     double x_fallback_resolution;
     double y_fallback_resolution;
 
     cairo_clip_t *clip;
 
     /*
      * Each time a clip region is modified, it gets the next value in this
      * sequence.  This means that clip regions for this surface are uniquely
--- a/gfx/cairo/cairo/src/cairo-surface.c
+++ b/gfx/cairo/cairo/src/cairo-surface.c
@@ -57,16 +57,18 @@ const cairo_surface_t name = {					\
     { 1.0, 0.0,							\
       0.0, 1.0,							\
       0.0, 0.0							\
     },					/* device_transform */	\
     { 1.0, 0.0,							\
       0.0, 1.0,							\
       0.0, 0.0							\
     },					/* device_transform_inverse */	\
+    0.0,				/* x_resolution */	\
+    0.0,				/* y_resolution */	\
     0.0,				/* x_fallback_resolution */	\
     0.0,				/* y_fallback_resolution */	\
     NULL,				/* clip */		\
     0,					/* next_clip_serial */	\
     0,					/* current_clip_serial */	\
     FALSE,				/* is_snapshot */	\
     FALSE,				/* has_font_options */	\
     { CAIRO_ANTIALIAS_DEFAULT,					\
@@ -190,16 +192,19 @@ void
     surface->status = CAIRO_STATUS_SUCCESS;
     surface->finished = FALSE;
 
     _cairo_user_data_array_init (&surface->user_data);
 
     cairo_matrix_init_identity (&surface->device_transform);
     cairo_matrix_init_identity (&surface->device_transform_inverse);
 
+    surface->x_resolution = CAIRO_SURFACE_RESOLUTION_DEFAULT;
+    surface->y_resolution = CAIRO_SURFACE_RESOLUTION_DEFAULT;
+
     surface->x_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
     surface->y_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
 
     surface->clip = NULL;
     surface->next_clip_serial = 0;
     surface->current_clip_serial = 0;
 
     surface->is_snapshot = FALSE;
@@ -1019,56 +1024,59 @@ cairo_status_t
 _cairo_surface_clone_similar (cairo_surface_t  *surface,
 			      cairo_surface_t  *src,
 			      int               src_x,
 			      int               src_y,
 			      int               width,
 			      int               height,
 			      cairo_surface_t **clone_out)
 {
-    cairo_status_t status;
+    cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
     cairo_image_surface_t *image;
     void *image_extra;
 
     if (surface->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
-    if (surface->backend->clone_similar == NULL)
-	return (cairo_int_status_t)
-	    _cairo_surface_fallback_clone_similar (surface, src,
-						   src_x, src_y,
-						   width, height,
-						   clone_out);
+    if (surface->backend->clone_similar) {
+	status = surface->backend->clone_similar (surface, src, src_x, src_y,
+						  width, height, clone_out);
+
+	if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+	    /* If we failed, try again with an image surface */
+	    status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
+	    if (status == CAIRO_STATUS_SUCCESS) {
+		status =
+		    surface->backend->clone_similar (surface, &image->base,
+						     src_x, src_y,
+						     width, height,
+						     clone_out);
 
-    status = surface->backend->clone_similar (surface, src, src_x, src_y,
-					      width, height, clone_out);
-    if (status == CAIRO_STATUS_SUCCESS && *clone_out != src)
-        (*clone_out)->device_transform = src->device_transform;
+		_cairo_surface_release_source_image (src, image, image_extra);
+	    }
+	}
+    }
 
-    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+    /* If we're still unsupported, hit our fallback path to get a clone */
+    if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+	status =
+	    _cairo_surface_fallback_clone_similar (surface, src, src_x, src_y,
+						   width, height, clone_out);
+
+    /* We should never get UNSUPPORTED here, so if we have an error, bail. */
+    if (status)
 	return status;
 
-    status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
-    if (status != CAIRO_STATUS_SUCCESS)
-	return status;
-
-    status = surface->backend->clone_similar (surface, &image->base, src_x,
-					      src_y, width, height, clone_out);
-    if (status == CAIRO_STATUS_SUCCESS && *clone_out != src) {
+    /* Update the clone's device_transform (which the underlying surface
+     * backend knows nothing about) */
+    if (*clone_out != src) {
         (*clone_out)->device_transform = src->device_transform;
         (*clone_out)->device_transform_inverse = src->device_transform_inverse;
-    }
+    }	
 
-    /* If the above failed point, we could implement a full fallback
-     * using acquire_dest_image, but that's going to be very
-     * inefficient compared to a backend-specific implementation of
-     * clone_similar() with an image source. So we don't bother
-     */
-
-    _cairo_surface_release_source_image (src, image, image_extra);
     return status;
 }
 
 /* XXX: Shouldn't really need to do this here. */
 #include "cairo-meta-surface-private.h"
 
 /**
  * _cairo_surface_snapshot
@@ -1386,16 +1394,75 @@ cairo_status_t
  CLEANUP_SOURCE:
     _cairo_pattern_fini (&dev_source.base);
  FINISH:
 
     return status;
 }
 
 cairo_status_t
+_cairo_surface_fill_stroke (cairo_surface_t	    *surface,
+			    cairo_operator_t	     fill_op,
+			    cairo_pattern_t	    *fill_source,
+			    cairo_fill_rule_t	     fill_rule,
+			    double		     fill_tolerance,
+			    cairo_antialias_t	     fill_antialias,
+			    cairo_path_fixed_t	    *path,
+			    cairo_operator_t	     stroke_op,
+			    cairo_pattern_t	    *stroke_source,
+			    cairo_stroke_style_t    *stroke_style,
+			    cairo_matrix_t	    *stroke_ctm,
+			    cairo_matrix_t	    *stroke_ctm_inverse,
+			    double		     stroke_tolerance,
+			    cairo_antialias_t	     stroke_antialias)
+{
+    cairo_status_t status;
+
+    if (surface->backend->fill_stroke) {
+	cairo_pattern_union_t dev_stroke_source;
+	cairo_pattern_union_t dev_fill_source;
+	cairo_matrix_t dev_ctm = *stroke_ctm;
+	cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;
+
+	status = _cairo_surface_copy_pattern_for_destination (stroke_source, surface, &dev_stroke_source.base);
+	if (status)
+	    return status;
+
+	status = _cairo_surface_copy_pattern_for_destination (fill_source, surface, &dev_fill_source.base);
+	if (status) {
+	    _cairo_pattern_fini (&dev_stroke_source.base);
+	    return status;
+	}
+
+	status = surface->backend->fill_stroke (surface, fill_op, &dev_fill_source.base,
+						fill_rule, fill_tolerance, fill_antialias,
+						path, stroke_op, &dev_stroke_source.base, stroke_style,
+						&dev_ctm, &dev_ctm_inverse, stroke_tolerance,
+						stroke_antialias);
+
+	_cairo_pattern_fini (&dev_stroke_source.base);
+	_cairo_pattern_fini (&dev_fill_source.base);
+
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    return status;
+    }
+
+    status = _cairo_surface_fill (surface, fill_op, fill_source, path,
+				  fill_rule, fill_tolerance, fill_antialias);
+    if (status)
+	return status;
+
+    status = _cairo_surface_stroke (surface, stroke_op, stroke_source, path,
+				    stroke_style, stroke_ctm, stroke_ctm_inverse,
+				    stroke_tolerance, stroke_antialias);
+
+    return status;
+}
+
+cairo_status_t
 _cairo_surface_stroke (cairo_surface_t		*surface,
 		       cairo_operator_t		 op,
 		       cairo_pattern_t		*source,
 		       cairo_path_fixed_t	*path,
 		       cairo_stroke_style_t	*stroke_style,
 		       cairo_matrix_t		*ctm,
 		       cairo_matrix_t		*ctm_inverse,
 		       double			 tolerance,
@@ -1518,51 +1585,74 @@ cairo_status_t
     return  _cairo_surface_fallback_composite_trapezoids (op, pattern, dst,
 							  antialias,
 							  src_x, src_y,
 							  dst_x, dst_y,
 							  width, height,
 							  traps, num_traps);
 }
 
+/**
+ * cairo_surface_copy_page:
+ * @suface: a #cairo_surface_t
+ *
+ * Emits the current page for backends that support multiple pages,
+ * but doesn't clear it, so that the contents of the current page will
+ * be retained for the next page.  Use cairo_surface_show_page() if you
+ * want to get an empty page after the emission.
+ *
+ * Since: 1.6
+ */
 cairo_status_t
-_cairo_surface_copy_page (cairo_surface_t *surface)
+cairo_surface_copy_page (cairo_surface_t *surface)
 {
     assert (! surface->is_snapshot);
 
     if (surface->status)
 	return surface->status;
 
     if (surface->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
     /* It's fine if some backends don't implement copy_page */
     if (surface->backend->copy_page == NULL)
 	return CAIRO_STATUS_SUCCESS;
 
     return surface->backend->copy_page (surface);
 }
+slim_hidden_def (cairo_surface_copy_page);
+
+/**
+ * cairo_surface_show_page:
+ * @surface: a #cairo_Surface_t
+ *
+ * Emits and clears the current page for backends that support multiple
+ * pages.  Use cairo_surface_copy_page() if you don't want to clear the page.
+ *
+ * Since: 1.6
+ **/
 
 cairo_status_t
-_cairo_surface_show_page (cairo_surface_t *surface)
+cairo_surface_show_page (cairo_surface_t *surface)
 {
     assert (! surface->is_snapshot);
 
     if (surface->status)
 	return surface->status;
 
     if (surface->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
     /* It's fine if some backends don't implement show_page */
     if (surface->backend->show_page == NULL)
 	return CAIRO_STATUS_SUCCESS;
 
     return surface->backend->show_page (surface);
 }
+slim_hidden_def (cairo_surface_show_page);
 
 /**
  * _cairo_surface_get_current_clip_serial:
  * @surface: the #cairo_surface_t to return the serial number for
  *
  * Returns the serial number associated with the current
  * clip in the surface.  All gstate functions must
  * verify that the correct clip is set in the surface before
@@ -1830,16 +1920,24 @@ cairo_status_t
 	return surface->status;
 
     if (surface->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
     return surface->backend->get_extents (surface, rectangle);
 }
 
+/* Note: the backends may modify the contents of the glyph array as long as
+ * they do not return CAIRO_STATUS_UNSUPPORTED. This makes it possible to
+ * avoid copying the array again and again, and edit it in-place.
+ * Backends are in fact free to use the array as a generic buffer as they
+ * see fit.
+ * See commits 5a9642c5746fd677aed35ce620ce90b1029b1a0c and
+ * 1781e6018c17909311295a9cc74b70500c6b4d0a for the rationale.
+ */
 cairo_status_t
 _cairo_surface_show_glyphs (cairo_surface_t	*surface,
 			    cairo_operator_t	 op,
 			    cairo_pattern_t	*source,
 			    cairo_glyph_t	*glyphs,
 			    int			 num_glyphs,
 			    cairo_scaled_font_t	*scaled_font)
 {
@@ -2188,10 +2286,29 @@ static cairo_status_t
 	assert (status == CAIRO_STATUS_SUCCESS);
 
 	_cairo_pattern_transform (pattern_out, &device_to_surface);
     }
 
     return CAIRO_STATUS_SUCCESS;
 }
 
+/**
+ * _cairo_surface_set_resolution
+ * @surface: the surface
+ * @x_res: x resolution, in dpi
+ * @y_res: y resolution, in dpi
+ *
+ * Set the actual surface resolution of @surface to the given x and y DPI.
+ * Mainly used for correctly computing the scale factor when fallback
+ * rendering needs to take place in the paginated surface.
+ */
+void
+_cairo_surface_set_resolution (cairo_surface_t *surface,
+			       double x_res,
+			       double y_res)
+{
+    surface->x_resolution = x_res;
+    surface->y_resolution = y_res;
+}
+
 /*  LocalWords:  rasterized
  */
--- a/gfx/cairo/cairo/src/cairo-svg-surface.c
+++ b/gfx/cairo/cairo/src/cairo-svg-surface.c
@@ -1,9 +1,9 @@
-/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* vim: set sw=4 sts=4: -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
 /* cairo - a vector graphics library with display and print output
  *
  * Copyright © 2004 Red Hat, Inc
  * Copyright © 2005-2006 Emmanuel Pacaud <emmanuel.pacaud@free.fr>
  * Copyright © 2006 Red Hat, Inc
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
@@ -446,26 +446,25 @@ static cairo_int_status_t
     _cairo_svg_surface_store_page (surface);
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static void
 _cairo_svg_surface_emit_transform (cairo_output_stream_t *output,
 		char const *attribute_str,
-		char const *trailer,
 		cairo_matrix_t *matrix)
 {
-    _cairo_output_stream_printf (output,
-				 "%s=\"matrix(%f,%f,%f,%f,%f,%f)\"%s",
-				 attribute_str,
-				 matrix->xx, matrix->yx,
-				 matrix->xy, matrix->yy,
-				 matrix->x0, matrix->y0,
-				 trailer);
+    if (!_cairo_matrix_is_identity (matrix))
+	_cairo_output_stream_printf (output,
+				     "%s=\"matrix(%f,%f,%f,%f,%f,%f)\"",
+				     attribute_str,
+				     matrix->xx, matrix->yx,
+				     matrix->xy, matrix->yy,
+				     matrix->x0, matrix->y0);
 }
 
 typedef struct
 {
     cairo_output_stream_t *output;
     cairo_matrix_t *ctm_inverse;
 } svg_path_info_t;
 
@@ -611,17 +610,18 @@ static cairo_int_status_t
     image = scaled_glyph->surface;
     if (image->format != CAIRO_FORMAT_A1) {
 	image = _cairo_image_surface_clone (image, CAIRO_FORMAT_A1);
 	if (cairo_surface_status (&image->base))
 	    return cairo_surface_status (&image->base);
     }
 
     _cairo_output_stream_printf (document->xml_node_glyphs, "<g");
-    _cairo_svg_surface_emit_transform (document->xml_node_glyphs, " transform", ">/n", &image->base.device_transform);
+    _cairo_svg_surface_emit_transform (document->xml_node_glyphs, " transform", &image->base.device_transform_inverse);
+    _cairo_output_stream_printf (document->xml_node_glyphs, ">/n");
 
     for (y = 0, row = image->data, rows = image->height; rows; row += image->stride, rows--, y++) {
 	for (x = 0, byte = row, cols = (image->width + 7) / 8; cols; byte++, cols--) {
 	    unsigned char output_byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte);
 	    for (bit = 7; bit >= 0 && x < image->width; bit--, x++) {
 		if (output_byte & (1 << bit)) {
 		    _cairo_output_stream_printf (document->xml_node_glyphs,
 						 "<rect x=\"%d\" y=\"%d\" width=\"1\" height=\"1\"/>\n",
@@ -912,25 +912,26 @@ static cairo_status_t
 
     if (pattern_id != invalid_pattern_id) {
 	_cairo_output_stream_printf (output,
 				     "<pattern id=\"pattern%d\" "
 				     "patternUnits=\"userSpaceOnUse\" "
 				     "width=\"%d\" height=\"%d\"",
 				     pattern_id,
 				     extents.width, extents.height);
-	_cairo_svg_surface_emit_transform (output, " patternTransform", ">\n", &p2u);
+	_cairo_svg_surface_emit_transform (output, " patternTransform", &p2u);
+	_cairo_output_stream_printf (output, ">\n");
     }
 
     _cairo_output_stream_printf (output,
 				 "  <image width=\"%d\" height=\"%d\"",
 				 extents.width, extents.height);
 
     if (pattern_id == invalid_pattern_id)
-	_cairo_svg_surface_emit_transform (output, " transform", "", &p2u);
+	_cairo_svg_surface_emit_transform (output, " transform", &p2u);
 
     if (extra_attributes)
 	_cairo_output_stream_printf (output, " %s", extra_attributes);
 
     _cairo_output_stream_printf (output, " xlink:href=\"");
 
     status = _cairo_surface_base64_encode (surface, output);
 
@@ -985,17 +986,17 @@ static cairo_status_t
 					   document->owner->y_fallback_resolution);
 
     status = _cairo_meta_surface_replay ((cairo_surface_t *)meta, paginated_surface);
     if (status) {
 	cairo_surface_destroy (&meta->base);
 	return status;
     }
 
-    status = _cairo_surface_show_page (paginated_surface);
+    status = cairo_surface_show_page (paginated_surface);
     if (status) {
 	cairo_surface_destroy (&meta->base);
 	return status;
     }
 
     new_snapshot.meta = meta;
     new_snapshot.id = svg_surface->id;
     status = _cairo_array_append (&document->meta_snapshots, &new_snapshot);
@@ -1087,25 +1088,26 @@ static cairo_status_t
     if (pattern_id != invalid_pattern_id) {
 	_cairo_output_stream_printf (output,
 				     "<pattern id=\"pattern%d\" "
 				     "patternUnits=\"userSpaceOnUse\" "
 				     "width=\"%d\" height=\"%d\"",
 				     pattern_id,
 				     meta_surface->width_pixels,
 				     meta_surface->height_pixels);
-	_cairo_svg_surface_emit_transform (output, " patternTransform", ">\n", &p2u);
+	_cairo_svg_surface_emit_transform (output, " patternTransform", &p2u);
+	_cairo_output_stream_printf (output, ">\n");
     }
 
     _cairo_output_stream_printf (output,
 				 "<use xlink:href=\"#surface%d\"",
 				 id);
 
     if (pattern_id == invalid_pattern_id)
-	_cairo_svg_surface_emit_transform (output, " transform", "", &p2u);
+	_cairo_svg_surface_emit_transform (output, " transform", &p2u);
 
     if (extra_attributes)
 	_cairo_output_stream_printf (output, " %s", extra_attributes);
 
     _cairo_output_stream_printf (output, "/>\n");
 
     if (pattern_id != invalid_pattern_id)
 	_cairo_output_stream_printf (output, "</pattern>\n");
@@ -1394,17 +1396,18 @@ static cairo_status_t
     _cairo_output_stream_printf (document->xml_node_defs,
 				 "<linearGradient id=\"linear%d\" "
 				 "gradientUnits=\"userSpaceOnUse\" "
 				 "x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" ",
 				 document->linear_pattern_id,
 				 x0, y0, x1, y1);
 
     _cairo_svg_surface_emit_pattern_extend (document->xml_node_defs, &pattern->base.base),
-    _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", ">\n", &p2u);
+    _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u);
+    _cairo_output_stream_printf (document->xml_node_defs, ">\n");
 
     _cairo_svg_surface_emit_pattern_stops (document->xml_node_defs ,&pattern->base, 0.0, FALSE, FALSE);
 
     _cairo_output_stream_printf (document->xml_node_defs,
 				 "</linearGradient>\n");
 
     _cairo_output_stream_printf (style,
 				 "%s: url(#linear%d);",
@@ -1464,18 +1467,18 @@ static cairo_status_t
 	_cairo_output_stream_printf (document->xml_node_defs,
 				     "<radialGradient id=\"radial%d\" "
 				     "gradientUnits=\"userSpaceOnUse\" "
 				     "cx=\"%f\" cy=\"%f\" "
 				     "fx=\"%f\" fy=\"%f\" r=\"%f\" ",
 				     document->radial_pattern_id,
 				     x1, y1,
 				     x1, y1, r1);
-
-	_cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", ">\n", &p2u);
+	_cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u);
+	_cairo_output_stream_printf (document->xml_node_defs, ">\n");
 
 	if (extend == CAIRO_EXTEND_NONE ||
 	    pattern->base.n_stops < 1)
 	    _cairo_output_stream_printf (document->xml_node_defs,
 					 "<stop offset=\"0\" style=\""
 					 "stop-color: rgb(0%%,0%%,0%%); "
 					 "stop-opacity: 0;\"/>\n");
 	else {
@@ -1549,17 +1552,18 @@ static cairo_status_t
 				     document->radial_pattern_id,
 				     x1, y1,
 				     fx, fy, r1);
 
 	if (emulate_reflect)
 	    _cairo_output_stream_printf (document->xml_node_defs, "spreadMethod=\"repeat\" ");
 	else
 	    _cairo_svg_surface_emit_pattern_extend (document->xml_node_defs, &pattern->base.base);
-	_cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", ">\n", &p2u);
+	_cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u);
+	_cairo_output_stream_printf (document->xml_node_defs, ">\n");
 
 	/* To support cairo's EXTEND_NONE, (for which SVG has no similar
 	 * notion), we add transparent color stops on either end of the
 	 * user-provided stops. */
 	if (extend == CAIRO_EXTEND_NONE) {
 	    _cairo_output_stream_printf (document->xml_node_defs,
 					 "<stop offset=\"0\" style=\""
 					 "stop-color: rgb(0%%,0%%,0%%); "
@@ -1608,16 +1612,134 @@ static cairo_status_t
 	return _cairo_svg_surface_emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern, output, is_stroke);
 
     case CAIRO_PATTERN_TYPE_RADIAL:
 	return _cairo_svg_surface_emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern, output, is_stroke);
     }
     return CAIRO_STATUS_SUCCESS;
 }
 
+static void
+_cairo_svg_surface_emit_fill_style (cairo_output_stream_t *output,
+				    cairo_svg_surface_t *surface,
+				    cairo_operator_t op,
+				    cairo_pattern_t *source,
+				    cairo_fill_rule_t fill_rule)
+{
+    _cairo_output_stream_printf (output,
+				 "fill-rule: %s; ",
+				 fill_rule == CAIRO_FILL_RULE_EVEN_ODD ?
+				 "evenodd" : "nonzero");
+    _cairo_svg_surface_emit_operator (output, surface, op);
+    _cairo_svg_surface_emit_pattern (surface, source, output, FALSE);
+}
+
+static void
+_cairo_svg_surface_emit_stroke_style (cairo_output_stream_t *output,
+				      cairo_svg_surface_t   *surface,
+				      cairo_operator_t	     op,
+				      cairo_pattern_t	    *source,
+				      cairo_stroke_style_t  *stroke_style)
+{
+    const char *line_cap, *line_join;
+    unsigned int i;
+
+    switch (stroke_style->line_cap) {
+	case CAIRO_LINE_CAP_BUTT:
+	    line_cap = "butt";
+	    break;
+	case CAIRO_LINE_CAP_ROUND:
+	    line_cap = "round";
+	    break;
+	case CAIRO_LINE_CAP_SQUARE:
+	    line_cap = "square";
+	    break;
+	default:
+	    ASSERT_NOT_REACHED;
+    }
+
+    switch (stroke_style->line_join) {
+	case CAIRO_LINE_JOIN_MITER:
+	    line_join = "miter";
+	    break;
+	case CAIRO_LINE_JOIN_ROUND:
+	    line_join = "round";
+	    break;
+	case CAIRO_LINE_JOIN_BEVEL:
+	    line_join = "bevel";
+	    break;
+	default:
+	    ASSERT_NOT_REACHED;
+    }
+
+    _cairo_output_stream_printf (output,
+				 "stroke-width: %f; "
+				 "stroke-linecap: %s; "
+				 "stroke-linejoin: %s; ",
+				 stroke_style->line_width,
+				 line_cap,
+				 line_join);
+
+     _cairo_svg_surface_emit_pattern (surface, source, output, TRUE);
+     _cairo_svg_surface_emit_operator (output, surface, op);
+
+    if (stroke_style->num_dashes > 0) {
+	_cairo_output_stream_printf (output, "stroke-dasharray: ");
+	for (i = 0; i < stroke_style->num_dashes; i++) {
+	    _cairo_output_stream_printf (output, "%f",
+					 stroke_style->dash[i]);
+	    if (i + 1 < stroke_style->num_dashes)
+		_cairo_output_stream_printf (output, ",");
+	    else
+		_cairo_output_stream_printf (output, "; ");
+	}
+	if (stroke_style->dash_offset != 0.0) {
+	    _cairo_output_stream_printf (output,
+					 "stroke-dashoffset: %f; ",
+					 stroke_style->dash_offset);
+	}
+    }
+
+    _cairo_output_stream_printf (output,
+				 "stroke-miterlimit: %f; ",
+				 stroke_style->miter_limit);
+}
+
+static cairo_int_status_t
+_cairo_svg_surface_fill_stroke (void			*abstract_surface,
+				cairo_operator_t	 fill_op,
+				cairo_pattern_t		*fill_source,
+				cairo_fill_rule_t	 fill_rule,
+				double			 fill_tolerance,
+				cairo_antialias_t	 fill_antialias,
+				cairo_path_fixed_t	*path,
+				cairo_operator_t	 stroke_op,
+				cairo_pattern_t		*stroke_source,
+				cairo_stroke_style_t	*stroke_style,
+				cairo_matrix_t		*stroke_ctm,
+				cairo_matrix_t		*stroke_ctm_inverse,
+				double			 stroke_tolerance,
+				cairo_antialias_t	 stroke_antialias)
+{
+    cairo_svg_surface_t *surface = abstract_surface;
+    cairo_status_t status;
+
+    _cairo_output_stream_printf (surface->xml_node, "<path style=\"");
+    _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, fill_op, fill_source, fill_rule);
+    _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface, stroke_op, stroke_source, stroke_style);
+    _cairo_output_stream_printf (surface->xml_node, "\" ");
+
+    status = _cairo_svg_surface_emit_path (surface->xml_node, path, stroke_ctm_inverse);
+
+    _cairo_svg_surface_emit_transform (surface->xml_node, " transform", stroke_ctm);
+    _cairo_output_stream_printf (surface->xml_node, "/>\n");
+
+    return status;
+}
+
 static cairo_int_status_t
 _cairo_svg_surface_fill (void			*abstract_surface,
 			 cairo_operator_t	 op,
 			 cairo_pattern_t	*source,
 			 cairo_path_fixed_t	*path,
 			 cairo_fill_rule_t	 fill_rule,
 			 double			 tolerance,
 			 cairo_antialias_t	 antialias)
@@ -1625,23 +1747,18 @@ static cairo_int_status_t
     cairo_svg_surface_t *surface = abstract_surface;
     cairo_status_t status;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_svg_surface_analyze_operation (surface, op, source);
 
     assert (_cairo_svg_surface_operation_supported (surface, op, source));
 
-    _cairo_output_stream_printf (surface->xml_node,
- 				 "<path style=\"stroke: none; "
- 				 "fill-rule: %s; ",
- 				 fill_rule == CAIRO_FILL_RULE_EVEN_ODD ?
- 				 "evenodd" : "nonzero");
-    _cairo_svg_surface_emit_operator (surface->xml_node, surface, op);
-    _cairo_svg_surface_emit_pattern (surface, source, surface->xml_node, FALSE);
+    _cairo_output_stream_printf (surface->xml_node, "<path style=\" stroke:none;");
+    _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, op, source, fill_rule);
     _cairo_output_stream_printf (surface->xml_node, "\" ");
 
     status = _cairo_svg_surface_emit_path (surface->xml_node, path, NULL);
 
     _cairo_output_stream_printf (surface->xml_node, "/>\n");
 
     return status;
 }
@@ -1810,88 +1927,30 @@ static cairo_int_status_t
 			   cairo_stroke_style_t *stroke_style,
 			   cairo_matrix_t	*ctm,
 			   cairo_matrix_t	*ctm_inverse,
 			   double		 tolerance,
 			   cairo_antialias_t	 antialias)
 {
     cairo_svg_surface_t *surface = abstract_dst;
     cairo_status_t status;
-    const char *line_cap, *line_join;
-    unsigned int i;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_svg_surface_analyze_operation (surface, op, source);
 
     assert (_cairo_svg_surface_operation_supported (surface, op, source));
 
-    switch (stroke_style->line_cap) {
-    case CAIRO_LINE_CAP_BUTT:
- 	line_cap = "butt";
- 	break;
-    case CAIRO_LINE_CAP_ROUND:
- 	line_cap = "round";
- 	break;
-    case CAIRO_LINE_CAP_SQUARE:
- 	line_cap = "square";
- 	break;
-    default:
- 	ASSERT_NOT_REACHED;
-    }
-
-    switch (stroke_style->line_join) {
-    case CAIRO_LINE_JOIN_MITER:
- 	line_join = "miter";
- 	break;
-    case CAIRO_LINE_JOIN_ROUND:
- 	line_join = "round";
- 	break;
-    case CAIRO_LINE_JOIN_BEVEL:
- 	line_join = "bevel";
- 	break;
-    default:
- 	ASSERT_NOT_REACHED;
-    }
-
-    _cairo_output_stream_printf (surface->xml_node,
- 				 "<path style=\"fill: none; "
- 				 "stroke-width: %f; "
- 				 "stroke-linecap: %s; "
- 				 "stroke-linejoin: %s; ",
-				 stroke_style->line_width,
- 				 line_cap,
- 				 line_join);
-
-     _cairo_svg_surface_emit_pattern (surface, source, surface->xml_node, TRUE);
-     _cairo_svg_surface_emit_operator (surface->xml_node, surface, op);
-
-    if (stroke_style->num_dashes > 0) {
- 	_cairo_output_stream_printf (surface->xml_node, "stroke-dasharray: ");
-	for (i = 0; i < stroke_style->num_dashes; i++) {
- 	    _cairo_output_stream_printf (surface->xml_node, "%f",
- 					 stroke_style->dash[i]);
- 	    if (i + 1 < stroke_style->num_dashes)
- 		_cairo_output_stream_printf (surface->xml_node, ",");
- 	    else
- 		_cairo_output_stream_printf (surface->xml_node, "; ");
-	}
-	if (stroke_style->dash_offset != 0.0) {
- 	    _cairo_output_stream_printf (surface->xml_node,
- 					 "stroke-dashoffset: %f; ",
- 					 stroke_style->dash_offset);
-	}
-    }
-
-    _cairo_output_stream_printf (surface->xml_node,
- 				 "stroke-miterlimit: %f;\" ",
- 				 stroke_style->miter_limit);
+    _cairo_output_stream_printf (surface->xml_node, "<path style=\"fill: none; ");
+    _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface, op, source, stroke_style);
+    _cairo_output_stream_printf (surface->xml_node, "\" ");
 
     status = _cairo_svg_surface_emit_path (surface->xml_node, path, ctm_inverse);
 
-    _cairo_svg_surface_emit_transform (surface->xml_node, " transform", "/>\n", ctm);
+    _cairo_svg_surface_emit_transform (surface->xml_node, " transform", ctm);
+    _cairo_output_stream_printf (surface->xml_node, "/>\n");
 
     return status;
 }
 
 static cairo_int_status_t
 _cairo_svg_surface_show_glyphs (void			*abstract_surface,
 				cairo_operator_t	 op,
 				cairo_pattern_t		*pattern,
@@ -2038,17 +2097,21 @@ static const cairo_surface_backend_t cai
 	NULL, /* flush */
 	NULL, /* mark dirty rectangle */
 	NULL, /* scaled font fini */
 	NULL, /* scaled glyph fini */
 	_cairo_svg_surface_paint,
 	_cairo_svg_surface_mask,
 	_cairo_svg_surface_stroke,
 	_cairo_svg_surface_fill,
-	_cairo_svg_surface_show_glyphs
+	_cairo_svg_surface_show_glyphs,
+	NULL, /* snapshot */
+	NULL, /* is_similar */
+	NULL, /* reset */
+	_cairo_svg_surface_fill_stroke
 };
 
 static cairo_svg_document_t *
 _cairo_svg_document_create (cairo_output_stream_t	*output_stream,
 			    double			 width,
 			    double			 height,
 			    cairo_svg_version_t		 version)
 {
--- a/gfx/cairo/cairo/src/cairo-truetype-subset.c
+++ b/gfx/cairo/cairo/src/cairo-truetype-subset.c
@@ -926,23 +926,26 @@ cairo_status_t
 
     truetype_subset->x_min = (double)font->base.x_min/font->base.units_per_em;
     truetype_subset->y_min = (double)font->base.y_min/font->base.units_per_em;
     truetype_subset->x_max = (double)font->base.x_max/font->base.units_per_em;
     truetype_subset->y_max = (double)font->base.y_max/font->base.units_per_em;
     truetype_subset->ascent = (double)font->base.ascent/font->base.units_per_em;
     truetype_subset->descent = (double)font->base.descent/font->base.units_per_em;
 
-    truetype_subset->data = malloc (length);
-    if (truetype_subset->data == NULL) {
-	status = CAIRO_STATUS_NO_MEMORY;
-	goto fail3;
-    }
+    if (length) {
+	truetype_subset->data = malloc (length);
+	if (truetype_subset->data == NULL) {
+	    status = CAIRO_STATUS_NO_MEMORY;
+	    goto fail3;
+	}
 
-    memcpy (truetype_subset->data, data, length);
+	memcpy (truetype_subset->data, data, length);
+    } else
+	truetype_subset->data = NULL;
     truetype_subset->data_length = length;
 
     if (num_strings) {
 	offsets_length = num_strings * sizeof (unsigned long);
 	truetype_subset->string_offsets = malloc (offsets_length);
 	if (truetype_subset->string_offsets == NULL) {
 	    status = CAIRO_STATUS_NO_MEMORY;
 	    goto fail4;
--- a/gfx/cairo/cairo/src/cairo-types-private.h
+++ b/gfx/cairo/cairo/src/cairo-types-private.h
@@ -33,47 +33,34 @@
  *
  * Contributor(s):
  *	Carl D. Worth <cworth@cworth.org>
  */
 
 #ifndef CAIRO_TYPES_PRIVATE_H
 #define CAIRO_TYPES_PRIVATE_H
 
-typedef struct _cairo_array cairo_array_t;
-struct _cairo_array {
-    unsigned int size;
-    unsigned int num_elements;
-    unsigned int element_size;
-    char **elements;
-
-    cairo_bool_t is_snapshot;
-};
-
-typedef cairo_array_t cairo_user_data_array_t;
+/* This is the only header file not including cairoint.h.  It only contains
+ * typedefs.*/
+#include "cairo.h"
 
-struct _cairo_font_options {
-    cairo_antialias_t antialias;
-    cairo_subpixel_order_t subpixel_order;
-    cairo_hint_style_t hint_style;
-    cairo_hint_metrics_t hint_metrics;
-};
-
+typedef struct _cairo_array cairo_array_t;
 typedef struct _cairo_hash_table cairo_hash_table_t;
-
-typedef struct _cairo_cache {
-    cairo_hash_table_t *hash_table;
-
-    cairo_destroy_func_t entry_destroy;
-
-    unsigned long max_size;
-    unsigned long size;
-
-    int freeze_count;
-} cairo_cache_t;
+typedef struct _cairo_cache cairo_cache_t;
+typedef struct _cairo_hash_entry cairo_hash_entry_t;
+typedef struct _cairo_surface_backend cairo_surface_backend_t;
+typedef struct _cairo_clip cairo_clip_t;
+typedef struct _cairo_output_stream cairo_output_stream_t;
+typedef struct _cairo_scaled_font_subsets cairo_scaled_font_subsets_t;
+typedef struct _cairo_paginated_surface_backend cairo_paginated_surface_backend_t;
+typedef struct _cairo_scaled_font_backend   cairo_scaled_font_backend_t;
+typedef struct _cairo_font_face_backend     cairo_font_face_backend_t;
+typedef struct _cairo_xlib_screen_info cairo_xlib_screen_info_t;
+typedef enum _cairo_paginated_mode cairo_paginated_mode_t;
+typedef cairo_array_t cairo_user_data_array_t;
 
 /**
  * cairo_hash_entry_t:
  *
  * A #cairo_hash_entry_t contains both a key and a value for
  * cairo_hash_table_t. User-derived types for cairo_hash_entry_t must
  * be type-compatible with this structure (eg. they must have an
  * unsigned long as the first parameter. The easiest way to get this
@@ -99,30 +86,67 @@ typedef struct _cairo_cache {
  * Which parts of the entry make up the "key" and which part make up
  * the value are entirely up to the caller, (as determined by the
  * computation going into base.hash as well as the keys_equal
  * function). A few of the cairo_hash_table functions accept an entry
  * which will be used exclusively as a "key", (indicated by a
  * parameter name of key). In these cases, the value-related fields of
  * the entry need not be initialized if so desired.
  **/
-typedef struct _cairo_hash_entry {
+struct _cairo_hash_entry {
     unsigned long hash;
-} cairo_hash_entry_t;
+};
 
+struct _cairo_array {
+    unsigned int size;
+    unsigned int num_elements;
+    unsigned int element_size;
+    char **elements;
+
+    cairo_bool_t is_snapshot;
+};
 
-typedef struct _cairo_surface_backend cairo_surface_backend_t;
-typedef struct _cairo_clip cairo_clip_t;
-typedef struct _cairo_output_stream cairo_output_stream_t;
-typedef struct _cairo_scaled_font_subsets cairo_scaled_font_subsets_t;
-typedef struct _cairo_paginated_surface_backend cairo_paginated_surface_backend_t;
-typedef struct _cairo_scaled_font_backend   cairo_scaled_font_backend_t;
-typedef struct _cairo_font_face_backend     cairo_font_face_backend_t;
+struct _cairo_font_options {
+    cairo_antialias_t antialias;
+    cairo_subpixel_order_t subpixel_order;
+    cairo_hint_style_t hint_style;
+    cairo_hint_metrics_t hint_metrics;
+};
+
+struct _cairo_cache {
+    cairo_hash_table_t *hash_table;
 
+    cairo_destroy_func_t entry_destroy;
 
-typedef struct _cairo_xlib_screen_info cairo_xlib_screen_info_t;
+    unsigned long max_size;
+    unsigned long size;
 
-typedef enum {
+    int freeze_count;
+};
+
+enum _cairo_paginated_mode {
     CAIRO_PAGINATED_MODE_ANALYZE,	/* analyze page regions */
     CAIRO_PAGINATED_MODE_RENDER		/* render page contents */
-} cairo_paginated_mode_t;
+};
+
+/* Sure wish C had a real enum type so that this would be distinct
+   from cairo_status_t. Oh well, without that, I'll use this bogus 1000
+   offset */
+typedef enum _cairo_int_status {
+    CAIRO_INT_STATUS_DEGENERATE = 1000,
+    CAIRO_INT_STATUS_UNSUPPORTED,
+    CAIRO_INT_STATUS_NOTHING_TO_DO,
+    CAIRO_INT_STATUS_CACHE_EMPTY,
+    CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY,
+    CAIRO_INT_STATUS_IMAGE_FALLBACK,
+    CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN,
+} cairo_int_status_t;
+
+typedef enum _cairo_internal_surface_type {
+    CAIRO_INTERNAL_SURFACE_TYPE_META = 0x1000,
+    CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED,
+    CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
+    CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
+    CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+    CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED
+} cairo_internal_surface_type_t;
 
 #endif /* CAIRO_TYPES_PRIVATE_H */
--- a/gfx/cairo/cairo/src/cairo-win32-font.c
+++ b/gfx/cairo/cairo/src/cairo-win32-font.c
@@ -298,43 +298,40 @@ static cairo_scaled_font_t *
     f->delete_scaled_hfont = !f->scaled_hfont;
 
     cairo_matrix_multiply (&scale, font_matrix, ctm);
     _compute_transform (f, &scale);
 
     status = _cairo_scaled_font_init (&f->base, font_face,
 				      font_matrix, ctm, options,
 				      &cairo_win32_scaled_font_backend);
-    if (status) {
-	free (f);
-	return NULL;
-    }
+    if (status)
+	goto FAIL;
 
     status = _cairo_win32_scaled_font_set_metrics (f);
+
     if (status) {
-	_cairo_scaled_font_fini (f);
-	free (f);
-	return NULL;
+	_cairo_scaled_font_fini (&f->base);
+	goto FAIL;
     }
 
     return &f->base;
+
+ FAIL:
+    free (f);
+    return NULL;
 }
 
 static cairo_status_t
 _win32_scaled_font_set_world_transform (cairo_win32_scaled_font_t *scaled_font,
 					HDC                        hdc)
 {
     XFORM xform;
 
-    xform.eM11 = scaled_font->logical_to_device.xx;
-    xform.eM21 = scaled_font->logical_to_device.xy;
-    xform.eM12 = scaled_font->logical_to_device.yx;
-    xform.eM22 = scaled_font->logical_to_device.yy;
-    xform.eDx = scaled_font->logical_to_device.x0;
-    xform.eDy = scaled_font->logical_to_device.y0;
+    _cairo_matrix_to_win32_xform (&scaled_font->logical_to_device, &xform);
 
     if (!SetWorldTransform (hdc, &xform))
 	return _cairo_win32_print_gdi_error ("_win32_scaled_font_set_world_transform");
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
new file mode 100644
--- /dev/null
+++ b/gfx/cairo/cairo/src/cairo-win32-printing-surface.c
@@ -0,0 +1,1220 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ *      Adrian Johnson <ajohnson@redneon.com>
+ *      Vladimir Vukicevic <vladimir@pobox.com>
+ */
+
+#define WIN32_LEAN_AND_MEAN
+/* We require Windows 2000 features such as ETO_PDY */
+#if !defined(WINVER) || (WINVER < 0x0500)
+# define WINVER 0x0500
+#endif
+#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
+# define _WIN32_WINNT 0x0500
+#endif
+
+#include "cairoint.h"
+
+#include "cairo-paginated-private.h"
+
+#include "cairo-clip-private.h"
+#include "cairo-win32-private.h"
+
+#include <windows.h>
+
+#if !defined(POSTSCRIPT_IDENTIFY)
+# define POSTSCRIPT_IDENTIFY 0x1015
+#endif
+
+#if !defined(PSIDENT_GDICENTRIC)
+# define PSIDENT_GDICENTRIC 0x0000
+#endif
+
+#if !defined(GET_PS_FEATURESETTING)
+# define GET_PS_FEATURESETTING 0x1019
+#endif
+
+#if !defined(FEATURESETTING_PSLEVEL)
+# define FEATURESETTING_PSLEVEL 0x0002
+#endif
+
+#define PELS_72DPI  ((LONG)(72. / 0.0254))
+#define NIL_SURFACE ((cairo_surface_t*)&_cairo_surface_nil)
+
+static const cairo_surface_backend_t cairo_win32_printing_surface_backend;
+static const cairo_paginated_surface_backend_t cairo_win32_surface_paginated_backend;
+
+static void
+_cairo_win32_printing_surface_init_ps_mode (cairo_win32_surface_t *surface)
+{
+    DWORD word;
+    INT ps_feature, ps_level;
+
+    word = PSIDENT_GDICENTRIC;
+    if (ExtEscape (surface->dc, POSTSCRIPT_IDENTIFY, sizeof(DWORD), (char *)&word, 0, (char *)NULL) <= 0)
+	return;
+
+    ps_feature = FEATURESETTING_PSLEVEL;
+    if (ExtEscape (surface->dc, GET_PS_FEATURESETTING, sizeof(INT),
+		   (char *)&ps_feature, sizeof(INT), (char *)&ps_level) <= 0)
+	return;
+
+    if (ps_level >= 3)
+	surface->flags |= CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT;
+}
+
+static cairo_bool_t