merge commit for bug 399397
authorBob Clary <bclary@bclary.com>
Thu, 24 Jul 2008 00:52:24 -0400
changeset 16164 15bab6c49cb283b54f483f42e12d7f40b13537e8
parent 16163 e97f539042ad9a147f01d9c26412103def387a98 (current diff)
parent 16162 8fecac9bc5ba473d3f2b46b9a9e7e6e25cead7d0 (diff)
child 16165 5daf2445b8b4052b7d60a9f63c4c2f864442243d
push id810
push userbclary@mozilla.com
push dateThu, 24 Jul 2008 04:53:43 +0000
treeherderautoland@15bab6c49cb2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs399397
milestone1.9.1a2pre
merge commit for bug 399397
gfx/cairo/cairo/src/cairo-debug.h
gfx/cairo/libpixman/src/pixman-combine.c
gfx/cairo/libpixman/src/pixman-remap.h
--- a/.hgtags
+++ b/.hgtags
@@ -1,4 +1,6 @@
 df7a3c8ffeeaba229067efee5a20e21dae0dd877 MOZILLA_1_9_a4_BASE
 4209e16b58411750ac73f761023e46b76b793e2c MOZILLA_1_9_a6_BASE
 66a5c7bce7ee86a820d3c0d54fa07cb719be751c MOZILLA_1_9_a7_BASE
 caeba7562e495a9f604984df0b48b6f99bec3e2e FENNEC_M4
