diff --git a/content/base/src/nsDOMLists.h b/content/base/src/nsDOMLists.h
index b1ab7610422dea87dec328428e86ec4045493561..c9bbe5f94dc5a50292a1c83bd89b11e87705d29f 100644
--- a/content/base/src/nsDOMLists.h
+++ b/content/base/src/nsDOMLists.h
@@ -28,6 +28,11 @@ public:
     return mNames.AppendElement(aName) != nsnull;
   }
 
+  void Clear()
+  {
+    mNames.Clear();
+  }
+
 private:
   nsTArray<nsString> mNames;
 };
diff --git a/content/base/src/nsDOMSettableTokenList.h b/content/base/src/nsDOMSettableTokenList.h
index 867bf1753d6fb645ed6a7938b2c700a8c26f0a47..3ca8a08ec8e6a15cc3959b9ec4ec838e96edc0ba 100644
--- a/content/base/src/nsDOMSettableTokenList.h
+++ b/content/base/src/nsDOMSettableTokenList.h
@@ -16,6 +16,8 @@
 class nsGenericElement;
 class nsIAtom;
 
+// nsISupports must be on the primary inheritance chain 
+// because nsDOMSettableTokenList is traversed by nsGenericElement.
 class nsDOMSettableTokenList : public nsDOMTokenList,
                                public nsIDOMDOMSettableTokenList
 {
@@ -30,7 +32,6 @@ public:
   virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
                                bool *triedToWrap);
 
-protected:
   virtual ~nsDOMSettableTokenList();
 };
 
diff --git a/content/base/src/nsDOMTokenList.h b/content/base/src/nsDOMTokenList.h
index 1924613e397b484b1cee9e7f8589311d9fe40569..72befdd37ba9ac0bc1febe6286677ed1e3ddc797 100644
--- a/content/base/src/nsDOMTokenList.h
+++ b/content/base/src/nsDOMTokenList.h
@@ -14,6 +14,8 @@
 
 class nsAttrValue;
 
+// nsISupports must be on the primary inheritance chain 
+// because nsDOMSettableTokenList is traversed by nsGenericElement.
 class nsDOMTokenList : public nsIDOMDOMTokenList,
                        public nsWrapperCache
 {
@@ -34,9 +36,6 @@ public:
     return mElement;
   }
 
-protected:
-  ~nsDOMTokenList();
-
   const nsAttrValue* GetParsedAttr() {
     if (!mElement) {
       return nsnull;
@@ -44,6 +43,9 @@ protected:
     return mElement->GetAttrInfo(kNameSpaceID_None, mAttrAtom).mValue;
   }
 
+protected:
+  ~nsDOMTokenList();
+
   nsresult CheckToken(const nsAString& aStr);
   void AddInternal(const nsAttrValue* aAttr, const nsAString& aToken);
   void RemoveInternal(const nsAttrValue* aAttr, const nsAString& aToken);
diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp
index 5dd1576292fa258fc4b7f9e86e90e5bfd3498ef5..c082991d4c0bdb72faa7130cbd0ab67d1be35c6a 100644
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -4487,9 +4487,16 @@ ContentUnbinder* ContentUnbinder::sContentUnbinder = nsnull;
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGenericElement)
   nsINode::Unlink(tmp);
 
-  if (tmp->HasProperties() && tmp->IsXUL()) {
-    tmp->DeleteProperty(nsGkAtoms::contextmenulistener);
-    tmp->DeleteProperty(nsGkAtoms::popuplistener);
+  if (tmp->HasProperties()) {
+    if (tmp->IsHTML()) {
+      tmp->DeleteProperty(nsGkAtoms::microdataProperties);
+      tmp->DeleteProperty(nsGkAtoms::itemtype);
+      tmp->DeleteProperty(nsGkAtoms::itemref);
+      tmp->DeleteProperty(nsGkAtoms::itemprop);
+    } else if (tmp->IsXUL()) {
+      tmp->DeleteProperty(nsGkAtoms::contextmenulistener);
+      tmp->DeleteProperty(nsGkAtoms::popuplistener);
+    }
   }
 
   // Unlink child content (and unbind our subtree).
@@ -4987,14 +4994,25 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGenericElement)
 
   tmp->OwnerDoc()->BindingManager()->Traverse(tmp, cb);
 
-  if (tmp->HasProperties() && tmp->IsXUL()) {
-    nsISupports* property =
-      static_cast<nsISupports*>
-                 (tmp->GetProperty(nsGkAtoms::contextmenulistener));
-    cb.NoteXPCOMChild(property);
-    property = static_cast<nsISupports*>
-                          (tmp->GetProperty(nsGkAtoms::popuplistener));
-    cb.NoteXPCOMChild(property);
+  if (tmp->HasProperties()) {
+    if (tmp->IsHTML()) {
+      nsISupports* property = static_cast<nsISupports*>
+                                         (tmp->GetProperty(nsGkAtoms::microdataProperties));
+      cb.NoteXPCOMChild(property);
+      property = static_cast<nsISupports*>(tmp->GetProperty(nsGkAtoms::itemref));
+      cb.NoteXPCOMChild(property);
+      property = static_cast<nsISupports*>(tmp->GetProperty(nsGkAtoms::itemprop));
+      cb.NoteXPCOMChild(property);
+      property = static_cast<nsISupports*>(tmp->GetProperty(nsGkAtoms::itemtype));
+      cb.NoteXPCOMChild(property);
+    } else if (tmp->IsXUL()) {
+      nsISupports* property = static_cast<nsISupports*>
+                                         (tmp->GetProperty(nsGkAtoms::contextmenulistener));
+      cb.NoteXPCOMChild(property);
+      property = static_cast<nsISupports*>
+                            (tmp->GetProperty(nsGkAtoms::popuplistener));
+      cb.NoteXPCOMChild(property);
+    }
   }
 
   // Traverse attribute names and child content.
diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h
index f25b95077f0d84d9403c8959384c2f666258ef87..ebd1c5d614b6d12405df6440fcee334ff2a4a77c 100644
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -536,6 +536,7 @@ GK_ATOM(message, "message")
 GK_ATOM(meta, "meta")
 GK_ATOM(meter, "meter")
 GK_ATOM(method, "method")
+GK_ATOM(microdataProperties, "microdataProperties")
 GK_ATOM(middle, "middle")
 GK_ATOM(min, "min")
 GK_ATOM(minheight, "minheight")
diff --git a/content/html/content/public/nsHTMLAudioElement.h b/content/html/content/public/nsHTMLAudioElement.h
index 1538c234134ffcb3f0e34019b7bfdc2ec16fb4e7..0aab9fc804cdae6f2270a3f8a2908de81897b6ea 100644
--- a/content/html/content/public/nsHTMLAudioElement.h
+++ b/content/html/content/public/nsHTMLAudioElement.h
@@ -49,6 +49,10 @@ public:
   virtual nsXPCClassInfo* GetClassInfo();
 
   virtual nsIDOMNode* AsDOMNode() { return this; }
+
+protected:
+  virtual void GetItemValueText(nsAString& text);
+  virtual void SetItemValueText(const nsAString& text);
 };
 
 #endif
diff --git a/content/html/content/public/nsHTMLVideoElement.h b/content/html/content/public/nsHTMLVideoElement.h
index 4dfad6316ac26911c507737bf9497940472400ac..1a66fd925743ecb803235ba39f2d22f25a07aa8b 100644
--- a/content/html/content/public/nsHTMLVideoElement.h
+++ b/content/html/content/public/nsHTMLVideoElement.h
@@ -60,6 +60,10 @@ public:
   virtual nsXPCClassInfo* GetClassInfo();
 
   virtual nsIDOMNode* AsDOMNode() { return this; }
+
+protected:
+  virtual void GetItemValueText(nsAString& text);
+  virtual void SetItemValueText(const nsAString& text);
 };
 
 #endif
