Merge commit for bug 112294
☠☠ backed out by ed6642a02b2d ☠ ☠
authorEre Maijala <emaijala@kolumbus.fi>
Wed, 23 Jul 2008 10:32:44 +0300
changeset 16131 ed4c2de9fa703acf3f116423f7948655b9ce6a66
parent 16130 fec39d6457d68d1988e8053f484f0ff20c10db7c (current diff)
parent 16128 80865e03f6af9ae6d9f88e358f483cc8a8f232d4 (diff)
child 16132 29309764fdb139b69cdfa3a30877e8f9d2524d57
child 16134 ed6642a02b2d4cdb2a8bd6a5f081c60d85c198ee
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
bugs112294
milestone1.9.1a1pre
Merge commit for bug 112294
gfx/cairo/cairo/src/cairo-debug.h
gfx/cairo/libpixman/src/pixman-combine.c
gfx/cairo/libpixman/src/pixman-remap.h
js/tests/sisyphus-javascript.patch
--- a/accessible/src/base/nsAccessNode.cpp
+++ b/accessible/src/base/nsAccessNode.cpp
@@ -186,18 +186,17 @@ NS_IMETHODIMP nsAccessNode::Init()
     do_QueryInterface(docAccessible);
   NS_ASSERTION(privateDocAccessible, "No private docaccessible for docaccessible");
   privateDocAccessible->CacheAccessNode(uniqueID, this);
 
   // Make sure an ancestor in real content is cached
   // so that nsDocAccessible::RefreshNodes() can find the anonymous subtree to release when
   // the root node goes away
   nsCOMPtr<nsIContent> content = do_QueryInterface(mDOMNode);
-  if (content && (content->IsNativeAnonymous() ||
-                  content->GetBindingParent())) {
+  if (content && content->IsInAnonymousSubtree()) {
     // Specific examples of where this is used: <input type="file"> and <xul:findbar>
     nsCOMPtr<nsIAccessible> parentAccessible;
     docAccessible->GetAccessibleInParentChain(mDOMNode, PR_TRUE, getter_AddRefs(parentAccessible));
     if (parentAccessible) {
       PRInt32 childCountUnused;
       parentAccessible->GetChildCount(&childCountUnused);
     }
   }
--- a/accessible/src/base/nsAccessibilityUtils.cpp
+++ b/accessible/src/base/nsAccessibilityUtils.cpp
@@ -787,29 +787,28 @@ nsAccUtils::FindNeighbourPointingToNode(
 
 nsIContent*
 nsAccUtils::FindNeighbourPointingToNode(nsIContent *aForNode, 
                                         nsIAtom **aRelationAttrs,
                                         PRUint32 aAttrNum,
                                         nsIAtom *aTagName,
                                         PRUint32 aAncestorLevelsToSearch)
 {
-  nsCOMPtr<nsIContent> binding;
   nsAutoString controlID;
   if (!nsAccUtils::GetID(aForNode, controlID)) {
-    binding = aForNode->GetBindingParent();
-    if (binding == aForNode)
+    if (aForNode->IsInAnonymousSubtree())
       return nsnull;
 
     aForNode->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::anonid, controlID);
     if (controlID.IsEmpty())
       return nsnull;
   }
 
   // Look for label in subtrees of nearby ancestors
+  nsCOMPtr<nsIContent> binding(aForNode->GetBindingParent());
   PRUint32 count = 0;
   nsIContent *labelContent = nsnull;
   nsIContent *prevSearched = nsnull;
 
   while (!labelContent && ++count <= aAncestorLevelsToSearch &&
          (aForNode = aForNode->GetParent()) != nsnull) {
 
     if (aForNode == binding) {
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -1755,19 +1755,18 @@ void nsDocAccessible::RefreshNodes(nsIDO
         children->GetLength(&childCount);
       nsCOMPtr<nsIDOMNode> possibleAnonNode;
       for (PRUint32 index = 0; index < childCount; index++) {
         nsCOMPtr<nsIAccessNode> childAccessNode;
         children->QueryElementAt(index, NS_GET_IID(nsIAccessNode),
                                  getter_AddRefs(childAccessNode));
         childAccessNode->GetDOMNode(getter_AddRefs(possibleAnonNode));
         nsCOMPtr<nsIContent> iterContent = do_QueryInterface(possibleAnonNode);
-        if (iterContent && (iterContent->IsNativeAnonymous() ||
-                            iterContent->GetBindingParent())) {
-          // GetBindingParent() check is a perf win -- make sure we don't
+        if (iterContent && iterContent->IsInAnonymousSubtree()) {
+          // IsInAnonymousSubtree() check is a perf win -- make sure we don't
           // shut down the same subtree twice since we'll reach non-anon content via
           // DOM traversal later in this method
           RefreshNodes(possibleAnonNode);
         }
       }
     }
   }
 
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -635,17 +635,19 @@ nsresult nsHyperTextAccessible::DOMPoint
   // Get accessible for this findNode, or if that node isn't accessible, use the
   // accessible for the next DOM node which has one (based on forward depth first search)
   nsCOMPtr<nsIAccessible> descendantAccessible;
   if (findNode) {
     nsCOMPtr<nsIContent> findContent = do_QueryInterface(findNode);
     if (findContent->IsNodeOfType(nsINode::eHTML) && 
         findContent->NodeInfo()->Equals(nsAccessibilityAtoms::br)) {
       nsIContent *parent = findContent->GetParent();
-      if (parent && parent->IsNativeAnonymous() && parent->GetChildCount() == 1) {
+      if (parent &&
+          parent->IsRootOfNativeAnonymousSubtree() &&
+          parent->GetChildCount() == 1) {
         // This <br> is the only node in a text control, therefore it is the hacky
         // "bogus node" used when there is no text in a control
         *aHyperTextOffset = 0;
         return NS_OK;
       }
     }
     descendantAccessible = GetFirstAvailableAccessible(findNode);
   }
--- a/browser/branding/unofficial/branding.nsi
+++ b/browser/branding/unofficial/branding.nsi
@@ -32,24 +32,24 @@
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
 # NSIS branding defines for unofficial builds.
 # The official release build branding.nsi is located in other-license/branding/firefox/
 # The nightly build branding.nsi is located in browser/installer/windows/nsis/
-!define BrandShortName        "Gran Paradiso"
+!define BrandShortName        "Shiretoko"
 # BrandFullNameInternal is used for some registry and file system values
 # instead of BrandFullName and typically should not be modified.
-!define BrandFullNameInternal "Gran Paradiso"
+!define BrandFullNameInternal "Shiretoko"
 !define CompanyName           "mozilla.org"
 !define URLInfoAbout          "http://www.mozilla.org"
 !define URLUpdateInfo         "http://www.mozilla.org/projects/firefox"
 !define SurveyURL             "https://survey.mozilla.com/1/Mozilla%20Firefox/${AppVersion}/${AB_CD}/exit.html"
 
 # Everything below this line may be modified for Alpha / Beta releases.
-!define BrandFullName         "Gran Paradiso"
+!define BrandFullName         "Shiretoko"
 
 # Add !define NO_INSTDIR_FROM_REG to prevent finding a non-default installation
 # directory in the registry and using that as the default. This prevents
 # Beta releases built with official branding from finding an existing install
 # of an official release and defaulting to its installation directory.
--- a/browser/branding/unofficial/configure.sh
+++ b/browser/branding/unofficial/configure.sh
@@ -1,1 +1,1 @@
-MOZ_APP_DISPLAYNAME="GranParadiso"
\ No newline at end of file
+MOZ_APP_DISPLAYNAME="Shiretoko"
--- a/browser/branding/unofficial/license.r
+++ b/browser/branding/unofficial/license.r
@@ -23,30 +23,30 @@ resource 'STR#' (5000, "English") {
     // Decline (Disagree)
     "Decline",
     // Print, ellipsis is 0xC9
     "Print",
     // Save As, ellipsis is 0xC9
     "Save As",
     // Descriptive text, curly quotes are 0xD2 and 0xD3
     "You are about to install\n"
-    "Gran Paradiso.\n"
+    "Shiretoko.\n"
     "\n"
     "Please read the license agreement.  If you agree to its terms and accept, click Accept to access the software.  Otherwise, click Decline to cancel."
   };
 };
 
 // Beware of 1024(?) byte (character?) line length limitation.  Split up long
 // lines.
 // If straight quotes are used ("), remember to escape them (\").
 // Newline is \n, to leave a blank line, use two of them.
 // 0xD2 and 0xD3 are curly double-quotes ("), 0xD4 and 0xD5 are curly
 //   single quotes ('), 0xD5 is also the apostrophe.
 data 'TEXT' (5000, "English") {
-  "GRAN PARADISO END-USER SOFTWARE LICENSE AGREEMENT\n"
+  "SHIRETOKO END-USER SOFTWARE LICENSE AGREEMENT\n"
   "Version 3.0, May 2008\n"
   "\n"
   "A SOURCE CODE VERSION OF CERTAIN FIREFOX BROWSER FUNCTIONALITY THAT YOU MAY USE, MODIFY AND DISTRIBUTE IS AVAILABLE TO YOU FREE-OF-CHARGE FROM WWW.MOZILLA.ORG UNDER THE MOZILLA PUBLIC LICENSE and other open source software licenses.\n"
   "\n"
   "The accompanying executable code version of Mozilla Firefox and related documentation (the Product) is made available to you under the terms of this MOZILLA FIREFOX END-USER SOFTWARE LICENSE AGREEMENT (THE AGREEMENT).  BY CLICKING THE ACCEPT BUTTON, OR BY INSTALLING OR USING THE MOZILLA FIREFOX BROWSER, YOU ARE CONSENTING TO BE BOUND BY THE AGREEMENT.  IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT, DO NOT CLICK THE ACCEPT BUTTON, AND DO NOT INSTALL OR USE ANY PART OF THE MOZILLA FIREFOX BROWSER.\n"
   "\n"
   "DURING THE MOZILLA FIREFOX INSTALLATION PROCESS, AND AT LATER TIMES, YOU MAY BE GIVEN THE OPTION OF INSTALLING ADDITIONAL COMPONENTS FROM THIRD-PARTY SOFTWARE PROVIDERS.  THE INSTALLATION AND USE OF THOSE THIRD-PARTY COMPONENTS MAY BE GOVERNED BY ADDITIONAL LICENSE AGREEMENTS.\n"
   "\n"
--- a/browser/branding/unofficial/locales/browserconfig.properties
+++ b/browser/branding/unofficial/locales/browserconfig.properties
@@ -1,3 +1,3 @@
 # Do NOT localize or otherwise change these values
-browser.startup.homepage=http://www.mozilla.org/projects/granparadiso/
+browser.startup.homepage=http://www.mozilla.org/projects/shiretoko/
 
--- a/browser/branding/unofficial/locales/en-US/brand.dtd
+++ b/browser/branding/unofficial/locales/en-US/brand.dtd
@@ -1,6 +1,6 @@
-<!ENTITY  brandShortName        "Gran Paradiso">
-<!ENTITY  brandFullName         "Gran Paradiso">            
+<!ENTITY  brandShortName        "Shiretoko">
+<!ENTITY  brandFullName         "Shiretoko">
 <!ENTITY  vendorShortName       "mozilla.org">
 
 <!-- LOCALIZATION NOTE (releaseBaseURL): The about: page appends __MOZ_APP_VERSION__.html, e.g. 2.0.html -->
-<!ENTITY  releaseBaseURL        "http://www.mozilla.org/projects/granparadiso/releases/">
+<!ENTITY  releaseBaseURL        "http://www.mozilla.org/projects/shiretoko/releases/">
--- a/browser/branding/unofficial/locales/en-US/brand.properties
+++ b/browser/branding/unofficial/locales/en-US/brand.properties
@@ -1,3 +1,3 @@
-brandShortName=Gran Paradiso
-brandFullName=Gran Paradiso
+brandShortName=Shiretoko
+brandFullName=Shiretoko
 vendorShortName=mozilla.org
--- a/browser/branding/unofficial/locales/jar.mn
+++ b/browser/branding/unofficial/locales/jar.mn
@@ -1,7 +1,7 @@
 #filter substitution
 
 @AB_CD@.jar:
 % locale branding @AB_CD@ %locale/branding/
-# Gran Paradiso branding only exists in en-US
+# Unofficial branding only exists in en-US
   locale/branding/brand.dtd        (en-US/brand.dtd)
 * locale/branding/brand.properties (en-US/brand.properties)
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -65,16 +65,18 @@ mandir		= @mandir@
 idldir		= $(datadir)/idl/$(MOZ_APP_NAME)-$(MOZ_APP_VERSION)
 
 installdir	= $(libdir)/$(MOZ_APP_NAME)-$(MOZ_APP_VERSION)
 sdkdir		= $(libdir)/$(MOZ_APP_NAME)-devel-$(MOZ_APP_VERSION)
 
 DIST		= $(DEPTH)/dist
 LIBXUL_SDK      = @LIBXUL_SDK@
 
+L10NBASEDIR     = @L10NBASEDIR@
+
 ifdef LIBXUL_SDK
 LIBXUL_DIST = $(LIBXUL_SDK)
 else
 LIBXUL_DIST = $(DIST)
 endif
 
 XULRUNNER_STUB_NAME = @XULRUNNER_STUB_NAME@
 
--- a/config/config.mk
+++ b/config/config.mk
@@ -863,17 +863,21 @@ endif
 # Localization build automation
 #
 
 # Because you might wish to "make locales AB_CD=ab-CD", we don't hardcode
 # MOZ_UI_LOCALE directly, but use an intermediate variable that can be
 # overridden by the command line. (Besides, AB_CD is prettier).
 AB_CD = $(MOZ_UI_LOCALE)
 
-EXPAND_LOCALE_SRCDIR = $(if $(filter en-US,$(AB_CD)),$(topsrcdir)/$(1)/en-US,$(topsrcdir)/../l10n/$(AB_CD)/$(subst /locales,,$(1)))
+ifndef L10NBASEDIR
+L10NBASEDIR = $(error L10NBASEDIR not defined by configure)
+endif
+
+EXPAND_LOCALE_SRCDIR = $(if $(filter en-US,$(AB_CD)),$(topsrcdir)/$(1)/en-US,$(L10NBASEDIR)/$(AB_CD)/$(subst /locales,,$(1)))
 
 ifdef relativesrcdir
 LOCALE_SRCDIR = $(call EXPAND_LOCALE_SRCDIR,$(relativesrcdir))
 endif
 
 ifdef LOCALE_SRCDIR
 MAKE_JARS_FLAGS += -c $(LOCALE_SRCDIR)
 endif
--- a/config/system-headers
+++ b/config/system-headers
@@ -191,16 +191,17 @@ files.h
 Files.h
 FindDirectory.h
 Finder.h
 FinderRegistry.h
 FixMath.h
 float.h
 Folders.h
 fontconfig/fontconfig.h
+fontconfig/fcfreetype.h
 Font.h
 Fonts.h
 fp.h
 fpieee.h
 frame/log.h
 frame/req.h
 freetype/freetype.h
 freetype/ftcache.h
--- a/configure.in
+++ b/configure.in
@@ -202,16 +202,30 @@ fi
 
 COMPILE_ENVIRONMENT=1
 MOZ_ARG_ENABLE_BOOL(compile-environment,
 [  --disable-compile-environment
                            Disable compiler/library checks.],
     COMPILE_ENVIRONMENT=1,
     COMPILE_ENVIRONMENT= )
 
+MOZ_ARG_WITH_STRING(l10n-base,
+[  --with-l10nbase=DIR     path to l10n repositories],
+    L10NBASEDIR=$withval)
+if test ! -z "$L10NBASEDIR"; then
+    if test "$L10NBASEDIR" = "yes" -o "$L10NBASEDIR" = "no"; then
+        AC_MSG_ERROR([--with-l10n-base must specify a path])
+    elif test -d "$L10NBASEDIR"; then
+        L10NBASEDIR=`cd "$L10NBASEDIR" && pwd`
+    else
+        AC_MSG_ERROR([Invalid value --with-l10n-base, $L10NBASEDIR doesn't exist])
+    fi
+fi
+AC_SUBST(L10NBASEDIR)
+
 dnl ========================================================
 dnl Checks for compilers.
 dnl ========================================================
 dnl Set CROSS_COMPILE in the environment when running configure
 dnl to use the cross-compile setup for now
 dnl ========================================================
 
 if test "$COMPILE_ENVIRONMENT"; then
--- a/content/base/public/nsIContent.h
+++ b/content/base/public/nsIContent.h
@@ -141,17 +141,17 @@ public:
     return GetCurrentDoc();
   }
 
   /**
    * Get whether this content is C++-generated anonymous content
    * @see nsIAnonymousContentCreator
    * @return whether this content is anonymous
    */
-  PRBool IsNativeAnonymous() const
+  PRBool IsRootOfNativeAnonymousSubtree() const
   {
     return HasFlag(NODE_IS_ANONYMOUS);
   }
 
   /**
    * Makes this content anonymous
    * @see nsIAnonymousContentCreator
    */
@@ -172,29 +172,54 @@ public:
   PRBool IsInNativeAnonymousSubtree() const
   {
 #ifdef DEBUG
     if (HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE)) {
       return PR_TRUE;
     }
     nsIContent* content = GetBindingParent();
     while (content) {
-      if (content->IsNativeAnonymous()) {
+      if (content->IsRootOfNativeAnonymousSubtree()) {
         NS_ERROR("Element not marked to be in native anonymous subtree!");
         break;
       }
       content = content->GetBindingParent();
     }
     return PR_FALSE;
 #else
     return HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE);
 #endif
   }
 
   /**
+   * Returns true if and only if this node has a parent, but is not in
+   * its parent's child list.
+   */
+  PRBool IsRootOfAnonymousSubtree() const
+  {
+    NS_ASSERTION(!IsRootOfNativeAnonymousSubtree() ||
+                 (GetParent() && GetBindingParent() == GetParent()),
+                 "root of native anonymous subtree must have parent equal "
+                 "to binding parent");
+    nsIContent *bindingParent = GetBindingParent();
+    return bindingParent && bindingParent == GetParent();
+  }
+
+  /**
+   * Returns true if and only if there is NOT a path through child lists
+   * from the top of this node's parent chain back to this node.
+   */
+  PRBool IsInAnonymousSubtree() const
+  {
+    NS_ASSERTION(!IsInNativeAnonymousSubtree() || GetBindingParent(),
+                 "must have binding parent when in native anonymous subtree");
+    return GetBindingParent() != nsnull;
+  }
+
+  /**
    * Get the namespace that this element's tag is defined in
    * @return the namespace
    */
   PRInt32 GetNameSpaceID() const
   {
     return mNodeInfo->NamespaceID();
   }
 
@@ -558,19 +583,22 @@ public:
       editableAncestor = parent;
     // This is in another editable content, use the result of it.
     if (editableAncestor)
       return editableAncestor->GetDesiredIMEState();
     return IME_STATUS_ENABLE;
   }
 
   /**
-   * Gets content node with the binding responsible for our construction (and
-   * existence).  Used by anonymous content (XBL-generated). null for all
-   * explicit content.
+   * Gets content node with the binding (or native code, possibly on the
+   * frame) responsible for our construction (and existence).  Used by
+   * anonymous content (both XBL-generated and native-anonymous).
+   *
+   * null for all explicit content (i.e., content reachable from the top
+   * of its GetParent() chain via child lists).
    *
    * @return the binding parent
    */
   virtual nsIContent *GetBindingParent() const = 0;
 
   /**
    * Get the base URI for any relative URIs within this piece of
    * content. Generally, this is the document's base URI, but certain
--- a/content/base/public/nsIMutationObserver.h
+++ b/content/base/public/nsIMutationObserver.h
@@ -44,24 +44,52 @@ class nsIContent;
 class nsIDocument;
 class nsINode;
 
 #define NS_IMUTATION_OBSERVER_IID \
 { 0x32e68316, 0x67d4, 0x44a5, \
  { 0x8d, 0x35, 0xd, 0x39, 0xf, 0xa9, 0xdf, 0x11 } }
 
 /**
- * Information details about a characterdata change
+ * Information details about a characterdata change.  Basically, we
+ * view all changes as replacements of a length of text at some offset
+ * with some other text (of possibly some other length).
  */
 struct CharacterDataChangeInfo
 {
+  /**
+   * True if this character data change is just an append.
+   */
   PRBool mAppend;
+
+  /**
+   * The offset in the text where the change occurred.
+   */
   PRUint32 mChangeStart;
+
+  /**
+   * The offset such that mChangeEnd - mChangeStart is equal to the length of
+   * the text we removed. If this was a pure insert or append, this is equal to
+   * mChangeStart.
+   */
   PRUint32 mChangeEnd;
+
+  /**
+   * The length of the text that was inserted in place of the removed text.  If
+   * this was a pure text removal, this is 0.
+   */
   PRUint32 mReplaceLength;
+
+  /**
+   * The net result is that mChangeStart characters at the beginning of the
+   * text remained as they were.  The next mChangeEnd - mChangeStart characters
+   * were removed, and mReplaceLength characters were inserted in their place.
+   * The text that used to begin at mChangeEnd now begins at
+   * mChangeStart + mReplaceLength.
+   */
 };
 
 /**
  * Mutation observer interface
  *
  * WARNING: During these notifications, you are not allowed to perform
  * any mutations to the current or any other document, or start a
  * network load.  If you need to perform such operations do that
--- a/content/base/src/Makefile.in
+++ b/content/base/src/Makefile.in
@@ -141,16 +141,17 @@ CPPSRCS		= \
 		nsLineBreaker.cpp \
 		nsLoadListenerProxy.cpp \
 		nsMappedAttributeElement.cpp \
 		nsMappedAttributes.cpp \
 		nsNameSpaceManager.cpp \
 		nsNoDataProtocolContentPolicy.cpp \
 		nsNodeInfo.cpp \
 		nsNodeInfoManager.cpp \
+		nsNodeIterator.cpp \
 		nsNodeUtils.cpp \
 		nsObjectLoadingContent.cpp \
 		nsParserUtils.cpp \
 		nsPlainTextSerializer.cpp \
 		nsPropertyTable.cpp \
 		nsRange.cpp \
 		nsReferencedElement.cpp \
 		nsScriptElement.cpp \
@@ -159,16 +160,17 @@ CPPSRCS		= \
 		nsStubDocumentObserver.cpp \
 		nsStubImageDecoderObserver.cpp \
 		nsStubMutationObserver.cpp \
 		nsStyledElement.cpp \
 		nsStyleLinkElement.cpp \
 		nsSyncLoadService.cpp \
 		nsTextFragment.cpp \
 		nsTextNode.cpp \
+		nsTraversal.cpp \
 		nsTreeWalker.cpp \
 		nsXMLContentSerializer.cpp \
 		nsXMLHttpRequest.cpp \
 		nsXMLNameSpaceMap.cpp \
 		$(NULL)
 
 GQI_SRCS = contentbase.gqi
 
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -1885,17 +1885,17 @@ nsContentUtils::GenerateStateKey(nsICont
     KeyAppendInt(aID, aKey);
     return NS_OK;
   }
 
   // We must have content if we're not using a special state id
   NS_ENSURE_TRUE(aContent, NS_ERROR_FAILURE);
 
   // Don't capture state for anonymous content
-  if (aContent->IsNativeAnonymous() || aContent->GetBindingParent()) {
+  if (aContent->IsInAnonymousSubtree()) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIDOMElement> element(do_QueryInterface(aContent));
   if (element && IsAutocompleteOff(element)) {
     return NS_OK;
   }
 
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -80,16 +80,17 @@
 #include "nsNodeUtils.h"
 #include "nsLayoutUtils.h" // for GetFrameForPoint
 #include "nsIFrame.h"
 
 #include "nsRange.h"
 #include "nsIDOMText.h"
 #include "nsIDOMComment.h"
 #include "nsDOMDocumentType.h"
+#include "nsNodeIterator.h"
 #include "nsTreeWalker.h"
 
 #include "nsIServiceManager.h"
 
 #include "nsContentCID.h"
 #include "nsDOMError.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
@@ -1136,16 +1137,17 @@ NS_INTERFACE_TABLE_HEAD(nsDocument)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMNSEventTarget)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMNode)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsPIDOMEventTarget)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOM3Node)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOM3Document)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsISupportsWeakReference)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIRadioGroupContainer)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIMutationObserver)
+    NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMNodeSelector)
     // nsNodeSH::PreCreate() depends on the identity pointer being the
     // same as nsINode (which nsIDocument inherits), so if you change
     // the below line, make sure nsNodeSH::PreCreate() still does the
     // right thing!
     NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(nsDocument, nsISupports, nsIDocument)
   NS_INTERFACE_TABLE_END
   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsDocument)
   if (aIID.Equals(NS_GET_IID(nsIDOMXPathEvaluator)) ||
@@ -2138,18 +2140,18 @@ nsDocument::ElementFromPoint(PRInt32 aX,
     return NS_OK;
   }
 
   // If we have an anonymous element (such as an internal div from a textbox),
   // or a node that isn't an element (such as a text frame node),
   // replace it with the first non-anonymous parent node of type element.
   while (ptContent &&
          !ptContent->IsNodeOfType(nsINode::eELEMENT) ||
-         ptContent->GetBindingParent() ||
-         ptContent->IsNativeAnonymous()) {
+         ptContent->IsInAnonymousSubtree()) {
+    // XXXldb: Faster to jump to GetBindingParent if non-null?
     ptContent = ptContent->GetParent();
   }
  
   if (ptContent)
     CallQueryInterface(ptContent, aReturn);
   return NS_OK;
 }
 
@@ -4196,39 +4198,69 @@ nsDocument::CreateRange(nsIDOMRange** aR
 
 NS_IMETHODIMP
 nsDocument::CreateNodeIterator(nsIDOMNode *aRoot,
                                PRUint32 aWhatToShow,
                                nsIDOMNodeFilter *aFilter,
                                PRBool aEntityReferenceExpansion,
                                nsIDOMNodeIterator **_retval)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  *_retval = nsnull;
+
+  if (!aRoot)
+    return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+
+  nsresult rv = nsContentUtils::CheckSameOrigin(this, aRoot);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  NS_ENSURE_ARG_POINTER(_retval);
+
+  nsCOMPtr<nsINode> root = do_QueryInterface(aRoot);
+  NS_ENSURE_TRUE(root, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+
+  nsNodeIterator *iterator = new nsNodeIterator(root,
+                                                aWhatToShow,
+                                                aFilter,
+                                                aEntityReferenceExpansion);
+  NS_ENSURE_TRUE(iterator, NS_ERROR_OUT_OF_MEMORY);
+
+  NS_ADDREF(*_retval = iterator);
+
+  return NS_OK; 
 }
 
 NS_IMETHODIMP
 nsDocument::CreateTreeWalker(nsIDOMNode *aRoot,
                              PRUint32 aWhatToShow,
                              nsIDOMNodeFilter *aFilter,
                              PRBool aEntityReferenceExpansion,
                              nsIDOMTreeWalker **_retval)
 {
   *_retval = nsnull;
 
-  if (!aRoot) {
+  if (!aRoot)
     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
-  }
 
   nsresult rv = nsContentUtils::CheckSameOrigin(this, aRoot);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  return NS_NewTreeWalker(aRoot, aWhatToShow, aFilter,
-                          aEntityReferenceExpansion, _retval);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  NS_ENSURE_ARG_POINTER(_retval);
+
+  nsCOMPtr<nsINode> root = do_QueryInterface(aRoot);
+  NS_ENSURE_TRUE(root, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+
+  nsTreeWalker* walker = new nsTreeWalker(root,
+                                          aWhatToShow,
+                                          aFilter,
+                                          aEntityReferenceExpansion);
+  NS_ENSURE_TRUE(walker, NS_ERROR_OUT_OF_MEMORY);
+
+  NS_ADDREF(*_retval = walker);
+
+  return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsDocument::GetDefaultView(nsIDOMAbstractView** aDefaultView)
 {
   nsPIDOMWindow* win = GetWindow();
   if (win) {
@@ -6593,8 +6625,22 @@ nsDocument::GetScriptTypeID(PRUint32 *aS
 }
 
 NS_IMETHODIMP
 nsDocument::SetScriptTypeID(PRUint32 aScriptType)
 {
     NS_ERROR("Can't change default script type for a document");
     return NS_ERROR_NOT_IMPLEMENTED;
 }
+
+NS_IMETHODIMP
+nsDocument::QuerySelector(const nsAString& aSelector,
+                          nsIDOMElement **aReturn)
+{
+  return nsGenericElement::doQuerySelector(this, aSelector, aReturn);
+}
+
+NS_IMETHODIMP
+nsDocument::QuerySelectorAll(const nsAString& aSelector,
+                             nsIDOMNodeList **aReturn)
+{
+  return nsGenericElement::doQuerySelectorAll(this, aSelector, aReturn);
+}
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -62,16 +62,17 @@
 #include "nsIDOM3EventTarget.h"
 #include "nsIDOMNSEventTarget.h"
 #include "nsIDOMStyleSheetList.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIContent.h"
 #include "nsIEventListenerManager.h"
 #include "nsIDOM3Node.h"
+#include "nsIDOMNodeSelector.h"
 #include "nsIPrincipal.h"
 #include "nsIParser.h"
 #include "nsBindingManager.h"
 #include "nsINodeInfo.h"
 #include "nsIDOMDocumentEvent.h"
 #include "nsIDOM3DocumentEvent.h"
 #include "nsHashtable.h"
 #include "nsInterfaceHashtable.h"
@@ -399,16 +400,17 @@ class nsDocument : public nsIDocument,
                    public nsIDOMDocumentXBL,
                    public nsIDOM3Document,
                    public nsSupportsWeakReference,
                    public nsIDOMEventTarget,
                    public nsIDOM3EventTarget,
                    public nsIDOMNSEventTarget,
                    public nsIScriptObjectPrincipal,
                    public nsIRadioGroupContainer,
+                   public nsIDOMNodeSelector,
                    public nsStubMutationObserver
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   virtual void Reset(nsIChannel *aChannel, nsILoadGroup *aLoadGroup);
   virtual void ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
                           nsIPrincipal* aPrincipal);
@@ -729,16 +731,19 @@ public:
   NS_DECL_NSIDOMEVENTTARGET
 
   // nsIDOM3EventTarget
   NS_DECL_NSIDOM3EVENTTARGET
 
   // nsIDOMNSEventTarget
   NS_DECL_NSIDOMNSEVENTTARGET
 
+  // nsIDOMNodeSelector
+  NS_DECL_NSIDOMNODESELECTOR
+
   // nsIMutationObserver
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
 
   // nsIScriptObjectPrincipal
   virtual nsIPrincipal* GetPrincipal();
--- a/content/base/src/nsGenericDOMDataNode.cpp
+++ b/content/base/src/nsGenericDOMDataNode.cpp
@@ -587,36 +587,40 @@ nsGenericDOMDataNode::BindToTree(nsIDocu
   // only assert if our parent is _changing_ while we have a parent.
   NS_PRECONDITION(!GetParent() || aParent == GetParent(),
                   "Already have a parent.  Unbind first!");
   NS_PRECONDITION(!GetBindingParent() ||
                   aBindingParent == GetBindingParent() ||
                   (!aBindingParent && aParent &&
                    aParent->GetBindingParent() == GetBindingParent()),
                   "Already have a binding parent.  Unbind first!");
-  NS_PRECONDITION(aBindingParent != this || IsNativeAnonymous(),
-                  "Only native anonymous content should have itself as its "
+  NS_PRECONDITION(aBindingParent != this,
+                  "Content must not be its own binding parent");
+  NS_PRECONDITION(!IsRootOfNativeAnonymousSubtree() || 
+                  aBindingParent == aParent,
+                  "Native anonymous content must have its parent as its "
                   "own binding parent");
 
   if (!aBindingParent && aParent) {
     aBindingParent = aParent->GetBindingParent();
   }
 
   // First set the binding parent
   if (aBindingParent) {
     nsDataSlots *slots = GetDataSlots();
     NS_ENSURE_TRUE(slots, NS_ERROR_OUT_OF_MEMORY);
 
-    NS_ASSERTION(IsNativeAnonymous() || !HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE) ||
+    NS_ASSERTION(IsRootOfNativeAnonymousSubtree() ||
+                 !HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE) ||
                  aBindingParent->IsInNativeAnonymousSubtree(),
                  "Trying to re-bind content from native anonymous subtree to"
                  "non-native anonymous parent!");
     slots->mBindingParent = aBindingParent; // Weak, so no addref happens.
-    if (IsNativeAnonymous() ||
-        aBindingParent->IsInNativeAnonymousSubtree()) {
+    if (IsRootOfNativeAnonymousSubtree() ||
+        aParent->IsInNativeAnonymousSubtree()) {
       SetFlags(NODE_IS_IN_ANONYMOUS_SUBTREE);
     }
   }
 
   // Set parent
   if (aParent) {
     mParentPtrBits =
       reinterpret_cast<PtrBits>(aParent) | PARENT_BIT_PARENT_IS_CONTENT;
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -121,16 +121,19 @@
 #include "nsIDOMNSEditableElement.h"
 #include "nsIEditor.h"
 #include "nsIEditorDocShell.h"
 #include "nsEventDispatcher.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsIFocusController.h"
 #include "nsIControllers.h"
 #include "nsXBLInsertionPoint.h"
+#include "nsICSSStyleRule.h" /* For nsCSSSelectorList */
+#include "nsCSSRuleProcessor.h"
+
 #ifdef MOZ_XUL
 #include "nsIXULDocument.h"
 #endif /* MOZ_XUL */
 
 #ifdef ACCESSIBILITY
 #include "nsIAccessibilityService.h"
 #include "nsIAccessibleEvent.h"
 #endif /* ACCESSIBILITY */
@@ -427,28 +430,25 @@ nsIContent::UpdateEditableState()
 
   SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE));
 }
 
 nsIContent*
 nsIContent::FindFirstNonNativeAnonymous() const
 {
   // This handles also nested native anonymous content.
-  nsIContent* content = GetBindingParent();
-  nsIContent* possibleResult = 
-    !IsNativeAnonymous() ? const_cast<nsIContent*>(this) : nsnull;
-  while (content) {
-    if (content->IsNativeAnonymous()) {
-      content = possibleResult = content->GetParent();
-    } else {
-      content = content->GetBindingParent();
+  for (const nsIContent *content = this; content;
+       content = content->GetBindingParent()) {
+    if (!content->IsInNativeAnonymousSubtree()) {
+      // Oops, this function signature allows casting const to
+      // non-const.  (Then again, so does GetChildAt(0)->GetParent().)
+      return const_cast<nsIContent*>(content);
     }
   }
-
-  return possibleResult;
+  return nsnull;
 }
 
 //----------------------------------------------------------------------
 
 nsChildContentList::~nsChildContentList()
 {
   MOZ_COUNT_DTOR(nsChildContentList);
 }
@@ -1152,16 +1152,78 @@ nsDOMEventRTTearoff::AddEventListener(co
   }
 
   return listener_manager->AddEventListenerByType(aListener, aType, flags,
                                                   nsnull);
 }
 
 //----------------------------------------------------------------------
 
+NS_IMPL_CYCLE_COLLECTION_1(nsNodeSelectorTearoff, mContent)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsNodeSelectorTearoff)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMNodeSelector)
+NS_INTERFACE_MAP_END_AGGREGATED(mContent)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsNodeSelectorTearoff)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsNodeSelectorTearoff)
+
+NS_IMETHODIMP
+nsNodeSelectorTearoff::QuerySelector(const nsAString& aSelector,
+                                     nsIDOMElement **aReturn)
+{
+  return nsGenericElement::doQuerySelector(mContent, aSelector, aReturn);
+}
+
+NS_IMETHODIMP
+nsNodeSelectorTearoff::QuerySelectorAll(const nsAString& aSelector,
+                                        nsIDOMNodeList **aReturn)
+{
+  return nsGenericElement::doQuerySelectorAll(mContent, aSelector, aReturn);
+}
+
+//----------------------------------------------------------------------
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsStaticContentList)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsStaticContentList)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mList)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsStaticContentList)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mList)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsStaticContentList)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsStaticContentList)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsStaticContentList)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMNodeList)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(NodeList)
+NS_INTERFACE_MAP_END
+
+NS_IMETHODIMP
+nsStaticContentList::GetLength(PRUint32* aLength)
+{
+  *aLength = mList.Count();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsStaticContentList::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
+{
+  nsIContent* c = mList.SafeObjectAt(aIndex);
+  if (!c) {
+    *aReturn = nsnull;
+    return NS_OK;
+  }
+
+  return CallQueryInterface(c, aReturn);
+}
+
+//----------------------------------------------------------------------
+
 PRUint32 nsMutationGuard::sMutationCount = 0;
 
 nsGenericElement::nsDOMSlots::nsDOMSlots(PtrBits aFlags)
   : nsINode::nsSlots(aFlags),
     mBindingParent(nsnull)
 {
 }
 
@@ -2021,21 +2083,21 @@ nsGenericElement::BindToTree(nsIDocument
   NS_PRECONDITION(!GetBindingParent() ||
                   aBindingParent == GetBindingParent() ||
                   (!aBindingParent && aParent &&
                    aParent->GetBindingParent() == GetBindingParent()),
                   "Already have a binding parent.  Unbind first!");
   NS_PRECONDITION(!aParent || !aDocument ||
                   !aParent->HasFlag(NODE_FORCE_XBL_BINDINGS),
                   "Parent in document but flagged as forcing XBL");
-  NS_PRECONDITION(aBindingParent != this || IsNativeAnonymous(),
-                  "Only native anonymous content should have itself as its "
-                  "own binding parent");
-  NS_PRECONDITION(!IsNativeAnonymous() || aBindingParent == this,
-                  "Native anonymous content must have itself as its "
+  NS_PRECONDITION(aBindingParent != this,
+                  "Content must not be its own binding parent");
+  NS_PRECONDITION(!IsRootOfNativeAnonymousSubtree() ||
+                  aBindingParent == aParent,
+                  "Native anonymous content must have its parent as its "
                   "own binding parent");
 
   if (!aBindingParent && aParent) {
     aBindingParent = aParent->GetBindingParent();
   }
 
 #ifdef MOZ_XUL
   // First set the binding parent
@@ -2051,23 +2113,23 @@ nsGenericElement::BindToTree(nsIDocument
 
       if (!slots) {
         return NS_ERROR_OUT_OF_MEMORY;
       }
 
       slots->mBindingParent = aBindingParent; // Weak, so no addref happens.
     }
   }
-  NS_ASSERTION(!aBindingParent || IsNativeAnonymous() ||
+  NS_ASSERTION(!aBindingParent || IsRootOfNativeAnonymousSubtree() ||
                !HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE) ||
                aBindingParent->IsInNativeAnonymousSubtree(),
                "Trying to re-bind content from native anonymous subtree to"
                "non-native anonymous parent!");
-  if (IsNativeAnonymous() ||
-      aBindingParent && aBindingParent->IsInNativeAnonymousSubtree()) {
+  if (IsRootOfNativeAnonymousSubtree() ||
+      aParent && aParent->IsInNativeAnonymousSubtree()) {
     SetFlags(NODE_IS_IN_ANONYMOUS_SUBTREE);
   }
 
   PRBool hadForceXBL = HasFlag(NODE_FORCE_XBL_BINDINGS);
 
   // Now set the parent and set the "Force attach xbl" flag if needed.
   if (aParent) {
     mParentPtrBits = reinterpret_cast<PtrBits>(aParent) | PARENT_BIT_PARENT_IS_CONTENT;
@@ -2232,33 +2294,33 @@ nsGenericElement::PreHandleEvent(nsEvent
 }
 
 static nsIContent*
 FindNativeAnonymousSubtreeOwner(nsIContent* aContent)
 {
   if (aContent->IsInNativeAnonymousSubtree()) {
     PRBool isNativeAnon = PR_FALSE;
     while (aContent && !isNativeAnon) {
-      isNativeAnon = aContent->IsNativeAnonymous();
+      isNativeAnon = aContent->IsRootOfNativeAnonymousSubtree();
       aContent = aContent->GetParent();
     }
   }
   return aContent;
 }
 
 nsresult
 nsGenericElement::doPreHandleEvent(nsIContent* aContent,
                                    nsEventChainPreVisitor& aVisitor)
 {
   //FIXME! Document how this event retargeting works, Bug 329124.
   aVisitor.mCanHandle = PR_TRUE;
 
   // Don't propagate mouseover and mouseout events when mouse is moving
   // inside native anonymous content.
-  PRBool isAnonForEvents = aContent->IsNativeAnonymous();
+  PRBool isAnonForEvents = aContent->IsRootOfNativeAnonymousSubtree();
   if ((aVisitor.mEvent->message == NS_MOUSE_ENTER_SYNTH ||
        aVisitor.mEvent->message == NS_MOUSE_EXIT_SYNTH) &&
       // This is an optimization - try to stop event propagation when
       // event has just possibly been retargeted.
       static_cast<nsISupports*>(aContent) == aVisitor.mEvent->target) {
      nsCOMPtr<nsIContent> relatedTarget =
        do_QueryInterface(static_cast<nsMouseEvent*>
                                     (aVisitor.mEvent)->relatedTarget);
@@ -3578,16 +3640,18 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMEventTarget,
                                  nsDOMEventRTTearoff::Create(this))
   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOM3EventTarget,
                                  nsDOMEventRTTearoff::Create(this))
   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMNSEventTarget,
                                  nsDOMEventRTTearoff::Create(this))
   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference,
                                  new nsNodeSupportsWeakRefTearoff(this))
+  NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMNodeSelector,
+                                 new nsNodeSelectorTearoff(this))
   // nsNodeSH::PreCreate() depends on the identity pointer being the
   // same as nsINode (which nsIContent inherits), so if you change the
   // below line, make sure nsNodeSH::PreCreate() still does the right
   // thing!
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsGenericElement, nsIContent)
@@ -4524,8 +4588,203 @@ nsGenericElement::PostHandleEventForLink
 }
 
 void
 nsGenericElement::GetLinkTarget(nsAString& aTarget)
 {
   aTarget.Truncate();
 }
 
+// NOTE: The aPresContext pointer is NOT addrefed.
+static nsresult
+ParseSelectorList(nsINode* aNode,
+                  const nsAString& aSelectorString,
+                  nsCSSSelectorList** aSelectorList,
+                  nsPresContext** aPresContext)
+{
+  NS_ENSURE_ARG(aNode);
+
+  nsIDocument* doc = aNode->GetOwnerDoc();
+  NS_ENSURE_STATE(doc);
+
+  nsCOMPtr<nsICSSParser> parser;
+  nsresult rv = doc->CSSLoader()->GetParserFor(nsnull, getter_AddRefs(parser));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = parser->ParseSelectorString(aSelectorString,
+                                   doc->GetDocumentURI(),
+                                   0, // XXXbz get the right line number!
+                                   aSelectorList);
+  doc->CSSLoader()->RecycleParser(parser);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // It's not strictly necessary to have a prescontext here, but it's
+  // a bit of an optimization for various stuff.
+  *aPresContext = nsnull;
+  nsIPresShell* shell = doc->GetPrimaryShell();
+  if (shell) {
+    *aPresContext = shell->GetPresContext();
+  }
+
+  return NS_OK;
+}
+
+/*
+ * Callback to be called as we iterate over the tree and match elements.  If
+ * the callbacks returns false, the iteration should be stopped.
+ */
+typedef PRBool
+(* PR_CALLBACK ElementMatchedCallback)(nsIContent* aMatchingElement,
+                                       void* aClosure);
+
+// returning false means stop iteration
+static PRBool
+TryMatchingElementsInSubtree(nsINode* aRoot,
+                             RuleProcessorData* aParentData,
+                             nsPresContext* aPresContext,
+                             nsCSSSelectorList* aSelectorList,
+                             ElementMatchedCallback aCallback,
+                             void* aClosure)
+{
+  PRUint32 count = aRoot->GetChildCount();
+  /* To improve the performance of '+' and '~' combinators and the :nth-*
+   * selectors, we keep track of the immediately previous sibling data.  That's
+   * cheaper than heap-allocating all the datas and keeping track of them all,
+   * and helps a good bit in the common cases.  We also keep track of the whole
+   * parent data chain, since we have those Around anyway */
+  char databuf[2 * sizeof(RuleProcessorData)];
+  RuleProcessorData* prevSibling = nsnull;
+  RuleProcessorData* data = reinterpret_cast<RuleProcessorData*>(databuf);
+  nsIContent * const * kidSlot = aRoot->GetChildArray();
+  nsIContent * const * end = kidSlot + count;
+
+  PRBool continueIteration = PR_TRUE;
+  for (; kidSlot != end; ++kidSlot) {
+    nsIContent* kid = *kidSlot;
+    if (!kid->IsNodeOfType(nsINode::eELEMENT)) {
+      continue;
+    }
+    /* See whether we match */
+    new (data) RuleProcessorData(aPresContext, kid, nsnull);
+    NS_ASSERTION(!data->mParentData, "Shouldn't happen");
+    NS_ASSERTION(!data->mPreviousSiblingData, "Shouldn't happen");
+    data->mParentData = aParentData;
+    data->mPreviousSiblingData = prevSibling;
+
+    if (nsCSSRuleProcessor::SelectorListMatches(*data, aSelectorList)) {
+      continueIteration = (*aCallback)(kid, aClosure);
+    }
+
+    if (continueIteration) {
+      continueIteration =
+        TryMatchingElementsInSubtree(kid, data, aPresContext, aSelectorList,
+                                     aCallback, aClosure);
+    }
+    
+    /* Clear out the parent and previous sibling data if we set them, so that
+     * ~RuleProcessorData won't try to delete a placement-new'd object. Make
+     * sure this happens before our possible early break.  Note that we can
+     * have null aParentData but non-null data->mParentData if we're scoped to
+     * an element.  However, prevSibling and data->mPreviousSiblingData must
+     * always match.
+     */
+    NS_ASSERTION(!aParentData || data->mParentData == aParentData,
+                 "Unexpected parent");
+    NS_ASSERTION(data->mPreviousSiblingData == prevSibling,
+                 "Unexpected prev sibling");
+    data->mPreviousSiblingData = nsnull;
+    if (prevSibling) {
+      if (aParentData) {
+        prevSibling->mParentData = nsnull;
+      }
+      prevSibling->~RuleProcessorData();
+    } else {
+      /* This is the first time through, so point |prevSibling| to the location
+         we want to have |data| end up pointing to. */
+      prevSibling = data + 1;
+    }
+
+    /* Now swap |prevSibling| and |data|.  Again, before the early break */
+    RuleProcessorData* temp = prevSibling;
+    prevSibling = data;
+    data = temp;
+    if (!continueIteration) {
+      break;
+    }
+  }
+  if (prevSibling) {
+    if (aParentData) {
+      prevSibling->mParentData = nsnull;
+    }
+    /* Make sure to clean this up */
+    prevSibling->~RuleProcessorData();
+  }
+  return continueIteration;
+}
+
+PR_STATIC_CALLBACK(PRBool)
+FindFirstMatchingElement(nsIContent* aMatchingElement,
+                         void* aClosure)
+{
+  NS_PRECONDITION(aMatchingElement && aClosure, "How did that happen?");
+  nsIContent** slot = static_cast<nsIContent**>(aClosure);
+  *slot = aMatchingElement;
+  return PR_FALSE;
+}
+
+/* static */
+nsresult
+nsGenericElement::doQuerySelector(nsINode* aRoot, const nsAString& aSelector,
+                                  nsIDOMElement **aReturn)
+{
+  NS_PRECONDITION(aReturn, "Null out param?");
+
+  nsAutoPtr<nsCSSSelectorList> selectorList;
+  nsPresContext* presContext;
+  nsresult rv = ParseSelectorList(aRoot, aSelector,
+                                  getter_Transfers(selectorList),
+                                  &presContext);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsIContent* foundElement = nsnull;
+  TryMatchingElementsInSubtree(aRoot, nsnull, presContext, selectorList,
+                               FindFirstMatchingElement, &foundElement);
+
+  if (foundElement) {
+    return CallQueryInterface(foundElement, aReturn);
+  }
+
+  *aReturn = nsnull;
+  return NS_OK;
+}
+
+PR_STATIC_CALLBACK(PRBool)
+AppendAllMatchingElements(nsIContent* aMatchingElement,
+                          void* aClosure)
+{
+  NS_PRECONDITION(aMatchingElement && aClosure, "How did that happen?");
+  static_cast<nsStaticContentList*>(aClosure)->AppendContent(aMatchingElement);
+  return PR_TRUE;
+}
+
+/* static */
+nsresult
+nsGenericElement::doQuerySelectorAll(nsINode* aRoot,
+                                     const nsAString& aSelector,
+                                     nsIDOMNodeList **aReturn)
+{
+  NS_PRECONDITION(aReturn, "Null out param?");
+
+  nsStaticContentList* contentList = new nsStaticContentList();
+  NS_ENSURE_TRUE(contentList, NS_ERROR_OUT_OF_MEMORY);
+  NS_ADDREF(*aReturn = contentList);
+  
+  nsAutoPtr<nsCSSSelectorList> selectorList;
+  nsPresContext* presContext;
+  nsresult rv = ParseSelectorList(aRoot, aSelector,
+                                  getter_Transfers(selectorList),
+                                  &presContext);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  TryMatchingElementsInSubtree(aRoot, nsnull, presContext, selectorList,
+                               AppendAllMatchingElements, contentList);
+  return NS_OK;
+}
--- a/content/base/src/nsGenericElement.h
+++ b/content/base/src/nsGenericElement.h
@@ -59,16 +59,17 @@
 #include "nsContentUtils.h"
 #include "nsNodeUtils.h"
 #include "nsAttrAndChildArray.h"
 #include "mozFlushType.h"
 #include "nsDOMAttributeMap.h"
 #include "nsIWeakReference.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIDocument.h"
+#include "nsIDOMNodeSelector.h"
 
 class nsIDOMAttr;
 class nsIDOMEventListener;
 class nsIFrame;
 class nsIDOMNamedNodeMap;
 class nsDOMCSSDeclaration;
 class nsIDOMCSSStyleDeclaration;
 class nsIURI;
@@ -264,16 +265,61 @@ private:
   /**
    * Strong reference back to the content object from where an instance of this
    * class was 'torn off'
    */
   nsCOMPtr<nsIContent> mContent;
 };
 
 /**
+ * A tearoff class for nsGenericElement to implement NodeSelector
+ */
+class nsNodeSelectorTearoff : public nsIDOMNodeSelector
+{
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+
+  NS_DECL_NSIDOMNODESELECTOR
+
+  NS_DECL_CYCLE_COLLECTION_CLASS(nsNodeSelectorTearoff)
+
+  nsNodeSelectorTearoff(nsIContent *aContent) : mContent(aContent)
+  {
+  }
+
+private:
+  ~nsNodeSelectorTearoff() {}
+
+private:
+  nsCOMPtr<nsIContent> mContent;
+};
+
+/**
+ * A static NodeList class, which just holds a COMArray of nodes
+ */
+class nsStaticContentList : public nsIDOMNodeList {
+public:
+  nsStaticContentList() {}
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_NSIDOMNODELIST
+
+  NS_DECL_CYCLE_COLLECTION_CLASS(nsStaticContentList)
+
+  PRBool AppendContent(nsIContent* aContent) {
+    return mList.AppendObject(aContent);
+  }
+
+private:
+  ~nsStaticContentList() {}
+  
+  nsCOMArray<nsIContent> mList;
+};
+
+/**
  * Class used to detect unexpected mutations. To use the class create an
  * nsMutationGuard on the stack before unexpected mutations could occur.
  * You can then at any time call Mutated to check if any unexpected mutations
  * have occured.
  *
  * When a guard is instantiated sMutationCount is set to 300. It is then
  * decremented by every mutation (capped at 0). This means that we can only
  * detect 300 mutations during the lifetime of a single guard, however that
@@ -667,16 +713,25 @@ public:
    * @param aChildArray The child array to work with
    */
   static nsresult doRemoveChildAt(PRUint32 aIndex, PRBool aNotify,
                                   nsIContent* aKid, nsIContent* aParent,
                                   nsIDocument* aDocument,
                                   nsAttrAndChildArray& aChildArray);
 
   /**
+   * Helper methods for implementing querySelector/querySelectorAll
+   */
+  static nsresult doQuerySelector(nsINode* aRoot, const nsAString& aSelector,
+                                  nsIDOMElement **aReturn);
+  static nsresult doQuerySelectorAll(nsINode* aRoot,
+                                     const nsAString& aSelector,
+                                     nsIDOMNodeList **aReturn);
+
+  /**
    * Default event prehandling for content objects. Handles event retargeting.
    */
   static nsresult doPreHandleEvent(nsIContent* aContent,
                                    nsEventChainPreVisitor& aVisitor);
 
   /**
    * Method to create and dispatch a left-click event loosely based on
    * aSourceEvent. If aFullDispatch is true, the event will be dispatched
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -490,16 +490,17 @@ GK_ATOM(ltr, "ltr")
 GK_ATOM(map, "map")
 GK_ATOM(manifest, "manifest")
 GK_ATOM(marginheight, "marginheight")
 GK_ATOM(marginwidth, "marginwidth")
 GK_ATOM(marquee, "marquee")
 GK_ATOM(match, "match")
 GK_ATOM(max, "max")
 GK_ATOM(maxheight, "maxheight")
+GK_ATOM(maximum_scale, "maximum-scale")
 GK_ATOM(maxlength, "maxlength")
 GK_ATOM(maxpos, "maxpos")
 GK_ATOM(maxwidth, "maxwidth")
 GK_ATOM(mayscript, "mayscript")
 GK_ATOM(media, "media")
 GK_ATOM(mediaType, "media-type")
 GK_ATOM(member, "member")
 GK_ATOM(menu, "menu")
@@ -1310,17 +1311,16 @@ GK_ATOM(lt_, "lt")
 GK_ATOM(maction_, "maction")
 GK_ATOM(maligngroup_, "maligngroup")
 GK_ATOM(malignmark_, "malignmark")
 GK_ATOM(mathbackground_, "mathbackground")
 GK_ATOM(mathcolor_, "mathcolor")
 GK_ATOM(mathsize_, "mathsize")
 GK_ATOM(mathvariant_, "mathvariant")
 GK_ATOM(matrixrow_, "matrixrow")
-GK_ATOM(maximum_scale, "maximum-scale")
 GK_ATOM(maxsize_, "maxsize")
 GK_ATOM(mean_, "mean")
 GK_ATOM(median_, "median")
 GK_ATOM(mediummathspace_, "mediummathspace")
 GK_ATOM(menclose_, "menclose")
 GK_ATOM(merror_, "merror")
 GK_ATOM(mfenced_, "mfenced")
 GK_ATOM(mfrac_, "mfrac")
new file mode 100644
--- /dev/null
+++ b/content/base/src/nsNodeIterator.cpp
@@ -0,0 +1,378 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.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/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is this file as it was released on July 19 2008.
+ *
+ * The Initial Developer of the Original Code is
+ * Craig Topper.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Craig Topper <craig.topper@gmail.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Implementation of DOM Traversal's nsIDOMNodeIterator
+ */
+
+#include "nsNodeIterator.h"
+
+#include "nsIDOMNode.h"
+#include "nsIDOMNodeFilter.h"
+#include "nsDOMError.h"
+
+#include "nsIContent.h"
+#include "nsIDocument.h"
+
+#include "nsContentUtils.h"
+#include "nsCOMPtr.h"
+
+/*
+ * NodePointer implementation
+ */
+nsNodeIterator::NodePointer::NodePointer(nsINode *aNode,
+                                         PRBool aBeforeNode) :
+    mNode(aNode),
+    mBeforeNode(aBeforeNode)
+{ 
+}
+
+PRBool nsNodeIterator::NodePointer::MoveToNext(nsINode *aRoot)
+{
+    if (mBeforeNode) {
+        mBeforeNode = PR_FALSE;
+        return PR_TRUE;
+    }
+
+    return MoveForward(aRoot, mNode, -1);
+}
+
+PRBool nsNodeIterator::NodePointer::MoveToPrevious(nsINode *aRoot)
+{
+    if (!mBeforeNode) {
+        mBeforeNode = PR_TRUE;
+        return PR_TRUE;
+    }
+
+    if (mNode == aRoot)
+        return PR_FALSE;
+
+    NS_ASSERTION(mNodeParent == mNode->GetNodeParent(), "Parent node incorrect in MoveToPrevious");
+    NS_ASSERTION(mIndexInParent == mNodeParent->IndexOf(mNode), "Index mismatch in MoveToPrevious");
+    MoveBackward(mNodeParent, mIndexInParent);
+
+    return PR_TRUE;
+}
+
+void nsNodeIterator::NodePointer::AdjustAfterInsertion(nsINode *aContainer, PRInt32 aIndexInContainer)
+{
+    if (!mNode)
+        return;
+
+    // check if earlier sibling was added
+    if (aContainer == mNodeParent && aIndexInContainer <= mIndexInParent)
+        mIndexInParent++;
+}
+
+void nsNodeIterator::NodePointer::AdjustAfterRemoval(nsINode* aRoot, nsINode *aContainer, nsIContent *aChild, PRInt32 aIndexInContainer)
+{
+    if (!mNode)
+        return;
+
+    // check if earlier sibling was removed
+    if (aContainer == mNodeParent && aIndexInContainer < mIndexInParent)
+        mIndexInParent--;
+
+    // check if ancestor was removed
+    if (!nsContentUtils::ContentIsDescendantOf(mNode, aChild))
+        return;
+
+    if (mBeforeNode) {
+
+        if (MoveForward(aRoot, aContainer, aIndexInContainer-1))
+            return;
+
+        // No suitable node was found so try going backwards
+        mBeforeNode = PR_FALSE;
+    }
+
+    MoveBackward(aContainer, aIndexInContainer);
+}
+
+PRBool nsNodeIterator::NodePointer::MoveForward(nsINode *aRoot, nsINode *aParent, PRInt32 aChildNum)
+{
+    while (1) {
+        nsINode *node = aParent->GetChildAt(aChildNum+1);
+        if (node) {
+            mNode = node;
+            mIndexInParent = aChildNum+1;
+            mNodeParent = aParent;
+            return PR_TRUE;
+        }
+
+        if (aParent == aRoot)
+            break;
+
+        node = aParent;
+
+        if (node == mNode) {
+            NS_ASSERTION(mNodeParent == mNode->GetNodeParent(), "Parent node incorrect in MoveForward");
+            NS_ASSERTION(mIndexInParent == mNodeParent->IndexOf(mNode), "Index mismatch in MoveForward");
+
+            aParent = mNodeParent;
+            aChildNum = mIndexInParent;
+        } else {
+            aParent = node->GetNodeParent();
+            aChildNum = aParent->IndexOf(node);
+        }
+    }
+
+    return PR_FALSE;
+}
+
+void nsNodeIterator::NodePointer::MoveBackward(nsINode *aParent, PRInt32 aChildNum)
+{
+    nsINode *sibling = aParent->GetChildAt(aChildNum-1);
+    mNode = aParent;
+    if (sibling) {
+        do {
+            mIndexInParent = aChildNum-1;
+            mNodeParent = mNode;
+            mNode = sibling;
+
+            aChildNum = mNode->GetChildCount();
+            sibling = mNode->GetChildAt(aChildNum-1);
+        } while (sibling);
+    } else {
+        mNodeParent = mNode->GetNodeParent();
+        if (mNodeParent)
+            mIndexInParent = mNodeParent->IndexOf(mNode);
+    }
+}
+
+/*
+ * Factories, constructors and destructors
+ */
+
+nsNodeIterator::nsNodeIterator(nsINode *aRoot,
+                               PRUint32 aWhatToShow,
+                               nsIDOMNodeFilter *aFilter,
+                               PRBool aExpandEntityReferences) :
+    nsTraversal(aRoot, aWhatToShow, aFilter, aExpandEntityReferences),
+    mDetached(PR_FALSE),
+    mPointer(mRoot, PR_TRUE)
+{
+    aRoot->AddMutationObserver(this);
+}
+
+nsNodeIterator::~nsNodeIterator()
+{
+    /* destructor code */
+    if (!mDetached && mRoot)
+        mRoot->RemoveMutationObserver(this);
+}
+
+/*
+ * nsISupports and cycle collection stuff
+ */
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsNodeIterator)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsNodeIterator)
+    if (!tmp->mDetached && tmp->mRoot)
+        tmp->mRoot->RemoveMutationObserver(tmp);
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRoot)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFilter)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsNodeIterator)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRoot)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFilter)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+// QueryInterface implementation for nsNodeIterator
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsNodeIterator)
+    NS_INTERFACE_MAP_ENTRY(nsIDOMNodeIterator)
+    NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
+    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMNodeIterator)
+    NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(NodeIterator)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsNodeIterator)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsNodeIterator)
+
+/* readonly attribute nsIDOMNode root; */
+NS_IMETHODIMP nsNodeIterator::GetRoot(nsIDOMNode * *aRoot)
+{
+    if (mRoot)
+        return CallQueryInterface(mRoot, aRoot);
+
+    *aRoot = nsnull;
+
+    return NS_OK;
+}
+
+/* readonly attribute unsigned long whatToShow; */
+NS_IMETHODIMP nsNodeIterator::GetWhatToShow(PRUint32 *aWhatToShow)
+{
+    *aWhatToShow = mWhatToShow;
+    return NS_OK;
+}
+
+/* readonly attribute nsIDOMNodeFilter filter; */
+NS_IMETHODIMP nsNodeIterator::GetFilter(nsIDOMNodeFilter **aFilter)
+{
+    NS_ENSURE_ARG_POINTER(aFilter);
+
+    nsCOMPtr<nsIDOMNodeFilter> filter = mFilter;
+    filter.swap((*aFilter = nsnull));
+
+    return NS_OK;
+}
+
+/* readonly attribute boolean expandEntityReferences; */
+NS_IMETHODIMP nsNodeIterator::GetExpandEntityReferences(PRBool *aExpandEntityReferences)
+{
+    *aExpandEntityReferences = mExpandEntityReferences;
+    return NS_OK;
+}
+
+/* nsIDOMNode nextNode ()  raises (DOMException); */
+NS_IMETHODIMP nsNodeIterator::NextNode(nsIDOMNode **_retval)
+{
+    nsresult rv;
+    PRInt16 filtered;
+
+    *_retval = nsnull;
+
+    if (mDetached)
+        return NS_ERROR_DOM_INVALID_STATE_ERR;
+
+    mWorkingPointer = mPointer;
+
+    while (mWorkingPointer.MoveToNext(mRoot)) {
+        nsCOMPtr<nsINode> testNode = mWorkingPointer.mNode;
+        rv = TestNode(testNode, &filtered);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
+            mPointer = mWorkingPointer;
+            mWorkingPointer.Clear();
+            return CallQueryInterface(testNode, _retval);
+        }
+    }
+
+    mWorkingPointer.Clear();
+    return NS_OK;
+}
+
+/* nsIDOMNode previousNode ()  raises (DOMException); */
+NS_IMETHODIMP nsNodeIterator::PreviousNode(nsIDOMNode **_retval)
+{
+    nsresult rv;
+    PRInt16 filtered;
+
+    *_retval = nsnull;
+
+    if (mDetached)
+        return NS_ERROR_DOM_INVALID_STATE_ERR;
+
+    mWorkingPointer = mPointer;
+
+    while (mWorkingPointer.MoveToPrevious(mRoot)) {
+        nsCOMPtr<nsINode> testNode = mWorkingPointer.mNode;
+        rv = TestNode(testNode, &filtered);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
+            mPointer = mWorkingPointer;
+            mWorkingPointer.Clear();
+            return CallQueryInterface(testNode, _retval);
+        }
+    }
+
+    mWorkingPointer.Clear();
+    return NS_OK;
+}
+
+/* void detach (); */
+NS_IMETHODIMP nsNodeIterator::Detach(void)
+{
+    if (!mDetached) {
+        mRoot->RemoveMutationObserver(this);
+
+        mPointer.Clear();
+
+        mDetached = PR_TRUE;
+    }
+
+    return NS_OK;
+}
+
+/* readonly attribute nsIDOMNode referenceNode; */
+NS_IMETHODIMP nsNodeIterator::GetReferenceNode(nsIDOMNode * *aRefNode)
+{
+    if (mPointer.mNode)
+        return CallQueryInterface(mPointer.mNode, aRefNode);
+
+    *aRefNode = nsnull;
+    return NS_OK;
+}
+
+/* readonly attribute boolean pointerBeforeReferenceNode; */
+NS_IMETHODIMP nsNodeIterator::GetPointerBeforeReferenceNode(PRBool *aBeforeNode)
+{
+    *aBeforeNode = mPointer.mBeforeNode;
+    return NS_OK;
+}
+
+/*
+ * nsIMutationObserver interface
+ */
+
+void nsNodeIterator::ContentInserted(nsIDocument* aDocument,
+                                     nsIContent* aContainer,
+                                     nsIContent* aChild,
+                                     PRInt32 aIndexInContainer)
+{
+    nsINode *container = NODE_FROM(aContainer, aDocument);
+
+    mPointer.AdjustAfterInsertion(container, aIndexInContainer);
+    mWorkingPointer.AdjustAfterInsertion(container, aIndexInContainer);
+}
+
+
+void nsNodeIterator::ContentRemoved(nsIDocument *aDocument,
+                                    nsIContent *aContainer,
+                                    nsIContent *aChild,
+                                    PRInt32 aIndexInContainer)
+{
+    nsINode *container = NODE_FROM(aContainer, aDocument);
+
+    mPointer.AdjustAfterRemoval(mRoot, container, aChild, aIndexInContainer);
+    mWorkingPointer.AdjustAfterRemoval(mRoot, container, aChild, aIndexInContainer);
+}
new file mode 100644
--- /dev/null
+++ b/content/base/src/nsNodeIterator.h
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.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/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is this file as it was released on July 19 2008.
+ *
+ * The Initial Developer of the Original Code is
+ * Craig Toppper.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Craig Topper <craig.topper@gmail.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+ 
+/*
+ * Implementation of DOM Traversal's nsIDOMNodeIterator
+ */
+
+#ifndef nsNodeIterator_h___
+#define nsNodeIterator_h___
+
+#include "nsIDOMNodeIterator.h"
+#include "nsTraversal.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsStubMutationObserver.h"
+
+class nsINode;
+class nsIDOMNode;
+class nsIDOMNodeFilter;
+
+class nsNodeIterator : public nsIDOMNodeIterator,
+                       public nsTraversal,
+                       public nsStubMutationObserver
+{
+public:
+    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+    NS_DECL_NSIDOMNODEITERATOR
+
+    nsNodeIterator(nsINode *aRoot,
+                   PRUint32 aWhatToShow,
+                   nsIDOMNodeFilter *aFilter,
+                   PRBool aExpandEntityReferences);
+    virtual ~nsNodeIterator();
+
+    NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
+    NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
+
+    NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsNodeIterator, nsIDOMNodeIterator)
+
+private:
+    struct NodePointer {
+        NodePointer() : mNode(nsnull) {};
+        NodePointer(nsINode *aNode, PRBool aBeforeNode);
+
+        PRBool MoveToNext(nsINode *aRoot);
+        PRBool MoveToPrevious(nsINode *aRoot);
+
+        PRBool MoveForward(nsINode *aRoot, nsINode *aParent, PRInt32 aChildNum);
+        void MoveBackward(nsINode *aParent, PRInt32 aChildNum);
+
+        void AdjustAfterInsertion(nsINode *aContainer, PRInt32 aIndexInContainer);
+        void AdjustAfterRemoval(nsINode *aRoot, nsINode *aContainer, nsIContent *aChild, PRInt32 aIndexInContainer);
+        
+        void Clear() { mNode = nsnull; }
+
+        nsINode *mNode;
+        // pointer to the parent of mNode. Can be dangling if mNode is null or points to the root
+        nsINode *mNodeParent;
+        PRBool mBeforeNode;
+        PRInt32 mIndexInParent;
+    };
+
+    PRBool mDetached;
+    NodePointer mPointer;
+    NodePointer mWorkingPointer;
+};
+
+#endif
new file mode 100644
--- /dev/null
+++ b/content/base/src/nsTraversal.cpp
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.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/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is this file as it was released on May 1 2001.
+ *
+ * The Initial Developer of the Original Code is
+ * Jonas Sicking.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jonas Sicking <sicking@bigfoot.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsTraversal.h"
+
+#include "nsIDOMNode.h"
+#include "nsIDOMNodeFilter.h"
+#include "nsDOMError.h"
+
+#include "nsIContent.h"
+
+#include "nsGkAtoms.h"
+
+nsTraversal::nsTraversal(nsINode *aRoot,
+                         PRUint32 aWhatToShow,
+                         nsIDOMNodeFilter *aFilter,
+                         PRBool aExpandEntityReferences) :
+    mRoot(aRoot),
+    mWhatToShow(aWhatToShow),
+    mFilter(aFilter),
+    mExpandEntityReferences(aExpandEntityReferences)
+{
+    NS_ASSERTION(aRoot, "invalid root in call to nsTraversal constructor");
+}
+
+nsTraversal::~nsTraversal()
+{
+    /* destructor code */
+}
+
+/*
+ * Tests if and how a node should be filtered. Uses mWhatToShow and
+ * mFilter to test the node.
+ * @param aNode     Node to test
+ * @param _filtered Returned filtervalue. See nsIDOMNodeFilter.idl
+ * @returns         Errorcode
+ */
+nsresult nsTraversal::TestNode(nsINode* aNode, PRInt16* _filtered)
+{
+    nsresult rv;
+
+    *_filtered = nsIDOMNodeFilter::FILTER_SKIP;
+
+    PRUint16 nodeType = 0;
+    // Check the most common cases
+    if (aNode->IsNodeOfType(nsINode::eELEMENT)) {
+        nodeType = nsIDOMNode::ELEMENT_NODE;
+    }
+    else if (aNode->IsNodeOfType(nsINode::eCONTENT)) {
+        nsIAtom* tag = static_cast<nsIContent*>(aNode)->Tag();
+        if (tag == nsGkAtoms::textTagName) {
+            nodeType = nsIDOMNode::TEXT_NODE;
+        }
+        else if (tag == nsGkAtoms::cdataTagName) {
+            nodeType = nsIDOMNode::CDATA_SECTION_NODE;
+        }
+        else if (tag == nsGkAtoms::commentTagName) {
+            nodeType = nsIDOMNode::COMMENT_NODE;
+        }
+        else if (tag == nsGkAtoms::processingInstructionTagName) {
+            nodeType = nsIDOMNode::PROCESSING_INSTRUCTION_NODE;
+        }
+    }
+
+    nsCOMPtr<nsIDOMNode> domNode;
+    if (!nodeType) {
+        domNode = do_QueryInterface(aNode);
+        rv = domNode->GetNodeType(&nodeType);
+        NS_ENSURE_SUCCESS(rv, rv);
+    }
+
+    if (nodeType <= 12 && !((1 << (nodeType-1)) & mWhatToShow)) {
+        return NS_OK;
+    }
+
+    if (mFilter) {
+        if (!domNode) {
+            domNode = do_QueryInterface(aNode);
+        }
+
+        return mFilter->AcceptNode(domNode, _filtered);
+    }
+
+    *_filtered = nsIDOMNodeFilter::FILTER_ACCEPT;
+    return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/content/base/src/nsTraversal.h
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.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/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is this file as it was released on May 1 2001.
+ *
+ * The Initial Developer of the Original Code is
+ * Jonas Sicking.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jonas Sicking <sicking@bigfoot.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+ 
+/*
+ * Implementation of DOM Traversal's nsIDOMTreeWalker
+ */
+
+#ifndef nsTraversal_h___
+#define nsTraversal_h___
+
+#include "nsCOMPtr.h"
+
+class nsINode;
+class nsIDOMNodeFilter;
+
+class nsTraversal
+{
+public:
+    nsTraversal(nsINode *aRoot,
+                PRUint32 aWhatToShow,
+                nsIDOMNodeFilter *aFilter,
+                PRBool aExpandEntityReferences);
+    virtual ~nsTraversal();
+
+protected:
+    nsCOMPtr<nsINode> mRoot;
+    PRUint32 mWhatToShow;
+    nsCOMPtr<nsIDOMNodeFilter> mFilter;
+    PRBool mExpandEntityReferences;
+
+    /*
+     * Tests if and how a node should be filtered. Uses mWhatToShow and
+     * mFilter to test the node.
+     * @param aNode     Node to test
+     * @param _filtered Returned filtervalue. See nsIDOMNodeFilter.idl
+     * @returns         Errorcode
+     */
+    nsresult TestNode(nsINode* aNode, PRInt16* _filtered);
+};
+
+#endif
+
--- a/content/base/src/nsTreeWalker.cpp
+++ b/content/base/src/nsTreeWalker.cpp
@@ -46,57 +46,29 @@
 #include "nsIDOMNode.h"
 #include "nsIDOMNodeFilter.h"
 #include "nsDOMError.h"
 
 #include "nsIContent.h"
 #include "nsIDocument.h"
 
 #include "nsContentUtils.h"
-#include "nsMemory.h"
-#include "nsCOMArray.h"
-#include "nsGkAtoms.h"
 
 /*
  * Factories, constructors and destructors
  */
 
-nsresult
-NS_NewTreeWalker(nsIDOMNode *aRoot,
-                 PRUint32 aWhatToShow,
-                 nsIDOMNodeFilter *aFilter,
-                 PRBool aEntityReferenceExpansion,
-                 nsIDOMTreeWalker **aInstancePtrResult)
-{
-    NS_ENSURE_ARG_POINTER(aInstancePtrResult);
-
-    nsCOMPtr<nsINode> root = do_QueryInterface(aRoot);
-    NS_ENSURE_TRUE(root, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-
-    nsTreeWalker* walker = new nsTreeWalker(root,
-                                            aWhatToShow,
-                                            aFilter,
-                                            aEntityReferenceExpansion);
-    NS_ENSURE_TRUE(walker, NS_ERROR_OUT_OF_MEMORY);
-
-    return CallQueryInterface(walker, aInstancePtrResult);
-}
-
 nsTreeWalker::nsTreeWalker(nsINode *aRoot,
                            PRUint32 aWhatToShow,
                            nsIDOMNodeFilter *aFilter,
                            PRBool aExpandEntityReferences) :
-    mRoot(aRoot),
-    mWhatToShow(aWhatToShow),
-    mFilter(aFilter),
-    mExpandEntityReferences(aExpandEntityReferences),
+    nsTraversal(aRoot, aWhatToShow, aFilter, aExpandEntityReferences),
     mCurrentNode(aRoot),
     mPossibleIndexesPos(-1)
 {
-    NS_ASSERTION(aRoot, "invalid root in call to nsTreeWalker constructor");
 }
 
 nsTreeWalker::~nsTreeWalker()
 {
     /* destructor code */
 }
 
 /*
@@ -568,73 +540,16 @@ nsTreeWalker::ChildOf(nsINode* aNode,
         }
     }
 
     *_retval = nsnull;
     return NS_OK;
 }
 
 /*
- * Tests if and how a node should be filtered. Uses mWhatToShow and
- * mFilter to test the node.
- * @param aNode     Node to test
- * @param _filtered Returned filtervalue. See nsIDOMNodeFilter.idl
- * @returns         Errorcode
- */
-nsresult nsTreeWalker::TestNode(nsINode* aNode, PRInt16* _filtered)
-{
-    nsresult rv;
-
-    *_filtered = nsIDOMNodeFilter::FILTER_SKIP;
-
-    PRUint16 nodeType = 0;
-    // Check the most common cases
-    if (aNode->IsNodeOfType(nsINode::eELEMENT)) {
-        nodeType = nsIDOMNode::ELEMENT_NODE;
-    }
-    else if (aNode->IsNodeOfType(nsINode::eCONTENT)) {
-        nsIAtom* tag = static_cast<nsIContent*>(aNode)->Tag();
-        if (tag == nsGkAtoms::textTagName) {
-            nodeType = nsIDOMNode::TEXT_NODE;
-        }
-        else if (tag == nsGkAtoms::cdataTagName) {
-            nodeType = nsIDOMNode::CDATA_SECTION_NODE;
-        }
-        else if (tag == nsGkAtoms::commentTagName) {
-            nodeType = nsIDOMNode::COMMENT_NODE;
-        }
-        else if (tag == nsGkAtoms::processingInstructionTagName) {
-            nodeType = nsIDOMNode::PROCESSING_INSTRUCTION_NODE;
-        }
-    }
-
-    nsCOMPtr<nsIDOMNode> domNode;
-    if (!nodeType) {
-        domNode = do_QueryInterface(aNode);
-        rv = domNode->GetNodeType(&nodeType);
-        NS_ENSURE_SUCCESS(rv, rv);
-    }
-
-    if (nodeType <= 12 && !((1 << (nodeType-1)) & mWhatToShow)) {
-        return NS_OK;
-    }
-
-    if (mFilter) {
-        if (!domNode) {
-            domNode = do_QueryInterface(aNode);
-        }
-
-        return mFilter->AcceptNode(domNode, _filtered);
-    }
-
-    *_filtered = nsIDOMNodeFilter::FILTER_ACCEPT;
-    return NS_OK;
-}
-
-/*
  * Gets the child index of a node within it's parent. Gets a possible index
  * from mPossibleIndexes to gain speed. If the value in mPossibleIndexes
  * isn't correct it'll get the index the usual way
  * @param aParent   in which to get the index
  * @param aChild    node to get the index of
  * @param aIndexPos position in mPossibleIndexes that contains the possible.
  *                  index
  * @returns         resulting index
--- a/content/base/src/nsTreeWalker.h
+++ b/content/base/src/nsTreeWalker.h
@@ -40,44 +40,40 @@
 /*
  * Implementation of DOM Traversal's nsIDOMTreeWalker
  */
 
 #ifndef nsTreeWalker_h___
 #define nsTreeWalker_h___
 
 #include "nsIDOMTreeWalker.h"
+#include "nsTraversal.h"
 #include "nsCOMPtr.h"
 #include "nsVoidArray.h"
-#include "nsJSUtils.h"
 #include "nsCycleCollectionParticipant.h"
 
 class nsINode;
 class nsIDOMNode;
 class nsIDOMNodeFilter;
 
-class nsTreeWalker : public nsIDOMTreeWalker
+class nsTreeWalker : public nsIDOMTreeWalker, public nsTraversal
 {
 public:
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_NSIDOMTREEWALKER
 
     nsTreeWalker(nsINode *aRoot,
                  PRUint32 aWhatToShow,
                  nsIDOMNodeFilter *aFilter,
                  PRBool aExpandEntityReferences);
     virtual ~nsTreeWalker();
 
     NS_DECL_CYCLE_COLLECTION_CLASS(nsTreeWalker)
 
 private:
-    nsCOMPtr<nsINode> mRoot;
-    PRUint32 mWhatToShow;
-    nsCOMPtr<nsIDOMNodeFilter> mFilter;
-    PRBool mExpandEntityReferences;
     nsCOMPtr<nsINode> mCurrentNode;
     
     /*
      * Array with all child indexes up the tree. This should only be
      * considered a hint and the value could be wrong.
      * The array contains casted PRInt32's
      */
     nsAutoVoidArray mPossibleIndexes;
@@ -146,25 +142,16 @@ private:
      */
     nsresult ChildOf(nsINode* aNode,
                      PRInt32 childNum,
                      PRBool aReversed,
                      PRInt32 aIndexPos,
                      nsINode** _retval);
 
     /*
-     * Tests if and how a node should be filtered. Uses mWhatToShow and
-     * mFilter to test the node.
-     * @param aNode     Node to test
-     * @param _filtered Returned filtervalue. See nsIDOMNodeFilter.idl
-     * @returns         Errorcode
-     */
-    nsresult TestNode(nsINode* aNode, PRInt16* _filtered);
-    
-    /*
      * Gets the child index of a node within it's parent. Gets a possible index
      * from mPossibleIndexes to gain speed. If the value in mPossibleIndexes
      * isn't correct it'll get the index the usual way.
      * @param aParent   in which to get the index
      * @param aChild    node to get the index of
      * @param aIndexPos position in mPossibleIndexes that contains the possible.
      *                  index
      * @returns         resulting index
@@ -182,17 +169,10 @@ private:
     void SetChildIndex(PRInt32 aIndexPos, PRInt32 aChildIndex)
     {
         if (aIndexPos != -1)
             mPossibleIndexes.ReplaceElementAt(NS_INT32_TO_PTR(aChildIndex),
                                               aIndexPos);
     }
 };
 
-// Make a new nsIDOMTreeWalker object
-nsresult NS_NewTreeWalker(nsIDOMNode *aRoot,
-                          PRUint32 aWhatToShow,
-                          nsIDOMNodeFilter *aFilter,
-                          PRBool aEntityReferenceExpansion,
-                          nsIDOMTreeWalker **aInstancePtrResult);
-
 #endif
 
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -146,16 +146,19 @@ include $(topsrcdir)/config/rules.mk
 		test_bug405182.html \
 		test_bug403841.html \
 		test_bug409380.html \
 		test_bug410229.html \
 		test_bug413974.html \
 		test_bug415860.html \
 		test_bug414190.html \
 		test_bug414796.html \
+		test_bug416317-1.html \
+		test_bug416317-2.html \
+		file_bug416317.xhtml \
 		test_bug416383.html \
 		test_bug417255.html \
 		test_bug417384.html \
 		test_bug418214.html \
 		test_bug419527.xhtml \
 		test_bug420609.xhtml \
 		test_bug420700.html \
 		test_bug421602.html \
@@ -181,16 +184,19 @@ include $(topsrcdir)/config/rules.mk
 		test_bug425201.html \
 		test_bug431833.html \
 		test_bug438519.html \
 		test_bug444722.html \
 		test_text_replaceWholeText.html \
 		test_text_wholeText.html \
 		wholeTexty-helper.xml \
 		test_bug444030.xhtml \
+		test_NodeIterator_basics_filters.xhtml \
+		test_NodeIterator_mutations_1.xhtml \
+		test_NodeIterator_mutations_2.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
 
 check::
 	@$(EXIT_ON_ERROR) \
 	for f in $(subst .cpp,,$(CPP_UNIT_TESTS)); do \
new file mode 100644
--- /dev/null
+++ b/content/base/test/file_bug416317.xhtml
@@ -0,0 +1,1413 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg"
+  xml:lang="en" lang="en" dir="ltr" id="html" class="unitTest" title=":root selector">
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+  <title>selectorTest</title>
+  <!-- (c) Disruptive Innovations 2008 -->
+  <style type="text/css">
+    /* TEST 0 : BASIC TESTS */
+    /* element type selector */
+    body { background-color: red; margin: 10px; padding: 10px; color: red; font-family: sans-serif }
+    div { background-color: red; color: red; }
+    div.header { background-color: #e0e0e0; color: black; padding: 10px; margin-bottom: 10px;}
+    /* class selector */
+    .unitTest { width: 10px; background-color: red; color: red; margin: 0px; margin-right: 2px; float: left; }
+    .test { margin-bottom: 2px; background-color: green; color: green; }
+    /* group of selectors */
+    .unitTest, .test { height: 10px; }
+
+    .UI > * { float: left }
+    .UI { clear: both; height: auto; padding-top: 6px;}
+    .tilda { clear: both; height: auto; padding-top: 6px;}
+    .plus { clear: both; height: auto; padding-top: 6px;}
+
+    h1, p { width: 500px; color: #000; }
+    a { color: #000; }
+    #results { background: #FFF; width: 600px; padding: 10px 40px; color: #000; font-size: 11px; line-height: 1.3em; }
+    #root, #root2, #root3 { display: none; }
+
+    /* init */
+    .blox16 { background-color: red; }
+    .blox17 { background-color: red; }
+    .lastChild > p { background-color: red; }
+    .firstOfType > p { background-color: red }
+    .lastOfType > p { background-color: red }
+    .empty > .isEmpty { color: red; }
+    html { background-color: red; }
+  </style>
+  <span type="text/test" id="test"><![CDATA[
+    /* :target selector */
+    .target :target { background-color: lime; }
+
+    /* test 1 : childhood selector */
+    html > body { background-color: green; }
+    .test > .blox1 { background-color: lime; }
+
+    /* test 2 : attribute existence selector */
+    /* attribute with a value */
+    .blox2[align] { background-color: lime; }
+    /* attribute with empty value */
+    .blox3[align] { background-color: lime; }
+    /* attribute with almost similar name */
+    .blox4, .blox5 { background-color: lime }
+    .blox4[align], .blox5[align] { background-color: red; }
+
+    /* test3 : attribute value selector */
+    .blox6[align="center"] { background-color: lime; }
+    .blox6[align="c"] { background-color: red; }
+    .blox6[align="centera"] { background-color: red; }
+    .blox6[foo="\e9"] { background-color: lime; }
+    .blox6[\_foo="\e9"] { background-color: lime; }
+
+    /* test 4 : [~=] */
+    .blox7[class~="foo"] { background-color: lime; }
+    .blox8, .blox9, .blox10 { background-color: lime; }
+    .blox8[class~=""] { background-color: red; }
+    .blox9[foo~=""] { background-color: red; }
+    .blox10[foo~="foo"] { background-color: red; }
+
+    /* test5 [^=] */
+    .attrStart > .t3 { background-color: lime; }
+    .attrStart > .t1[class^="unit"] { background-color: lime; }
+    .attrStart > .t2 { background-color: lime; }
+    .attrStart > .t2[class^="nit"] { background-color: red; }
+    .attrStart > .t3[align^=""] { background-color: red; }
+    .attrStart > .t4[foo^="\e9"] { background-color: lime; }
+
+    /* test6 [$=] */
+    .attrEnd > .t3 { background-color: lime; }
+    .attrEnd > .t1[class$="t1"] { background-color: lime; }
+    .attrEnd > .t2 { background-color: lime; }
+    .attrEnd > .t2[class$="unit"] { background-color: red; }
+    .attrEnd > .t3[align$=""] { background-color: red; }
+    .attrEnd > .t4[foo$="\e9"] { background-color: lime; }
+
+    /* test7 [*=] */
+    .attrMiddle > .t3 { background-color: lime; }
+    .attrMiddle > .t1[class*="t t"] { background-color: lime; }
+    .attrMiddle > .t2 { background-color: lime; }
+    .attrMiddle > .t2[class*="a"] { background-color: red; }
+    .attrMiddle > .t3[align*=""] { background-color: red; }
+    .attrMiddle > .t4[foo*="\e9"] { background-color: lime; }
+
+    /* :first-child tests */
+    .firstChild .unitTest:first-child { background-color: lime; }
+    .blox12:first-child { background-color: red; }
+    .blox13:first-child { background-color: red; }
+    .blox12, .blox13 { background-color: lime }
+
+    /* :root tests */
+    :root { background-color: green; }
+
+    /* :nth-child(n) tests */
+    .nthchild1 > :nth-last-child(odd) { background-color: lime; }
+    .nthchild1 > :nth-child(odd) { background-color: lime; }
+
+    .nthchild2 > :nth-last-child(even) { background-color: lime; }
+    .nthchild2 > :nth-child(even) { background-color: lime; }
+
+    .nthchild3 > :nth-child(3n+2) { background-color: lime; }
+    .nthchild3 > :nth-last-child(3n+1) { background-color: lime; }
+    .nthchild3 > :nth-last-child(3n+3) { background-color: lime; }
+
+    .nthoftype1 > div:nth-of-type(odd) { background-color: lime; }
+    .nthoftype1 > div:nth-last-of-type(odd) { background-color: lime; }
+    .nthoftype1 > p { background-color: green; }
+
+    .nthoftype2 > div:nth-of-type(even) { background-color: lime; }
+    .nthoftype2 > div:nth-last-of-type(even) { background-color: lime; }
+    .nthoftype2 > p { background-color: green; }
+
+    .nthoftype3 > div:nth-of-type(3n+1) { background-color: lime; }
+    .nthoftype3 > div:nth-last-of-type(3n+1) { background-color: lime; }
+    .nthoftype3 > div:nth-last-of-type(3n+2) { background-color: lime; }
+    .nthoftype3 > p { background-color: green; }
+
+    /* :not() tests */
+    .blox14:not(span) { background-color: lime; }
+    .blox15:not([foo="blox14"]) { background-color: lime; }
+    .blox16:not(.blox15) { background-color: lime; }
+
+    /* :only-of-type tests */
+    .blox17:only-of-type { background-color: lime; }
+    .blox18:only-of-type { background-color: red; }
+    .blox18:not(:only-of-type) { background-color: lime; }
+
+    /* :last-child tests */
+    .lastChild > :last-child { background-color: lime }
+    .lastChild > :not(:last-child) { background-color: lime }
+
+    /* :first-of-type tests */
+    .firstOfType > *:first-of-type { background-color: lime; }
+    *.firstOfType > :not(:first-of-type) { background-color: lime; }
+
+    /* :last-of-type tests */
+    .lastOfType > *:last-of-type { background-color: lime; }
+    *.lastOfType > :not(:last-of-type) { background-color: lime; }
+
+    /* :only-child tests */
+    .onlyChild > *:not(:only-child) { background-color: lime; }
+    .onlyChild > .unitTest > *:only-child { background-color: lime; }
+
+    /* :only-of-type tests */
+    .onlyOfType *:only-of-type { background-color: lime; }
+    .onlyOfType *:not(:only-of-type) { background-color: lime; }
+
+    /* :empty tests */
+    .empty > *.isEmpty:empty { background-color: lime; color: lime; }
+    .empty > .isNotEmpty { background-color: blue; color: blue; }
+    .empty > .isNotEmpty:empty { background-color: red; color: red; }
+    .empty > .isNotEmpty:not(:empty) { background-color: lime; color: lime; }
+
+    /* :lang() tests */
+    .lang :lang(en) { background-color: lime; }
+    .lang :lang(fr) { background-color: lime; }
+    .lang .t1 { background-color: blue; }
+    .lang .t1:lang(es) { background-color: lime; }
+    .lang :lang(es-AR) { background-color: red; }
+
+    /* [|=] tests */
+    .attrLang .t1 { background-color: lime; }
+    .attrLang .t1[lang|="en"] { background-color: red; }
+    .attrLang [lang|="fr"] { background-color: lime; }
+    .attrLang .t2[lang|="en"] { background-color: lime; }
+    .attrLang .t3 { background-color: blue; }
+    .attrLang .t3[lang|="es"] { background-color: lime; }
+    .attrLang [lang|="es-AR"] { background-color: red; }
+
+    /* UI tests */
+    .UI .t1:enabled > .unitTest { background-color: lime; }
+    .UI .t2:disabled > .unitTest { background-color: lime; }
+    .UI .t3:checked + div { background-color: lime; }
+    .UI .t4:not(:checked) + div { background-color: lime; }
+
+    /* ~ combinator tests */
+    .tilda .t1 { background-color: white; }
+    .tilda .t1 ~ .unitTest { background-color: lime; }
+    .tilda .t1:hover ~ .unitTest { background-color: red; }
+
+    /* ~ combinator tests */
+    .plus .t1, .plus .t2 { background-color: white; }
+    .plus .t1 + .unitTest + .unitTest { background-color: lime; }
+    .plus .t1:hover + .unitTest + .unitTest { background-color: red; }
+  ]]></span>
+  <span type="text/test" id="error">
+    .blox16:not(.blox15[foo="blox14"]) { background-color: red; }
+
+    /* Tests from http://www.w3.org/Style/CSS/Test/CSS3/Selectors/20060307/html/index.html */
+    div:not(:not(div)) { background-color : red }
+
+    div, { background: red; }
+    .5cm { background: red; }
+    foo &amp; address, p { background: red; }
+    [*=test] { background: red; }
+    [*|*=test] { background: red; }
+
+    div:subject { background: red; }
+    :canvas { background: red; }
+    :viewport { background: red; }
+    :window { background: red; }
+    :menu { background: red; }
+    :table { background: red; }
+    :select { background: red; }
+    ::canvas { background: red; }
+    ::viewport { background: red; }
+    ::window { background: red; }
+    ::menu { background: red; }
+    ::table { background: red; }
+    ::select { background: red; }
+
+    ..test { background: red; color: yellow; }
+    .foo..quux { background: red; color: yellow; }
+    .bar. { background: red; color: yellow; }
+  </span>
+  <script><![CDATA[
+  window.onload = function(){
+    if ( window.location.hash.indexOf("target") == -1 )
+      window.location.hash = "#target";
+
+    var root = document.getElementById("root");
+    var root2 = document.getElementById("root2");
+    var root3 = document.getElementById("root3");
+    var results = [];
+    var tests = 0, passed = 0;
+    var cache = {};
+
+    var css = document.getElementById("test").firstChild.nodeValue.split("\n");
+    for ( var i = 0; i < css.length; i++ ) {
+      css[i] = css[i].replace(/\/\*.*?\*\//g, "")
+        .replace(/^\s*|\s*$/g, "").split(/\s*{/);
+    }
+
+    var ecss = document.getElementById("error").firstChild.nodeValue.split("\n");
+    for ( var i = 0; i < ecss.length; i++ ) {
+      ecss[i] = ecss[i].replace(/\/\*.*?\*\//g, "")
+        .replace(/^\s*|\s*$/g, "").split(/\s*{/);
+    }
+
+    var namespaceCheck = {};
+
+    var badNamespace = [
+      {},
+      null,
+      undefined,
+    ];
+
+    interfaceCheck(root, "Element");
+    runTest( css, "Element", root, true );
+    check( "Inside Element", root, true, false );
+    cacheCheck( "Element", root );
+    check( "Outside Element", root2, passed === 0 ? "autofail" : false, false );
+    runTest( ecss, "SyntaxError: Element", root, false );
+    jqTests("Element", root3, "querySelectorAll");
+
+    var root4 = root2.cloneNode(true);
+    interfaceCheck(root4, "Disconnected Element");
+    runTest( css, "Disconnected Element", root4, true );
+    check( "Disconnected Element", root4, true, true );
+    cacheCheck( "Disconnected Element", root4 );
+    runTest( ecss, "SyntaxError: Disconnected Element", root4, false );
+    jqTests("Disconnected Element", root3.cloneNode(true), "querySelectorAll");
+
+    var fragment = document.createDocumentFragment();
+    fragment.appendChild( root2.cloneNode(true) );
+
+    interfaceCheck(fragment, "Fragment");
+    runTest( css, "Fragment", fragment, true );
+    check( "Fragment", fragment, true, true );
+    runTest( ecss, "SyntaxError: Fragment", fragment, false );
+    cacheCheck( "Fragment", fragment );
+
+    root.parentNode.removeChild( root );
+    
+    interfaceCheck(document, "Document");
+    runTest( css, "Document", document, true );
+    check( "Document", document, true, false );
+    runTest( ecss, "SyntaxError: Document", document, false );
+    jqTests("Document", document, "querySelectorAll");
+    cacheCheck( "Document", document );
+    
+    done();
+
+    function interfaceCheck(obj, type){
+      var q = typeof obj.querySelector === "function";
+      assert( q, type + " supports querySelector" );
+      var qa = typeof obj.querySelectorAll === "function";
+      assert( qa, type + " supports querySelectorAll" );
+      return q && qa;
+    }
+
+    function done(){
+      if (window.parent && window.parent.SimpleTest) {
+        window.parent.SimpleTest.finish();
+      } else {
+        var r = document.getElementById("results");
+        var li = document.createElement("li");
+        var b = document.createElement("b");
+        b.appendChild( document.createTextNode( ((passed / tests) * 100).toFixed(1) + "%" ) );
+        li.appendChild( b );
+        li.appendChild( document.createTextNode( ": " + passed + " passed, " + (tests - passed) + " failed" ) );
+        r.appendChild( li );
+
+        for ( var i = 0; i < results.length; i++ ) {
+              var li = document.createElement("li");
+              var span = document.createElement("span");
+              span.style.color = (results[i][0] === "FAIL" ? "red" : "green");
+              span.appendChild( document.createTextNode( results[i][0] ) );
+              li.appendChild( span );
+              li.appendChild( document.createTextNode( " " + results[i][1] ) );
+              r.appendChild( li );
+        }
+      }
+    }
+
+    function cacheCheck( type, root ) {
+      try {
+        var pre = root.querySelectorAll( "div" ), preLength = pre.length;
+
+        var div = document.createElement("div");
+        (root.body || root).appendChild( div );
+
+        var post = root.querySelectorAll( "div" ), postLength = post.length;
+
+        assert( pre.length == preLength, type + ": StaticNodeList" );
+        assert( post.length != pre.length, type + ": StaticNodeList" );
+      } catch(e) {
+        assert( false, type + ": StaticNodeList" );
+        assert( false, type + ": StaticNodeList" );
+      }
+
+      if ( div )
+        (root.body || root).removeChild( div );
+    }
+
+
+    function runTest( css, type, root, expect ) {
+      var pass = false;
+      try {
+        root.querySelectorAll("");
+      } catch(e){ pass = e.code == DOMException.SYNTAX_ERR; }
+      assert( pass, type + ".querySelectorAll Empty String" );
+
+      pass = false;
+      try {
+        root.querySelectorAll(null);
+      } catch(e){ pass = e.code == DOMException.SYNTAX_ERR; }
+      assert( pass, type + ".querySelectorAll null" );
+
+      pass = false;
+      try {
+        root.querySelectorAll(undefined);
+      } catch(e){ pass = e.code == DOMException.SYNTAX_ERR; }
+      assert_todo( pass, type + ".querySelectorAll undefined" );
+
+      pass = false;
+      try {
+        if ( root.querySelectorAll )
+          root.querySelectorAll();
+      } catch(e){ pass = true; }
+      assert( pass, type + ".querySelectorAll no value" );
+
+      var pass = false;
+      try {
+        root.querySelector("");
+      } catch(e){ pass = e.code == DOMException.SYNTAX_ERR; }
+      assert( pass, type + ".querySelector Empty String" );
+
+      pass = false;
+      try {
+        root.querySelector(null);
+      } catch(e){ pass = e.code == DOMException.SYNTAX_ERR; }
+      assert( pass, type + ".querySelector null" );
+
+      pass = false;
+      try {
+        root.querySelector(undefined);
+      } catch(e){ pass = e.code == DOMException.SYNTAX_ERR; }
+      assert_todo( pass, type + ".querySelector undefined" );
+
+      pass = false;
+      try {
+        if ( root.querySelector )
+          root.querySelector();
+      } catch(e){ pass = true; }
+      assert( pass, type + ".querySelector no value" );
+
+      for ( var i = 0; i < css.length; i++ ) {
+        var test = css[i];
+        if ( test.length == 2 ) {
+          var query = test[0], color = test[1].match(/: ([^\s;]+)/)[1];
+  
+          try {
+            var found = root.querySelectorAll(query);
+  
+            for ( var f = 0; f < found.length; f++ ) {
+              found[f].style.backgroundColor = color;
+            }
+
+            var pass = color != "red" || found.length === 0;
+
+            assert(expect && pass, type + ".querySelectorAll: " + query);
+          } catch(e){
+            var pass = !expect && e.code == DOMException.SYNTAX_ERR || false;
+            assert(pass, type + ".querySelectorAll: " + query);
+          }
+
+          if ( expect ) {
+            var pass = false;
+
+            try {
+              var found2 = root.querySelectorAll( "  \t\r\n  " + query + "  \t\r\n  " );
+              pass = found2.length == found.length;
+            } catch(e) {}
+
+            assert(pass, type + ".querySelectorAll Whitespace Trim: " + query);
+          }
+
+          try {
+            var single = root.querySelector(query);
+
+            var pass = found.length == 0 && single === null ||
+              found.length && found[0] == single;
+
+            assert(expect, type + ".querySelector: " + query);
+          } catch(e){
+            var pass = !expect && e.code == DOMException.SYNTAX_ERR || false;
+            assert(pass, type + ".querySelector: " + query);
+          }
+        }
+      }
+    }
+
+    function check( type, root, expect, fragment ){
+      var walker = document.createTreeWalker( root, NodeFilter.SHOW_ELEMENT, { acceptNode: function(){ return 1; } }, false );
+
+      while ( walker.nextNode() ) {
+        var div = walker.currentNode;
+        if ( (div.getAttribute("class") || "").toString().indexOf("unitTest") > -1 &&
+            (!fragment || div.getAttribute("id") !== "nofragment") ) {
+          // If we're display:none, we need to toggle that when doing computed
+          //  style.
+          var needToggle =
+            (window.frameElement &&
+             window.frameElement.style.display == "none");
+          if (needToggle) {
+            if ((div.getAttribute("class") || "").toString().indexOf("skipWhenToggling") > -1) {
+              continue;
+            }
+            window.frameElement.style.display = "";
+            // make sure it kicks in immediately
+            document.body.offsetWidth;
+          }
+          var view = document.defaultView.getComputedStyle(div, null);
+          var bg = view.getPropertyValue("background-color") || div.style.backgroundColor;
+          if (needToggle) {
+            window.frameElement.style.display = "none";
+            // make sure it kicks in immediately
+            document.body.offsetWidth;
+          }
+
+          var pass = bg && bg.indexOf("(255, 0, 0") == -1 && bg.indexOf("#ff0000") == -1 && bg.indexOf("red") == -1;
+          //var pass = bg && bg.indexOf("(255, 0, 0") == -1 && bg.indexOf("#ff0000") == -1;
+          assert(pass === expect, type + ": " + (div.title || div.parentNode.title));
+        }
+      }
+    }
+
+    function assert(pass, title) {
+      // Update |passed| no matter what: some tests depend on this
+      passed += (pass ? 1 : 0);
+
+      if (window.parent && window.parent.SimpleTest) {
+        window.parent.SimpleTest.ok(pass, title);
+      } else {
+        results.push([ (!pass ? "FAIL" : "PASS"), title ]);
+        tests++;
+      }
+    }
+
+    function assert_todo(pass, title) {
+      if (window.parent && window.parent.SimpleTest) {
+        window.parent.SimpleTest.todo(pass, title);
+      } else {
+        assert(pass, title);
+      }
+    }
+
+    function jqTests(type, root, select) {
+
+      function query(q, resolver){
+        try {
+          return root[select](q, resolver);
+        } catch(e){
+          if ( e.message.indexOf("ERR") > -1 || e.code == DOMException.NAMESPACE_ERR ||
+              e.code == DOMException.SYNTAX_ERR)
+            throw e;
+        }
+      }
+
+      function t( name, q, ids, restrict, ids2 ) {
+        var pass = true;
+
+        if ( restrict === false && root != document )
+          return;
+
+        var namespaced = /\|[^=]/.test( q );
+        var prepend = namespaced ? "xHTML|*#root3 " : "#root3 ";
+        q = (restrict === false || restrict === ":root" ? "" : prepend) + q.replace(/,/g, ", " + prepend);
+        var nq = q.replace(/>/g, "&gt;").replace(/</g, "&lt;");
+
+        if ( namespaced ) {
+          for ( var i = 0; i < badNamespace.length; i++ ) {
+            var resolver = badNamespace[i], pass = false, results = null;
+
+            try {
+              results = query(q, resolver);
+            } catch(e) {
+              pass = (e.message === "bad ERROR" || e.code == DOMException.NAMESPACE_ERR);
+            }
+
+            assert( pass, type + ": " + name + " Bad Resolver #" + (i+1) + " (" + nq + ")" + 
+              (pass ? "" : " Expected: " + extra(ids) + " Received: " + extra(results)) );
+          }
+        } else {
+          var pass = false;
+
+          try {
+            var results = query(q);
+            pass = hasPassed( results, ids );
+          } catch(e) {
+            pass = e.code == DOMException.SYNTAX_ERR;
+          }
+  
+          assert( pass, type + ": " + name + " (" + nq + ")" +
+            (pass ? "" : " Expected: " + extra(ids) + " Received: " + extra(results)) );
+        }
+
+        function hasPassed(results, ids){
+          var pass = (results && results.length == ids.length) || (!results && !ids);
+  
+          if ( ids && results ) {
+            for ( var i = 0; ids && i < ids.length; i++ ) {
+              if ( ids[i] !== results[i].getAttribute("id") ) {
+                pass = false;
+              }
+            }
+          } else {
+            pass = false;
+          }
+
+          return pass;
+        }
+
+        function extra(results){
+          var extra = " [";
+          if ( results ) {
+            for ( var i = 0; i < results.length; i++ ) {
+              extra += (extra.length > 2 ? "," : "") + "'" + (results[i].id || results[i]) + "'";
+            }
+          }
+  
+          extra += "]";
+          return extra;
+        }
+      }
+
+      t( "SVG", "*|svg", ["svg1","svg2","svg3"] );
+      t( "SVG", "svg|svg", ["svg2","svg3"] );
+      t( "SVG", "svg|svg *|circle", ["circle2","circle3"] );
+      t( "SVG", "svg|svg svg|circle", ["circle2","circle3"] );
+      t( "SVG", "xHTML|div *|svg", ["svg1","svg2","svg3"] );
+      t( "SVG", "div svg|svg", ["svg2","svg3"] );
+      t( "SVG", "xHTML|div svg|svg", ["svg2","svg3"] );
+      t( "SVG", "xHTML|div svg|svg *|circle", ["circle2","circle3"] );
+      t( "SVG", "xHTML|div svg *|circle", ["circle1","circle2","circle3"], true, ["circle1"] );
+      t( "SVG", "xHTML|div svg|svg svg|circle", ["circle2","circle3"] );
+
+      t( "Element Selector", "xHTML|p", ["firstp","ap","sndp","en","sap","first"] );
+      t( "Parent Element", "xHTML|div p", ["firstp","ap","sndp","en","sap","first"] );
+      t( "Parent Element", "xHTML|div xHTML|p", ["firstp","ap","sndp","en","sap","first"] );
+      t( "Parent Element", "*|div xHTML|p", ["firstp","ap","sndp","en","sap","first"] );
+      t( "Parent Element", "*|div *|p", ["firstp","ap","sndp","en","sap","first"] );
+      t( "Child", "xHTML|p > xHTML|a", ["simon1","google","groups","mark","yahoo","simon"] );
+      t( "Adjacent", "xHTML|a + xHTML|a", ["groups"] );
+      t( "Adjacent", "xHTML|a + a", ["groups"] );
+      t( "Nth-child", "xHTML|*#form xHTML|*#select1 xHTML|option:nth-child(3)", ["option1c"] );
+
+      var all = query("*");
+      assert( all && all.length > 30, type + ": Select all" );
+      var good = all && all.length;
+      for ( var i = 0; all && i < all.length; i++ )
+        if ( all[i].nodeType != 1 )
+          good = false;
+      assert( good, type + ": Select all elements, no comment nodes" );
+
+      if ( root == document ) {
+        t( ":root Selector", ":root", ["html"], false );
+      } else {
+        t( ":root Selector", ":root", [], ":root" );
+
+        if ( !root.parentNode ) {
+          t( ":root All Selector", ":root *", [], ":root" );
+        }
+      }
+
+      if ( root.parentNode || root == document ) {
+        assert( query(":root *").length == query("*").length - (root == document ? 1 : 0), type + ": :root All Selector" );
+      }
+
+      t( "Element Selector", "p", ["firstp","ap","sndp","en","sap","first"] );
+      t( "Element Selector", "body", ["body"], false );
+      t( "Element Selector", "html", ["html"], false );
+      t( "Parent Element", "div p", ["firstp","ap","sndp","en","sap","first"] );
+      var param = query("#object1 param");
+      assert( param && param.length == 2, type + ": Object/param as context" );
+
+      var l = query("#length");  
+      assert( l && l.length, type + ': &lt;input name="length"&gt; cannot be found under IE' );
+      var lin = query("#lengthtest input");
+      assert( lin && lin.length, type + ': &lt;input name="length"&gt; cannot be found under IE' );
+
+      t( "Broken Selector", "[" );
+      t( "Broken Selector", "(" );
+      t( "Broken Selector", "{" );
+      t( "Broken Selector", "<" );
+      t( "Broken Selector", "()" );
+      t( "Broken Selector", "<>" );
+      t( "Broken Selector", "{}" );
+
+      t( "ID Selector", "#body", ["body"], false );
+      t( "ID Selector w/ Element", "body#body", ["body"], false );
+      t( "ID Selector w/ Element", "ul#first", [] );
+      t( "ID selector with existing ID descendant", "#firstp #simon1", ["simon1"] );
+      t( "ID selector with non-existant descendant", "#firstp #foobar", [] );
+
+      t( "ID selector using UTF8", "#台北Táiběi", ["台北Táiběi"] );
+      t( "Multiple ID selectors using UTF8", "#台北Táiběi, #台北", ["台北Táiběi","台北"] );
+      t( "Descendant ID selector using UTF8", "div #台北", ["台北"] );
+      t( "Child ID selector using UTF8", "form > #台北", ["台北"] );
+  
+      t( "Escaped ID", "#foo\\:bar", ["foo:bar"] );
+      t( "Escaped ID", "#test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
+      t( "Descendant escaped ID", "div #foo\\:bar", ["foo:bar"] );
+      t( "Descendant escaped ID", "div #test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
+      t( "Child escaped ID", "form > #foo\\:bar", ["foo:bar"] );
+      t( "Child escaped ID", "form > #test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
+  
+      t( "ID Selector, child ID present", "#form > #radio1", ["radio1"] ); // bug #267
+      t( "ID Selector, not an ancestor ID", "#form #first", [] );
+      t( "ID Selector, not a child ID", "#form > #option1a", [] );
+      
+      t( "All Children of ID", "#foo > *", ["sndp", "en", "sap"] );
+      t( "All Children of ID with no children", "#firstUL > *", [] );
+
+      t( "ID selector with non-existant ancestor", "#asdfasdf #foobar", [] ); // bug #986
+
+      //t( "body div#form", [], "ID selector within the context of another element" );
+
+      t( "Class Selector", ".blog", ["mark","simon"] );
+      t( "Class Selector", ".blog.link", ["simon"] );
+      t( "Class Selector w/ Element", "a.blog", ["mark","simon"] );
+      t( "Parent Class Selector", "p .blog", ["mark","simon"] );
+  
+      t( "Class selector using UTF8", ".台北Táiběi", ["utf8class1"] );
+      t( "Class selector using UTF8", ".台北", ["utf8class1","utf8class2"] );
+      t( "Class selector using UTF8", ".台北Táiběi.台北", ["utf8class1"] );
+      t( "Class selector using UTF8", ".台北Táiběi, .台北", ["utf8class1","utf8class2"] );
+      t( "Descendant class selector using UTF8", "div .台北Táiběi", ["utf8class1"] );
+      t( "Child class selector using UTF8", "form > .台北Táiběi", ["utf8class1"] );
+  
+      t( "Escaped Class", ".foo\\:bar", ["foo:bar"] );
+      t( "Escaped Class", ".test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
+      t( "Descendant scaped Class", "div .foo\\:bar", ["foo:bar"] );
+      t( "Descendant scaped Class", "div .test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
+      t( "Child escaped Class", "form > .foo\\:bar", ["foo:bar"] );
+      t( "Child escaped Class", "form > .test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
+
+      t( "Comma Support", "a.blog, p", ['firstp','ap','mark','sndp','en','sap','simon','first'] );
+      t( "Comma Support", "a.blog , p", ['firstp','ap','mark','sndp','en','sap','simon','first'] );
+      t( "Comma Support", "a.blog ,p", ['firstp','ap','mark','sndp','en','sap','simon','first'] );
+      t( "Comma Support", "a.blog,p", ['firstp','ap','mark','sndp','en','sap','simon','first'] );
+
+      t( "Child", "p > a", ["simon1","google","groups","mark","yahoo","simon"] );
+      t( "Child", "p> a", ["simon1","google","groups","mark","yahoo","simon"] );
+      t( "Child", "p >a", ["simon1","google","groups","mark","yahoo","simon"] );
+      t( "Child", "p>a", ["simon1","google","groups","mark","yahoo","simon"] );
+      t( "Child w/ Class", "p > a.blog", ["mark","simon"] );
+      t( "All Children", "code > *", ["anchor1","anchor2"] );
+      t( "All Grandchildren", "p > * > *", ["anchor1","anchor2"] );
+      t( "Adjacent", "a + a", ["groups"] );
+      t( "Adjacent", "a +a", ["groups"] );
+      t( "Adjacent", "a+ a", ["groups"] );
+      t( "Adjacent", "a+a", ["groups"] );
+      t( "Adjacent", "p + p", ["ap","en","sap"] );
+      t( "Comma, Child, and Adjacent", "a + a, code > a", ["groups","anchor1","anchor2"] );
+      
+      t( "First Child", "p:first-child", ["firstp","sndp"] );
+      t( "Nth Child", "p:nth-child(1)", ["firstp","sndp"] );
+      
+      t( "Last Child", "p:last-child", ["sap"] );
+      t( "Last Child", "a:last-child", ["simon1","anchor1","mark","yahoo","anchor2","simon"] );
+  
+      t( "Nth-child", "#main form#form > *:nth-child(2)", ["text2"] );
+      t( "Nth-child", "#main form#form > :nth-child(2)", ["text2"] );
+
+      t( "Nth-child", "#form #select1 option:nth-child(3)", ["option1c"] );
+      t( "Nth-child", "#form #select1 option:nth-child(0n+3)", ["option1c"] );
+      t( "Nth-child", "#form #select1 option:nth-child(1n+0)", ["option1a", "option1b", "option1c", "option1d"] );
+      t( "Nth-child", "#form #select1 option:nth-child(1n)", ["option1a", "option1b", "option1c", "option1d"] );
+      t( "Nth-child", "#form #select1 option:nth-child(n)", ["option1a", "option1b", "option1c", "option1d"] );
+      t( "Nth-child", "#form #select1 option:nth-child(even)", ["option1b", "option1d"] );
+      t( "Nth-child", "#form #select1 option:nth-child(odd)", ["option1a", "option1c"] );
+      t( "Nth-child", "#form #select1 option:nth-child(2n)", ["option1b", "option1d"] );
+      t( "Nth-child", "#form #select1 option:nth-child(2n+1)", ["option1a", "option1c"] );
+      t( "Nth-child", "#form #select1 option:nth-child(3n)", ["option1c"] );
+      t( "Nth-child", "#form #select1 option:nth-child(3n+1)", ["option1a", "option1d"] );
+      t( "Nth-child", "#form #select1 option:nth-child(3n+2)", ["option1b"] );
+      t( "Nth-child", "#form #select1 option:nth-child(3n+3)", ["option1c"] );
+      t( "Nth-child", "#form #select1 option:nth-child(3n-1)", ["option1b"] );
+      t( "Nth-child", "#form #select1 option:nth-child(3n-2)", ["option1a", "option1d"] );
+      t( "Nth-child", "#form #select1 option:nth-child(3n-3)", ["option1c"] );
+      t( "Nth-child", "#form #select1 option:nth-child(3n+0)", ["option1c"] );
+      t( "Nth-child", "#form #select1 option:nth-child(-n+3)", ["option1a", "option1b", "option1c"] );
+
+      t( "Attribute Exists", "a[title]", ["google"] );
+      t( "Attribute Exists", "*[title]", ["google"] );
+      t( "Attribute Exists", "[title]", ["google"] );
+      
+      t( "Attribute Equals", "a[rel='bookmark']", ["simon1"] );
+      t( "Attribute Equals", 'a[rel="bookmark"]', ["simon1"] );
+      t( "Attribute Equals", "a[rel=bookmark]", ["simon1"] );
+      t( "Multiple Attribute Equals", "#form input[type='hidden'],#form input[type='radio']", ['radio1','radio2','hidden1'] );
+      t( "Multiple Attribute Equals", "#form input[type=\"hidden\"],#form input[type='radio']", ['radio1','radio2','hidden1'] );
+      t( "Multiple Attribute Equals", "#form input[type=hidden],#form input[type=radio]", ['radio1','radio2','hidden1'] );
+  
+      t( "Attribute selector using UTF8", "span[lang=中文]", ["台北"] );
+  
+      t( "Attribute Begins With", "a[href ^= 'http://www']", ["google","yahoo"] );
+      t( "Attribute Ends With", "a[href $= 'org/']", ["mark"] );
+      t( "Attribute Contains", "a[href *= 'google']", ["google","groups"] );
+  
+      // t("Select options via [selected]", "#select1 option[selected]", ["option1a"] );
+      t("Select options via [selected]", "#select1 option[selected]", [] );
+      t("Select options via [selected]", "#select2 option[selected]", ["option2d"] );
+      t("Select options via [selected]", "#select3 option[selected]", ["option3b", "option3c"] );
+  
+      t( "Grouped Form Elements", "input[name='foo[bar]']", ["hidden2"] );
+  
+      t( ":not() Existing attribute", "#form select:not([multiple])", ["select1", "select2"]);
+      t( ":not() Equals attribute", "#form select:not([name=select1])", ["select2", "select3"]);
+      t( ":not() Equals quoted attribute", "#form select:not([name='select1'])", ["select2", "select3"]);
+
+      t( "First Child", "p:first-child", ["firstp","sndp"] );
+      t( "Last Child", "p:last-child", ["sap"] );
+      t( "Only Child", "a:only-child", ["simon1","anchor1","yahoo","anchor2"] );
+      t( "Empty", "ul:empty", ["firstUL"] );
+      //t( "Enabled UI Element", "#form input:enabled", ["text1","radio1","radio2","check1","check2","hidden2","name"] );
+      t( "Disabled UI Element", "#form input:disabled", ["text2"] );
+      t( "Checked UI Element", "#form input:checked", ["radio2","check1"] );
+      t( "Element Preceded By", "p ~ div", ["foo","fx-queue","fx-tests", "moretests"] );
+      t( "Not", "a.blog:not(.link)", ["mark"] );
+    }
+  };
+  ]]></script>
+</head>
+<body id="body" class="unitTest" title="childhood and element type selectors">
+<h1><a href="http://www.w3.org/TR/selectors-api/">Selectors API</a> Test Suite</h1>
+<p>Testrunner by <a href="http://ejohn.org/">John Resig</a>, tests by <a href="http://ejohn.org/">John Resig</a>, <a href="http://disruptive-innovations.com/zoo/css3tests/selectorTest.html">Disruptive Innovations</a>, <a href="http://www.w3.org/Style/CSS/Test/CSS3/Selectors/20060307/html/index.html">W3C CSS Working Group</a>, <a href="http://jquery.com/test/">jQuery JavaScript Library</a>.</p>
+<div id="root">
+  <div class="header">
+    <h3>CSS 3 Selectors tests</h3>
+    <p>(c) <a href="http://www.disruptive-innovations.com">Disruptive Innovations</a> 2008<br/>
+    Last update: 2008-06-06</p>
+  </div>
+
+  <div class="test target">
+    <div class="unitTest skipWhenToggling" id="target" title=":target selector"></div>
+  </div>
+
+  <div class="test">
+    <div class="blox1 unitTest" title="childhood selector"></div>
+  </div>
+
+  <div class="test attributeExistence">
+    <div class="blox2 unitTest" align="center" title="attribute existence selector"></div>
+    <div class="blox3 unitTest" align="" title="attribute existence selector with empty string value"></div>
+    <div class="blox4 unitTest" valign="center" title="attribute existence selector with almost identical attribute"></div>
+    <div class="blox5 unitTest" alignv="center" title="attribute existence selector with almost identical attribute"></div>
+  </div>
+
+  <div class="test attributeValue">
+    <div class="blox6 unitTest" align="center" title="attribute value selector"></div>
+    <div class="blox6 unitTest" foo="&eacute;" title="attribute value selector with an entity in the attribute and an escaped value in the selector"></div>
+    <div class="blox6 unitTest" _foo="&eacute;" title="attribute value selector with an entity in the attribute, an escaped value in the selector, and a leading underscore in the attribute name"></div>
+  </div>
+
+  <div class="test attributeSpaceSeparatedValues">
+    <div class="blox7 foo unitTest" title="[~=] attribute selector"></div>
+    <div class="blox8 unitTest" title="[~=] attribute selector looking for empty string"></div>
+    <div class="blox9 unitTest" foo="" title="[~=] attribute selector looking for empty string in empty attribute"></div>
+    <div class="blox10 unitTest" foo="foobar" title="[~=] attribute selector looking for 'foo' in 'foobar'"></div>
+  </div>
+
+  <div class="test attrStart">
+    <div class="unitTest t1" title="[^=] attribute selector"></div>
+    <div class="unitTest t2" title="[^=] attribute selector"></div>
+    <div class="unitTest t3" align="center" title="[^=] attribute selector looking for empty string"></div>
+    <div class="unitTest t4" foo="&eacute;tagada" title="[^=] attribute selector looking for &eacute;"></div>
+  </div>
+
+  <div class="test attrEnd">
+    <div class="unitTest t1" title="[$=] attribute selector"></div>
+    <div class="unitTest t2" title="[$=] attribute selector"></div>
+    <div class="unitTest t3" align="center" title="[$=] attribute selector looking for empty string"></div>
+    <div class="unitTest t4" foo="tagada&eacute;" title="[$=] attribute selector looking for &eacute;"></div>
+  </div>
+
+  <div class="test attrMiddle">
+    <div class="unitTest t1" title="[*=] attribute selector"></div>
+    <div class="unitTest t2" title="[*=] attribute selector"></div>
+    <div class="unitTest t3" align="center" title="[*=] attribute selector looking for empty string"></div>
+    <div class="unitTest t4" foo="tagada&eacute;foo" title="[*=] attribute selector looking for &eacute;"></div>
+  </div>
+
+  <div class="test firstChild">
+    <div class="unitTest" title=":first-child selector"></div>
+    <div class="blox12 unitTest" title=":first-child selector should not match non first child"></div>
+    <div class="blox13 unitTest" title=":first-child selector should not match non first child"></div>
+  </div>
+
+  <div class="test not">
+    <div class="blox14 unitTest" title="negation pseudo-class with argument being an element type selector"></div>
+    <div class="blox15 unitTest" foo="blox15" title="negation pseudo-class with argument being an attribute selector"></div>
+    <div class="blox16 unitTest" foo="blox15" title="negation pseudo-class accepts only simple selectors for argument"></div>
+  </div>
+
+  <div class="test onlyOfType">
+    <div class="blox17 unitTest" title=":only-of-type selector"></div>
+    <p class="blox18 unitTest" title="negated :only-of-type selector"></p>
+    <p class="blox18 unitTest" title="negated :only-of-type selector"></p>
+  </div>
+
+  <div class="test nthchild1">
+    <div class="unitTest" title=":nth-child(odd) selector"></div>
+    <div class="unitTest" title=":nth-last-child(odd) selector"></div>
+    <div class="unitTest" title=":nth-child(odd) selector"></div>
+    <div class="unitTest" title=":nth-last-child(odd) selector"></div>
+    <div class="unitTest" title=":nth-child(odd) selector"></div>
+    <div class="unitTest" title=":nth-last-child(odd) selector"></div>
+  </div>
+  <div class="test nthchild2">
+    <div class="unitTest" title=":nth-last-child(even) selector"></div>
+    <div class="unitTest" title=":nth-child(even) selector"></div>
+    <div class="unitTest" title=":nth-last-child(even) selector"></div>
+    <div class="unitTest" title=":nth-child(even) selector"></div>
+    <div class="unitTest" title=":nth-last-child(even) selector"></div>
+    <div class="unitTest" title=":nth-child(even) selector"></div>
+  </div>
+  <div class="test nthchild3">
+    <div class="unitTest no" title=":nth-last-child(3n+3) selector"></div>
+    <div class="unitTest" title=":nth-child(3n+2) selector"></div>
+    <div class="unitTest no" title=":nth-last-child(3n+1) selector"></div>
+    <div class="unitTest no" title=":nth-last-child(3n+3) selector"></div>
+    <div class="unitTest" title=":nth-child(3n+2) selector"></div>
+    <div class="unitTest no" title=":nth-last-child(3n+1) selector"></div>
+  </div>
+
+  <div class="test nthoftype1">
+    <div class="unitTest" title=":nth-of-type(odd) selector"></div>
+    <p class="unitTest" title=":nth-* selector"></p>
+    <p class="unitTest" title=":nth-* selector"></p>
+    <div class="unitTest" title=":nth-last-of-type(odd) selector"></div>
+    <p class="unitTest" title=":nth-* selector"></p>
+    <div class="unitTest" title=":nth-of-type(odd) selector"></div>
+    <div class="unitTest" title=":nth-last-of-type(odd) selector"></div>
+  </div>
+  <div class="test nthoftype2">
+    <div class="unitTest" title=":nth-last-of-type(even) selector"></div>
+    <p class="unitTest" title=":nth-* selector"></p>
+    <p class="unitTest" title=":nth-* selector"></p>
+    <div class="unitTest" title=":nth-of-type(even) selector"></div>
+    <p class="unitTest" title=":nth-* selector"></p>
+    <div class="unitTest" title=":nth-last-of-type(even) selector"></div>
+    <div class="unitTest" title=":nth-of-type(even) selector"></div>
+  </div>
+  <div class="test nthoftype3">
+    <div class="unitTest" title=":nth-of-type(3n+1) selector"></div>
+    <p class="unitTest" title=":nth-* selector"></p>
+    <p class="unitTest" title=":nth-* selector"></p>
+    <div class="unitTest" title=":nth-last-of-type(3n+2) selector"></div>
+    <p class="unitTest" title=":nth-* selector"></p>
+    <div class="unitTest" title=":nth-last-of-type(3n+1) selector"></div>
+    <div class="unitTest" title=":nth-of-type(3n+1) selector"></div>
+    <p class="unitTest" title=":nth-* selector"></p>
+    <div class="unitTest" title=":nth-last-of-type(3n+2) selector"></div>
+    <div class="unitTest" title=":nth-last-of-type(3n+1) selector"></div>
+  </div>
+
+  <div class="test lastChild">
+    <p class="unitTest" title=":not(:last-child) selector"></p>
+    <div class="unitTest" title=":last-child selector"></div>&nbsp;
+  </div>
+
+  <div class="test firstOfType">
+    <p class="unitTest" title=":first-of-type selector"></p>
+    <div class="unitTest" title=":first-of-type selector"></div>
+    <p class="unitTest" title=":not(:first-of-type)"></p>
+    <div class="unitTest" title=":not(:first-of-type)"></div>
+  </div>
+
+  <div class="test lastOfType">
+    <p class="unitTest" title=":not(:last-of-type)"></p>
+    <div class="unitTest" title=":not(:last-of-type)"></div>
+    <p class="unitTest" title=":last-of-type selector"></p>
+    <div class="unitTest" title=":last-of-type selector"></div>
+  </div>
+
+  <div class="test onlyChild">
+    <div class="unitTest" title=":only-child where the element is NOT the only child"></div>
+    <div class="unitTest" title=":only-child where the element is the only child">
+      <div class="unitTest" title=":only-child where the element is the only child"></div>
+    </div>
+  </div>
+
+  <div class="test onlyOfType">
+    <p class="unitTest" title=":only-of-type"></p>
+    <div class="unitTest" title=":only-of-type">
+      <div class="unitTest" title=":only-of-type"></div>
+    </div>
+    <div class="unitTest" title=":not(only-of-type)"></div>
+  </div>
+
+  <div class="test empty">
+    <div class="unitTest isEmpty" title=":empty with empty element"></div>
+    <div class="unitTest isNotEmpty" title=":empty but element contains a whitespace"> </div>
+    <div class="unitTest isEmpty" title=":empty and element contains an SGML comment"><!-- foo --></div>
+    <div class="unitTest isNotEmpty" title=":empty but element contains a SPAN element"><span></span></div>
+    <div class="unitTest isNotEmpty" title=":empty but element contains an entity reference">&nbsp;</div>
+  </div>
+
+  <div class="test lang">
+    <div id="nofragment" class="unitTest" title=":lang() where language comes from the document"></div>
+    <div class="unitTest" lang="fr" title=":lang() where language comes from the element"></div>
+    <div class="unitTest" lang="en-US" title=":lang() where language comes from the element but is a dialect of the language queried"></div>
+    <div class="unitTest t1" lang="es" title=":lang() where language comes from the element but the language queried is a dialect of the element's one so it should not match"></div>
+  </div>
+
+  <div class="test attrLang">
+    <div class="unitTest t1" title="[|=] where language comes from the document"></div>
+    <div class="unitTest" lang="fr" title="[|=] where language comes from the element"></div>
+    <div class="unitTest t2" lang="en-US" title="[|=] where language comes from the element but is a dialect of the language queried"></div>
+    <div class="unitTest t3" lang="es" title="[|=] where language comes from the element but the language queried is a dialect of the element's one so it should not match"></div>
+  </div>
+
+  <div class="test UI">
+    <button name="submit" type="submit" value="submit" class="t1"  title=":enabled pseudo-class"><div class="unitTest"></div></button>
+    <button name="submit" type="submit" value="submit" class="t2" disabled="true"  title=":enabled pseudo-class"><div class="unitTest"></div></button>
+  </div>
+  <div class="test UI">
+    <input class="t3" type="checkbox" checked="true"/><div class="unitTest" title=":checked"></div>
+    the previous square should be green when the checkbox is checked and become red when you uncheck it
+  </div>
+  <div class="test UI">
+    <input class="t4" type="checkbox"/><div class="unitTest" title=":not(:checked)"></div>
+    the previous square should be green when the checkbox is NOT checked and become red when you check it
+  </div>
+
+  <div class="test tilda">
+    <div class="unitTest t1" title="~ combinator"></div>
+    <div class="unitTest" title="~ combinator"></div>
+    <div class="unitTest" title="~ combinator"></div>
+    <div class="unitTest" title="~ combinator"></div>
+    <span style="float:left">the three last squares should be green and become red when the pointer hovers over the white square</span>
+  </div>
+  <div class="test plus">
+    <div class="unitTest t1" title="+ combinator"></div>
+    <div class="unitTest t2" title="+ combinator"></div>
+    <div class="unitTest" title="+ combinator"></div>
+    <span style="float:left">the last square should be green and become red when the pointer hovers over the FIRST white square</span>
+  </div>
+</div>
+<div id="root2">
+  <div class="header">
+    <h3>CSS 3 Selectors tests</h3>
+    <p>(c) <a href="http://www.disruptive-innovations.com">Disruptive Innovations</a> 2008<br/>
+    Last update: 2008-06-06</p>
+  </div>
+
+  <div class="test">
+    <div class="blox1 unitTest" title="childhood selector"></div>
+  </div>
+
+  <div class="test attributeExistence">
+    <div class="blox2 unitTest" align="center" title="attribute existence selector"></div>
+    <div class="blox3 unitTest" align="" title="attribute existence selector with empty string value"></div>
+    <div class="blox4 unitTest" valign="center" title="attribute existence selector with almost identical attribute"></div>
+    <div class="blox5 unitTest" alignv="center" title="attribute existence selector with almost identical attribute"></div>
+  </div>
+
+  <div class="test attributeValue">
+    <div class="blox6 unitTest" align="center" title="attribute value selector"></div>
+    <div class="blox6 unitTest" foo="&eacute;" title="attribute value selector with an entity in the attribute and an escaped value in the selector"></div>
+    <div class="blox6 unitTest" _foo="&eacute;" title="attribute value selector with an entity in the attribute, an escaped value in the selector, and a leading underscore in the attribute name"></div>
+  </div>
+
+  <div class="test attributeSpaceSeparatedValues">
+    <div class="blox7 foo unitTest" title="[~=] attribute selector"></div>
+    <div class="blox8 unitTest" title="[~=] attribute selector looking for empty string"></div>
+    <div class="blox9 unitTest" foo="" title="[~=] attribute selector looking for empty string in empty attribute"></div>
+    <div class="blox10 unitTest" foo="foobar" title="[~=] attribute selector looking for 'foo' in 'foobar'"></div>
+  </div>
+
+  <div class="test attrStart">
+    <div class="unitTest t1" title="[^=] attribute selector"></div>
+    <div class="unitTest t2" title="[^=] attribute selector"></div>
+    <div class="unitTest t3" align="center" title="[^=] attribute selector looking for empty string"></div>
+    <div class="unitTest t4" foo="&eacute;tagada" title="[^=] attribute selector looking for &eacute;"></div>
+  </div>
+
+  <div class="test attrEnd">
+    <div class="unitTest t1" title="[$=] attribute selector"></div>
+    <div class="unitTest t2" title="[$=] attribute selector"></div>
+    <div class="unitTest t3" align="center" title="[$=] attribute selector looking for empty string"></div>
+    <div class="unitTest t4" foo="tagada&eacute;" title="[$=] attribute selector looking for &eacute;"></div>
+  </div>
+
+  <div class="test attrMiddle">
+    <div class="unitTest t1" title="[*=] attribute selector"></div>
+    <div class="unitTest t2" title="[*=] attribute selector"></div>
+    <div class="unitTest t3" align="center" title="[*=] attribute selector looking for empty string"></div>
+    <div class="unitTest t4" foo="tagada&eacute;foo" title="[*=] attribute selector looking for &eacute;"></div>
+  </div>
+
+  <div class="test firstChild">
+    <div class="unitTest" title=":first-child selector"></div>
+    <div class="blox12 unitTest" title=":first-child selector should not match non first child"></div>
+    <div class="blox13 unitTest" title=":first-child selector should not match non first child"></div>
+  </div>
+
+  <div class="test not">
+    <div class="blox14 unitTest" title="negation pseudo-class with argument being an element type selector"></div>
+    <div class="blox15 unitTest" foo="blox15" title="negation pseudo-class with argument being an attribute selector"></div>
+    <div class="blox16 unitTest" foo="blox15" title="negation pseudo-class accepts only simple selectors for argument"></div>
+  </div>
+
+  <div class="test onlyOfType">
+    <div class="blox17 unitTest" title=":only-of-type selector"></div>
+    <p class="blox18 unitTest" title="negated :only-of-type selector"></p>
+    <p class="blox18 unitTest" title="negated :only-of-type selector"></p>
+  </div>
+
+  <div class="test nthchild1">
+    <div class="unitTest" title=":nth-child(odd) selector"></div>
+    <div class="unitTest" title=":nth-last-child(odd) selector"></div>
+    <div class="unitTest" title=":nth-child(odd) selector"></div>
+    <div class="unitTest" title=":nth-last-child(odd) selector"></div>
+    <div class="unitTest" title=":nth-child(odd) selector"></div>
+    <div class="unitTest" title=":nth-last-child(odd) selector"></div>
+  </div>
+  <div class="test nthchild2">
+    <div class="unitTest" title=":nth-last-child(even) selector"></div>
+    <div class="unitTest" title=":nth-child(even) selector"></div>
+    <div class="unitTest" title=":nth-last-child(even) selector"></div>
+    <div class="unitTest" title=":nth-child(even) selector"></div>
+    <div class="unitTest" title=":nth-last-child(even) selector"></div>
+    <div class="unitTest" title=":nth-child(even) selector"></div>
+  </div>
+  <div class="test nthchild3">
+    <div class="unitTest no" title=":nth-last-child(3n+3) selector"></div>
+    <div class="unitTest" title=":nth-child(3n+2) selector"></div>
+    <div class="unitTest no" title=":nth-last-child(3n+1) selector"></div>
+    <div class="unitTest no" title=":nth-last-child(3n+3) selector"></div>
+    <div class="unitTest" title=":nth-child(3n+2) selector"></div>
+    <div class="unitTest no" title=":nth-last-child(3n+1) selector"></div>
+  </div>
+
+  <div class="test nthoftype1">
+    <div class="unitTest" title=":nth-of-type(odd) selector"></div>
+    <p class="unitTest" title=":nth-of-* selector"></p>
+    <p class="unitTest" title=":nth-of-* selector"></p>
+    <div class="unitTest" title=":nth-last-of-type(odd) selector"></div>
+    <p class="unitTest" title=":nth-of-* selector"></p>
+    <div class="unitTest" title=":nth-of-type(odd) selector"></div>
+    <div class="unitTest" title=":nth-last-of-type(odd) selector"></div>
+  </div>
+  <div class="test nthoftype2">
+    <div class="unitTest" title=":nth-last-of-type(even) selector"></div>
+    <p class="unitTest" title=":nth-of-* selector"></p>
+    <p class="unitTest" title=":nth-of-* selector"></p>
+    <div class="unitTest" title=":nth-of-type(even) selector"></div>
+    <p class="unitTest" title=":nth-of-* selector"></p>
+    <div class="unitTest" title=":nth-last-of-type(even) selector"></div>
+    <div class="unitTest" title=":nth-of-type(even) selector"></div>
+  </div>
+  <div class="test nthoftype3">
+    <div class="unitTest" title=":nth-of-type(3n+1) selector"></div>
+    <p class="unitTest" title=":nth-of-* selector"></p>
+    <p class="unitTest" title=":nth-of-* selector"></p>
+    <div class="unitTest" title=":nth-last-of-type(3n+2) selector"></div>
+    <p class="unitTest" title=":nth-of-* selector"></p>
+    <div class="unitTest" title=":nth-last-of-type(3n+1) selector"></div>
+    <div class="unitTest" title=":nth-of-type(3n+1) selector"></div>
+    <p class="unitTest" title=":nth-of-* selector"></p>
+    <div class="unitTest" title=":nth-last-of-type(3n+2) selector"></div>
+    <div class="unitTest" title=":nth-last-of-type(3n+1) selector"></div>
+  </div>
+
+  <div class="test lastChild">
+    <p class="unitTest" title=":not(:last-child) selector"></p>
+    <div class="unitTest" title=":last-child selector"></div>&nbsp;
+  </div>
+
+  <div class="test firstOfType">
+    <p class="unitTest" title=":first-of-type selector"></p>
+    <div class="unitTest" title=":first-of-type selector"></div>
+    <p class="unitTest" title=":not(:first-of-type)"></p>
+    <div class="unitTest" title=":not(:first-of-type)"></div>
+  </div>
+
+  <div class="test lastOfType">
+    <p class="unitTest" title=":not(:last-of-type)"></p>
+    <div class="unitTest" title=":not(:last-of-type)"></div>
+    <p class="unitTest" title=":last-of-type selector"></p>
+    <div class="unitTest" title=":last-of-type selector"></div>
+  </div>
+
+  <div class="test onlyChild">
+    <div class="unitTest" title=":only-child where the element is NOT the only child"></div>
+    <div class="unitTest" title=":only-child where the element is the only child">
+      <div class="unitTest" title=":only-child where the element is the only child"></div>
+    </div>
+  </div>
+
+  <div class="test onlyOfType">
+    <p class="unitTest" title=":only-of-type"></p>
+    <div class="unitTest" title=":only-of-type">
+      <div class="unitTest" title=":only-of-type"></div>
+    </div>
+    <div class="unitTest" title=":not(only-of-type)"></div>
+  </div>
+
+  <div class="test empty">
+    <div class="unitTest isEmpty" title=":empty with empty element"></div>
+    <div class="unitTest isNotEmpty" title=":empty but element contains a whitespace"> </div>
+    <div class="unitTest isEmpty" title=":empty and element contains an SGML comment"><!-- foo --></div>
+    <div class="unitTest isNotEmpty" title=":empty but element contains a SPAN element"><span></span></div>
+    <div class="unitTest isNotEmpty" title=":empty but element contains an entity reference">&nbsp;</div>
+  </div>
+
+  <div class="test lang">
+    <div id="nofragment" class="unitTest" title=":lang() where language comes from the document"></div>
+    <div class="unitTest" lang="fr" title=":lang() where language comes from the element"></div>
+    <div class="unitTest" lang="en-US" title=":lang() where language comes from the element but is a dialect of the language queried"></div>
+    <div class="unitTest t1" lang="es" title=":lang() where language comes from the element but the language queried is a dialect of the element's one so it should not match"></div>
+  </div>
+
+  <div class="test attrLang">
+    <div class="unitTest t1" title="[|=] where language comes from the document"></div>
+    <div class="unitTest" lang="fr" title="[|=] where language comes from the element"></div>
+    <div class="unitTest t2" lang="en-US" title="[|=] where language comes from the element but is a dialect of the language queried"></div>
+    <div class="unitTest t3" lang="es" title="[|=] where language comes from the element but the language queried is a dialect of the element's one so it should not match"></div>
+  </div>
+
+  <div class="test UI">
+    <button name="submit" type="submit" value="submit" class="t1"  title=":enabled pseudo-class"><div class="unitTest"></div></button>
+    <button name="submit" type="submit" value="submit" class="t2" disabled="true"  title=":enabled pseudo-class"><div class="unitTest"></div></button>
+  </div>
+  <div class="test UI">
+    <input class="t3" type="checkbox" checked="true"/><div class="unitTest" title=":checked"></div>
+    the previous square should be green when the checkbox is checked and become red when you uncheck it
+  </div>
+  <div class="test UI">
+    <input class="t4" type="checkbox"/><div class="unitTest" title=":not(:checked)"></div>
+    the previous square should be green when the checkbox is NOT checked and become red when you check it
+  </div>
+
+  <div class="test tilda">
+    <div class="unitTest t1" title="~ combinator"></div>
+    <div class="unitTest" title="~ combinator"></div>
+    <div class="unitTest" title="~ combinator"></div>
+    <div class="unitTest" title="~ combinator"></div>
+    <span style="float:left">the three last squares should be green and become red when the pointer hovers over the white square</span>
+  </div>
+  <div class="test plus">
+    <div class="unitTest t1" title="+ combinator"></div>
+    <div class="unitTest t2" title="+ combinator"></div>
+    <div class="unitTest" title="+ combinator"></div>
+    <span style="float:left">the last square should be green and become red when the pointer hovers over the FIRST white square</span>
+  </div>
+</div>
+<div id="root3">
+  <div id="svgs">
+  <!-- svg elements, but in the xhtml namespace -->
+  <svg width="12cm" height="4cm" viewBox="0 0 1200 400" version="1.1" id="svg1">
+    <desc id="desc1">Example circle01 - circle filled with red and stroked with blue</desc>
+    <rect id="rect1" x="1" y="1" width="1198" height="398" fill="none" stroke="blue" stroke-width="2"/>
+    <circle id="circle1" cx="600" cy="200" r="100" fill="red" stroke="blue" stroke-width="10"  />
+  </svg>
+  <!-- svg elements using svg: -->
+  <svg:svg width="12cm" height="4cm" viewBox="0 0 1200 400" version="1.1" id="svg2">
+    <svg:desc id="desc2">Example circle01 - circle filled with red and stroked with blue</svg:desc>
+    <svg:rect id="rect2" x="1" y="1" width="1198" height="398" fill="none" stroke="blue" stroke-width="2"/>
+    <svg:circle id="circle2" cx="600" cy="200" r="100" fill="red" stroke="blue" stroke-width="10"  />
+  </svg:svg>
+  <!-- svg using an inline xmlns -->
+  <svg width="12cm" height="4cm" viewBox="0 0 1200 400" xmlns="http://www.w3.org/2000/svg" version="1.1" id="svg3">
+    <desc id="desc3">Example circle01 - circle filled with red and stroked with blue</desc>
+    <rect id="rect3" x="1" y="1" width="1198" height="398" fill="none" stroke="blue" stroke-width="2"/>
+    <circle id="circle3" cx="600" cy="200" r="100" fill="red" stroke="blue" stroke-width="10"  />
+  </svg>
+  </div>
+
+  <h1 id="header">jQuery Test Suite</h1>
+  <h2 id="banner"></h2>
+  <h2 id="userAgent"></h2>
+  
+  <!-- Test HTML -->
+  <div id="nothiddendiv" style="height:1px;background:white;">
+
+    <div id="nothiddendivchild"></div>
+  </div>
+  <!-- this iframe is outside the #main so it won't reload constantly wasting time, but it means the tests must be "safe" and clean up after themselves -->
+  <iframe id="loadediframe" name="loadediframe" style="display:none;" src="data/iframe.html"></iframe>
+  <dl id="dl" style="display:none;">
+  <div id="main" style="display: none;">
+    <p id="firstp">See <a id="simon1" href="http://simon.incutio.com/archive/2003/03/25/#getElementsBySelector" rel="bookmark">this blog entry</a> for more information.</p>
+
+    <p id="ap">
+      Here are some links in a normal paragraph: <a id="google" href="http://www.google.com/" title="Google!">Google</a>, 
+      <a id="groups" href="http://groups.google.com/">Google Groups</a>. 
+      This link has <code><a href="http://smin" id="anchor1">class="blog"</a></code>: 
+      <a href="http://diveintomark.org/" class="blog" hreflang="en" id="mark">diveintomark</a>
+
+    </p>
+    <div id="foo">
+
+      <p id="sndp">Everything inside the red border is inside a div with <code>id="foo"</code>.</p>
+      <p lang="en" id="en">This is a normal link: <a id="yahoo" href="http://www.yahoo.com/" class="blogTest">Yahoo</a></p>
+      <p id="sap">This link has <code><a href="#2" id="anchor2">class="blog"</a></code>: <a href="http://simon.incutio.com/" class="blog link" id="simon">Simon Willison's Weblog</a></p>
+
+    </div>
+
+    <p id="first">Try them out:</p>
+    <ul id="firstUL"></ul>
+    <ol id="empty"></ol>
+    <form id="form" action="formaction">
+      <input type="text" name="action" value="Test" id="text1" maxlength="30"/>
+      <input type="text" name="text2" value="Test" id="text2" disabled="disabled"/>
+      <input type="radio" name="radio1" id="radio1" value="on"/>
+
+      <input type="radio" name="radio2" id="radio2" checked="checked"/>
+
+      <input type="checkbox" name="check" id="check1" checked="checked"/>
+      <input type="checkbox" id="check2" value="on"/>
+
+      <input type="hidden" name="hidden" id="hidden1"/>
+      <input type="text" style="display:none;" name="foo[bar]" id="hidden2"/>
+      
+      <input type="text" id="name" name="name" value="name" />
+      
+      <button id="button" name="button">Button</button>
+      
+      <textarea id="area1" maxlength="30">foobar</textarea>
+
+      
+      <select name="select1" id="select1">
+        <option id="option1a" class="emptyopt" value="">Nothing</option>
+        <option id="option1b" value="1">1</option>
+        <option id="option1c" value="2">2</option>
+        <option id="option1d" value="3">3</option>
+      </select>
+      <select name="select2" id="select2">
+
+        <option id="option2a" class="emptyopt" value="">Nothing</option>
+        <option id="option2b" value="1">1</option>
+        <option id="option2c" value="2">2</option>
+        <option id="option2d" selected="selected" value="3">3</option>
+      </select>
+      <select name="select3" id="select3" multiple="multiple">
+        <option id="option3a" class="emptyopt" value="">Nothing</option>
+
+        <option id="option3b" selected="selected" value="1">1</option>
+        <option id="option3c" selected="selected" value="2">2</option>
+        <option id="option3d" value="3">3</option>
+      </select>
+      
+      <object id="object1" codebase="stupid">
+        <param name="p1" value="x1" />
+        <param name="p2" value="x2" />
+
+      </object>
+      
+      <span id="台北Táiběi"></span>
+      <span id="台北" lang="中文"></span>
+      <span id="utf8class1" class="台北Táiběi 台北"></span>
+      <span id="utf8class2" class="台北"></span>
+      <span id="foo:bar" class="foo:bar"></span>
+      <span id="test.foo[5]bar" class="test.foo[5]bar"></span>
+      
+      <foo_bar id="foobar">test element</foo_bar>
+
+    </form>
+    <b id="floatTest">Float test.</b>
+    <iframe id="iframe" name="iframe"></iframe>
+    <form id="lengthtest">
+      <input type="text" id="length" name="test"/>
+      <input type="text" id="idTest" name="id"/>
+    </form>
+    <table id="table"></table>
+
+    
+    <div id="fx-queue">
+      <div id="fadein" class='chain test'>fadeIn<div>fadeIn</div></div>
+      <div id="fadeout" class='chain test out'>fadeOut<div>fadeOut</div></div>
+      
+      <div id="show" class='chain test'>show<div>show</div></div>
+      <div id="hide" class='chain test out'>hide<div>hide</div></div>
+
+      
+      <div id="togglein" class='chain test'>togglein<div>togglein</div></div>
+      <div id="toggleout" class='chain test out'>toggleout<div>toggleout</div></div>
+    
+      
+      <div id="slideup" class='chain test'>slideUp<div>slideUp</div></div>
+      <div id="slidedown" class='chain test out'>slideDown<div>slideDown</div></div>
+      
+      <div id="slidetogglein" class='chain test'>slideToggleIn<div>slideToggleIn</div></div>
+
+      <div id="slidetoggleout" class='chain test out'>slideToggleOut<div>slideToggleOut</div></div>
+    </div>
+    
+    <div id="fx-tests"></div>
+
+    <form id="testForm" action="#" method="get">
+      <textarea name="T3" rows="2" cols="15">?
+Z</textarea>
+      <input type="hidden" name="H1" value="x" />
+      <input type="hidden" name="H2" />
+
+      <input name="PWD" type="password" value="" />
+      <input name="T1" type="text" />
+      <input name="T2" type="text" value="YES" readonly="readonly" />
+      <input type="checkbox" name="C1" value="1" />
+      <input type="checkbox" name="C2" />
+      <input type="radio" name="R1" value="1" />
+      <input type="radio" name="R1" value="2" />
+      <input type="text" name="My Name" value="me" />
+      <input type="reset" name="reset" value="NO" />
+
+      <select name="S1">
+        <option value="abc">ABC</option>
+        <option value="abc">ABC</option>
+        <option value="abc">ABC</option>
+      </select>
+      <select name="S2" multiple="multiple" size="3">
+        <option value="abc">ABC</option>
+
+        <option value="abc">ABC</option>
+        <option value="abc">ABC</option>
+      </select>
+      <select name="S3">
+        <option selected="selected">YES</option>
+      </select>
+      <select name="S4">
+
+        <option value="" selected="selected">NO</option>
+      </select>
+      <input type="submit" name="sub1" value="NO" />
+      <input type="submit" name="sub2" value="NO" />
+      <input type="image" name="sub3" value="NO" />
+      <button name="sub4" type="submit" value="NO">NO</button>
+      <input name="D1" type="text" value="NO" disabled="disabled" />
+      <input type="checkbox" checked="checked" disabled="disabled" name="D2" value="NO" />
+
+      <input type="radio" name="D3" value="NO" checked="checked" disabled="disabled" />
+      <select name="D4" disabled="disabled">
+        <option selected="selected" value="NO">NO</option>
+      </select>
+    </form>
+    <div id="moretests">
+      <form>
+        <div id="checkedtest" style="display:none;">
+
+          <input type="radio" name="checkedtestradios" checked="checked"/>
+          <input type="radio" name="checkedtestradios" value="on"/>
+          <input type="checkbox" name="checkedtestcheckboxes" checked="checked"/>
+          <input type="checkbox" name="checkedtestcheckboxes" />
+        </div>
+      </form>
+      <div id="nonnodes"><span>hi</span> there <!-- mon ami --></div>
+
+      <div id="t2037">
+        <div><div class="hidden">hidden</div></div>
+      </div>
+    </div>
+  </div>
+  </dl>
+  
+  <ol id="tests"></ol>
+</div>
+<ol id="results"></ol>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_NodeIterator_basics_filters.xhtml
@@ -0,0 +1,117 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!-- NodeIterator basics and filters tests.
+     Originally written by Ian Hickson, Mochi-ified by Zack Weinberg.
+     This file based on 001.xml, 002.xml, and 010.xml from
+       http://hixie.ch/tests/adhoc/dom/traversal/node-iterator/
+     with some additional cases.
+  -->
+<head>
+  <title>DOM Traversal: NodeIterator: Basics and Filters</title>
+  <script type="text/javascript" src="/MochiKit/packed.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>
+<p id="display"></p>
+<div id="content" style="display: none">
+<!-- comment -->
+<?body processing instruction?>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript"><![CDATA[
+  function compare_arrays(e, f, label) {
+    var length = (e.length > f.length) ? e.length : f.length;
+    for (var i = 0; i < length; i += 1) {
+      if (e[i] > 0) 
+        is(f[i], e[i], label + " - index " + i + ": ");
+      else
+        todo_is(f[i], -e[i], label + " - index " + i + ": ");
+    }
+  }
+
+  /** DOM Traversal: NodeIterator: Basics **/
+  // NOTE: If you change the document structure, you have to make sure
+  // the magic numbers in this array (and 'expected_f', below) match.
+  var expected = new Array(9, // document
+                           1, // html
+                           3, 8, // leading comment
+                           3, 1, // head
+                           3, 1, 3, // title
+                           3, 1, // first script tag
+                           3, 1, // second script tag
+                           3, 1, // stylesheet tag
+                           3,    // close head
+                           3, 1, // body
+                           3, 1, // p#display
+                           3, 1, // div#content
+                           3, 8, // comment
+                           3, 7, // processing instruction
+                           3,    // close div
+                           3, 1, // pre#test
+                           3, 1, 4, // script and CDATA block
+                           -3, -3, -3); // close close close
+                                        // these aren't there
+                                        // not sure why
+  var found = new Array();
+
+  var iterator = document.createNodeIterator(document,
+                                             NodeFilter.SHOW_ALL,
+                                             null, false);
+  var node;
+
+  // forwards
+  while (node = iterator.nextNode())
+    found.push(node.nodeType);
+  compare_arrays(expected, found, 'basics forward');
+
+  // backwards
+  found.length = 0;
+  while (node = iterator.previousNode())
+    found.unshift(node.nodeType);
+  compare_arrays(expected, found, 'basics backward');
+
+  /** DOM Traversal: NodeIterator: Filters **/
+  function filter(n) {
+    if (n.nodeType == 3) {
+      return NodeFilter.FILTER_SKIP;
+    } else if (n.nodeName == 'body') {
+      return NodeFilter.FILTER_REJECT; // same as _SKIP
+    }
+    return 1; // FILTER_ACCEPT
+  }
+
+  // Same warning applies to this array as to 'expected'.
+  var expect_f = new Array(9, // document
+                           1, // html
+                           8, // leading comment
+                           1, // head
+                           1, // title
+                           1, // first script tag
+                           1, // second script tag
+                           1, // stylesheet tag
+                           // body skipped
+                           1, // p#display
+                           1, // div#content
+                           8, // comment
+                           // processing instruction skipped
+                           1, // pre#test
+                           1, 4); // script and CDATA block
+
+  found.length = 0;
+  iterator = document.createNodeIterator(document, NodeFilter.SHOW_ALL,
+                                         filter, false);
+
+  // forwards
+  while (node = iterator.nextNode())
+    found.push(node.nodeType);
+  compare_arrays(expect_f, found, 'filtered forward');
+
+  // backwards
+  found.length = 0;
+  while (node = iterator.previousNode())
+    found.unshift(node.nodeType);
+  compare_arrays(expect_f, found, 'filtered backward');
+]]></script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_NodeIterator_mutations_1.xhtml
@@ -0,0 +1,205 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!-- NodeIterator mutation tests.
+     Originally written by Ian Hickson, Mochi-ified by Zack Weinberg.
+     This file based on 00[3-9].xml from
+       http://hixie.ch/tests/adhoc/dom/traversal/node-iterator/
+  -->
+<head>
+  <title>DOM Traversal: NodeIterator: Mutations (1/x)</title>
+  <script type="text/javascript" src="/MochiKit/packed.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>
+<p id="display"></p>
+<div id="content" style="display: none">
+<span id="X"></span><span id="Y"><span id="root1"><span id="A"><span id="B"><span id="C"><span id="D"><span id="E"></span></span></span></span></span></span></span>
+<span id="root2"><span id="F"><span id="FF"></span></span><span id="G"></span><span id="H"><span id="HH"></span></span></span>
+<span id="root3"><span id="I"><span id="II"></span></span><span id="J"></span><span id="K"><span id="KK"></span></span></span>
+<span id="root4"><span id="L"></span><span id="M"><span id="MM"></span></span><span id="N"></span></span>
+<span id="root5"><span id="O"></span><span id="P"><span id="PP"></span></span><span id="Q"></span></span>
+<span id="root6"><span id="R"></span><span id="S"><span id="SS"></span></span><span id="T"></span></span>
+<span id="root7"><span id="U"></span><span id="V"><span id="VV"></span></span><span id="W"></span></span>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript"><![CDATA[
+  /** Originally written by Ian Hickson. **/
+
+  function check(f, e, label) {
+    var eid = e.id;
+    var fid = f ? f.id : 'null';
+    is(f, e, label + ': expected ' + eid + ' have ' + fid);
+  }
+
+  var childid = 0;
+  function addChildTo(a) {
+    var x = document.createElementNS('http://www.w3.org/1999/xhtml', 'span');
+    x.id = 'X' + childid;
+    childid++;
+    ok(a, 'parent ' + (a?a.id:'undefined') + ' for child ' + x.id);
+    if (a)
+      a.appendChild(x);
+    return x;
+  }
+  function remove(a) {
+    var p = a.parentNode;
+    ok(a && p,
+       'removing ' + ( a?(a.id?a.id:'(no id)'):'undefined' )
+       + ' with parent ' + ( p?(p.id?p.id:'(no id)'):'undefined' ));
+    if (a && p)
+      p.removeChild(a);
+  }
+
+  /** Removal of nodes that should have no effect **/
+  (function () {
+    var root = $('root1');
+    var A = $('A');
+    var B = $('B');
+    var C = $('C');
+    var D = $('D');
+    var E = $('E');
+
+    var iterator = document.createNodeIterator(root, NodeFilter.SHOW_ALL,
+					       null, false);
+    check(iterator.nextNode(), root, '1.0');
+
+    // 1. Remove a node unrelated to the reference node
+    remove($('X'));
+    check(iterator.nextNode(), A, '1.1');
+
+    // 2. Remove an ancestor of the root node
+    remove($('Y'));
+    check(iterator.nextNode(), B, '1.2');
+
+    // 3. Remove the root node itself
+    remove(root);
+    check(iterator.nextNode(), C, '1.3');
+
+    // 4. Remove a descendant of the reference node
+    remove(E);
+    check(iterator.nextNode(), D, '1.4');
+  })();
+
+  /** Removal of the reference node **/
+  (function () {
+    var root = $('root2');
+    var F = $('F');
+    var FF = $('FF');
+    var G = $('G');
+    var H = $('H');
+    var iterator = document.createNodeIterator(root, NodeFilter.SHOW_ALL,
+					       null, false);
+
+    check(iterator.nextNode(), root, '2.0');
+    check(iterator.nextNode(), F,    '2.1');
+    check(iterator.nextNode(), FF,   '2.2');
+    check(iterator.nextNode(), G,    '2.3');
+    remove(G);
+    check(iterator.previousNode(), FF, '2.4');
+    remove(FF);
+    check(iterator.nextNode(), H, '2.5');
+  })();
+
+  /** Removal of the reference node (deep check) **/
+  (function () {
+    var root = $('root3');
+    var I = $('I');
+    var II = $('II');
+    var J = $('J');
+    var K = $('K');
+    var KK = $('KK');
+
+    var iterator = document.createNodeIterator(root, NodeFilter.SHOW_ALL,
+					       null, false);
+    check(iterator.nextNode(), root, '3.0');
+    check(iterator.nextNode(), I, '3.1');
+    check(iterator.nextNode(), II, '3.2');
+    check(iterator.nextNode(), J, '3.3');
+    remove(J);
+    var X = addChildTo(II);
+    check(iterator.nextNode(), X, '3.4');
+    check(iterator.previousNode(), X, '3.5');
+    remove(X);
+    var Y = addChildTo(II);
+    check(iterator.previousNode(), Y, '3.6');
+    check(iterator.nextNode(), Y, '3.7');
+    check(iterator.nextNode(), K, '3.8');
+    check(iterator.nextNode(), KK, '3.9');
+  })();
+
+  /** Removal of an ancestor of the Reference Node (forwards) **/
+  (function () {
+    var root = $('root4');
+    var L = $('L');
+    var M = $('M');
+    var MM = $('MM');
+    var N = $('N');
+
+    var iterator = document.createNodeIterator(root, NodeFilter.SHOW_ALL,
+					       null, false);
+    check(iterator.nextNode(), root, '4.1');
+    check(iterator.nextNode(), L, '4.2');
+    check(iterator.nextNode(), M, '4.3');
+    check(iterator.nextNode(), MM, '4.4');
+    remove(M);
+    check(iterator.previousNode(), L, '4.5');
+  })();
+
+  /** Removal of an ancestor of the Reference Node (forwards) (deep check) **/
+  (function () {
+    var root = $('root5');
+    var O = $('O');
+    var P = $('P');
+    var PP = $('PP');
+    var Q = $('Q');
+
+    var iterator = document.createNodeIterator(root, NodeFilter.SHOW_ALL,
+					       null, false);
+    check(iterator.nextNode(), root, '5.1');
+    check(iterator.nextNode(), O, '5.2');
+    check(iterator.nextNode(), P, '5.3');
+    check(iterator.nextNode(), PP, '5.4');
+    remove(P);
+    var X = addChildTo(O);
+    check(iterator.nextNode(), X, '5.5');
+  })();
+
+  /** Removal of an ancestor of the Reference Node (backwards) **/
+  (function () {
+    var root = $('root6');
+    var R = $('R');
+    var S = $('S');
+    var SS = $('SS');
+    var T = $('T');
+
+    var iterator = document.createNodeIterator(root, NodeFilter.SHOW_ALL,
+					       null, false);
+    check(iterator.nextNode(), root, '6.1');
+    check(iterator.nextNode(), R, '6.2');
+    check(iterator.nextNode(), S, '6.3');
+    check(iterator.nextNode(), SS, '6.4');
+    check(iterator.previousNode(), SS, '6.5');
+    remove(S);
+    check(iterator.nextNode(), T, '6.6');
+  })();
+
+  /** Removal of an ancestor of the Reference Node (backwards) (deep check) **/
+  (function () {
+    var root = $('root7');
+    var U = $('U');
+    var V = $('V');
+    var VV = $('VV');
+    var W = $('W');
+
+    var iterator = document.createNodeIterator(root, NodeFilter.SHOW_ALL,
+					       null, false);
+    check(iterator.nextNode(), root, '7.1');
+    check(iterator.nextNode(), U, '7.2');
+    check(iterator.nextNode(), V, '7.3');
+    check(iterator.nextNode(), VV, '7.4');
+    check(iterator.previousNode(), VV, '7.5');
+    remove(V);
+    var X = addChildTo(U);
+    check(iterator.previousNode(), X, '7.6');
+  })();
+]]></script></pre></body></html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_NodeIterator_mutations_2.html
@@ -0,0 +1,113 @@
+<!DOCTYPE HTML>
+<html>
+<!-- NodeIterator mutation tests, 2.
+     Originally part of WebKit, Mochi-ified by Zack Weinberg.
+     This file based on node-iterator-00[...].html from
+       http://svn.webkit.org/repository/webkit/trunk/LayoutTests/traversal/
+  -->
+<head>
+ <title>DOM Traversal: NodeIterator: Mutations (2/x)</title>
+  <script type="text/javascript" src="/MochiKit/packed.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
+</head>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+  function resetContent() {
+    var content = $('content');
+    content.innerHTML = ('<span id="A"><\/span><span id="B"><\/span>'
+			 + '<span id="C"><\/span><span id="D"><\/span>'
+			 + '<span id="E"><\/span><span id="F"><\/span>'
+			 + '<span id="G"><\/span><span id="H"><\/span>'
+			 + '<span id="I"><\/span>');
+    return content;
+  }
+
+  function makeSpan(id) {
+    var e = document.createElement('span');
+    e.id = id;
+    return e;
+  }
+
+  function testNodeFilter(n) {
+    if (n.tagName == 'SPAN')
+      return NodeFilter.FILTER_ACCEPT;
+    return NodeFilter.FILTER_SKIP;
+  }
+
+  function checkseq(it, root, expect) {
+    var checkIt = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT,
+					      testNodeFilter, false);
+    var printedPointer = (it.referenceNode == undefined);
+    var string = '';
+    var node;
+    while ((node = checkIt.nextNode()) != null) {
+      if (!printedPointer && it.referenceNode == node) {
+        printedPointer = true;
+	var s = '[' + node.id + '] ';
+          if (it.pointerBeforeReferenceNode)
+            string += "* " + s;
+          else
+            string += s + "* ";
+      } else {
+        string += node.id + " ";
+      }
+    }
+    is(string.slice(0, -1), expect, "sequence check");
+  }
+
+  // first a basic sanity check [node-iterator-001]
+  (function(){
+     var root = resetContent();
+     var it = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT,
+					  testNodeFilter, false);
+
+     checkseq(it, root, 'A B C D E F G H I');
+     it.nextNode();
+     checkseq(it, root, '[A] * B C D E F G H I');
+     it.previousNode();
+     checkseq(it, root, '* [A] B C D E F G H I');
+     it.previousNode();
+     checkseq(it, root, '* [A] B C D E F G H I');
+  })();
+
+  // Mutations that should not move the iterator [node-iterator-002]
+  (function(){
+     var root = resetContent();
+     var it = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT,
+					  testNodeFilter, false);
+
+     for (var i = 0; i < 4; i++)
+       it.nextNode();
+     checkseq(it, root, 'A B C [D] * E F G H I');
+
+     root.removeChild($('E'));
+     checkseq(it, root, 'A B C [D] * F G H I');
+
+     var X = makeSpan('X');
+     root.insertBefore(X, $('F'));
+     checkseq(it, root, 'A B C [D] * X F G H I');
+
+     var I = $('I');
+     root.removeChild(I);
+     root.insertBefore(I, X);
+     checkseq(it, root, 'A B C [D] * I X F G H');
+  })();
+
+  // 002 complete
+
+  /* Template
+  (function(){
+     var root = resetContent();
+     var it = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT,
+					  testNodeFilter, false);
+
+  })();
+  */
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug416317-1.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=416317
+-->
+<head>
+  <title>Test for Bug 416317</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>
+    SimpleTest.waitForExplicitFinish();
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=416317">Mozilla Bug 416317</a>
+<p id="display">
+  <iframe src="file_bug416317.xhtml#target"></iframe>
+</p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 416317 **/
+// Subframe handles the test
+</script>
+</pre>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug416317-2.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=416317
+-->
+<head>
+  <title>Test for Bug 416317</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>
+    SimpleTest.waitForExplicitFinish();
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=416317">Mozilla Bug 416317</a>
+<p id="display">
+  <iframe style="display: none" src="file_bug416317.xhtml#target"></iframe>
+</p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 416317 **/
+// Subframe handles the test
+</script>
+</pre>
+</body>
+</html>
+
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -129,20 +129,18 @@ nsDOMEvent::nsDOMEvent(nsPresContext* aP
     mEvent->time = PR_Now();
   }
 
   // Get the explicit original target (if it's anonymous make it null)
   {
     mExplicitOriginalTarget = GetTargetFromFrame();
     mTmpRealOriginalTarget = mExplicitOriginalTarget;
     nsCOMPtr<nsIContent> content = do_QueryInterface(mExplicitOriginalTarget);
-    if (content) {
-      if (content->IsNativeAnonymous() || content->GetBindingParent()) {
-        mExplicitOriginalTarget = nsnull;
-      }
+    if (content && content->IsInAnonymousSubtree()) {
+      mExplicitOriginalTarget = nsnull;
     }
   }
 }
 
 nsDOMEvent::~nsDOMEvent() 
 {
   NS_ASSERT_OWNINGTHREAD(nsDOMEvent);
 
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -820,17 +820,16 @@ nsHTMLInputElement::SetUserInput(const n
 
 NS_IMETHODIMP
 nsHTMLInputElement::TakeTextFrameValue(const nsAString& aValue)
 {
   if (mValue) {
     nsMemory::Free(mValue);
   }
   mValue = ToNewUTF8String(aValue);
-  SetValueChanged(PR_TRUE);
   return NS_OK;
 }
 
 void
 nsHTMLInputElement::GetFileName(nsAString& aValue)
 {
   if (mFileName) {
     aValue = *mFileName;
--- a/content/html/content/src/nsHTMLTextAreaElement.cpp
+++ b/content/html/content/src/nsHTMLTextAreaElement.cpp
@@ -475,17 +475,16 @@ nsHTMLTextAreaElement::GetValueInternal(
 
 NS_IMETHODIMP
 nsHTMLTextAreaElement::TakeTextFrameValue(const nsAString& aValue)
 {
   if (mValue) {
     nsMemory::Free(mValue);
   }
   mValue = ToNewUTF8String(aValue);
-  SetValueChanged(PR_TRUE);
   return NS_OK;
 }
 
 nsresult
 nsHTMLTextAreaElement::SetValueInternal(const nsAString& aValue,
                                         nsITextControlFrame* aFrame,
                                         PRBool aUserInput)
 {
--- a/content/html/content/test/Makefile.in
+++ b/content/html/content/test/Makefile.in
@@ -103,20 +103,21 @@ include $(topsrcdir)/config/rules.mk
 		test_bug390975.html \
 		test_bug391994.html \
 		test_bug392567.html \
 		bug392567.jar       \
 		bug392567.jar^headers^ \
 		test_bug394700.html \
 		test_bug395107.html \
 		test_bug401160.xhtml \
+		test_bug406596.html \
 		test_bug408231.html \
 		test_bug417760.html \
 		file_bug417760.png \
+		test_bug421640.html \
+		test_bug424698.html \
 		test_bug428135.xhtml \
-		test_bug406596.html \
-		test_bug421640.html \
 		test_bug430351.html \
 		test_bug430392.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
--- a/content/html/content/test/test_bug389797.html
+++ b/content/html/content/test/test_bug389797.html
@@ -31,17 +31,18 @@ function getClassName(tag) {
 function HTML_TAG(aTagName, aImplClass) {
   allTags.push(aTagName);
   classInfos[aTagName] = aImplClass;
   interfaces[aTagName] =
     [ "nsIDOM3Node",
       "nsIDOMNSElement",
       "nsIDOMEventTarget",
       "nsIDOMNSHTMLElement",
-      "nsIDOMElementCSSInlineStyle" ];
+      "nsIDOMElementCSSInlineStyle",
+      "nsIDOMNodeSelector" ];
 
   // Some interfaces don't appear in classinfo because other interfaces that
   // inherit from them do.
   interfacesNonClassinfo[aTagName] =
     [ "nsIDOMNode",
       "nsIDOMElement",
       "nsIDOM3EventTarget", "nsIDOMNSEventTarget",
       "nsISupportsWeakReference" ];
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_bug424698.html
@@ -0,0 +1,95 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=424698
+-->
+<head>
+  <title>Test for Bug 424698</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.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=424698">Mozilla Bug 424698</a>
+<p id="display">
+<input id="i1">
+<input id="target">
+<textarea id="i2"></textarea>
+<textarea id="target2"></textarea>
+</p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 424698 **/
+var i = $("i1");
+is(i.value, "", "Value should be empty string");
+i.defaultValue = "test";
+is(i.value, "test", "Setting defaultValue should work");
+i.defaultValue = "test2";
+is(i.value, "test2", "Setting defaultValue multiple times should work");
+
+// Now let's hide and reshow things
+i.style.display = "none";
+is(i.offsetWidth, 0, "Input didn't hide?");
+i.style.display = "";
+isnot(i.offsetWidth, 0, "Input didn't show?");
+is(i.value, "test2", "Hiding/showing should not affect value");
+i.defaultValue = "test3";
+is(i.value, "test3", "Setting defaultValue after hide/show should work");
+
+// Make sure typing works ok
+i = $("target");
+i.focus(); // Otherwise editor gets confused when we send the key events
+is(i.value, "", "Value should be empty string in second control");
+sendString("2test2");
+is(i.value, "2test2", 'We just typed the string "2test2"');
+i.defaultValue = "2test3";
+is(i.value, "2test2", "Setting defaultValue after typing should not work");
+i.style.display = "none";
+is(i.offsetWidth, 0, "Second input didn't hide?");
+i.style.display = "";
+isnot(i.offsetWidth, 0, "Second input didn't show?");
+is(i.value, "2test2", "Hiding/showing second input should not affect value");
+i.defaultValue = "2test4";
+is(i.value, "2test2", "Setting defaultValue after hide/show should not work if we typed");
+
+i = $("i2");
+is(i.value, "", "Textarea value should be empty string");
+i.defaultValue = "test";
+is(i.value, "test", "Setting textarea defaultValue should work");
+i.defaultValue = "test2";
+is(i.value, "test2", "Setting textarea defaultValue multiple times should work");
+
+// Now let's hide and reshow things
+i.style.display = "none";
+is(i.offsetWidth, 0, "Textarea didn't hide?");
+i.style.display = "";
+isnot(i.offsetWidth, 0, "Textarea didn't show?");
+is(i.value, "test2", "Hiding/showing textarea should not affect value");
+i.defaultValue = "test3";
+is(i.value, "test3", "Setting textarea defaultValue after hide/show should work");
+
+// Make sure typing works ok
+i = $("target2");
+i.focus(); // Otherwise editor gets confused when we send the key events
+is(i.value, "", "Textarea value should be empty string in second control");
+sendString("2test2", "target2");
+is(i.value, "2test2", 'We just typed the string "2test2"');
+i.defaultValue = "2test3";
+is(i.value, "2test2", "Setting textarea defaultValue after typing should not work");
+i.style.display = "none";
+is(i.offsetWidth, 0, "Second textarea didn't hide?");
+i.style.display = "";
+isnot(i.offsetWidth, 0, "Second textarea didn't show?");
+is(i.value, "2test2", "Hiding/showing second textarea should not affect value");
+i.defaultValue = "2test4";
+is(i.value, "2test2", "Setting textarea defaultValue after hide/show should not work if we typed");
+</script>
+</pre>
+</body>
+</html>
+
--- a/content/svg/content/src/nsSVGFilters.cpp
+++ b/content/svg/content/src/nsSVGFilters.cpp
@@ -236,16 +236,27 @@ nsSVGFE::ComputeNeededSourceBBoxes(const
                                    nsTArray<nsIntRect>& aSourceBBoxes,
                                    const nsSVGFilterInstance& aInstance)
 {
   for (PRUint32 i = 0; i < aSourceBBoxes.Length(); ++i) {
     aSourceBBoxes[i] = aTargetBBox;
   }
 }
 
+nsIntRect
+nsSVGFE::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
+                           const nsSVGFilterInstance& aInstance)
+{
+  nsIntRect r;
+  for (PRUint32 i = 0; i < aSourceChangeBoxes.Length(); ++i) {
+    r.UnionRect(r, aSourceChangeBoxes[i]);
+  }
+  return r;
+}
+
 void
 nsSVGFE::GetSourceImageNames(nsTArray<nsSVGString*>* aSources)
 {
 }
 
 //----------------------------------------------------------------------
 // nsIDOMSVGFilterPrimitiveStandardAttributes methods
 
@@ -314,16 +325,18 @@ public:
                           const Image* aTarget,
                           const nsIntRect& aDataRect);
   virtual nsSVGString* GetResultImageName() { return &mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGString*>* aSources);
   virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
           const nsSVGFilterInstance& aInstance);
   virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
           nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance);
+  virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
+          const nsSVGFilterInstance& aInstance);
 
   // Gaussian
   NS_DECL_NSIDOMSVGFEGAUSSIANBLURELEMENT
 
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGFEGaussianBlurElementBase::)
 
   NS_FORWARD_NSIDOMNODE(nsSVGFEGaussianBlurElementBase::)
   NS_FORWARD_NSIDOMELEMENT(nsSVGFEGaussianBlurElementBase::)
@@ -339,17 +352,17 @@ protected:
   static NumberInfo sNumberInfo[2];
 
   enum { RESULT, IN1 };
   nsSVGString mStringAttributes[2];
   static StringInfo sStringInfo[2];
 
 private:
   nsresult GetDXY(PRUint32 *aDX, PRUint32 *aDY, const nsSVGFilterInstance& aInstance);
-  void InflateRectForBlur(nsIntRect* aRect, const nsSVGFilterInstance& aInstance);
+  nsIntRect InflateRectForBlur(const nsIntRect& aRect, const nsSVGFilterInstance& aInstance);
 
   void GaussianBlur(const Image *aSource, const Image *aTarget,
                     const nsIntRect& aDataRect,
                     PRUint32 aDX, PRUint32 aDY);
 };
 
 nsSVGElement::NumberInfo nsSVGFEGaussianBlurElement::sNumberInfo[2] =
 {
@@ -690,43 +703,48 @@ nsSVGFEGaussianBlurElement::Filter(nsSVG
 }
 
 void
 nsSVGFEGaussianBlurElement::GetSourceImageNames(nsTArray<nsSVGString*>* aSources)
 {
   aSources->AppendElement(&mStringAttributes[IN1]);
 }
 
-void
-nsSVGFEGaussianBlurElement::InflateRectForBlur(nsIntRect* aRect,
+nsIntRect
+nsSVGFEGaussianBlurElement::InflateRectForBlur(const nsIntRect& aRect,
                                                const nsSVGFilterInstance& aInstance)
 {
   PRUint32 dX, dY;
   nsresult rv = GetDXY(&dX, &dY, aInstance);
+  nsIntRect result = aRect;
   if (NS_SUCCEEDED(rv)) {
-    InflateRectForBlurDXY(aRect, dX, dY);
+    InflateRectForBlurDXY(&result, dX, dY);
   }
+  return result;
 }
 
 nsIntRect
 nsSVGFEGaussianBlurElement::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
         const nsSVGFilterInstance& aInstance)
 {
-  nsIntRect r = aSourceBBoxes[0];
-  InflateRectForBlur(&r, aInstance);
-  return r;
+  return InflateRectForBlur(aSourceBBoxes[0], aInstance);
 }
 
 void
 nsSVGFEGaussianBlurElement::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
           nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance)
 {
-  nsIntRect r = aTargetBBox;
-  InflateRectForBlur(&r, aInstance);
-  aSourceBBoxes[0] = r;
+  aSourceBBoxes[0] = InflateRectForBlur(aTargetBBox, aInstance);
+}
+
+nsIntRect
+nsSVGFEGaussianBlurElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
+                                              const nsSVGFilterInstance& aInstance)
+{
+  return InflateRectForBlur(aSourceChangeBoxes[0], aInstance);
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 nsSVGElement::NumberAttributesInfo
 nsSVGFEGaussianBlurElement::GetNumberInfo()
 {
@@ -2384,16 +2402,18 @@ public:
                           const Image* aTarget,
                           const nsIntRect& aDataRect);
   virtual nsSVGString* GetResultImageName() { return &mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGString*>* aSources);
   virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
           const nsSVGFilterInstance& aInstance);
   virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
           nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance);
+  virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
+          const nsSVGFilterInstance& aInstance);
 
   // Offset
   NS_DECL_NSIDOMSVGFEOFFSETELEMENT
 
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGFEOffsetElementBase::)
 
   NS_FORWARD_NSIDOMNODE(nsSVGFEOffsetElementBase::)
   NS_FORWARD_NSIDOMELEMENT(nsSVGFEOffsetElementBase::)
@@ -2521,16 +2541,23 @@ nsSVGFEOffsetElement::GetSourceImageName
 
 nsIntRect
 nsSVGFEOffsetElement::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
         const nsSVGFilterInstance& aInstance)
 {
   return aSourceBBoxes[0] + GetOffset(aInstance);
 }
 
+nsIntRect
+nsSVGFEOffsetElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
+                                        const nsSVGFilterInstance& aInstance)
+{
+  return aSourceChangeBoxes[0] + GetOffset(aInstance);
+}
+
 void
 nsSVGFEOffsetElement::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
           nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance)
 {
   aSourceBBoxes[0] = aTargetBBox - GetOffset(aInstance);
 }
 
 //----------------------------------------------------------------------
@@ -2717,16 +2744,18 @@ public:
                           const Image* aTarget,
                           const nsIntRect& aDataRect);
   virtual nsSVGString* GetResultImageName() { return &mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGString*>* aSources);
   virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
           const nsSVGFilterInstance& aInstance);
   virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
           nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance);
+  virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
+          const nsSVGFilterInstance& aInstance);
 
   // Tile
   NS_DECL_NSIDOMSVGFETILEELEMENT
 
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGFETileElementBase::)
 
   NS_FORWARD_NSIDOMNODE(nsSVGFETileElementBase::)
   NS_FORWARD_NSIDOMELEMENT(nsSVGFETileElementBase::)
@@ -2795,16 +2824,23 @@ nsSVGFETileElement::ComputeTargetBBox(co
 
 void
 nsSVGFETileElement::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
           nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance)
 {
   // Just assume we need the entire source bounding box, so do nothing.
 }
 
+nsIntRect
+nsSVGFETileElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
+                                      const nsSVGFilterInstance& aInstance)
+{
+  return GetMaxRect();
+}
+
 static PRInt32 WrapInterval(PRInt32 aVal, PRInt32 aMax)
 {
   aVal = aVal % aMax;
   return aVal < 0 ? aMax + aVal : aVal;
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement methods
@@ -3408,30 +3444,32 @@ public:
                           const Image* aTarget,
                           const nsIntRect& aDataRect);
   virtual nsSVGString* GetResultImageName() { return &mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGString*>* aSources);
   virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
           const nsSVGFilterInstance& aInstance);
   virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
           nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance);
+  virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
+          const nsSVGFilterInstance& aInstance);
 
   // Morphology
   NS_DECL_NSIDOMSVGFEMORPHOLOGYELEMENT
 
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGFEMorphologyElementBase::)
 
   NS_FORWARD_NSIDOMNODE(nsSVGFEMorphologyElementBase::)
   NS_FORWARD_NSIDOMELEMENT(nsSVGFEMorphologyElementBase::)
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
 protected:
   void GetRXY(PRInt32 *aRX, PRInt32 *aRY, const nsSVGFilterInstance& aInstance);
-  void InflateRect(nsIntRect* aRect, const nsSVGFilterInstance& aInstance);
+  nsIntRect InflateRect(const nsIntRect& aRect, const nsSVGFilterInstance& aInstance);
 
   virtual NumberAttributesInfo GetNumberInfo();
   virtual EnumAttributesInfo GetEnumInfo();
   virtual StringAttributesInfo GetStringInfo();
 
   enum { RADIUS_X, RADIUS_Y };
   nsSVGNumber2 mNumberAttributes[2];
   static NumberInfo sNumberInfo[2];
@@ -3533,41 +3571,46 @@ nsSVGFEMorphologyElement::SetRadius(floa
 }
 
 void
 nsSVGFEMorphologyElement::GetSourceImageNames(nsTArray<nsSVGString*>* aSources)
 {
   aSources->AppendElement(&mStringAttributes[IN1]);
 }
 
-void
-nsSVGFEMorphologyElement::InflateRect(nsIntRect* aRect,
+nsIntRect
+nsSVGFEMorphologyElement::InflateRect(const nsIntRect& aRect,
                                       const nsSVGFilterInstance& aInstance)
 {
   PRInt32 rx, ry;
   GetRXY(&rx, &ry, aInstance);
-  aRect->Inflate(PR_MAX(0, rx), PR_MAX(0, ry));
+  nsIntRect result = aRect;
+  result.Inflate(PR_MAX(0, rx), PR_MAX(0, ry));
+  return result;
 }
 
 nsIntRect
 nsSVGFEMorphologyElement::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
         const nsSVGFilterInstance& aInstance)
 {
-  nsIntRect r = aSourceBBoxes[0];
-  InflateRect(&r, aInstance);
-  return r;
+  return InflateRect(aSourceBBoxes[0], aInstance);
 }
 
 void
 nsSVGFEMorphologyElement::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
           nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance)
 {
-  nsIntRect r = aTargetBBox;
-  InflateRect(&r, aInstance);
-  aSourceBBoxes[0] = r;
+  aSourceBBoxes[0] = InflateRect(aTargetBBox, aInstance);
+}
+
+nsIntRect
+nsSVGFEMorphologyElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
+                                            const nsSVGFilterInstance& aInstance)
+{
+  return InflateRect(aSourceChangeBoxes[0], aInstance);
 }
 
 #define MORPHOLOGY_EPSILON 0.0001
 
 void
 nsSVGFEMorphologyElement::GetRXY(PRInt32 *aRX, PRInt32 *aRY,
         const nsSVGFilterInstance& aInstance)
 {
@@ -3723,16 +3766,18 @@ public:
                           const Image* aTarget,
                           const nsIntRect& aDataRect);
   virtual nsSVGString* GetResultImageName() { return &mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGString*>* aSources);
   virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
           const nsSVGFilterInstance& aInstance);
   virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
           nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance);
+  virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
+          const nsSVGFilterInstance& aInstance);
 
   // Color Matrix
   NS_DECL_NSIDOMSVGFECONVOLVEMATRIXELEMENT
 
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGFEConvolveMatrixElementBase::)
 
   NS_FORWARD_NSIDOMNODE(nsSVGFEConvolveMatrixElementBase::)
   NS_FORWARD_NSIDOMELEMENT(nsSVGFEConvolveMatrixElementBase::)
@@ -3954,16 +3999,25 @@ void
 nsSVGFEConvolveMatrixElement::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
           nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance)
 {
   // XXX Precise results are possible but we're going to skip that work
   // for now. Do nothing, which means the needed-box remains the
   // source's output bounding box.
 }
 
+nsIntRect
+nsSVGFEConvolveMatrixElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
+                                                const nsSVGFilterInstance& aInstance)
+{
+  // XXX Precise results are possible but we're going to skip that work
+  // for now.
+  return GetMaxRect();
+}
+
 static PRInt32 BoundInterval(PRInt32 aVal, PRInt32 aMax)
 {
   aVal = PR_MAX(aVal, 0);
   return PR_MIN(aVal, aMax - 1);
 }
 
 static void
 ConvolvePixel(const PRUint8 *aSourceData,
@@ -4487,18 +4541,22 @@ public:
   NS_FORWARD_NSIDOMSVGFILTERPRIMITIVESTANDARDATTRIBUTES(nsSVGFELightingElementBase::)
 
   virtual nsresult Filter(nsSVGFilterInstance* aInstance,
                           const nsTArray<const Image*>& aSources,
                           const Image* aTarget,
                           const nsIntRect& aDataRect);
   virtual nsSVGString* GetResultImageName() { return &mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGString*>* aSources);
+  // XXX shouldn't we have ComputeTargetBBox here, since the output can
+  // extend beyond the bounds of the inputs thanks to the convolution kernel?
   virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
           nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance);
+  virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
+          const nsSVGFilterInstance& aInstance);
 
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGFELightingElementBase::)
   NS_FORWARD_NSIDOMNODE(nsSVGFELightingElementBase::)
   NS_FORWARD_NSIDOMELEMENT(nsSVGFELightingElementBase::)
 
   NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const;
 
 protected:
@@ -4536,17 +4594,17 @@ nsSVGElement::StringInfo nsSVGFELighting
 };
 
 //----------------------------------------------------------------------
 // nsISupports methods
 
 NS_IMPL_ADDREF_INHERITED(nsSVGFELightingElement,nsSVGFELightingElementBase)
 NS_IMPL_RELEASE_INHERITED(nsSVGFELightingElement,nsSVGFELightingElementBase)
 
-NS_INTERFACE_MAP_BEGIN(nsSVGFELightingElement)
+NS_INTERFACE_MAP_BEGIN(nsSVGFELightingElement) 
 NS_INTERFACE_MAP_END_INHERITING(nsSVGFELightingElementBase)
 
 //----------------------------------------------------------------------
 // Implementation
 
 NS_IMETHODIMP_(PRBool)
 nsSVGFELightingElement::IsAttributeMapped(const nsIAtom* name) const
 {
@@ -4568,16 +4626,24 @@ void
 nsSVGFELightingElement::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
           nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance)
 {
   // XXX lighting can depend on more than the target area, because
   // of the kernels it uses. We could compute something precise here
   // but just leave it and assume we use the entire source bounding box.
 }
 
+nsIntRect
+nsSVGFELightingElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
+                                          const nsSVGFilterInstance& aInstance)
+{
+  // XXX be conservative for now
+  return GetMaxRect();
+}
+
 #define DOT(a,b) (a[0] * b[0] + a[1] * b[1] + a[2] * b[2])
 #define NORMALIZE(vec) \
   PR_BEGIN_MACRO \
     float norm = sqrt(DOT(vec, vec)); \
     vec[0] /= norm; \
     vec[1] /= norm; \
     vec[2] /= norm; \
   PR_END_MACRO
@@ -5439,16 +5505,18 @@ public:
                           const Image* aTarget,
                           const nsIntRect& aDataRect);
   virtual nsSVGString* GetResultImageName() { return &mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGString*>* aSources);
   virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
           const nsSVGFilterInstance& aInstance);
   virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
           nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance);
+  virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
+          const nsSVGFilterInstance& aInstance);
 
   // DisplacementMap
   NS_DECL_NSIDOMSVGFEDISPLACEMENTMAPELEMENT
 
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGFEDisplacementMapElementBase::)
 
   NS_FORWARD_NSIDOMNODE(nsSVGFEDisplacementMapElementBase::)
   NS_FORWARD_NSIDOMELEMENT(nsSVGFEDisplacementMapElementBase::)
@@ -5660,16 +5728,25 @@ nsSVGFEDisplacementMapElement::ComputeNe
   aSourceBBoxes[1] = aTargetBBox;
   // XXX to figure out which parts of 'in' we might read, we could
   // do some analysis of 'scale' to figure out the maximum displacement.
   // For now, just leave aSourceBBoxes[0] alone, i.e. assume we use its
   // entire output bounding box.
   // If we change this, we need to change coordinate assumptions above
 }
 
+nsIntRect
+nsSVGFEDisplacementMapElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
+                                                 const nsSVGFilterInstance& aInstance)
+{
+  // XXX we could do something clever here involving analysis of 'scale'
+  // to figure out the maximum displacement
+  return GetMaxRect();
+}
+
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 nsSVGElement::NumberAttributesInfo
 nsSVGFEDisplacementMapElement::GetNumberInfo()
 {
   return NumberAttributesInfo(mNumberAttributes, sNumberInfo,
                               NS_ARRAY_LENGTH(sNumberInfo));
--- a/content/svg/content/src/nsSVGFilters.h
+++ b/content/svg/content/src/nsSVGFilters.h
@@ -135,34 +135,41 @@ public:
   // interfaces:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMSVGFILTERPRIMITIVESTANDARDATTRIBUTES
 
   virtual nsSVGString* GetResultImageName() = 0;
   // Return a list of all image names used as sources. Default is to
   // return no sources.
   virtual void GetSourceImageNames(nsTArray<nsSVGString*>* aSources);
-  // Compute the bounding-box of the filter output. The default is just the
-  // union of the source bounding-boxes. The caller is
+  // Compute the bounding box of the filter output. The default is just the
+  // union of the source bounding boxes. The caller is
   // responsible for clipping this to the filter primitive subregion, so
   // if the filter fills its filter primitive subregion, it can just
   // return GetMaxRect() here.
-  // The source bounding-boxes are ordered corresponding to GetSourceImageNames.
+  // The source bounding boxes are ordered corresponding to GetSourceImageNames.
   virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
           const nsSVGFilterInstance& aInstance);
-  // Given a bounding-box for what we need to compute in the target,
+  // Given a bounding box for what we need to compute in the target,
   // compute which regions of the inputs are needed. On input
   // aSourceBBoxes contains the bounding box of what's rendered by
   // each source; this function should change those boxes to indicate
   // which region of the source's output it needs.
   // The default implementation sets all the source bboxes to the
   // target bbox.
   virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
           nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance);
-
+  // Given the bounding boxes for the pixels that have changed in the inputs,
+  // compute the bounding box of the changes in this primitive's output.
+  // The result will be clipped by the caller to the result of ComputeTargetBBox
+  // since there's no way anything outside that can change.
+  // The default implementation returns the union of the source change boxes.
+  virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
+          const nsSVGFilterInstance& aInstance);
+  
   // Perform the actual filter operation.
   // We guarantee that every mImage from aSources and aTarget has the
   // same width, height, stride and device offset.
   // aTarget is already filled in. This function just needs to fill in the
   // pixels of aTarget->mImage (which have already been cleared).
   // @param aDataRect the destination rectangle that needs to be painted,
   // relative to aTarget's surface data. This is the intersection of the
   // filter primitive subregion for this filter element and the
--- a/content/xbl/src/nsBindingManager.cpp
+++ b/content/xbl/src/nsBindingManager.cpp
@@ -1258,25 +1258,21 @@ nsBindingManager::WalkRules(nsStyleSet* 
       if (content != aData->mContent) {
         if (!binding->InheritsStyle()) {
           // Go no further; we're not inheriting style from anything above here
           break;
         }
       }
     }
 
-    nsIContent* parent = content->GetBindingParent();
-    if (parent == content) {
-      NS_ASSERTION(content->IsNativeAnonymous(), "Unexpected binding parent");
-                             
-      break; // The anonymous content case is often deliberately hacked to
-             // return itself to cut off style inheritance here.  Do that.
+    if (content->IsRootOfNativeAnonymousSubtree()) {
+      break; // Deliberately cut off style inheritance here.
     }
 
-    content = parent;
+    content = content->GetBindingParent();
   } while (content);
 
   // If "content" is non-null that means we cut off inheritance at some point
   // in the loop.
   *aCutOffInheritance = (content != nsnull);
 
   // Null out the scoped root that we set repeatedly
   aData->mScopedRoot = nsnull;
--- a/content/xbl/src/nsXBLService.cpp
+++ b/content/xbl/src/nsXBLService.cpp
@@ -105,21 +105,20 @@ IsAncestorBinding(nsIDocument* aDocument
                   nsIURI* aChildBindingURI,
                   nsIContent* aChild)
 {
   NS_ASSERTION(aDocument, "expected a document");
   NS_ASSERTION(aChildBindingURI, "expected a binding URI");
   NS_ASSERTION(aChild, "expected a child content");
 
   PRUint32 bindingRecursion = 0;
-  nsIContent* bindingParent = aChild->GetBindingParent();
   nsBindingManager* bindingManager = aDocument->BindingManager();
-  for (nsIContent* prev = aChild;
-       bindingParent && prev != bindingParent;
-       prev = bindingParent, bindingParent = bindingParent->GetBindingParent()) {
+  for (nsIContent *bindingParent = aChild->GetBindingParent();
+       bindingParent;
+       bindingParent = bindingParent->GetBindingParent()) {
     nsXBLBinding* binding = bindingManager->GetBinding(bindingParent);
     if (!binding) {
       continue;
     }
     PRBool equal;
     nsresult rv =
       binding->PrototypeBinding()->BindingURI()->Equals(aChildBindingURI,
                                                         &equal);
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -1081,16 +1081,17 @@ nsXULElement::UnregisterAccessKey(const 
 
         if (shell) {
             nsIContent *content = this;
 
             // find out what type of content node this is
             if (mNodeInfo->Equals(nsGkAtoms::label)) {
                 // For anonymous labels the unregistering must
                 // occur on the binding parent control.
+                // XXXldb: And what if the binding parent is null?
                 content = GetBindingParent();
             }
 
             if (content) {
                 shell->GetPresContext()->EventStateManager()->
                     UnregisterAccessKey(content, aOldValue.First());
             }
         }
--- a/dom/public/idl/core/Makefile.in
+++ b/dom/public/idl/core/Makefile.in
@@ -75,11 +75,12 @@ XPIDLSRCS =                             
 	nsIDOMDOMStringList.idl			\
 	nsIDOMNameList.idl			\
 	nsIDOMNSDocument.idl			\
 	nsIDOMXMLDocument.idl			\
 	nsIDOMUserDataHandler.idl		\
 	nsIDOMDOMConfiguration.idl		\
 	nsIDOMNSEditableElement.idl		\
 	nsIDOMNSElement.idl			\
+	nsIDOMNodeSelector.idl                  \
 	$(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/public/idl/core/nsIDOMNodeSelector.idl
@@ -0,0 +1,53 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.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/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Boris Zbarsky <bzbarsky@mit.edu> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "domstubs.idl"
+
+/**
+ * The nsIDOMNodeSelector interface is an interface for getting nodes
+ * that mtch a given CSS selector.
+ *
+ * For more information on this interface please see 
+ * http://www.w3.org/TR/selectors-api/
+ */
+[scriptable, uuid(7cebc153-168a-416c-ba5a-56a8c2ddb2ec)]
+interface nsIDOMNodeSelector : nsISupports
+{
+  nsIDOMElement querySelector(in DOMString selectors);
+  nsIDOMNodeList querySelectorAll(in DOMString selectors);
+};
--- a/dom/public/idl/traversal/nsIDOMNodeIterator.idl
+++ b/dom/public/idl/traversal/nsIDOMNodeIterator.idl
@@ -51,9 +51,13 @@ interface nsIDOMNodeIterator : nsISuppor
   readonly attribute unsigned long    whatToShow;
   readonly attribute nsIDOMNodeFilter filter;
   readonly attribute boolean          expandEntityReferences;
   nsIDOMNode         nextNode()
                                         raises(DOMException);
   nsIDOMNode         previousNode()
                                         raises(DOMException);
   void               detach();
+
+  // WebKit extensions, convenient for debugging.
+  readonly attribute nsIDOMNode referenceNode;
+  readonly attribute boolean    pointerBeforeReferenceNode;
 };
--- a/dom/public/nsDOMClassInfoID.h
+++ b/dom/public/nsDOMClassInfoID.h
@@ -432,16 +432,19 @@ enum nsDOMClassInfoID {
 #if defined(MOZ_MEDIA)
   eDOMClassInfo_HTMLVideoElement_id,
   eDOMClassInfo_HTMLSourceElement_id,
   eDOMClassInfo_ProgressEvent_id,
   eDOMClassInfo_HTMLMediaError_id,
   eDOMClassInfo_HTMLAudioElement_id,
 #endif
 
+  // DOM Traversal NodeIterator class
+  eDOMClassInfo_NodeIterator_id,
+
   // This one better be the last one in this list
   eDOMClassInfoIDCount
 };
 
 /**
  * nsIClassInfo helper macros
  */
 
--- a/dom/src/base/nsDOMClassInfo.cpp
+++ b/dom/src/base/nsDOMClassInfo.cpp
@@ -328,16 +328,17 @@
 #include "nsIDOMCSSMozDocumentRule.h"
 #include "nsIDOMCSSPrimitiveValue.h"
 #include "nsIDOMCSSStyleRule.h"
 #include "nsIDOMCSSStyleSheet.h"
 #include "nsIDOMCSSValueList.h"
 #include "nsIDOMRange.h"
 #include "nsIDOMNSRange.h"
 #include "nsIDOMRangeException.h"
+#include "nsIDOMNodeIterator.h"
 #include "nsIDOMTreeWalker.h"
 #include "nsIDOMXULDocument.h"
 #include "nsIDOMXULElement.h"
 #include "nsIDOMXULCommandDispatcher.h"
 #include "nsIDOMCrypto.h"
 #include "nsIDOMCRMFObject.h"
 #include "nsIDOMPkcs11.h"
 #include "nsIControllers.h"
@@ -1259,16 +1260,20 @@ static nsDOMClassInfoData sClassInfoData
                            ELEMENT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(ProgressEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(HTMLMediaError, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(HTMLAudioElement, nsHTMLElementSH,
                            ELEMENT_SCRIPTABLE_FLAGS)
 #endif
+
+  // DOM Traversal NodeIterator class  
+  NS_DEFINE_CLASSINFO_DATA(NodeIterator, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
 };
 
 // Objects that shuld be constructable through |new Name();|
 struct nsContractIDMapData
 {
   PRInt32 mDOMClassInfoID;
   const char *mContractID;
 };
@@ -1847,24 +1852,27 @@ nsDOMClassInfo::RegisterExternalClasses(
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSDocumentStyle)                            \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDocumentView)                               \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDocumentRange)                              \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDocumentTraversal)                          \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDocumentXBL)                                \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)                                \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Document)                                  \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Node)                                      \
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathEvaluator)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathEvaluator)                             \
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector)
+
 
 #define DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES                                \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSHTMLElement)                              \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMElementCSSInlineStyle)                      \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)                                \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Node)                                      \
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement)                                  \
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector)
 
 #define DOM_CLASSINFO_EVENT_MAP_ENTRIES                                       \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent)                                      \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSEvent)                                    \
 
 #define DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES                                    \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMUIEvent)                                    \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSUIEvent)                                  \
@@ -1995,23 +2003,25 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN(DOMException, nsIDOMDOMException)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMException)
     DOM_CLASSINFO_MAP_ENTRY(nsIException)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(DocumentFragment, nsIDOMDocumentFragment)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDocumentFragment)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Node)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(Element, nsIDOMElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Node)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(Attr, nsIDOMAttr)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMAttr)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Node)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Attr)
   DOM_CLASSINFO_MAP_END
 
@@ -2507,16 +2517,20 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSRGBAColor)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(Range, nsIDOMRange)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMRange)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSRange)
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN(NodeIterator, nsIDOMNodeIterator)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeIterator)
+  DOM_CLASSINFO_MAP_END
+
   DOM_CLASSINFO_MAP_BEGIN(TreeWalker, nsIDOMTreeWalker)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMTreeWalker)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(Selection, nsISelection)
     DOM_CLASSINFO_MAP_ENTRY(nsISelection)
   DOM_CLASSINFO_MAP_END
 
@@ -2528,16 +2542,17 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(XULElement, nsIDOMXULElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Node)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMElementCSSInlineStyle)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(XULCommandDispatcher, nsIDOMXULCommandDispatcher)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULCommandDispatcher)
   DOM_CLASSINFO_MAP_END
 #endif
 
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULControllers, nsIControllers)
@@ -2643,17 +2658,18 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMBeforeUnloadEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
 #ifdef MOZ_SVG
 #define DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGElement) \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement)  \
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Node)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Node)      \
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector)
 
 #define DOM_CLASSINFO_SVG_GRAPHIC_ELEMENT_MAP_ENTRIES \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)        \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGLocatable)       \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTransformable)   \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGStylable)        \
     DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES
 
--- a/dom/src/base/nsJSEnvironment.cpp
+++ b/dom/src/base/nsJSEnvironment.cpp
@@ -2725,33 +2725,31 @@ nsJSContext::AddSupportsPrimitiveTojsval
     case nsISupportsPrimitive::TYPE_FLOAT : {
       nsCOMPtr<nsISupportsFloat> p(do_QueryInterface(argPrimitive));
       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
 
       float data;
 
       p->GetData(&data);
 
-      jsdouble *d = ::JS_NewDouble(cx, data);
-
-      *aArgv = DOUBLE_TO_JSVAL(d);
+      JSBool ok = ::JS_NewNumberValue(cx, data, aArgv);
+      NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
 
       break;
     }
     case nsISupportsPrimitive::TYPE_DOUBLE : {
       nsCOMPtr<nsISupportsDouble> p(do_QueryInterface(argPrimitive));
       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
 
       double data;
 
       p->GetData(&data);
 
-      jsdouble *d = ::JS_NewDouble(cx, data);
-
-      *aArgv = DOUBLE_TO_JSVAL(d);
+      JSBool ok = ::JS_NewNumberValue(cx, data, aArgv);
+      NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
 
       break;
     }
     case nsISupportsPrimitive::TYPE_INTERFACE_POINTER : {
       nsCOMPtr<nsISupportsInterfacePointer> p(do_QueryInterface(argPrimitive));
       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
 
       nsCOMPtr<nsISupports> data;
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -435,17 +435,17 @@ nsEditor::GetDesiredSpellCheckState()
   }
 
   // Check DOM state
   nsCOMPtr<nsIContent> content = do_QueryInterface(GetRoot());
   if (!content) {
     return PR_FALSE;
   }
 
-  if (content->IsNativeAnonymous()) {
+  if (content->IsRootOfNativeAnonymousSubtree()) {
     content = content->GetParent();
   }
 
   nsCOMPtr<nsIDOMNSHTMLElement> element = do_QueryInterface(content);
   if (!element) {
     return PR_FALSE;
   }
 
@@ -5236,17 +5236,17 @@ nsEditor::GetPIDOMEventTarget()
 
   nsIDOMElement *rootElement = GetRoot();
 
   // Now hack to make sure we are not anonymous content.
   // If we are grab the parent of root element for our observer.
 
   nsCOMPtr<nsIContent> content = do_QueryInterface(rootElement);
 
-  if (content && content->IsNativeAnonymous())
+  if (content && content->IsRootOfNativeAnonymousSubtree())
   {
     mEventTarget = do_QueryInterface(content->GetParent());
     piTarget = mEventTarget;
     NS_IF_ADDREF(piTarget);
   }
   else
   {
     // Don't use getDocument here, because we have no way of knowing
--- a/editor/libeditor/html/nsHTMLAnonymousUtils.cpp
+++ b/editor/libeditor/html/nsHTMLAnonymousUtils.cpp
@@ -183,17 +183,17 @@ nsHTMLEditor::CreateAnonymousElement(con
     if (NS_FAILED(res)) return res;
   }
 
   {
     nsAutoScriptBlocker scriptBlocker;
 
     // establish parenthood of the element
     newContent->SetNativeAnonymous();
-    res = newContent->BindToTree(doc, parentContent, newContent, PR_TRUE);
+    res = newContent->BindToTree(doc, parentContent, parentContent, PR_TRUE);
     if (NS_FAILED(res)) {
       newContent->UnbindFromTree();
       return res;
     }
   }
 
   nsElementDeletionObserver* observer =
     new nsElementDeletionObserver(newContent, parentContent);
--- a/editor/libeditor/html/nsHTMLEditor.cpp
+++ b/editor/libeditor/html/nsHTMLEditor.cpp
@@ -5923,17 +5923,17 @@ nsHTMLEditor::GetSelectionContainer(nsID
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLEditor::IsAnonymousElement(nsIDOMElement * aElement, PRBool * aReturn)
 {
   NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
   nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
-  *aReturn = content->IsNativeAnonymous();
+  *aReturn = content->IsRootOfNativeAnonymousSubtree();
   return NS_OK;
 }
 
 nsresult
 nsHTMLEditor::SetReturnInParagraphCreatesNewParagraph(PRBool aCreatesNewParagraph)
 {
   mCRInParagraphCreatesParagraph = aCreatesNewParagraph;
   return NS_OK;
--- a/embedding/components/find/src/nsFind.cpp
+++ b/embedding/components/find/src/nsFind.cpp
@@ -361,17 +361,17 @@ nsFindContentIterator::MaybeSetupInnerIt
 }
 
 void
 nsFindContentIterator::SetupInnerIterator(nsIContent* aContent)
 {
   if (!aContent) {
     return;
   }
-  NS_ASSERTION(!aContent->IsNativeAnonymous(), "invalid call");
+  NS_ASSERTION(!aContent->IsRootOfNativeAnonymousSubtree(), "invalid call");
 
   nsIDocument* doc = aContent->GetDocument();
   nsIPresShell* shell = doc ? doc->GetPrimaryShell() : nsnull;
   if (!shell)
     return;
 
   nsIFrame* frame = shell->GetPrimaryFrameFor(aContent);
   if (!frame)
--- a/embedding/components/find/src/nsWebBrowserFind.cpp
+++ b/embedding/components/find/src/nsWebBrowserFind.cpp
@@ -406,31 +406,16 @@ FocusElementButNotDocument(nsIDocument* 
   aDocument->EndUpdate(UPDATE_CONTENT_STATE);
 
   // Reset esm::mCurrentFocus = nsnull for this doc, so when this document
   // does get focus next time via preHandleEvent() NS_GOTFOCUS,
   // the old document gets blurred
   esm->SetFocusedContent(nsnull);
 }
 
-static PRBool
-IsInNativeAnonymousSubtree(nsIContent* aContent)
-{
-    while (aContent) {
-        nsIContent* bindingParent = aContent->GetBindingParent();
-        if (bindingParent == aContent) {
-            return PR_TRUE;
-        }
-
-        aContent = bindingParent;
-    }
-
-    return PR_FALSE;
-}
-
 void nsWebBrowserFind::SetSelectionAndScroll(nsIDOMWindow* aWindow,
                                              nsIDOMRange*  aRange)
 {
   nsCOMPtr<nsIDOMDocument> domDoc;    
   aWindow->GetDocument(getter_AddRefs(domDoc));
   if (!domDoc) return;
 
   nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
@@ -446,17 +431,17 @@ void nsWebBrowserFind::SetSelectionAndSc
   nsCOMPtr<nsISelectionController> selCon;
   frame->GetSelectionController(presShell->GetPresContext(),
                                 getter_AddRefs(selCon));
   
   // since the match could be an anonymous textnode inside a
   // <textarea> or text <input>, we need to get the outer frame
   nsITextControlFrame *tcFrame = nsnull;
   for ( ; content; content = content->GetParent()) {
-    if (!IsInNativeAnonymousSubtree(content)) {
+    if (!content->IsInNativeAnonymousSubtree()) {
       nsIFrame* f = presShell->GetPrimaryFrameFor(content);
       if (!f)
         return;
       CallQueryInterface(f, &tcFrame);
       break;
     }
   }
 
--- a/gfx/cairo/README
+++ b/gfx/cairo/README
@@ -2,51 +2,31 @@ 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.6.4 - 1.6.4)
-  pixman (0.10.x - pixman-0.10.0-8-g0b207ae)
-  glitz 0.5.2 (cvs - 2006-01-10)
+  cairo (1.6.4-350-g1a9809b)
+  pixman (pixman-0.11.8-7-gdb3fb5e)
 
 ***** NOTE FOR VISUAL C++ 6.0 *****
 
 VC6 is not supported.  Please upgrade to VC8.
 
 ==== Patches ====
 
 Some specific things:
 
-cairo git commit ea6dbfd36f2182fda16cb82bca92007e0f7b8d77 - 
-  [cairo-meta-surface] Save and restore the original clip.
-
-cairo git commit d96fdd58abf8d6c8692dbb08ec54cdd80accba79 -
-  win32: Fix broken printing of type1 fonts
-
-cairo git commit 547e2f552cff264b943803d3a1ff03d05bde35c0
-  Fix win32-printing show_glyphs analysis for Type 1 fonts
-
-cairo git commit 158d24412bba99a4f57907d7fd22a86aae6e87af
-  Make win32-printing surface work with bitmap fonts
-
-cairo git commit d35d6eec24c1b7ab0a49149a51bf65ea8e223203
-  Fix win32 bitmap font metrics when device scale != 1
-
 max-font-size.patch: Clamp freetype font size to 1000 to avoid overflow issues
 
 win32-logical-font-scale.patch: set CAIRO_WIN32_LOGICAL_FONT_SCALE to 1
 
 nonfatal-assertions.patch: Make assertions non-fatal
 
 buggy-repeat.patch: Unconditionally turn on buggy-repeat handling to bandaid bug 413583.
 
-clip-clone.patch: _cairo_clip_init_deep_copy should pass 0,0 as the
-source coordinates to clone from since it wants an exact copy of the
-source's clipping surface
-
 ==== pixman patches ====
 
 endian.patch: include cairo-platform.h for endian macros
 
--- a/gfx/cairo/cairo/src/Makefile.in
+++ b/gfx/cairo/cairo/src/Makefile.in
@@ -113,26 +113,28 @@ CSRCS   = \
         cairo-skiplist.c \
         cairo-slope.c \
         cairo-spline.c \
         cairo-stroke-style.c \
         cairo-surface.c \
         cairo-surface-fallback.c \
         cairo-traps.c \
         cairo-unicode.c \
+	cairo-user-font.c \
         cairo-wideint.c \
         $(NULL)
 
 EXPORTS = cairo.h cairo-features.h cairo-platform.h cairo-deprecated.h cairo-rename.h
 
 # cairo-type1-subset.c should be here, but it's only supported on freetype platforms
 
 PSPDF_BASE_CSRCS = \
 	cairo-base85-stream.c \
 	cairo-type1-fallback.c \
+	cairo-type3-glyph-surface.c \
 	cairo-truetype-subset.c \
 	cairo-cff-subset.c \
 	$(NULL)
 
 PDF_CSRCS = \
 	cairo-pdf-surface.c \
 	cairo-pdf-operators.c \
 	$(NULL)
--- a/gfx/cairo/cairo/src/cairo-analysis-surface-private.h
+++ b/gfx/cairo/cairo/src/cairo-analysis-surface-private.h
@@ -37,25 +37,37 @@
 
 #include "cairoint.h"
 
 cairo_private cairo_surface_t *
 _cairo_analysis_surface_create (cairo_surface_t		*target,
 				int			 width,
 				int			 height);
 
+cairo_private void
+_cairo_analysis_surface_set_ctm (cairo_surface_t *surface,
+				 cairo_matrix_t  *ctm);
+
+cairo_private void
+_cairo_analysis_surface_get_ctm (cairo_surface_t *surface,
+				 cairo_matrix_t  *ctm);
+
 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 *surface);
 
 cairo_private cairo_bool_t
 _cairo_analysis_surface_has_supported (cairo_surface_t *surface);
 
 cairo_private cairo_bool_t
 _cairo_analysis_surface_has_unsupported (cairo_surface_t *surface);
 
 cairo_private void
 _cairo_analysis_surface_get_bounding_box (cairo_surface_t *surface,
 					  cairo_box_t     *bbox);
 
+
+cairo_private cairo_surface_t *
+_cairo_null_surface_create (cairo_content_t content);
+
 #endif /* CAIRO_ANALYSIS_SURFACE_H */
--- a/gfx/cairo/cairo/src/cairo-analysis-surface.c
+++ b/gfx/cairo/cairo/src/cairo-analysis-surface.c
@@ -79,17 +79,17 @@ static cairo_int_status_t
     assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
     surface_pattern = (cairo_surface_pattern_t *) pattern;
     assert (_cairo_surface_is_meta (surface_pattern->surface));
 
     old_width = surface->width;
     old_height = surface->height;
     old_clip = surface->current_clip;
     status = _cairo_surface_get_extents (surface_pattern->surface, &meta_extents);
-    if (status)
+    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
 	return status;
 
     surface->width = meta_extents.width;
     surface->height = meta_extents.height;
     surface->current_clip.x = 0;
     surface->current_clip.y = 0;
     surface->current_clip.width = surface->width;
     surface->current_clip.height = surface->height;
@@ -135,56 +135,41 @@ static cairo_int_status_t
 	    return CAIRO_STATUS_SUCCESS;
 	}
 	else
 	{
 	    return CAIRO_INT_STATUS_IMAGE_FALLBACK;
 	}
     }
 
+    _cairo_box_from_rectangle (&bbox, rect);
+
     if (surface->has_ctm) {
-	double x1, y1, x2, y2;
 
-	x1 = rect->x;
-	y1 = rect->y;
-	x2 = rect->x + rect->width;
-	y2 = rect->y + rect->height;
-	_cairo_matrix_transform_bounding_box (&surface->ctm,
-					      &x1, &y1, &x2, &y2,
-					      NULL);
-	rect->x = floor (x1);
-	rect->y = floor (y1);
+	_cairo_matrix_transform_bounding_box_fixed (&surface->ctm, &bbox, NULL);
 
-	x2 = ceil (x2) - rect->x;
-	y2 = ceil (y2) - rect->y;
-	if (x2 <= 0 || y2 <= 0) {
+	if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) {
 	    /* Even though the operation is not visible we must be
 	     * careful to not allow unsupported operations to be
 	     * replayed to the backend during
 	     * CAIRO_PAGINATED_MODE_RENDER */
 	    if (backend_status == CAIRO_STATUS_SUCCESS ||
 		backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
 	    {
 		return CAIRO_STATUS_SUCCESS;
 	    }
 	    else
 	    {
 		return CAIRO_INT_STATUS_IMAGE_FALLBACK;
 	    }
 	}
 
-	rect->width  = x2;
-	rect->height = y2;
+	_cairo_box_round_to_rectangle (&bbox, rect);
     }
 
-    bbox.p1.x = _cairo_fixed_from_int (rect->x);
-    bbox.p1.y = _cairo_fixed_from_int (rect->y);
-    bbox.p2.x = _cairo_fixed_from_int (rect->x + rect->width);
-    bbox.p2.y = _cairo_fixed_from_int (rect->y + rect->height);
-
     if (surface->first_op) {
 	surface->first_op = FALSE;
 	surface->page_bbox = bbox;
     } else {
 	if (bbox.p1.x < surface->page_bbox.p1.x)
 	    surface->page_bbox.p1.x = bbox.p1.x;
 	if (bbox.p1.y < surface->page_bbox.p1.y)
 	    surface->page_bbox.p1.y = bbox.p1.y;
@@ -248,16 +233,18 @@ static cairo_int_status_t
 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);
 
+    cairo_surface_destroy (surface->target);
+
     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,
@@ -314,17 +301,17 @@ static cairo_int_status_t
 	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)
+    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
 	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;
 
@@ -372,17 +359,17 @@ static cairo_int_status_t
 										       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)
+    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
 	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;
 
@@ -427,17 +414,17 @@ static cairo_int_status_t
 							      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)
+    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
 	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;
 
@@ -506,17 +493,17 @@ static cairo_int_status_t
 						    source, path, fill_rule,
 						    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)
+    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
 	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;
 
@@ -564,36 +551,130 @@ static cairo_int_status_t
 }
 
 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_scaled_font_t  *scaled_font,
+				     int                  *remaining_glyphs)
 {
     cairo_analysis_surface_t *surface = abstract_surface;
     cairo_status_t	     status, backend_status;
     cairo_rectangle_int_t    extents, glyph_extents;
 
-    if (!surface->target->backend->show_glyphs)
-	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
-    else
+    /* Adapted from _cairo_surface_show_glyphs */
+    if (surface->target->backend->show_glyphs)
 	backend_status = (*surface->target->backend->show_glyphs) (surface->target, op,
-							   source,
-							   glyphs, num_glyphs,
-							   scaled_font);
+								   source,
+								   glyphs, num_glyphs,
+								   scaled_font,
+								   remaining_glyphs);
+    else if (surface->target->backend->show_text_glyphs)
+	backend_status = surface->target->backend->show_text_glyphs (surface->target, op,
+								     source,
+								     NULL, 0,
+								     glyphs, num_glyphs,
+								     NULL, 0,
+								     FALSE,
+								     scaled_font);
+    else
+	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
 
     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)
+    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
+	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 cairo_bool_t
+_cairo_analysis_surface_has_show_text_glyphs (void *abstract_surface)
+{
+    cairo_analysis_surface_t *surface = abstract_surface;
+
+    return _cairo_surface_has_show_text_glyphs (surface->target);
+}
+
+static cairo_int_status_t
+_cairo_analysis_surface_show_text_glyphs (void			    *abstract_surface,
+					  cairo_operator_t	     op,
+					  cairo_pattern_t	    *source,
+					  const char		    *utf8,
+					  int			     utf8_len,
+					  cairo_glyph_t		    *glyphs,
+					  int			     num_glyphs,
+					  const cairo_text_cluster_t *clusters,
+					  int			     num_clusters,
+					  cairo_bool_t		     backward,
+					  cairo_scaled_font_t	    *scaled_font)
+{
+    cairo_analysis_surface_t *surface = abstract_surface;
+    cairo_status_t	     status, backend_status;
+    cairo_rectangle_int_t    extents, glyph_extents;
+
+    /* Adapted from _cairo_surface_show_glyphs */
+    backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
+    if (surface->target->backend->show_text_glyphs)
+	backend_status = surface->target->backend->show_text_glyphs (surface->target, op,
+								     source,
+								     utf8, utf8_len,
+								     glyphs, num_glyphs,
+								     clusters, num_clusters,
+								     backward,
+								     scaled_font);
+    if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED && surface->target->backend->show_glyphs) {
+	int remaining_glyphs = num_glyphs;
+	backend_status = surface->target->backend->show_glyphs (surface->target, op,
+								source,
+								glyphs, num_glyphs,
+								scaled_font,
+								&remaining_glyphs);
+	glyphs += num_glyphs - remaining_glyphs;
+	num_glyphs = remaining_glyphs;
+	if (remaining_glyphs == 0)
+	    backend_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 && status != CAIRO_INT_STATUS_UNSUPPORTED)
 	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;
 
@@ -645,16 +726,19 @@ static const cairo_surface_backend_t cai
     _cairo_analysis_surface_mask,
     _cairo_analysis_surface_stroke,
     _cairo_analysis_surface_fill,
     _cairo_analysis_surface_show_glyphs,
     NULL, /* snapshot */
     NULL, /* is_similar */
     NULL, /* reset */
     NULL, /* fill_stroke */
+    NULL, /* create_solid_pattern_surface */
+    _cairo_analysis_surface_has_show_text_glyphs,
+    _cairo_analysis_surface_show_text_glyphs
 };
 
 cairo_surface_t *
 _cairo_analysis_surface_create (cairo_surface_t		*target,
 				int			 width,
 				int			 height)
 {
     cairo_analysis_surface_t *surface;
@@ -668,31 +752,64 @@ cairo_surface_t *
     _cairo_surface_init (&surface->base, &cairo_analysis_surface_backend,
 			 CAIRO_CONTENT_COLOR_ALPHA);
 
     surface->width = width;
     surface->height = height;
     cairo_matrix_init_identity (&surface->ctm);
     surface->has_ctm = FALSE;
 
-    surface->target = target;
+    surface->target = cairo_surface_reference (target);
     surface->first_op  = TRUE;
     surface->has_supported = FALSE;
     surface->has_unsupported = FALSE;
+
+    surface->page_bbox.p1.x = 0;
+    surface->page_bbox.p1.y = 0;
+    surface->page_bbox.p2.x = 0;
+    surface->page_bbox.p2.y = 0;
+
     _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;
+    if (width == -1 && height == -1) {
+	surface->current_clip.x      = CAIRO_RECT_INT_MIN;
+	surface->current_clip.y      = CAIRO_RECT_INT_MIN;
+	surface->current_clip.width  = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
+	surface->current_clip.height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
+    } else {
+	surface->current_clip.x = 0;
+	surface->current_clip.y = 0;
+	surface->current_clip.width = width;
+	surface->current_clip.height = height;
+    }
 
     return &surface->base;
 }
 
+cairo_private void
+_cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface,
+				 cairo_matrix_t  *ctm)
+{
+    cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
+
+    surface->ctm = *ctm;
+    surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
+}
+
+cairo_private void
+_cairo_analysis_surface_get_ctm (cairo_surface_t *abstract_surface,
+				 cairo_matrix_t  *ctm)
+{
+    cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
+
+    *ctm = surface->ctm;
+}
+
+
 cairo_region_t *
 _cairo_analysis_surface_get_supported (cairo_surface_t *abstract_surface)
 {
     cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
 
     return &surface->supported_region;
 }
 
@@ -723,8 +840,113 @@ cairo_bool_t
 void
 _cairo_analysis_surface_get_bounding_box (cairo_surface_t *abstract_surface,
 					  cairo_box_t     *bbox)
 {
     cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
 
     *bbox = surface->page_bbox;
 }
+
+/* null surface type: a surface that does nothing (has no side effects, yay!) */
+
+static cairo_int_status_t
+_return_success (void)
+{
+    return CAIRO_STATUS_SUCCESS;
+}
+
+/* These typedefs are just to silence the compiler... */
+typedef cairo_int_status_t
+(*_set_clip_region_func)	(void			*surface,
+				 cairo_region_t		*region);
+typedef cairo_int_status_t
+(*_paint_func)			(void			*surface,
+			         cairo_operator_t	 op,
+				 cairo_pattern_t	*source);
+
+typedef cairo_int_status_t
+(*_mask_func)			(void			*surface,
+			         cairo_operator_t	 op,
+				 cairo_pattern_t	*source,
+				 cairo_pattern_t	*mask);
+
+typedef cairo_int_status_t
+(*_stroke_func)			(void			*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);
+
+typedef cairo_int_status_t
+(*_fill_func)			(void			*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);
+
+typedef cairo_int_status_t
+(*_show_glyphs_func)		(void			*surface,
+			         cairo_operator_t	 op,
+				 cairo_pattern_t	*source,
+				 cairo_glyph_t		*glyphs,
+				 int			 num_glyphs,
+				 cairo_scaled_font_t	*scaled_font,
+				 int			*remaining_glyphs);
+
+static const cairo_surface_backend_t cairo_null_surface_backend = {
+    CAIRO_INTERNAL_SURFACE_TYPE_NULL,
+
+    NULL, /* create_similar */
+    NULL, /* 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 */
+    (_set_clip_region_func) _return_success, /* set_clip_region */
+    NULL, /* intersect_clip_path */
+    NULL, /* get_extents */
+    NULL, /* old_show_glyphs */
+    NULL, /* get_font_options */
+    NULL, /* flush */
+    NULL, /* mark_dirty_rectangle */
+    NULL, /* scaled_font_fini */
+    NULL, /* scaled_glyph_fini */
+    (_paint_func) _return_success,	    /* paint */
+    (_mask_func) _return_success,	    /* mask */
+    (_stroke_func) _return_success,	    /* stroke */
+    (_fill_func) _return_success,	    /* fill */
+    (_show_glyphs_func) _return_success,    /* show_glyphs */
+    NULL, /* snapshot */
+    NULL, /* is_similar */
+    NULL, /* reset */
+    NULL, /* fill_stroke */
+    NULL, /* create_solid_pattern_surface */
+    NULL, /* has_show_text_glyphs */
+    NULL  /* show_text_glyphs */
+};
+
+cairo_surface_t *
+_cairo_null_surface_create (cairo_content_t content)
+{
+    cairo_surface_t *surface;
+
+    surface = malloc (sizeof (cairo_surface_t));
+    if (surface == NULL) {
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+    }
+
+    _cairo_surface_init (surface, &cairo_null_surface_backend, content);
+
+    return surface;
+}
--- a/gfx/cairo/cairo/src/cairo-arc.c
+++ b/gfx/cairo/cairo/src/cairo-arc.c
@@ -176,23 +176,25 @@ static void
 _cairo_arc_in_direction (cairo_t	  *cr,
 			 double		   xc,
 			 double		   yc,
 			 double		   radius,
 			 double		   angle_min,
 			 double		   angle_max,
 			 cairo_direction_t dir)
 {
+    if (cairo_status (cr))
+        return;
+
     while (angle_max - angle_min > 4 * M_PI)
 	angle_max -= 2 * M_PI;
 
     /* Recurse if drawing arc larger than pi */
     if (angle_max - angle_min > M_PI) {
 	double angle_mid = angle_min + (angle_max - angle_min) / 2.0;
-	/* XXX: Something tells me this block could be condensed. */
 	if (dir == CAIRO_DIRECTION_FORWARD) {
 	    _cairo_arc_in_direction (cr, xc, yc, radius,
 				     angle_min, angle_mid,
 				     dir);
 
 	    _cairo_arc_in_direction (cr, xc, yc, radius,
 				     angle_mid, angle_max,
 				     dir);
@@ -200,17 +202,17 @@ static void
 	    _cairo_arc_in_direction (cr, xc, yc, radius,
 				     angle_mid, angle_max,
 				     dir);
 
 	    _cairo_arc_in_direction (cr, xc, yc, radius,
 				     angle_min, angle_mid,
 				     dir);
 	}
-    } else {
+    } else if (angle_max != angle_min) {
 	cairo_matrix_t ctm;
 	int i, segments;
 	double angle, angle_step;
 
 	cairo_get_matrix (cr, &ctm);
 	segments = _arc_segments_needed (angle_max - angle_min,
 					 radius, &ctm,
 					 cairo_get_tolerance (cr));
--- a/gfx/cairo/cairo/src/cairo-array.c
+++ b/gfx/cairo/cairo/src/cairo-array.c
@@ -231,17 +231,17 @@ void
  * Append a single item onto the array by growing the array by at
  * least one element, then copying element_size bytes from @element
  * into the array. The address of the resulting object within the
  * array can be determined with:
  *
  * _cairo_array_index (array, _cairo_array_num_elements (array) - 1);
  *
  * Return value: %CAIRO_STATUS_SUCCESS if successful or
- * CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
+ * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
  * operation.
  **/
 cairo_status_t
 _cairo_array_append (cairo_array_t	*array,
 		     const void		*element)
 {
     assert (! array->is_snapshot);
 
@@ -251,17 +251,17 @@ cairo_status_t
 /**
  * _cairo_array_append:
  *
  * Append one or more items onto the array by growing the array by
  * @num_elements, then copying @num_elements * element_size bytes from
  * @elements into the array.
  *
  * Return value: %CAIRO_STATUS_SUCCESS if successful or
- * CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
+ * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
  * operation.
  **/
 cairo_status_t
 _cairo_array_append_multiple (cairo_array_t	*array,
 			      const void	*elements,
 			      int		 num_elements)
 {
     cairo_status_t status;
@@ -282,17 +282,17 @@ cairo_status_t
  * _cairo_array_allocate:
  *
  * Allocate space at the end of the array for @num_elements additional
  * elements, providing the address of the new memory chunk in
  * @elements. This memory will be unitialized, but will be accounted
  * for in the return value of _cairo_array_num_elements().
  *
  * Return value: %CAIRO_STATUS_SUCCESS if successful or
- * CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
+ * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
  * operation.
  **/
 cairo_status_t
 _cairo_array_allocate (cairo_array_t	 *array,
 		       unsigned int	  num_elements,
 		       void		**elements)
 {
     cairo_status_t status;
--- a/gfx/cairo/cairo/src/cairo-base85-stream.c
+++ b/gfx/cairo/cairo/src/cairo-base85-stream.c
@@ -1,9 +1,10 @@
-/* cairo_output_stream.c: Output stream abstraction
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
+/* 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
--- a/gfx/cairo/cairo/src/cairo-bentley-ottmann.c
+++ b/gfx/cairo/cairo/src/cairo-bentley-ottmann.c
@@ -503,17 +503,17 @@ det64_128 (cairo_int64_t a,
 
     return _cairo_int128_sub (ad, bc);
 }
 
 /* Compute the intersection of two lines as defined by two edges. The
  * result is provided as a coordinate pair of 128-bit integers.
  *
  * Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection or
- * CAIRO_BO_STATUS_PARALLEL if the two lines are exactly parallel.
+ * %CAIRO_BO_STATUS_PARALLEL if the two lines are exactly parallel.
  */
 static cairo_bo_status_t
 intersect_lines (cairo_bo_edge_t		*a,
 		 cairo_bo_edge_t		*b,
 		 cairo_bo_intersect_point_t	*intersection)
 {
     cairo_int64_t a_det, b_det;
 
@@ -1209,17 +1209,17 @@ static cairo_status_t
 			int32_t			 top,
 			cairo_fill_rule_t	 fill_rule,
 			cairo_bo_traps_t	*bo_traps)
 {
     cairo_status_t status;
     int in_out = 0;
     cairo_bo_edge_t *edge;
 
-    for (edge = head; edge && edge->next; edge = edge->next) {
+    for (edge = head; edge; edge = edge->next) {
 	if (fill_rule == CAIRO_FILL_RULE_WINDING) {
 	    if (edge->reversed)
 		in_out++;
 	    else
 		in_out--;
 	    if (in_out == 0) {
 		status = _cairo_bo_edge_end_trap (edge, top, bo_traps);
 		if (status)
@@ -1410,19 +1410,19 @@ update_minmax(cairo_fixed_t *inout_min,
 {
     if (v < *inout_min)
 	*inout_min = v;
     if (v > *inout_max)
 	*inout_max = v;
 }
 
 cairo_status_t
-_cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t	*traps,
-					   cairo_polygon_t	*polygon,
-					   cairo_fill_rule_t	 fill_rule)
+_cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t	 *traps,
+					   const cairo_polygon_t *polygon,
+					   cairo_fill_rule_t	  fill_rule)
 {
     int intersections;
     cairo_status_t status;
     cairo_bo_edge_t stack_edges[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_edge_t)];
     cairo_bo_edge_t *edges;
     cairo_fixed_t xmin = 0x7FFFFFFF;
     cairo_fixed_t ymin = 0x7FFFFFFF;
     cairo_fixed_t xmax = -0x80000000;
--- a/gfx/cairo/cairo/src/cairo-beos.h
+++ b/gfx/cairo/cairo/src/cairo-beos.h
@@ -31,17 +31,17 @@
  * <cbiesinger@web.de>
  *
  * Contributor(s):
  */
 
 #ifndef CAIRO_BEOS_H
 #define CAIRO_BEOS_H
 
-#include <cairo.h>
+#include "cairo.h"
 
 #if CAIRO_HAS_BEOS_SURFACE
 
 #include <View.h>
 
 CAIRO_BEGIN_DECLS
 
 cairo_public cairo_surface_t *
--- a/gfx/cairo/cairo/src/cairo-cache.c
+++ b/gfx/cairo/cairo/src/cairo-cache.c
@@ -291,17 +291,17 @@ static void
  * @cache: a cache
  * @entry: an entry to be inserted
  *
  * Insert @entry into the cache. If an entry exists in the cache with
  * a matching key, then the old entry will be removed first, (and the
  * entry_destroy() callback will be called on it).
  *
  * Return value: %CAIRO_STATUS_SUCCESS if successful or
- * CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
+ * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
  **/
 cairo_status_t
 _cairo_cache_insert (cairo_cache_t	 *cache,
 		     cairo_cache_entry_t *entry)
 {
     cairo_status_t status;
 
     _cairo_cache_shrink_to_accommodate (cache, entry->size);
--- a/gfx/cairo/cairo/src/cairo-clip.c
+++ b/gfx/cairo/cairo/src/cairo-clip.c
@@ -269,23 +269,23 @@ cairo_status_t
 cairo_status_t
 _cairo_clip_combine_to_surface (cairo_clip_t                  *clip,
 				cairo_operator_t              op,
 				cairo_surface_t               *dst,
 				int                           dst_x,
 				int                           dst_y,
 				const cairo_rectangle_int_t *extents)
 {
-    cairo_pattern_union_t pattern;
+    cairo_surface_pattern_t pattern;
     cairo_status_t status;
 
     if (clip->all_clipped)
 	return CAIRO_STATUS_SUCCESS;
 
-    _cairo_pattern_init_for_surface (&pattern.surface, clip->surface);
+    _cairo_pattern_init_for_surface (&pattern, clip->surface);
 
     status = _cairo_surface_composite (op,
 				       &pattern.base,
 				       NULL,
 				       dst,
 				       extents->x - clip->surface_rect.x,
 				       extents->y - clip->surface_rect.y,
 				       0, 0,
@@ -480,18 +480,17 @@ static cairo_status_t
 	bounded by the mask.
 
     */
 
     surface = _cairo_surface_create_similar_solid (target,
 						   CAIRO_CONTENT_ALPHA,
 						   surface_rect.width,
 						   surface_rect.height,
-						   CAIRO_COLOR_TRANSPARENT,
-						   &pattern.base);
+						   CAIRO_COLOR_TRANSPARENT);
     if (surface->status) {
 	_cairo_pattern_fini (&pattern.base);
 	return surface->status;
     }
 
     /* Render the new clipping path into the new mask surface. */
 
     _cairo_traps_translate (traps, -surface_rect.x, -surface_rect.y);
@@ -625,17 +624,17 @@ void
         cairo_clip_path_t *clip_path = clip->path;
 	cairo_matrix_t matrix;
 
 	cairo_matrix_init_translate (&matrix,
 				     _cairo_fixed_to_double (tx),
 				     _cairo_fixed_to_double (ty));
 
         while (clip_path) {
-            _cairo_path_fixed_device_transform (&clip_path->path, &matrix);
+            _cairo_path_fixed_transform (&clip_path->path, &matrix);
             clip_path = clip_path->prev;
         }
     }
 }
 
 static cairo_status_t
 _cairo_clip_path_reapply_clip_path (cairo_clip_t      *clip,
                                     cairo_clip_path_t *clip_path)
@@ -673,17 +672,18 @@ cairo_status_t
 	    if (status)
 		goto BAIL;
 
 	    clip->has_region = TRUE;
         }
 
         if (other->surface) {
             status = _cairo_surface_clone_similar (target, other->surface,
-					           0, 0,
+					           0,
+						   0,
 						   other->surface_rect.width,
 						   other->surface_rect.height,
 						   &clip->surface);
 	    if (status)
 		goto BAIL;
 
             clip->surface_rect = other->surface_rect;
         }
--- a/gfx/cairo/cairo/src/cairo-compiler-private.h
+++ b/gfx/cairo/cairo/src/cairo-compiler-private.h
@@ -106,17 +106,17 @@ CAIRO_BEGIN_DECLS
 #else
 # define CAIRO_FUNCTION_ALIAS(old, new)
 #endif
 
 #ifndef __GNUC__
 #define __attribute__(x)
 #endif
 
-#if defined(__WIN32__) || defined(_MSC_VER)
+#if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER)
 #define snprintf _snprintf
 #endif
 
 #ifdef _MSC_VER
 #undef inline
 #define inline __inline
 #endif
 
--- a/gfx/cairo/cairo/src/cairo-debug.c
+++ b/gfx/cairo/cairo/src/cairo-debug.c
@@ -56,20 +56,20 @@
  * objects, this call is likely to cause a crash, (eg. an assertion
  * failure due to a hash table being destroyed when non-empty).
  **/
 void
 cairo_debug_reset_static_data (void)
 {
     CAIRO_MUTEX_INITIALIZE ();
 
-    _cairo_font_reset_static_data ();
+    _cairo_font_face_reset_static_data ();
 
 #if CAIRO_HAS_FT_FONT
     _cairo_ft_font_reset_static_data ();
 #endif
 
-    _cairo_pattern_reset_static_data ();
+    _cairo_scaled_font_reset_static_data ();
 
-    _cairo_scaled_font_reset_static_data ();
+    _cairo_pattern_reset_static_data ();
 
     CAIRO_MUTEX_FINALIZE ();
 }
deleted file mode 100644
--- a/gfx/cairo/cairo/src/cairo-debug.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/* 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):
- *	Carl D. Worth <cworth@cworth.org>
- */
-
-#ifndef CAIRO_DEBUG_H
-#define CAIRO_DEBUG_H
-
-#include <cairo-features.h>
-#include <stdio.h>
-
-CAIRO_BEGIN_DECLS
-
-struct _cairo_path_fixed;
-struct _cairo_traps;
-struct _cairo_trapezoid;
-struct _cairo_clip;
-
-cairo_public void
-cairo_debug_reset_static_data (void);
-
-cairo_public void
-cairo_debug_dump_clip (struct _cairo_clip *clip,
-                       FILE *fp);
-cairo_public void
-cairo_debug_dump_path (struct _cairo_path_fixed *path,
-                       FILE *fp);
-
-cairo_public void
-cairo_debug_dump_traps (struct _cairo_traps *traps,
-                        FILE *fp);
-
-cairo_public void
-cairo_debug_dump_trapezoid_array (struct _cairo_trapezoid *traps,
-                                  int num_traps,
-                                  FILE *fp);
-
-CAIRO_END_DECLS
-
-#endif /* CAIRO_H */
--- a/gfx/cairo/cairo/src/cairo-deflate-stream.c
+++ b/gfx/cairo/cairo/src/cairo-deflate-stream.c
@@ -1,9 +1,10 @@
-/* cairo_deflate_stream.c: Output stream abstraction
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
+/* cairo - a vector graphics library with display and print output
  *
  * Copyright © 2006 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
--- a/gfx/cairo/cairo/src/cairo-deprecated.h
+++ b/gfx/cairo/cairo/src/cairo-deprecated.h
@@ -47,18 +47,16 @@
  * Additionally, the support for the RGB16_565 format was never
  * completely implemented. So while this format value is currently
  * deprecated, it may eventually acquire complete support in the future.
  */
 #define CAIRO_FORMAT_RGB16_565 4
 
 #define CAIRO_FONT_TYPE_ATSUI CAIRO_FONT_TYPE_QUARTZ
 
-#ifndef _CAIROINT_H_
-
 /* Obsolete functions. These definitions exist to coerce the compiler
  * into providing a little bit of guidance with its error
  * messages. The idea is to help users port their old code without
  * having to dig through lots of documentation.
  *
  * The first set of REPLACED_BY functions is for functions whose names
  * have just been changed. So fixing these up is mechanical, (and
  * automated by means of the cairo/util/cairo-api-update script.
@@ -132,11 +130,9 @@
 #define cairo_set_target_ps		cairo_set_target_ps_DEPRECATED_BY_cairo_ps_surface_create
 #define cairo_set_target_quartz		cairo_set_target_quartz_DEPRECATED_BY_cairo_quartz_surface_create
 #define cairo_set_target_win32		cairo_set_target_win32_DEPRECATED_BY_cairo_win32_surface_create
 #define cairo_set_target_xcb		cairo_set_target_xcb_DEPRECATED_BY_cairo_xcb_surface_create
 #define cairo_set_target_drawable	cairo_set_target_drawable_DEPRECATED_BY_cairo_xlib_surface_create
 #define cairo_get_status_string		cairo_get_status_string_DEPRECATED_BY_cairo_status_AND_cairo_status_to_string
 #define cairo_status_string		cairo_status_string_DEPRECATED_BY_cairo_status_AND_cairo_status_to_string
 
-#endif
-
 #endif /* CAIRO_DEPRECATED_H */
--- a/gfx/cairo/cairo/src/cairo-directfb-surface.c
+++ b/gfx/cairo/cairo/src/cairo-directfb-surface.c
@@ -1601,17 +1601,18 @@ static void
 }
 
 static cairo_int_status_t
 _cairo_directfb_surface_show_glyphs (void                *abstract_dst,
                                      cairo_operator_t     op,
                                      cairo_pattern_t     *pattern,
                                      cairo_glyph_t       *glyphs,
                                      int                  num_glyphs,
-                                     cairo_scaled_font_t *scaled_font)
+                                     cairo_scaled_font_t *scaled_font,
+				     int		 *remaining_glyphs)
 {
     cairo_directfb_surface_t    *dst = abstract_dst;
     cairo_directfb_font_cache_t *cache;
     cairo_status_t               ret;
     DFBSurfaceBlittingFlags      flags;
     DFBSurfaceBlendFunction      sblend;
     DFBSurfaceBlendFunction      dblend;
     DFBColor                     color;
--- a/gfx/cairo/cairo/src/cairo-directfb.h
+++ b/gfx/cairo/cairo/src/cairo-directfb.h
@@ -42,17 +42,17 @@
  *
  *  %CAIRO_DIRECTFB_ARGB_FONT (boolean)
  *      if found, enables using ARGB fonts instead of A8
  */
 
 #ifndef CAIRO_DIRECTFB_H
 #define CAIRO_DIRECTFB_H
 
-#include <cairo.h>
+#include "cairo.h"
 
 #ifdef  CAIRO_HAS_DIRECTFB_SURFACE
 
 #include <directfb.h>
 
 CAIRO_BEGIN_DECLS
 
 cairo_public cairo_surface_t *
--- a/gfx/cairo/cairo/src/cairo-fixed-private.h
+++ b/gfx/cairo/cairo/src/cairo-fixed-private.h
@@ -221,13 +221,24 @@ static inline cairo_fixed_16_16_t
 
 static inline cairo_fixed_t
 _cairo_fixed_mul (cairo_fixed_t a, cairo_fixed_t b)
 {
     cairo_int64_t temp = _cairo_int32x32_64_mul (a, b);
     return _cairo_int64_to_int32(_cairo_int64_rsl (temp, CAIRO_FIXED_FRAC_BITS));
 }
 
+/* computes a * b / c */
+static inline cairo_fixed_t
+_cairo_fixed_mul_div (cairo_fixed_t a, cairo_fixed_t b, cairo_fixed_t c)
+{
+    cairo_int64_t ab  = _cairo_int32x32_64_mul (a, b);
+    cairo_int64_t c64 = _cairo_int32_to_int64 (c);
+    cairo_int64_t quo = _cairo_int64_divrem (ab, c64).quo;
+
+    return _cairo_int64_to_int32(quo);
+}
+
 #else
 # error Please define multiplication and other operands for your fixed-point type size
 #endif
 
 #endif /* CAIRO_FIXED_PRIVATE_H */
--- a/gfx/cairo/cairo/src/cairo-font-face.c
+++ b/gfx/cairo/cairo/src/cairo-font-face.c
@@ -58,16 +58,18 @@ const cairo_font_face_t _cairo_font_face
 
 cairo_status_t
 _cairo_font_face_set_error (cairo_font_face_t *font_face,
 	                    cairo_status_t     status)
 {
     if (status == CAIRO_STATUS_SUCCESS)
 	return status;
 
+    /* Don't overwrite an existing error. This preserves the first
+     * error, which is the most significant. */
     _cairo_status_set_error (&font_face->status, status);
 
     return _cairo_error (status);
 }
 
 void
 _cairo_font_face_init (cairo_font_face_t               *font_face,
 		       const cairo_font_face_backend_t *backend)
@@ -127,17 +129,18 @@ cairo_font_face_destroy (cairo_font_face
 	    CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
 	return;
 
     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&font_face->ref_count));
 
     if (! _cairo_reference_count_dec_and_test (&font_face->ref_count))
 	return;
 
-    font_face->backend->destroy (font_face);
+    if (font_face->backend->destroy)
+	font_face->backend->destroy (font_face);
 
     /* We allow resurrection to deal with some memory management for the
      * FreeType backend where cairo_ft_font_face_t and cairo_ft_unscaled_font_t
      * need to effectively mutually reference each other
      */
     if (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&font_face->ref_count))
 	return;
 
@@ -529,17 +532,17 @@ void
 	return;
 
     unscaled_font->backend->destroy (unscaled_font);
 
     free (unscaled_font);
 }
 
 void
-_cairo_font_reset_static_data (void)
+_cairo_font_face_reset_static_data (void)
 {
     _cairo_scaled_font_map_destroy ();
 
     /* We manually acquire the lock rather than calling
      * cairo_toy_font_face_hash_table_lock simply to avoid
      * creating the table only to destroy it again. */
     CAIRO_MUTEX_LOCK (_cairo_font_face_mutex);
     _cairo_hash_table_destroy (cairo_toy_font_face_hash_table);
--- a/gfx/cairo/cairo/src/cairo-font-options.c
+++ b/gfx/cairo/cairo/src/cairo-font-options.c
@@ -90,17 +90,16 @@ cairo_font_options_create (void)
 	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
 	return (cairo_font_options_t *) &_cairo_font_options_nil;
     }
 
     _cairo_font_options_init_default (options);
 
     return options;
 }
-slim_hidden_def (cairo_font_options_create);
 
 /**
  * cairo_font_options_copy:
  * @original: a #cairo_font_options_t
  *
  * Allocates a new font options object copying the option values from
  *  @original.
  *
@@ -139,17 +138,16 @@ cairo_font_options_copy (const cairo_fon
 void
 cairo_font_options_destroy (cairo_font_options_t *options)
 {
     if (cairo_font_options_status (options))
 	return;
 
     free (options);
 }
-slim_hidden_def (cairo_font_options_destroy);
 
 /**
  * cairo_font_options_status:
  * @options: a #cairo_font_options_t
  *
  * Checks whether an error has previously occurred for this
  * font options object
  *
--- a/gfx/cairo/cairo/src/cairo-ft-font.c
+++ b/gfx/cairo/cairo/src/cairo-ft-font.c
@@ -1,8 +1,9 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
 /* cairo - a vector graphics library with display and print output
  *
  * Copyright © 2000 Keith Packard
  * 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
@@ -86,17 +87,17 @@ typedef struct _cairo_ft_font_transform 
  * just create a one-off version with a permanent face value.
  */
 
 typedef struct _cairo_ft_font_face cairo_ft_font_face_t;
 
 struct _cairo_ft_unscaled_font {
     cairo_unscaled_font_t base;
 
-    cairo_bool_t from_face; /* from cairo_ft_font_face_create_for_ft_face()? */
+    cairo_bool_t from_face; /* was the FT_Face provided by user? */
     FT_Face face;	    /* provided or cached face */
 
     /* only set if from_face is false */
     char *filename;
     int id;
 
     /* We temporarily scale the unscaled font as needed */
     cairo_bool_t have_scale;
@@ -277,27 +278,32 @@ static cairo_ft_unscaled_font_map_t *
 static void
 _cairo_ft_unscaled_font_map_unlock (void)
 {
     CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex);
 }
 
 static void
 _cairo_ft_unscaled_font_init_key (cairo_ft_unscaled_font_t *key,
+				  cairo_bool_t              from_face,
 				  char			   *filename,
-				  int			    id)
+				  int			    id,
+				  FT_Face		    face)
 {
     unsigned long hash;
 
+    key->from_face = from_face;
     key->filename = filename;
     key->id = id;
-
-    /* 1607 is just an arbitrary prime. */
+    key->face = face;
+
     hash = _cairo_hash_string (filename);
+    /* the constants are just arbitrary primes */
     hash += ((unsigned long) id) * 1607;
+    hash += ((unsigned long) face) * 2137;
 
     key->base.hash_entry.hash = hash;
 }
 
 /**
  * _cairo_ft_unscaled_font_init:
  *
  * Initialize a #cairo_ft_unscaled_font_t.
@@ -315,56 +321,48 @@ static void
  * Note that the code handles these two flavors in very distinct
  * ways. For example there is a hash_table mapping
  * filename/id->#cairo_unscaled_font_t in the !from_face case, but no
  * parallel in the from_face case, (where the calling code would have
  * to do its own mapping to ensure similar sharing).
  **/
 static cairo_status_t
 _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled,
+			      cairo_bool_t              from_face,
 			      const char	       *filename,
 			      int			id,
 			      FT_Face			face)
 {
     _cairo_unscaled_font_init (&unscaled->base,
 			       &cairo_ft_unscaled_font_backend);
 
-    if (face) {
+    if (from_face) {
 	unscaled->from_face = TRUE;
-	unscaled->face = face;
-	unscaled->filename = NULL;
-	unscaled->id = 0;
+	_cairo_ft_unscaled_font_init_key (unscaled, TRUE, NULL, 0, face);
     } else {
 	char *filename_copy;
 
 	unscaled->from_face = FALSE;
 	unscaled->face = NULL;
 
 	filename_copy = strdup (filename);
 	if (filename_copy == NULL)
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-	_cairo_ft_unscaled_font_init_key (unscaled, filename_copy, id);
+	_cairo_ft_unscaled_font_init_key (unscaled, FALSE, filename_copy, id, NULL);
     }
 
     unscaled->have_scale = FALSE;
     CAIRO_MUTEX_INIT (unscaled->mutex);
     unscaled->lock_count = 0;
 
     unscaled->faces = NULL;
 
     return CAIRO_STATUS_SUCCESS;
 }
 
-cairo_bool_t
-_cairo_unscaled_font_is_ft (cairo_unscaled_font_t *unscaled_font)
-{
-    return unscaled_font->backend == &cairo_ft_unscaled_font_backend;
-}
-
 /**
  * _cairo_ft_unscaled_font_fini:
  *
  * Free all data associated with a #cairo_ft_unscaled_font_t.
  *
  * CAUTION: The unscaled->face field must be %NULL before calling this
  * function. This is because the #cairo_ft_unscaled_font_t_map keeps a
  * count of these faces (font_map->num_open_faces) so it maintains the
@@ -386,45 +384,51 @@ static void
 
 static int
 _cairo_ft_unscaled_font_keys_equal (const void *key_a,
 				    const void *key_b)
 {
     const cairo_ft_unscaled_font_t *unscaled_a = key_a;
     const cairo_ft_unscaled_font_t *unscaled_b = key_b;
 
-    return (strcmp (unscaled_a->filename, unscaled_b->filename) == 0 &&
-	    unscaled_a->id == unscaled_b->id);
+    if (unscaled_a->id == unscaled_b->id &&
+	unscaled_a->from_face == unscaled_b->from_face)
+    {
+        if (unscaled_a->from_face)
+	    return unscaled_a->face == unscaled_b->face;
+
+	if (unscaled_a->filename == NULL && unscaled_b->filename == NULL)
+	    return TRUE;
+	else if (unscaled_a->filename == NULL || unscaled_b->filename == NULL)
+	    return FALSE;
+	else
+	    return (strcmp (unscaled_a->filename, unscaled_b->filename) == 0);
+    }
+
+    return FALSE;
 }
 
 /* Finds or creates a #cairo_ft_unscaled_font_t for the filename/id from
  * pattern.  Returns a new reference to the unscaled font.
  */
 static cairo_ft_unscaled_font_t *
-_cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern)
+_cairo_ft_unscaled_font_create_internal (cairo_bool_t from_face,
+					 char *filename,
+					 int id,
+					 FT_Face font_face)
 {
     cairo_ft_unscaled_font_t key, *unscaled;
     cairo_ft_unscaled_font_map_t *font_map;
     cairo_status_t status;
-    FcChar8 *fc_filename;
-    char *filename;
-    int id;
-
-    if (FcPatternGetString (pattern, FC_FILE, 0, &fc_filename) != FcResultMatch)
-	goto UNWIND;
-    filename = (char *) fc_filename;
-
-    if (FcPatternGetInteger (pattern, FC_INDEX, 0, &id) != FcResultMatch)
-	goto UNWIND;
 
     font_map = _cairo_ft_unscaled_font_map_lock ();
     if (font_map == NULL)
 	goto UNWIND;
 
-    _cairo_ft_unscaled_font_init_key (&key, filename, id);
+    _cairo_ft_unscaled_font_init_key (&key, from_face, filename, id, font_face);
 
     /* Return existing unscaled font if it exists in the hash table. */
     if (_cairo_hash_table_lookup (font_map->hash_table, &key.base.hash_entry,
 				  (cairo_hash_entry_t **) &unscaled))
     {
 	_cairo_unscaled_font_reference (&unscaled->base);
 	_cairo_ft_unscaled_font_map_unlock ();
 	return unscaled;
@@ -432,17 +436,17 @@ static cairo_ft_unscaled_font_t *
 
     /* Otherwise create it and insert into hash table. */
     unscaled = malloc (sizeof (cairo_ft_unscaled_font_t));
     if (unscaled == NULL) {
 	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
 	goto UNWIND_FONT_MAP_LOCK;
     }
 
-    status = _cairo_ft_unscaled_font_init (unscaled, filename, id, NULL);
+    status = _cairo_ft_unscaled_font_init (unscaled, from_face, filename, id, font_face);
     if (status)
 	goto UNWIND_UNSCALED_MALLOC;
 
     status = _cairo_hash_table_insert (font_map->hash_table,
 				       &unscaled->base.hash_entry);
     if (status)
 	goto UNWIND_UNSCALED_FONT_INIT;
 
@@ -455,67 +459,76 @@ UNWIND_UNSCALED_FONT_INIT:
 UNWIND_UNSCALED_MALLOC:
     free (unscaled);
 UNWIND_FONT_MAP_LOCK:
     _cairo_ft_unscaled_font_map_unlock ();
 UNWIND:
     return NULL;
 }
 
+
+static cairo_ft_unscaled_font_t *
+_cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern)
+{
+    FT_Face font_face = NULL;
+    char *filename = NULL;
+    int id = 0;
+
+    if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &font_face) != FcResultMatch) {
+	FcChar8 *fc_filename = NULL;
+
+	if (FcPatternGetString (pattern, FC_FILE, 0, &fc_filename) != FcResultMatch)
+	    goto UNWIND;
+	filename = (char *) fc_filename;
+
+	if (FcPatternGetInteger (pattern, FC_INDEX, 0, &id) != FcResultMatch)
+	    goto UNWIND;
+    }
+
+    return _cairo_ft_unscaled_font_create_internal (font_face != NULL, filename, id, font_face);
+
+UNWIND:
+    return NULL;
+}
+
 static cairo_ft_unscaled_font_t *
 _cairo_ft_unscaled_font_create_from_face (FT_Face face)
 {
-    cairo_status_t status;
-    cairo_ft_unscaled_font_t *unscaled;
-
-    unscaled = malloc (sizeof (cairo_ft_unscaled_font_t));
-    if (unscaled == NULL) {
-	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
-	return NULL;
-    }
-
-    status = _cairo_ft_unscaled_font_init (unscaled, NULL, 0, face);
-    if (status) {
-	free (unscaled);
-	return NULL;
-    }
-
-    return unscaled;
+    return _cairo_ft_unscaled_font_create_internal (TRUE, NULL, 0, face);
 }
 
 static void
 _cairo_ft_unscaled_font_destroy (void *abstract_font)
 {
     cairo_ft_unscaled_font_t *unscaled  = abstract_font;
+    cairo_ft_unscaled_font_map_t *font_map;
 
     if (unscaled == NULL)
 	return;
 
+    font_map = _cairo_ft_unscaled_font_map_lock ();
+    /* All created objects must have been mapped in the font map. */
+    assert (font_map != NULL);
+
+    _cairo_hash_table_remove (font_map->hash_table,
+			      &unscaled->base.hash_entry);
+
     if (unscaled->from_face) {
 	/* See comments in _ft_font_face_destroy about the "zombie" state
 	 * for a _ft_font_face.
 	 */
 	if (unscaled->faces && !unscaled->faces->unscaled)
 	    cairo_font_face_destroy (&unscaled->faces->base);
-
-	unscaled->face = NULL;
     } else {
-	cairo_ft_unscaled_font_map_t *font_map;
-
-	font_map = _cairo_ft_unscaled_font_map_lock ();
-	/* All created objects must have been mapped in the font map. */
-	assert (font_map != NULL);
-
-	_cairo_hash_table_remove (font_map->hash_table,
-				  &unscaled->base.hash_entry);
-
 	_font_map_release_face_lock_held (font_map, unscaled);
-
-	_cairo_ft_unscaled_font_map_unlock ();
     }
+    unscaled->face = NULL;
+
+    _cairo_ft_unscaled_font_map_unlock ();
+
     _cairo_ft_unscaled_font_fini (unscaled);
 }
 
 static cairo_bool_t
 _has_unlocked_face (void *entry)
 {
     cairo_ft_unscaled_font_t *unscaled = entry;
 
@@ -574,30 +587,30 @@ FT_Face
     }
 
     unscaled->face = face;
 
     font_map->num_open_faces++;
 
     return face;
 }
-slim_hidden_def (cairo_ft_scaled_font_lock_face);
+
 
 /* Unlock unscaled font locked with _cairo_ft_unscaled_font_lock_face
  */
 void
 _cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled)
 {
     assert (unscaled->lock_count > 0);
 
     unscaled->lock_count--;
 
     CAIRO_MUTEX_UNLOCK (unscaled->mutex);
 }
-slim_hidden_def (cairo_ft_scaled_font_unlock_face);
+
 
 static cairo_status_t
 _compute_transform (cairo_ft_font_transform_t *sf,
 		    cairo_matrix_t      *scale)
 {
     cairo_status_t status;
     double x_scale, y_scale;
     cairo_matrix_t normalized = *scale;
@@ -606,17 +619,17 @@ static cairo_status_t
      * 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.
      */
 
     status = _cairo_matrix_compute_scale_factors (scale,
 						  &x_scale, &y_scale,
-						  /* XXX */ 1);
+						  1);
     if (status)
 	return status;
 
     /* FreeType docs say this about x_scale and y_scale:
      * "A character width or height smaller than 1pt is set to 1pt;"
      * So, we cap them from below at 1.0 and let the FT transform
      * take care of sub-1.0 scaling. */
     if (x_scale < 1.0)
@@ -1269,17 +1282,17 @@ static const cairo_unscaled_font_backend
 /* #cairo_ft_scaled_font_t */
 
 typedef struct _cairo_ft_scaled_font {
     cairo_scaled_font_t base;
     cairo_ft_unscaled_font_t *unscaled;
     cairo_ft_options_t ft_options;
 } cairo_ft_scaled_font_t;
 
-const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend;
+const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend;
 
 /* The load flags passed to FT_Load_Glyph control aspects like hinting and
  * antialiasing. Here we compute them from the fields of a FcPattern.
  */
 static void
 _get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret)
 {
     FcBool antialias, vertical_layout, hinting, autohint, bitmap, embolden;
@@ -1514,17 +1527,17 @@ static cairo_status_t
     scaled_font->unscaled = unscaled;
 
     _cairo_font_options_init_copy (&scaled_font->ft_options.base, options);
     _cairo_ft_options_merge (&scaled_font->ft_options, &ft_options);
 
     status = _cairo_scaled_font_init (&scaled_font->base,
 			              font_face,
 				      font_matrix, ctm, options,
-				      &cairo_ft_scaled_font_backend);
+				      &_cairo_ft_scaled_font_backend);
     if (status) {
 	_cairo_unscaled_font_destroy (&unscaled->base);
 	free (scaled_font);
 	goto FAIL;
     }
 
     status = _cairo_ft_unscaled_font_set_scale (unscaled,
 				                &scaled_font->base.scale);
@@ -1592,17 +1605,17 @@ static cairo_status_t
     _cairo_ft_unscaled_font_unlock_face (unscaled);
 
     return status;
 }
 
 cairo_bool_t
 _cairo_scaled_font_is_ft (cairo_scaled_font_t *scaled_font)
 {
-    return scaled_font->backend == &cairo_ft_scaled_font_backend;
+    return scaled_font->backend == &_cairo_ft_scaled_font_backend;
 }
 
 static cairo_status_t
 _cairo_ft_scaled_font_create_toy (cairo_toy_font_face_t	      *toy_face,
 				  const cairo_matrix_t	      *font_matrix,
 				  const cairo_matrix_t	      *ctm,
 				  const cairo_font_options_t  *font_options,
 				  cairo_scaled_font_t	     **font)
@@ -2164,59 +2177,55 @@ static cairo_int_status_t
 
     _cairo_ft_unscaled_font_unlock_face (unscaled);
 #endif
 
     return status;
 }
 
 static cairo_int_status_t
-_cairo_ft_map_glyphs_to_unicode (void	                    *abstract_font,
-                                 cairo_scaled_font_subset_t *font_subset)
+_cairo_ft_index_to_ucs4(void	        *abstract_font,
+			unsigned long    index,
+			uint32_t	*ucs4)
 {
     cairo_ft_scaled_font_t *scaled_font = abstract_font;
     cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled;
     FT_Face face;
-    FT_UInt glyph;
-    unsigned long charcode;
-    unsigned int i;
-    int count;
+    FT_ULong  charcode;
+    FT_UInt   gindex;
 
     face = _cairo_ft_unscaled_font_lock_face (unscaled);
     if (!face)
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-    count = font_subset->num_glyphs;
-    charcode = FT_Get_First_Char( face, &glyph);
-    while (glyph != 0 && count > 0)
-    {
-        for (i = 0; i < font_subset->num_glyphs; i++) {
-            if (font_subset->glyphs[i] == glyph) {
-                font_subset->to_unicode[i] = charcode;
-                count--;
-                break;
-            }
-        }
-        charcode = FT_Get_Next_Char (face, charcode, &glyph);
+    *ucs4 = (uint32_t) -1;
+    charcode = FT_Get_First_Char(face, &gindex);
+    while (gindex != 0) {
+	charcode = FT_Get_Next_Char (face, charcode, &gindex);
+	if (gindex == index) {
+	    *ucs4 = charcode;
+	    break;
+	}
     }
+
     _cairo_ft_unscaled_font_unlock_face (unscaled);
 
     return CAIRO_STATUS_SUCCESS;
 }
 
-const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend = {
+const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend = {
     CAIRO_FONT_TYPE_FT,
     _cairo_ft_scaled_font_create_toy,
     _cairo_ft_scaled_font_fini,
     _cairo_ft_scaled_glyph_init,
     NULL,			/* text_to_glyphs */
     _cairo_ft_ucs4_to_index,
     NULL, 			/* show_glyphs */
     _cairo_ft_load_truetype_table,
-    _cairo_ft_map_glyphs_to_unicode,
+    _cairo_ft_index_to_ucs4
 };
 
 /* #cairo_ft_font_face_t */
 
 static void
 _cairo_ft_font_face_destroy (void *abstract_face)
 {
     cairo_ft_font_face_t *font_face = abstract_face;
@@ -2287,16 +2296,20 @@ static cairo_status_t
     /* The handling of font options is different depending on how the
      * font face was created. When the user creates a font face with
      * cairo_ft_font_face_create_for_ft_face(), then the load flags
      * passed in augment the load flags for the options.  But for
      * cairo_ft_font_face_create_for_pattern(), the load flags are
      * derived from a pattern where the user has called
      * cairo_ft_font_options_substitute(), so *just* use those load
      * flags and ignore the options.
+     *
+     * XXX two points about the above comment:
+     * 1. I don't see how the comment is relevant here,
+     * 2. What if the face is coming from FC_FT_FACE of a pattern?
      */
 
     ft_options = font_face->ft_options;
 
     return  _cairo_ft_scaled_font_create (font_face->unscaled,
 					  &font_face->base,
 					  font_matrix, ctm,
 					  options, ft_options,
@@ -2482,24 +2495,35 @@ cairo_ft_font_options_substitute (const 
  *   release your reference to the pattern with FcPatternDestroy() if
  *   you no longer need to access it.
  *
  * Creates a new font face for the FreeType font backend based on a
  * fontconfig pattern. This font can then be used with
  * cairo_set_font_face() or cairo_scaled_font_create(). The
  * #cairo_scaled_font_t returned from cairo_scaled_font_create() is
  * also for the FreeType backend and can be used with functions such
- * as cairo_ft_font_lock_face().
+ * as cairo_ft_scaled_font_lock_face().
  *
  * Font rendering options are represented both here and when you
  * call cairo_scaled_font_create(). Font options that have a representation
  * in a #FcPattern must be passed in here; to modify #FcPattern
  * appropriately to reflect the options in a #cairo_font_options_t, call
  * cairo_ft_font_options_substitute().
  *
+ * The pattern's FC_FT_FACE element is inspected first and if that is set,
+ * that will be the FreeType font face associated with the returned cairo
+ * font face.  Otherwise the FC_FILE and FC_INDEX elements of @pattern are
+ * used to load a font face from file.
+ *
+ * If the FC_FT_FACE element of @pattern is set, the user is responsible
+ * for making sure that the referenced FT_Face remains valid for the life
+ * time of the returned #cairo_font_face_t.  See
+ * cairo_ft_font_face_create_for_ft_face() for an exmaple of how to couple
+ * the life time of the FT_Face to that of the cairo font-face.
+ *
  * Return value: a newly created #cairo_font_face_t. Free with
  *  cairo_font_face_destroy() when you are done using it.
  **/
 cairo_font_face_t *
 cairo_ft_font_face_create_for_pattern (FcPattern *pattern)
 {
     cairo_ft_unscaled_font_t *unscaled;
     cairo_font_face_t *font_face;
@@ -2534,17 +2558,33 @@ cairo_ft_font_face_create_for_pattern (F
  *   are useful. You should not pass any of the flags affecting
  *   the load target, such as %FT_LOAD_TARGET_LIGHT.
  *
  * Creates a new font face for the FreeType font backend from a
  * pre-opened FreeType face. This font can then be used with
  * cairo_set_font_face() or cairo_scaled_font_create(). The
  * #cairo_scaled_font_t returned from cairo_scaled_font_create() is
  * also for the FreeType backend and can be used with functions such
- * as cairo_ft_font_lock_face().
+ * as cairo_ft_scaled_font_lock_face().
+ *
+ * As an example, here is how one might correctly couple the lifetime of
+ * the FreeType face object to the #cairo_font_face_t:
+ *
+ * <informalexample><programlisting>
+ * static const cairo_user_data_key_t key;
+ *
+ * font_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0);
+ * status = cairo_font_face_set_user_data (font_face, &key,
+ *                                ft_face, (cairo_destroy_func_t) FT_Done_Face);
+ * if (status) {
+ *    cairo_font_face_destroy (font_face);
+ *    FT_Done_Face (ft_face);
+ *    return ERROR;
+ * }
+ * </programlisting></informalexample>
  *
  * Return value: a newly created #cairo_font_face_t. Free with
  *  cairo_font_face_destroy() when you are done using it.
  **/
 cairo_font_face_t *
 cairo_ft_font_face_create_for_ft_face (FT_Face         face,
 				       int             load_flags)
 {
@@ -2568,26 +2608,26 @@ cairo_ft_font_face_create_for_ft_face (F
     return font_face;
 }
 
 /**
  * cairo_ft_scaled_font_lock_face:
  * @scaled_font: A #cairo_scaled_font_t from the FreeType font backend. Such an
  *   object can be created by calling cairo_scaled_font_create() on a
  *   FreeType backend font face (see cairo_ft_font_face_create_for_pattern(),
- *   cairo_ft_font_face_create_for_face()).
+ *   cairo_ft_font_face_create_for_ft_face()).
  *
- * cairo_ft_font_lock_face() gets the #FT_Face object from a FreeType
+ * cairo_ft_scaled_font_lock_face() gets the #FT_Face object from a FreeType
  * backend font and scales it appropriately for the font. You must
- * release the face with cairo_ft_font_unlock_face()
+ * release the face with cairo_ft_scaled_font_unlock_face()
  * when you are done using it.  Since the #FT_Face object can be
  * shared between multiple #cairo_scaled_font_t objects, you must not
  * lock any other font objects until you unlock this one. A count is
- * kept of the number of times cairo_ft_font_lock_face() is
- * called. cairo_ft_font_unlock_face() must be called the same number
+ * kept of the number of times cairo_ft_scaled_font_lock_face() is
+ * called. cairo_ft_scaled_font_unlock_face() must be called the same number
  * of times.
  *
  * You must be careful when using this function in a library or in a
  * threaded application, because freetype's design makes it unsafe to
  * call freetype functions simultaneously from multiple threads, (even
  * if using distinct FT_Face objects). Because of this, application
  * code that acquires an FT_Face object with this call must add it's
  * own locking to protect any use of that object, (and which also must
@@ -2600,16 +2640,21 @@ cairo_ft_font_face_create_for_ft_face (F
  **/
 FT_Face
 cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font)
 {
     cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font;
     FT_Face face;
     cairo_status_t status;
 
+    if (! _cairo_scaled_font_is_ft (abstract_font)) {
+	_cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH);
+	return NULL;
+    }
+
     if (scaled_font->base.status)
 	return NULL;
 
     face = _cairo_ft_unscaled_font_lock_face (scaled_font->unscaled);
     if (face == NULL) {
 	status = _cairo_scaled_font_set_error (&scaled_font->base, CAIRO_STATUS_NO_MEMORY);
 	return NULL;
     }
@@ -2642,16 +2687,21 @@ cairo_ft_scaled_font_lock_face (cairo_sc
  *
  * Releases a face obtained with cairo_ft_scaled_font_lock_face().
  **/
 void
 cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *abstract_font)
 {
     cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font;
 
+    if (! _cairo_scaled_font_is_ft (abstract_font)) {
+	_cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH);
+	return;
+    }
+
     if (scaled_font->base.status)
 	return;
 
     /* Note: We released the unscaled font's mutex at the end of
      * cairo_ft_scaled_font_lock_face, so we have to acquire it again
      * as _cairo_ft_unscaled_font_unlock_face expects it to be held
      * when we call into it. */
     CAIRO_MUTEX_LOCK (scaled_font->unscaled->mutex);
--- a/gfx/cairo/cairo/src/cairo-ft-private.h
+++ b/gfx/cairo/cairo/src/cairo-ft-private.h
@@ -32,29 +32,26 @@
  * Contributor(s):
  *      Graydon Hoare <graydon@redhat.com>
  *	Owen Taylor <otaylor@redhat.com>
  */
 
 #ifndef CAIRO_FT_PRIVATE_H
 #define CAIRO_FT_PRIVATE_H
 
-#include <cairo-ft.h>
-#include <cairoint.h>
+#include "cairo-ft.h"
+#include "cairoint.h"
 
 #if CAIRO_HAS_FT_FONT
 
 CAIRO_BEGIN_DECLS
 
 typedef struct _cairo_ft_unscaled_font cairo_ft_unscaled_font_t;
 
 cairo_private cairo_bool_t
-_cairo_unscaled_font_is_ft (cairo_unscaled_font_t *unscaled_font);
-
-cairo_private cairo_bool_t
 _cairo_scaled_font_is_ft (cairo_scaled_font_t *scaled_font);
 
 /* These functions are needed by the PDF backend, which needs to keep track of the
  * the different fonts-on-disk used by a document, so it can embed them
  */
 cairo_private cairo_unscaled_font_t *
 _cairo_ft_scaled_font_get_unscaled_font (cairo_scaled_font_t *scaled_font);
 
@@ -62,15 +59,12 @@ cairo_private FT_Face
 _cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled);
 
 cairo_private void
 _cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled);
 
 cairo_private cairo_bool_t
 _cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font);
 
-slim_hidden_proto (cairo_ft_scaled_font_lock_face);
-slim_hidden_proto (cairo_ft_scaled_font_unlock_face);
-
 CAIRO_END_DECLS
 
 #endif /* CAIRO_HAS_FT_FONT */
 #endif /* CAIRO_FT_PRIVATE_H */
--- a/gfx/cairo/cairo/src/cairo-ft.h
+++ b/gfx/cairo/cairo/src/cairo-ft.h
@@ -32,17 +32,17 @@
  * Contributor(s):
  *      Graydon Hoare <graydon@redhat.com>
  *	Owen Taylor <otaylor@redhat.com>
  */
 
 #ifndef CAIRO_FT_H
 #define CAIRO_FT_H
 
-#include <cairo.h>
+#include "cairo.h"
 
 #if CAIRO_HAS_FT_FONT
 
 /* Fontconfig/Freetype platform-specific font interface */
 
 #include <fontconfig/fontconfig.h>
 #include <ft2build.h>
 #include FT_FREETYPE_H
--- a/gfx/cairo/cairo/src/cairo-glitz-surface.c
+++ b/gfx/cairo/cairo/src/cairo-glitz-surface.c
@@ -953,17 +953,17 @@ static cairo_int_status_t
 				       unsigned int		        width,
 				       unsigned int		        height,
 				       cairo_glitz_surface_t	    **src_out,
 				       cairo_glitz_surface_t	    **mask_out,
 				       cairo_glitz_surface_attributes_t *sattr,
 				       cairo_glitz_surface_attributes_t *mattr)
 {
     cairo_int_status_t	  status;
-    cairo_pattern_union_t tmp;
+    cairo_solid_pattern_t tmp;
 
     /* If src and mask are both solid, then the mask alpha can be
      * combined into src and mask can be ignored. */
 
     /* XXX: This optimization assumes that there is no color
      * information in mask, so this will need to change when we
      * support RENDER-style 4-channel masks. */
 
@@ -972,20 +972,17 @@ static cairo_int_status_t
     {
 	cairo_color_t combined;
 	cairo_solid_pattern_t *src_solid = (cairo_solid_pattern_t *) src;
 	cairo_solid_pattern_t *mask_solid = (cairo_solid_pattern_t *) mask;
 
 	combined = src_solid->color;
 	_cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
 
-	_cairo_pattern_init_solid (&tmp.solid, &combined,
-				   CAIRO_COLOR_IS_OPAQUE (&combined) ?
-				   CAIRO_CONTENT_COLOR :
-				   CAIRO_CONTENT_COLOR_ALPHA);
+	_cairo_pattern_init_solid (&tmp, &combined, CAIRO_CONTENT_COLOR_ALPHA);
 
 	mask = NULL;
     } else {
 	status = _cairo_pattern_init_copy (&tmp.base, src);
 	if (status)
 	    return status;
     }
 
@@ -1159,18 +1156,17 @@ static cairo_int_status_t
     default:
 	if (_glitz_ensure_target (dst->surface))
 	    return CAIRO_INT_STATUS_UNSUPPORTED;
 
 	src = (cairo_glitz_surface_t *)
 	    _cairo_surface_create_similar_solid (&dst->base,
 						 CAIRO_CONTENT_COLOR_ALPHA,
 						 1, 1,
-						 (cairo_color_t *) color,
-						 NULL);
+						 (cairo_color_t *) color);
 	if (src->base.status)
 	    return src->base.status;
 
 	glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT);
 
 	while (n_rects--)
 	{
 	    glitz_composite (_glitz_operator (op),
--- a/gfx/cairo/cairo/src/cairo-glitz.h
+++ b/gfx/cairo/cairo/src/cairo-glitz.h
@@ -32,17 +32,17 @@
  *
  * Contributor(s):
  *	Carl D. Worth <cworth@cworth.org>
  */
 
 #ifndef CAIRO_GLITZ_H
 #define CAIRO_GLITZ_H
 
-#include <cairo.h>
+#include "cairo.h"
 
 #if CAIRO_HAS_GLITZ_SURFACE
 
 #include <glitz.h>
 
 CAIRO_BEGIN_DECLS
 
 cairo_public cairo_surface_t *
--- a/gfx/cairo/cairo/src/cairo-gstate.c
+++ b/gfx/cairo/cairo/src/cairo-gstate.c
@@ -59,17 +59,18 @@ static cairo_status_t
 
 static void
 _cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate);
 
 static void
 _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t      *gstate,
                                            const cairo_glyph_t *glyphs,
                                            int                  num_glyphs,
-                                           cairo_glyph_t       *transformed_glyphs);
+                                           cairo_glyph_t       *transformed_glyphs,
+					   int		       *num_transformed_glyphs);
 
 cairo_status_t
 _cairo_gstate_init (cairo_gstate_t  *gstate,
 		    cairo_surface_t *target)
 {
     cairo_status_t status;
 
     gstate->next = NULL;
@@ -198,99 +199,71 @@ void
 
     cairo_surface_destroy (gstate->original_target);
     gstate->original_target = NULL;
 
     cairo_pattern_destroy (gstate->source);
     gstate->source = NULL;
 }
 
-static void
-_cairo_gstate_destroy (cairo_gstate_t *gstate)
-{
-    _cairo_gstate_fini (gstate);
-    free (gstate);
-}
-
-/**
- * _cairo_gstate_clone:
- * @other: a #cairo_gstate_t to be copied, not %NULL.
- *
- * Create a new #cairo_gstate_t setting all graphics state parameters
- * to the same values as contained in @other. gstate->next will be set
- * to %NULL and may be used by the caller to chain #cairo_gstate_t
- * objects together.
- *
- * Return value: a new #cairo_gstate_t or %NULL if there is insufficient
- * memory.
- **/
-static cairo_status_t
-_cairo_gstate_clone (cairo_gstate_t *other, cairo_gstate_t **out)
-{
-    cairo_status_t status;
-    cairo_gstate_t *gstate;
-
-    assert (other != NULL);
-
-    gstate = malloc (sizeof (cairo_gstate_t));
-    if (gstate == NULL)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    status = _cairo_gstate_init_copy (gstate, other);
-    if (status) {
-	free (gstate);
-	return status;
-    }
-
-    *out = gstate;
-    return CAIRO_STATUS_SUCCESS;
-}
-
 /**
  * _cairo_gstate_save:
  * @gstate: input/output gstate pointer
  *
  * Makes a copy of the current state of @gstate and saves it
  * to @gstate->next, then put the address of the newly allcated
  * copy into @gstate.  _cairo_gstate_restore() reverses this.
  **/
 cairo_status_t
-_cairo_gstate_save (cairo_gstate_t **gstate)
+_cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
 {
-    cairo_gstate_t *top = NULL;
+    cairo_gstate_t *top;
     cairo_status_t status;
 
-    status = _cairo_gstate_clone (*gstate, &top);
-    if (status)
+    top = *freelist;
+    if (top == NULL) {
+	top = malloc (sizeof (cairo_gstate_t));
+	if (top == NULL)
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    } else
+	*freelist = top->next;
+
+    status = _cairo_gstate_init_copy (top, *gstate);
+    if (status) {
+	top->next = *freelist;
+	*freelist = top;
 	return status;
+    }
 
     top->next = *gstate;
     *gstate = top;
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 /**
  * _cairo_gstate_restore:
  * @gstate: input/output gstate pointer
  *
  * Reverses the effects of one _cairo_gstate_save() call.
  **/
 cairo_status_t
-_cairo_gstate_restore (cairo_gstate_t **gstate)
+_cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
 {
     cairo_gstate_t *top;
 
     top = *gstate;
     if (top->next == NULL)
 	return _cairo_error (CAIRO_STATUS_INVALID_RESTORE);
 
     *gstate = top->next;
 
-    _cairo_gstate_destroy (top);
+    _cairo_gstate_fini (top);
+    top->next = *freelist;
+    *freelist = top;
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 /**
  * _cairo_gstate_redirect_target:
  * @gstate: a #cairo_gstate_t
  * @child: the new child target
@@ -817,25 +790,26 @@ static cairo_status_t
     cairo_surface_pattern_t *surface_pattern;
     cairo_surface_t *surface;
     cairo_status_t status;
 
     status = _cairo_pattern_init_copy (pattern, original);
     if (status)
 	return status;
 
-    _cairo_pattern_transform (pattern, ctm_inverse);
-
+    /* apply device_transform first so that it is transformed by ctm_inverse */
     if (cairo_pattern_get_type (original) == CAIRO_PATTERN_TYPE_SURFACE) {
         surface_pattern = (cairo_surface_pattern_t *) original;
         surface = surface_pattern->surface;
         if (_cairo_surface_has_device_transform (surface))
             _cairo_pattern_transform (pattern, &surface->device_transform);
     }
 
+    _cairo_pattern_transform (pattern, ctm_inverse);
+
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
 _cairo_gstate_copy_transformed_source (cairo_gstate_t  *gstate,
 				       cairo_pattern_t *pattern)
 {
     return _cairo_gstate_copy_transformed_pattern (gstate, pattern,
@@ -1169,31 +1143,42 @@ cairo_status_t
 cairo_status_t
 _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
 {
     return _cairo_clip_clip (&gstate->clip,
 			     path, gstate->fill_rule, gstate->tolerance,
 			     gstate->antialias, gstate->target);
 }
 
+static cairo_status_t
+_cairo_gstate_int_clip_extents (cairo_gstate_t        *gstate,
+				cairo_rectangle_int_t *extents)
+{
+    cairo_status_t status;
+
+    status = _cairo_surface_get_extents (gstate->target, extents);
+    if (status)
+        return status;
+
+    status = _cairo_clip_intersect_to_rectangle (&gstate->clip, extents);
+
+    return status;
+}
+
 cairo_status_t
 _cairo_gstate_clip_extents (cairo_gstate_t *gstate,
 		            double         *x1,
 		            double         *y1,
         		    double         *x2,
         		    double         *y2)
 {
     cairo_rectangle_int_t extents;
     cairo_status_t status;
     
-    status = _cairo_surface_get_extents (gstate->target, &extents);
-    if (status)
-        return status;
-
-    status = _cairo_clip_intersect_to_rectangle (&gstate->clip, &extents);
+    status = _cairo_gstate_int_clip_extents (gstate, &extents);
     if (status)
         return status;
 
     if (x1)
 	*x1 = extents.x;
     if (y1)
 	*y1 = extents.y;
     if (x2)
@@ -1508,20 +1493,31 @@ cairo_status_t
 
     cairo_scaled_font_glyph_extents (gstate->scaled_font,
 				     glyphs, num_glyphs,
 				     extents);
 
     return cairo_scaled_font_status (gstate->scaled_font);
 }
 
+cairo_bool_t
+_cairo_gstate_has_show_text_glyphs (cairo_gstate_t *gstate)
+{
+    return _cairo_surface_has_show_text_glyphs (gstate->target);
+}
+
 cairo_status_t
-_cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
-			   const cairo_glyph_t *glyphs,
-			   int num_glyphs)
+_cairo_gstate_show_text_glyphs (cairo_gstate_t		   *gstate,
+				const char		   *utf8,
+				int			    utf8_len,
+				const cairo_glyph_t	   *glyphs,
+				int			    num_glyphs,
+				const cairo_text_cluster_t *clusters,
+				int			    num_clusters,
+				cairo_bool_t		    backward)
 {
     cairo_status_t status;
     cairo_pattern_union_t source_pattern;
     cairo_glyph_t *transformed_glyphs;
     cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
 
     if (gstate->source->status)
 	return gstate->source->status;
@@ -1538,28 +1534,67 @@ cairo_status_t
 	transformed_glyphs = stack_transformed_glyphs;
     } else {
 	transformed_glyphs = _cairo_malloc_ab (num_glyphs, sizeof(cairo_glyph_t));
 	if (transformed_glyphs == NULL)
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     }
 
     _cairo_gstate_transform_glyphs_to_backend (gstate, glyphs, num_glyphs,
-                                               transformed_glyphs);
+                                               transformed_glyphs, &num_glyphs);
+
+    if (!num_glyphs)
+	goto CLEANUP_GLYPHS;
 
     status = _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
     if (status)
 	goto CLEANUP_GLYPHS;
 
-    status = _cairo_surface_show_glyphs (gstate->target,
-					 gstate->op,
-					 &source_pattern.base,
-					 transformed_glyphs,
-					 num_glyphs,
-					 gstate->scaled_font);
+    /* For really huge font sizes, we can just do path;fill instead of
+     * show_glyphs, as show_glyphs would put excess pressure on the cache,
+     * and moreover, not all components below us correctly handle huge font
+     * sizes.  I wanted to set the limit at 256.  But alas, seems like cairo's
+     * rasterizer is something like ten times slower than freetype's for huge
+     * sizes.  So, no win just yet.  For now, do it for insanely-huge sizes,
+     * just to make sure we don't make anyone unhappy.  When we get a really
+     * fast rasterizer in cairo, we may want to readjust this.
+     *
+     * Needless to say, do this only if show_text_glyphs is not available. */
+    if (_cairo_gstate_has_show_text_glyphs (gstate) ||
+	_cairo_scaled_font_get_max_scale (gstate->scaled_font) <= 10240) {
+	status = _cairo_surface_show_text_glyphs (gstate->target,
+						  gstate->op,
+						  &source_pattern.base,
+						  utf8, utf8_len,
+						  transformed_glyphs, num_glyphs,
+						  clusters, num_clusters,
+						  backward,
+						  gstate->scaled_font);
+    } else {
+	cairo_path_fixed_t path;
+
+	_cairo_path_fixed_init (&path);
+
+	CAIRO_MUTEX_LOCK (gstate->scaled_font->mutex);
+	status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
+						transformed_glyphs, num_glyphs,
+						&path);
+	CAIRO_MUTEX_UNLOCK (gstate->scaled_font->mutex);
+
+	if (status == CAIRO_STATUS_SUCCESS)
+	  status = _cairo_surface_fill (gstate->target,
+					gstate->op,
+					&source_pattern.base,
+					&path,
+					CAIRO_FILL_RULE_WINDING,
+					gstate->tolerance,
+					gstate->scaled_font->options.antialias);
+
+	_cairo_path_fixed_fini (&path);
+    }
 
     _cairo_pattern_fini (&source_pattern.base);
 
 CLEANUP_GLYPHS:
     if (transformed_glyphs != stack_transformed_glyphs)
       free (transformed_glyphs);
 
     return status;
@@ -1582,17 +1617,17 @@ cairo_status_t
     if (num_glyphs < ARRAY_LENGTH (stack_transformed_glyphs))
       transformed_glyphs = stack_transformed_glyphs;
     else
       transformed_glyphs = _cairo_malloc_ab (num_glyphs, sizeof(cairo_glyph_t));
     if (transformed_glyphs == NULL)
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
     _cairo_gstate_transform_glyphs_to_backend (gstate, glyphs, num_glyphs,
-                                               transformed_glyphs);
+                                               transformed_glyphs, NULL);
 
     CAIRO_MUTEX_LOCK (gstate->scaled_font->mutex);
     status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
 					    transformed_glyphs, num_glyphs,
 					    path);
     CAIRO_MUTEX_UNLOCK (gstate->scaled_font->mutex);
 
     if (transformed_glyphs != stack_transformed_glyphs)
@@ -1618,63 +1653,126 @@ cairo_antialias_t
 
 /**
  * _cairo_gstate_transform_glyphs_to_backend:
  * @gstate: a #cairo_gstate_t
  * @glyphs: the array of #cairo_glyph_t objects to be transformed
  * @num_glyphs: the number of elements in @glyphs
  * @transformed_glyphs: a pre-allocated array of at least @num_glyphs
  * #cairo_glyph_t objects
+ * @num_transformed_glyphs: the number of elements in @transformed_glyphs
+ * after dropping out of bounds glyphs, or %NULL if glyphs shouldn't be
+ * dropped
  *
  * Transform an array of glyphs to backend space by first adding the offset
  * of the font matrix, then transforming from user space to backend space.
  * The result of the transformation is placed in @transformed_glyphs.
+ *
+ * This also uses information from the scaled font and the surface to
+ * cull/drop glyphs that will not be visible.
  **/
 static void
 _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t      *gstate,
                                            const cairo_glyph_t *glyphs,
                                            int                  num_glyphs,
-                                           cairo_glyph_t *transformed_glyphs)
+                                           cairo_glyph_t       *transformed_glyphs,
+					   int		       *num_transformed_glyphs)
 {
-    int i;
+    int i, j;
     cairo_matrix_t *ctm = &gstate->ctm;
+    cairo_matrix_t *font_matrix = &gstate->font_matrix;
     cairo_matrix_t *device_transform = &gstate->target->device_transform;
+    cairo_bool_t drop = FALSE;
+    double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
+
+    if (num_transformed_glyphs != NULL) {
+	cairo_rectangle_int_t surface_extents;
+	double scale = _cairo_scaled_font_get_max_scale (gstate->scaled_font);
+
+	drop = TRUE;
+
+	if (_cairo_gstate_int_clip_extents (gstate, &surface_extents))
+	    drop = FALSE; /* unbounded surface */
+	else {
+	    if (surface_extents.width == 0 || surface_extents.height == 0) {
+	      /* No visible area.  Don't draw anything */
+	      *num_transformed_glyphs = 0;
+	      return;
+	    }
+	    /* XXX We currently drop any glyphs that has its position outside
+	     * of the surface boundaries by a safety margin depending on the
+	     * font scale.  This however can fail in extreme cases where the
+	     * font has really long swashes for example...  We can correctly
+	     * handle that by looking the glyph up and using its device bbox
+	     * to device if it's going to be visible, but I'm not inclined to
+	     * do that now.
+	     */
+	    x1 = surface_extents.x - 2*scale;
+	    y1 = surface_extents.y - 2*scale;
+	    x2 = surface_extents.x + surface_extents.width  + scale;
+	    y2 = surface_extents.y + surface_extents.height + scale;
+	}
+
+	if (!drop)
+	    *num_transformed_glyphs = num_glyphs;
+    } else
+	num_transformed_glyphs = &j;
+
+#define KEEP_GLYPH(glyph) (x1 <= glyph.x && glyph.x <= x2 && y1 <= glyph.y && glyph.y <= y2)
 
     if (_cairo_matrix_is_identity (ctm) &&
         _cairo_matrix_is_identity (device_transform) &&
-	gstate->font_matrix.x0 == 0 && gstate->font_matrix.y0 == 0)
+	font_matrix->x0 == 0 && font_matrix->y0 == 0)
     {
-        memcpy (transformed_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t));
+	if (!drop)
+	    memcpy (transformed_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t));
+	else {
+	    for (j = 0, i = 0; i < num_glyphs; i++)
+	    {
+		transformed_glyphs[j].index = glyphs[i].index;
+		transformed_glyphs[j].x = glyphs[i].x;
+		transformed_glyphs[j].y = glyphs[i].y;
+		if (KEEP_GLYPH (transformed_glyphs[j]))
+		    j++;
+	    }
+	    *num_transformed_glyphs = j;
+	}
     }
     else if (_cairo_matrix_is_translation (ctm) &&
              _cairo_matrix_is_translation (device_transform))
     {
-        double tx = gstate->font_matrix.x0 + ctm->x0 + device_transform->x0;
-        double ty = gstate->font_matrix.y0 + ctm->y0 + device_transform->y0;
+        double tx = font_matrix->x0 + ctm->x0 + device_transform->x0;
+        double ty = font_matrix->y0 + ctm->y0 + device_transform->y0;
 
-        for (i = 0; i < num_glyphs; i++)
+        for (j = 0, i = 0; i < num_glyphs; i++)
         {
-            transformed_glyphs[i].index = glyphs[i].index;
-            transformed_glyphs[i].x = glyphs[i].x + tx;
-            transformed_glyphs[i].y = glyphs[i].y + ty;
+            transformed_glyphs[j].index = glyphs[i].index;
+            transformed_glyphs[j].x = glyphs[i].x + tx;
+            transformed_glyphs[j].y = glyphs[i].y + ty;
+	    if (!drop || KEEP_GLYPH (transformed_glyphs[j]))
+		j++;
         }
+	*num_transformed_glyphs = j;
     }
     else
     {
         cairo_matrix_t aggregate_transform;
 
         cairo_matrix_init_translate (&aggregate_transform,
                                      gstate->font_matrix.x0,
                                      gstate->font_matrix.y0);
         cairo_matrix_multiply (&aggregate_transform,
                                &aggregate_transform, ctm);
         cairo_matrix_multiply (&aggregate_transform,
                                &aggregate_transform, device_transform);
 
-        for (i = 0; i < num_glyphs; i++)
+        for (j = 0, i = 0; i < num_glyphs; i++)
         {
-            transformed_glyphs[i] = glyphs[i];
+            transformed_glyphs[j] = glyphs[i];
             cairo_matrix_transform_point (&aggregate_transform,
-                                          &transformed_glyphs[i].x,
-                                          &transformed_glyphs[i].y);
+                                          &transformed_glyphs[j].x,
+                                          &transformed_glyphs[j].y);
+	    if (!drop || KEEP_GLYPH (transformed_glyphs[j]))
+		j++;
         }
+	*num_transformed_glyphs = j;
     }
 }
--- a/gfx/cairo/cairo/src/cairo-hash.c
+++ b/gfx/cairo/cairo/src/cairo-hash.c
@@ -291,17 +291,17 @@ static cairo_hash_entry_t **
  * _cairo_hash_table_resize:
  * @hash_table: a hash table
  *
  * Resize the hash table if the number of entries has gotten much
  * bigger or smaller than the ideal number of entries for the current
  * size.
  *
  * Return value: %CAIRO_STATUS_SUCCESS if successful or
- * CAIRO_STATUS_NO_MEMORY if out of memory.
+ * %CAIRO_STATUS_NO_MEMORY if out of memory.
  **/
 static cairo_status_t
 _cairo_hash_table_resize  (cairo_hash_table_t *hash_table)
 {
     cairo_hash_table_t tmp;
     cairo_hash_entry_t **entry;
     unsigned long new_size, i;
 
@@ -396,17 +396,17 @@ cairo_bool_t
  * entries in the hash table in a pseudo-random order. Walking
  * linearly would favor entries following gaps in the hash table. We
  * could also call rand() repeatedly, which works well for almost-full
  * tables, but degrades when the table is almost empty, or predicate
  * returns %TRUE for most entries.
  *
  * Return value: a random live entry or %NULL if there are no entries
  * that match the given predicate. In particular, if predicate is
- * NULL, a %NULL return value indicates that the table is empty.
+ * %NULL, a %NULL return value indicates that the table is empty.
  **/
 void *
 _cairo_hash_table_random_entry (cairo_hash_table_t	   *hash_table,
 				cairo_hash_predicate_func_t predicate)
 {
     cairo_hash_entry_t **entry;
     unsigned long hash;
     unsigned long table_size, i, idx, step;
@@ -454,17 +454,17 @@ void *
  * WARNING: It is a fatal error to insert an element while
  * an iterator is running
  *
  * Instead of using insert to replace an entry, consider just editing
  * the entry obtained with _cairo_hash_table_lookup. Or if absolutely
  * necessary, use _cairo_hash_table_remove first.
  *
  * Return value: %CAIRO_STATUS_SUCCESS if successful or
- * CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
+ * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
  **/
 cairo_status_t
 _cairo_hash_table_insert (cairo_hash_table_t *hash_table,
 			  cairo_hash_entry_t *key_and_value)
 {
     cairo_status_t status;
     cairo_hash_entry_t **entry;
 
@@ -499,17 +499,17 @@ cairo_status_t
  * @hash_table: a hash table
  * @key: key of entry to be removed
  *
  * Remove an entry from the hash table which has a key that matches
  * @key, if any (as determined by the keys_equal() function passed to
  * _cairo_hash_table_create).
  *
  * Return value: %CAIRO_STATUS_SUCCESS if successful or
- * CAIRO_STATUS_NO_MEMORY if out of memory.
+ * %CAIRO_STATUS_NO_MEMORY if out of memory.
  **/
 void
 _cairo_hash_table_remove (cairo_hash_table_t *hash_table,
 			  cairo_hash_entry_t *key)
 {
     cairo_hash_entry_t **entry;
 
     entry = _cairo_hash_table_lookup_internal (hash_table, key, FALSE);
--- a/gfx/cairo/cairo/src/cairo-hull.c
+++ b/gfx/cairo/cairo/src/cairo-hull.c
@@ -31,65 +31,56 @@
  * California.
  *
  * Contributor(s):
  *	Carl D. Worth <cworth@cworth.org>
  */
 
 #include "cairoint.h"
 
-typedef struct cairo_hull
-{
+typedef struct cairo_hull {
     cairo_point_t point;
     cairo_slope_t slope;
     int discard;
     int id;
 } cairo_hull_t;
 
-static cairo_status_t
-_cairo_hull_create (cairo_pen_vertex_t	     *vertices,
-	            int			      num_vertices,
-		    cairo_hull_t	    **out)
+static void
+_cairo_hull_init (cairo_hull_t			*hull,
+	          cairo_pen_vertex_t		*vertices,
+		  int				 num_vertices)
 {
+    cairo_point_t *p, *extremum, tmp;
     int i;
-    cairo_hull_t *hull;
-    cairo_point_t *p, *extremum, tmp;
 
     extremum = &vertices[0].point;
     for (i = 1; i < num_vertices; i++) {
 	p = &vertices[i].point;
 	if (p->y < extremum->y || (p->y == extremum->y && p->x < extremum->x))
 	    extremum = p;
     }
     /* Put the extremal point at the beginning of the array */
     tmp = *extremum;
     *extremum = vertices[0].point;
     vertices[0].point = tmp;
 
-    hull = _cairo_malloc_ab (num_vertices, sizeof (cairo_hull_t));
-    if (hull == NULL)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
     for (i = 0; i < num_vertices; i++) {
 	hull[i].point = vertices[i].point;
 	_cairo_slope_init (&hull[i].slope, &hull[0].point, &hull[i].point);
 
         /* give each point a unique id for later comparison */
         hull[i].id = i;
 
         /* Don't discard by default */
         hull[i].discard = 0;
 
 	/* Discard all points coincident with the extremal point */
 	if (i != 0 && hull[i].slope.dx == 0 && hull[i].slope.dy == 0)
 	    hull[i].discard = 1;
     }
-
-    *out = hull;
-    return CAIRO_STATUS_SUCCESS;
 }
 
 static int
 _cairo_hull_vertex_compare (const void *av, const void *bv)
 {
     cairo_hull_t *a = (cairo_hull_t *) av;
     cairo_hull_t *b = (cairo_hull_t *) bv;
     int ret;
@@ -191,27 +182,34 @@ static void
     *num_vertices = j;
 }
 
 /* Given a set of vertices, compute the convex hull using the Graham
    scan algorithm. */
 cairo_status_t
 _cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices)
 {
-    cairo_status_t status;
-    cairo_hull_t *hull = NULL;
+    cairo_hull_t hull_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_hull_t)];
+    cairo_hull_t *hull;
     int num_hull = *num_vertices;
 
-    status = _cairo_hull_create (vertices, num_hull, &hull);
-    if (status)
-	return status;
+    if (num_hull > ARRAY_LENGTH (hull_stack)) {
+	hull = _cairo_malloc_ab (num_hull, sizeof (cairo_hull_t));
+	if (hull == NULL)
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    } else {
+	hull = hull_stack;
+    }
+
+    _cairo_hull_init (hull, vertices, num_hull);
 
     qsort (hull + 1, num_hull - 1,
 	   sizeof (cairo_hull_t), _cairo_hull_vertex_compare);
 
     _cairo_hull_eliminate_concave (hull, num_hull);
 
     _cairo_hull_to_pen (hull, vertices, num_vertices);
 
-    free (hull);
+    if (hull != hull_stack)
+	free (hull);
 
     return CAIRO_STATUS_SUCCESS;
 }
--- a/gfx/cairo/cairo/src/cairo-image-surface.c
+++ b/gfx/cairo/cairo/src/cairo-image-surface.c
@@ -119,17 +119,17 @@ cairo_surface_t *
 					      pixman_format_code_t	 pixman_format)
 {
     cairo_image_surface_t *surface;
 
     surface = malloc (sizeof (cairo_image_surface_t));
     if (surface == NULL)
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
-    _cairo_surface_init (&surface->base, &cairo_image_surface_backend,
+    _cairo_surface_init (&surface->base, &_cairo_image_surface_backend,
 			 _cairo_content_from_pixman_format (pixman_format));
 
     surface->pixman_image = pixman_image;
 
     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;
@@ -387,17 +387,18 @@ cairo_surface_t *
  * <informalexample><programlisting>
  * int stride;
  * unsigned char *data;
  * #cairo_surface_t *surface;
  *
  * stride = cairo_format_stride_for_width (format, width);
  * data = malloc (stride * height);
  * surface = cairo_image_surface_create_for_data (data, format,
- *						  width, height);
+ *						  width, height,
+ *						  stride);
  * </programlisting></informalexample>
  *
  * Return value: the appropriate stride to use given the desired
  * format and width, or -1 if either the format is invalid or the width
  * too large.
  *
  * Since: 1.6
  **/
@@ -1187,17 +1188,17 @@ static cairo_int_status_t
 }
 
 cairo_int_status_t
 _cairo_image_surface_set_clip_region (void *abstract_surface,
 				      cairo_region_t *region)
 {
     cairo_image_surface_t *surface = (cairo_image_surface_t *) abstract_surface;
 
-    if (! pixman_image_set_clip_region (surface->pixman_image, &region->rgn))
+    if (! pixman_image_set_clip_region32 (surface->pixman_image, &region->rgn))
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
     surface->has_clip = region != NULL;
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
@@ -1241,20 +1242,20 @@ static cairo_status_t
  *
  * Checks if a surface is an #cairo_image_surface_t
  *
  * Return value: %TRUE if the surface is an image surface
  **/
 cairo_bool_t
 _cairo_surface_is_image (const cairo_surface_t *surface)
 {
-    return surface->backend == &cairo_image_surface_backend;
+    return surface->backend == &_cairo_image_surface_backend;
 }
 
-const cairo_surface_backend_t cairo_image_surface_backend = {
+const cairo_surface_backend_t _cairo_image_surface_backend = {
     CAIRO_SURFACE_TYPE_IMAGE,
     _cairo_image_surface_create_similar,
     _cairo_image_surface_finish,
     _cairo_image_surface_acquire_source_image,
     _cairo_image_surface_release_source_image,
     _cairo_image_surface_acquire_dest_image,
     _cairo_image_surface_release_dest_image,
     _cairo_image_surface_clone_similar,
--- a/gfx/cairo/cairo/src/cairo-lzw.c
+++ b/gfx/cairo/cairo/src/cairo-lzw.c
@@ -77,17 +77,17 @@ static void
 	buf->data_size = 0;
 	buf->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	return;
     }
 }
 
 /* Increase the buffer size by doubling.
  *
- * Returns %CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
+ * Returns %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
  */
 static cairo_status_t
 _lzw_buf_grow (lzw_buf_t *buf)
 {
     int new_size = buf->data_size * 2;
     unsigned char *new_data;
 
     if (buf->status)
--- a/gfx/cairo/cairo/src/cairo-matrix.c
+++ b/gfx/cairo/cairo/src/cairo-matrix.c
@@ -418,16 +418,28 @@ void
         *is_tight =
             (quad_x[1] == quad_x[0] && quad_y[1] == quad_y[3] &&
              quad_x[2] == quad_x[3] && quad_y[2] == quad_y[0]) ||
             (quad_x[1] == quad_x[3] && quad_y[1] == quad_y[0] &&
              quad_x[2] == quad_x[0] && quad_y[2] == quad_y[3]);
     }
 }
 
+cairo_private void
+_cairo_matrix_transform_bounding_box_fixed (const cairo_matrix_t *matrix,
+					    cairo_box_t          *bbox,
+					    cairo_bool_t *is_tight)
+{
+    double x1, y1, x2, y2;
+
+    _cairo_box_to_doubles (bbox, &x1, &y1, &x2, &y2);
+    _cairo_matrix_transform_bounding_box (matrix, &x1, &y1, &x2, &y2, is_tight);
+    _cairo_box_from_doubles (bbox, &x1, &y1, &x2, &y2);
+}
+
 static void
 _cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar)
 {
     matrix->xx *= scalar;
     matrix->yx *= scalar;
 
     matrix->xy *= scalar;
     matrix->yy *= scalar;
@@ -473,37 +485,37 @@ static void
 cairo_status_t
 cairo_matrix_invert (cairo_matrix_t *matrix)
 {
     /* inv (A) = 1/det (A) * adj (A) */
     double det;
 
     _cairo_matrix_compute_determinant (matrix, &det);
 
-    if (det == 0)
+    if (! ISFINITE (det))
 	return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
 
-    if (! ISFINITE (det))
+    if (det == 0)
 	return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
 
     _cairo_matrix_compute_adjoint (matrix);
     _cairo_matrix_scalar_multiply (matrix, 1 / det);
 
     return CAIRO_STATUS_SUCCESS;
 }
 slim_hidden_def(cairo_matrix_invert);
 
 cairo_bool_t
 _cairo_matrix_is_invertible (const cairo_matrix_t *matrix)
 {
     double det;
 
     _cairo_matrix_compute_determinant (matrix, &det);
 
-    return det != 0. && ISFINITE (det);
+    return ISFINITE (det) && det != 0.;
 }
 
 void
 _cairo_matrix_compute_determinant (const cairo_matrix_t *matrix,
 				   double		*det)
 {
     double a, b, c, d;
 
@@ -708,16 +720,20 @@ cairo_bool_t
 
   Which is the solution to this problem.
 
   Walter Brisken
   2004/10/08
 
   (Note that the minor axis length is at the minimum of the above solution,
   which is just sqrt ( f - sqrt(g² + h²) ) given the symmetry of (D)).
+
+
+  For another derivation of the same result, using Singular Value Decomposition,
+  see doc/tutorial/src/singular.c.
 */
 
 /* determine the length of the major axis of a circle of the given radius
    after applying the transformation matrix. */
 double
 _cairo_matrix_transformed_circle_major_axis (cairo_matrix_t *matrix, double radius)
 {
     double  a, b, c, d, f, g, h, i, j;
--- a/gfx/cairo/cairo/src/cairo-meta-surface-private.h
+++ b/gfx/cairo/cairo/src/cairo-meta-surface-private.h
@@ -41,17 +41,17 @@
 #include "cairo-path-fixed-private.h"
 
 typedef enum {
     /* The 5 basic drawing operations. */
     CAIRO_COMMAND_PAINT,
     CAIRO_COMMAND_MASK,
     CAIRO_COMMAND_STROKE,
     CAIRO_COMMAND_FILL,
-    CAIRO_COMMAND_SHOW_GLYPHS,
+    CAIRO_COMMAND_SHOW_TEXT_GLYPHS,
 
     /* Other junk. For most of these, we should be able to assert that
      * they never get called except as part of fallbacks for the 5
      * 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
@@ -99,24 +99,29 @@ typedef struct _cairo_command_fill {
     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 {
+typedef struct _cairo_command_show_text_glyphs {
     cairo_command_header_t       header;
     cairo_operator_t		 op;
     cairo_pattern_union_t	 source;
+    char			*utf8;
+    int				 utf8_len;
     cairo_glyph_t		*glyphs;
     unsigned int		 num_glyphs;
+    cairo_text_cluster_t	*clusters;
+    int				 num_clusters;
+    cairo_bool_t		 backward;
     cairo_scaled_font_t		*scaled_font;
-} cairo_command_show_glyphs_t;
+} cairo_command_show_text_glyphs_t;
 
 typedef struct _cairo_command_intersect_clip_path {
     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;
@@ -125,17 +130,17 @@ typedef struct _cairo_command_intersect_
 typedef union _cairo_command {
     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;
+    cairo_command_show_text_glyphs_t		show_text_glyphs;
 
     /* The other junk. */
     cairo_command_intersect_clip_path_t		intersect_clip_path;
 } cairo_command_t;
 
 typedef struct _cairo_meta_surface {
     cairo_surface_t base;
 
@@ -154,16 +159,20 @@ typedef struct _cairo_meta_surface {
     int replay_start_idx;
 } cairo_meta_surface_t;
 
 cairo_private cairo_surface_t *
 _cairo_meta_surface_create (cairo_content_t	content,
 			    int			width_pixels,
 			    int			height_pixels);
 
+cairo_private cairo_int_status_t
+_cairo_meta_surface_get_path (cairo_surface_t	 *surface,
+			      cairo_path_fixed_t *path);
+
 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);
 
--- a/gfx/cairo/cairo/src/cairo-meta-surface.c
+++ b/gfx/cairo/cairo/src/cairo-meta-surface.c
@@ -34,17 +34,17 @@
  * 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
+ * level of paint, mask, stroke, fill, and show_text_glyphs). The meta
  * surface can then be "replayed" against any target surface with:
  *
  *	_cairo_meta_surface_replay (meta, target);
  *
  * after which the results in target will be identical to the results
  * that would have been obtained if the original operations applied to
  * the meta surface had instead been applied to the target surface.
  *
@@ -152,20 +152,22 @@ static cairo_status_t
 	    break;
 
 	case CAIRO_COMMAND_FILL:
 	    _cairo_pattern_fini (&command->fill.source.base);
 	    _cairo_path_fixed_fini (&command->fill.path);
 	    free (command);
 	    break;
 
-	case CAIRO_COMMAND_SHOW_GLYPHS:
-	    _cairo_pattern_fini (&command->show_glyphs.source.base);
-	    free (command->show_glyphs.glyphs);
-	    cairo_scaled_font_destroy (command->show_glyphs.scaled_font);
+	case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
+	    _cairo_pattern_fini (&command->show_text_glyphs.source.base);
+	    free (command->show_text_glyphs.utf8);
+	    free (command->show_text_glyphs.glyphs);
+	    free (command->show_text_glyphs.clusters);
+	    cairo_scaled_font_destroy (command->show_text_glyphs.scaled_font);
 	    free (command);
 	    break;
 
 	/* Other junk. */
 	case CAIRO_COMMAND_INTERSECT_CLIP_PATH:
 	    if (command->intersect_clip_path.path_pointer)
 		_cairo_path_fixed_fini (&command->intersect_clip_path.path);
 	    free (command);
@@ -421,76 +423,115 @@ static cairo_int_status_t
     _cairo_path_fixed_fini (&command->path);
   CLEANUP_SOURCE:
     _cairo_pattern_fini (&command->source.base);
   CLEANUP_COMMAND:
     free (command);
     return status;
 }
 
+static cairo_bool_t
+_cairo_meta_surface_has_show_text_glyphs (void *abstract_surface)
+{
+    return TRUE;
+}
+
 static cairo_int_status_t
-_cairo_meta_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_meta_surface_show_text_glyphs (void			    *abstract_surface,
+				      cairo_operator_t		     op,
+				      cairo_pattern_t		    *source,
+				      const char		    *utf8,
+				      int			     utf8_len,
+				      cairo_glyph_t		    *glyphs,
+				      int			     num_glyphs,
+				      const cairo_text_cluster_t    *clusters,
+				      int			     num_clusters,
+				      cairo_bool_t		     backward,
+				      cairo_scaled_font_t	    *scaled_font)
 {
     cairo_status_t status;
     cairo_meta_surface_t *meta = abstract_surface;
-    cairo_command_show_glyphs_t *command;
+    cairo_command_show_text_glyphs_t *command;
 
-    command = malloc (sizeof (cairo_command_show_glyphs_t));
+    command = malloc (sizeof (cairo_command_show_text_glyphs_t));
     if (command == NULL)
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-    command->header.type = CAIRO_COMMAND_SHOW_GLYPHS;
+    command->header.type = CAIRO_COMMAND_SHOW_TEXT_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) {
-	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	goto CLEANUP_SOURCE;
+    command->utf8 = NULL;
+    command->utf8_len = utf8_len;
+    command->glyphs = NULL;
+    command->num_glyphs = num_glyphs;
+    command->clusters = NULL;
+    command->num_clusters = num_clusters;
+
+    if (utf8_len) {
+	command->utf8 = malloc (utf8_len);
+	if (command->utf8 == NULL) {
+	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    goto CLEANUP_ARRAYS;
+	}
+	memcpy (command->utf8, utf8, utf8_len);
     }
-    memcpy (command->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
+    if (num_glyphs) {
+	command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (glyphs[0]));
+	if (command->glyphs == NULL) {
+	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    goto CLEANUP_ARRAYS;
+	}
+	memcpy (command->glyphs, glyphs, sizeof (glyphs[0]) * num_glyphs);
+    }
+    if (num_clusters) {
+	command->clusters = _cairo_malloc_ab (num_clusters, sizeof (clusters[0]));
+	if (command->clusters == NULL) {
+	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    goto CLEANUP_ARRAYS;
+	}
+	memcpy (command->clusters, clusters, sizeof (clusters[0]) * num_clusters);
+    }
 
-    command->num_glyphs = num_glyphs;
+    command->backward = backward;
 
     command->scaled_font = cairo_scaled_font_reference (scaled_font);
 
     status = _cairo_array_append (&meta->commands, &command);
     if (status)
 	goto CLEANUP_SCALED_FONT;
 
     return CAIRO_STATUS_SUCCESS;
 
   CLEANUP_SCALED_FONT:
     cairo_scaled_font_destroy (command->scaled_font);
+  CLEANUP_ARRAYS:
+    free (command->utf8);
     free (command->glyphs);
-  CLEANUP_SOURCE:
+    free (command->clusters);
+
     _cairo_pattern_fini (&command->source.base);
   CLEANUP_COMMAND:
     free (command);
     return status;
 }
 
 /**
  * _cairo_meta_surface_snapshot
  * @surface: a #cairo_surface_t which must be a meta surface
  *
  * Make an immutable copy of @surface. It is an error to call a
  * surface-modifying function on the result of this function.
  *
  * The caller owns the return value and should call
- * cairo_surface_destroy when finished with it. This function will not
+ * cairo_surface_destroy() when finished with it. This function will not
  * return %NULL, but will return a nil surface instead.
  *
  * Return value: The snapshot surface.
  **/
 static cairo_surface_t *
 _cairo_meta_surface_snapshot (void *abstract_other)
 {
     cairo_meta_surface_t *other = abstract_other;
@@ -565,16 +606,19 @@ static cairo_int_status_t
  * replayed, (as passed in to _cairo_meta_surface_create).
  */
 static cairo_int_status_t
 _cairo_meta_surface_get_extents (void			 *abstract_surface,
 				 cairo_rectangle_int_t   *rectangle)
 {
     cairo_meta_surface_t *surface = abstract_surface;
 
+    if (surface->width_pixels == -1 && surface->height_pixels == -1)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
     rectangle->x = 0;
     rectangle->y = 0;
     rectangle->width = surface->width_pixels;
     rectangle->height = surface->height_pixels;
 
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -613,47 +657,128 @@ static const cairo_surface_backend_t cai
     NULL, /* get_font_options */
     NULL, /* flush */
     NULL, /* mark_dirty_rectangle */
     NULL, /* scaled_font_fini */
     NULL, /* scaled_glyph_fini */
 
     /* Here are the 5 basic drawing operations, (which are in some
      * sense the only things that cairo_meta_surface should need to
-     * implement). */
+     * implement).  However, we implement the more generic show_text_glyphs
+     * instead of show_glyphs.  One or the other is eough. */
 
     _cairo_meta_surface_paint,
     _cairo_meta_surface_mask,
     _cairo_meta_surface_stroke,
     _cairo_meta_surface_fill,
-    _cairo_meta_surface_show_glyphs,
+    NULL,
+
+    _cairo_meta_surface_snapshot,
 
-    _cairo_meta_surface_snapshot
+    NULL, /* is_similar */
+    NULL, /* reset */
+    NULL, /* fill_stroke */
+    NULL, /* create_solid_pattern_surface */
+
+    _cairo_meta_surface_has_show_text_glyphs,
+    _cairo_meta_surface_show_text_glyphs
 };
 
 static cairo_path_fixed_t *
 _cairo_command_get_path (cairo_command_t *command)
 {
     switch (command->header.type) {
     case CAIRO_COMMAND_PAINT:
     case CAIRO_COMMAND_MASK:
-    case CAIRO_COMMAND_SHOW_GLYPHS:
+    case CAIRO_COMMAND_SHOW_TEXT_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_int_status_t
+_cairo_meta_surface_get_path (cairo_surface_t	 *surface,
+			      cairo_path_fixed_t *path)
+{
+    cairo_meta_surface_t *meta;
+    cairo_command_t *command, **elements;
+    int i, num_elements;
+    cairo_int_status_t status;
+
+    if (surface->status)
+	return surface->status;
+
+    meta = (cairo_meta_surface_t *) surface;
+    status = CAIRO_STATUS_SUCCESS;
+
+    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];
+
+	switch (command->header.type) {
+	case CAIRO_COMMAND_PAINT:
+	case CAIRO_COMMAND_MASK:
+	case CAIRO_COMMAND_INTERSECT_CLIP_PATH:
+	    status = CAIRO_INT_STATUS_UNSUPPORTED;
+	    break;
+
+	case CAIRO_COMMAND_STROKE:
+	{
+	    cairo_traps_t traps;
+
+	    _cairo_traps_init (&traps);
+
+	    /* XXX call cairo_stroke_to_path() when that is implemented */
+	    status = _cairo_path_fixed_stroke_to_traps (&command->stroke.path,
+							&command->stroke.style,
+							&command->stroke.ctm,
+							&command->stroke.ctm_inverse,
+							command->stroke.tolerance,
+							&traps);
+
+	    if (status == CAIRO_STATUS_SUCCESS)
+		status = _cairo_traps_path (&traps, path);
+
+	    _cairo_traps_fini (&traps);
+	    break;
+	}
+	case CAIRO_COMMAND_FILL:
+	{
+	    status = _cairo_path_fixed_append (path, &command->fill.path, CAIRO_DIRECTION_FORWARD);
+	    break;
+	}
+	case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
+	{
+	    status = _cairo_scaled_font_glyph_path (command->show_text_glyphs.scaled_font,
+						    command->show_text_glyphs.glyphs,
+						    command->show_text_glyphs.num_glyphs,
+						    path);
+	    break;
+	}
+
+	default:
+	    ASSERT_NOT_REACHED;
+	}
+
+	if (status)
+	    break;
+    }
+
+    return _cairo_surface_set_error (surface, status);
+}
+
 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;
@@ -694,17 +819,17 @@ static cairo_status_t
 		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);
+	    _cairo_path_fixed_transform (&path_copy, device_transform);
 	    dev_path = &path_copy;
 	}
 
 	switch (command->header.type) {
 	case CAIRO_COMMAND_PAINT:
 	    status = _cairo_surface_paint (target,
 					   command->paint.op,
 					   &command->paint.source.base);
@@ -793,23 +918,23 @@ static cairo_status_t
 					      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:
+	case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
 	{
-	    cairo_glyph_t *glyphs = command->show_glyphs.glyphs;
+	    cairo_glyph_t *glyphs = command->show_text_glyphs.glyphs;
 	    cairo_glyph_t *dev_glyphs;
-	    int i, num_glyphs = command->show_glyphs.num_glyphs;
+	    int i, num_glyphs = command->show_text_glyphs.num_glyphs;
 
-            /* show_glyphs is special because _cairo_surface_show_glyphs is allowed
+            /* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed
 	     * to modify the glyph array that's passed in.  We must always
 	     * copy the array before handing it to the backend.
 	     */
 	    dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
 	    if (dev_glyphs == NULL) {
 		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 		break;
 	    }
@@ -820,21 +945,24 @@ static cairo_status_t
 		    cairo_matrix_transform_point (device_transform,
 						  &dev_glyphs[i].x,
 						  &dev_glyphs[i].y);
 		}
 	    } else {
 		memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
 	    }
 
-	    status = _cairo_surface_show_glyphs	(target,
-						 command->show_glyphs.op,
-						 &command->show_glyphs.source.base,
-						 dev_glyphs, num_glyphs,
-						 command->show_glyphs.scaled_font);
+	    status = _cairo_surface_show_text_glyphs	(target,
+							 command->show_text_glyphs.op,
+							 &command->show_text_glyphs.source.base,
+							 command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
+							 dev_glyphs, num_glyphs,
+							 command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
+							 command->show_text_glyphs.backward,
+							 command->show_text_glyphs.scaled_font);
 
 	    free (dev_glyphs);
 	    break;
 	}
 	case CAIRO_COMMAND_INTERSECT_CLIP_PATH:
 	    /* XXX Meta surface clipping is broken and requires some
 	     * cairo-gstate.c rewriting.  Work around it for now. */
 	    if (dev_path == NULL)
@@ -882,17 +1010,17 @@ cairo_status_t
     return _cairo_meta_surface_replay_internal (surface,
 						target,
 						CAIRO_META_REPLAY,
 						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
+ * %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,
--- a/gfx/cairo/cairo/src/cairo-misc.c
+++ b/gfx/cairo/cairo/src/cairo-misc.c
@@ -33,16 +33,18 @@
  * California.
  *
  * Contributor(s):
  *	Carl D. Worth <cworth@cworth.org>
  */
 
 #include "cairoint.h"
 
+COMPILE_TIME_ASSERT (CAIRO_STATUS_LAST_STATUS < CAIRO_INT_STATUS_UNSUPPORTED);
+COMPILE_TIME_ASSERT (CAIRO_INT_STATUS_LAST_STATUS <= 127);
 
 /**
  * cairo_status_to_string:
  * @status: a cairo status
  *
  * Provides a human-readable description of a #cairo_status_t.
  *
  * Returns: a string representation of the status
@@ -96,16 +98,26 @@ cairo_status_to_string (cairo_status_t s
     case CAIRO_STATUS_INVALID_INDEX:
 	return "invalid index passed to getter";
     case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
         return "clip region not representable in desired format";
     case CAIRO_STATUS_TEMP_FILE_ERROR:
 	return "error creating or writing to a temporary file";
     case CAIRO_STATUS_INVALID_STRIDE:
 	return "invalid value for stride";
+    case CAIRO_STATUS_FONT_TYPE_MISMATCH:
+	return "the font type is not appropriate for the operation";
+    case CAIRO_STATUS_USER_FONT_IMMUTABLE:
+	return "the user-font is immutable";
+    case CAIRO_STATUS_USER_FONT_ERROR:
+	return "error occurred in a user-font callback function";
+    case CAIRO_STATUS_NEGATIVE_COUNT:
+	return "negative number used where it is not allowed";
+    case CAIRO_STATUS_INVALID_CLUSTERS:
+	return "input clusters do not represent the accompanying text and glyph arrays";
     }
 
     return "<unknown error status>";
 }
 
 /**
  * _cairo_operator_bounded_by_mask:
  * @op: a #cairo_operator_t
new file mode 100644
--- /dev/null
+++ b/gfx/cairo/cairo/src/cairo-mutex-impl-private.h
@@ -0,0 +1,226 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005,2007 Red Hat, Inc.
+ * Copyright © 2007 Mathias Hasselmann
+ *
+ * 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 University of Southern
+ * California.
+ *
+ * Contributor(s):
+ *	Carl D. Worth <cworth@cworth.org>
+ *	Mathias Hasselmann <mathias.hasselmann@gmx.de>
+ *	Behdad Esfahbod <behdad@behdad.org>
+ */
+
+#ifndef CAIRO_MUTEX_IMPL_PRIVATE_H
+#define CAIRO_MUTEX_IMPL_PRIVATE_H
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cairo-features.h"
+
+CAIRO_BEGIN_DECLS
+
+
+/* A fully qualified no-operation statement */
+#define CAIRO_MUTEX_IMPL_NOOP	do {/*no-op*/} while (0)
+/* And one that evaluates it's argument once */
+#define CAIRO_MUTEX_IMPL_NOOP1(expr)        do { if (expr) ; } while (0)
+
+
+/* Cairo mutex implementation:
+ *
+ * Any new mutex implementation needs to do the following:
+ *
+ * - Condition on the right header or feature.  Headers are
+ *   preferred as eg. you still can use win32 mutex implementation
+ *   on a win32 system even if you do not compile the win32
+ *   surface/backend.
+ *
+ * - typedef #cairo_mutex_impl_t to the proper mutex type on your target
+ *   system.  Note that you may or may not need to use a pointer,
+ *   depending on what kinds of initialization your mutex
+ *   implementation supports.  No trailing semicolon needed.
+ *   You should be able to compile the following snippet (don't try
+ *   running it):
+ *
+ *   <programlisting>
+ *	cairo_mutex_impl_t _cairo_some_mutex;
+ *   </programlisting>
+ *
+ * - #define CAIRO_MUTEX_IMPL_LOCK(mutex) and CAIRO_MUTEX_IMPL_UNLOCK(mutex) to
+ *   proper statement to lock/unlock the mutex object passed in.
+ *   You can (and should) assume that the mutex is already
+ *   initialized, and is-not-already-locked/is-locked,
+ *   respectively.  Use the "do { ... } while (0)" idiom if necessary.
+ *   No trailing semicolons are needed (in any macro you define here).
+ *   You should be able to compile the following snippet:
+ *
+ *   <programlisting>
+ *	cairo_mutex_impl_t _cairo_some_mutex;
+ *
+ *      if (1)
+ *          CAIRO_MUTEX_IMPL_LOCK (_cairo_some_mutex);
+ *      else
+ *          CAIRO_MUTEX_IMPL_UNLOCK (_cairo_some_mutex);
+ *   </programlisting>
+ *
+ * - #define %CAIRO_MUTEX_IMPL_NIL_INITIALIZER to something that can
+ *   initialize the #cairo_mutex_impl_t type you defined.  Most of the
+ *   time one of 0, %NULL, or {} works.  At this point
+ *   you should be able to compile the following snippet:
+ *
+ *   <programlisting>
+ *	cairo_mutex_impl_t _cairo_some_mutex = CAIRO_MUTEX_IMPL_NIL_INITIALIZER;
+ *
+ *      if (1)
+ *          CAIRO_MUTEX_IMPL_LOCK (_cairo_some_mutex);
+ *      else
+ *          CAIRO_MUTEX_IMPL_UNLOCK (_cairo_some_mutex);
+ *   </programlisting>
+ *
+ * - If the above code is not enough to initialize a mutex on
+ *   your platform, #define CAIRO_MUTEX_IMPL_INIT(mutex) to statement
+ *   to initialize the mutex (allocate resources, etc).  Such that
+ *   you should be able to compile AND RUN the following snippet:
+ *
+ *   <programlisting>
+ *	cairo_mutex_impl_t _cairo_some_mutex = CAIRO_MUTEX_IMPL_NIL_INITIALIZER;
+ *
+ *      CAIRO_MUTEX_IMPL_INIT (_cairo_some_mutex);
+ *
+ *      if (1)
+ *          CAIRO_MUTEX_IMPL_LOCK (_cairo_some_mutex);
+ *      else
+ *          CAIRO_MUTEX_IMPL_UNLOCK (_cairo_some_mutex);
+ *   </programlisting>
+ *
+ * - If you define CAIRO_MUTEX_IMPL_INIT(mutex), cairo will use it to
+ *   initialize all static mutex'es.  If for any reason that should
+ *   not happen (eg. %CAIRO_MUTEX_IMPL_INIT is just a faster way than
+ *   what cairo does using %CAIRO_MUTEX_IMPL_NIL_INITIALIZER), then
+ *   <programlisting>
+ *      #define CAIRO_MUTEX_IMPL_INITIALIZE() CAIRO_MUTEX_IMPL_NOOP
+ *   </programlisting>
+ *
+ * - If your system supports freeing a mutex object (deallocating
+ *   resources, etc), then #define CAIRO_MUTEX_IMPL_FINI(mutex) to do
+ *   that.
+ *
+ * - If you define CAIRO_MUTEX_IMPL_FINI(mutex), cairo will use it to
+ *   define a finalizer function to finalize all static mutex'es.
+ *   However, it's up to you to call CAIRO_MUTEX_IMPL_FINALIZE() at
+ *   proper places, eg. when the system is unloading the cairo library.
+ *   So, if for any reason finalizing static mutex'es is not needed
+ *   (eg. you never call CAIRO_MUTEX_IMPL_FINALIZE()), then
+ *   <programlisting>
+ *      #define CAIRO_MUTEX_IMPL_FINALIZE() CAIRO_MUTEX_IMPL_NOOP
+ *   </programlisting>
+ *
+ * - That is all.  If for any reason you think the above API is
+ *   not enough to implement #cairo_mutex_impl_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.
+ */
+
+#ifndef CAIRO_MUTEX_TYPE_PRIVATE_H
+#error "Do not include cairo-mutex-impl-private.h directly.  Include cairo-mutex-type-private.h instead."
+#endif
+
+#if CAIRO_NO_MUTEX
+
+/* No mutexes */
+
+  typedef int cairo_mutex_impl_t;
+
+# define CAIRO_MUTEX_IMPL_INITIALIZE() CAIRO_MUTEX_IMPL_NOOP
+# define CAIRO_MUTEX_IMPL_LOCK(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex)
+# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex)
+# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER 0
+
+#elif HAVE_PTHREAD_H /*******************************************************/
+
+# include <pthread.h>
+
+  typedef pthread_mutex_t cairo_mutex_impl_t;
+
+# define CAIRO_MUTEX_IMPL_LOCK(mutex) pthread_mutex_lock (&(mutex))
+# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) pthread_mutex_unlock (&(mutex))
+# define CAIRO_MUTEX_IMPL_FINI(mutex) pthread_mutex_destroy (&(mutex))
+# define CAIRO_MUTEX_IMPL_FINALIZE() CAIRO_MUTEX_IMPL_NOOP
+# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+
+#elif HAVE_WINDOWS_H /*******************************************************/
+
+# include <windows.h>
+
+  typedef CRITICAL_SECTION cairo_mutex_impl_t;
+
+# define CAIRO_MUTEX_IMPL_LOCK(mutex) EnterCriticalSection (&(mutex))
+# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) LeaveCriticalSection (&(mutex))
+# define CAIRO_MUTEX_IMPL_INIT(mutex) InitializeCriticalSection (&(mutex))
+# define CAIRO_MUTEX_IMPL_FINI(mutex) DeleteCriticalSection (&(mutex))
+# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER { NULL, 0, 0, NULL, NULL, 0 }
+
+#elif defined __OS2__ /******************************************************/
+
+# define INCL_BASE
+# define INCL_PM
+# include <os2.h>
+
+  typedef HMTX cairo_mutex_impl_t;
+
+# define CAIRO_MUTEX_IMPL_LOCK(mutex) DosRequestMutexSem(mutex, SEM_INDEFINITE_WAIT)
+# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) DosReleaseMutexSem(mutex)
+# define CAIRO_MUTEX_IMPL_INIT(mutex) DosCreateMutexSem (NULL, &(mutex), 0L, FALSE)
+# define CAIRO_MUTEX_IMPL_FINI(mutex) DosCloseMutexSem (mutex)
+# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER 0
+
+#elif CAIRO_HAS_BEOS_SURFACE /***********************************************/
+
+  typedef BLocker* cairo_mutex_impl_t;
+
+# define CAIRO_MUTEX_IMPL_LOCK(mutex) (mutex)->Lock()
+# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) (mutex)->Unlock()
+# define CAIRO_MUTEX_IMPL_INIT(mutex) (mutex) = new BLocker()
+# define CAIRO_MUTEX_IMPL_FINI(mutex) delete (mutex)
+# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER NULL
+
+#else /**********************************************************************/
+
+# error "XXX: No mutex implementation found.  Cairo will not work with multiple threads.  Define CAIRO_NO_MUTEX to 1 to acknowledge and accept this limitation and compile cairo without thread-safety support."
+
+
+#endif
+
+CAIRO_END_DECLS
+
+#endif
--- a/gfx/cairo/cairo/src/cairo-mutex-private.h
+++ b/gfx/cairo/cairo/src/cairo-mutex-private.h
@@ -36,141 +36,32 @@
  *	Carl D. Worth <cworth@cworth.org>
  *	Mathias Hasselmann <mathias.hasselmann@gmx.de>
  *	Behdad Esfahbod <behdad@behdad.org>
  */
 
 #ifndef CAIRO_MUTEX_PRIVATE_H
 #define CAIRO_MUTEX_PRIVATE_H
 
-#if HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <cairo-features.h>
-
-#include "cairo-compiler-private.h"
 #include "cairo-mutex-type-private.h"
 
-/* Only the following three are mandatory at this point */
-#ifndef CAIRO_MUTEX_LOCK
-# error "CAIRO_MUTEX_LOCK not defined.  Check cairo-mutex-type-private.h."
-#endif
-#ifndef CAIRO_MUTEX_UNLOCK
-# error "CAIRO_MUTEX_UNLOCK not defined.  Check cairo-mutex-type-private.h."
-#endif
-#ifndef CAIRO_MUTEX_NIL_INITIALIZER
-# error "CAIRO_MUTEX_NIL_INITIALIZER not defined.  Check cairo-mutex-type-private.h."
-#endif
-
 CAIRO_BEGIN_DECLS
 
+#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
+cairo_private void _cairo_mutex_initialize (void);
+#endif
+#if _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
+cairo_private void _cairo_mutex_finalize (void);
+#endif
+/* only if using static initializer and/or finalizer define the boolean */
+#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER || _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
+  cairo_private extern cairo_bool_t _cairo_mutex_initialized;
+#endif
 
-#define CAIRO_MUTEX_DECLARE(mutex) extern cairo_mutex_t mutex
+/* Finally, extern the static mutexes and undef */
+
+#define CAIRO_MUTEX_DECLARE(mutex) cairo_private extern cairo_mutex_t mutex
 #include "cairo-mutex-list-private.h"
 #undef CAIRO_MUTEX_DECLARE
 
-
-/* make sure implementations don't fool us: we decide these ourself */
-#undef _CAIRO_MUTEX_USE_STATIC_INITIALIZER
-#undef _CAIRO_MUTEX_USE_STATIC_FINALIZER
-
-
-#ifdef CAIRO_MUTEX_INIT
-
-/* If %CAIRO_MUTEX_INIT is defined, we may need to initialize all
- * static mutex'es. */
-# ifndef CAIRO_MUTEX_INITIALIZE
-#  define CAIRO_MUTEX_INITIALIZE() do {	\
-       if (!_cairo_mutex_initialized)	\
-           _cairo_mutex_initialize ();	\
-   } while(0)
-
-   cairo_private void _cairo_mutex_initialize (void);
-
-   /* and make sure we implement the above */
-#  define _CAIRO_MUTEX_USE_STATIC_INITIALIZER 1
-# endif /* CAIRO_MUTEX_INITIALIZE */
-
-#else /* no CAIRO_MUTEX_INIT */
-
-/* Otherwise we probably don't need to initialize static mutex'es, */
-# ifndef CAIRO_MUTEX_INITIALIZE
-#  define CAIRO_MUTEX_INITIALIZE() CAIRO_MUTEX_NOOP
-# endif /* CAIRO_MUTEX_INITIALIZE */
-
-/* and dynamic ones can be initialized using the static initializer. */
-# define CAIRO_MUTEX_INIT(mutex) do {				\
-      cairo_mutex_t _tmp_mutex = CAIRO_MUTEX_NIL_INITIALIZER;	\
-      memcpy (&(mutex), &_tmp_mutex, sizeof (_tmp_mutex));	\
-  } while (0)
-
-#endif /* CAIRO_MUTEX_INIT */
-
-
-#ifdef CAIRO_MUTEX_FINI
-
-/* If %CAIRO_MUTEX_FINI is defined, we may need to finalize all
- * static mutex'es. */
-# ifndef CAIRO_MUTEX_FINALIZE
-#  define CAIRO_MUTEX_FINALIZE() do {	\
-       if (_cairo_mutex_initialized)	\
-           _cairo_mutex_finalize ();	\
-   } while(0)
-
-   cairo_private void _cairo_mutex_finalize (void);
-
-   /* and make sure we implement the above */
-#  define _CAIRO_MUTEX_USE_STATIC_FINALIZER 1
-# endif /* CAIRO_MUTEX_FINALIZE */
-
-#else /* no CAIRO_MUTEX_FINI */
-
-/* Otherwise we probably don't need to finalize static mutex'es, */
-# ifndef CAIRO_MUTEX_FINALIZE
-#  define CAIRO_MUTEX_FINALIZE() CAIRO_MUTEX_NOOP
-# endif /* CAIRO_MUTEX_FINALIZE */
-
-/* neither do the dynamic ones. */
-# define CAIRO_MUTEX_FINI(mutex)	CAIRO_MUTEX_NOOP1(mutex)
-
-#endif /* CAIRO_MUTEX_FINI */
-
-
-#ifndef _CAIRO_MUTEX_USE_STATIC_INITIALIZER
-#define _CAIRO_MUTEX_USE_STATIC_INITIALIZER 0
-#endif
-#ifndef _CAIRO_MUTEX_USE_STATIC_FINALIZER
-#define _CAIRO_MUTEX_USE_STATIC_FINALIZER 0
-#endif
-
-/* only if using static initializer and/or finalizer define the boolean */
-#if _CAIRO_MUTEX_USE_STATIC_INITIALIZER || _CAIRO_MUTEX_USE_STATIC_FINALIZER
-  cairo_private extern cairo_bool_t _cairo_mutex_initialized;
-#endif
-
-
 CAIRO_END_DECLS
 
-/* Make sure everything we want is defined */
-#ifndef CAIRO_MUTEX_INITIALIZE
-# error "CAIRO_MUTEX_INITIALIZE not defined"
 #endif
-#ifndef CAIRO_MUTEX_FINALIZE
-# error "CAIRO_MUTEX_FINALIZE not defined"
-#endif
-#ifndef CAIRO_MUTEX_LOCK
-# error "CAIRO_MUTEX_LOCK not defined"
-#endif
-#ifndef CAIRO_MUTEX_UNLOCK
-# error "CAIRO_MUTEX_UNLOCK not defined"
-#endif
-#ifndef CAIRO_MUTEX_INIT
-# error "CAIRO_MUTEX_INIT not defined"
-#endif
-#ifndef CAIRO_MUTEX_FINI
-# error "CAIRO_MUTEX_FINI not defined"
-#endif
-#ifndef CAIRO_MUTEX_NIL_INITIALIZER
-# error "CAIRO_MUTEX_NIL_INITIALIZER not defined"
-#endif
-
-#endif
--- a/gfx/cairo/cairo/src/cairo-mutex-type-private.h
+++ b/gfx/cairo/cairo/src/cairo-mutex-type-private.h
@@ -40,171 +40,149 @@
 
 #ifndef CAIRO_MUTEX_TYPE_PRIVATE_H
 #define CAIRO_MUTEX_TYPE_PRIVATE_H
 
 #if HAVE_CONFIG_H
 #include "config.h"
 #endif
 
-#include <cairo-features.h>
+#include "cairo-features.h"
+
+#include "cairo-compiler-private.h"
+#include "cairo-mutex-impl-private.h"
 
-CAIRO_BEGIN_DECLS
+/* Only the following three are mandatory at this point */
+#ifndef CAIRO_MUTEX_IMPL_LOCK
+# error "CAIRO_MUTEX_IMPL_LOCK not defined.  Check cairo-mutex-impl-private.h."
+#endif
+#ifndef CAIRO_MUTEX_IMPL_UNLOCK
+# error "CAIRO_MUTEX_IMPL_UNLOCK not defined.  Check cairo-mutex-impl-private.h."
+#endif
+#ifndef CAIRO_MUTEX_IMPL_NIL_INITIALIZER
+# error "CAIRO_MUTEX_IMPL_NIL_INITIALIZER not defined.  Check cairo-mutex-impl-private.h."
+#endif
+
+
+/* make sure implementations don't fool us: we decide these ourself */
+#undef _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
+#undef _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
 
 
-/* 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)
+#ifdef CAIRO_MUTEX_IMPL_INIT
+
+/* If %CAIRO_MUTEX_IMPL_INIT is defined, we may need to initialize all
+ * static mutex'es. */
+# ifndef CAIRO_MUTEX_IMPL_INITIALIZE
+#  define CAIRO_MUTEX_IMPL_INITIALIZE() do {	\
+       if (!_cairo_mutex_initialized)	\
+           _cairo_mutex_initialize ();	\
+    } while(0)
+
+/* and make sure we implement the above */
+#  define _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER 1
+# endif /* CAIRO_MUTEX_IMPL_INITIALIZE */
+
+#else /* no CAIRO_MUTEX_IMPL_INIT */
+
+/* Otherwise we probably don't need to initialize static mutex'es, */
+# ifndef CAIRO_MUTEX_IMPL_INITIALIZE
+#  define CAIRO_MUTEX_IMPL_INITIALIZE() CAIRO_MUTEX_IMPL_NOOP
+# endif /* CAIRO_MUTEX_IMPL_INITIALIZE */
+
+/* and dynamic ones can be initialized using the static initializer. */
+# define CAIRO_MUTEX_IMPL_INIT(mutex) do {				\
+      cairo_mutex_t _tmp_mutex = CAIRO_MUTEX_IMPL_NIL_INITIALIZER;	\
+      memcpy (&(mutex), &_tmp_mutex, sizeof (_tmp_mutex));	\
+  } while (0)
+
+#endif /* CAIRO_MUTEX_IMPL_INIT */
 
 
-/* Cairo mutex implementation:
- *
- * Any new mutex implementation needs to do the following:
- *
- * - Condition on the right header or feature.  Headers are
- *   preferred as eg. you still can use win32 mutex implementation
- *   on a win32 system even if you do not compile the win32
- *   surface/backend.
- *
- * - typedef #cairo_mutex_t to the proper mutex type on your target
- *   system.  Note that you may or may not need to use a pointer,
- *   depending on what kinds of initialization your mutex
- *   implementation supports.  No trailing semicolon needed.
- *   You should be able to compile the following snippet (don't try
- *   running it):
- *
- *	cairo_mutex_t _cairo_some_mutex;
- *
- * - #define CAIRO_MUTEX_LOCK(mutex) and CAIRO_MUTEX_UNLOCK(mutex) to
- *   proper statement to lock/unlock the mutex object passed in.
- *   You can (and should) assume that the mutex is already
- *   initialized, and is-not-already-locked/is-locked,
- *   respectively.  Use the "do { ... } while (0)" idiom if necessary.
- *   No trailing semicolons are needed (in any macro you define here).
- *   You should be able to compile the following snippet:
- *
- *	cairo_mutex_t _cairo_some_mutex;
- *
- *      if (1)
- *          %CAIRO_MUTEX_LOCK (_cairo_some_mutex);
- *      else
- *          %CAIRO_MUTEX_UNLOCK (_cairo_some_mutex);
- *
- * - #define %CAIRO_MUTEX_NIL_INITIALIZER to something that can
- *   initialize the #cairo_mutex_t type you defined.  Most of the
- *   time one of 0, %NULL, or {} works.  At this point
- *   you should be able to compile the following snippet:
- *
- *	cairo_mutex_t _cairo_some_mutex = CAIRO_MUTEX_NIL_INITIALIZER;
- *
- *      if (1)
- *          %CAIRO_MUTEX_LOCK (_cairo_some_mutex);
- *      else
- *          %CAIRO_MUTEX_UNLOCK (_cairo_some_mutex);
- *
- * - If the above code is not enough to initialize a mutex on
- *   your platform, #define CAIRO_MUTEX_INIT(mutex) to statement
- *   to initialize the mutex (allocate resources, etc).  Such that
- *   you should be able to compile AND RUN the following snippet:
- *
- *	cairo_mutex_t _cairo_some_mutex = CAIRO_MUTEX_NIL_INITIALIZER;
- *
- *      %CAIRO_MUTEX_INIT (_cairo_some_mutex);
- *
- *      if (1)
- *          %CAIRO_MUTEX_LOCK (_cairo_some_mutex);
- *      else
- *          %CAIRO_MUTEX_UNLOCK (_cairo_some_mutex);
- *
- * - If you define CAIRO_MUTEX_INIT(mutex), cairo will use it to
- *   initialize all static mutex'es.  If for any reason that should
- *   not happen (eg. %CAIRO_MUTEX_INIT is just a faster way than
- *   what cairo does using %CAIRO_MUTEX_NIL_INITIALIZER), then
- *   #define CAIRO_MUTEX_INITIALIZE() CAIRO_MUTEX_NOOP
- *
- * - If your system supports freeing a mutex object (deallocating
- *   resources, etc), then #define CAIRO_MUTEX_FINI(mutex) to do
- *   that.
- *
- * - If you define CAIRO_MUTEX_FINI(mutex), cairo will use it to
- *   define a finalizer function to finalize all static mutex'es.
- *   However, it's up to you to call CAIRO_MUTEX_FINALIZE() at
- *   proper places, eg. when the system is unloading the cairo library.
- *   So, if for any reason finalizing static mutex'es is not needed
- *   (eg. you never call %CAIRO_MUTEX_FINALIZE), then
- *   #define CAIRO_MUTEX_FINALIZE() CAIRO_MUTEX_NOOP
- *
- * - 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.
- */
+#ifdef CAIRO_MUTEX_IMPL_FINI
+
+/* If %CAIRO_MUTEX_IMPL_FINI is defined, we may need to finalize all
+ * static mutex'es. */
+# ifndef CAIRO_MUTEX_IMPL_FINALIZE
+#  define CAIRO_MUTEX_IMPL_FINALIZE() do {	\
+       if (_cairo_mutex_initialized)	\
+           _cairo_mutex_finalize ();	\
+    } while(0)
+
+/* and make sure we implement the above */
+#  define _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER 1
+# endif /* CAIRO_MUTEX_IMPL_FINALIZE */
+
+#else /* no CAIRO_MUTEX_IMPL_FINI */
 
-#if CAIRO_NO_MUTEX
-
-/* No mutexes */
-
-  typedef int cairo_mutex_t;
-
-# define CAIRO_MUTEX_INITIALIZE() CAIRO_MUTEX_NOOP
-# 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 /*******************************************************/
+/* Otherwise we probably don't need to finalize static mutex'es, */
+# ifndef CAIRO_MUTEX_IMPL_FINALIZE
+#  define CAIRO_MUTEX_IMPL_FINALIZE() CAIRO_MUTEX_IMPL_NOOP
+# endif /* CAIRO_MUTEX_IMPL_FINALIZE */
 
-# include <pthread.h>
-
-  typedef pthread_mutex_t cairo_mutex_t;
-
-# define CAIRO_MUTEX_LOCK(mutex) pthread_mutex_lock (&(mutex))
-# define CAIRO_MUTEX_UNLOCK(mutex) pthread_mutex_unlock (&(mutex))
-# define CAIRO_MUTEX_FINI(mutex) pthread_mutex_destroy (&(mutex))
-# define CAIRO_MUTEX_FINALIZE() CAIRO_MUTEX_NOOP
-# define CAIRO_MUTEX_NIL_INITIALIZER PTHREAD_MUTEX_INITIALIZER
-
-#elif HAVE_WINDOWS_H /*******************************************************/
-
-# include <windows.h>
-
-  typedef CRITICAL_SECTION cairo_mutex_t;
+/* neither do the dynamic ones. */
+# define CAIRO_MUTEX_IMPL_FINI(mutex)	CAIRO_MUTEX_IMPL_NOOP1(mutex)
 
-# define CAIRO_MUTEX_LOCK(mutex) EnterCriticalSection (&(mutex))
-# define CAIRO_MUTEX_UNLOCK(mutex) LeaveCriticalSection (&(mutex))
-# define CAIRO_MUTEX_INIT(mutex) InitializeCriticalSection (&(mutex))
-# define CAIRO_MUTEX_FINI(mutex) DeleteCriticalSection (&(mutex))
-# define CAIRO_MUTEX_NIL_INITIALIZER { NULL, 0, 0, NULL, NULL, 0 }
+#endif /* CAIRO_MUTEX_IMPL_FINI */
 
-#elif defined __OS2__ /******************************************************/
-
-# define INCL_BASE
-# define INCL_PM
-# include <os2.h>
-
-  typedef HMTX cairo_mutex_t;
 
-# define CAIRO_MUTEX_LOCK(mutex) DosRequestMutexSem(mutex, SEM_INDEFINITE_WAIT)
-# define CAIRO_MUTEX_UNLOCK(mutex) DosReleaseMutexSem(mutex)
-# define CAIRO_MUTEX_INIT(mutex) DosCreateMutexSem (NULL, &(mutex), 0L, FALSE)
-# define CAIRO_MUTEX_FINI(mutex) DosCloseMutexSem (mutex)
-# define CAIRO_MUTEX_NIL_INITIALIZER 0
-
-#elif CAIRO_HAS_BEOS_SURFACE /***********************************************/
-
-  typedef BLocker* cairo_mutex_t;
-
-# define CAIRO_MUTEX_LOCK(mutex) (mutex)->Lock()
-# define CAIRO_MUTEX_UNLOCK(mutex) (mutex)->Unlock()
-# define CAIRO_MUTEX_INIT(mutex) (mutex) = new BLocker()
-# define CAIRO_MUTEX_FINI(mutex) delete (mutex)
-# define CAIRO_MUTEX_NIL_INITIALIZER NULL
-
-#else /**********************************************************************/
-
-# error "XXX: No mutex implementation found.  Cairo will not work with multiple threads.  Define CAIRO_NO_MUTEX to 1 to acknowledge and accept this limitation and compile cairo without thread-safety support."
+#ifndef _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
+#define _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER 0
+#endif
+#ifndef _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
+#define _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER 0
+#endif
 
 
+/* Make sure everything we want is defined */
+#ifndef CAIRO_MUTEX_IMPL_INITIALIZE
+# error "CAIRO_MUTEX_IMPL_INITIALIZE not defined"
+#endif
+#ifndef CAIRO_MUTEX_IMPL_FINALIZE
+# error "CAIRO_MUTEX_IMPL_FINALIZE not defined"
+#endif
+#ifndef CAIRO_MUTEX_IMPL_LOCK
+# error "CAIRO_MUTEX_IMPL_LOCK not defined"
+#endif
+#ifndef CAIRO_MUTEX_IMPL_UNLOCK
+# error "CAIRO_MUTEX_IMPL_UNLOCK not defined"
+#endif
+#ifndef CAIRO_MUTEX_IMPL_INIT
+# error "CAIRO_MUTEX_IMPL_INIT not defined"
+#endif
+#ifndef CAIRO_MUTEX_IMPL_FINI
+# error "CAIRO_MUTEX_IMPL_FINI not defined"
+#endif
+#ifndef CAIRO_MUTEX_IMPL_NIL_INITIALIZER
+# error "CAIRO_MUTEX_IMPL_NIL_INITIALIZER not defined"
 #endif
 
-CAIRO_END_DECLS
+
+/* Public interface. */
+
+/* By default it simply uses the implementation provided.
+ * But we can provide for debugging features by overriding them */
+
+#ifndef CAIRO_MUTEX_DEBUG
+typedef cairo_mutex_impl_t cairo_mutex_t;
+#else
+# define cairo_mutex_t			cairo_mutex_impl_t
+#endif
+
+#define CAIRO_MUTEX_INITIALIZE		CAIRO_MUTEX_IMPL_INITIALIZE
+#define CAIRO_MUTEX_FINALIZE		CAIRO_MUTEX_IMPL_FINALIZE
+#define CAIRO_MUTEX_LOCK		CAIRO_MUTEX_IMPL_LOCK
+#define CAIRO_MUTEX_UNLOCK		CAIRO_MUTEX_IMPL_UNLOCK
+#define CAIRO_MUTEX_INIT		CAIRO_MUTEX_IMPL_INIT
+#define CAIRO_MUTEX_FINI		CAIRO_MUTEX_IMPL_FINI
+#define CAIRO_MUTEX_NIL_INITIALIZER	CAIRO_MUTEX_IMPL_NIL_INITIALIZER
+
+
+
+/* Debugging support */
+
+#ifdef CAIRO_MUTEX_DEBUG
+
+/* TODO add mutex debugging facilities here (eg deadlock detection) */
+
+#endif /* CAIRO_MUTEX_DEBUG */
 
 #endif
--- a/gfx/cairo/cairo/src/cairo-mutex.c
+++ b/gfx/cairo/cairo/src/cairo-mutex.c
@@ -28,49 +28,51 @@
  * The Original Code is the cairo graphics library.
  *
  * Contributor(s):
  *	Mathias Hasselmann <mathias.hasselmann@gmx.de>
  */
 
 #include "cairoint.h"
 
+#include "cairo-mutex-private.h"
+
 #define CAIRO_MUTEX_DECLARE(mutex) cairo_mutex_t mutex = CAIRO_MUTEX_NIL_INITIALIZER
 #include "cairo-mutex-list-private.h"
 #undef   CAIRO_MUTEX_DECLARE
 
-#if _CAIRO_MUTEX_USE_STATIC_INITIALIZER || _CAIRO_MUTEX_USE_STATIC_FINALIZER
+#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER || _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
 
-# if _CAIRO_MUTEX_USE_STATIC_INITIALIZER
-#  define _CAIRO_MUTEX_INITIALIZED_DEFAULT_VALUE FALSE
+# if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
+#  define _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE FALSE
 # else
-#  define _CAIRO_MUTEX_INITIALIZED_DEFAULT_VALUE TRUE
+#  define _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE TRUE
 # endif
 
-cairo_bool_t _cairo_mutex_initialized = _CAIRO_MUTEX_INITIALIZED_DEFAULT_VALUE;
+cairo_bool_t _cairo_mutex_initialized = _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE;
 
-# undef _CAIRO_MUTEX_INITIALIZED_DEFAULT_VALUE
+# undef _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE
 
 #endif
 
-#if _CAIRO_MUTEX_USE_STATIC_INITIALIZER
+#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
 void _cairo_mutex_initialize (void)
 {
     if (_cairo_mutex_initialized)
         return;
 
     _cairo_mutex_initialized = TRUE;
 
 #define  CAIRO_MUTEX_DECLARE(mutex) CAIRO_MUTEX_INIT (mutex)
 #include "cairo-mutex-list-private.h"
 #undef   CAIRO_MUTEX_DECLARE
 }
 #endif
 
-#if _CAIRO_MUTEX_USE_STATIC_FINALIZER
+#if _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
 void _cairo_mutex_finalize (void)
 {
     if (!_cairo_mutex_initialized)
         return;
 
     _cairo_mutex_initialized = FALSE;
 
 #define  CAIRO_MUTEX_DECLARE(mutex) CAIRO_MUTEX_FINI (mutex)
--- a/gfx/cairo/cairo/src/cairo-os2-private.h
+++ b/gfx/cairo/cairo/src/cairo-os2-private.h
@@ -44,17 +44,17 @@
 #define INCL_WIN
 #define INCL_GPI
 #ifdef __WATCOMC__
 # include <os2.h>
 #else
 # include <os2emx.h>
 #endif
 
-#include <cairo-os2.h>
+#include "cairo-os2.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;
--- a/gfx/cairo/cairo/src/cairo-os2-surface.c
+++ b/gfx/cairo/cairo/src/cairo-os2-surface.c
@@ -51,18 +51,18 @@
 # include "cairo-os2.h"
 # ifndef __WATCOMC__
 #  include <emx/startup.h>
 # endif
 #endif
 
 /*
  * Here comes the extra API for the OS/2 platform. Currently it consists
- * of two extra functions, the cairo_os2_init () and the
- * cairo_os2_fini (). Both of them are called automatically if
+ * of two extra functions, the cairo_os2_init() and the
+ * cairo_os2_fini(). Both of them are called automatically if
  * Cairo is compiled to be a DLL file, but you have to call them before
  * using the Cairo API if you link to Cairo statically!
  *
  * You'll also find the code in here which deals with DLL initialization
  * and termination, if the code is built to be a DLL.
  * (if BUILD_CAIRO_DLL is defined)
  */
 
@@ -140,18 +140,20 @@ cairo_os2_fini (void)
     _cairo_font_reset_static_data ();
 #if CAIRO_HAS_FT_FONT
     _cairo_ft_font_reset_static_data ();
 #endif
 
     CAIRO_MUTEX_FINALIZE ();
 
 #if CAIRO_HAS_FT_FONT
+# if HAVE_FCFINI
     /* Uninitialize FontConfig */
     FcFini ();
+# endif
 #endif
 
 #ifdef __WATCOMC__
     /* It can happen that the libraries we use have memory leaks,
      * so there are still memory chunks allocated at this point.
      * In these cases, Watcom might still have a bigger memory chunk,
      * called "the heap" allocated from the OS.
      * As we want to minimize the memory we lose from the point of
--- a/gfx/cairo/cairo/src/cairo-os2.h
+++ b/gfx/cairo/cairo/src/cairo-os2.h
@@ -33,17 +33,17 @@
  *
  * Contributor(s):
  *     Peter Weilbacher <mozilla@Weilbacher.org>
  */
 
 #ifndef _CAIRO_OS2_H_
 #define _CAIRO_OS2_H_
 
-#include <cairo.h>
+#include "cairo.h"
 
 CAIRO_BEGIN_DECLS
 
 /* The OS/2 Specific Cairo API */
 
 cairo_public void
 cairo_os2_init (void);
 
--- a/gfx/cairo/cairo/src/cairo-output-stream-private.h
+++ b/gfx/cairo/cairo/src/cairo-output-stream-private.h
@@ -152,17 +152,17 @@ cairo_private cairo_output_stream_t *
 
 cairo_private void
 _cairo_memory_stream_copy (cairo_output_stream_t *base,
 			   cairo_output_stream_t *dest);
 
 cairo_private int
 _cairo_memory_stream_length (cairo_output_stream_t *stream);
 
-/* cairo_base85_stream.c */
+/* cairo-base85-stream.c */
 cairo_private cairo_output_stream_t *
 _cairo_base85_stream_create (cairo_output_stream_t *output);
 
-/* cairo_deflate_stream.c */
+/* cairo-deflate-stream.c */
 cairo_private cairo_output_stream_t *
 _cairo_deflate_stream_create (cairo_output_stream_t *output);
 
 #endif /* CAIRO_OUTPUT_STREAM_PRIVATE_H */
--- a/gfx/cairo/cairo/src/cairo-output-stream.c
+++ b/gfx/cairo/cairo/src/cairo-output-stream.c
@@ -44,29 +44,31 @@
 #include <ctype.h>
 #include <errno.h>
 
 /* Numbers printed with %f are printed with this number of significant
  * digits after the decimal.
  */
 #define SIGNIFICANT_DIGITS_AFTER_DECIMAL 6
 
-/* Numbers printed with %g are assumed to only have CAIRO_FIXED_FRAC_BITS
+/* Numbers printed with %g are assumed to only have %CAIRO_FIXED_FRAC_BITS
  * bits of precision available after the decimal point.
  *
  * FIXED_POINT_DECIMAL_DIGITS specifies the minimum number of decimal
  * digits after the decimal point required to preserve the available
  * precision.
  *
  * The conversion is:
  *
+ * <programlisting>
  * FIXED_POINT_DECIMAL_DIGITS = ceil( CAIRO_FIXED_FRAC_BITS * ln(2)/ln(10) )
+ * </programlisting>
  *
  * We can replace ceil(x) with (int)(x+1) since x will never be an
- * integer for any likely value of CAIRO_FIXED_FRAC_BITS.
+ * integer for any likely value of %CAIRO_FIXED_FRAC_BITS.
  */
 #define FIXED_POINT_DECIMAL_DIGITS ((int)(CAIRO_FIXED_FRAC_BITS*0.301029996 + 1))
 
 void
 _cairo_output_stream_init (cairo_output_stream_t            *stream,
 			   cairo_output_stream_write_func_t  write_func,
 			   cairo_output_stream_close_func_t  close_func)
 {
--- a/gfx/cairo/cairo/src/cairo-paginated-private.h
+++ b/gfx/cairo/cairo/src/cairo-paginated-private.h
@@ -62,60 +62,68 @@ struct _cairo_paginated_surface_backend 
 
     /* Optional. Specifies the smallest box that encloses all objects
      * on the page. Will be called at the end of the ANALYZE phase but
      * before the mode is changed to RENDER.
      */
     cairo_warn cairo_int_status_t
     (*set_bounding_box)	(void	   	*surface,
 			 cairo_box_t	*bbox);
+
+    /* Optional. Indicates whether the page requires fallback images.
+     * Will be called at the end of the ANALYZE phase but before the
+     * mode is changed to RENDER.
+     */
+    cairo_warn cairo_int_status_t
+    (*set_fallback_images_required)(void   	  *surface,
+				    cairo_bool_t   fallbacks_required);
 };
 
 /* A #cairo_paginated_surface_t provides a very convenient wrapper that
  * is well-suited for doing the analysis common to most surfaces that
  * have paginated output, (that is, things directed at printers, or
  * for saving content in files such as PostScript or PDF files).
  *
  * To use the paginated surface, you'll first need to create your
  * 'real' surface using _cairo_surface_init() and the standard
  * #cairo_surface_backend_t. Then you also call
  * _cairo_paginated_surface_create which takes its own, much simpler,
  * #cairo_paginated_surface_backend_t. You are free to return the result
  * of _cairo_paginated_surface_create() from your public
- * cairo_<foo>_surface_create. The paginated backend will be careful
+ * cairo_<foo>_surface_create(). The paginated backend will be careful
  * to not let the user see that they really got a "wrapped"
  * surface. See test-paginated-surface.c for a fairly minimal example
  * of a paginated-using surface. That should be a reasonable example
  * to follow.
  *
  * What the paginated surface does is first save all drawing
  * operations for a page into a meta-surface. Then when the user calls
- * cairo_show_page, the paginated surface performs the following
+ * cairo_show_page(), the paginated surface performs the following
  * sequence of operations (using the backend functions passed to
- * cairo_paginated_surface_create):
+ * cairo_paginated_surface_create()):
  *
- * 1. Calls start_page (if non %NULL). At this point, it is appropriate
+ * 1. Calls start_page() (if not %NULL). At this point, it is appropriate
  *    for the target to emit any page-specific header information into
  *    its output.
  *
- * 2. Calls set_paginated_mode with an argument of CAIRO_PAGINATED_MODE_ANALYZE
+ * 2. Calls set_paginated_mode() with an argument of %CAIRO_PAGINATED_MODE_ANALYZE
  *
  * 3. Replays the meta-surface to the target surface, (with an
  *    analysis surface inserted between which watches the return value
  *    from each operation). This analysis stage is used to decide which
  *    operations will require fallbacks.
  *
- * 4. Calls set_bounding_box to provide the target surface with the
+ * 4. Calls set_bounding_box() to provide the target surface with the
  *    tight bounding box of the page.
  *
- * 5. Calls set_paginated_mode with an argument of CAIRO_PAGINATED_MODE_RENDER
+ * 5. Calls set_paginated_mode() with an argument of %CAIRO_PAGINATED_MODE_RENDER
  *
  * 6. Replays a subset of the meta-surface operations to the target surface
  *
- * 7. Calls set_paginated_mode with an argument of CAIRO_PAGINATED_MODE_FALLBACK
+ * 7. Calls set_paginated_mode() with an argument of %CAIRO_PAGINATED_MODE_FALLBACK
  *
  * 8. Replays the remaining operations to an image surface, sets an
  *    appropriate clip on the target, then paints the resulting image
  *    surface to the target.
  *
  * So, the target will see drawing operations during three separate
  * stages, (ANALYZE, RENDER and FALLBACK). During the ANALYZE phase
  * the target should not actually perform any rendering, (for example,
--- a/gfx/cairo/cairo/src/cairo-paginated-surface.c
+++ b/gfx/cairo/cairo/src/cairo-paginated-surface.c
@@ -84,17 +84,17 @@ cairo_surface_t *
 
     _cairo_surface_init (&surface->base, &cairo_paginated_surface_backend,
 			 content);
 
     /* Override surface->base.type with target's type so we don't leak
      * evidence of the paginated wrapper out to the user. */
     surface->base.type = cairo_surface_get_type (target);
 
-    surface->target = target;
+    surface->target = cairo_surface_reference (target);
 
     surface->content = content;
     surface->width = width;
     surface->height = height;
 
     surface->backend = backend;
 
     surface->meta = _cairo_meta_surface_create (content, width, height);
@@ -311,16 +311,25 @@ static cairo_int_status_t
 	 cairo_box_t bbox;
 
 	 _cairo_analysis_surface_get_bounding_box (analysis, &bbox);
 	 status = surface->backend->set_bounding_box (surface->target, &bbox);
 	 if (status)
 	     goto FAIL;
      }
 
+    if (surface->backend->set_fallback_images_required) {
+	cairo_bool_t has_fallbacks = _cairo_analysis_surface_has_unsupported (analysis);
+
+	status = surface->backend->set_fallback_images_required (surface->target,
+								 has_fallbacks);
+	if (status)
+	    goto FAIL;
+    }
+
     surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_RENDER);
 
     /* 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:
@@ -590,47 +599,63 @@ static cairo_int_status_t
 
     surface->page_is_blank = FALSE;
 
     return _cairo_surface_fill (surface->meta, op, source,
 				path, fill_rule,
 				tolerance, antialias);
 }
 
+static cairo_bool_t
+_cairo_paginated_surface_has_show_text_glyphs (void *abstract_surface)
+{
+    cairo_paginated_surface_t *surface = abstract_surface;
+
+    return _cairo_surface_has_show_text_glyphs (surface->target);
+}
+
 static cairo_int_status_t
-_cairo_paginated_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_paginated_surface_show_text_glyphs (void			    *abstract_surface,
+					  cairo_operator_t	     op,
+					  cairo_pattern_t	    *source,
+					  const char		    *utf8,
+					  int			     utf8_len,
+					  cairo_glyph_t		    *glyphs,
+					  int			     num_glyphs,
+					  const cairo_text_cluster_t *clusters,
+					  int			     num_clusters,
+					  cairo_bool_t		     backward,
+					  cairo_scaled_font_t	    *scaled_font)
 {
     cairo_paginated_surface_t *surface = abstract_surface;
     cairo_int_status_t status;
 
     /* Optimize away erasing of nothing. */
     if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
 	return CAIRO_STATUS_SUCCESS;
 
     surface->page_is_blank = FALSE;
 
     /* Since this is a "wrapping" surface, we're calling back into
-     * _cairo_surface_show_glyphs from within a call to the same.
-     * Since _cairo_surface_show_glyphs acquires a mutex, we release
+     * _cairo_surface_show_text_glyphs from within a call to the same.
+     * Since _cairo_surface_show_text_glyphs acquires a mutex, we release
      * and re-acquire the mutex around this nested call.
      *
      * Yes, this is ugly, but we consider it pragmatic as compared to
      * adding locking code to all 18 surface-backend-specific
      * show_glyphs functions, (which would get less testing and likely
      * lead to bugs).
      */
     CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
-    status = _cairo_surface_show_glyphs (surface->meta, op, source,
-					 glyphs, num_glyphs,
-					 scaled_font);
+    status = _cairo_surface_show_text_glyphs (surface->meta, op, source,
+					      utf8, utf8_len,
+					      glyphs, num_glyphs,
+					      clusters, num_clusters,
+					      backward,
+					      scaled_font);
     CAIRO_MUTEX_LOCK (scaled_font->mutex);
 
     return status;
 }
 
 static cairo_surface_t *
 _cairo_paginated_surface_snapshot (void *abstract_other)
 {
@@ -661,11 +686,17 @@ static const cairo_surface_backend_t cai
     NULL, /* flush */
     NULL, /* mark_dirty_rectangle */
     NULL, /* scaled_font_fini */
     NULL, /* scaled_glyph_fini */
     _cairo_paginated_surface_paint,
     _cairo_paginated_surface_mask,
     _cairo_paginated_surface_stroke,
     _cairo_paginated_surface_fill,
-    _cairo_paginated_surface_show_glyphs,
-    _cairo_paginated_surface_snapshot
+    NULL, /* show_glyphs */
+    _cairo_paginated_surface_snapshot,
+    NULL, /* is_similar */
+    NULL, /* reset */
+    NULL, /* fill_stroke */
+    NULL, /* create_solid_pattern_surface */
+    _cairo_paginated_surface_has_show_text_glyphs,
+    _cairo_paginated_surface_show_text_glyphs
 };
--- a/gfx/cairo/cairo/src/cairo-path-fixed.c
+++ b/gfx/cairo/cairo/src/cairo-path-fixed.c
@@ -471,26 +471,26 @@ static int const num_args[] =
 {
     1, /* cairo_path_move_to */
     1, /* cairo_path_op_line_to */
     3, /* cairo_path_op_curve_to */
     0, /* cairo_path_op_close_path */
 };
 
 cairo_status_t
-_cairo_path_fixed_interpret (cairo_path_fixed_t			*path,
+_cairo_path_fixed_interpret (const cairo_path_fixed_t		*path,
 			     cairo_direction_t			 dir,
 			     cairo_path_fixed_move_to_func_t	*move_to,
 			     cairo_path_fixed_line_to_func_t	*line_to,
 			     cairo_path_fixed_curve_to_func_t	*curve_to,
 			     cairo_path_fixed_close_path_func_t	*close_path,
 			     void				*closure)
 {
     cairo_status_t status;
-    cairo_path_buf_t *buf;
+    const cairo_path_buf_t *buf;
     cairo_path_op_t op;
     cairo_bool_t forward = (dir == CAIRO_DIRECTION_FORWARD);
     int step = forward ? 1 : -1;
 
     for (buf = forward ? &path->buf_head.base : path->buf_tail;
 	 buf;
 	 buf = forward ? buf->next : buf->prev)
     {
@@ -536,16 +536,62 @@ cairo_status_t
 	    }
 
 	}
     }
 
     return CAIRO_STATUS_SUCCESS;
 }
 
+static cairo_status_t
+_append_move_to (void		 *closure,
+	  cairo_point_t  *point)
+{
+    cairo_path_fixed_t *path = (cairo_path_fixed_t *) closure;
+    return _cairo_path_fixed_move_to (path, point->x, point->y);
+}
+
+static cairo_status_t
+_append_line_to (void		 *closure,
+	  cairo_point_t *point)
+{
+    cairo_path_fixed_t *path = (cairo_path_fixed_t *) closure;
+    return _cairo_path_fixed_line_to (path, point->x, point->y);
+}
+
+static cairo_status_t
+_append_curve_to (void	  *closure,
+	   cairo_point_t *p0,
+	   cairo_point_t *p1,
+	   cairo_point_t *p2)
+{
+    cairo_path_fixed_t *path = (cairo_path_fixed_t *) closure;
+    return _cairo_path_fixed_curve_to (path, p0->x, p0->y, p1->x, p1->y, p2->x, p2->y);
+}
+
+static cairo_status_t
+_append_close_path (void *closure)
+{
+    cairo_path_fixed_t *path = (cairo_path_fixed_t *) closure;
+    return _cairo_path_fixed_close_path (path);
+}
+
+cairo_private cairo_status_t
+_cairo_path_fixed_append (cairo_path_fixed_t		  *path,
+			  const cairo_path_fixed_t	  *other,
+			  cairo_direction_t		   dir)
+{