+9d9941eacb14827fdab4716710042fdde84eb60d FIREFOX_3_1a1_RELEASE
+9d9941eacb14827fdab4716710042fdde84eb60d FIREFOX_3_1a1_BUILD1
--- a/accessible/public/msaa/ISimpleDOMDocument.idl
+++ b/accessible/public/msaa/ISimpleDOMDocument.idl
@@ -87,40 +87,32 @@ cpp_quote("// * See latest W3C CSS specs
 cpp_quote("//")
 cpp_quote("//")
 cpp_quote("///////////////////////////////////////////////////////////////////////////////////////////////////////")
 cpp_quote("")
 cpp_quote("")
 
 import "objidl.idl";
 import "oaidl.idl";
-        
-        
-const long DISPID_DOC_URL         = -5904;
-const long DISPID_DOC_TITLE       = -5905;
-const long DISPID_DOC_MIMETYPE    = -5906;
-const long DISPID_DOC_DOCTYPE     = -5907;
-const long DISPID_DOC_NAMESPACE   = -5908;
-const long DISPID_DOC_MEDIATYPES  = -5909;
 
 [object, uuid(0D68D6D0-D93D-4d08-A30D-F00DD1F45B24)]
 interface ISimpleDOMDocument : IUnknown
 {
-  [propget, id(DISPID_DOC_URL)] HRESULT URL(
+  [propget] HRESULT URL(
     [out, retval] BSTR * url
   );
-  [propget, id(DISPID_DOC_TITLE)] HRESULT title(
+  [propget] HRESULT title(
     [out, retval] BSTR * title
   );
-  [propget, id(DISPID_DOC_MIMETYPE)] HRESULT mimeType(
+  [propget] HRESULT mimeType(
     [out, retval] BSTR * mimeType
   );
-  [propget, id(DISPID_DOC_DOCTYPE)] HRESULT docType(
+  [propget] HRESULT docType(
     [out, retval] BSTR * docType
   );
-  [propget, id(DISPID_DOC_NAMESPACE)] HRESULT nameSpaceURIForID(
+  [propget] HRESULT nameSpaceURIForID(
     [in]  short nameSpaceID,
     [out, retval] BSTR * nameSpaceURI
   );
-  [propput, id(DISPID_DOC_MEDIATYPES)] HRESULT alternateViewMediaTypes(
+  [propput] HRESULT alternateViewMediaTypes(
     [in] BSTR * commaSeparatedMediaTypes
 	);
 }
--- a/accessible/public/msaa/ISimpleDOMNode.idl
+++ b/accessible/public/msaa/ISimpleDOMNode.idl
@@ -128,23 +128,19 @@ cpp_quote("// Returns the computed langu
 cpp_quote("//")
 cpp_quote("//")
 cpp_quote("///////////////////////////////////////////////////////////////////////////////////////////////////////")
 cpp_quote("")
 cpp_quote("")
 
 import "objidl.idl";
 import "oaidl.idl";
-        
-const long DISPID_NODE_NODEINFO   = -5900;
-const long DISPID_NODE_ATTRIBUTES = -5901;
-const long DISPID_NODE_ATTRIBUTESFORNAMES = -5902;
-const long DISPID_NODE_COMPSTYLE  = -5903;
-const long DISPID_NODE_COMPSTYLEFORPROPS = -5904;
-const long DISPID_NODE_LANGUAGE = -5905;
+
+import "ISimpleDOMText.idl";
+import "ISimpleDOMDocument.idl";
 
 [object, uuid(1814ceeb-49e2-407f-af99-fa755a7d2607)]
 interface ISimpleDOMNode : IUnknown
 {
   const unsigned short NODETYPE_ELEMENT = 1;
   const unsigned short NODETYPE_ATTRIBUTE = 2;
   const unsigned short NODETYPE_TEXT = 3;
   const unsigned short NODETYPE_CDATA_SECTION = 4;
@@ -152,49 +148,49 @@ interface ISimpleDOMNode : IUnknown
   const unsigned short NODETYPE_ENTITY = 6;
   const unsigned short NODETYPE_PROCESSING_INSTRUCTION = 7;
   const unsigned short NODETYPE_COMMENT = 8;
   const unsigned short NODETYPE_DOCUMENT = 9;
   const unsigned short NODETYPE_DOCUMENT_TYPE = 10;
   const unsigned short NODETYPE_DOCUMENT_FRAGMENT = 11;
   const unsigned short NODETYPE_NOTATION = 12;
 
-  [propget, id(DISPID_NODE_NODEINFO)] HRESULT nodeInfo(
+  [propget] HRESULT nodeInfo(
     [out] BSTR *nodeName,   // for performance returns NULL for text nodes (true nodeName would be "#text")
     [out] short *nameSpaceID,
     [out] BSTR *nodeValue,
     [out] unsigned int *numChildren,
     [out] unsigned int *uniqueID, // In Win32 accessible events we generate, the target's childID matches to this
     [out, retval] unsigned short *nodeType
   );
 
-  [propget, id(DISPID_NODE_ATTRIBUTES)] HRESULT attributes(  
+  [propget] HRESULT attributes(  
     [in] unsigned short maxAttribs,
     [out, size_is(maxAttribs), length_is(*numAttribs)] BSTR *attribNames, 
     [out, size_is(maxAttribs), length_is(*numAttribs)] short *nameSpaceID,  
     [out, size_is(maxAttribs), length_is(*numAttribs)] BSTR *attribValues,
     [out, retval] unsigned short *numAttribs
   );
 
-  [propget, id(DISPID_NODE_ATTRIBUTESFORNAMES)] HRESULT attributesForNames(  
+  [propget] HRESULT attributesForNames(  
     [in] unsigned short numAttribs,
     [in, size_is(numAttribs), length_is(numAttribs)] BSTR *attribNames, 
     [in, size_is(numAttribs), length_is(numAttribs)] short *nameSpaceID,  
     [out, retval, size_is(numAttribs), length_is(numAttribs)] BSTR *attribValues
   );
 
-  [propget, id(DISPID_NODE_COMPSTYLE)] HRESULT computedStyle(  
+  [propget] HRESULT computedStyle(  
     [in] unsigned short maxStyleProperties,
     [in] boolean useAlternateView,  // If TRUE, returns properites for media as set in nsIDOMDocument::set_alternateViewMediaTypes
     [out, size_is(maxStyleProperties), length_is(*numStyleProperties)] BSTR *styleProperties, 
     [out, size_is(maxStyleProperties), length_is(*numStyleProperties)] BSTR *styleValues,
     [out, retval] unsigned short *numStyleProperties
   );
 
-  [propget, id(DISPID_NODE_COMPSTYLEFORPROPS)] HRESULT computedStyleForProperties(  
+  [propget] HRESULT computedStyleForProperties(  
     [in] unsigned short numStyleProperties, 
     [in] boolean useAlternateView,  // If TRUE, returns properites for media as set in nsIDOMDocument::set_alternateViewMediaTypes
     [in, size_is(numStyleProperties), length_is(numStyleProperties)] BSTR *styleProperties, 
     [out, retval, size_is(numStyleProperties), length_is(numStyleProperties)] BSTR *styleValues
   );
 
   HRESULT scrollTo([in] boolean placeTopLeft);
 
@@ -205,12 +201,23 @@ interface ISimpleDOMNode : IUnknown
   [propget] HRESULT nextSibling([out, retval] ISimpleDOMNode **node);
   [propget] HRESULT childAt([in] unsigned childIndex, 
                             [out, retval] ISimpleDOMNode **node);
 
   [propget] HRESULT innerHTML([out, retval] BSTR *innerHTML);
 
   [propget, local] HRESULT localInterface([out][retval] void **localInterface);
 
-  [propget, id(DISPID_NODE_LANGUAGE)] HRESULT language([out, retval] BSTR *language);
+  [propget] HRESULT language([out, retval] BSTR *language);
 }
 
 
+[
+    uuid(a6245497-9c0b-4449-85a5-bd6ad07df8ea), 
+    helpstring("ISimpleDOM Type Library")
+] 
+library ISimpleDOM 
+{
+  interface ISimpleDOMNode;
+  interface ISimpleDOMText;
+  interface ISimpleDOMDocument;
+};
+
--- a/accessible/public/msaa/Makefile.in
+++ b/accessible/public/msaa/Makefile.in
@@ -93,17 +93,17 @@ OS_LIBS = \
 	$(NULL)
 
 $(MIDL_GENERATED_FILES): done_gen
 
 done_gen: ISimpleDOMNode.idl \
           ISimpleDOMDocument.idl \
           ISimpleDOMText.idl
 
-	$(MIDL) $(MIDL_FLAGS) -Oicf $(srcdir)/ISimpleDOMNode.idl
+	$(MIDL) $(MIDL_FLAGS) -I $(srcdir) -Oicf $(srcdir)/ISimpleDOMNode.idl
 	$(MIDL) $(MIDL_FLAGS) -Oicf $(srcdir)/ISimpleDOMDocument.idl
 	$(MIDL) $(MIDL_FLAGS) -Oicf $(srcdir)/ISimpleDOMText.idl
 	touch $@
 
 EXPORTS = \
 	ISimpleDOMNode.h \
 	ISimpleDOMNode_i.c \
 	ISimpleDOMDocument.h \
--- 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/base/nsTextUtils.cpp
+++ b/accessible/src/base/nsTextUtils.cpp
@@ -84,17 +84,18 @@ static nsCSSTextAttrMapItem gCSSTextAttr
   { "color",             kAnyValue,       kCopyName,                  kCopyValue },
   { "font-family",       kAnyValue,       kCopyName,                  kCopyValue },
   { "font-size",         kAnyValue,       kCopyName,                  kCopyValue },
   { "font-style",        kAnyValue,       kCopyName,                  kCopyValue },
   { "font-weight",       kAnyValue,       kCopyName,                  kCopyValue },
   { "text-decoration",   "line-through",  "text-line-through-style",  "solid" },
   { "text-decoration",   "underline",     "text-underline-style",     "solid" },
   { "text-align",        kAnyValue,       kCopyName,                  kCopyValue },
-  { "text-indent",       kAnyValue,       kCopyName,                  kCopyValue }
+  { "text-indent",       kAnyValue,       kCopyName,                  kCopyValue },
+  { "vertical-align",    kAnyValue,       "text-position",            kCopyValue }
 };
 
 nsCSSTextAttr::nsCSSTextAttr(PRBool aIncludeDefAttrValue, nsIDOMElement *aElm,
                              nsIDOMElement *aRootElm) :
   mIndex(-1), mIncludeDefAttrValue(aIncludeDefAttrValue)
 {
   nsAccessNode::GetComputedStyleDeclaration(EmptyString(), aElm,
                                             getter_AddRefs(mStyleDecl));
--- 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/accessible/tests/mochitest/test_textattrs.html
+++ b/accessible/tests/mochitest/test_textattrs.html
@@ -62,60 +62,63 @@
       } catch (e) {
       }
 
       if (!attrs) {
         ok(false, "Can't get text attributes for " + aID);
         return;
       }
 
+      var errorMsg = " for " + aID + "at offset " + aOffset;
       is(startOffset.value, aStartOffset,
-         "Wrong start offset for " + aID);
+         "Wrong start offset" + errorMsg);
       is(endOffset.value, aEndOffset,
-          "Wrong end offset for " + aID);
+          "Wrong end offset" + errorMsg);
 
-      compareTextAttrs(aID, attrs, aAttrs);
+      compareTextAttrs(errorMsg, attrs, aAttrs);
 
       var defAttrs = null;
       try{
         defAttrs = accessible.defaultTextAttributes;
       } catch (e) {
       }
 
       if (!defAttrs) {
         ok(false, "Can't get default attributes for " + aID);
         return;
       }
 
-      compareTextAttrs(aID, defAttrs, aDefAttrs);
+      compareTextAttrs(errorMsg, defAttrs, aDefAttrs);
     }
 
-    function compareTextAttrs(aID, aAttrs, aExpectedAttrs)
+    function compareTextAttrs(aErrorMsg, aAttrs, aExpectedAttrs)
     {
       var enumerate = aAttrs.enumerate();
       while (enumerate.hasMoreElements()) {
         var prop = enumerate.getNext().
           QueryInterface(Components.interfaces.nsIPropertyElement);
 
         if (!(prop.key in aExpectedAttrs))
-          ok(false, "Unexpected attribute '" + prop.key + "' for " + aID);
+          ok(false,
+             "Unexpected attribute '" + prop.key + "'" + aErrorMsg);
         else
           is(prop.value, aExpectedAttrs[prop.key],
-             "Attribute '" + prop.key + "' has wrong value for " + aID);
+             "Attribute '" + prop.key + "' has wrong value" + aErrorMsg);
       }
 
       for (var name in aExpectedAttrs) {
         var value = "";
         try {
           value = aAttrs.getStringProperty(name);
         } catch(e) {
         }
 
         if (!value)
-          ok(false, "There is no expected attribute '" + name + "' for " + aID);
+          ok(false,
+             "There is no expected attribute '" + name + "'" + aErrorMsg);
       }
     }
 
     var gObserverService = null;
     var gA11yEventObserver = null;
 
     function testSpellTextAttrs()
     {
@@ -137,17 +140,17 @@
 
       // Add accessibility event listeners
       var gObserverService = Components.classes["@mozilla.org/observer-service;1"].
                             getService(nsIObserverService);
 
       gObserverService.addObserver(gA11yEventObserver, "accessible-event",
                                   false);
 
-      ID = "area7";
+      ID = "area8";
   
       var node = document.getElementById(ID);
       node.focus();
 
       var editor = node.QueryInterface(nsIDOMNSEditableElement).editor;
       var spellchecker = editor.getInlineSpellChecker(true);
       spellchecker.enableRealTimeSpell = true;
 
@@ -156,17 +159,18 @@
           var defAttrs = {
             "font-style": "normal",
             "text-align": "start",
             "font-size": "11px",
             "background-color": "rgb(255, 255, 255)",
             "font-weight": "400",
             "text-indent": "0px",
             "color": "rgb(0, 0, 0)",
-            "font-family": "Lucida Grande"
+            "font-family": "Lucida Grande",
+            "text-position": "baseline"
           };
 
           var attrs = { "background-color": "transparent" };
           var misspelledAttrs = {
             "background-color": "transparent",
             "invalid": "spelling"
           };
 
@@ -196,17 +200,18 @@
       var defAttrs = {
         "font-style": "normal",
         "text-align": "start",
         "font-size": "16px",
         "background-color": "transparent",
         "font-weight": "400",
         "text-indent": "0px",
         "color": "rgb(0, 0, 0)",
-        "font-family": "serif"
+        "font-family": "serif",
+        "text-position": "baseline"
       };
 
       var attrs = {};
       testTextAttrs(ID, 0, attrs, 0, 7, defAttrs);
 
       attrs = {"font-weight": "401"};
       testTextAttrs(ID, 7, attrs, 7, 11, defAttrs);
 
@@ -219,17 +224,18 @@
       defAttrs = {
         "font-style": "normal",
         "text-align": "start",
         "font-size": "16px",
         "background-color": "transparent",
         "font-weight": "400",
         "text-indent": "0px",
         "color": "rgb(0, 0, 0)",
-        "font-family": "serif"
+        "font-family": "serif",
+        "text-position": "baseline"
       };
 
       attrs = {};
       testTextAttrs(ID, 0, attrs, 0, 7, defAttrs);
 
       attrs = {"font-weight": "401"};
       testTextAttrs(ID, 7, attrs, 7, 12, defAttrs);
 
@@ -248,17 +254,18 @@
       defAttrs = {
         "font-style": "normal",
         "text-align": "start",
         "font-size": "16px",
         "background-color": "transparent",
         "font-weight": "400",
         "text-indent": "0px",
         "color": "rgb(0, 0, 0)",
-        "font-family": "serif"
+        "font-family": "serif",
+        "text-position": "baseline"
       };
 
       attrs = {"color": "rgb(0, 128, 0)"};
       testTextAttrs(ID, 0, attrs, 0, 6, defAttrs);
 
       attrs = {"color": "rgb(255, 0, 0)"};
       testTextAttrs(ID, 6, attrs, 6, 26, defAttrs);
 
@@ -271,17 +278,18 @@
       defAttrs = {
         "font-style": "normal",
         "text-align": "start",
         "font-size": "16px",
         "background-color": "transparent",
         "font-weight": "400",
         "text-indent": "0px",
         "color": "rgb(0, 0, 0)",
-        "font-family": "serif"
+        "font-family": "serif",
+        "text-position": "baseline"
       };
 
       attrs = {"color": "rgb(0, 128, 0)"};
       testTextAttrs(ID, 0, attrs, 0, 16, defAttrs);
 
       attrs = {"color": "rgb(255, 0, 0)"};
       testTextAttrs(ID, 16, attrs, 16, 33, defAttrs);
 
@@ -294,43 +302,84 @@
       defAttrs = {
         "font-style": "normal",
         "text-align": "start",
         "font-size": "16px",
         "background-color": "transparent",
         "font-weight": "400",
         "text-indent": "0px",
         "color": "rgb(0, 0, 0)",
-        "font-family": "serif"
+        "font-family": "serif",
+        "text-position": "baseline"
       };
 
       attrs = {"color": "rgb(0, 128, 0)"};
       testTextAttrs(ID, 0, attrs, 0, 5, defAttrs);
 
       attrs = {};
       testTextAttrs(ID, 7, attrs, 5, 8, defAttrs);
 
       attrs = {"color": "rgb(255, 0, 0)"};
       testTextAttrs(ID, 9, attrs, 8, 11, defAttrs);
 
       attrs = {};
       testTextAttrs(ID, 11, attrs, 11, 18, defAttrs);
 
       //////////////////////////////////////////////////////////////////////////
-      // area6
+      // area6 (CSS vertical-align property, bug 445938)
       ID = "area6";
       defAttrs = {
         "font-style": "normal",
         "text-align": "start",
         "font-size": "16px",
         "background-color": "transparent",
         "font-weight": "400",
         "text-indent": "0px",
         "color": "rgb(0, 0, 0)",
-        "font-family": "serif"
+        "font-family": "serif",
+        "text-position": "baseline"
+      };
+
+      attrs = {};
+      testTextAttrs(ID, 0, attrs, 0, 5, defAttrs);
+
+      attrs = {"text-position": "super", "font-size": "13px" };
+      testTextAttrs(ID, 5, attrs, 5, 13, defAttrs);
+
+      attrs = {};
+      testTextAttrs(ID, 13, attrs, 13, 27, defAttrs);
+
+      attrs = {"text-position": "super" };
+      testTextAttrs(ID, 27, attrs, 27, 35, defAttrs);
+
+      attrs = {};
+      testTextAttrs(ID, 35, attrs, 35, 39, defAttrs);
+
+      attrs = {"text-position": "sub", "font-size": "13px" };
+      testTextAttrs(ID, 39, attrs, 39, 50, defAttrs);
+
+      attrs = {};
+      testTextAttrs(ID, 50, attrs, 50, 55, defAttrs);
+
+      attrs = {"text-position": "sub" };
+      testTextAttrs(ID, 55, attrs, 55, 64, defAttrs);
+
+      //////////////////////////////////////////////////////////////////////////
+      // area7
+      ID = "area7";
+      defAttrs = {
+        "font-style": "normal",
+        "text-align": "start",
+        "font-size": "16px",
+        "background-color": "transparent",
+        "font-weight": "400",
+        "text-indent": "0px",
+        "color": "rgb(0, 0, 0)",
+        "font-family": "serif",
+        "text-position": "baseline"
       };
 
       attrs = {"language": "ru"};
       testTextAttrs(ID, 0, attrs, 0, 12, defAttrs);
 
       attrs = {"language": "en"};
       testTextAttrs(ID, 12, attrs, 12, 13, defAttrs);
 
@@ -398,23 +447,30 @@
       Green again
     </span>
   </p>
   <p id="area5">
     <span style="color: green">Green</span>
     <img src="moz.png" alt="image"/>
     <span style="color: red">Red</span>Normal
   </p>
-  <p lang="en" id="area6">
+  <p id="area6">
+    This <sup>sentence</sup> has the word 
+    <span style="vertical-align:super;">sentence</span> in 
+    <sub>superscript</sub> and 
+    <span style="vertical-align:sub;">subscript</span>
+  </p>
+
+  <p lang="en" id="area7">
     <span lang="ru">Привет</span>
     <span style="background-color: blue">Blue BG color</span>
     <span lang="de">Ich bin/Du bist</span>
     <span lang="en">
       Normal
       <span style="color: magenta">Magenta<b>Bold</b>Magenta</span>
     </span>
   </p>
 
-  <input id="area7" value="valid text inalid tixt"/>
+  <input id="area8" value="valid text inalid tixt"/>
 
   <p id="output"/>
 </body>
 </html>
--- a/browser/app/module.ver
+++ b/browser/app/module.ver
@@ -1,8 +1,8 @@
 WIN32_MODULE_COMPANYNAME=Mozilla Corporation
 WIN32_MODULE_COPYRIGHT=Firefox and Mozilla Developers, according to the MPL 1.1/GPL 2.0/LGPL 2.1 licenses, as applicable.
 WIN32_MODULE_PRODUCTVERSION=3,1,0,0
-WIN32_MODULE_PRODUCTVERSION_STRING=3.1a1pre
+WIN32_MODULE_PRODUCTVERSION_STRING=3.1a2pre
 WIN32_MODULE_TRADEMARKS=Firefox is a Trademark of The Mozilla Foundation.
 WIN32_MODULE_DESCRIPTION=Firefox
 WIN32_MODULE_PRODUCTNAME=Firefox
 WIN32_MODULE_NAME=Firefox
--- 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/browser/config/version.txt
+++ b/browser/config/version.txt
@@ -1,1 +1,1 @@
-3.1a1pre
+3.1a2pre
--- 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/doxygen.cfg.in
+++ b/config/doxygen.cfg.in
@@ -1,24 +1,32 @@
-# Doxyfile 1.2.8.1
+# Doxyfile 1.5.5
 
 # This file describes the settings to be used by the documentation system
 # doxygen (www.doxygen.org) for a project
 #
 # All text after a hash (#) is considered a comment and will be ignored
 # The format is:
 #       TAG = value [value, ...]
 # For lists items can also be appended using:
 #       TAG += value [value, ...]
 # Values that contain spaces should be placed between quotes (" ")
 
 #---------------------------------------------------------------------------
-# General configuration options
+# Project related configuration options
 #---------------------------------------------------------------------------
 
+# This tag specifies the encoding used for all characters in the config file 
+# that follow. The default is UTF-8 which is also the encoding used for all 
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the 
+# iconv built into libc) for the transcoding. See 
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
 # by quotes) that should identify the project.
 
 PROJECT_NAME           = "Mozilla"
 
 # The PROJECT_NUMBER tag can be used to enter a project or revision number. 
 # This could be handy for archiving the generated documentation or 
 # if some version control system is used.
@@ -27,194 +35,367 @@ PROJECT_NUMBER         =
 
 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
 # base path where the generated documentation will be put. 
 # If a relative path is entered, it will be relative to the location 
 # where doxygen was started. If left blank the current directory will be used.
 
 OUTPUT_DIRECTORY       = @MOZ_DOC_OUTPUT_DIR@
 
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of 
+# source files, where putting all generated files in the same directory would 
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
 # The OUTPUT_LANGUAGE tag is used to specify the language in which all 
 # documentation generated by doxygen is written. Doxygen will use this 
 # information to generate all constant output in the proper language. 
 # The default language is English, other supported languages are: 
-# Brazilian, Chinese, Croatian, Czech, Danish, Dutch, Finnish, French, 
-# German, Hungarian, Italian, Japanese, Korean, Norwegian, Polish, 
-# Portuguese, Romanian, Russian, Slovak, Slovene, Spanish and Swedish.
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
+# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, 
+# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), 
+# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, 
+# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, 
+# and Ukrainian.
 
 OUTPUT_LANGUAGE        = English
 
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
-# documentation are documented, even if no documentation was available. 
-# Private class members and static file members will be hidden unless 
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
-
-EXTRACT_ALL            = NO
-
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
-# will be included in the documentation.
-
-EXTRACT_PRIVATE        = NO
-
-# If the EXTRACT_STATIC tag is set to YES all static members of a file 
-# will be included in the documentation.
-
-EXTRACT_STATIC         = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
-# undocumented members of documented classes, files or namespaces. 
-# If set to NO (the default) these members will be included in the 
-# various overviews, but no documentation section is generated. 
-# This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_MEMBERS     = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
-# undocumented classes that are normally visible in the class hierarchy. 
-# If set to NO (the default) these class will be included in the various 
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_CLASSES     = NO
-
 # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
 # include brief member descriptions after the members that are listed in 
 # the file and class documentation (similar to JavaDoc). 
 # Set to NO to disable this.
 
 BRIEF_MEMBER_DESC      = YES
 
 # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
 # the brief description of a member or function before the detailed description. 
 # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
 # brief descriptions will be completely suppressed.
 
 REPEAT_BRIEF           = YES
 
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is 
+# used as the annotated text. Otherwise, the brief description is used as-is. 
+# If left blank, the following values are used ("$name" is automatically 
+# replaced with the name of the entity): "The $name class" "The $name widget" 
+# "The $name file" "is" "provides" "specifies" "contains" 
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = 
+
 # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
 # Doxygen will generate a detailed section even if there is only a brief 
 # description.
 
 ALWAYS_DETAILED_SEC    = NO
 
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
+# inherited members of a class in the documentation of that class as if those 
+# members were ordinary class members. Constructors, destructors and assignment 
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
 # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
 # path before files name in the file list and in the header files. If set 
 # to NO the shortest path that makes the file name unique will be used.
 
 FULL_PATH_NAMES        = NO
 
 # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
-# can be used to strip a user defined part of the path. Stripping is 
+# can be used to strip a user-defined part of the path. Stripping is 
 # only done if one of the specified strings matches the left-hand part of 
-# the path. It is allowed to use relative paths in the argument list.
+# the path. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
+# path to strip.
 
 STRIP_FROM_PATH        = 
 
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like regular Qt-style comments 
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will 
+# interpret the first line (until the first dot) of a Qt-style 
+# comment as the brief description. If set to NO, the comments 
+# will behave just like regular Qt-style comments (thus requiring 
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member 
+# documentation.
+
+DETAILS_AT_TOP         = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
+# a new page for each member. If set to NO, the documentation of a member will 
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = "status=\par Status:\n"
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
+# sources only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Java. For instance, namespaces will be presented as packages, qualified 
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL 
+# sources. Doxygen will then generate output that is tailored for 
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 
+# to include (a tag file for) the STL sources as input, then you should 
+# set this tag to YES in order to let doxygen match functions declarations and 
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
+# func(std::string) {}). This also make the inheritance and collaboration 
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 
+# Doxygen will parse them like normal C++ but will assume all classes use public 
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = YES
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum 
+# is documented as struct, union, or enum with the name of the typedef. So 
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct 
+# with name TypeT. When disabled the typedef will appear as a member of a file, 
+# namespace, or class. And the struct will be named TypeS. This can typically 
+# be useful for C code in case the coding convention dictates that all compound 
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be 
+# extracted and appear in the documentation as a namespace called 
+# 'anonymous_namespace{file}', where file will be replaced with the base 
+# name of the file that contains the anonymous namespace. By default 
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
 # The INTERNAL_DOCS tag determines if documentation 
 # that is typed after a \internal command is included. If the tag is set 
 # to NO (the default) then the documentation will be excluded. 
 # Set it to YES to include the internal documentation.
 
 INTERNAL_DOCS          = NO
 
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
-# generate a class diagram (in Html and LaTeX) for classes with base or 
-# super classes. Setting the tag to NO turns the diagrams off.
-
-CLASS_DIAGRAMS         = YES
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
-# be generated. Documented entities will be cross-referenced with these sources.
-
-SOURCE_BROWSER         = NO
-
-# Setting the INLINE_SOURCES tag to YES will include the body 
-# of functions and classes directly in the documentation.
-
-INLINE_SOURCES         = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
-# doxygen to hide any special comment blocks from generated source code 
-# fragments. Normal C and C++ comments will always remain visible.
-
-STRIP_CODE_COMMENTS    = YES
-
 # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
-# file names in lower case letters. If set to YES upper case letters are also 
+# file names in lower-case letters. If set to YES upper-case letters are also 
 # allowed. This is useful if you have classes or files whose names only differ 
 # in case and if your file system supports case sensitive file names. Windows 
-# users are adviced to set this option to NO.
+# and Mac users are advised to set this option to NO.
 
 CASE_SENSE_NAMES       = YES
 
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
-# (but less readable) file names. This can be useful is your file systems 
-# doesn't support long names like on DOS, Mac, or CD-ROM.
-
-SHORT_NAMES            = NO
-
 # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
 # will show members with their full class and namespace scopes in the 
 # documentation. If set to YES the scope will be hidden.
 
 HIDE_SCOPE_NAMES       = NO
 
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
-# will generate a verbatim copy of the header file for each class for 
-# which an include is specified. Set to NO to disable this.
-
-VERBATIM_HEADERS       = YES
-
 # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
-# will put list of the files that are included by a file in the documentation 
+# will put a list of the files that are included by a file in the documentation 
 # of that file.
 
 SHOW_INCLUDE_FILES     = YES
 
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
-# will interpret the first line (until the first dot) of a JavaDoc-style 
-# comment as the brief description. If set to NO, the JavaDoc 
-# comments  will behave just like the Qt-style comments (thus requiring an 
-# explict @brief command for a brief description.
-
-JAVADOC_AUTOBRIEF      = YES
-
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
-# member inherits the documentation from any documented member that it 
-# reimplements.
-
-INHERIT_DOCS           = YES
-
 # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
 # is inserted in the documentation for inline members.
 
 INLINE_INFO            = YES
 
 # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
 # will sort the (detailed) documentation of file and class members 
 # alphabetically by member name. If set to NO the members will appear in 
 # declaration order.
 
 SORT_MEMBER_DOCS       = YES
 
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
-# tag is set to YES, then doxygen will reuse the documentation of the first 
-# member in the group (if any) for the other members of the group. By default 
-# all members of a group must be documented explicitly.
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
 
-DISTRIBUTE_GROUP_DOC   = NO
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the 
+# hierarchy of group names into alphabetical order. If set to NO (the default) 
+# the group names will appear in their defined order.
 
-# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
-# Doxygen uses this value to replace tabs by spaces in code fragments.
-
-TAB_SIZE               = 4
+SORT_GROUP_NAMES       = NO
 
-# The ENABLED_SECTIONS tag can be used to enable conditional 
-# documentation sections, marked by \if sectionname ... \endif.
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the 
+# alphabetical list.
 
-ENABLED_SECTIONS       = 
+SORT_BY_SCOPE_NAME     = NO
 
 # The GENERATE_TODOLIST tag can be used to enable (YES) or 
 # disable (NO) the todo list. This list is created by putting \todo 
 # commands in the documentation.
 
 GENERATE_TODOLIST      = YES
 
 # The GENERATE_TESTLIST tag can be used to enable (YES) or 
@@ -224,48 +405,59 @@ GENERATE_TODOLIST      = YES
 GENERATE_TESTLIST      = YES
 
 # The GENERATE_BUGLIST tag can be used to enable (YES) or 
 # disable (NO) the bug list. This list is created by putting \bug 
 # commands in the documentation.
 
 GENERATE_BUGLIST       = NO
 
-# This tag can be used to specify a number of aliases that acts 
-# as commands in the documentation. An alias has the form "name=value". 
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
-# put the command \sideeffect (or @sideeffect) in the documentation, which 
-# will result in a user defined paragraph with heading "Side Effects:". 
-# You can put \n's in the value part of an alias to insert newlines.
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
 
-ALIASES                = "status=\par Status:\n"
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
 
 # The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
-# the initial value of a variable or define consist of for it to appear in 
+# the initial value of a variable or define consists of for it to appear in 
 # the documentation. If the initializer consists of more lines than specified 
 # here it will be hidden. Use a value of 0 to hide initializers completely. 
 # The appearance of the initializer of individual variables and defines in the 
 # documentation can be controlled using \showinitializer or \hideinitializer 
 # command in the documentation regardless of this setting.
 
 MAX_INITIALIZER_LINES  = 30
 
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources 
-# only. Doxygen will then generate output that is more tailored for C. 
-# For instance some of the names that are used will be different. The list 
-# of all members will be omitted, etc.
-
-OPTIMIZE_OUTPUT_FOR_C  = NO
-
 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
 # at the bottom of the documentation of classes and structs. If set to YES the 
 # list will mention the files that were used to generate the documentation.
 
 SHOW_USED_FILES        = YES
 
+# If the sources in your project are distributed over multiple directories 
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
+# doxygen should invoke to get the current version for each file (typically from 
+# the version control system). Doxygen will invoke the program by executing (via 
+# popen()) the command <command> <input-file>, where <command> is the value of 
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
+# provided by doxygen. Whatever the program writes to standard output 
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    = 
+
 #---------------------------------------------------------------------------
 # configuration options related to warning and progress messages
 #---------------------------------------------------------------------------
 
 # The QUIET tag can be used to turn on/off the messages that are generated 
 # by doxygen. Possible values are YES and NO. If left blank NO is used.
 
 QUIET                  = NO
@@ -275,22 +467,39 @@ QUIET                  = NO
 # NO is used.
 
 WARNINGS               = YES
 
 # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
 # for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
 # automatically be disabled.
 
-WARN_IF_UNDOCUMENTED   = YES
+WARN_IF_UNDOCUMENTED   = NO
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for 
+# functions that are documented, but have no documentation for their parameters 
+# or return value. If set to NO (the default) doxygen will only warn about 
+# wrong or incomplete parameter documentation, but not about the absence of 
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
 
 # The WARN_FORMAT tag determines the format of the warning messages that 
 # doxygen can produce. The string should contain the $file, $line, and $text 
 # tags, which will be replaced by the file and line number from which the 
-# warning originated and the warning text.
+# warning originated and the warning text. Optionally the format may contain 
+# $version, which will be replaced by the version of the file (if it could 
+# be obtained via FILE_VERSION_FILTER)
 
 WARN_FORMAT            = 
 
 # The WARN_LOGFILE tag can be used to specify a file to which warning 
 # and error messages should be written. If left blank the output is written 
 # to stderr.
 
 WARN_LOGFILE           = 
@@ -301,76 +510,176 @@ WARN_LOGFILE           =
 
 # The INPUT tag can be used to specify the files and/or directories that contain 
 # documented source files. You may enter file names like "myfile.cpp" or 
 # directories like "/usr/src/myproject". Separate the files or directories 
 # with spaces.
 
 INPUT                  = @MOZ_DOC_INPUT_DIRS@
 
+# This tag can be used to specify the character encoding of the source files 
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 
+# also the default input encoding. Doxygen uses libiconv (or the iconv built 
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for 
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
 # If the value of the INPUT tag contains directories, you can use the 
 # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
 # and *.h) to filter out the source-files in the directories. If left 
-# blank all files are included.
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
 
-FILE_PATTERNS          = *.idl *.cpp *.h
+FILE_PATTERNS          = *.idl \
+                         *.cpp \
+                         *.h
 
 # The RECURSIVE tag can be used to turn specify whether or not subdirectories 
 # should be searched for input files as well. Possible values are YES and NO. 
 # If left blank NO is used.
 
 RECURSIVE              = YES
 
 # The EXCLUDE tag can be used to specify files and/or directories that should 
 # excluded from the INPUT source files. This way you can easily exclude a 
 # subdirectory from a directory tree whose root is specified with the INPUT tag.
 
 EXCLUDE                = 
 
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
+# directories that are symbolic links (a Unix filesystem feature) are excluded 
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
 # If the value of the INPUT tag contains directories, you can use the 
 # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
-# certain files from those directories.
+# certain files from those directories. Note that the wildcards are matched 
+# against the file with absolute path, so to exclude all test directories 
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = nsI*.h mozI*.h imgI*.h
 
-EXCLUDE_PATTERNS       = nsI*.h
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
+# (namespaces, classes, functions, etc.) that should be excluded from the 
+# output. The symbol name can be a fully qualified name, a word, or if the 
+# wildcard * is used, a substring. Examples: ANamespace, AClass, 
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        = nsCOMPtr_base
 
 # The EXAMPLE_PATH tag can be used to specify one or more files or 
 # directories that contain example code fragments that are included (see 
 # the \include command).
 
 EXAMPLE_PATH           = 
 
 # If the value of the EXAMPLE_PATH tag contains directories, you can use the 
 # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
 # and *.h) to filter out the source-files in the directories. If left 
 # blank all files are included.
 
 EXAMPLE_PATTERNS       = 
 
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
 # The IMAGE_PATH tag can be used to specify one or more files or 
 # directories that contain image that are included in the documentation (see 
 # the \image command).
 
 IMAGE_PATH             = 
 
 # The INPUT_FILTER tag can be used to specify a program that doxygen should 
 # invoke to filter for each input file. Doxygen will invoke the filter program 
 # by executing (via popen()) the command <filter> <input-file>, where <filter> 
 # is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
 # input file. Doxygen will then use the output that the filter program writes 
-# to standard output.
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
+# ignored.
 
 INPUT_FILTER           = 
 
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis.  Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match.  The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
+# is applied to all files.
+
+FILTER_PATTERNS        = 
+
 # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
 # INPUT_FILTER) will be used to filter the input files when producing source 
-# files to browse.
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
 
 FILTER_SOURCE_FILES    = NO
 
 #---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES (the default) 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.  Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = NO
+
+# If the USE_HTAGS tag is set to YES then the references to source code 
+# will point to the HTML generated by the htags(1) tool instead of doxygen 
+# built-in source browser. The htags tool is part of GNU's global source 
+# tagging system (see http://www.gnu.org/software/global/global.html). You 
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = NO
+
+#---------------------------------------------------------------------------
 # configuration options related to the alphabetical class index
 #---------------------------------------------------------------------------
 
 # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
 # of all compounds will be generated. Enable this if the project 
 # contains a lot of classes, structs, unions or interfaces.
 
 ALPHABETICAL_INDEX     = YES
@@ -381,79 +690,136 @@ ALPHABETICAL_INDEX     = YES
 
 COLS_IN_ALPHA_INDEX    = 5
 
 # In case all classes in a project start with a common prefix, all 
 # classes will be put under the same header in the alphabetical index. 
 # The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
 # should be ignored while generating the index headers.
 
-IGNORE_PREFIX          = ns moz img in
+IGNORE_PREFIX          = nsI ns \
+                         mozI moz \
+                         imgI img
 
 #---------------------------------------------------------------------------
 # configuration options related to the HTML output
 #---------------------------------------------------------------------------
 
 # If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
 # generate HTML output.
 
 GENERATE_HTML          = YES
 
 # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
 # If a relative path is entered the value of OUTPUT_DIRECTORY will be 
 # put in front of it. If left blank `html' will be used as the default path.
 
 HTML_OUTPUT            = 
 
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
 # The HTML_HEADER tag can be used to specify a personal HTML header for 
 # each generated HTML page. If it is left blank doxygen will generate a 
 # standard header.
 
 HTML_HEADER            = 
 
 # The HTML_FOOTER tag can be used to specify a personal HTML footer for 
 # each generated HTML page. If it is left blank doxygen will generate a 
 # standard footer.
 
 HTML_FOOTER            = 
 
-# The HTML_STYLESHEET tag can be used to specify a user defined cascading 
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
 # style sheet that is used by each HTML page. It can be used to 
 # fine-tune the look of the HTML output. If the tag is left blank doxygen 
-# will generate a default style sheet
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# stylesheet in the HTML output directory as well, or it will be erased!
 
 HTML_STYLESHEET        = 
 
 # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
 # files or namespaces will be aligned in HTML using tables. If set to 
 # NO a bullet list will be used.
 
 HTML_ALIGN_MEMBERS     = YES
 
 # If the GENERATE_HTMLHELP tag is set to YES, additional index files 
 # will be generated that can be used as input for tools like the 
-# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) 
 # of the generated HTML documentation.
 
 GENERATE_HTMLHELP      = NO
 
+# If the GENERATE_DOCSET tag is set to YES, additional index files 
+# will be generated that can be used as input for Apple's Xcode 3 
+# integrated development environment, introduced with OSX 10.5 (Leopard). 
+# To create a documentation set, doxygen will generate a Makefile in the 
+# HTML output directory. Running make will produce the docset in that 
+# directory and running "make install" will install the docset in 
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find 
+# it at startup.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the 
+# feed. A documentation feed provides an umbrella under which multiple 
+# documentation sets from a single provider (such as a company or product suite) 
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that 
+# should uniquely identify the documentation set bundle. This should be a 
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen 
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 
+# documentation will contain sections that can be hidden and shown after the 
+# page has loaded. For this to work a browser that supports 
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output directory.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
 # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
 # controls if a separate .chi index file is generated (YES) or that 
 # it should be included in the master .chm file (NO).
 
 GENERATE_CHI           = NO
 
 # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
 # controls whether a binary table of contents is generated (YES) or a 
 # normal table of contents (NO) in the .chm file.
 
 BINARY_TOC             = NO
 
 # The TOC_EXPAND flag can be set to YES to add extra items for group members 
-# to the contents of the Html help documentation and to the tree view.
+# to the contents of the HTML help documentation and to the tree view.
 
 TOC_EXPAND             = NO
 
 # The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
 # top of each HTML page. The value NO (the default) enables the index and 
 # the value YES disables it.
 
 DISABLE_INDEX          = NO
@@ -461,18 +827,19 @@ DISABLE_INDEX          = NO
 # This tag can be used to set the number of enum values (range [1..20]) 
 # that doxygen will group on one line in the generated HTML documentation.
 
 ENUM_VALUES_PER_LINE   = 4
 
 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
 # generated containing a tree-like index structure (just like the one that 
 # is generated for HTML Help). For this to work a browser that supports 
-# JavaScript and frames is required (for instance Netscape 4.0+ 
-# or Internet explorer 4.0+).
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature.
 
 GENERATE_TREEVIEW      = NO
 
 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
 # used to set the initial width (in pixels) of the frame in which the tree 
 # is shown.
 
 TREEVIEW_WIDTH         = 250
@@ -487,16 +854,27 @@ TREEVIEW_WIDTH         = 250
 GENERATE_LATEX         = NO
 
 # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
 # If a relative path is entered the value of OUTPUT_DIRECTORY will be 
 # put in front of it. If left blank `latex' will be used as the default path.
 
 LATEX_OUTPUT           = 
 
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
 # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
 # LaTeX documents. This may be useful for small projects and may help to 
 # save some trees in general.
 
 COMPACT_LATEX          = NO
 
 # The PAPER_TYPE tag can be used to set the paper type that is used 
 # by the printer. Possible values are: a4, a4wide, letter, legal and 
@@ -531,22 +909,28 @@ USE_PDFLATEX           = NO
 
 # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
 # command to the generated LaTeX files. This will instruct LaTeX to keep 
 # running if errors occur, instead of asking the user for help. 
 # This option is also used when generating formulas in HTML.
 
 LATEX_BATCHMODE        = NO
 
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
 #---------------------------------------------------------------------------
 # configuration options related to the RTF output
 #---------------------------------------------------------------------------
 
 # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
-# The RTF output is optimised for Word 97 and may not look very pretty with 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
 # other RTF readers or editors.
 
 GENERATE_RTF           = NO
 
 # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
 # If a relative path is entered the value of OUTPUT_DIRECTORY will be 
 # put in front of it. If left blank `rtf' will be used as the default path.
 
@@ -563,17 +947,17 @@ COMPACT_RTF            = NO
 # contain links (just like the HTML output) instead of page references. 
 # This makes the output suitable for online browsing using WORD or other 
 # programs which support those fields. 
 # Note: wordpad (write) and others do not support links.
 
 RTF_HYPERLINKS         = NO
 
 # Load stylesheet definitions from file. Syntax is similar to doxygen's 
-# config file, i.e. a series of assigments. You only have to provide 
+# config file, i.e. a series of assignments. You only have to provide 
 # replacements, missing definitions are set to their default value.
 
 RTF_STYLESHEET_FILE    = 
 
 # Set optional variables used in the generation of an rtf document. 
 # Syntax is similar to doxygen's config file.
 
 RTF_EXTENSIONS_FILE    = 
@@ -593,44 +977,124 @@ GENERATE_MAN           = NO
 
 MAN_OUTPUT             = 
 
 # The MAN_EXTENSION tag determines the extension that is added to 
 # the generated man pages (default is the subroutine's section .3)
 
 MAN_EXTENSION          = 
 
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
-# then it will generate one additional man file for each entity
-# documented in the real man page(s). These additional files
-# only source the real man page, but without them the man command
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
 # would be unable to find the correct page. The default is NO.
 
 MAN_LINKS              = NO
 
 #---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
 # Configuration options related to the preprocessor   
 #---------------------------------------------------------------------------
 
 # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
 # evaluate all C-preprocessor directives found in the sources and include 
 # files.
 
-ENABLE_PREPROCESSING   = NO
+ENABLE_PREPROCESSING   = YES
 
 # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
 # names in the source code. If set to NO (the default) only conditional 
 # compilation will be performed. Macro expansion can be done in a controlled 
 # way by setting EXPAND_ONLY_PREDEF to YES.
 
-MACRO_EXPANSION        = NO
+MACRO_EXPANSION        = YES
 
 # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
 # then the macro expansion is limited to the macros specified with the 
-# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+# PREDEFINED and EXPAND_AS_DEFINED tags.
 
 EXPAND_ONLY_PREDEF     = NO
 
 # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
 # in the INCLUDE_PATH (see below) will be search if a #include is found.
 
 SEARCH_INCLUDES        = YES
 
@@ -640,169 +1104,257 @@ SEARCH_INCLUDES        = YES
 
 INCLUDE_PATH           = @MOZ_DOC_INCLUDE_DIRS@
 
 # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
 # patterns (like *.h and *.hpp) to filter out the header-files in the 
 # directories. If left blank, the patterns specified with FILE_PATTERNS will 
 # be used.
 
-INCLUDE_FILE_PATTERNS  = 
+INCLUDE_FILE_PATTERNS  = *.h 
 
 # The PREDEFINED tag can be used to specify one or more macro names that 
 # are defined before the preprocessor is started (similar to the -D option of 
 # gcc). The argument of the tag is a list of macros of the form: name 
 # or name=definition (no spaces). If the definition and the = are 
-# omitted =1 is assumed.
+# omitted =1 is assumed. To prevent a macro definition from being 
+# undefined via #undef or recursively expanded use the := operator 
+# instead of the = operator.
 
 PREDEFINED             = 
 
-# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then 
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
 # this tag can be used to specify a list of macro names that should be expanded. 
 # The macro definition that is found in the sources will be used. 
 # Use the PREDEFINED tag if you want to use a different macro definition.
 
 EXPAND_AS_DEFINED      = 
 
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse 
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
 #---------------------------------------------------------------------------
-# Configuration::addtions related to external references   
+# Configuration::additions related to external references   
 #---------------------------------------------------------------------------
 
-# The TAGFILES tag can be used to specify one or more tagfiles.
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
 
 TAGFILES               = 
 
 # When a file name is specified after GENERATE_TAGFILE, doxygen will create 
 # a tag file that is based on the input files it reads.
 
 GENERATE_TAGFILE       = 
 
 # If the ALLEXTERNALS tag is set to YES all external classes will be listed 
 # in the class index. If set to NO only the inherited external classes 
 # will be listed.
 
 ALLEXTERNALS           = NO
 
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
 # The PERL_PATH should be the absolute path and name of the perl script 
 # interpreter (i.e. the result of `which perl').
 
 PERL_PATH              = 
 
 #---------------------------------------------------------------------------
 # Configuration options related to the dot tool   
 #---------------------------------------------------------------------------
 
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
+# or super classes. Setting the tag to NO turns the diagrams off. Note that 
+# this option is superseded by the HAVE_DOT option below. This is only a 
+# fallback. It is recommended to install and use dot, since it yields more 
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc 
+# command. Doxygen will then run the mscgen tool (see 
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the 
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where 
+# the mscgen tool resides. If left empty the tool is assumed to be found in the 
+# default search path.
+
+MSCGEN_PATH            = 
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
 # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
 # available from the path. This tool is part of Graphviz, a graph visualization 
 # toolkit from AT&T and Lucent Bell Labs. The other options in this section 
 # have no effect if this option is set to NO (the default)
 
-HAVE_DOT               = NO
+HAVE_DOT               = YES
 
 # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
 # will generate a graph for each documented class showing the direct and 
 # indirect inheritance relations. Setting this tag to YES will force the 
 # the CLASS_DIAGRAMS tag to NO.
 
 CLASS_GRAPH            = YES
 
 # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
 # will generate a graph for each documented class showing the direct and 
 # indirect implementation dependencies (inheritance, containment, and 
 # class references variables) of the class with other documented classes.
 
 COLLABORATION_GRAPH    = YES
 
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
 # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
 # tags are set to YES then doxygen will generate a graph for each documented 
 # file showing the direct and indirect include dependencies of the file with 
 # other documented files.
 
 INCLUDE_GRAPH          = YES
 
 # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
 # HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
 # documented header file showing the documented files that directly or 
 # indirectly include this file.
 
 INCLUDED_BY_GRAPH      = YES
 
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then 
+# doxygen will generate a call dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable call graphs 
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then 
+# doxygen will generate a caller dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable caller 
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
 # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
 # will graphical hierarchy of all classes instead of a textual one.
 
 GRAPHICAL_HIERARCHY    = YES
 
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
+# then doxygen will show the dependencies a directory has on other directories 
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
 # The tag DOT_PATH can be used to specify the path where the dot tool can be 
-# found. If left blank, it is assumed the dot tool can be found on the path.
+# found. If left blank, it is assumed the dot tool can be found in the path.
 
 DOT_PATH               = 
 
-# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width 
-# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
-# this value, doxygen will try to truncate the graph, so that it fits within 
-# the specified constraint. Beware that most browsers cannot cope with very 
-# large images.
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
 
-MAX_DOT_GRAPH_WIDTH    = 1024
+# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
+# nodes that will be shown in the graph. If the number of nodes in a graph 
+# becomes larger than this value, doxygen will truncate the graph, which is 
+# visualized by representing a node as a red box. Note that doxygen if the 
+# number of direct children of the root node in a graph is already larger than 
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note 
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
 
-# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height 
-# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
-# this value, doxygen will try to truncate the graph, so that it fits within 
-# the specified constraint. Beware that most browsers cannot cope with very 
-# large images.
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes 
+# that lay further from the root node will be omitted. Note that setting this 
+# option to 1 or 2 may greatly reduce the computation time needed for large 
+# code bases. Also note that the size of a graph can be further restricted by 
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 3
 
-MAX_DOT_GRAPH_HEIGHT   = 1024
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
+# background. This is enabled by default, which results in a transparent 
+# background. Warning: Depending on the platform used, enabling this option 
+# may lead to badly anti-aliased labels on the edges of a graph (i.e. they 
+# become hard to read).
+
+DOT_TRANSPARENT        = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
+# files in one run (i.e. multiple -o and -T options on the command line). This 
+# makes dot run faster, but since only newer versions of dot (>1.8.10) 
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
 
 # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
 # generate a legend page explaining the meaning of the various boxes and 
 # arrows in the dot generated graphs.
 
 GENERATE_LEGEND        = YES
 
 # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
-# remove the intermedate dot files that are used to generate 
+# remove the intermediate dot files that are used to generate 
 # the various graphs.
 
 DOT_CLEANUP            = YES
 
 #---------------------------------------------------------------------------
-# Configuration::addtions related to the search engine   
+# Configuration::additions related to the search engine   
 #---------------------------------------------------------------------------
 
 # The SEARCHENGINE tag specifies whether or not a search engine should be 
 # used. If set to NO the values of all tags below this one will be ignored.
 
 SEARCHENGINE           = NO
-
-# The CGI_NAME tag should be the name of the CGI script that 
-# starts the search engine (doxysearch) with the correct parameters. 
-# A script with this name will be generated by doxygen.
-
-CGI_NAME               = 
-
-# The CGI_URL tag should be the absolute URL to the directory where the 
-# cgi binaries are located. See the documentation of your http daemon for 
-# details.
-
-CGI_URL                = 
-
-# The DOC_URL tag should be the absolute URL to the directory where the 
-# documentation is located. If left blank the absolute path to the 
-# documentation, with file:// prepended to it, will be used.
-
-DOC_URL                = 
-
-# The DOC_ABSPATH tag should be the absolute path to the directory where the 
-# documentation is located. If left blank the directory on the local machine 
-# will be used.
-
-DOC_ABSPATH            = 
-
-# The BIN_ABSPATH tag must point to the directory where the doxysearch binary 
-# is installed.
-
-BIN_ABSPATH            = 
-
-# The EXT_DOC_PATHS tag can be used to specify one or more paths to 
-# documentation generated for other projects. This allows doxysearch to search 
-# the documentation for these projects as well.
-
-EXT_DOC_PATHS          = 
--- a/config/milestone.txt
+++ b/config/milestone.txt
@@ -5,9 +5,9 @@
 #    x.x.x.x
 #    x.x.x+
 #
 # Referenced by milestone.pl.
 # Hopefully I'll be able to automate replacement of *all*
 # hardcoded milestones in the tree from these two files.
 #--------------------------------------------------------
 
-1.9.1a1pre
+1.9.1a2pre
--- 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/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/canvas/src/Makefile.in
+++ b/content/canvas/src/Makefile.in
@@ -58,17 +58,16 @@ REQUIRES	= \
 		unicharutil \
 		webshell \
 		necko \
 		pref \
 		docshell \
 		xpconnect \
 		caps \
 		imglib2 \
-		cairo \
 		thebes \
 		view \
 		$(NULL)
 
 # XXX some platforms can't handle building
 # an empty .a/lib.  Remove this dummy.cpp
 # whenever w have a rendering context
 # that doesn't depend on any non-default
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -90,17 +90,16 @@
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeNode.h"
 #include "nsIXPConnect.h"
 #include "jsapi.h"
 #include "jsnum.h"
 
 #include "nsTArray.h"
 
-#include "cairo.h"
 #include "imgIEncoder.h"
 
 #include "gfxContext.h"
 #include "gfxASurface.h"
 #include "gfxImageSurface.h"
 #include "gfxPlatform.h"
 #include "gfxFont.h"
 #include "gfxTextRunCache.h"
@@ -162,28 +161,23 @@ static PRBool FloatValidate (double f1, 
  **/
 #define NS_CANVASGRADIENT_PRIVATE_IID \
     { 0x491d39d8, 0x4058, 0x42bd, { 0xac, 0x76, 0x70, 0xd5, 0x62, 0x7f, 0x02, 0x10 } }
 class nsCanvasGradient : public nsIDOMCanvasGradient
 {
 public:
     NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASGRADIENT_PRIVATE_IID)
 
-    nsCanvasGradient(cairo_pattern_t *cpat, nsICSSParser *cssparser)
-        : mPattern(cpat), mCSSParser(cssparser)
+    nsCanvasGradient(gfxPattern* pat, nsICSSParser* cssparser)
+        : mPattern(pat), mCSSParser(cssparser)
     {
     }
 
-    ~nsCanvasGradient() {
-        if (mPattern)
-            cairo_pattern_destroy(mPattern);
-    }
-
-    void Apply(cairo_t *cairo) {
-        cairo_set_source(cairo, mPattern);
+    void Apply(gfxContext* ctx) {
+        ctx->SetPattern(mPattern);
     }
 
     /* nsIDOMCanvasGradient */
     NS_IMETHOD AddColorStop (float offset,
                              const nsAString& colorstr)
     {
         nscolor color;
 
@@ -192,28 +186,25 @@ public:
 
         if (offset < 0.0 || offset > 1.0)
             return NS_ERROR_DOM_INDEX_SIZE_ERR;
 
         nsresult rv = mCSSParser->ParseColorString(nsString(colorstr), nsnull, 0, &color);
         if (NS_FAILED(rv))
             return NS_ERROR_DOM_SYNTAX_ERR;
 
-        cairo_pattern_add_color_stop_rgba (mPattern, (double) offset,
-                                           NS_GET_R(color) / 255.0,
-                                           NS_GET_G(color) / 255.0,
-                                           NS_GET_B(color) / 255.0,
-                                           NS_GET_A(color) / 255.0);
+        mPattern->AddColorStop(offset, gfxRGBA(color));
+
         return NS_OK;
     }
 
     NS_DECL_ISUPPORTS
 
 protected:
-    cairo_pattern_t *mPattern;
+    nsRefPtr<gfxPattern> mPattern;
     nsCOMPtr<nsICSSParser> mCSSParser;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsCanvasGradient, NS_CANVASGRADIENT_PRIVATE_IID)
 
 NS_IMPL_ADDREF(nsCanvasGradient)
 NS_IMPL_RELEASE(nsCanvasGradient)
 
@@ -229,43 +220,37 @@ NS_INTERFACE_MAP_END
  **/
 #define NS_CANVASPATTERN_PRIVATE_IID \
     { 0xb85c6c8a, 0x0624, 0x4530, { 0xb8, 0xee, 0xff, 0xdf, 0x42, 0xe8, 0x21, 0x6d } }
 class nsCanvasPattern : public nsIDOMCanvasPattern
 {
 public:
     NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASPATTERN_PRIVATE_IID)
 
-    nsCanvasPattern(cairo_pattern_t *cpat,
+    nsCanvasPattern(gfxPattern* pat,
                     nsIPrincipal* principalForSecurityCheck,
                     PRBool forceWriteOnly)
-        : mPattern(cpat),
+        : mPattern(pat),
           mPrincipal(principalForSecurityCheck),
           mForceWriteOnly(forceWriteOnly)
     {
         NS_PRECONDITION(mPrincipal, "Must have a principal");
     }
 
-    ~nsCanvasPattern() {
-        if (mPattern)
-            cairo_pattern_destroy(mPattern);
-    }
-
-    void Apply(cairo_t *cairo) {
-        cairo_set_source(cairo, mPattern);
+    void Apply(gfxContext* ctx) {
+        ctx->SetPattern(mPattern);
     }
     
     nsIPrincipal* Principal() { return mPrincipal; }
     PRBool GetForceWriteOnly() { return mForceWriteOnly; }
 
     NS_DECL_ISUPPORTS
 
 protected:
-    cairo_pattern_t *mPattern;
-    PRUint8 *mData;
+    nsRefPtr<gfxPattern> mPattern;
     nsCOMPtr<nsIPrincipal> mPrincipal;
     PRPackedBool mForceWriteOnly;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsCanvasPattern, NS_CANVASPATTERN_PRIVATE_IID)
 
 NS_IMPL_ADDREF(nsCanvasPattern)
 NS_IMPL_RELEASE(nsCanvasPattern)
@@ -323,17 +308,17 @@ class nsCanvasRenderingContext2D :
     public nsIDOMCanvasRenderingContext2D,
     public nsICanvasRenderingContextInternal
 {
 public:
     nsCanvasRenderingContext2D();
     virtual ~nsCanvasRenderingContext2D();
 
     nsresult Redraw();
-    void SetCairoColor(nscolor c);
+    void SetThebesColor(nscolor c);
 
     // nsICanvasRenderingContextInternal
     NS_IMETHOD SetCanvasElement(nsICanvasElement* aParentCanvas);
     NS_IMETHOD SetDimensions(PRInt32 width, PRInt32 height);
     NS_IMETHOD Render(gfxContext *ctx);
     NS_IMETHOD GetInputStream(const char* aMimeType,
                               const PRUnichar* aEncoderOptions,
                               nsIInputStream **aStream);
@@ -342,35 +327,32 @@ public:
 
     // nsISupports interface
     NS_DECL_ISUPPORTS
 
     // nsIDOMCanvasRenderingContext2D interface
     NS_DECL_NSIDOMCANVASRENDERINGCONTEXT2D
 
 protected:
-    // destroy cairo/image stuff, in preparation for possibly recreating
+    // destroy thebes/image stuff, in preparation for possibly recreating
     void Destroy();
 
     // Some helpers.  Doesn't modify acolor on failure.
-    enum {
+    enum Style {
         STYLE_STROKE = 0,
         STYLE_FILL,
-        STYLE_SHADOW
-        //STYLE_MAX
+        STYLE_SHADOW,
+        STYLE_MAX
     };
 
-    // VC6 sucks
-#define STYLE_MAX 3
-
-    nsresult SetStyleFromVariant(nsIVariant* aStyle, PRInt32 aWhichStyle);
+    nsresult SetStyleFromVariant(nsIVariant* aStyle, Style aWhichStyle);
     void StyleColorToString(const nscolor& aColor, nsAString& aStr);
 
     void DirtyAllStyles();
-    void ApplyStyle(PRInt32 aWhichStyle);
+    void ApplyStyle(Style aWhichStyle);
     
     // If aPrincipal is not subsumed by this canvas element, then
     // we make the canvas write-only so bad guys can't extract the pixel
     // data.  If forceWriteOnly is set, we force write only to be set
     // and ignore aPrincipal.  (This is used for when the original data came
     // from a <canvas> that had write-only set.)
     void DoDrawImageSecurityCheck(nsIPrincipal* aPrincipal,
                                   PRBool forceWriteOnly);
@@ -382,23 +364,26 @@ protected:
 
     // the canvas element informs us when it's going away,
     // so these are not nsCOMPtrs
     nsICanvasElement* mCanvasElement;
 
     // our CSS parser, for colors and whatnot
     nsCOMPtr<nsICSSParser> mCSSParser;
 
-    // yay cairo
-    nsRefPtr<gfxContext> mThebesContext;
-    nsRefPtr<gfxASurface> mThebesSurface;
+    // yay thebes
+    nsRefPtr<gfxContext> mThebes;
+    nsRefPtr<gfxASurface> mSurface;
 
     PRUint32 mSaveCount;
-    cairo_t *mCairo;
-    cairo_surface_t *mSurface;
+
+    /**
+     * Draws a rectangle in the given style; used by FillRect and StrokeRect.
+     */
+    nsresult DrawRect(const gfxRect& rect, Style style);
 
     // text
     enum TextAlign {
         TEXT_ALIGN_START,
         TEXT_ALIGN_END,
         TEXT_ALIGN_LEFT,
         TEXT_ALIGN_RIGHT,
         TEXT_ALIGN_CENTER
@@ -428,17 +413,21 @@ protected:
     nsresult DrawOrMeasureText(const nsAString& text,
                                float x,
                                float y,
                                float maxWidth,
                                TextDrawOperation op,
                                float* aWidth);
  
     // style handling
-    PRInt32 mLastStyle;
+    /*
+     * The previous set style. Is equal to STYLE_MAX when there is no valid
+     * previous style.
+     */
+    Style mLastStyle;
     PRPackedBool mDirtyStyle[STYLE_MAX];
 
     // state stack handling
     class ContextState {
     public:
         ContextState() : globalAlpha(1.0),
                          textAlign(TEXT_ALIGN_START),
                          textBaseline(TEXT_BASELINE_ALPHABETIC) { }
@@ -452,28 +441,28 @@ protected:
         {
             for (int i = 0; i < STYLE_MAX; i++) {
                 colorStyles[i] = other.colorStyles[i];
                 gradientStyles[i] = other.gradientStyles[i];
                 patternStyles[i] = other.patternStyles[i];
             }
         }
 
-        inline void SetColorStyle(int whichStyle, nscolor color) {
+        inline void SetColorStyle(Style whichStyle, nscolor color) {
             colorStyles[whichStyle] = color;
             gradientStyles[whichStyle] = nsnull;
             patternStyles[whichStyle] = nsnull;
         }
 
-        inline void SetPatternStyle(int whichStyle, nsCanvasPattern* pat) {
+        inline void SetPatternStyle(Style whichStyle, nsCanvasPattern* pat) {
             gradientStyles[whichStyle] = nsnull;
             patternStyles[whichStyle] = pat;
         }
 
-        inline void SetGradientStyle(int whichStyle, nsCanvasGradient* grad) {
+        inline void SetGradientStyle(Style whichStyle, nsCanvasGradient* grad) {
             gradientStyles[whichStyle] = grad;
             patternStyles[whichStyle] = nsnull;
         }
 
         float globalAlpha;
 
         nsString font;
         nsRefPtr<gfxFontGroup> fontGroup;
@@ -494,23 +483,23 @@ protected:
     // stolen from nsJSUtils
     static PRBool ConvertJSValToUint32(PRUint32* aProp, JSContext* aContext,
                                        jsval aValue);
     static PRBool ConvertJSValToXPCObject(nsISupports** aSupports, REFNSIID aIID,
                                           JSContext* aContext, jsval aValue);
     static PRBool ConvertJSValToDouble(double* aProp, JSContext* aContext,
                                        jsval aValue);
 
-    // cairo helpers
-    nsresult CairoSurfaceFromElement(nsIDOMElement *imgElt,
-                                     PRBool forceCopy,
-                                     cairo_surface_t **aCairoSurface,
-                                     PRInt32 *widthOut, PRInt32 *heightOut,
-                                     nsIPrincipal **prinOut,
-                                     PRBool *forceWriteOnlyOut);
+    // thebes helpers
+    nsresult ThebesSurfaceFromElement(nsIDOMElement *imgElt,
+                                      PRBool forceCopy,
+                                      gfxASurface **aSurface,
+                                      PRInt32 *widthOut, PRInt32 *heightOut,
+                                      nsIPrincipal **prinOut,
+                                      PRBool *forceWriteOnlyOut);
 
     // other helpers
     void GetAppUnitsValues(PRUint32 *perDevPixel, PRUint32 *perCSSPixel) {
         // If we don't have a canvas element, we just return something generic.
         PRUint32 devPixel = 60;
         PRUint32 cssPixel = 60;
 
         nsCOMPtr<nsINode> elem = do_QueryInterface(mCanvasElement);
@@ -547,49 +536,45 @@ NS_INTERFACE_MAP_END
 
 /**
  ** CanvasRenderingContext2D impl
  **/
 
 nsresult
 NS_NewCanvasRenderingContext2D(nsIDOMCanvasRenderingContext2D** aResult)
 {
-    nsIDOMCanvasRenderingContext2D* ctx = new nsCanvasRenderingContext2D();
+    nsRefPtr<nsIDOMCanvasRenderingContext2D> ctx = new nsCanvasRenderingContext2D();
     if (!ctx)
         return NS_ERROR_OUT_OF_MEMORY;
 
-    NS_ADDREF(*aResult = ctx);
+    *aResult = ctx.forget().get();
     return NS_OK;
 }
 
 nsCanvasRenderingContext2D::nsCanvasRenderingContext2D()
     : mValid(PR_FALSE), mOpaque(PR_FALSE), mCanvasElement(nsnull),
-      mSaveCount(0), mCairo(nsnull), mSurface(nsnull), mStyleStack(20)
+      mSaveCount(0), mStyleStack(20)
 {
 }
 
 nsCanvasRenderingContext2D::~nsCanvasRenderingContext2D()
 {
     Destroy();
 }
 
 void
 nsCanvasRenderingContext2D::Destroy()
 {
     mSurface = nsnull;
-    mThebesSurface = nsnull;
-
-    mCairo = nsnull;
-    mThebesContext = nsnull;
-
+    mThebes = nsnull;
     mValid = PR_FALSE;
 }
 
 nsresult
-nsCanvasRenderingContext2D::SetStyleFromVariant(nsIVariant* aStyle, PRInt32 aWhichStyle)
+nsCanvasRenderingContext2D::SetStyleFromVariant(nsIVariant* aStyle, Style aWhichStyle)
 {
     nsresult rv;
     nscolor color;
 
     PRUint16 paramType;
     rv = aStyle->GetDataType(&paramType);
     NS_ENSURE_SUCCESS(rv, rv);
 
@@ -710,17 +695,17 @@ nsCanvasRenderingContext2D::DoDrawImageS
             return;
         }
     }
     
     mCanvasElement->SetWriteOnly();
 }
 
 void
-nsCanvasRenderingContext2D::ApplyStyle(PRInt32 aWhichStyle)
+nsCanvasRenderingContext2D::ApplyStyle(Style aWhichStyle)
 {
     if (mLastStyle == aWhichStyle &&
         !mDirtyStyle[aWhichStyle])
     {
         // nothing to do, this is already the set style
         return;
     }
 
@@ -729,107 +714,102 @@ nsCanvasRenderingContext2D::ApplyStyle(P
 
     nsCanvasPattern* pattern = CurrentState().patternStyles[aWhichStyle];
     if (pattern) {
         if (!mCanvasElement)
             return;
 
         DoDrawImageSecurityCheck(pattern->Principal(),
                                  pattern->GetForceWriteOnly());
-        pattern->Apply(mCairo);
+        pattern->Apply(mThebes);
         return;
     }
 
     if (CurrentState().gradientStyles[aWhichStyle]) {
-        CurrentState().gradientStyles[aWhichStyle]->Apply(mCairo);
+        CurrentState().gradientStyles[aWhichStyle]->Apply(mThebes);
         return;
     }
 
-    SetCairoColor(CurrentState().colorStyles[aWhichStyle]);
+    SetThebesColor(CurrentState().colorStyles[aWhichStyle]);
 }
 
 nsresult
 nsCanvasRenderingContext2D::Redraw()
 {
     if (!mCanvasElement)
-        return nsnull;
+        return NS_OK;
 
     return mCanvasElement->InvalidateFrame();
 }
 
 void
-nsCanvasRenderingContext2D::SetCairoColor(nscolor c)
+nsCanvasRenderingContext2D::SetThebesColor(nscolor c)
 {
-    double r = double(NS_GET_R(c) / 255.0);
-    double g = double(NS_GET_G(c) / 255.0);
-    double b = double(NS_GET_B(c) / 255.0);
-    double a = double(NS_GET_A(c) / 255.0) * CurrentState().globalAlpha;
-
-    cairo_set_source_rgba (mCairo, r, g, b, a);
+    gfxRGBA color(c);
+    color.a *= CurrentState().globalAlpha;
+
+    mThebes->SetColor(color);
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetDimensions(PRInt32 width, PRInt32 height)
 {
     Destroy();
 
     mWidth = width;
     mHeight = height;
 
     // Check that the dimensions are sane
     if (gfxASurface::CheckSurfaceSize(gfxIntSize(width, height), 0xffff)) {
         gfxASurface::gfxImageFormat format = gfxASurface::ImageFormatARGB32;
         if (mOpaque)
             format = gfxASurface::ImageFormatRGB24;
 
-        mThebesSurface = gfxPlatform::GetPlatform()->CreateOffscreenSurface
+        mSurface = gfxPlatform::GetPlatform()->CreateOffscreenSurface
             (gfxIntSize(width, height), format);
 
-        if (mThebesSurface->CairoStatus() == 0) {
-            mThebesContext = new gfxContext(mThebesSurface);
+        if (mSurface->CairoStatus() == 0) {
+            mThebes = new gfxContext(mSurface);
         }
     }
 
     /* Create dummy surfaces here */
-    if (mThebesSurface == nsnull || mThebesSurface->CairoStatus() != 0 ||
-        mThebesContext == nsnull || mThebesContext->HasError())
+    if (mSurface == nsnull || mSurface->CairoStatus() != 0 ||
+        mThebes == nsnull || mThebes->HasError())
     {
-        mThebesSurface = new gfxImageSurface(gfxIntSize(1,1), gfxASurface::ImageFormatARGB32);
-        mThebesContext = new gfxContext(mThebesSurface);
+        mSurface = new gfxImageSurface(gfxIntSize(1,1), gfxASurface::ImageFormatARGB32);
+        mThebes = new gfxContext(mSurface);
     } else {
         mValid = PR_TRUE;
     }
 
-    mSurface = mThebesSurface->CairoSurface();
-    mCairo = mThebesContext->GetCairo();
-
     // set up the initial canvas defaults
     mStyleStack.Clear();
     mSaveCount = 0;
 
     ContextState *state = mStyleStack.AppendElement();
     state->globalAlpha = 1.0;
     for (int i = 0; i < STYLE_MAX; i++)
         state->colorStyles[i] = NS_RGB(0,0,0);
-    mLastStyle = -1;
+    mLastStyle = STYLE_MAX;
 
     DirtyAllStyles();
 
-    cairo_set_operator(mCairo, CAIRO_OPERATOR_CLEAR);
-    cairo_new_path(mCairo);
-    cairo_rectangle(mCairo, 0, 0, mWidth, mHeight);
-    cairo_fill(mCairo);
-
-    cairo_set_line_width(mCairo, 1.0);
-    cairo_set_operator(mCairo, CAIRO_OPERATOR_OVER);
-    cairo_set_miter_limit(mCairo, 10.0);
-    cairo_set_line_cap(mCairo, CAIRO_LINE_CAP_BUTT);
-    cairo_set_line_join(mCairo, CAIRO_LINE_JOIN_MITER);
-
-    cairo_new_path(mCairo);
+    mThebes->SetOperator(gfxContext::OPERATOR_CLEAR);
+    mThebes->NewPath();
+    mThebes->Rectangle(gfxRect(0, 0, mWidth, mHeight));
+    mThebes->Fill();
+
+    mThebes->SetLineWidth(1.0);
+    mThebes->SetOperator(gfxContext::OPERATOR_OVER);
+    mThebes->SetMiterLimit(10.0);
+    mThebes->SetLineCap(gfxContext::LINE_CAP_BUTT);
+    mThebes->SetLineJoin(gfxContext::LINE_JOIN_MITER);
+
+    mThebes->NewPath();
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetIsOpaque(PRBool isOpaque)
 {
     if (isOpaque == mOpaque)
@@ -847,25 +827,25 @@ nsCanvasRenderingContext2D::SetIsOpaque(
     return NS_OK;
 }
  
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Render(gfxContext *ctx)
 {
     nsresult rv = NS_OK;
 
-    if (!mValid || !mSurface || !mCairo ||
-        cairo_surface_status(mSurface) != CAIRO_STATUS_SUCCESS ||
-        cairo_status(mCairo) != CAIRO_STATUS_SUCCESS)
+    if (!mValid || !mSurface ||
+        mSurface->CairoStatus() ||
+        mThebes->HasError())
         return NS_ERROR_FAILURE;
 
-    if (!mThebesSurface)
+    if (!mSurface)
         return NS_ERROR_FAILURE;
 
-    nsRefPtr<gfxPattern> pat = new gfxPattern(mThebesSurface);
+    nsRefPtr<gfxPattern> pat = new gfxPattern(mSurface);
 
     gfxContext::GraphicsOperator op = ctx->CurrentOperator();
     if (mOpaque)
         ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
 
     // XXX I don't want to use PixelSnapped here, but layout doesn't guarantee
     // pixel alignment for this stuff!
     ctx->NewPath();
@@ -879,18 +859,18 @@ nsCanvasRenderingContext2D::Render(gfxCo
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::GetInputStream(const char *aMimeType,
                                            const PRUnichar *aEncoderOptions,
                                            nsIInputStream **aStream)
 {
     if (!mValid || !mSurface ||
-        cairo_status(mCairo) != CAIRO_STATUS_SUCCESS ||
-        cairo_surface_status(mSurface) != CAIRO_STATUS_SUCCESS)
+        mSurface->CairoStatus() ||
+        mThebes->HasError())
         return NS_ERROR_FAILURE;
 
     nsresult rv;
     const char encoderPrefix[] = "@mozilla.org/image/encoder;2?type=";
     nsAutoArrayPtr<char> conid(new (std::nothrow) char[strlen(encoderPrefix) + strlen(aMimeType) + 1]);
 
     if (!conid)
         return NS_ERROR_OUT_OF_MEMORY;
@@ -901,29 +881,32 @@ nsCanvasRenderingContext2D::GetInputStre
     nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(conid);
     if (!encoder)
         return NS_ERROR_FAILURE;
 
     nsAutoArrayPtr<PRUint8> imageBuffer(new (std::nothrow) PRUint8[mWidth * mHeight * 4]);
     if (!imageBuffer)
         return NS_ERROR_OUT_OF_MEMORY;
 
-    cairo_surface_t *imgsurf = cairo_image_surface_create_for_data (imageBuffer.get(),
-                                                                    CAIRO_FORMAT_ARGB32,
-                                                                    mWidth, mHeight, mWidth * 4);
-    if (!imgsurf || cairo_surface_status(imgsurf))
+    nsRefPtr<gfxImageSurface> imgsurf = new gfxImageSurface(imageBuffer.get(),
+                                                            gfxIntSize(mWidth, mHeight),
+                                                            mWidth * 4,
+                                                            gfxASurface::ImageFormatARGB32);
+
+    if (!imgsurf || imgsurf->CairoStatus())
         return NS_ERROR_FAILURE;
 
-    cairo_t *cr = cairo_create(imgsurf);
-    cairo_surface_destroy (imgsurf);
-
-    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
-    cairo_set_source_surface (cr, mSurface, 0, 0);
-    cairo_paint (cr);
-    cairo_destroy (cr);
+    nsRefPtr<gfxContext> ctx = new gfxContext(imgsurf);
+
+    if (!ctx || ctx->HasError())
+        return NS_ERROR_FAILURE;
+
+    ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
+    ctx->SetSource(mSurface, gfxPoint(0, 0));
+    ctx->Paint();
 
     rv = encoder->InitFromData(imageBuffer.get(),
                                mWidth * mHeight * 4, mWidth, mHeight, mWidth * 4,
                                imgIEncoder::INPUT_FORMAT_HOSTARGB,
                                nsDependentString(aEncoderOptions));
     NS_ENSURE_SUCCESS(rv, rv);
 
     return CallQueryInterface(encoder, aStream);
@@ -962,94 +945,94 @@ nsCanvasRenderingContext2D::GetCanvas(ns
 // state
 //
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Save()
 {
     ContextState state = CurrentState();
     mStyleStack.AppendElement(state);
-    cairo_save (mCairo);
+    mThebes->Save();
     mSaveCount++;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Restore()
 {
     if (mSaveCount == 0)
         return NS_OK;
     if (mSaveCount < 0)
         return NS_ERROR_DOM_INVALID_STATE_ERR;
 
     mStyleStack.RemoveElementAt(mSaveCount);
-    cairo_restore (mCairo);
-
-    mLastStyle = -1;
+    mThebes->Restore();
+
+    mLastStyle = STYLE_MAX;
     DirtyAllStyles();
 
     mSaveCount--;
     return NS_OK;
 }
 
 //
 // transformations
 //
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Scale(float x, float y)
 {
     if (!FloatValidate(x,y))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_scale (mCairo, x, y);
+    mThebes->Scale(x, y);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Rotate(float angle)
 {
     if (!FloatValidate(angle))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_rotate (mCairo, angle);
+    mThebes->Rotate(angle);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Translate(float x, float y)
 {
     if (!FloatValidate(x,y))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_translate (mCairo, x, y);
+    mThebes->Translate(gfxPoint(x, y));
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Transform(float m11, float m12, float m21, float m22, float dx, float dy)
 {
     if (!FloatValidate(m11,m12,m21,m22,dx,dy))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_matrix_t mat;
-    cairo_matrix_init (&mat, m11, m12, m21, m22, dx, dy);
-    cairo_transform (mCairo, &mat);
+    gfxMatrix matrix(m11, m12, m21, m22, dx, dy);
+    mThebes->Multiply(matrix);
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetTransform(float m11, float m12, float m21, float m22, float dx, float dy)
 {
     if (!FloatValidate(m11,m12,m21,m22,dx,dy))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_matrix_t mat;
-    cairo_matrix_init (&mat, m11, m12, m21, m22, dx, dy);
-    cairo_set_matrix (mCairo, &mat);
+    gfxMatrix matrix(m11, m12, m21, m22, dx, dy);
+    mThebes->SetMatrix(matrix);
+
     return NS_OK;
 }
 
 //
 // colors
 //
 
 NS_IMETHODIMP
@@ -1101,17 +1084,17 @@ nsCanvasRenderingContext2D::GetStrokeSty
     } else {
         nsString styleStr;
         StyleColorToString(CurrentState().colorStyles[STYLE_STROKE], styleStr);
 
         rv = var->SetAsDOMString(styleStr);
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
-    NS_ADDREF(*aStyle = var);
+    *aStyle = var.forget().get();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetFillStyle(nsIVariant* aStyle)
 {
     return SetStyleFromVariant(aStyle, STYLE_FILL);
 }
@@ -1136,108 +1119,104 @@ nsCanvasRenderingContext2D::GetFillStyle
     } else {
         nsString styleStr;
         StyleColorToString(CurrentState().colorStyles[STYLE_FILL], styleStr);
 
         rv = var->SetAsDOMString(styleStr);
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
-    NS_ADDREF(*aStyle = var);
+    *aStyle = var.forget().get();
     return NS_OK;
 }
 
 //
 // gradients and patterns
 //
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::CreateLinearGradient(float x0, float y0, float x1, float y1,
                                                  nsIDOMCanvasGradient **_retval)
 {
     if (!FloatValidate(x0,y0,x1,y1))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_pattern_t *gradpat = nsnull;
-    gradpat = cairo_pattern_create_linear ((double) x0, (double) y0, (double) x1, (double) y1);
-    nsCanvasGradient *grad = new nsCanvasGradient(gradpat, mCSSParser);
-    if (!grad) {
-        cairo_pattern_destroy(gradpat);
+    nsRefPtr<gfxPattern> gradpat = new gfxPattern(x0, y0, x1, y1);
+    if (!gradpat)
         return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-    NS_ADDREF(*_retval = grad);
+
+    nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasGradient(gradpat, mCSSParser);
+    if (!grad)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    *_retval = grad.forget().get();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::CreateRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1,
                                                  nsIDOMCanvasGradient **_retval)
 {
     if (!FloatValidate(x0,y0,r0,x1,y1,r1))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_pattern_t *gradpat = nsnull;
-    gradpat = cairo_pattern_create_radial ((double) x0, (double) y0, (double) r0,
-                                           (double) x1, (double) y1, (double) r1);
-    nsCanvasGradient *grad = new nsCanvasGradient(gradpat, mCSSParser);
-    if (!grad) {
-        cairo_pattern_destroy(gradpat);
+    nsRefPtr<gfxPattern> gradpat = new gfxPattern(x0, y0, r0, x1, y1, r1);
+    if (!gradpat)
         return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-    NS_ADDREF(*_retval = grad);
+
+    nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasGradient(gradpat, mCSSParser);
+    if (!grad)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    *_retval = grad.forget().get();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::CreatePattern(nsIDOMHTMLElement *image,
                                           const nsAString& repeat,
                                           nsIDOMCanvasPattern **_retval)
 {
     nsresult rv;
-    cairo_extend_t extend;
+    gfxPattern::GraphicsExtend extend;
 
     if (repeat.IsEmpty() || repeat.EqualsLiteral("repeat")) {
-        extend = CAIRO_EXTEND_REPEAT;
+        extend = gfxPattern::EXTEND_REPEAT;
     } else if (repeat.EqualsLiteral("repeat-x")) {
         // XX
-        extend = CAIRO_EXTEND_REPEAT;
+        extend = gfxPattern::EXTEND_REPEAT;
     } else if (repeat.EqualsLiteral("repeat-y")) {
         // XX
-        extend = CAIRO_EXTEND_REPEAT;
+        extend = gfxPattern::EXTEND_REPEAT;
     } else if (repeat.EqualsLiteral("no-repeat")) {
-        extend = CAIRO_EXTEND_NONE;
+        extend = gfxPattern::EXTEND_NONE;
     } else {
         // XXX ERRMSG we need to report an error to developers here! (bug 329026)
         return NS_ERROR_DOM_SYNTAX_ERR;
     }
 
-    cairo_surface_t *imgSurf = nsnull;
     PRInt32 imgWidth, imgHeight;
     nsCOMPtr<nsIPrincipal> principal;
     PRBool forceWriteOnly = PR_FALSE;
-    rv = CairoSurfaceFromElement(image, PR_TRUE,
-                                 &imgSurf, &imgWidth, &imgHeight,
-                                 getter_AddRefs(principal), &forceWriteOnly);
+    nsRefPtr<gfxASurface> imgsurf;
+    rv = ThebesSurfaceFromElement(image, PR_TRUE,
+                                  getter_AddRefs(imgsurf), &imgWidth, &imgHeight,
+                                  getter_AddRefs(principal), &forceWriteOnly);
     if (NS_FAILED(rv))
         return rv;
 
-    cairo_pattern_t *cairopat = cairo_pattern_create_for_surface(imgSurf);
-    cairo_surface_destroy(imgSurf);
-
-    cairo_pattern_set_extend (cairopat, extend);
-
-    nsCanvasPattern *pat = new nsCanvasPattern(cairopat, principal,
-                                               forceWriteOnly);
-    if (!pat) {
-        cairo_pattern_destroy(cairopat);
+    nsRefPtr<gfxPattern> thebespat = new gfxPattern(imgsurf);
+
+    thebespat->SetExtend(extend);
+
+    nsRefPtr<nsCanvasPattern> pat = new nsCanvasPattern(thebespat, principal,
+                                                        forceWriteOnly);
+    if (!pat)
         return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-    NS_ADDREF(*_retval = pat);
+
+    *_retval = pat.forget().get();
     return NS_OK;
 }
 
 //
 // shadows
 //
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetShadowOffsetX(float x)
@@ -1306,163 +1285,156 @@ nsCanvasRenderingContext2D::GetShadowCol
 //
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::ClearRect(float x, float y, float w, float h)
 {
     if (!FloatValidate(x,y,w,h))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_path_t *old_path = cairo_copy_path (mCairo);
-    cairo_save (mCairo);
-    cairo_set_operator (mCairo, CAIRO_OPERATOR_CLEAR);
-    cairo_new_path (mCairo);
-    cairo_rectangle (mCairo, x, y, w, h);
-    cairo_fill (mCairo);
-    cairo_restore (mCairo);
-    cairo_new_path (mCairo);
-    if (old_path->status == CAIRO_STATUS_SUCCESS && old_path->num_data != 0)
-        cairo_append_path (mCairo, old_path);
-    cairo_path_destroy (old_path);
+    nsRefPtr<gfxPath> path = mThebes->CopyPath();
+
+    mThebes->Save();
+    mThebes->SetOperator(gfxContext::OPERATOR_CLEAR);
+    mThebes->NewPath();
+    mThebes->Rectangle(gfxRect(x, y, w, h));
+    mThebes->Fill();
+    mThebes->Restore();
+
+    mThebes->NewPath();
+    mThebes->AppendPath(path);
+
+    return Redraw();
+}
+
+nsresult
+nsCanvasRenderingContext2D::DrawRect(const gfxRect& rect, Style style)
+{
+    if (!FloatValidate(rect.pos.x, rect.pos.y, rect.size.width, rect.size.height))
+        return NS_ERROR_DOM_SYNTAX_ERR;
+
+    nsRefPtr<gfxPath> path = mThebes->CopyPath();
+
+    mThebes->NewPath();
+    mThebes->Rectangle(rect);
+
+    ApplyStyle(style);
+    if (style == STYLE_FILL)
+        mThebes->Fill();
+    else // STYLE_STROKE
+        mThebes->Stroke();
+
+    mThebes->NewPath();
+    mThebes->AppendPath(path);
 
     return Redraw();
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::FillRect(float x, float y, float w, float h)
 {
-    if (!FloatValidate(x,y,w,h))
-        return NS_ERROR_DOM_SYNTAX_ERR;
-
-    cairo_path_t *old_path = cairo_copy_path (mCairo);
-    cairo_new_path (mCairo);
-    cairo_rectangle (mCairo, x, y, w, h);
-
-    ApplyStyle(STYLE_FILL);
-    cairo_fill (mCairo);
-    cairo_new_path (mCairo);
-    if (old_path->status == CAIRO_STATUS_SUCCESS && old_path->num_data != 0)
-        cairo_append_path (mCairo, old_path);
-    cairo_path_destroy (old_path);
-
-    return Redraw();
+    return DrawRect(gfxRect(x, y, w, h), STYLE_FILL);
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::StrokeRect(float x, float y, float w, float h)
 {
-    if (!FloatValidate(x,y,w,h))
-        return NS_ERROR_DOM_SYNTAX_ERR;
-
-    cairo_path_t *old_path = cairo_copy_path (mCairo);
-    cairo_new_path (mCairo);
-    cairo_rectangle (mCairo, x, y, w, h);
-
-    ApplyStyle(STYLE_STROKE);
-    cairo_stroke (mCairo);
-    cairo_new_path (mCairo);
-    if (old_path->status == CAIRO_STATUS_SUCCESS && old_path->num_data != 0)
-        cairo_append_path (mCairo, old_path);
-    cairo_path_destroy (old_path);
-
-    return Redraw();
+    return DrawRect(gfxRect(x, y, w, h), STYLE_STROKE);
 }
 
 //
 // path bits
 //
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::BeginPath()
 {
-    cairo_new_path(mCairo);
+    mThebes->NewPath();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::ClosePath()
 {
-    cairo_close_path(mCairo);
+    mThebes->ClosePath();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Fill()
 {
     ApplyStyle(STYLE_FILL);
-    cairo_fill_preserve(mCairo);
+    mThebes->Fill();
     return Redraw();
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Stroke()
 {
     ApplyStyle(STYLE_STROKE);
-    cairo_stroke_preserve(mCairo);
+    mThebes->Stroke();
     return Redraw();
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Clip()
 {
-    cairo_clip_preserve(mCairo);
+    mThebes->Clip();
     return Redraw();
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::MoveTo(float x, float y)
 {
     if (!FloatValidate(x,y))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_move_to(mCairo, x, y);
+    mThebes->MoveTo(gfxPoint(x, y));
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::LineTo(float x, float y)
 {
     if (!FloatValidate(x,y))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_line_to(mCairo, x, y);
+    mThebes->LineTo(gfxPoint(x, y));
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::QuadraticCurveTo(float cpx, float cpy, float x, float y)
 {
     if (!FloatValidate(cpx,cpy,x,y))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    double cx, cy;
-
     // we will always have a current point, since beginPath forces
     // a moveto(0,0)
-    cairo_get_current_point(mCairo, &cx, &cy);
-    cairo_curve_to(mCairo,
-                   (cx + cpx * 2.0) / 3.0,
-                   (cy + cpy * 2.0) / 3.0,
-                   (cpx * 2.0 + x) / 3.0,
-                   (cpy * 2.0 + y) / 3.0,
-                   x,
-                   y);
+    gfxPoint c = mThebes->CurrentPoint();
+    gfxPoint p(x,y);
+    gfxPoint cp(cpx, cpy);
+
+    mThebes->CurveTo((c+cp*2)/3.0, (p+cp*2)/3.0, p);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::BezierCurveTo(float cp1x, float cp1y,
                                           float cp2x, float cp2y,
                                           float x, float y)
 {
     if (!FloatValidate(cp1x,cp1y,cp2x,cp2y,x,y))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_curve_to(mCairo, cp1x, cp1y, cp2x, cp2y, x, y);
+    mThebes->CurveTo(gfxPoint(cp1x, cp1y),
+                     gfxPoint(cp2x, cp2y),
+                     gfxPoint(x, y));
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::ArcTo(float x1, float y1, float x2, float y2, float radius)
 {
     if (!FloatValidate(x1,y1,x2,y2,radius))
         return NS_ERROR_DOM_SYNTAX_ERR;
@@ -1470,52 +1442,51 @@ nsCanvasRenderingContext2D::ArcTo(float 
     if (radius <= 0)
         return NS_ERROR_DOM_INDEX_SIZE_ERR;
 
     /* This is an adaptation of the cairo_arc_to patch from Behdad
      * Esfahbod; once that patch is accepted, we should remove this
      * and just call cairo_arc_to() directly.
      */
     
-    double x0, y0;
     double angle0, angle1, angle2, angled;
     double d0, d2;
     double sin_, cos_;
-    double xc, yc, dc;
+    double dc;
     int forward;
 
-    cairo_get_current_point(mCairo, &x0, &y0);
-
-    angle0 = atan2 (y0 - y1, x0 - x1); /* angle from (x1,y1) to (x0,y0) */
+    gfxPoint p0 = mThebes->CurrentPoint();
+
+    angle0 = atan2 (p0.y - y1, p0.x - x1); /* angle from (x1,y1) to (p0.x,p0.y) */
     angle2 = atan2 (y2 - y1, x2 - x1); /* angle from (x1,y1) to (x2,y2) */
     angle1 = (angle0 + angle2) / 2;    /* angle from (x1,y1) to (xc,yc) */
 
-    angled = angle2 - angle0;          /* the angle (x0,y0)--(x1,y1)--(x2,y2) */
+    angled = angle2 - angle0;          /* the angle (p0.x,p0.y)--(x1,y1)--(x2,y2) */
 
     /* Shall we go forward or backward? */
     if (angled > M_PI || (angled < 0 && angled > -M_PI)) {
         angle1 += M_PI;
         angled = 2 * M_PI - angled;
         forward = 1;
     } else {
         double tmp;
         tmp = angle0;
         angle0 = angle2;
         angle2 = tmp;
         forward = 0;
     }
 
-    angle0 += M_PI_2; /* angle from (xc,yc) to (x0,y0) */
+    angle0 += M_PI_2; /* angle from (xc,yc) to (p0.x,p0.y) */
     angle2 -= M_PI_2; /* angle from (xc,yc) to (x2,y2) */
-    angled /= 2;      /* the angle (x0,y0)--(x1,y1)--(xc,yc) */
-
-
-    /* distance from (x1,y1) to (x0,y0) */
-    d0 = sqrt ((x0-x1)*(x0-x1)+(y0-y1)*(y0-y1));
-    /* distance from (x2,y2) to (x0,y0) */
+    angled /= 2;      /* the angle (p0.x,p0.y)--(x1,y1)--(xc,yc) */
+
+
+    /* distance from (x1,y1) to (p0.x,p0.y) */
+    d0 = sqrt ((p0.x-x1)*(p0.x-x1)+(p0.y-y1)*(p0.y-y1));
+    /* distance from (x2,y2) to (p0.x,p0.y) */
     d2 = sqrt ((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
 
     dc = -1;
     sin_ = sin(angled);
     cos_ = cos(angled);
     if (fabs(cos_) >= 1e-5) { /* the arc may not fit */
         /* min distance of end-points from corner */
         double min_d = d0 < d2 ? d0 : d2;
@@ -1529,53 +1500,53 @@ nsCanvasRenderingContext2D::ArcTo(float 
         }
     }
 
     if (dc < 0)
         dc = radius / sin_; /* distance of (xc,yc) from (x1,y1) */
 
 
     /* find (cx,cy), the center of the arc */
-    xc = x1 + sin(angle1) * dc;
-    yc = y1 + cos(angle1) * dc;
-
-
-    /* the arc operation draws the line from current point (x0,y0)
+    gfxPoint c(x1 + sin(angle1) * dc, y1 + cos(angle1) * dc);
+
+    /* the arc operation draws the line from current point (p0.x,p0.y)
      * to arc center too. */
 
     if (forward)
-        cairo_arc (mCairo, xc, yc, radius, angle0, angle2);
+        mThebes->Arc(c, radius, angle0, angle2);
     else
-        cairo_arc_negative (mCairo, xc, yc, radius, angle2, angle0);
-
-    cairo_line_to (mCairo, x2, y2);
+        mThebes->NegativeArc(c, radius, angle2, angle0);
+
+    mThebes->LineTo(gfxPoint(x2, y2));
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Arc(float x, float y, float r, float startAngle, float endAngle, int ccw)
 {
     if (!FloatValidate(x,y,r,startAngle,endAngle))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
+    gfxPoint p(x,y);
+
     if (ccw)
-        cairo_arc_negative (mCairo, x, y, r, startAngle, endAngle);
+        mThebes->NegativeArc(p, r, startAngle, endAngle);
     else
-        cairo_arc (mCairo, x, y, r, startAngle, endAngle);
+        mThebes->Arc(p, r, startAngle, endAngle);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Rect(float x, float y, float w, float h)
 {
     if (!FloatValidate(x,y,w,h))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_rectangle (mCairo, x, y, w, h);
+    mThebes->Rectangle(gfxRect(x, y, w, h));
     return NS_OK;
 }
 
 //
 // text
 //
 
 /**
@@ -1890,53 +1861,53 @@ nsCanvasRenderingContext2D::MeasureText(
  */
 struct NS_STACK_CLASS nsCanvasBidiProcessor : public nsBidiPresUtils::BidiProcessor
 {
     virtual void SetText(const PRUnichar* text, PRInt32 length, nsBidiDirection direction)
     {
         mTextRun = gfxTextRunCache::MakeTextRun(text,
                                                 length,
                                                 mFontgrp,
-                                                mCtx->mThebesContext,
+                                                mCtx->mThebes,
                                                 mAppUnitsPerDevPixel,
                                                 direction==NSBIDI_RTL ? gfxTextRunFactory::TEXT_IS_RTL : 0);
     }
 
     virtual nscoord GetWidth()
     {
         PRBool tightBoundingBox = PR_FALSE;
         gfxTextRun::Metrics textRunMetrics = mTextRun->MeasureText(0,
                                                                    mTextRun->GetLength(),
                                                                    tightBoundingBox,
-                                                                   mCtx->mThebesContext,
+                                                                   mCtx->mThebes,
                                                                    nsnull);
 
         return static_cast<nscoord>(textRunMetrics.mAdvanceWidth/gfxFloat(mAppUnitsPerDevPixel));
     }
 
     virtual void DrawText(nscoord xOffset, nscoord width)
     {
         gfxPoint point = mPt;
         point.x += xOffset * mAppUnitsPerDevPixel;
 
         // offset is given in terms of left side of string
         if (mTextRun->IsRightToLeft())
             point.x += width * mAppUnitsPerDevPixel;
 
         // stroke or fill the text depending on operation
         if (mOp == nsCanvasRenderingContext2D::TEXT_DRAW_OPERATION_STROKE)
-            mTextRun->DrawToPath(mCtx->mThebesContext,
+            mTextRun->DrawToPath(mCtx->mThebes,
                                  point,
                                  0,
                                  mTextRun->GetLength(),
                                  nsnull,
                                  nsnull);
         else
             // mOp == TEXT_DRAW_OPERATION_FILL
-            mTextRun->Draw(mCtx->mThebesContext,
+            mTextRun->Draw(mCtx->mThebes,
                            point,
                            0,
                            mTextRun->GetLength(),
                            nsnull,
                            nsnull,
                            nsnull);
     }
 
@@ -2097,56 +2068,54 @@ nsCanvasRenderingContext2D::DrawOrMeasur
     processor.mPt.y += anchorY;
 
     processor.mPt.x *= processor.mAppUnitsPerDevPixel;
     processor.mPt.y *= processor.mAppUnitsPerDevPixel;
 
     // if text is over aMaxWidth, then scale the text horizontally such that its
     // width is precisely aMaxWidth
     if (aMaxWidth > 0 && totalWidth > aMaxWidth) {
-        mThebesContext->Save();
+        mThebes->Save();
         // translate the anchor point to 0, then scale and translate back
         gfxPoint trans(aX, 0);
-        mThebesContext->Translate(trans);
-        mThebesContext->Scale(aMaxWidth/totalWidth, 1);
-        mThebesContext->Translate(-trans);
+        mThebes->Translate(trans);
+        mThebes->Scale(aMaxWidth/totalWidth, 1);
+        mThebes->Translate(-trans);
     }
 
-    cairo_path_t* old_path;
+    nsRefPtr<gfxPath> path;
 
     // back up path if stroking
     if (aOp == nsCanvasRenderingContext2D::TEXT_DRAW_OPERATION_STROKE)
-        old_path = cairo_copy_path(mCairo);
+        path = mThebes->CopyPath();
     else
         ApplyStyle(STYLE_FILL);
 
     rv = bidiUtils->ProcessText(textToDraw.get(),
                                 textToDraw.Length(),
                                 isRTL ? NSBIDI_RTL : NSBIDI_LTR,
                                 presShell->GetPresContext(),
                                 processor,
                                 nsBidiPresUtils::MODE_DRAW,
                                 nsnull,
                                 0,
                                 nsnull);
 
     // stroke and restore path
     if (aOp == nsCanvasRenderingContext2D::TEXT_DRAW_OPERATION_STROKE) {
         ApplyStyle(STYLE_STROKE);
-        mThebesContext->Stroke();
-
-        cairo_new_path(mCairo);
-        if (old_path->status == CAIRO_STATUS_SUCCESS && old_path->num_data != 0)
-            cairo_append_path(mCairo, old_path);
-        cairo_path_destroy(old_path);
+        mThebes->Stroke();
+
+        mThebes->NewPath();
+        mThebes->AppendPath(path);
     }
 
     // have to restore the context if was modified for maxWidth
     if (aMaxWidth > 0 && totalWidth > aMaxWidth)
-        mThebesContext->Restore();
+        mThebes->Restore();
 
     if (NS_FAILED(rv))
         return rv;
 
     return Redraw();
 }
 
 NS_IMETHODIMP
@@ -2184,29 +2153,29 @@ nsCanvasRenderingContext2D::MozDrawText(
 
     PRUint32 aupdp;
     GetAppUnitsValues(&aupdp, NULL);
 
     gfxTextRunCache::AutoTextRun textRun;
     textRun = gfxTextRunCache::MakeTextRun(textdata,
                                            textToDraw.Length(),
                                            GetCurrentFontStyle(),
-                                           mThebesContext,
+                                           mThebes,
                                            aupdp,
                                            textrunflags);
 
     if(!textRun.get())
         return NS_ERROR_FAILURE;
 
     gfxPoint pt(0.0f,0.0f);
 
     // Fill color is text color
     ApplyStyle(STYLE_FILL);
     
-    textRun->Draw(mThebesContext,
+    textRun->Draw(mThebes,
                   pt,
                   /* offset = */ 0,
                   textToDraw.Length(),
                   nsnull,
                   nsnull,
                   nsnull);
     return NS_OK;
 }
@@ -2232,53 +2201,53 @@ nsCanvasRenderingContext2D::MozPathText(
 
     PRUint32 aupdp;
     GetAppUnitsValues(&aupdp, NULL);
 
     gfxTextRunCache::AutoTextRun textRun;
     textRun = gfxTextRunCache::MakeTextRun(textdata,
                                            textToPath.Length(),
                                            GetCurrentFontStyle(),
-                                           mThebesContext,
+                                           mThebes,
                                            aupdp,
                                            textrunflags);
 
     if(!textRun.get())
         return NS_ERROR_FAILURE;
 
     gfxPoint pt(0.0f,0.0f);
 
-    textRun->DrawToPath(mThebesContext,
+    textRun->DrawToPath(mThebes,
                         pt,
                         /* offset = */ 0,
                         textToPath.Length(),
                         nsnull,
                         nsnull);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::MozTextAlongPath(const nsAString& textToDraw, PRBool stroke)
 {
     // Most of this code is copied from its svg equivalent
-    nsRefPtr<gfxFlattenedPath> path(mThebesContext->GetFlattenedPath());
+    nsRefPtr<gfxFlattenedPath> path(mThebes->GetFlattenedPath());
 
     const PRUnichar* textdata;
     textToDraw.GetData(&textdata);
 
     PRUint32 textrunflags = 0;
 
     PRUint32 aupdp;
     GetAppUnitsValues(&aupdp, NULL);
 
     gfxTextRunCache::AutoTextRun textRun;
     textRun = gfxTextRunCache::MakeTextRun(textdata,
                                            textToDraw.Length(),
                                            GetCurrentFontStyle(),
-                                           mThebesContext,
+                                           mThebes,
                                            aupdp,
                                            textrunflags);
 
     if(!textRun.get())
         return NS_ERROR_FAILURE;
 
     struct PathChar
     {
@@ -2322,157 +2291,157 @@ nsCanvasRenderingContext2D::MozTextAlong
     else
         ApplyStyle(STYLE_FILL);
 
     for(PRUint32 i = 0; i < strLength; i++)
     {
         // Skip non-visible characters
         if(!cp[i].draw) continue;
 
-        gfxMatrix matrix = mThebesContext->CurrentMatrix();
+        gfxMatrix matrix = mThebes->CurrentMatrix();
 
         gfxMatrix rot;
         rot.Rotate(cp[i].angle);
-        mThebesContext->Multiply(rot);
+        mThebes->Multiply(rot);
 
         rot.Invert();
         rot.Scale(aupdp,aupdp);
         gfxPoint pt = rot.Transform(cp[i].pos);
 
         if(stroke) {
-            textRun->DrawToPath(mThebesContext, pt, i, 1, nsnull, nsnull);
+            textRun->DrawToPath(mThebes, pt, i, 1, nsnull, nsnull);
         } else {
-            textRun->Draw(mThebesContext, pt, i, 1, nsnull, nsnull, nsnull);
+            textRun->Draw(mThebes, pt, i, 1, nsnull, nsnull, nsnull);
         }
-        mThebesContext->SetMatrix(matrix);
+        mThebes->SetMatrix(matrix);
     }
 
     delete [] cp;
 
     return NS_OK;
 }
 
 //
 // line caps/joins
 //
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetLineWidth(float width)
 {
     if (!FloatValidate(width))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_set_line_width(mCairo, width);
+    mThebes->SetLineWidth(width);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::GetLineWidth(float *width)
 {
-    double d = cairo_get_line_width(mCairo);
-    *width = (float) d;
+    gfxFloat d = mThebes->CurrentLineWidth();
+    *width = static_cast<float>(d);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetLineCap(const nsAString& capstyle)
 {
-    cairo_line_cap_t cap;
+    gfxContext::GraphicsLineCap cap;
 
     if (capstyle.EqualsLiteral("butt"))
-        cap = CAIRO_LINE_CAP_BUTT;
+        cap = gfxContext::LINE_CAP_BUTT;
     else if (capstyle.EqualsLiteral("round"))
-        cap = CAIRO_LINE_CAP_ROUND;
+        cap = gfxContext::LINE_CAP_ROUND;
     else if (capstyle.EqualsLiteral("square"))
-        cap = CAIRO_LINE_CAP_SQUARE;
+        cap = gfxContext::LINE_CAP_SQUARE;
     else
         // XXX ERRMSG we need to report an error to developers here! (bug 329026)
         return NS_ERROR_NOT_IMPLEMENTED;
 
-    cairo_set_line_cap (mCairo, cap);
+    mThebes->SetLineCap(cap);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::GetLineCap(nsAString& capstyle)
 {
-    cairo_line_cap_t cap = cairo_get_line_cap(mCairo);
-
-    if (cap == CAIRO_LINE_CAP_BUTT)
+    gfxContext::GraphicsLineCap cap = mThebes->CurrentLineCap();
+
+    if (cap == gfxContext::LINE_CAP_BUTT)
         capstyle.AssignLiteral("butt");
-    else if (cap == CAIRO_LINE_CAP_ROUND)
+    else if (cap == gfxContext::LINE_CAP_ROUND)
         capstyle.AssignLiteral("round");
-    else if (cap == CAIRO_LINE_CAP_SQUARE)
+    else if (cap == gfxContext::LINE_CAP_SQUARE)
         capstyle.AssignLiteral("square");
     else
         return NS_ERROR_FAILURE;
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetLineJoin(const nsAString& joinstyle)
 {
-    cairo_line_join_t j;
+    gfxContext::GraphicsLineJoin j;
 
     if (joinstyle.EqualsLiteral("round"))
-        j = CAIRO_LINE_JOIN_ROUND;
+        j = gfxContext::LINE_JOIN_ROUND;
     else if (joinstyle.EqualsLiteral("bevel"))
-        j = CAIRO_LINE_JOIN_BEVEL;
+        j = gfxContext::LINE_JOIN_BEVEL;
     else if (joinstyle.EqualsLiteral("miter"))
-        j = CAIRO_LINE_JOIN_MITER;
+        j = gfxContext::LINE_JOIN_MITER;
     else
         // XXX ERRMSG we need to report an error to developers here! (bug 329026)
         return NS_ERROR_NOT_IMPLEMENTED;
 
-    cairo_set_line_join (mCairo, j);
+    mThebes->SetLineJoin(j);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::GetLineJoin(nsAString& joinstyle)
 {
-    cairo_line_join_t j = cairo_get_line_join(mCairo);
-
-    if (j == CAIRO_LINE_JOIN_ROUND)
+    gfxContext::GraphicsLineJoin j = mThebes->CurrentLineJoin();
+
+    if (j == gfxContext::LINE_JOIN_ROUND)
         joinstyle.AssignLiteral("round");
-    else if (j == CAIRO_LINE_JOIN_BEVEL)
+    else if (j == gfxContext::LINE_JOIN_BEVEL)
         joinstyle.AssignLiteral("bevel");
-    else if (j == CAIRO_LINE_JOIN_MITER)
+    else if (j == gfxContext::LINE_JOIN_MITER)
         joinstyle.AssignLiteral("miter");
     else
         return NS_ERROR_FAILURE;
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetMiterLimit(float miter)
 {
     if (!FloatValidate(miter))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_set_miter_limit(mCairo, miter);
+    mThebes->SetMiterLimit(miter);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::GetMiterLimit(float *miter)
 {
-    double d = cairo_get_miter_limit(mCairo);
-    *miter = (float) d;
+    gfxFloat d = mThebes->CurrentMiterLimit();
+    *miter = static_cast<float>(d);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::IsPointInPath(float x, float y, PRBool *retVal)
 {
     if (!FloatValidate(x,y))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    *retVal = !!cairo_in_fill(mCairo, x, y);
+    *retVal = mThebes->PointInFill(gfxPoint(x,y));
     return NS_OK;
 }
 
 //
 // image
 //
 
 // drawImage(in HTMLImageElement image, in float dx, in float dy);
@@ -2521,26 +2490,26 @@ nsCanvasRenderingContext2D::DrawImage()
     double dx,dy,dw,dh;
 
     nsCOMPtr<nsIDOMElement> imgElt;
     if (!ConvertJSValToXPCObject(getter_AddRefs(imgElt),
                                  NS_GET_IID(nsIDOMElement),
                                  ctx, argv[0]))
         return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
 
-    cairo_surface_t *imgSurf = nsnull;
-    cairo_matrix_t surfMat;
-    cairo_pattern_t *pat;
-    cairo_path_t *old_path;
     PRInt32 imgWidth, imgHeight;
     nsCOMPtr<nsIPrincipal> principal;
     PRBool forceWriteOnly = PR_FALSE;
-    rv = CairoSurfaceFromElement(imgElt, PR_FALSE,
-                                 &imgSurf, &imgWidth, &imgHeight,
-                                 getter_AddRefs(principal), &forceWriteOnly);
+    gfxMatrix matrix;
+    nsRefPtr<gfxPattern> pattern;
+    nsRefPtr<gfxPath> path;
+    nsRefPtr<gfxASurface> imgsurf;
+    rv = ThebesSurfaceFromElement(imgElt, PR_FALSE,
+                                  getter_AddRefs(imgsurf), &imgWidth, &imgHeight,
+                                  getter_AddRefs(principal), &forceWriteOnly);
     if (NS_FAILED(rv))
         return rv;
     DoDrawImageSecurityCheck(principal, forceWriteOnly);
 
 #define GET_ARG(dest,whicharg) \
     do { if (!ConvertJSValToDouble(dest, ctx, whicharg)) { rv = NS_ERROR_INVALID_ARG; goto FINISH; } } while (0)
 
     rv = NS_OK;
@@ -2592,121 +2561,112 @@ nsCanvasRenderingContext2D::DrawImage()
         sw < 0.0 || sw > (double) imgWidth ||
         sh < 0.0 || sh > (double) imgHeight ||
         dw < 0.0 || dh < 0.0)
     {
         // XXX ERRMSG we need to report an error to developers here! (bug 329026)
         rv = NS_ERROR_DOM_INDEX_SIZE_ERR;
         goto FINISH;
     }
-
-    cairo_matrix_init_translate(&surfMat, sx, sy);
-    cairo_matrix_scale(&surfMat, sw/dw, sh/dh);
-    pat = cairo_pattern_create_for_surface(imgSurf);
-    cairo_pattern_set_matrix(pat, &surfMat);
-
-    old_path = cairo_copy_path(mCairo);
-    cairo_save(mCairo);
-    cairo_translate(mCairo, dx, dy);
-    cairo_new_path(mCairo);
-    cairo_rectangle(mCairo, 0, 0, dw, dh);
-    cairo_set_source(mCairo, pat);
-    cairo_clip(mCairo);
-    cairo_paint_with_alpha(mCairo, CurrentState().globalAlpha);
-    cairo_restore(mCairo);
+    
+    matrix.Translate(gfxPoint(sx, sy));
+    matrix.Scale(sw/dw, sh/dh);
+
+    pattern = new gfxPattern(imgsurf);
+    pattern->SetMatrix(matrix);
+
+    path = mThebes->CopyPath();
+
+    mThebes->Save();
+    mThebes->Translate(gfxPoint(dx, dy));
+    mThebes->SetPattern(pattern);
+    mThebes->Clip(gfxRect(0, 0, dw, dh));
+    mThebes->Paint(CurrentState().globalAlpha);
+    mThebes->Restore();
 
 #if 1
-    // XXX cairo bug workaround; force a clip update on mCairo.
+    // XXX cairo bug workaround; force a clip update on mThebes.
     // Otherwise, a pixman clip gets left around somewhere, and pixman
     // (Render) does source clipping as well -- so we end up
     // compositing with an incorrect clip.  This only seems to affect
     // fallback cases, which happen when we have CSS scaling going on.
     // This will blow away the current path, but we already blew it
     // away in this function earlier.
-    cairo_new_path(mCairo);
-    cairo_rectangle(mCairo, 0, 0, 0, 0);
-    cairo_fill(mCairo);
+    mThebes->UpdateSurfaceClip();
 #endif
 
-    cairo_pattern_destroy(pat);
-
-    cairo_new_path(mCairo);
-    if (old_path->status == CAIRO_STATUS_SUCCESS && old_path->num_data != 0)
-        cairo_append_path(mCairo, old_path);
-    cairo_path_destroy(old_path);
+    mThebes->NewPath();
+    mThebes->AppendPath(path);
 
 FINISH:
-    if (imgSurf)
-        cairo_surface_destroy(imgSurf);
-
     if (NS_SUCCEEDED(rv))
         rv = Redraw();
 
     return rv;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetGlobalCompositeOperation(const nsAString& op)
 {
-    cairo_operator_t cairo_op;
-
-#define CANVAS_OP_TO_CAIRO_OP(cvsop,cairoop) \
+    gfxContext::GraphicsOperator thebes_op;
+
+#define CANVAS_OP_TO_THEBES_OP(cvsop,thebesop) \
     if (op.EqualsLiteral(cvsop))   \
-        cairo_op = CAIRO_OPERATOR_##cairoop;
+        thebes_op = gfxContext::OPERATOR_##thebesop;
 
     // XXX "darker" isn't really correct
-    CANVAS_OP_TO_CAIRO_OP("clear", CLEAR)
-    else CANVAS_OP_TO_CAIRO_OP("copy", SOURCE)
-    else CANVAS_OP_TO_CAIRO_OP("darker", SATURATE)  // XXX
-    else CANVAS_OP_TO_CAIRO_OP("destination-atop", DEST_ATOP)
-    else CANVAS_OP_TO_CAIRO_OP("destination-in", DEST_IN)
-    else CANVAS_OP_TO_CAIRO_OP("destination-out", DEST_OUT)
-    else CANVAS_OP_TO_CAIRO_OP("destination-over", DEST_OVER)
-    else CANVAS_OP_TO_CAIRO_OP("lighter", ADD)
-    else CANVAS_OP_TO_CAIRO_OP("source-atop", ATOP)
-    else CANVAS_OP_TO_CAIRO_OP("source-in", IN)
-    else CANVAS_OP_TO_CAIRO_OP("source-out", OUT)
-    else CANVAS_OP_TO_CAIRO_OP("source-over", OVER)
-    else CANVAS_OP_TO_CAIRO_OP("xor", XOR)
+    CANVAS_OP_TO_THEBES_OP("clear", CLEAR)
+    else CANVAS_OP_TO_THEBES_OP("copy", SOURCE)
+    else CANVAS_OP_TO_THEBES_OP("darker", SATURATE)  // XXX
+    else CANVAS_OP_TO_THEBES_OP("destination-atop", DEST_ATOP)
+    else CANVAS_OP_TO_THEBES_OP("destination-in", DEST_IN)
+    else CANVAS_OP_TO_THEBES_OP("destination-out", DEST_OUT)
+    else CANVAS_OP_TO_THEBES_OP("destination-over", DEST_OVER)
+    else CANVAS_OP_TO_THEBES_OP("lighter", ADD)
+    else CANVAS_OP_TO_THEBES_OP("source-atop", ATOP)
+    else CANVAS_OP_TO_THEBES_OP("source-in", IN)
+    else CANVAS_OP_TO_THEBES_OP("source-out", OUT)
+    else CANVAS_OP_TO_THEBES_OP("source-over", OVER)
+    else CANVAS_OP_TO_THEBES_OP("xor", XOR)
     // not part of spec, kept here for compat
-    else CANVAS_OP_TO_CAIRO_OP("over", OVER)
+    else CANVAS_OP_TO_THEBES_OP("over", OVER)
     else return NS_ERROR_NOT_IMPLEMENTED;
 
-#undef CANVAS_OP_TO_CAIRO_OP
-
-    cairo_set_operator(mCairo, cairo_op);
+#undef CANVAS_OP_TO_THEBES_OP
+
+    mThebes->SetOperator(thebes_op);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::GetGlobalCompositeOperation(nsAString& op)
 {
-    cairo_operator_t cairo_op = cairo_get_operator(mCairo);
-
-#define CANVAS_OP_TO_CAIRO_OP(cvsop,cairoop) \
-    if (cairo_op == CAIRO_OPERATOR_##cairoop) \
+    gfxContext::GraphicsOperator thebes_op = mThebes->CurrentOperator();
+
+#define CANVAS_OP_TO_THEBES_OP(cvsop,thebesop) \
+    if (thebes_op == gfxContext::OPERATOR_##thebesop) \
         op.AssignLiteral(cvsop);
 
     // XXX "darker" isn't really correct
-    CANVAS_OP_TO_CAIRO_OP("clear", CLEAR)
-    else CANVAS_OP_TO_CAIRO_OP("copy", SOURCE)
-    else CANVAS_OP_TO_CAIRO_OP("darker", SATURATE)  // XXX
-    else CANVAS_OP_TO_CAIRO_OP("destination-atop", DEST_ATOP)
-    else CANVAS_OP_TO_CAIRO_OP("destination-in", DEST_IN)
-    else CANVAS_OP_TO_CAIRO_OP("destination-out", DEST_OUT)
-    else CANVAS_OP_TO_CAIRO_OP("destination-over", DEST_OVER)
-    else CANVAS_OP_TO_CAIRO_OP("lighter", ADD)
-    else CANVAS_OP_TO_CAIRO_OP("source-atop", ATOP)
-    else CANVAS_OP_TO_CAIRO_OP("source-in", IN)
-    else CANVAS_OP_TO_CAIRO_OP("source-out", OUT)
-    else CANVAS_OP_TO_CAIRO_OP("source-over", OVER)
-    else CANVAS_OP_TO_CAIRO_OP("xor", XOR)
+    CANVAS_OP_TO_THEBES_OP("clear", CLEAR)
+    else CANVAS_OP_TO_THEBES_OP("copy", SOURCE)
+    else CANVAS_OP_TO_THEBES_OP("darker", SATURATE)  // XXX
+    else CANVAS_OP_TO_THEBES_OP("destination-atop", DEST_ATOP)
+    else CANVAS_OP_TO_THEBES_OP("destination-in", DEST_IN)
+    else CANVAS_OP_TO_THEBES_OP("destination-out", DEST_OUT)
+    else CANVAS_OP_TO_THEBES_OP("destination-over", DEST_OVER)
+    else CANVAS_OP_TO_THEBES_OP("lighter", ADD)
+    else CANVAS_OP_TO_THEBES_OP("source-atop", ATOP)
+    else CANVAS_OP_TO_THEBES_OP("source-in", IN)
+    else CANVAS_OP_TO_THEBES_OP("source-out", OUT)
+    else CANVAS_OP_TO_THEBES_OP("source-over", OVER)
+    else CANVAS_OP_TO_THEBES_OP("xor", XOR)
     else return NS_ERROR_FAILURE;
 
-#undef CANVAS_OP_TO_CAIRO_OP
+#undef CANVAS_OP_TO_THEBES_OP
 
     return NS_OK;
 }
 
 
 //
 // Utils
 //
@@ -2757,32 +2717,32 @@ nsCanvasRenderingContext2D::ConvertJSVal
       WrapJS(aContext, JSVAL_TO_OBJECT(aValue), aIID, (void**)aSupports);
 
     return NS_SUCCEEDED(rv);
   }
 
   return JS_FALSE;
 }
 
-/* cairo ARGB32 surfaces are ARGB stored as a packed 32-bit integer; on little-endian
+/* thebes ARGB32 surfaces are ARGB stored as a packed 32-bit integer; on little-endian
  * platforms, they appear as BGRA bytes in the surface data.  The color values are also
  * stored with premultiplied alpha.
  *
  * If forceCopy is FALSE, a surface may be returned that's only valid during the current
  * operation.  If it's TRUE, a copy will always be made that can safely be retained.
  */
 
 nsresult
-nsCanvasRenderingContext2D::CairoSurfaceFromElement(nsIDOMElement *imgElt,
-                                                    PRBool forceCopy,
-                                                    cairo_surface_t **aCairoSurface,
-                                                    PRInt32 *widthOut,
-                                                    PRInt32 *heightOut,
-                                                    nsIPrincipal **prinOut,
-                                                    PRBool *forceWriteOnlyOut)
+nsCanvasRenderingContext2D::ThebesSurfaceFromElement(nsIDOMElement *imgElt,
+                                                     PRBool forceCopy,
+                                                     gfxASurface **aSurface,
+                                                     PRInt32 *widthOut,
+                                                     PRInt32 *heightOut,
+                                                     nsIPrincipal **prinOut,
+                                                     PRBool *forceWriteOnlyOut)
 {
     nsresult rv;
 
     nsCOMPtr<imgIContainer> imgContainer;
 
     nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(imgElt);
     if (imageLoader) {
         nsCOMPtr<imgIRequest> imgRequest;
@@ -2818,17 +2778,17 @@ nsCanvasRenderingContext2D::CairoSurface
 
             nsRefPtr<gfxASurface> sourceSurface;
 
             if (!forceCopy && canvas->CountContexts() == 1) {
                 nsICanvasRenderingContextInternal *srcCanvas = canvas->GetContextAtIndex(0);
                 rv = srcCanvas->GetThebesSurface(getter_AddRefs(sourceSurface));
                 // force a copy if we couldn't get the surface, or if it's
                 // the same as what we have
-                if (sourceSurface == mThebesSurface || NS_FAILED(rv))
+                if (sourceSurface == mSurface || NS_FAILED(rv))
                     sourceSurface = nsnull;
             }
 
             if (sourceSurface == nsnull) {
                 nsRefPtr<gfxASurface> surf =
                     gfxPlatform::GetPlatform()->CreateOffscreenSurface
                     (gfxIntSize(w, h), gfxASurface::ImageFormatARGB32);
                 nsRefPtr<gfxContext> ctx = new gfxContext(surf);
@@ -2840,18 +2800,17 @@ nsCanvasRenderingContext2D::CairoSurface
                 ctx->SetOperator(gfxContext::OPERATOR_OVER);
 
                 rv = canvas->RenderContexts(ctx);
                 if (NS_FAILED(rv))
                     return rv;
                 sourceSurface = surf;
             }
 
-            *aCairoSurface = sourceSurface->CairoSurface();
-            cairo_surface_reference(*aCairoSurface);
+            *aSurface = sourceSurface.forget().get();
             *widthOut = w;
             *heightOut = h;
 
             NS_ADDREF(*prinOut = node->NodePrincipal());
             *forceWriteOnlyOut = canvas->IsWriteOnly();
 
             return NS_OK;
         } else {
@@ -2888,18 +2847,17 @@ nsCanvasRenderingContext2D::CairoSurface
         gfxsurf = new gfxImageSurface (gfxIntSize(imgWidth, imgHeight), gfxASurface::ImageFormatARGB32);
         nsRefPtr<gfxContext> ctx = new gfxContext(gfxsurf);
 
         ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
         ctx->SetPattern(gfxpattern);
         ctx->Paint();
     }
 
-    *aCairoSurface = gfxsurf->CairoSurface();
-    cairo_surface_reference (*aCairoSurface);
+    *aSurface = gfxsurf.forget().get();
 
     return NS_OK;
 }
 
 /* Check that the rect [x,y,w,h] is a valid subrect of [0,0,realWidth,realHeight]
  * without overflowing any integers and the like.
  */
 PRBool
@@ -2995,20 +2953,20 @@ nsCanvasRenderingContext2D::DrawWindow(n
     nsIPresShell* presShell = presContext->PresShell();
     NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
 
     nsRect r(nsPresContext::CSSPixelsToAppUnits(aX),
              nsPresContext::CSSPixelsToAppUnits(aY),
              nsPresContext::CSSPixelsToAppUnits(aW),
              nsPresContext::CSSPixelsToAppUnits(aH));
     presShell->RenderDocument(r, PR_FALSE, PR_TRUE, bgColor,
-                              mThebesContext);
+                              mThebes);
 
     // get rid of the pattern surface ref, just in case
-    cairo_set_source_rgba (mCairo, 1, 1, 1, 1);
+    mThebes->SetColor(gfxRGBA(1,1,1,1));
     DirtyAllStyles();
 
     Redraw();
 
     return rv;
 }
 
 //
@@ -3057,25 +3015,34 @@ nsCanvasRenderingContext2D::GetImageData
 
     nsAutoArrayPtr<PRUint8> surfaceData (new (std::nothrow) PRUint8[w * h * 4]);
     int surfaceDataStride = w*4;
     int surfaceDataOffset = 0;
 
     if (!surfaceData)
         return NS_ERROR_OUT_OF_MEMORY;
 
-    cairo_surface_t *tmpsurf = cairo_image_surface_create_for_data (surfaceData,
-                                                                    CAIRO_FORMAT_ARGB32,
-                                                                    w, h, w*4);
-    cairo_t *tmpcr = cairo_create (tmpsurf);
-    cairo_set_operator (tmpcr, CAIRO_OPERATOR_SOURCE);
-    cairo_set_source_surface (tmpcr, mSurface, -(int)x, -(int)y);
-    cairo_paint (tmpcr);
-    cairo_destroy (tmpcr);
-    cairo_surface_destroy (tmpsurf);
+    nsRefPtr<gfxImageSurface> tmpsurf = new gfxImageSurface(surfaceData,
+                                                            gfxIntSize(w, h),
+                                                            w * 4,
+                                                            gfxASurface::ImageFormatARGB32);
+    if (!tmpsurf || tmpsurf->CairoStatus())
+        return NS_ERROR_FAILURE;
+
+    nsRefPtr<gfxContext> tmpctx = new gfxContext(tmpsurf);
+
+    if (!tmpctx || tmpctx->HasError())
+        return NS_ERROR_FAILURE;
+
+    tmpctx->SetOperator(gfxContext::OPERATOR_SOURCE);
+    tmpctx->SetSource(mSurface, gfxPoint(-(int)x, -(int)y));
+    tmpctx->Paint();
+
+    tmpctx = nsnull;
+    tmpsurf = nsnull;
 
     PRUint32 len = w * h * 4;
     if (len > (((PRUint32)0xfff00000)/sizeof(jsval)))
         return NS_ERROR_INVALID_ARG;
 
     nsAutoArrayPtr<jsval> jsvector(new (std::nothrow) jsval[w * h * 4]);
     if (!jsvector)
         return NS_ERROR_OUT_OF_MEMORY;
@@ -3202,17 +3169,16 @@ nsCanvasRenderingContext2D::PutImageData
         !JS_GetArrayLength(ctx, dataArray, &arrayLen) ||
         arrayLen < (jsuint)(w * h * 4))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
     nsAutoArrayPtr<PRUint8> imageBuffer(new (std::nothrow) PRUint8[w * h * 4]);
     if (!imageBuffer)
         return NS_ERROR_OUT_OF_MEMORY;
 
-    cairo_surface_t *imgsurf;
     PRUint8 *imgPtr = imageBuffer.get();
     jsval vr, vg, vb, va;
     PRUint8 ir, ig, ib, ia;
     for (int32 j = 0; j < h; j++) {
         for (int32 i = 0; i < w; i++) {
             if (!JS_GetElement(ctx, dataArray, (j*w*4) + i*4 + 0, &vr) ||
                 !JS_GetElement(ctx, dataArray, (j*w*4) + i*4 + 1, &vg) ||
                 !JS_GetElement(ctx, dataArray, (j*w*4) + i*4 + 2, &vb) ||
@@ -3250,45 +3216,47 @@ nsCanvasRenderingContext2D::PutImageData
             *imgPtr++ = ia;
             *imgPtr++ = ir;
             *imgPtr++ = ig;
             *imgPtr++ = ib;
 #endif
         }
     }
 
-    imgsurf = cairo_image_surface_create_for_data (imageBuffer.get(),
-                                                   CAIRO_FORMAT_ARGB32,
-                                                   w, h, w*4);
-    cairo_path_t *old_path = cairo_copy_path (mCairo);
-    cairo_save (mCairo);
-    cairo_identity_matrix (mCairo);
-    cairo_translate (mCairo, x, y);
-    cairo_new_path (mCairo);
-    cairo_rectangle (mCairo, 0, 0, w, h);
-    cairo_set_source_surface (mCairo, imgsurf, 0, 0);
-    cairo_set_operator (mCairo, CAIRO_OPERATOR_SOURCE);
-    cairo_fill (mCairo);
-    cairo_restore (mCairo);
-    cairo_new_path (mCairo);
-    if (old_path->status == CAIRO_STATUS_SUCCESS && old_path->num_data != 0)
-        cairo_append_path (mCairo, old_path);
-    cairo_path_destroy (old_path);
-
-    cairo_surface_destroy (imgsurf);
+    nsRefPtr<gfxImageSurface> imgsurf = new gfxImageSurface(imageBuffer.get(),
+                                                            gfxIntSize(w, h),
+                                                            w * 4,
+                                                            gfxASurface::ImageFormatARGB32);
+    if (!imgsurf || imgsurf->CairoStatus())
+        return NS_ERROR_FAILURE;
+
+    nsRefPtr<gfxPath> path = mThebes->CopyPath();
+
+    mThebes->Save();
+    mThebes->IdentityMatrix();
+    mThebes->Translate(gfxPoint(x, y));
+    mThebes->NewPath();
+    mThebes->Rectangle(gfxRect(0, 0, w, h));
+    mThebes->SetSource(imgsurf, gfxPoint(0, 0));
+    mThebes->SetOperator(gfxContext::OPERATOR_SOURCE);
+    mThebes->Fill();
+    mThebes->Restore();
+
+    mThebes->NewPath();
+    mThebes->AppendPath(path);
 
     return Redraw();
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::GetThebesSurface(gfxASurface **surface)
 {
-    if (!mThebesSurface) {
+    if (!mSurface) {
         *surface = nsnull;
         return NS_ERROR_NOT_AVAILABLE;
     }
 
-    *surface = mThebesSurface.get();
+    *surface = mSurface.get();
     NS_ADDREF(*surface);
 
     return NS_OK;
 }
 
--- 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/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" ];
--- 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/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));