diff --git a/content/html/content/src/HTMLPropertiesCollection.cpp b/content/html/content/src/HTMLPropertiesCollection.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7504ea6d6c22ecad30398d377fc15985e58ef13a
--- /dev/null
+++ b/content/html/content/src/HTMLPropertiesCollection.cpp
@@ -0,0 +1,610 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set tw=80 expandtab softtabstop=2 ts=2 sw=2: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "HTMLPropertiesCollection.h"
+#include "dombindings.h"
+#include "nsIDocument.h"
+#include "nsContentUtils.h"
+#include "nsGenericHTMLElement.h"
+#include "nsVariant.h"
+#include "nsDOMSettableTokenList.h"
+#include "nsAttrValue.h"
+
+DOMCI_DATA(HTMLPropertiesCollection, mozilla::dom::HTMLPropertiesCollection)
+DOMCI_DATA(PropertyNodeList, mozilla::dom::PropertyNodeList)
+
+namespace mozilla {
+namespace dom {
+
+static PLDHashOperator
+TraverseNamedProperties(const nsAString& aKey, PropertyNodeList* aEntry, void* aData)
+{
+  nsCycleCollectionTraversalCallback* cb = static_cast<nsCycleCollectionTraversalCallback*>(aData);
+  cb->NoteXPCOMChild(static_cast<nsIDOMPropertyNodeList*>(aEntry));
+  return PL_DHASH_NEXT;
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLPropertiesCollection)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(HTMLPropertiesCollection)
+  // SetDocument(nsnull) ensures that we remove ourselves as a mutation observer
+  tmp->SetDocument(nsnull);
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRoot)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mNames)
+  tmp->mNamedItemEntries.Clear();
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mProperties)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(HTMLPropertiesCollection)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDoc)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRoot)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNames)
+  tmp->mNamedItemEntries.EnumerateRead(TraverseNamedProperties, &cb);
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_OF_NSCOMPTR(mProperties)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(HTMLPropertiesCollection)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+HTMLPropertiesCollection::HTMLPropertiesCollection(nsGenericHTMLElement* aRoot)
+  : mRoot(aRoot)
+  , mDoc(aRoot->GetCurrentDoc())
+  , mIsDirty(true)
+{
+  SetIsDOMBinding();
+  mNames = new PropertyStringList(this);
+  if (mDoc) {
+    mDoc->AddMutationObserver(this);
+  }
+  mNamedItemEntries.Init();
+}
+
+HTMLPropertiesCollection::~HTMLPropertiesCollection()
+{
+  if (mDoc) {
+    mDoc->RemoveMutationObserver(this);
+  }
+}
+
+NS_INTERFACE_TABLE_HEAD(HTMLPropertiesCollection)
+    NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+    NS_INTERFACE_TABLE4(HTMLPropertiesCollection,
+                        nsIDOMHTMLPropertiesCollection,
+                        nsIDOMHTMLCollection,
+                        nsIHTMLCollection,
+                        nsIMutationObserver)
+    NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(HTMLPropertiesCollection)
+    NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(HTMLPropertiesCollection)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(HTMLPropertiesCollection)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(HTMLPropertiesCollection)
+
+
+static PLDHashOperator
+SetPropertyListDocument(const nsAString& aKey, PropertyNodeList* aEntry, void* aData)
+{
+  aEntry->SetDocument(static_cast<nsIDocument*>(aData));
+  return PL_DHASH_NEXT;
+}
+
+void
+HTMLPropertiesCollection::SetDocument(nsIDocument* aDocument) {
+  if (mDoc) {
+    mDoc->RemoveMutationObserver(this);
+  }
+  mDoc = aDocument;
+  if (mDoc) {
+    mDoc->AddMutationObserver(this);
+  }
+  mNamedItemEntries.EnumerateRead(SetPropertyListDocument, aDocument);
+  mIsDirty = true;
+}
+
+JSObject*
+HTMLPropertiesCollection::WrapObject(JSContext* cx, JSObject* scope,
+                                     bool* triedToWrap)
+{
+  return mozilla::dom::binding::HTMLPropertiesCollection::create(cx, scope, this,
+                                                                 triedToWrap);
+}
+
+NS_IMETHODIMP
+HTMLPropertiesCollection::GetLength(PRUint32* aLength)
+{
+  EnsureFresh();
+  *aLength = mProperties.Length();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HTMLPropertiesCollection::Item(PRUint32 aIndex, nsIDOMNode** aResult)
+{
+  EnsureFresh();
+  nsGenericHTMLElement* property = mProperties.SafeElementAt(aIndex);
+  *aResult = property ? property->AsDOMNode() : NULL;
+  NS_IF_ADDREF(*aResult);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HTMLPropertiesCollection::NamedItem(const nsAString& aName,
+                                    nsIDOMNode** aResult)
+{
+  *aResult = NULL;
+  return NS_OK;
+}
+
+nsISupports*
+HTMLPropertiesCollection::GetNamedItem(const nsAString& aName,
+                                       nsWrapperCache **aCache)
+{
+  EnsureFresh();
+  if (!mNames->ContainsInternal(aName)) {
+    *aCache = NULL;
+    return NULL;
+  }
+
+  nsRefPtr<PropertyNodeList> propertyList;
+  if (!mNamedItemEntries.Get(aName, getter_AddRefs(propertyList))) {
+    propertyList = new PropertyNodeList(this, mRoot, aName);
+    mNamedItemEntries.Put(aName, propertyList);
+  }
+  *aCache = propertyList;
+  return static_cast<nsIDOMPropertyNodeList*>(propertyList);
+}
+
+nsIContent*
+HTMLPropertiesCollection::GetNodeAt(PRUint32 aIndex)
+{
+  EnsureFresh();
+  return mProperties.SafeElementAt(aIndex);
+}
+
+nsINode*
+HTMLPropertiesCollection::GetParentObject()
+{
+  return mRoot;
+}
+
+NS_IMETHODIMP
+HTMLPropertiesCollection::NamedItem(const nsAString& aName,
+                                    nsIDOMPropertyNodeList** aResult)
+{
+  EnsureFresh();
+ 
+  nsRefPtr<PropertyNodeList> propertyList;
+  if (!mNamedItemEntries.Get(aName, getter_AddRefs(propertyList))) {
+    propertyList = new PropertyNodeList(this, mRoot, aName);
+    mNamedItemEntries.Put(aName, propertyList);
+  }
+  propertyList.forget(aResult);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HTMLPropertiesCollection::GetNames(nsIDOMDOMStringList** aResult)
+{
+  EnsureFresh();
+  NS_ADDREF(*aResult = mNames);
+  return NS_OK;
+}
+
+void
+HTMLPropertiesCollection::AttributeChanged(nsIDocument *aDocument, Element* aElement,
+                                           PRInt32 aNameSpaceID, nsIAtom* aAttribute,
+                                           PRInt32 aModType)
+{
+  mIsDirty = true;
+}
+
+void
+HTMLPropertiesCollection::ContentAppended(nsIDocument* aDocument, nsIContent* aContainer,
+                                          nsIContent* aFirstNewContent,
+                                          PRInt32 aNewIndexInContainer)
+{
+  mIsDirty = true;
+}
+
+void
+HTMLPropertiesCollection::ContentInserted(nsIDocument *aDocument,
+                                          nsIContent* aContainer,
+                                          nsIContent* aChild,
+                                          PRInt32 aIndexInContainer)
+{
+  mIsDirty = true;
+}
+
+void
+HTMLPropertiesCollection::ContentRemoved(nsIDocument *aDocument,
+                                         nsIContent* aContainer,
+                                         nsIContent* aChild,
+                                         PRInt32 aIndexInContainer,
+                                         nsIContent* aPreviousSibling)
+{
+  mIsDirty = true;
+}
+
+class TreeOrderComparator {
+  public:
+    bool Equals(const nsGenericHTMLElement* aElem1,
+                const nsGenericHTMLElement* aElem2) const {
+      return aElem1 == aElem2;
+    }
+    bool LessThan(const nsGenericHTMLElement* aElem1,
+                  const nsGenericHTMLElement* aElem2) const {
+      return nsContentUtils::PositionIsBefore(const_cast<nsGenericHTMLElement*>(aElem1),
+                                              const_cast<nsGenericHTMLElement*>(aElem2));
+    }
+};
+
+static PLDHashOperator
+MarkDirty(const nsAString& aKey, PropertyNodeList* aEntry, void* aData)
+{
+  aEntry->SetDirty();
+  return PL_DHASH_NEXT;
+}
+
+void
+HTMLPropertiesCollection::EnsureFresh()
+{
+  if (mDoc && !mIsDirty) {
+    return;
+  }
+  mIsDirty = false;
+
+  mProperties.Clear();
+  mNames->Clear();
+  // We don't clear NamedItemEntries because the PropertyNodeLists must be live.
+  mNamedItemEntries.EnumerateRead(MarkDirty, NULL);
+  if (!mRoot->HasAttr(kNameSpaceID_None, nsGkAtoms::itemscope)) {
+    return;
+  }
+
+  CrawlProperties();
+  TreeOrderComparator comparator;
+  mProperties.Sort(comparator);
+
+  // Create the names DOMStringList
+  PRUint32 count = mProperties.Length();
+  for (PRUint32 i = 0; i < count; ++i) {
+    const nsAttrValue* attr = mProperties.ElementAt(i)->GetParsedAttr(nsGkAtoms::itemprop); 
+    for (PRUint32 i = 0; i < attr->GetAtomCount(); i++) {
+      nsDependentAtomString propName(attr->AtomAt(i));
+      // ContainsInternal must not call EnsureFresh
+      bool contains = mNames->ContainsInternal(propName);
+      if (!contains) {
+        mNames->Add(propName);
+      }
+    }
+  }
+}
+  
+static Element*
+GetElementByIdForConnectedSubtree(nsIContent* aContent, const nsIAtom* aId)
+{
+  aContent = static_cast<nsIContent*>(aContent->SubtreeRoot());
+  do {
+    if (aContent->GetID() == aId) {
+      return aContent->AsElement();
+    }
+    aContent = aContent->GetNextNode();
+  } while(aContent);
+  
+  return NULL;
+}
+
+void
+HTMLPropertiesCollection::CrawlProperties()
+{
+  nsIDocument* doc = mRoot->GetCurrentDoc();
+ 
+  const nsAttrValue* attr = mRoot->GetParsedAttr(nsGkAtoms::itemref);
+  if (attr) {
+    for (PRUint32 i = 0; i < attr->GetAtomCount(); i++) {
+      nsIAtom* ref = attr->AtomAt(i);
+      Element* element;
+      if (doc) {
+        element = doc->GetElementById(nsDependentAtomString(ref));
+      } else {
+        element = GetElementByIdForConnectedSubtree(mRoot, ref);
+      }
+      if (element && element != mRoot) {
+        CrawlSubtree(element);
+      }
+    }
+  }
+  
+  CrawlSubtree(mRoot);
+}
+
+void
+HTMLPropertiesCollection::CrawlSubtree(Element* aElement)
+{
+  nsIContent* aContent = aElement;
+  while (aContent) {
+    // We must check aContent against mRoot because 
+    // an element must not be its own property
+    if (aContent == mRoot || !aContent->IsHTML()) {
+      // Move on to the next node in the tree
+      aContent = aContent->GetNextNode(aElement);
+    } else {
+      MOZ_ASSERT(aContent->IsElement(), "IsHTML() returned true!");
+      Element* element = aContent->AsElement();
+      if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::itemprop) &&
+          !mProperties.Contains(element)) {
+        mProperties.AppendElement(static_cast<nsGenericHTMLElement*>(element));
+      }                 
+                     
+      if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::itemscope)) {
+        aContent = element->GetNextNonChildNode(aElement);
+      } else {          
+        aContent = element->GetNextNode(aElement);
+      }                 
+    }                     
+  }                    
+}
+
+PropertyNodeList::PropertyNodeList(HTMLPropertiesCollection* aCollection,
+                                   nsIContent* aParent, const nsAString& aName)
+  : mName(aName),
+    mDoc(aParent->GetCurrentDoc()),
+    mCollection(aCollection),
+    mParent(aParent),
+    mIsDirty(true)
+{
+  SetIsDOMBinding();
+  if (mDoc) {
+    mDoc->AddMutationObserver(this);
+  }
+}
+
+PropertyNodeList::~PropertyNodeList()
+{
+  if (mDoc) {
+    mDoc->RemoveMutationObserver(this);
+  }
+}
+
+void
+PropertyNodeList::SetDocument(nsIDocument* aDoc)
+{
+  if (mDoc) {
+    mDoc->RemoveMutationObserver(this);
+  }
+  mDoc = aDoc;
+  if (mDoc) {
+    mDoc->AddMutationObserver(this);
+  }
+  mIsDirty = true;
+}
+
+NS_IMETHODIMP
+PropertyNodeList::GetLength(PRUint32* aLength)
+{
+  EnsureFresh();
+  *aLength = mElements.Length();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PropertyNodeList::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
+{
+  EnsureFresh();
+  nsINode* element = mElements.SafeElementAt(aIndex);
+  if (!element) {
+    *aReturn = NULL;
+    return NS_OK;
+  }
+  return CallQueryInterface(element, aReturn);
+}
+
+nsIContent*
+PropertyNodeList::GetNodeAt(PRUint32 aIndex)
+{
+  EnsureFresh();
+  return mElements.SafeElementAt(aIndex);
+}
+
+PRInt32
+PropertyNodeList::IndexOf(nsIContent* aContent)
+{
+  EnsureFresh();
+  return mElements.IndexOf(aContent);
+}
+
+nsINode*
+PropertyNodeList::GetParentObject()
+{
+  return mParent;
+}
+
+JSObject*
+PropertyNodeList::WrapObject(JSContext *cx, JSObject *scope,
+                             bool *triedToWrap)
+{
+  return mozilla::dom::binding::PropertyNodeList::create(cx, scope, this,
+                                                         triedToWrap);
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(PropertyNodeList)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(PropertyNodeList)
+  // SetDocument(nsnull) ensures that we remove ourselves as a mutation observer
+  tmp->SetDocument(nsnull);
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParent)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCollection)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mElements)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(PropertyNodeList)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDoc)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParent)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mCollection, nsIDOMHTMLPropertiesCollection)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_OF_NSCOMPTR(mElements)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(PropertyNodeList)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(PropertyNodeList)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(PropertyNodeList)
+
+NS_INTERFACE_TABLE_HEAD(PropertyNodeList)
+    NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+    NS_INTERFACE_TABLE4(PropertyNodeList,
+                        nsIDOMPropertyNodeList,
+                        nsIDOMNodeList,
+                        nsINodeList,
+                        nsIMutationObserver)
+    NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(PropertyNodeList)
+    NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(PropertyNodeList)
+NS_INTERFACE_MAP_END
+
+NS_IMETHODIMP
+PropertyNodeList::GetValues(nsIVariant** aValues)
+{
+  EnsureFresh();
+  nsCOMPtr<nsIWritableVariant> out = new nsVariant();
+
+  // We have to use an nsTArray<nsIVariant*> here and do manual refcounting because 
+  // nsWritableVariant::SetAsArray takes an nsIVariant**.
+  nsTArray<nsIVariant*> values;
+
+  PRUint32 length = mElements.Length();
+  if (length == 0) {
+    out->SetAsEmptyArray();
+  } else {
+    for (PRUint32 i = 0; i < length; ++i) {
+      nsIVariant* itemValue;
+      mElements.ElementAt(i)->GetItemValue(&itemValue);
+      values.AppendElement(itemValue);
+    }
+    out->SetAsArray(nsIDataType::VTYPE_INTERFACE_IS,
+                    &NS_GET_IID(nsIVariant),
+                    values.Length(),
+                    values.Elements());
+  }
+
+  out.forget(aValues);
+
+  for (PRUint32 i = 0; i < values.Length(); ++i) {
+    NS_RELEASE(values[i]);
+  }
+
+  return NS_OK;
+}
+
+void
+PropertyNodeList::AttributeChanged(nsIDocument* aDocument, Element* aElement,
+                                   PRInt32 aNameSpaceID, nsIAtom* aAttribute,
+                                   PRInt32 aModType)
+{
+  mIsDirty = true;
+}
+
+void
+PropertyNodeList::ContentAppended(nsIDocument* aDocument, nsIContent* aContainer,
+                                  nsIContent* aFirstNewContent,
+                                  PRInt32 aNewIndexInContainer)
+{
+  mIsDirty = true;
+}
+
+void
+PropertyNodeList::ContentInserted(nsIDocument* aDocument,
+                                  nsIContent* aContainer,
+                                  nsIContent* aChild,
+                                  PRInt32 aIndexInContainer)
+{
+  mIsDirty = true;
+}
+
+void
+PropertyNodeList::ContentRemoved(nsIDocument* aDocument,
+                                 nsIContent* aContainer,
+                                 nsIContent* aChild,
+                                 PRInt32 aIndexInContainer,
+                                 nsIContent* aPreviousSibling)
+{
+  mIsDirty = true;
+}
+
+void
+PropertyNodeList::EnsureFresh()
+{
+  if (mDoc && !mIsDirty) {
+    return;
+  }
+  mIsDirty = false;
+
+  mCollection->EnsureFresh();
+  Clear();
+
+  PRUint32 count = mCollection->mProperties.Length();
+  for (PRUint32 i = 0; i < count; ++i) {
+    nsGenericHTMLElement* element = mCollection->mProperties.ElementAt(i);
+    const nsAttrValue* attr = element->GetParsedAttr(nsGkAtoms::itemprop);
+    if (attr->Contains(mName)) {
+      AppendElement(element);
+    }
+  }
+}
+
+PropertyStringList::PropertyStringList(HTMLPropertiesCollection* aCollection)
+  : nsDOMStringList()
+  , mCollection(aCollection)
+{ }
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(PropertyStringList)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(PropertyStringList)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCollection)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(PropertyStringList)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mCollection, nsIDOMHTMLPropertiesCollection)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(PropertyStringList)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(PropertyStringList)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PropertyStringList)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMDOMStringList)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DOMStringList)
+NS_INTERFACE_MAP_END
+
+NS_IMETHODIMP
+PropertyStringList::Item(PRUint32 aIndex, nsAString& aResult)
+{
+  mCollection->EnsureFresh();
+  return nsDOMStringList::Item(aIndex, aResult);
+}
+
+NS_IMETHODIMP
+PropertyStringList::GetLength(PRUint32* aLength)
+{
+  mCollection->EnsureFresh();
+  return nsDOMStringList::GetLength(aLength);
+}
+
+NS_IMETHODIMP
+PropertyStringList::Contains(const nsAString& aString, bool* aResult)
+{
+  mCollection->EnsureFresh();
+  return nsDOMStringList::Contains(aString, aResult);
+}
+
+bool
+PropertyStringList::ContainsInternal(const nsAString& aString)
+{
+  // This method should not call EnsureFresh, otherwise we may become stuck in an infinite loop.
+  bool result;
+  nsDOMStringList::Contains(aString, &result);
+  return result;
+}
+
+} // namespace dom
+} // namespace mozilla
diff --git a/content/html/content/src/HTMLPropertiesCollection.h b/content/html/content/src/HTMLPropertiesCollection.h
new file mode 100644
index 0000000000000000000000000000000000000000..7d1d8d099c42512dab85a2384082a0146af84021
--- /dev/null
+++ b/content/html/content/src/HTMLPropertiesCollection.h
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set tw=80 expandtab softtabstop=2 ts=2 sw=2: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef HTMLPropertiesCollection_h_
+#define HTMLPropertiesCollection_h_
+
+#include "nsDOMLists.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsAutoPtr.h"
+#include "nsIDOMHTMLPropertiesCollection.h"
+#include "nsIDOMPropertyNodeList.h"
+#include "nsCOMArray.h"
+#include "nsIMutationObserver.h"
+#include "nsStubMutationObserver.h"
+#include "nsBaseHashtable.h"
+#include "nsINodeList.h"
+#include "nsIHTMLCollection.h"
+#include "nsHashKeys.h"
+#include "nsGenericHTMLElement.h"
+
+class nsXPCClassInfo;
+class nsIDocument;
+class nsINode;
+
+namespace mozilla {
+namespace dom {
+
+class HTMLPropertiesCollection;
+class PropertyNodeList;
+
+class PropertyStringList : public nsDOMStringList
+{
+public:
+  PropertyStringList(HTMLPropertiesCollection* aCollection);
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(PropertyStringList)
+  NS_DECL_NSIDOMDOMSTRINGLIST
+
+  bool ContainsInternal(const nsAString& aString);
+
+protected:
+  nsRefPtr<HTMLPropertiesCollection> mCollection;
+};
+
+class HTMLPropertiesCollection : public nsIDOMHTMLPropertiesCollection,
+                                 public nsStubMutationObserver,
+                                 public nsWrapperCache,
+                                 public nsIHTMLCollection
+{
+  friend class PropertyNodeList;
+  friend class PropertyStringList;
+public:
+  HTMLPropertiesCollection(nsGenericHTMLElement* aRoot);
+  virtual ~HTMLPropertiesCollection();
+
+  virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
+                               bool *triedToWrap);
+
+  NS_IMETHOD NamedItem(const nsAString& aName, nsIDOMNode** aResult);
+  void SetDocument(nsIDocument* aDocument);
+  nsINode* GetParentObject();
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_NSIDOMHTMLPROPERTIESCOLLECTION
+
+  NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
+  NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
+  NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
+  NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
+
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(HTMLPropertiesCollection,
+                                                         nsIHTMLCollection)
+
+  nsXPCClassInfo* GetClassInfo();
+
+protected:
+  // Make sure this collection is up to date, in case the DOM has been mutated.
+  void EnsureFresh();
+  
+  // Crawl the properties of mRoot, following any itemRefs it may have
+  void CrawlProperties();
+
+  // Crawl startNode and its descendants, looking for items
+  void CrawlSubtree(Element* startNode);
+
+  // the items that make up this collection
+  nsTArray<nsRefPtr<nsGenericHTMLElement> > mProperties; 
+  
+  // the itemprop attribute of the properties
+  nsRefPtr<PropertyStringList> mNames; 
+ 
+  // The cached PropertyNodeLists that are NamedItems of this collection 
+  nsRefPtrHashtable<nsStringHashKey, PropertyNodeList> mNamedItemEntries;
+  
+  // The element this collection is rooted at
+  nsCOMPtr<nsGenericHTMLElement> mRoot;
+  
+  // The document mRoot is in, if any
+  nsCOMPtr<nsIDocument> mDoc;
+  
+  // True if there have been DOM modifications since the last EnsureFresh call.
+  bool mIsDirty;
+};
+
+class PropertyNodeList : public nsINodeList,
+                         public nsIDOMPropertyNodeList,
+                         public nsStubMutationObserver
+{
+public:
+  PropertyNodeList(HTMLPropertiesCollection* aCollection,
+                   nsIContent* aRoot, const nsAString& aName);
+  virtual ~PropertyNodeList();
+
+  virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
+                               bool *triedToWrap);
+
+  void SetDocument(nsIDocument* aDocument);
+
+  NS_DECL_NSIDOMPROPERTYNODELIST
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(PropertyNodeList,
+                                                         nsINodeList)
+
+  NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
+  NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
+  NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
+  NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
+
+  // nsINodeList interface
+  virtual PRInt32 IndexOf(nsIContent* aContent);
+  virtual nsINode* GetParentObject();
+  
+  void AppendElement(nsGenericHTMLElement* aElement)
+  {
+    mElements.AppendElement(aElement);
+  }
+  
+  void Clear()
+  {
+    mElements.Clear();
+  }
+  
+  void SetDirty() { mIsDirty = true; }
+ 
+protected:
+  // Make sure this list is up to date, in case the DOM has been mutated.
+  void EnsureFresh();
+
+  // the the name that this list corresponds to 
+  nsString mName;
+
+  // the document mParent is in, if any
+  nsCOMPtr<nsIDocument> mDoc;
+
+  // the collection that this list is a named item of
+  nsRefPtr<HTMLPropertiesCollection> mCollection;
+
+  // the node this list is rooted at
+  nsCOMPtr<nsINode> mParent;
+
+  // the properties that make up this list
+  nsTArray<nsRefPtr<nsGenericHTMLElement> > mElements;
+
+  // True if there have been DOM modifications since the last EnsureFresh call. 
+  bool mIsDirty;
+};
+
+} // namespace dom
+} // namespace mozilla
+#endif // HTMLPropertiesCollection_h_ 
diff --git a/content/html/content/src/Makefile.in b/content/html/content/src/Makefile.in
index c225b544fb0e308d16d15839613966fa3e362787..54be7d9bf1548f1f2c5146a215093c8769cedc25 100644
--- a/content/html/content/src/Makefile.in
+++ b/content/html/content/src/Makefile.in
@@ -22,6 +22,7 @@ EXPORTS		= \
 		$(NULL)
 
 CPPSRCS		= \
+		HTMLPropertiesCollection.cpp \
 		nsClientRect.cpp \
 		nsHTMLDNSPrefetch.cpp \
 		nsGenericHTMLElement.cpp \
diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp
index ba71914ecdbf52291b6a59f88572d16464abb8e0..ad4479b24e1ec4b025e741b49e9f4e3bb6b4c84c 100644
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -91,6 +91,9 @@
 #include "mozilla/dom/FromParser.h"
 #include "mozilla/BloomFilter.h"
 
+#include "HTMLPropertiesCollection.h"
+#include "nsVariant.h"
+
 using namespace mozilla;
 using namespace mozilla::dom;
 
@@ -248,7 +251,6 @@ NS_INTERFACE_TABLE_HEAD(nsGenericHTMLElementTearoff)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsGenericHTMLElementTearoff)
 NS_INTERFACE_MAP_END_AGGREGATED(mElement)
 
-
 NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsGenericHTMLElement, TabIndex, tabindex, -1)
 NS_IMPL_BOOL_ATTR(nsGenericHTMLElement, Hidden, hidden)
 
@@ -1699,6 +1701,13 @@ nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (aDocument) {
+    if (HasProperties()) {
+      HTMLPropertiesCollection* properties = 
+        static_cast<HTMLPropertiesCollection*>(GetProperty(nsGkAtoms::microdataProperties));
+      if (properties) {
+        properties->SetDocument(aDocument);
+      }
+    }
     RegAccessKey();
     if (HasName()) {
       aDocument->
@@ -1721,6 +1730,14 @@ nsGenericHTMLElement::UnbindFromTree(bool aDeep, bool aNullParent)
   if (IsInDoc()) {
     UnregAccessKey();
   }
+  
+  if(HasProperties()) {
+    HTMLPropertiesCollection* properties = 
+      static_cast<HTMLPropertiesCollection*>(GetProperty(nsGkAtoms::microdataProperties));
+    if (properties) {
+      properties->SetDocument(nsnull);
+    }
+  }
 
   RemoveFromNameTable();
 
@@ -2073,6 +2090,13 @@ nsGenericHTMLElement::ParseAttribute(PRInt32 aNamespaceID,
       aResult.ParseAtom(aValue);
       return true;
     }
+
+    if (aAttribute == nsGkAtoms::itemref ||
+        aAttribute == nsGkAtoms::itemprop ||
+        aAttribute == nsGkAtoms::itemtype) {
+      aResult.ParseAtomArray(aValue);
+      return true;
+    }
   }
 
   return nsGenericHTMLElementBase::ParseAttribute(aNamespaceID, aAttribute,
@@ -4081,3 +4105,162 @@ nsGenericHTMLElement::ChangeEditableState(PRInt32 aChange)
   nsAutoScriptBlocker scriptBlocker;
   MakeContentDescendantsEditable(this, document);
 }
+
+NS_IMPL_BOOL_ATTR(nsGenericHTMLElement, ItemScope, itemscope)
+NS_IMPL_URI_ATTR(nsGenericHTMLElement, ItemId, itemid)
+
+NS_IMETHODIMP
+nsGenericHTMLElement::GetItemValue(nsIVariant** aValue)
+{
+  nsCOMPtr<nsIWritableVariant> out = new nsVariant();
+
+  if (!HasAttr(kNameSpaceID_None, nsGkAtoms::itemprop)) {
+    out->SetAsEmpty();
+    out.forget(aValue);
+    return NS_OK;
+  }
+
+  bool itemScope;
+  GetItemScope(&itemScope);
+  if (itemScope) {
+    out->SetAsISupports(static_cast<nsISupports*>(this));
+  } else {
+    nsAutoString string;
+    GetItemValueText(string);
+    out->SetAsAString(string);
+  }
+
+  out.forget(aValue);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGenericHTMLElement::SetItemValue(nsIVariant* aValue)
+{
+  if (!HasAttr(kNameSpaceID_None, nsGkAtoms::itemprop) ||
+      HasAttr(kNameSpaceID_None, nsGkAtoms::itemscope)) {
+    return NS_ERROR_DOM_INVALID_ACCESS_ERR;
+  }
+
+  nsAutoString string;
+  aValue->GetAsAString(string);
+  SetItemValueText(string);
+  return NS_OK;
+}
+
+void
+nsGenericHTMLElement::GetItemValueText(nsAString& text)
+{
+  GetTextContent(text);
+}
+
+void
+nsGenericHTMLElement::SetItemValueText(const nsAString& text)
+{
+  SetTextContent(text);
+}
+
+static void
+nsDOMSettableTokenListPropertyDestructor(void *aObject, nsIAtom *aProperty,
+                                         void *aPropertyValue, void *aData)
+{
+  nsDOMSettableTokenList* list =
+    static_cast<nsDOMSettableTokenList*>(aPropertyValue);
+  NS_IF_RELEASE(list);
+}
+
+nsDOMSettableTokenList*
+nsGenericHTMLElement::GetTokenList(nsIAtom* aAtom)
+{
+  nsDOMSettableTokenList* list = NULL;
+  if (HasProperties()) {
+    list = static_cast<nsDOMSettableTokenList*>(GetProperty(aAtom));
+  }
+  if (!list) {
+    list = new nsDOMSettableTokenList(this, aAtom);
+    NS_ADDREF(list);
+    SetProperty(aAtom, list, nsDOMSettableTokenListPropertyDestructor);
+  }                       
+  return list;
+}  
+
+NS_IMETHODIMP
+nsGenericHTMLElement::GetItemRef(nsIVariant** aResult)
+{
+  nsIDOMDOMSettableTokenList* itemRef = GetTokenList(nsGkAtoms::itemref);
+  nsCOMPtr<nsIWritableVariant> out = new nsVariant();
+  out->SetAsInterface(NS_GET_IID(nsIDOMDOMSettableTokenList), itemRef);
+  out.forget(aResult);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGenericHTMLElement::SetItemRef(nsIVariant* aValue)
+{
+  nsDOMSettableTokenList* itemRef = GetTokenList(nsGkAtoms::itemref);
+  nsAutoString string;
+  aValue->GetAsAString(string);
+  return itemRef->SetValue(string);
+}
+
+NS_IMETHODIMP
+nsGenericHTMLElement::GetItemProp(nsIVariant** aResult)
+{
+  nsIDOMDOMSettableTokenList* itemProp = GetTokenList(nsGkAtoms::itemprop);
+  nsCOMPtr<nsIWritableVariant> out = new nsVariant();
+  out->SetAsInterface(NS_GET_IID(nsIDOMDOMSettableTokenList), itemProp);
+  out.forget(aResult);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGenericHTMLElement::SetItemProp(nsIVariant* aValue)
+{
+  nsDOMSettableTokenList* itemProp = GetTokenList(nsGkAtoms::itemprop);
+  nsAutoString string;
+  aValue->GetAsAString(string);
+  return itemProp->SetValue(string);
+}
+
+NS_IMETHODIMP
+nsGenericHTMLElement::GetItemType(nsIVariant** aResult)
+{
+  nsIDOMDOMSettableTokenList* itemType = GetTokenList(nsGkAtoms::itemtype);
+  nsCOMPtr<nsIWritableVariant> out = new nsVariant();
+  out->SetAsInterface(NS_GET_IID(nsIDOMDOMSettableTokenList), itemType);
+  out.forget(aResult);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGenericHTMLElement::SetItemType(nsIVariant* aValue)
+{
+  nsDOMSettableTokenList* itemType = GetTokenList(nsGkAtoms::itemtype);
+  nsAutoString string;
+  aValue->GetAsAString(string);
+  return itemType->SetValue(string);
+}
+
+static void
+nsIDOMHTMLPropertiesCollectionDestructor(void *aObject, nsIAtom *aProperty,
+                                         void *aPropertyValue, void *aData)
+{
+  nsIDOMHTMLPropertiesCollection* properties = 
+    static_cast<nsIDOMHTMLPropertiesCollection*>(aPropertyValue);
+  NS_IF_RELEASE(properties);
+}
+
+NS_IMETHODIMP
+nsGenericHTMLElement::GetProperties(nsIDOMHTMLPropertiesCollection** aReturn)
+{
+  nsIDOMHTMLPropertiesCollection* properties = 
+    static_cast<nsIDOMHTMLPropertiesCollection*>(GetProperty(nsGkAtoms::microdataProperties));
+  if (!properties) {
+     properties = new HTMLPropertiesCollection(this);
+     NS_ADDREF(properties);
+     SetProperty(nsGkAtoms::microdataProperties, properties, nsIDOMHTMLPropertiesCollectionDestructor);
+  }
+  NS_ADDREF(*aReturn = properties);
+  return NS_OK;
+}
+
diff --git a/content/html/content/src/nsGenericHTMLElement.h b/content/html/content/src/nsGenericHTMLElement.h
index 49c8fb1f6e14932b8c86439952f7d76009068df8..cf970b5466b35ac7623ed02a27a94ba302edb28b 100644
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -13,6 +13,8 @@
 #include "nsFrameLoader.h"
 #include "nsGkAtoms.h"
 #include "nsContentCreatorFunctions.h"
+#include "nsDOMSettableTokenList.h"
+#include "nsIDOMHTMLPropertiesCollection.h"
 
 class nsIDOMAttr;
 class nsIDOMEventListener;
@@ -33,6 +35,7 @@ struct nsSize;
 class nsHTMLFormElement;
 class nsIDOMDOMStringMap;
 class nsIDOMHTMLMenuElement;
+class nsIDOMHTMLCollection;
 
 typedef nsMappedAttributeElement nsGenericHTMLElementBase;
 
@@ -114,6 +117,26 @@ public:
   NS_IMETHOD SetSpellcheck(bool aSpellcheck);
   NS_IMETHOD GetDraggable(bool* aDraggable);
   NS_IMETHOD SetDraggable(bool aDraggable);
+  NS_IMETHOD GetItemScope(bool* aItemScope);
+  NS_IMETHOD SetItemScope(bool aItemScope);
+  NS_IMETHOD GetItemValue(nsIVariant** aValue);
+  NS_IMETHOD SetItemValue(nsIVariant* aValue);
+protected:
+  // These methods are used to implement element-specific behavior of Get/SetItemValue
+  // when an element has @itemprop but no @itemscope.
+  virtual void GetItemValueText(nsAString& text);
+  virtual void SetItemValueText(const nsAString& text);
+  nsDOMSettableTokenList* GetTokenList(nsIAtom* aAtom);
+public:
+  NS_IMETHOD GetItemType(nsIVariant** aType);
+  NS_IMETHOD SetItemType(nsIVariant* aType);
+  NS_IMETHOD GetItemId(nsAString& aId);
+  NS_IMETHOD SetItemId(const nsAString& aId);
+  NS_IMETHOD GetItemRef(nsIVariant** aRef);
+  NS_IMETHOD SetItemRef(nsIVariant* aValue);
+  NS_IMETHOD GetItemProp(nsIVariant** aProp);
+  NS_IMETHOD SetItemProp(nsIVariant* aValue);
+  NS_IMETHOD GetProperties(nsIDOMHTMLPropertiesCollection** aReturn);
   NS_IMETHOD GetAccessKey(nsAString &aAccessKey);
   NS_IMETHOD SetAccessKey(const nsAString& aAccessKey);
   NS_IMETHOD GetAccessKeyLabel(nsAString& aLabel);
@@ -771,9 +794,6 @@ private:
   void ChangeEditableState(PRInt32 aChange);
 };
 
-
-//----------------------------------------------------------------------
-
 class nsHTMLFieldSetElement;
 
 /**
@@ -1376,6 +1396,45 @@ PR_STATIC_ASSERT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 1 < 32);
   NS_SCRIPTABLE NS_IMETHOD Blur() { \
     return _to Blur(); \
   } \
+  NS_SCRIPTABLE NS_IMETHOD GetItemScope(bool* aItemScope) { \
+    return _to GetItemScope(aItemScope); \
+  } \
+  NS_SCRIPTABLE NS_IMETHOD SetItemScope(bool aItemScope) { \
+    return _to SetItemScope(aItemScope); \
+  } \
+  NS_SCRIPTABLE NS_IMETHOD GetItemType(nsIVariant** aType) { \
+    return _to GetItemType(aType); \
+  } \
+  NS_SCRIPTABLE NS_IMETHOD SetItemType(nsIVariant* aType) { \
+    return _to SetItemType(aType); \
+  } \
+  NS_SCRIPTABLE NS_IMETHOD GetItemId(nsAString& aId) { \
+    return _to GetItemId(aId); \
+  } \
+  NS_SCRIPTABLE NS_IMETHOD SetItemId(const nsAString& aId) { \
+    return _to SetItemId(aId); \
+  } \
+  NS_SCRIPTABLE NS_IMETHOD GetProperties(nsIDOMHTMLPropertiesCollection** aReturn) { \
+    return _to GetProperties(aReturn); \
+  } \
+  NS_SCRIPTABLE NS_IMETHOD GetItemValue(nsIVariant** aValue) { \
+    return _to GetItemValue(aValue); \
+  } \
+  NS_SCRIPTABLE NS_IMETHOD SetItemValue(nsIVariant* aValue) { \
+    return _to SetItemValue(aValue); \
+  } \
+  NS_SCRIPTABLE NS_IMETHOD GetItemRef(nsIVariant** aRef) { \
+    return _to GetItemRef(aRef); \
+  } \
+  NS_SCRIPTABLE NS_IMETHOD SetItemRef(nsIVariant* aRef) { \
+    return _to SetItemRef(aRef); \
+  } \
+  NS_SCRIPTABLE NS_IMETHOD GetItemProp(nsIVariant** aProp) { \
+    return _to GetItemProp(aProp); \
+  } \
+  NS_SCRIPTABLE NS_IMETHOD SetItemProp(nsIVariant* aProp) { \
+    return _to SetItemProp(aProp); \
+  } \
   NS_SCRIPTABLE NS_IMETHOD GetAccessKey(nsAString& aAccessKey) { \
     return _to GetAccessKey(aAccessKey); \
   } \
diff --git a/content/html/content/src/nsHTMLAnchorElement.cpp b/content/html/content/src/nsHTMLAnchorElement.cpp
index 533098e0da672d5151145aa56f74f46eeb38bedb..2794c88e59a13905564d94a5802e28a54077ea6d 100644
--- a/content/html/content/src/nsHTMLAnchorElement.cpp
+++ b/content/html/content/src/nsHTMLAnchorElement.cpp
@@ -110,6 +110,10 @@ public:
   virtual void OnDNSPrefetchDeferred();
   virtual void OnDNSPrefetchRequested();
   virtual bool HasDeferredDNSPrefetchRequest();
+
+protected:
+  virtual void GetItemValueText(nsAString& text);
+  virtual void SetItemValueText(const nsAString& text);
 };
 
 // Indicates that a DNS Prefetch has been requested from this Anchor elem
@@ -166,6 +170,18 @@ NS_IMPL_STRING_ATTR(nsHTMLAnchorElement, Shape, shape)
 NS_IMPL_INT_ATTR(nsHTMLAnchorElement, TabIndex, tabindex)
 NS_IMPL_STRING_ATTR(nsHTMLAnchorElement, Type, type)
 
+void
+nsHTMLAnchorElement::GetItemValueText(nsAString& aValue)
+{
+  GetHref(aValue);
+}
+
+void
+nsHTMLAnchorElement::SetItemValueText(const nsAString& aValue)
+{
+  SetHref(aValue);
+}
+
 NS_IMETHODIMP
 nsHTMLAnchorElement::GetDraggable(bool* aDraggable)
 {
diff --git a/content/html/content/src/nsHTMLAreaElement.cpp b/content/html/content/src/nsHTMLAreaElement.cpp
index 47bdfe0f96da4076b70d7e83fe8ffb04bcedbcf0..1eb3d0d8c3f5692abeefd176ab74fd7009cd0f72 100644
--- a/content/html/content/src/nsHTMLAreaElement.cpp
+++ b/content/html/content/src/nsHTMLAreaElement.cpp
@@ -95,6 +95,10 @@ public:
   virtual nsXPCClassInfo* GetClassInfo();
 
   virtual nsIDOMNode* AsDOMNode() { return this; }
+
+protected:
+  virtual void GetItemValueText(nsAString& text);
+  virtual void SetItemValueText(const nsAString& text);
 };
 
 
@@ -137,6 +141,18 @@ NS_IMPL_BOOL_ATTR(nsHTMLAreaElement, NoHref, nohref)
 NS_IMPL_STRING_ATTR(nsHTMLAreaElement, Shape, shape)
 NS_IMPL_INT_ATTR(nsHTMLAreaElement, TabIndex, tabindex)
 
+void
+nsHTMLAreaElement::GetItemValueText(nsAString& aValue)
+{
+  GetHref(aValue);
+}
+
+void
+nsHTMLAreaElement::SetItemValueText(const nsAString& aValue)
+{
+  SetHref(aValue);
+}
+
 NS_IMETHODIMP
 nsHTMLAreaElement::GetTarget(nsAString& aValue)
 {
diff --git a/content/html/content/src/nsHTMLAudioElement.cpp b/content/html/content/src/nsHTMLAudioElement.cpp
index ee3177a92cd5cb556e29be0e390bd52ce69d7644..229f0c806b6a1392a61d052cddb5072daf2d47b8 100644
--- a/content/html/content/src/nsHTMLAudioElement.cpp
+++ b/content/html/content/src/nsHTMLAudioElement.cpp
@@ -83,6 +83,20 @@ nsHTMLAudioElement::~nsHTMLAudioElement()
 {
 }
 
+void
+nsHTMLAudioElement::GetItemValueText(nsAString& aValue)
+{
+  // Can't call GetSrc because we don't have a JSContext
+  GetURIAttr(nsGkAtoms::src, nsnull, aValue);
+}
+
+void
+nsHTMLAudioElement::SetItemValueText(const nsAString& aValue)
+{
+  // Can't call SetSrc because we don't have a JSContext
+  SetAttr(kNameSpaceID_None, nsGkAtoms::src, aValue, true);
+}
+
 NS_IMETHODIMP
 nsHTMLAudioElement::Initialize(nsISupports* aOwner, JSContext* aContext,
                                JSObject *aObj, PRUint32 argc, jsval *argv)
diff --git a/content/html/content/src/nsHTMLIFrameElement.cpp b/content/html/content/src/nsHTMLIFrameElement.cpp
index 9d9cb7ec2d5069eee5444cdc6a42a29b92e3baa7..69bb73fa09a0493cdd48023c66f787483428b5b8 100644
--- a/content/html/content/src/nsHTMLIFrameElement.cpp
+++ b/content/html/content/src/nsHTMLIFrameElement.cpp
@@ -58,6 +58,10 @@ public:
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
   virtual nsXPCClassInfo* GetClassInfo();
   virtual nsIDOMNode* AsDOMNode() { return this; }
+
+protected:
+  virtual void GetItemValueText(nsAString& text);
+  virtual void SetItemValueText(const nsAString& text);
 };
 
 
@@ -106,6 +110,18 @@ NS_IMPL_URI_ATTR(nsHTMLIFrameElement, Src, src)
 NS_IMPL_STRING_ATTR(nsHTMLIFrameElement, Width, width)
 NS_IMPL_BOOL_ATTR(nsHTMLIFrameElement, MozAllowFullScreen, mozallowfullscreen)
 
+void
+nsHTMLIFrameElement::GetItemValueText(nsAString& aValue)
+{
+  GetSrc(aValue);
+}
+
+void
+nsHTMLIFrameElement::SetItemValueText(const nsAString& aValue)
+{
+  SetSrc(aValue);
+}
+
 NS_IMETHODIMP
 nsHTMLIFrameElement::GetContentDocument(nsIDOMDocument** aContentDocument)
 {
diff --git a/content/html/content/src/nsHTMLImageElement.cpp b/content/html/content/src/nsHTMLImageElement.cpp
index 6a2a089f4ab9cd67de58a314c09497c252b32898..812334e48de6f49877d6ab10a61702a5a4a2d6be 100644
--- a/content/html/content/src/nsHTMLImageElement.cpp
+++ b/content/html/content/src/nsHTMLImageElement.cpp
@@ -116,6 +116,18 @@ NS_IMPL_URI_ATTR(nsHTMLImageElement, Src, src)
 NS_IMPL_STRING_ATTR(nsHTMLImageElement, UseMap, usemap)
 NS_IMPL_INT_ATTR(nsHTMLImageElement, Vspace, vspace)
 
+void
+nsHTMLImageElement::GetItemValueText(nsAString& aValue)
+{
+  GetSrc(aValue);
+}
+
+void
+nsHTMLImageElement::SetItemValueText(const nsAString& aValue)
+{
+  SetSrc(aValue);
+}
+
 // crossorigin is not "limited to only known values" per spec, so it's
 // just a string attr purposes of the DOM crossOrigin property.
 NS_IMPL_STRING_ATTR(nsHTMLImageElement, CrossOrigin, crossorigin)
diff --git a/content/html/content/src/nsHTMLImageElement.h b/content/html/content/src/nsHTMLImageElement.h
index e230f0f7bef7e01d23c5cf5c1b4853632efd1bf5..99c0a00a31a95dde1ee2f8d4a4d71e475f466777 100644
--- a/content/html/content/src/nsHTMLImageElement.h
+++ b/content/html/content/src/nsHTMLImageElement.h
@@ -103,6 +103,8 @@ public:
 protected:
   nsIntPoint GetXY();
   nsSize GetWidthHeight();
+  virtual void GetItemValueText(nsAString& text);
+  virtual void SetItemValueText(const nsAString& text);
 };
 
 #endif /* nsHTMLImageElement_h */
diff --git a/content/html/content/src/nsHTMLLinkElement.cpp b/content/html/content/src/nsHTMLLinkElement.cpp
index 6ae52fb16cd8d8a2a73f51b6aabe3f5b9d117379..2e72964081faa81974ba19a8a5a8dea6755fda41 100644
--- a/content/html/content/src/nsHTMLLinkElement.cpp
+++ b/content/html/content/src/nsHTMLLinkElement.cpp
@@ -95,6 +95,9 @@ protected:
                                  nsAString& aType,
                                  nsAString& aMedia,
                                  bool* aIsAlternate);
+protected:
+  virtual void GetItemValueText(nsAString& text);
+  virtual void SetItemValueText(const nsAString& text);
 };
 
 
@@ -172,6 +175,18 @@ NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Rev, rev)
 NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Target, target)
 NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Type, type)
 
+void
+nsHTMLLinkElement::GetItemValueText(nsAString& aValue)
+{
+  GetHref(aValue);
+}
+
+void
+nsHTMLLinkElement::SetItemValueText(const nsAString& aValue)
+{
+  SetHref(aValue);
+}
+
 nsresult
 nsHTMLLinkElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
diff --git a/content/html/content/src/nsHTMLMetaElement.cpp b/content/html/content/src/nsHTMLMetaElement.cpp
index d5c8bf76772e4d69f9f1aba796a9f3127946f60e..f82bafa21b2ce4e990652294422a148930f7fd30 100644
--- a/content/html/content/src/nsHTMLMetaElement.cpp
+++ b/content/html/content/src/nsHTMLMetaElement.cpp
@@ -45,6 +45,10 @@ public:
   virtual nsXPCClassInfo* GetClassInfo();
 
   virtual nsIDOMNode* AsDOMNode() { return this; }
+
+protected:
+  virtual void GetItemValueText(nsAString& text);
+  virtual void SetItemValueText(const nsAString& text);
 };
 
 
@@ -83,6 +87,19 @@ NS_IMPL_STRING_ATTR(nsHTMLMetaElement, HttpEquiv, httpEquiv)
 NS_IMPL_STRING_ATTR(nsHTMLMetaElement, Name, name)
 NS_IMPL_STRING_ATTR(nsHTMLMetaElement, Scheme, scheme)
 
+void
+nsHTMLMetaElement::GetItemValueText(nsAString& aValue)
+{
+  GetContent(aValue);
+}
+
+void
+nsHTMLMetaElement::SetItemValueText(const nsAString& aValue)
+{
+  SetContent(aValue);
+}
+
+
 nsresult
 nsHTMLMetaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
diff --git a/content/html/content/src/nsHTMLObjectElement.cpp b/content/html/content/src/nsHTMLObjectElement.cpp
index 6d6611827b7ded5dca367a284195d73b2f1b8148..6559d1b24317a4bde09184d55a40f357de1d920c 100644
--- a/content/html/content/src/nsHTMLObjectElement.cpp
+++ b/content/html/content/src/nsHTMLObjectElement.cpp
@@ -136,6 +136,9 @@ private:
    * value. This is used to know the default tabindex value.
    */
   bool IsFocusableForTabIndex();
+  
+  virtual void GetItemValueText(nsAString& text);
+  virtual void SetItemValueText(const nsAString& text);
 
   bool mIsDoneAddingChildren;
 };
@@ -224,6 +227,18 @@ nsHTMLObjectElement::GetForm(nsIDOMHTMLFormElement **aForm)
   return nsGenericHTMLFormElement::GetForm(aForm);
 }
 
+void
+nsHTMLObjectElement::GetItemValueText(nsAString& aValue)
+{
+  GetData(aValue);
+}
+
+void
+nsHTMLObjectElement::SetItemValueText(const nsAString& aValue)
+{
+  SetData(aValue);
+}
+
 nsresult
 nsHTMLObjectElement::BindToTree(nsIDocument *aDocument,
                                 nsIContent *aParent,
diff --git a/content/html/content/src/nsHTMLSharedObjectElement.cpp b/content/html/content/src/nsHTMLSharedObjectElement.cpp
index d2e8e6ba50668484ff4089f936cdd7bec93cf5d3..13c500d5d1919f166da3cec8c8e63238f5416699 100644
--- a/content/html/content/src/nsHTMLSharedObjectElement.cpp
+++ b/content/html/content/src/nsHTMLSharedObjectElement.cpp
@@ -153,6 +153,9 @@ private:
   // mIsDoneAddingChildren is only really used for <applet>.  This boolean is
   // always true for <embed>, per the documentation in nsIContent.h.
   bool mIsDoneAddingChildren;
+
+  virtual void GetItemValueText(nsAString& text);
+  virtual void SetItemValueText(const nsAString& text);
 };
 
 
@@ -171,6 +174,26 @@ nsHTMLSharedObjectElement::nsHTMLSharedObjectElement(already_AddRefed<nsINodeInf
   AddStatesSilently(NS_EVENT_STATE_LOADING);
 }
 
+void
+nsHTMLSharedObjectElement::GetItemValueText(nsAString& aValue)
+{
+  if (mNodeInfo->Equals(nsGkAtoms::applet)) {
+    nsGenericHTMLElement::GetItemValueText(aValue);
+  } else {
+    GetSrc(aValue);
+  }
+}
+
+void
+nsHTMLSharedObjectElement::SetItemValueText(const nsAString& aValue)
+{
+  if (mNodeInfo->Equals(nsGkAtoms::applet)) {
+    nsGenericHTMLElement::SetItemValueText(aValue);
+  } else {
+    SetSrc(aValue);
+  }
+}
+
 nsHTMLSharedObjectElement::~nsHTMLSharedObjectElement()
 {
   UnregisterFreezableElement();
diff --git a/content/html/content/src/nsHTMLSourceElement.cpp b/content/html/content/src/nsHTMLSourceElement.cpp
index 3263956004df18395788601c22dd25f3778f2465..64e4a24b08aec9deb7108c6b4f6db886aab6146d 100644
--- a/content/html/content/src/nsHTMLSourceElement.cpp
+++ b/content/html/content/src/nsHTMLSourceElement.cpp
@@ -47,6 +47,10 @@ public:
   virtual nsXPCClassInfo* GetClassInfo();
 
   virtual nsIDOMNode* AsDOMNode() { return this; }
+
+protected:
+  virtual void GetItemValueText(nsAString& text);
+  virtual void SetItemValueText(const nsAString& text);
 };
 
 
@@ -84,6 +88,18 @@ NS_IMPL_URI_ATTR(nsHTMLSourceElement, Src, src)
 NS_IMPL_STRING_ATTR(nsHTMLSourceElement, Type, type)
 NS_IMPL_STRING_ATTR(nsHTMLSourceElement, Media, media)
 
+void
+nsHTMLSourceElement::GetItemValueText(nsAString& aValue)
+{
+  GetSrc(aValue);
+}
+
+void
+nsHTMLSourceElement::SetItemValueText(const nsAString& aValue)
+{
+  SetSrc(aValue);
+}
+
 nsresult
 nsHTMLSourceElement::BindToTree(nsIDocument *aDocument,
                                 nsIContent *aParent,
diff --git a/content/html/content/src/nsHTMLVideoElement.cpp b/content/html/content/src/nsHTMLVideoElement.cpp
index 956d6c6123dbd3b751252c651e9ecb6c1eff6ae7..72d03ae80e86d24ee7c635d6bdbf358cb2a16993 100644
--- a/content/html/content/src/nsHTMLVideoElement.cpp
+++ b/content/html/content/src/nsHTMLVideoElement.cpp
@@ -80,6 +80,20 @@ nsHTMLVideoElement::~nsHTMLVideoElement()
 {
 }
 
+void
+nsHTMLVideoElement::GetItemValueText(nsAString& aValue)
+{
+  // Can't call GetSrc because we don't have a JSContext
+  GetURIAttr(nsGkAtoms::src, nsnull, aValue);
+}
+
+void
+nsHTMLVideoElement::SetItemValueText(const nsAString& aValue)
+{
+  // Can't call SetSrc because we don't have a JSContext
+  SetAttr(kNameSpaceID_None, nsGkAtoms::src, aValue, true);
+}
+
 nsresult nsHTMLVideoElement::GetVideoSize(nsIntSize* size)
 {
   if (mMediaSize.width == -1 && mMediaSize.height == -1) {
diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp
index 3634df795190b3da16dc8b4f6b6cf02a8432bb84..e4aba11fd8bd3f503826e48b03c248267c2ecf3e 100644
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -1765,6 +1765,84 @@ nsHTMLDocument::GetElementsByName(const nsAString& aElementName,
   return NS_OK;
 }
 
+static bool MatchItems(nsIContent* aContent, PRInt32 aNameSpaceID, 
+                       nsIAtom* aAtom, void* aData)
+{
+  if (!(aContent->IsElement() && aContent->AsElement()->IsHTML())) {
+    return false;
+  }
+
+  nsGenericHTMLElement* elem = static_cast<nsGenericHTMLElement*>(aContent);
+  if (!elem->HasAttr(kNameSpaceID_None, nsGkAtoms::itemscope) ||
+      elem->HasAttr(kNameSpaceID_None, nsGkAtoms::itemprop)) {
+    return false;
+  }
+
+  nsTArray<nsCOMPtr<nsIAtom> >* tokens = static_cast<nsTArray<nsCOMPtr<nsIAtom> >*>(aData);
+  if (tokens->IsEmpty()) {
+    return true;
+  }
+ 
+  const nsAttrValue* attr = elem->GetParsedAttr(nsGkAtoms::itemtype);
+  if (!attr)
+    return false;
+
+  for (PRUint32 i = 0; i < tokens->Length(); i++) {
+    if (!attr->Contains(tokens->ElementAt(i), eCaseMatters)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+static void DestroyTokens(void* aData)
+{
+  nsTArray<nsCOMPtr<nsIAtom> >* tokens = static_cast<nsTArray<nsCOMPtr<nsIAtom> >*>(aData);
+  delete tokens;
+}
+
+static void* CreateTokens(nsINode* aRootNode, const nsString* types)
+{
+  nsTArray<nsCOMPtr<nsIAtom> >* tokens = new nsTArray<nsCOMPtr<nsIAtom> >();
+  nsAString::const_iterator iter, end;
+  types->BeginReading(iter);
+  types->EndReading(end);
+  
+  // skip initial whitespace
+  while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) {
+    ++iter;
+  }
+
+  // parse the tokens
+  while (iter != end) {
+    nsAString::const_iterator start(iter);
+
+    do {
+      ++iter;
+    } while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter));
+
+    tokens->AppendElement(do_GetAtom(Substring(start, iter)));
+
+    // skip whitespace
+    while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) {
+      ++iter;
+    }
+  }
+  return tokens;
+}
+
+NS_IMETHODIMP
+nsHTMLDocument::GetItems(const nsAString& types, nsIDOMNodeList** aReturn)
+{
+  nsRefPtr<nsContentList> elements = 
+    NS_GetFuncStringContentList(this, MatchItems, DestroyTokens, 
+                                CreateTokens, types);
+  NS_ENSURE_TRUE(elements, NS_ERROR_OUT_OF_MEMORY);
+  elements.forget(aReturn);
+  return NS_OK;
+}
+
+
 void
 nsHTMLDocument::AddedForm()
 {
diff --git a/content/html/document/src/nsHTMLDocument.h b/content/html/document/src/nsHTMLDocument.h
index 288629e86c8b50e7caaf10ac75e57e804234cd2e..cf7a1b17fa1e67c995a271d3f7d976c47b67e3b1 100644
--- a/content/html/document/src/nsHTMLDocument.h
+++ b/content/html/document/src/nsHTMLDocument.h
@@ -112,7 +112,6 @@ public:
                                        UseExistingNameString, aName);
   }
 
-
   virtual nsresult ResolveName(const nsAString& aName,
                                nsIContent *aForm,
                                nsISupports **aResult,
diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp
index 92a0a708213afb02f3ee29a94a592546afdcfe55..99233e6422c0d5e547d5fa37ece24853543e93e8 100644
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -828,6 +828,11 @@ static nsDOMClassInfoData sClassInfoData[] = {
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(HTMLCollection, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(HTMLPropertiesCollection, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(PropertyNodeList, 
+                           nsDOMGenericSH, 
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   // HTML element classes
   NS_DEFINE_CLASSINFO_DATA(HTMLElement, nsElementSH,
@@ -2731,6 +2736,16 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLCollection)
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN(HTMLPropertiesCollection, nsIDOMHTMLPropertiesCollection)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLPropertiesCollection)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLCollection)
+  DOM_CLASSINFO_MAP_END
+
+  DOM_CLASSINFO_MAP_BEGIN(PropertyNodeList, nsIDOMPropertyNodeList)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMPropertyNodeList)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeList)
+  DOM_CLASSINFO_MAP_END
+
   DOM_CLASSINFO_MAP_BEGIN(HTMLElement, nsIDOMHTMLElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLElement)
     DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
diff --git a/dom/base/nsDOMClassInfoClasses.h b/dom/base/nsDOMClassInfoClasses.h
index 02b0814fcecf16bb36bf359a7fc7573071256cbb..ad155afaaa929cd0140c0b3e02ecb5ecaa4076ff 100644
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -58,6 +58,8 @@ DOMCI_CLASS(DeviceRotationRate)
 DOMCI_CLASS(HTMLDocument)
 DOMCI_CLASS(HTMLOptionsCollection)
 DOMCI_CLASS(HTMLCollection)
+DOMCI_CLASS(HTMLPropertiesCollection)
+DOMCI_CLASS(PropertyNodeList)
 
 // HTML element classes
 DOMCI_CLASS(HTMLElement)
diff --git a/dom/interfaces/html/Makefile.in b/dom/interfaces/html/Makefile.in
index 5d9e08a2c2e9694fe9b18111fcfbf65003748c43..098fa2ed14100d309bcef483ced79f30c0c216c4 100644
--- a/dom/interfaces/html/Makefile.in
+++ b/dom/interfaces/html/Makefile.in
@@ -61,6 +61,8 @@ SDK_XPIDLSRCS =					\
 	nsIDOMHTMLParagraphElement.idl		\
 	nsIDOMHTMLParamElement.idl		\
 	nsIDOMHTMLPreElement.idl		\
+	nsIDOMHTMLPropertiesCollection.idl  \
+	nsIDOMPropertyNodeList.idl  \
 	nsIDOMHTMLProgressElement.idl		\
 	nsIDOMHTMLQuoteElement.idl		\
 	nsIDOMHTMLScriptElement.idl		\
diff --git a/dom/interfaces/html/nsIDOMHTMLDocument.idl b/dom/interfaces/html/nsIDOMHTMLDocument.idl
index 36255bf89cdb385d58ad531e11bbf9a4914c1bca..406c74b7c455f09b34e6f0ea786095c7be560123 100644
--- a/dom/interfaces/html/nsIDOMHTMLDocument.idl
+++ b/dom/interfaces/html/nsIDOMHTMLDocument.idl
@@ -13,7 +13,7 @@
  */
 interface nsISelection;
 
-[scriptable, uuid(1B93973F-28CC-4F33-8E7B-B89C63AA9200)]
+[scriptable, uuid(ecae54c6-2ab9-4167-b0ef-61960aadbb68)]
 interface nsIDOMHTMLDocument : nsIDOMDocument
 {
   readonly attribute DOMString            URL;
@@ -34,6 +34,7 @@ interface nsIDOMHTMLDocument : nsIDOMDocument
   readonly attribute nsIDOMHTMLCollection forms;
   readonly attribute nsIDOMHTMLCollection scripts;
   nsIDOMNodeList            getElementsByName(in DOMString elementName);
+  nsIDOMNodeList  getItems([optional] in DOMString types);
 
   // If aContentType is not something supported by nsHTMLDocument and
   // the HTML content sink, trying to write to the document will
diff --git a/dom/interfaces/html/nsIDOMHTMLElement.idl b/dom/interfaces/html/nsIDOMHTMLElement.idl
index 91c6892114414695128d886edb3f0cff36cf94b9..9b08411ae17314fc6f084e43fd2c58396804f1b2 100644
--- a/dom/interfaces/html/nsIDOMHTMLElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLElement.idl
@@ -4,9 +4,11 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIDOMElement.idl"
+#include "nsIVariant.idl"
 
 interface nsIDOMDOMStringMap;
 interface nsIDOMHTMLMenuElement;
+interface nsIDOMHTMLPropertiesCollection;
 
 /**
  * The nsIDOMHTMLElement interface is the primary [X]HTML element
@@ -19,7 +21,7 @@ interface nsIDOMHTMLMenuElement;
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
-[scriptable, uuid(5C8B21BC-EF6E-4599-A26F-FACC05B4ADBE)]
+[scriptable, uuid(9a677a5b-e6f7-4e2e-9ef9-22c2ac9967b3)]
 interface nsIDOMHTMLElement : nsIDOMElement
 {
   // metadata attributes
@@ -30,6 +32,16 @@ interface nsIDOMHTMLElement : nsIDOMElement
            attribute DOMString        className;
   readonly attribute nsIDOMDOMStringMap dataset;
 
+           attribute boolean                        itemScope;
+           attribute nsIVariant                     itemType;
+           attribute DOMString                      itemId;
+  readonly attribute nsIDOMHTMLPropertiesCollection properties; 
+  // The following attributes are really nsDOMSettableTokenList, which has
+  // PutForwards, so we express them as nsIVariants to deal with this.
+           attribute nsIVariant                     itemValue;
+           attribute nsIVariant                     itemProp;
+           attribute nsIVariant                     itemRef;
+
   // user interaction
   /**
    * Indicates that the element is not yet, or is no longer, relevant.
diff --git a/dom/interfaces/html/nsIDOMHTMLPropertiesCollection.idl b/dom/interfaces/html/nsIDOMHTMLPropertiesCollection.idl
new file mode 100644
index 0000000000000000000000000000000000000000..0e949b3db0568049cc0bc8455c1114c1dbcda1cd
--- /dev/null
+++ b/dom/interfaces/html/nsIDOMHTMLPropertiesCollection.idl
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set tw=80 expandtab softtabstop=2 ts=2 sw=2: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsIDOMHTMLElement.idl"
+#include "nsIDOMPropertyNodeList.idl"
+#include "nsIDOMDOMStringList.idl"
+
+// This interface should extend nsIDOMHTMLCollection, which will be fixed when
+// it is converted to webidl.
+[scriptable, uuid(da1101db-d1d7-465d-9fd6-49ec9960cb20)]
+interface nsIDOMHTMLPropertiesCollection : nsISupports
+{
+  readonly attribute unsigned long    length;
+  readonly attribute nsIDOMDOMStringList names;
+
+  [getter,forward(getNodeAt)] nsIDOMNode                item(in unsigned long index);
+  nsIDOMPropertyNodeList namedItem(in DOMString name);
+
+  /**
+   * Get the node at the index.  Returns null if the index is out of bounds.
+   */
+  [noscript,notxpcom,nostdcall] nsIContent  getNodeAt(in unsigned long index);
+
+  /**
+   * Get the node for the name.  Returns null if no node exists for the name.
+   */
+  [noscript,notxpcom,nostdcall] nsISupports getNamedItem(in DOMString name,
+                                                         out nsWrapperCachePtr cache);
+};
diff --git a/dom/interfaces/html/nsIDOMPropertyNodeList.idl b/dom/interfaces/html/nsIDOMPropertyNodeList.idl
new file mode 100644
index 0000000000000000000000000000000000000000..2b69cc1f3b0602c7a87de94c4b9823f3983b0afd
--- /dev/null
+++ b/dom/interfaces/html/nsIDOMPropertyNodeList.idl
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set tw=80 expandtab softtabstop=2 ts=2 sw=2: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsIVariant.idl"
+
+interface nsIDOMNode;
+interface nsIContent;
+
+[scriptable, uuid(255cc828-49e8-4fb0-8e36-875e6e072da3)]
+interface nsIDOMPropertyNodeList : nsISupports {
+  [getter,forward(getNodeAt)] nsIDOMNode    item(in unsigned long index);
+  readonly attribute unsigned long          length;
+
+  /**
+   * Get the node at the index.  Returns null if the index is out of bounds
+   */
+  [noscript,notxpcom,nostdcall] nsIContent  getNodeAt(in unsigned long index);
+
+  nsIVariant getValues();
+};
diff --git a/js/xpconnect/src/codegen.py b/js/xpconnect/src/codegen.py
index 3a610491c5a9f570e9e9a7cf7b0daa174ca297fe..00b13b7bc3ca572485587ca0b63a28aced5ea77e 100644
--- a/js/xpconnect/src/codegen.py
+++ b/js/xpconnect/src/codegen.py
@@ -365,7 +365,8 @@ def writeResultConv(f, type, interfaceResultTemplate, jsvalPtr, jsvalRef):
         template = resultConvTemplates.get(typeName)
     elif isInterfaceType(type):
         if isVariantType(type):
-            template = "    return xpc_qsVariantToJsval(lccx, result, ${jsvalPtr});\n"
+            template =  ("    XPCLazyCallContext lccx(JS_CALLER, cx, obj);\n"
+                         "    return xpc_qsVariantToJsval(lccx, result, ${jsvalPtr});\n")
         else:
             template = ("    if (!result) {\n"
                         "      *${jsvalPtr} = JSVAL_NULL;\n"
diff --git a/js/xpconnect/src/dom_quickstubs.qsconf b/js/xpconnect/src/dom_quickstubs.qsconf
index 83bfd35b8416ccef64cc205c988947bcbdb91d3a..4a1da7e979ca0d791c85503e7eea564fe4187ac7 100644
--- a/js/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/xpconnect/src/dom_quickstubs.qsconf
@@ -219,7 +219,33 @@ members = [
     'nsIDOMHTMLDocument.getSelection',
     'nsIDOMHTMLDocument.designMode',
     'nsIDOMHTMLDocument.head',
-    'nsIDOMHTMLElement.*',
+    # We can't quick stub nsIDOMHTMLElement.* because we don't 
+    # generate quick stubs for nsIVariant attributes.
+    'nsIDOMHTMLElement.id',
+    'nsIDOMHTMLElement.title',
+    'nsIDOMHTMLElement.lang',
+    'nsIDOMHTMLElement.dir',
+    'nsIDOMHTMLElement.className',
+    'nsIDOMHTMLElement.dataset',
+    'nsIDOMHTMLElement.itemScope',
+    'nsIDOMHTMLElement.itemId',
+    'nsIDOMHTMLElement.properties',
+    'nsIDOMHTMLElement.hidden',
+    'nsIDOMHTMLElement.tabIndex',
+    'nsIDOMHTMLElement.accessKey',
+    'nsIDOMHTMLElement.accessKeyLabel',
+    'nsIDOMHTMLElement.draggable',
+    'nsIDOMHTMLElement.contentEditable',
+    'nsIDOMHTMLElement.isContentEditable',
+    'nsIDOMHTMLElement.contextMenu',
+    'nsIDOMHTMLElement.spellcheck',
+    'nsIDOMHTMLElement.innerHTML',
+    'nsIDOMHTMLElement.outerHTML',
+    'nsIDOMHTMLElement.offsetParent',
+    'nsIDOMHTMLElement.offsetTop',
+    'nsIDOMHTMLElement.offsetLeft',
+    'nsIDOMHTMLElement.offsetWidth',
+    'nsIDOMHTMLElement.offsetHeight',
     'nsIDOMHTMLFormElement.elements',
     'nsIDOMHTMLFormElement.name',
     'nsIDOMHTMLFormElement.submit',
@@ -269,6 +295,8 @@ members = [
     'nsIDOMHTMLOptionsCollection.item',
     'nsIDOMHTMLOptionsCollection.length',
     'nsIDOMHTMLProgressElement.*',
+    'nsIDOMHTMLPropertiesCollection.*',
+    'nsIDOMPropertyNodeList.*',
     'nsIDOMHTMLSelectElement.name',
     'nsIDOMHTMLSelectElement.form',
     'nsIDOMHTMLSelectElement.add',
diff --git a/js/xpconnect/src/dombindings.conf b/js/xpconnect/src/dombindings.conf
index a1b709663b3c94dce75e2e5f6c54aa0d221c3864..83a4ed6759c9fc081947950d617369dd995a02a2 100644
--- a/js/xpconnect/src/dombindings.conf
+++ b/js/xpconnect/src/dombindings.conf
@@ -8,6 +8,10 @@ list_classes = [
         'name': 'NodeList',
         'nativeClass': 'nsINodeList'
     },
+    {
+        'name': 'PropertyNodeList',
+        'nativeClass': 'mozilla::dom::PropertyNodeList'
+    },
     {
         'name': 'HTMLCollection',
         'nativeClass': 'nsIHTMLCollection'
@@ -15,6 +19,10 @@ list_classes = [
     {
         'name': 'HTMLOptionsCollection',
         'nativeClass': 'nsHTMLOptionCollection'
+    },
+    {
+        'name': 'HTMLPropertiesCollection',
+        'nativeClass': 'mozilla::dom::HTMLPropertiesCollection'
     }
 ]
 
@@ -33,11 +41,14 @@ prefableClasses = {
 
 irregularFilenames = {
     'nsHTMLOptionCollection': 'nsHTMLSelectElement',
+    'mozilla::dom::PropertyNodeList': 'HTMLPropertiesCollection',
     'nsClientRectList': 'nsClientRect',
     'nsPaintRequestList': 'nsPaintRequest',
     'nsDOMFileList': 'nsDOMFile',
     }
 
 customInheritance = {
+    'nsIDOMPropertyNodeList': 'nsIDOMNodeList',
     'nsIDOMHTMLOptionsCollection': 'nsIDOMHTMLCollection',
+    'nsIDOMHTMLPropertiesCollection': 'nsIDOMHTMLCollection',
     }