Bug 382267. Core implementation of the <video> and <audio> elements. r=jst,r+sr=roc
authorChris Double <chris.double@double.co.nz>
Wed, 09 Jul 2008 20:22:20 +1200
changeset 15751 82a78cd809c455c7ba65c851f0fac1d9311f3a54
parent 15750 a98fc827d275fe20c0e05207279f86ef19c38707
child 15752 979c6ac5ef1a63a2b369884e43a7ac0f76d7baae
push id470
push userrocallahan@mozilla.com
push dateWed, 09 Jul 2008 08:22:42 +0000
treeherdermozilla-central@82a78cd809c4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst, r
bugs382267
milestone1.9.1a1pre
Bug 382267. Core implementation of the <video> and <audio> elements. r=jst,r+sr=roc
config/autoconf.mk.in
configure.in
content/Makefile.in
content/base/src/nsAttrValue.cpp
content/base/src/nsAttrValue.h
content/base/src/nsContentUtils.cpp
content/base/src/nsGkAtomList.h
content/events/public/nsIPrivateDOMEvent.h
content/events/src/Makefile.in
content/events/src/nsDOMEvent.cpp
content/events/src/nsDOMEvent.h
content/events/src/nsDOMProgressEvent.cpp
content/events/src/nsDOMProgressEvent.h
content/events/src/nsEventDispatcher.cpp
content/html/content/public/Makefile.in
content/html/content/public/nsHTMLAudioElement.h
content/html/content/public/nsHTMLMediaElement.h
content/html/content/public/nsHTMLVideoElement.h
content/html/content/src/Makefile.in
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsGenericHTMLElement.h
content/html/content/src/nsHTMLAudioElement.cpp
content/html/content/src/nsHTMLMediaElement.cpp
content/html/content/src/nsHTMLMediaError.cpp
content/html/content/src/nsHTMLMediaError.h
content/html/content/src/nsHTMLSourceElement.cpp
content/html/content/src/nsHTMLVideoElement.cpp
content/html/document/src/nsHTMLContentSink.cpp
content/media/Makefile.in
content/media/video/Makefile.in
content/media/video/public/Makefile.in
content/media/video/public/nsVideoDecoder.h
content/media/video/src/Makefile.in
content/media/video/src/nsVideoDecoder.cpp
content/xml/document/src/nsXMLContentSink.cpp
dom/public/idl/events/Makefile.in
dom/public/idl/events/nsIDOMProgressEvent.idl
dom/public/idl/html/Makefile.in
dom/public/idl/html/nsIDOMHTMLAudioElement.idl
dom/public/idl/html/nsIDOMHTMLMediaElement.idl
dom/public/idl/html/nsIDOMHTMLMediaError.idl
dom/public/idl/html/nsIDOMHTMLSourceElement.idl
dom/public/idl/html/nsIDOMHTMLTimeRanges.idl
dom/public/idl/html/nsIDOMHTMLVideoElement.idl
dom/public/idl/html/nsIDOMHTMLVoidCallback.idl
dom/public/nsDOMClassInfoID.h
dom/src/base/nsDOMClassInfo.cpp
editor/libeditor/html/nsHTMLEditUtils.cpp
gfx/thebes/public/gfxImageSurface.h
gfx/thebes/src/gfxImageSurface.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsPresShell.cpp
layout/build/Makefile.in
layout/build/nsLayoutStatics.cpp
layout/generic/Makefile.in
layout/generic/nsVideoFrame.cpp
layout/generic/nsVideoFrame.h
layout/style/forms.css
parser/htmlparser/public/nsHTMLTagList.h
parser/htmlparser/src/nsElementTable.cpp
parser/htmlparser/src/nsHTMLTags.cpp
toolkit/content/jar.mn
toolkit/content/widgets/videocontrols.xml
toolkit/toolkit-makefiles.sh
widget/public/nsGUIEvent.h
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -156,16 +156,17 @@ MOZ_PLACES_BOOKMARKS = @MOZ_PLACES_BOOKM
 MOZ_STORAGE = @MOZ_STORAGE@
 MOZ_SAFE_BROWSING = @MOZ_SAFE_BROWSING@
 MOZ_URL_CLASSIFIER = @MOZ_URL_CLASSIFIER@
 MOZ_ZIPWRITER = @MOZ_ZIPWRITER@
 MOZ_MORK = @MOZ_MORK@
 MOZ_MORKREADER = @MOZ_MORKREADER@
 MOZ_NO_XPCOM_OBSOLETE = @MOZ_NO_XPCOM_OBSOLETE@
 MOZ_NO_FAST_LOAD = @MOZ_NO_FAST_LOAD@
+MOZ_MEDIA = @MOZ_MEDIA@
 NS_PRINTING = @NS_PRINTING@
 MOZ_CRASHREPORTER = @MOZ_CRASHREPORTER@
 MOZ_MOCHITEST = @MOZ_MOCHITEST@
 MOZ_HELP_VIEWER = @MOZ_HELP_VIEWER@
 
 MOZ_JAVAXPCOM = @MOZ_JAVAXPCOM@
 JAVA_INCLUDE_PATH="@JAVA_INCLUDE_PATH@"
 JAVA="@JAVA@"
--- a/configure.in
+++ b/configure.in
@@ -4310,16 +4310,17 @@ MOZ_MATHML=1
 MOZ_MOCHITEST=1
 MOZ_MORK=1
 MOZ_MORKREADER=
 MOZ_AUTH_EXTENSION=1
 MOZ_NO_ACTIVEX_SUPPORT=1
 MOZ_NO_INSPECTOR_APIS=
 MOZ_NO_XPCOM_OBSOLETE=
 MOZ_NO_FAST_LOAD=
+MOZ_MEDIA=
 MOZ_OJI=
 MOZ_PERMISSIONS=1
 MOZ_PLACES=
 MOZ_PLAINTEXT_EDITOR_ONLY=
 MOZ_PLUGINS=1
 MOZ_PREF_EXTENSIONS=1
 MOZ_PROFILELOCKING=1
 MOZ_PROFILESHARING=1
@@ -5279,16 +5280,30 @@ MOZ_ARG_DISABLE_BOOL(xpcom-fastload,
 
 AC_SUBST(MOZ_NO_FAST_LOAD)
 
 if test -n "$MOZ_NO_FAST_LOAD"; then
     AC_DEFINE(MOZ_NO_FAST_LOAD)
 fi
 
 dnl ========================================================
+dnl = Enable HTML video and audio support
+dnl ========================================================
+MOZ_ARG_ENABLE_BOOL(media,
+[  --enable-media           Enable HTML5 media support],
+    MOZ_MEDIA=1,
+    MOZ_MEDIA=)
+
+AC_SUBST(MOZ_MEDIA)
+
+if test -n "$MOZ_MEDIA"; then
+    AC_DEFINE(MOZ_MEDIA)
+fi
+
+dnl ========================================================
 dnl Permissions System
 dnl ========================================================
 MOZ_ARG_DISABLE_BOOL(permissions,
 [  --disable-permissions   Disable permissions (popup and cookie blocking)],
     MOZ_PERMISSIONS=,
     MOZ_PERMISSIONS=1
 )
 
--- a/content/Makefile.in
+++ b/content/Makefile.in
@@ -40,16 +40,22 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= content
 DIRS		= base canvas html xml xul xbl xslt
 
+ifdef MOZ_MEDIA
+DIRS		+= \
+		media \
+		$(NULL)
+endif
+
 ifdef MOZ_SVG
 DIRS		+= svg
 endif
 
 ifdef MOZ_XTF
 DIRS            += xtf
 endif
 
--- a/content/base/src/nsAttrValue.cpp
+++ b/content/base/src/nsAttrValue.cpp
@@ -395,18 +395,27 @@ nsAttrValue::ToString(nsAString& aResult
         aResult.Truncate();
       }
       break;
     }
 #ifdef MOZ_SVG
     case eSVGValue:
     {
       GetMiscContainer()->mSVGValue->GetValueString(aResult);
+      break;
     }
 #endif
+    case eFloatValue:
+    {
+      nsAutoString str;
+      str.AppendFloat(GetFloatValue());
+      aResult = str;
+
+      break;
+    }
   }
 }
 
 const nsCheapString
 nsAttrValue::GetStringValue() const
 {
   NS_PRECONDITION(Type() == eString, "wrong type");
 
@@ -955,16 +964,29 @@ nsAttrValue::ParseColor(const nsAString&
     MiscContainer* cont = GetMiscContainer();
     cont->mColor = color;
     cont->mType = eColor;
   }
 
   return PR_TRUE;
 }
 
+PRBool nsAttrValue::ParseFloatValue(const nsAString& aString)
+{
+  ResetIfSet();
+
+  PRInt32 ec;
+  float val = PromiseFlatString(aString).ToFloat(&ec);
+  if (NS_FAILED(ec)) {
+    return PR_FALSE;
+  }
+  SetFloatValue(val);
+  return PR_TRUE;
+}
+
 PRBool
 nsAttrValue::EnsureEmptyMiscContainer()
 {
   MiscContainer* cont;
   if (BaseType() == eOtherBase) {
     cont = GetMiscContainer();
     switch (cont->mType) {
       case eCSSStyleRule:
--- a/content/base/src/nsAttrValue.h
+++ b/content/base/src/nsAttrValue.h
@@ -112,16 +112,17 @@ public:
     ePercent =      0x0F, // 1111
     // Values below here won't matter, they'll be stored in the 'misc' struct
     // anyway
     eCSSStyleRule = 0x10,
     eAtomArray =    0x11 
 #ifdef MOZ_SVG
     ,eSVGValue =    0x12
 #endif
+    ,eFloatValue  = 0x13
   };
 
   ValueType Type() const;
 
   void Reset();
 
   void SetTo(const nsAttrValue& aOther);
   void SetTo(const nsAString& aValue);
@@ -144,16 +145,17 @@ public:
   PRBool GetColorValue(nscolor& aColor) const;
   inline PRInt16 GetEnumValue() const;
   inline float GetPercentValue() const;
   inline nsCOMArray<nsIAtom>* GetAtomArrayValue() const;
   inline nsICSSStyleRule* GetCSSStyleRuleValue() const;
 #ifdef MOZ_SVG
   inline nsISVGValue* GetSVGValue() const;
 #endif
+  inline float GetFloatValue() const;
 
   // Methods to get access to atoms we may have
   // Returns the number of atoms we have; 0 if we have none.  It's OK
   // to call this without checking the type first; it handles that.
   PRInt32 GetAtomCount() const;
   // Returns the atom at aIndex (0-based).  Do not call this with
   // aIndex >= GetAtomCount().
   nsIAtom* AtomAt(PRInt32 aIndex) const;
@@ -241,16 +243,24 @@ public:
    * Parse a string into a color.
    *
    * @param aString the string to parse
    * @param aDocument the document (to find out whether we're in quirks mode)
    * @return whether the value could be parsed
    */
   PRBool ParseColor(const nsAString& aString, nsIDocument* aDocument);
 
+  /**
+   * Parse a string value into a float.
+   *
+   * @param aString the string to parse
+   * @return whether the value could be parsed
+   */
+  PRBool ParseFloatValue(const nsAString& aString);
+
 private:
   // These have to be the same as in ValueType
   enum ValueBaseType {
     eStringBase =    eString,    // 00
     eOtherBase =     0x01,       // 01
     eAtomBase =      eAtom,      // 10
     eIntegerBase =   0x03        // 11
   };
@@ -260,23 +270,25 @@ private:
     ValueType mType;
     union {
       nscolor mColor;
       nsICSSStyleRule* mCSSStyleRule;
       nsCOMArray<nsIAtom>* mAtomArray;
 #ifdef MOZ_SVG
       nsISVGValue* mSVGValue;
 #endif
+      float mFloatValue;
     };
   };
 
   inline ValueBaseType BaseType() const;
 
   inline void SetPtrValueAndType(void* aValue, ValueBaseType aType);
   inline void SetIntValueAndType(PRInt32 aValue, ValueType aType);
+  inline void SetFloatValue(float aValue);
   inline void ResetIfSet();
 
   inline void* GetPtr() const;
   inline MiscContainer* GetMiscContainer() const;
   inline PRInt32 GetIntInternal() const;
 
   PRBool EnsureEmptyMiscContainer();
   PRBool EnsureEmptyAtomArray();
@@ -340,16 +352,23 @@ nsAttrValue::GetCSSStyleRuleValue() cons
 inline nsISVGValue*
 nsAttrValue::GetSVGValue() const
 {
   NS_PRECONDITION(Type() == eSVGValue, "wrong type");
   return GetMiscContainer()->mSVGValue;
 }
 #endif
 
+inline float
+nsAttrValue::GetFloatValue() const
+{
+  NS_PRECONDITION(Type() == eFloatValue, "wrong type");
+  return GetMiscContainer()->mFloatValue;
+}
+
 inline nsAttrValue::ValueBaseType
 nsAttrValue::BaseType() const
 {
   return static_cast<ValueBaseType>(mBits & NS_ATTRVALUE_BASETYPE_MASK);
 }
 
 inline void
 nsAttrValue::SetPtrValueAndType(void* aValue, ValueBaseType aType)
@@ -368,16 +387,25 @@ nsAttrValue::SetIntValueAndType(PRInt32 
     NS_ASSERTION(tmp / NS_ATTRVALUE_INTEGERTYPE_MULTIPLIER == aValue,
                  "Integer too big to fit");
   }
 #endif
   mBits = (aValue * NS_ATTRVALUE_INTEGERTYPE_MULTIPLIER) | aType;
 }
 
 inline void
+nsAttrValue::SetFloatValue(float aValue)
+{
+  if (EnsureEmptyMiscContainer()) {
+    MiscContainer* cont = GetMiscContainer();
+    cont->mFloatValue = aValue;
+    cont->mType = eFloatValue;
+  }
+}
+inline void
 nsAttrValue::ResetIfSet()
 {
   if (mBits) {
     Reset();
   }
 }
 
 inline void*
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -432,16 +432,38 @@ nsContentUtils::InitializeEventTable() {
     { &nsGkAtoms::onSVGUnload,                   { NS_SVG_UNLOAD, EventNameType_None }},
     { &nsGkAtoms::onSVGAbort,                    { NS_SVG_ABORT, EventNameType_None }},
     { &nsGkAtoms::onSVGError,                    { NS_SVG_ERROR, EventNameType_None }},
     { &nsGkAtoms::onSVGResize,                   { NS_SVG_RESIZE, EventNameType_None }},
     { &nsGkAtoms::onSVGScroll,                   { NS_SVG_SCROLL, EventNameType_None }},
     { &nsGkAtoms::onSVGZoom,                     { NS_SVG_ZOOM, EventNameType_None }},
     { &nsGkAtoms::onzoom,                        { NS_SVG_ZOOM, EventNameType_SVGSVG }}
 #endif // MOZ_SVG
+#ifdef MOZ_MEDIA 
+   ,{ &nsGkAtoms::onloadstart,                   { NS_LOADSTART, EventNameType_HTML }},
+    { &nsGkAtoms::onprogress,                    { NS_PROGRESS, EventNameType_HTML }},
+    { &nsGkAtoms::onloadedmetadata,              { NS_LOADEDMETADATA, EventNameType_HTML }},
+    { &nsGkAtoms::onloadedfirstframe,            { NS_LOADEDFIRSTFRAME, EventNameType_HTML }},
+    { &nsGkAtoms::onemptied,                     { NS_EMPTIED, EventNameType_HTML }},
+    { &nsGkAtoms::onstalled,                     { NS_STALLED, EventNameType_HTML }},
+    { &nsGkAtoms::onplay,                        { NS_PLAY, EventNameType_HTML }},
+    { &nsGkAtoms::onpause,                       { NS_PAUSE, EventNameType_HTML }},
+    { &nsGkAtoms::onwaiting,                     { NS_WAITING, EventNameType_HTML }},
+    { &nsGkAtoms::onseeking,                     { NS_SEEKING, EventNameType_HTML }},
+    { &nsGkAtoms::onseeked,                      { NS_SEEKED, EventNameType_HTML }},
+    { &nsGkAtoms::ontimeupdate,                  { NS_TIMEUPDATE, EventNameType_HTML }},
+    { &nsGkAtoms::onended,                       { NS_ENDED, EventNameType_HTML }},
+    { &nsGkAtoms::ondataunavailable,             { NS_DATAUNAVAILABLE, EventNameType_HTML }},
+    { &nsGkAtoms::oncanshowcurrentframe,         { NS_CANSHOWCURRENTFRAME, EventNameType_HTML }},
+    { &nsGkAtoms::oncanplay,                     { NS_CANPLAY, EventNameType_HTML }},
+    { &nsGkAtoms::oncanplaythrough,              { NS_CANPLAYTHROUGH, EventNameType_HTML }},
+    { &nsGkAtoms::onratechange,                  { NS_RATECHANGE, EventNameType_HTML }},
+    { &nsGkAtoms::ondurationchange,              { NS_DURATIONCHANGE, EventNameType_HTML }},
+    { &nsGkAtoms::onvolumechange,                { NS_VOLUMECHANGE, EventNameType_HTML }},
+#endif //MOZ_MEDIA
   };
 
   sEventTable = new nsDataHashtable<nsISupportsHashKey, EventNameMapping>;
   if (!sEventTable ||
       !sEventTable->Init(int(NS_ARRAY_LENGTH(eventArray) / 0.75) + 1)) {
     delete sEventTable;
     sEventTable = nsnull;
     return PR_FALSE;
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -106,16 +106,19 @@ GK_ATOM(area, "area")
 GK_ATOM(ascending, "ascending")
 GK_ATOM(assign, "assign")
 GK_ATOM(attribute, "attribute")
 GK_ATOM(attributeSet, "attribute-set")
 GK_ATOM(aural, "aural")
 GK_ATOM(_auto, "auto")
 GK_ATOM(autocheck, "autocheck")
 GK_ATOM(autocomplete, "autocomplete")
+#ifdef MOZ_MEDIA
+GK_ATOM(autoplay, "autoplay")
+#endif
 GK_ATOM(autorepeatbutton, "autorepeatbutton")
 GK_ATOM(axis, "axis")
 GK_ATOM(b, "b")
 GK_ATOM(background, "background")
 GK_ATOM(base, "base")
 GK_ATOM(basefont, "basefont")
 GK_ATOM(baseLevel, "BaseLevel")                            // PRUint8
 GK_ATOM(baseline, "baseline")
@@ -224,16 +227,19 @@ GK_ATOM(headerContentLanguage, "content-
 GK_ATOM(contentLocation, "content-location")
 GK_ATOM(headerContentScriptType, "content-script-type")
 GK_ATOM(headerContentStyleType, "content-style-type")
 GK_ATOM(headerContentType, "content-type")
 GK_ATOM(context, "context")
 GK_ATOM(contextmenu, "contextmenu")
 GK_ATOM(contextmenulistener, "contextmenulistener")
 GK_ATOM(control, "control")
+#ifdef MOZ_MEDIA
+GK_ATOM(controls, "controls")
+#endif
 GK_ATOM(coords, "coords")
 GK_ATOM(copy, "copy")
 GK_ATOM(copyOf, "copy-of")
 GK_ATOM(count, "count")
 GK_ATOM(crop, "crop")
 GK_ATOM(curpos, "curpos")
 GK_ATOM(current, "current")
 GK_ATOM(cycler, "cycler")
@@ -251,16 +257,19 @@ GK_ATOM(declare, "declare")
 GK_ATOM(decrement, "decrement")
 GK_ATOM(_default, "default")
 GK_ATOM(headerDefaultStyle, "default-style")
 GK_ATOM(defaultAction, "defaultAction")
 GK_ATOM(defaultchecked, "defaultchecked")
 GK_ATOM(defaultLabel, "defaultLabel")
 GK_ATOM(defaultselected, "defaultselected")
 GK_ATOM(defaultvalue, "defaultvalue")
+#ifdef MOZ_MEDIA
+GK_ATOM(defaultplaybackrate, "defaultplaybackrate")
+#endif
 GK_ATOM(defer, "defer")
 GK_ATOM(del, "del")
 GK_ATOM(descendant, "descendant")
 GK_ATOM(descendantOrSelf, "descendant-or-self")
 GK_ATOM(descending, "descending")
 GK_ATOM(description, "description")
 GK_ATOM(destructor, "destructor")
 GK_ATOM(dfn, "dfn")
@@ -661,31 +670,37 @@ GK_ATOM(parent, "parent")
 GK_ATOM(parsetype, "parsetype")
 GK_ATOM(patternSeparator, "pattern-separator")
 GK_ATOM(perMille, "per-mille")
 GK_ATOM(percent, "percent")
 GK_ATOM(persist, "persist")
 GK_ATOM(phase, "phase")
 GK_ATOM(ping, "ping")
 GK_ATOM(plaintext, "plaintext")
+#ifdef MOZ_MEDIA
+GK_ATOM(playbackrate, "playbackrate")
+#endif
 GK_ATOM(pointSize, "point-size")
 GK_ATOM(poly, "poly")
 GK_ATOM(polygon, "polygon")
 GK_ATOM(popup, "popup")
 GK_ATOM(popupList, "Popup-list")
 GK_ATOM(popupalign, "popupalign")
 GK_ATOM(popupanchor, "popupanchor")
 GK_ATOM(popupgroup, "popupgroup")
 GK_ATOM(popuphidden, "popuphidden")
 GK_ATOM(popuphiding, "popuphiding")
 GK_ATOM(popuplistener, "popuplistener")
 GK_ATOM(popupset, "popupset")
 GK_ATOM(popupshowing, "popupshowing")
 GK_ATOM(popupshown, "popupshown")
 GK_ATOM(position, "position")
+#ifdef MOZ_MEDIA
+GK_ATOM(poster, "poster")
+#endif
 GK_ATOM(pre, "pre")
 GK_ATOM(preceding, "preceding")
 GK_ATOM(precedingSibling, "preceding-sibling")
 GK_ATOM(predicate, "predicate")
 GK_ATOM(prefix, "prefix")
 GK_ATOM(preserve, "preserve")
 GK_ATOM(preserveSpace, "preserve-space")
 GK_ATOM(preventdefault, "preventdefault")
@@ -778,16 +793,19 @@ GK_ATOM(sort, "sort")
 GK_ATOM(sortActive, "sortActive")
 GK_ATOM(sortDirection, "sortDirection")
 GK_ATOM(sorted, "sorted")
 GK_ATOM(sortLocked, "sortLocked")
 GK_ATOM(sortResource, "sortResource")
 GK_ATOM(sortResource2, "sortResource2")
 GK_ATOM(sortSeparators, "sortSeparators")
 GK_ATOM(sortStaticsLast, "sortStaticsLast")
+#ifdef MOZ_MEDIA
+GK_ATOM(source, "source")
+#endif
 GK_ATOM(space, "space")
 GK_ATOM(spacer, "spacer")
 GK_ATOM(span, "span")
 GK_ATOM(spellcheck, "spellcheck")
 GK_ATOM(spinner, "spinner")
 GK_ATOM(split, "split")
 GK_ATOM(splitter, "splitter")
 GK_ATOM(spring, "spring")
@@ -906,16 +924,21 @@ GK_ATOM(var, "var")
 GK_ATOM(variable, "variable")
 GK_ATOM(vbox, "vbox")
 GK_ATOM(vcard_name, "vcard_name")
 GK_ATOM(vendor, "vendor")
 GK_ATOM(vendorUrl, "vendor-url")
 GK_ATOM(version, "version")
 GK_ATOM(vert, "vert")
 GK_ATOM(vertical, "vertical")
+#ifdef MOZ_MEDIA
+GK_ATOM(audio, "audio")
+GK_ATOM(video, "video")
+GK_ATOM(videocontrols, "videocontrols")
+#endif
 GK_ATOM(visibility, "visibility")
 GK_ATOM(vlink, "vlink")
 GK_ATOM(vspace, "vspace")
 GK_ATOM(wbr, "wbr")
 GK_ATOM(when, "when")
 GK_ATOM(where, "where")
 GK_ATOM(widget, "widget")
 GK_ATOM(width, "width")
@@ -1485,16 +1508,59 @@ GK_ATOM(svgPathGeometryFrame, "SVGPathGe
 GK_ATOM(svgPatternFrame, "SVGPatternFrame")
 GK_ATOM(svgRadialGradientFrame, "SVGRadialGradientFrame")
 GK_ATOM(svgStopFrame, "SVGStopFrame")
 GK_ATOM(svgTextFrame, "SVGTextFrame")
 GK_ATOM(svgTextPathFrame, "SVGTextPathFrame")
 GK_ATOM(svgTSpanFrame, "SVGTSpanFrame")
 GK_ATOM(svgUseFrame, "SVGUseFrame")
 #endif
+#ifdef MOZ_MEDIA
+GK_ATOM(HTMLVideoFrame, "VideoFrame")
+GK_ATOM(onloadstart, "onloadstart")
+GK_ATOM(onprogress, "onprogress")
+GK_ATOM(onloadedmetadata, "onloadedmetadata")
+GK_ATOM(onloadedfirstframe, "onloadedfirstframe")
+GK_ATOM(onemptied, "onemptied")
+GK_ATOM(onstalled, "onstalled")
+GK_ATOM(onplay, "onplay")
+GK_ATOM(onpause, "onpause")
+GK_ATOM(onwaiting, "onwaiting")
+GK_ATOM(onseeking, "onseeking")
+GK_ATOM(onseeked, "onseeked")
+GK_ATOM(ontimeupdate, "ontimeupdate")
+GK_ATOM(onended, "onended")
+GK_ATOM(ondataunavailable, "ondataunavailable")
+GK_ATOM(oncanshowcurrentframe, "oncanshowcurrentframe")
+GK_ATOM(oncanplay, "oncanplay")
+GK_ATOM(oncanplaythrough, "oncanplaythrough")
+GK_ATOM(onratechange, "onratechange")
+GK_ATOM(ondurationchange, "ondurationchange")
+GK_ATOM(onvolumechange, "onvolumechange")
+GK_ATOM(loadstart, "loadstart")
+GK_ATOM(progress, "progress")
+GK_ATOM(loadedmetadata, "loadedmetadata")
+GK_ATOM(loadedfirstframe, "loadedfirstframe")
+GK_ATOM(emptied, "emptied")
+GK_ATOM(stalled, "stalled")
+GK_ATOM(play, "play")
+GK_ATOM(pause, "pause")
+GK_ATOM(waiting, "waiting")
+GK_ATOM(seeking, "seeking")
+GK_ATOM(seeked, "seeked")
+GK_ATOM(timeupdate, "timeupdate")
+GK_ATOM(ended, "ended")
+GK_ATOM(dataunavailable, "dataunavailable")
+GK_ATOM(canshowcurrentframe, "canshowcurrentframe")
+GK_ATOM(canplay, "canplay")
+GK_ATOM(canplaythrough, "canplaythrough")
+GK_ATOM(ratechange, "ratechange")
+GK_ATOM(durationchange, "durationchange")
+GK_ATOM(volumechange, "volumechange")
+#endif
 
 // Frame property names
 GK_ATOM(boxMetricsProperty, "BoxMetricsProperty") // nsBoxLayoutMetrics*
 GK_ATOM(changeListProperty, "ChangeListProperty") // void*
 GK_ATOM(collapseOffsetProperty, "CollapseOffsetProperty")  // nsPoint*
 GK_ATOM(computedOffsetProperty, "ComputedOffsetProperty")  // nsPoint*
 GK_ATOM(generatedContent, "GeneratedContentProperty")  // nsCOMArray<nsIContent>*
 #ifdef MOZ_MATHML
--- a/content/events/public/nsIPrivateDOMEvent.h
+++ b/content/events/public/nsIPrivateDOMEvent.h
@@ -99,10 +99,13 @@ nsresult
 NS_NewDOMSVGZoomEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsGUIEvent* aEvent);
 #endif // MOZ_SVG
 nsresult
 NS_NewDOMXULCommandEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsXULCommandEvent* aEvent);
 nsresult
 NS_NewDOMCommandEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsCommandEvent* aEvent);
 nsresult
 NS_NewDOMMessageEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsEvent* aEvent);
-
+#ifdef MOZ_MEDIA
+nsresult
+NS_NewDOMProgressEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsEvent* aEvent);
+#endif // MOZ_MEDIA
 #endif // nsIPrivateDOMEvent_h__
--- a/content/events/src/Makefile.in
+++ b/content/events/src/Makefile.in
@@ -87,16 +87,22 @@ CPPSRCS		= \
 		nsXMLEventsManager.cpp \
 		nsXMLEventsElement.cpp \
 		nsPLDOMEvent.cpp \
 		nsEventDispatcher.cpp \
 		nsIMEStateManager.cpp \
 		nsQueryContentEventHandler.cpp \
 		$(NULL)
 
+ifdef MOZ_MEDIA
+CPPSRCS		+= \
+		nsDOMProgressEvent.cpp \
+		$(NULL)
+endif
+
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES	= \
              -I$(srcdir)/../../base/src \
              -I$(srcdir)/../../html/base/src \
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -72,16 +72,24 @@ static const char* const sEventNames[] =
   "DOMActivate", "DOMFocusIn", "DOMFocusOut",
   "pageshow", "pagehide", "DOMMouseScroll", "offline", "online",
   "copy", "cut", "paste"
 #ifdef MOZ_SVG
  ,
   "SVGLoad", "SVGUnload", "SVGAbort", "SVGError", "SVGResize", "SVGScroll",
   "SVGZoom"
 #endif // MOZ_SVG
+#ifdef MOZ_MEDIA
+  ,
+  "loadstart", "progress", "loadedmetadata", "loadedfirstframe",
+  "emptied", "stalled", "play", "pause",
+  "waiting", "seeking", "seeked", "timeupdate", "ended", "dataunavailable",
+  "canshowcurrentframe", "canplay", "canplaythrough", "ratechange",
+  "durationchange", "volumechange"
+#endif // MOZ_MEDIA
 };
 
 static char *sPopupAllowedEvents;
 
 
 nsDOMEvent::nsDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent)
 {
   mPresContext = aPresContext;
@@ -553,16 +561,66 @@ nsDOMEvent::SetEventType(const nsAString
     else if (atom == nsGkAtoms::onSVGScroll)
       mEvent->message = NS_SVG_SCROLL;
   } else if (mEvent->eventStructType == NS_SVGZOOM_EVENT) {
     if (atom == nsGkAtoms::onSVGZoom)
       mEvent->message = NS_SVG_ZOOM;
   }
 #endif // MOZ_SVG
 
+#ifdef MOZ_MEDIA
+  else if (mEvent->eventStructType == NS_MEDIA_EVENT) {
+    if (atom == nsGkAtoms::onloadstart)
+      mEvent->message = NS_LOADSTART;
+    else if (atom == nsGkAtoms::onprogress)
+      mEvent->message = NS_PROGRESS;
+    else if (atom == nsGkAtoms::onloadedmetadata)
+      mEvent->message = NS_LOADEDMETADATA;
+    else if (atom == nsGkAtoms::onloadedfirstframe)
+      mEvent->message = NS_LOADEDFIRSTFRAME;
+    else if (atom == nsGkAtoms::onemptied)
+      mEvent->message = NS_EMPTIED;
+    else if (atom == nsGkAtoms::onstalled)
+      mEvent->message = NS_STALLED;
+    else if (atom == nsGkAtoms::onplay)
+      mEvent->message = NS_PLAY;
+    else if (atom == nsGkAtoms::onpause)
+      mEvent->message = NS_PAUSE;
+    else if (atom == nsGkAtoms::onwaiting)
+      mEvent->message = NS_WAITING;
+    else if (atom == nsGkAtoms::onwaiting)
+      mEvent->message = NS_SEEKING;
+    else if (atom == nsGkAtoms::onseeking)
+      mEvent->message = NS_SEEKED;
+    else if (atom == nsGkAtoms::onseeked)
+      mEvent->message = NS_TIMEUPDATE;
+    else if (atom == nsGkAtoms::onended)
+      mEvent->message = NS_ENDED;
+    else if (atom == nsGkAtoms::ondataunavailable)
+      mEvent->message = NS_DATAUNAVAILABLE;
+    else if (atom == nsGkAtoms::oncanshowcurrentframe)
+      mEvent->message = NS_CANSHOWCURRENTFRAME;
+    else if (atom == nsGkAtoms::oncanplay)
+      mEvent->message = NS_CANPLAY;
+    else if (atom == nsGkAtoms::oncanplaythrough)
+      mEvent->message = NS_CANPLAYTHROUGH;
+    else if (atom == nsGkAtoms::onratechange)
+      mEvent->message = NS_RATECHANGE;
+    else if (atom == nsGkAtoms::ondurationchange)
+      mEvent->message = NS_DURATIONCHANGE;
+    else if (atom == nsGkAtoms::onvolumechange)
+      mEvent->message = NS_VOLUMECHANGE;
+    else if (atom == nsGkAtoms::onload)
+      mEvent->message = NS_LOAD;
+    else if (atom == nsGkAtoms::onabort)
+      mEvent->message = NS_MEDIA_ABORT;
+    else if (atom == nsGkAtoms::onerror)
+      mEvent->message = NS_MEDIA_ERROR;
+  }
+#endif // MOZ_MEDIA
   if (mEvent->message == NS_USER_DEFINED_EVENT)
     mEvent->userType = atom;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMEvent::InitEvent(const nsAString& aEventTypeArg, PRBool aCanBubbleArg, PRBool aCancelableArg)
@@ -1317,16 +1375,58 @@ const char* nsDOMEvent::GetEventName(PRU
     return sEventNames[eDOMEvents_SVGError];
   case NS_SVG_RESIZE:
     return sEventNames[eDOMEvents_SVGResize];
   case NS_SVG_SCROLL:
     return sEventNames[eDOMEvents_SVGScroll];
   case NS_SVG_ZOOM:
     return sEventNames[eDOMEvents_SVGZoom];
 #endif // MOZ_SVG
+#ifdef MOZ_MEDIA
+  case NS_LOADSTART:
+    return sEventNames[eDOMEvents_loadstart];
+  case NS_PROGRESS:
+    return sEventNames[eDOMEvents_progress];
+  case NS_LOADEDMETADATA:
+    return sEventNames[eDOMEvents_loadedmetadata];
+  case NS_LOADEDFIRSTFRAME:
+    return sEventNames[eDOMEvents_loadedfirstframe];
+  case NS_EMPTIED:
+    return sEventNames[eDOMEvents_emptied];
+  case NS_STALLED:
+    return sEventNames[eDOMEvents_stalled];
+  case NS_PLAY:
+    return sEventNames[eDOMEvents_play];
+  case NS_PAUSE:
+    return sEventNames[eDOMEvents_pause];
+  case NS_WAITING:
+    return sEventNames[eDOMEvents_waiting];
+  case NS_SEEKING:
+    return sEventNames[eDOMEvents_seeking];
+  case NS_SEEKED:
+    return sEventNames[eDOMEvents_seeked];
+  case NS_TIMEUPDATE:
+    return sEventNames[eDOMEvents_timeupdate];
+  case NS_ENDED:
+    return sEventNames[eDOMEvents_ended];
+  case NS_DATAUNAVAILABLE:
+    return sEventNames[eDOMEvents_dataunavailable];
+  case NS_CANSHOWCURRENTFRAME:
+    return sEventNames[eDOMEvents_canshowcurrentframe];
+  case NS_CANPLAY:
+    return sEventNames[eDOMEvents_canplay];
+  case NS_CANPLAYTHROUGH:
+    return sEventNames[eDOMEvents_canplaythrough];
+  case NS_RATECHANGE:
+    return sEventNames[eDOMEvents_ratechange];
+  case NS_DURATIONCHANGE:
+    return sEventNames[eDOMEvents_durationchange];
+  case NS_VOLUMECHANGE:
+    return sEventNames[eDOMEvents_volumechange];
+#endif
   default:
     break;
   }
   // XXXldb We can hit this case for nsEvent objects that we didn't
   // create and that are not user defined events since this function and
   // SetEventType are incomplete.  (But fixing that requires fixing the
   // arrays in nsEventListenerManager too, since the events for which
   // this is a problem generally *are* created by nsDOMEvent.)
--- a/content/events/src/nsDOMEvent.h
+++ b/content/events/src/nsDOMEvent.h
@@ -131,16 +131,39 @@ public:
     eDOMEvents_SVGLoad,
     eDOMEvents_SVGUnload,
     eDOMEvents_SVGAbort,
     eDOMEvents_SVGError,
     eDOMEvents_SVGResize,
     eDOMEvents_SVGScroll,
     eDOMEvents_SVGZoom
 #endif // MOZ_SVG
+#ifdef MOZ_MEDIA
+    ,
+    eDOMEvents_loadstart,
+    eDOMEvents_progress,
+    eDOMEvents_loadedmetadata,
+    eDOMEvents_loadedfirstframe,
+    eDOMEvents_emptied,
+    eDOMEvents_stalled,
+    eDOMEvents_play,
+    eDOMEvents_pause,
+    eDOMEvents_waiting,
+    eDOMEvents_seeking,
+    eDOMEvents_seeked,
+    eDOMEvents_timeupdate,
+    eDOMEvents_ended,
+    eDOMEvents_dataunavailable,
+    eDOMEvents_canshowcurrentframe,
+    eDOMEvents_canplay,
+    eDOMEvents_canplaythrough,
+    eDOMEvents_ratechange,
+    eDOMEvents_durationchange,
+    eDOMEvents_volumechange
+#endif
   };
 
   nsDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent);
   virtual ~nsDOMEvent();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDOMEvent, nsIDOMEvent)
 
new file mode 100644
--- /dev/null
+++ b/content/events/src/nsDOMProgressEvent.cpp
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: ML 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 "nsDOMProgressEvent.h"
+#include "nsContentUtils.h"
+
+
+NS_INTERFACE_MAP_BEGIN(nsDOMProgressEvent)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMProgressEvent)
+  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(ProgressEvent)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
+
+NS_IMPL_ADDREF_INHERITED(nsDOMProgressEvent, nsDOMEvent)
+NS_IMPL_RELEASE_INHERITED(nsDOMProgressEvent, nsDOMEvent)
+
+NS_IMETHODIMP
+nsDOMProgressEvent::GetLengthComputable(PRBool* aLengthComputable)
+{
+  if (aLengthComputable)
+    *aLengthComputable = mLengthComputable;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMProgressEvent::GetLoaded(PRUint32* aLoaded)
+{
+  if (aLoaded)
+    *aLoaded = mLoaded;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMProgressEvent::GetTotal(PRUint32* aTotal)
+{
+  if (aTotal)
+    *aTotal = mTotal;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMProgressEvent::InitProgressEvent(const nsAString& aType,
+                                      PRBool aCanBubble,
+                                      PRBool aCancelable,
+                                      PRBool aLengthComputable,
+                                      PRUint32 aLoaded,
+                                      PRUint32 aTotal)
+{
+  nsresult rv = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  mLoaded = aLoaded;
+  mLengthComputable = aLengthComputable;
+  mTotal = aTotal;
+
+  return NS_OK;
+}
+
+nsresult
+NS_NewDOMProgressEvent(nsIDOMEvent** aInstancePtrResult,
+                       nsPresContext* aPresContext,
+                       nsEvent* aEvent) 
+{
+  nsDOMProgressEvent* it = new nsDOMProgressEvent(aPresContext, aEvent);
+  if (nsnull == it)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  return CallQueryInterface(it, aInstancePtrResult);
+}
new file mode 100644
--- /dev/null
+++ b/content/events/src/nsDOMProgressEvent.h
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: ML 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 ***** */
+
+#ifndef nsDOMProgressEvent_h__
+#define nsDOMProgressEvent_h__
+
+#include "nsIDOMProgressEvent.h"
+#include "nsDOMEvent.h"
+
+/**
+ * Implements the ProgressEvent event, used for progress events from the media
+ * elements.
+
+ * See http://www.whatwg.org/specs/web-apps/current-work/#progress0 for
+ * further details.
+ */
+class nsDOMProgressEvent : public nsIDOMProgressEvent,
+                           public nsDOMEvent
+{
+public:
+  nsDOMProgressEvent(nsPresContext* aPresContext, nsEvent* aEvent)
+    : nsDOMEvent(aPresContext, aEvent)
+  {
+  }
+  
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_NSIDOMPROGRESSEVENT
+    
+  // Forward to base class
+  NS_FORWARD_TO_NSDOMEVENT
+
+private:
+  PRBool  mLengthComputable;
+  PRUint32 mLoaded;
+  PRUint32 mTotal;
+};
+
+#endif // nsDOMProgressEvent_h__
--- a/content/events/src/nsEventDispatcher.cpp
+++ b/content/events/src/nsEventDispatcher.cpp
@@ -647,11 +647,15 @@ nsEventDispatcher::CreateEvent(nsPresCon
   if (aEventType.LowerCaseEqualsLiteral("commandevent") ||
       aEventType.LowerCaseEqualsLiteral("commandevents"))
     return NS_NewDOMCommandEvent(aDOMEvent, aPresContext, nsnull);
   if (aEventType.LowerCaseEqualsLiteral("datacontainerevent") ||
       aEventType.LowerCaseEqualsLiteral("datacontainerevents"))
     return NS_NewDOMDataContainerEvent(aDOMEvent, aPresContext, nsnull);
   if (aEventType.LowerCaseEqualsLiteral("messageevent"))
     return NS_NewDOMMessageEvent(aDOMEvent, aPresContext, nsnull);
+#ifdef MOZ_MEDIA
+  if (aEventType.LowerCaseEqualsLiteral("progressevent"))
+    return NS_NewDOMProgressEvent(aDOMEvent, aPresContext, nsnull);
+#endif // MOZ_MEDIA
 
   return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
 }
--- a/content/html/content/public/Makefile.in
+++ b/content/html/content/public/Makefile.in
@@ -59,12 +59,15 @@ EXPORTS		= \
 		nsIOptionElement.h \
 		nsIRadioControlElement.h \
 		nsIRadioVisitor.h \
 		nsIRadioGroupContainer.h \
 		nsITextControlElement.h \
 		nsIFileControlElement.h \
 		nsIFormSubmission.h \
 		nsIFrameSetElement.h \
+		nsHTMLAudioElement.h \
+		nsHTMLMediaElement.h \
+		nsHTMLVideoElement.h \
                 $(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
new file mode 100644
--- /dev/null
+++ b/content/html/content/public/nsHTMLAudioElement.h
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 "nsIDOMHTMLAudioElement.h"
+#include "nsHTMLMediaElement.h"
+#include "nsVideoDecoder.h"
+
+typedef PRUint16 nsMediaNetworkState;
+typedef PRUint16 nsMediaReadyState;
+
+class nsHTMLAudioElement : public nsHTMLMediaElement,
+                           public nsIDOMHTMLAudioElement
+{
+public:
+  nsHTMLAudioElement(nsINodeInfo *aNodeInfo, PRBool aFromParser = PR_FALSE);
+  virtual ~nsHTMLAudioElement();
+
+  // nsISupports
+  NS_DECL_ISUPPORTS_INHERITED
+
+  // nsIDOMNode
+  NS_FORWARD_NSIDOMNODE(nsHTMLMediaElement::)
+
+  // nsIDOMElement
+  NS_FORWARD_NSIDOMELEMENT(nsHTMLMediaElement::)
+
+  // nsIDOMHTMLElement
+  NS_FORWARD_NSIDOMHTMLELEMENT(nsHTMLMediaElement::)
+
+  // nsIDOMHTMLMediaElement
+  NS_FORWARD_NSIDOMHTMLMEDIAELEMENT(nsHTMLMediaElement::)
+
+  // nsIDOMHTMLAudioElement
+  NS_DECL_NSIDOMHTMLAUDIOELEMENT
+
+  virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
+  virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                              nsIContent* aBindingParent,
+                              PRBool aCompileEventHandlers);
+  virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
+                              PRBool aNullParent = PR_TRUE);
+protected:
+  virtual nsresult InitializeDecoder(nsAString& aChosenMediaResource);
+};
new file mode 100644
--- /dev/null
+++ b/content/html/content/public/nsHTMLMediaElement.h
@@ -0,0 +1,168 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 "nsIDOMHTMLMediaElement.h"
+#include "nsGenericHTMLElement.h"
+#include "nsVideoDecoder.h"
+
+// Define to output information on decoding and painting framerate
+/* #define DEBUG_FRAME_RATE 1 */
+
+typedef PRUint16 nsMediaNetworkState;
+typedef PRUint16 nsMediaReadyState;
+
+class nsHTMLMediaElement : public nsGenericHTMLElement
+{
+public:
+  nsHTMLMediaElement(nsINodeInfo *aNodeInfo, PRBool aFromParser = PR_FALSE);
+  virtual ~nsHTMLMediaElement();
+
+  // nsIDOMHTMLMediaElement
+  NS_DECL_NSIDOMHTMLMEDIAELEMENT
+
+  virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
+                                nsIAtom* aAttribute,
+                                const nsAString& aValue,
+                                nsAttrValue& aResult);
+  // SetAttr override.  C++ is stupid, so have to override both
+  // overloaded methods.
+  nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
+                   const nsAString& aValue, PRBool aNotify)
+  {
+    return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
+  }
+  virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
+                           nsIAtom* aPrefix, const nsAString& aValue,
+                           PRBool aNotify);
+
+  virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                              nsIContent* aBindingParent,
+                              PRBool aCompileEventHandlers);
+  virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
+                              PRBool aNullParent = PR_TRUE);
+
+  virtual PRBool IsDoneAddingChildren();
+  virtual nsresult DoneAddingChildren(PRBool aHaveNotified);
+
+  // Called by the video decoder object, on the main thread,
+  // when it has read the metadata containing video dimensions,
+  // etc.
+  void MetadataLoaded();
+
+  // Called by the video decoder object, on the main thread,
+  // when it has read the first frame of the video
+  void FirstFrameLoaded();
+
+  // Called by the video decoder object, on the main thread,
+  // when the resource has completed downloading.
+  void ResourceLoaded();
+
+  // Called by the video decoder object, on the main thread,
+  // when the resource has a network error during loading.
+  void NetworkError();
+
+  // Called by the video decoder object, on the main thread,
+  // when the video playback has ended.
+  void PlaybackCompleted();
+
+  // Draw the latest video data. See nsVideoDecoder for 
+  // details.
+  void Paint(gfxContext* aContext, const gfxRect& aRect);
+
+  // Dispatch events
+  nsresult DispatchSimpleEvent(const nsAString& aName);
+  nsresult DispatchProgressEvent(const nsAString& aName);
+  nsresult DispatchAsyncSimpleEvent(const nsAString& aName);
+  nsresult DispatchAsyncProgressEvent(const nsAString& aName);
+
+protected:
+  nsresult PickMediaElement(nsAString& aChosenMediaResource);
+  virtual nsresult InitializeDecoder(nsAString& aChosenMediaResource);
+
+  // Use this method to change the mReadyState member, so required
+  // events can be fired.
+  void ChangeReadyState(nsMediaReadyState aState);
+
+  nsRefPtr<nsVideoDecoder> mDecoder;
+
+  // Error attribute
+  nsCOMPtr<nsIDOMHTMLMediaError> mError;
+
+  // Media loading flags. See: 
+  //   http://www.whatwg.org/specs/web-apps/current-work/#video)
+  nsMediaNetworkState mNetworkState;
+  nsMediaReadyState mReadyState;
+
+  // If true then we have begun downloading the media content.
+  // Set to false when completed, or not yet started.
+  PRPackedBool mBegun;
+
+  // If truen then the video playback has completed.
+  PRPackedBool mEnded;
+
+  // True when the decoder has loaded enough data to display the
+  // first frame of the content.
+  PRPackedBool mLoadedFirstFrame;
+
+  // Indicates whether current playback is a result of user action
+  // (ie. calling of the Play method), or automatic playback due to
+  // the 'autoplay' attribute being set. A true value indicates the 
+  // latter case.
+  // The 'autoplay' HTML attribute indicates that the video should
+  // start playing when loaded. The 'autoplay' attribute of the object
+  // is a mirror of the HTML attribute. These are different from this
+  // 'mAutoplaying' flag, which indicates whether the current playback
+  // is a result of the autoplay attribute.
+  PRPackedBool mAutoplaying;
+
+  // Playback of the video is paused either due to calling the
+  // 'Pause' method, or playback not yet having started.
+  PRPackedBool mPaused;
+
+  // True if we are currently seeking through the media file.
+  PRPackedBool mSeeking;
+
+  // True if the sound is muted
+  PRPackedBool mMuted;
+
+  // Value of the volume before it was muted
+  float mMutedVolume; 
+
+  // Flag to indicate if the child elements (eg. <source/>) have been
+  // parsed.
+  PRPackedBool mIsDoneAddingChildren;
+};
new file mode 100644
--- /dev/null
+++ b/content/html/content/public/nsHTMLVideoElement.h
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 "nsIDOMHTMLVideoElement.h"
+#include "nsHTMLMediaElement.h"
+#include "nsVideoDecoder.h"
+
+class nsHTMLVideoElement : public nsHTMLMediaElement,
+                           public nsIDOMHTMLVideoElement
+{
+public:
+  nsHTMLVideoElement(nsINodeInfo *aNodeInfo, PRBool aFromParser = PR_FALSE);
+  virtual ~nsHTMLVideoElement();
+
+  // nsISupports
+  NS_DECL_ISUPPORTS_INHERITED
+
+  // nsIDOMNode
+  NS_FORWARD_NSIDOMNODE(nsHTMLMediaElement::)
+
+  // nsIDOMElement
+  NS_FORWARD_NSIDOMELEMENT(nsHTMLMediaElement::)
+
+  // nsIDOMHTMLElement
+  NS_FORWARD_NSIDOMHTMLELEMENT(nsHTMLMediaElement::)
+
+  // nsIDOMHTMLMediaElement
+  NS_FORWARD_NSIDOMHTMLMEDIAELEMENT(nsHTMLMediaElement::)
+
+  // nsIDOMHTMLVideoElement
+  NS_DECL_NSIDOMHTMLVIDEOELEMENT
+
+  virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
+  virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                              nsIContent* aBindingParent,
+                              PRBool aCompileEventHandlers);
+  virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
+                              PRBool aNullParent = PR_TRUE);
+
+  // Returns the current video frame width and height.
+  // If there is no video frame, returns the given default size.
+  nsIntSize GetVideoSize(nsIntSize defaultSize);
+  double GetVideoFramerate();
+
+protected:
+  virtual nsresult InitializeDecoder(nsAString& aChosenMediaResource);
+
+};
--- a/content/html/content/src/Makefile.in
+++ b/content/html/content/src/Makefile.in
@@ -128,16 +128,26 @@ CPPSRCS		= \
 		nsHTMLTableCellElement.cpp \
 		nsHTMLTableColElement.cpp \
 		nsHTMLTableRowElement.cpp \
 		nsHTMLTableSectionElement.cpp \
 		nsHTMLTextAreaElement.cpp \
 		nsHTMLTitleElement.cpp \
 		$(NULL)
 
+ifdef MOZ_MEDIA
+CPPSRCS		+= \
+		nsHTMLAudioElement.cpp \
+		nsHTMLMediaElement.cpp \
+		nsHTMLMediaError.cpp \
+		nsHTMLSourceElement.cpp \
+		nsHTMLVideoElement.cpp \
+		$(NULL)
+endif
+
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 INCLUDES	+= \
 		-I$(srcdir)/../../../base/src \
 		-I$(srcdir)/../../../events/src \
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -2346,16 +2346,38 @@ nsGenericHTMLElement::SetIntAttr(nsIAtom
 {
   nsAutoString value;
   value.AppendInt(aValue);
 
   return SetAttr(kNameSpaceID_None, aAttr, value, PR_TRUE);
 }
 
 nsresult
+nsGenericHTMLElement::GetFloatAttr(nsIAtom* aAttr, float aDefault, float* aResult)
+{
+  const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(aAttr);
+  if (attrVal && attrVal->Type() == nsAttrValue::eFloatValue) {
+    *aResult = attrVal->GetFloatValue();
+  }
+  else {
+    *aResult = aDefault;
+  }
+  return NS_OK;
+}
+
+nsresult
+nsGenericHTMLElement::SetFloatAttr(nsIAtom* aAttr, float aValue)
+{
+  nsAutoString value;
+  value.AppendFloat(aValue);
+
+  return SetAttr(kNameSpaceID_None, aAttr, value, PR_TRUE);
+}
+
+nsresult
 nsGenericHTMLElement::GetURIAttr(nsIAtom* aAttr, nsIAtom* aBaseAttr, nsAString& aResult)
 {
   nsAutoString attrValue;
   if (!GetAttr(kNameSpaceID_None, aAttr, attrValue)) {
     aResult.Truncate();
 
     return NS_OK;
   }
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -710,16 +710,38 @@ protected:
    * in null namespace.
    *
    * @param aAttr    name of attribute.
    * @param aValue   Integer value of attribute.
    */
   NS_HIDDEN_(nsresult) SetIntAttr(nsIAtom* aAttr, PRInt32 aValue);
 
   /**
+   * Helper method for NS_IMPL_FLOAT_ATTR macro.
+   * Gets the float-value of an attribute, returns specified default value
+   * if the attribute isn't set or isn't set to a float. Only works for
+   * attributes in null namespace.
+   *
+   * @param aAttr    name of attribute.
+   * @param aDefault default-value to return if attribute isn't set.
+   * @param aResult  result value [out]
+   */
+  NS_HIDDEN_(nsresult) GetFloatAttr(nsIAtom* aAttr, float aDefault, float* aValue);
+
+  /**
+   * Helper method for NS_IMPL_FLOAT_ATTR macro.
+   * Sets value of attribute to specified float. Only works for attributes
+   * in null namespace.
+   *
+   * @param aAttr    name of attribute.
+   * @param aValue   Float value of attribute.
+   */
+  NS_HIDDEN_(nsresult) SetFloatAttr(nsIAtom* aAttr, float aValue);
+
+  /**
    * Helper method for NS_IMPL_URI_ATTR macro.
    * Gets the absolute URI value of an attribute, by resolving any relative
    * URIs in the attribute against the baseuri of the element. If the attribute
    * isn't a relative URI the value of the attribute is returned as is. Only
    * works for attributes in null namespace.
    *
    * @param aAttr      name of attribute.
    * @param aBaseAttr  name of base attribute.
@@ -1039,16 +1061,36 @@ NS_NewHTML##_elementName##Element(nsINod
   }                                                                       \
   NS_IMETHODIMP                                                           \
   _class::Set##_method(PRInt32 aValue)                                    \
   {                                                                       \
     return SetIntAttr(nsGkAtoms::_atom, aValue);                        \
   }
 
 /**
+ * A macro to implement the getter and setter for a given float
+ * valued content property. The method uses the generic GetAttr and
+ * SetAttr methods.
+ */
+#define NS_IMPL_FLOAT_ATTR(_class, _method, _atom)                    \
+  NS_IMPL_FLOAT_ATTR_DEFAULT_VALUE(_class, _method, _atom, 0.0)
+
+#define NS_IMPL_FLOAT_ATTR_DEFAULT_VALUE(_class, _method, _atom, _default)  \
+  NS_IMETHODIMP                                                             \
+  _class::Get##_method(float* aValue)                                   \
+  {                                                                         \
+    return GetFloatAttr(nsGkAtoms::_atom, _default, aValue);                \
+  }                                                                         \
+  NS_IMETHODIMP                                                             \
+  _class::Set##_method(float aValue)                                    \
+  {                                                                         \
+    return SetFloatAttr(nsGkAtoms::_atom, aValue);                          \
+  }
+
+/**
  * A macro to implement the getter and setter for a given content
  * property that needs to return a URI in string form.  The method
  * uses the generic GetAttr and SetAttr methods.  This macro is much
  * like the NS_IMPL_STRING_ATTR macro, except we make sure the URI is
  * absolute.
  */
 #define NS_IMPL_URI_ATTR(_class, _method, _atom)                    \
   NS_IMETHODIMP                                                     \
@@ -1163,16 +1205,19 @@ NS_NewHTML##_elementName##Element(nsINod
                                   PRBool aFromParser = PR_FALSE);
 
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Shared)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(SharedList)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(SharedObject)
 
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Anchor)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Area)
+#if defined(MOZ_MEDIA)
+NS_DECLARE_NS_NEW_HTML_ELEMENT(Audio)
+#endif
 NS_DECLARE_NS_NEW_HTML_ELEMENT(BR)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Body)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Button)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Canvas)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Mod)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Div)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(FieldSet)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Font)
@@ -1194,24 +1239,30 @@ NS_DECLARE_NS_NEW_HTML_ELEMENT(Map)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Meta)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Object)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(OptGroup)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Option)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Paragraph)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Pre)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Script)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Select)
+#if defined(MOZ_MEDIA)
+NS_DECLARE_NS_NEW_HTML_ELEMENT(Source)
+#endif
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Span)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Style)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(TableCaption)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(TableCell)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(TableCol)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Table)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(TableRow)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(TableSection)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Tbody)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(TextArea)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Tfoot)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Thead)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Title)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Unknown)
+#if defined(MOZ_MEDIA)
+NS_DECLARE_NS_NEW_HTML_ELEMENT(Video)
+#endif
 
 #endif /* nsGenericHTMLElement_h___ */
new file mode 100644
--- /dev/null
+++ b/content/html/content/src/nsHTMLAudioElement.cpp
@@ -0,0 +1,120 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: ML 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 "nsIDOMHTMLAudioElement.h"
+#include "nsIDOMHTMLSourceElement.h"
+#include "nsHTMLAudioElement.h"
+#include "nsGenericHTMLElement.h"
+#include "nsPresContext.h"
+#include "nsIPresShell.h"
+#include "nsGkAtoms.h"
+#include "nsSize.h"
+#include "nsIFrame.h"
+#include "nsIDocument.h"
+#include "nsIDOMDocument.h"
+#include "nsDOMError.h"
+#include "nsNodeInfoManager.h"
+#include "plbase64.h"
+#include "nsNetUtil.h"
+#include "prmem.h"
+#include "nsNetUtil.h"
+#include "nsXPCOMStrings.h"
+#include "prlock.h"
+#include "nsThreadUtils.h"
+
+#include "nsIScriptSecurityManager.h"
+#include "nsIXPConnect.h"
+#include "jsapi.h"
+
+#include "nsIRenderingContext.h"
+#include "nsITimer.h"
+
+#include "nsEventDispatcher.h"
+#include "nsIDOMDocumentEvent.h"
+#include "nsIDOMProgressEvent.h"
+#include "nsHTMLMediaError.h"
+
+NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Audio)
+
+NS_IMPL_ADDREF_INHERITED(nsHTMLAudioElement, nsHTMLMediaElement)
+NS_IMPL_RELEASE_INHERITED(nsHTMLAudioElement, nsHTMLMediaElement)
+
+NS_HTML_CONTENT_INTERFACE_TABLE_HEAD(nsHTMLAudioElement, nsHTMLMediaElement)
+  NS_INTERFACE_TABLE_INHERITED1(nsHTMLAudioElement, nsIDOMHTMLAudioElement)
+NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLAudioElement)
+
+NS_IMPL_ELEMENT_CLONE(nsHTMLAudioElement)
+
+
+nsHTMLAudioElement::nsHTMLAudioElement(nsINodeInfo *aNodeInfo, PRBool aFromParser)
+  : nsHTMLMediaElement(aNodeInfo, aFromParser)
+{
+}
+
+nsHTMLAudioElement::~nsHTMLAudioElement()
+{
+}
+
+nsresult nsHTMLAudioElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                                        nsIContent* aBindingParent,
+                                        PRBool aCompileEventHandlers)
+{
+  if (mDecoder)
+    mDecoder->ElementAvailable(this);
+
+  return nsHTMLMediaElement::BindToTree(aDocument, 
+                                        aParent, 
+                                        aBindingParent, 
+                                        aCompileEventHandlers);
+}
+
+void nsHTMLAudioElement::UnbindFromTree(PRBool aDeep,
+                                        PRBool aNullParent)
+{
+  if (mDecoder) 
+    mDecoder->ElementUnavailable();
+
+  nsHTMLMediaElement::UnbindFromTree(aDeep, aNullParent);
+}
+
+nsresult nsHTMLAudioElement::InitializeDecoder(nsAString& aChosenMediaResource)
+{
+  if (mDecoder) 
+    mDecoder->ElementAvailable(this);
+
+  return nsHTMLMediaElement::InitializeDecoder(aChosenMediaResource);
+}
new file mode 100644
--- /dev/null
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -0,0 +1,784 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: ML 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 "nsIDOMHTMLMediaElement.h"
+#include "nsIDOMHTMLSourceElement.h"
+#include "nsHTMLMediaElement.h"
+#include "nsGenericHTMLElement.h"
+#include "nsPresContext.h"
+#include "nsIPresShell.h"
+#include "nsGkAtoms.h"
+#include "nsSize.h"
+#include "nsIFrame.h"
+#include "nsIDocument.h"
+#include "nsIDOMDocument.h"
+#include "nsDOMError.h"
+#include "nsNodeInfoManager.h"
+#include "plbase64.h"
+#include "nsNetUtil.h"
+#include "prmem.h"
+#include "nsNetUtil.h"
+#include "nsXPCOMStrings.h"
+#include "prlock.h"
+#include "nsThreadUtils.h"
+
+#include "nsIScriptSecurityManager.h"
+#include "nsIXPConnect.h"
+#include "jsapi.h"
+
+#include "nsIRenderingContext.h"
+#include "nsITimer.h"
+
+#include "nsEventDispatcher.h"
+#include "nsIDOMDocumentEvent.h"
+#include "nsIDOMProgressEvent.h"
+#include "nsHTMLMediaError.h"
+
+class nsAsyncEventRunner : public nsRunnable
+{
+private:
+  nsString mName;
+  nsCOMPtr<nsHTMLMediaElement> mElement;
+  PRPackedBool mProgress;
+  
+public:
+  nsAsyncEventRunner(const nsAString& aName, nsHTMLMediaElement* aElement, PRBool aProgress) : 
+    mName(aName), mElement(aElement), mProgress(aProgress)
+  {
+  }
+  
+  NS_IMETHOD Run() {
+    return mProgress ?
+      mElement->DispatchProgressEvent(mName) :
+      mElement->DispatchSimpleEvent(mName);
+  }
+};
+
+// nsIDOMHTMLMediaElement
+NS_IMPL_URI_ATTR(nsHTMLMediaElement, Src, src)
+NS_IMPL_BOOL_ATTR(nsHTMLMediaElement, Controls, controls)
+NS_IMPL_FLOAT_ATTR_DEFAULT_VALUE(nsHTMLMediaElement, PlaybackRate, playbackrate, 1.0)
+NS_IMPL_FLOAT_ATTR_DEFAULT_VALUE(nsHTMLMediaElement, DefaultPlaybackRate, defaultplaybackrate, 1.0)
+
+/* readonly attribute nsIDOMHTMLMediaError error; */
+NS_IMETHODIMP nsHTMLMediaElement::GetError(nsIDOMHTMLMediaError * *aError)
+{
+  NS_IF_ADDREF(*aError = mError);
+
+  return NS_OK;
+}
+
+/* readonly attribute DOMString currentSrc; */
+NS_IMETHODIMP nsHTMLMediaElement::GetCurrentSrc(nsAString & aCurrentSrc)
+{
+  nsCAutoString src;
+  
+  if (mDecoder) {
+    nsCOMPtr<nsIURI> uri;
+    mDecoder->GetCurrentURI(getter_AddRefs(uri));
+    if (uri) {
+      uri->GetSpec(src);
+    }
+  }
+
+  aCurrentSrc = NS_ConvertUTF8toUTF16(src);
+
+  return NS_OK;
+}
+
+/* readonly attribute unsigned short networkState; */
+NS_IMETHODIMP nsHTMLMediaElement::GetNetworkState(PRUint16 *aNetworkState)
+{
+  if (aNetworkState) {
+    *aNetworkState = mNetworkState;
+  }
+
+  return NS_OK;
+}
+
+/* readonly attribute float bufferingRate; */
+NS_IMETHODIMP nsHTMLMediaElement::GetBufferingRate(float *aBufferingRate)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* readonly attribute nsIDOMTimeRanges buffered; */
+NS_IMETHODIMP nsHTMLMediaElement::GetBuffered(nsIDOMHTMLTimeRanges * *aBuffered)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* void load (); */
+NS_IMETHODIMP nsHTMLMediaElement::Load()
+{
+  if (mBegun) {
+    mBegun = PR_FALSE;
+    
+    mError = new (std::nothrow) nsHTMLMediaError(nsHTMLMediaError::MEDIA_ERR_ABORTED);
+    DispatchProgressEvent(NS_LITERAL_STRING("abort"));
+    return NS_OK;
+  }
+
+  mError = nsnull;
+  mLoadedFirstFrame = PR_FALSE;
+  mAutoplaying = PR_TRUE;
+
+  float rate = 1.0;
+  GetDefaultPlaybackRate(&rate);
+  SetPlaybackRate(rate);
+
+  if (mNetworkState != nsIDOMHTMLMediaElement::EMPTY) {
+    mNetworkState = nsIDOMHTMLMediaElement::EMPTY;
+    ChangeReadyState(nsIDOMHTMLMediaElement::DATA_UNAVAILABLE);
+    mPaused = PR_TRUE;
+    mSeeking = PR_FALSE;
+    // TODO: The current playback position must be set to 0.
+    // TODO: The currentLoop DOM attribute must be set to 0.
+    DispatchSimpleEvent(NS_LITERAL_STRING("emptied"));
+  }
+
+  nsAutoString chosenMediaResource;
+  nsresult rv = PickMediaElement(chosenMediaResource);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  mNetworkState = nsIDOMHTMLMediaElement::LOADING;
+  
+  // This causes the currentSrc attribute to become valid
+  rv = InitializeDecoder(chosenMediaResource);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  mBegun = PR_TRUE;
+  mEnded = PR_FALSE;
+
+  DispatchAsyncProgressEvent(NS_LITERAL_STRING("loadstart"));
+
+  return NS_OK;
+}
+
+/* readonly attribute unsigned short readyState; */
+NS_IMETHODIMP nsHTMLMediaElement::GetReadyState(PRUint16 *aReadyState)
+{
+  if (aReadyState) {
+    *aReadyState = mReadyState;
+  }
+
+  return NS_OK;
+}
+
+/* readonly attribute boolean seeking; */
+NS_IMETHODIMP nsHTMLMediaElement::GetSeeking(PRBool *aSeeking)
+{
+  if (aSeeking) {
+    *aSeeking = mSeeking;
+  }
+
+  return NS_OK;
+}
+
+/* attribute float currentTime; */
+NS_IMETHODIMP nsHTMLMediaElement::GetCurrentTime(float *aCurrentTime)
+{
+  *aCurrentTime = mDecoder ? mDecoder->GetCurrentTime() : 0.0;
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsHTMLMediaElement::SetCurrentTime(float aCurrentTime)
+{
+  return mDecoder ? mDecoder->Seek(aCurrentTime) : NS_ERROR_DOM_INVALID_STATE_ERR;
+}
+
+/* readonly attribute float duration; */
+NS_IMETHODIMP nsHTMLMediaElement::GetDuration(float *aDuration)
+{
+  if (!aDuration)
+    return NS_OK;
+
+  if (!mDecoder) {
+    *aDuration = 0.0;
+    return NS_OK;
+  }
+
+  *aDuration = mDecoder->GetDuration();
+  return NS_OK;
+}
+
+/* readonly attribute unsigned short paused; */
+NS_IMETHODIMP nsHTMLMediaElement::GetPaused(PRUint16 *aPaused)
+{
+  if (aPaused) {
+    *aPaused = mPaused;
+  }
+
+  return NS_OK;
+}
+
+/* readonly attribute nsIDOMHTMLTimeRanges played; */
+NS_IMETHODIMP nsHTMLMediaElement::GetPlayed(nsIDOMHTMLTimeRanges * *aPlayed)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* readonly attribute nsIDOMHTMLTimeRanges seekable; */
+NS_IMETHODIMP nsHTMLMediaElement::GetSeekable(nsIDOMHTMLTimeRanges * *aSeekable)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* readonly attribute boolean ended; */
+NS_IMETHODIMP nsHTMLMediaElement::GetEnded(PRBool *aEnded)
+{
+  if (aEnded)
+    *aEnded = mEnded;
+
+  return NS_OK;
+}
+
+/* attribute boolean autoplay; */
+NS_IMETHODIMP nsHTMLMediaElement::GetAutoplay(PRBool *aAutoplay)
+{
+  if (!aAutoplay)
+    return NS_OK;
+
+  if (HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay)) 
+    *aAutoplay = PR_TRUE;
+  else
+    *aAutoplay = PR_FALSE;
+
+  return NS_OK;
+}
+NS_IMETHODIMP nsHTMLMediaElement::SetAutoplay(PRBool aAutoplay)
+{
+  return SetAttr(kNameSpaceID_None, 
+                 nsGkAtoms::autoplay,
+                 NS_LITERAL_STRING("true"),
+                 PR_TRUE);
+}
+
+/* void pause (); */
+NS_IMETHODIMP nsHTMLMediaElement::Pause()
+{
+  if (!mDecoder) 
+    return NS_OK;
+
+  nsresult rv;
+
+  if (mNetworkState == nsIDOMHTMLMediaElement::EMPTY) {
+    rv = Load();
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  mDecoder->Pause();
+  PRBool oldPaused = mPaused;
+  mPaused = PR_TRUE;
+  mAutoplaying = PR_FALSE;
+  
+  if (!oldPaused) {
+    DispatchAsyncSimpleEvent(NS_LITERAL_STRING("timeupdate"));
+    DispatchAsyncSimpleEvent(NS_LITERAL_STRING("pause"));
+  }
+
+  return NS_OK;
+}
+
+/* attribute float start; */
+NS_IMETHODIMP nsHTMLMediaElement::GetStart(float *aStart)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+NS_IMETHODIMP nsHTMLMediaElement::SetStart(float aStart)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* attribute float end; */
+NS_IMETHODIMP nsHTMLMediaElement::GetEnd(float *aEnd)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+NS_IMETHODIMP nsHTMLMediaElement::SetEnd(float aEnd)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* attribute float loopStart; */
+NS_IMETHODIMP nsHTMLMediaElement::GetLoopStart(float *aLoopStart)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+NS_IMETHODIMP nsHTMLMediaElement::SetLoopStart(float aLoopStart)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* attribute float loopEnd; */
+NS_IMETHODIMP nsHTMLMediaElement::GetLoopEnd(float *aLoopEnd)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+NS_IMETHODIMP nsHTMLMediaElement::SetLoopEnd(float aLoopEnd)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* attribute unsigned long loopCount; */
+NS_IMETHODIMP nsHTMLMediaElement::GetLoopCount(PRUint32 *aLoopCount)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+NS_IMETHODIMP nsHTMLMediaElement::SetLoopCount(PRUint32 aLoopCount)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* attribute unsigned long currentLoop; */
+NS_IMETHODIMP nsHTMLMediaElement::GetCurrentLoop(PRUint32 *aCurrentLoop)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+NS_IMETHODIMP nsHTMLMediaElement::SetCurrentLoop(PRUint32 aCurrentLoop)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* void addCuePoint (in float time, in nsIDOMHTMLVoidCallback callback, in boolean pause); */
+NS_IMETHODIMP nsHTMLMediaElement::AddCuePoint(float time, nsIDOMHTMLVoidCallback *callback, PRBool pause)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* void removeCuePoint (in float time, in nsIDOMHTMLVoidCallback callback); */
+NS_IMETHODIMP nsHTMLMediaElement::RemoveCuePoint(float time, nsIDOMHTMLVoidCallback *callback)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* attribute float volume; */
+NS_IMETHODIMP nsHTMLMediaElement::GetVolume(float *aVolume)
+{
+  if (mMuted)
+    *aVolume = mMutedVolume;
+  else
+    *aVolume = mDecoder ? mDecoder->GetVolume() : 0.0;
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsHTMLMediaElement::SetVolume(float aVolume)
+{
+  if (mMuted) 
+    mMutedVolume = aVolume;
+  else {
+    if (mDecoder)
+      mDecoder->SetVolume(aVolume);
+
+    DispatchSimpleEvent(NS_LITERAL_STRING("volumechange"));
+  }
+  return NS_OK;
+}
+
+/* attribute boolean muted; */
+NS_IMETHODIMP nsHTMLMediaElement::GetMuted(PRBool *aMuted)
+{
+  if (*aMuted)
+    *aMuted = mMuted;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsHTMLMediaElement::SetMuted(PRBool aMuted)
+{
+  PRBool oldMuted = mMuted;
+
+  if (mDecoder) {
+    if (mMuted && !aMuted) {
+      mDecoder->SetVolume(mMutedVolume);
+    }
+    else if (!mMuted && aMuted) {
+      mMutedVolume = mDecoder->GetVolume();
+      mDecoder->SetVolume(0.0);
+    }
+  }
+
+  mMuted = aMuted;
+
+  if (oldMuted != mMuted) 
+    DispatchSimpleEvent(NS_LITERAL_STRING("volumechange"));
+  return NS_OK;
+}
+
+nsHTMLMediaElement::nsHTMLMediaElement(nsINodeInfo *aNodeInfo, PRBool aFromParser)
+  : nsGenericHTMLElement(aNodeInfo),
+    mNetworkState(nsIDOMHTMLMediaElement::EMPTY),
+    mReadyState(nsIDOMHTMLMediaElement::DATA_UNAVAILABLE),
+    mBegun(PR_FALSE),
+    mEnded(PR_FALSE),
+    mLoadedFirstFrame(PR_FALSE),
+    mAutoplaying(PR_TRUE),
+    mPaused(PR_TRUE),
+    mSeeking(PR_FALSE),
+    mMuted(PR_FALSE),
+    mMutedVolume(0.0),
+    mIsDoneAddingChildren(!aFromParser)
+{
+}
+
+nsHTMLMediaElement::~nsHTMLMediaElement()
+{
+}
+
+NS_IMETHODIMP
+nsHTMLMediaElement::Play(void)
+{
+  if (!mDecoder)
+    return NS_OK;
+
+  nsresult rv;
+
+  if (mNetworkState == nsIDOMHTMLMediaElement::EMPTY) {
+    rv = Load();
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // TODO: If the playback has ended, then the user agent must set 
+  // currentLoop to zero and seek to the effective start.
+  float rate = 1.0;
+  GetDefaultPlaybackRate(&rate);
+  SetPlaybackRate(rate);
+  rv = mDecoder->Play();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  PRBool oldPaused = mPaused;
+  mPaused = PR_FALSE;
+  mAutoplaying = PR_FALSE;
+
+  if (oldPaused)
+    DispatchAsyncSimpleEvent(NS_LITERAL_STRING("play"));
+
+
+  return NS_OK;
+}
+
+PRBool
+nsHTMLMediaElement::ParseAttribute(PRInt32 aNamespaceID,
+                                   nsIAtom* aAttribute,
+                                   const nsAString& aValue,
+                                   nsAttrValue& aResult)
+{
+  if (aNamespaceID == kNameSpaceID_None) {
+    if (aAttribute == nsGkAtoms::src) {
+      static const char* kWhitespace = " \n\r\t\b";
+      aResult.SetTo(nsContentUtils::TrimCharsInSet(kWhitespace, aValue));
+      return PR_TRUE;
+    }
+    else if(aAttribute == nsGkAtoms::playbackrate || aAttribute == nsGkAtoms::defaultplaybackrate) {
+      return aResult.ParseFloatValue(aValue);
+    }
+    else if (ParseImageAttribute(aAttribute, aValue, aResult)) {
+      return PR_TRUE;
+    }
+  }
+
+  return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
+                                              aResult);
+}
+#include "nsString.h"
+nsresult
+nsHTMLMediaElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
+                            nsIAtom* aPrefix, const nsAString& aValue,
+                            PRBool aNotify)
+{
+  nsresult rv = 
+    nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
+                                    aNotify);
+  if (aNotify && aNameSpaceID == kNameSpaceID_None) {
+    if (aName == nsGkAtoms::src) {
+      Load();
+    }
+    else if(aName == nsGkAtoms::playbackrate || aName == nsGkAtoms::defaultplaybackrate) {
+      if (mDecoder) 
+        mDecoder->PlaybackRateChanged();
+      DispatchAsyncSimpleEvent(NS_LITERAL_STRING("ratechange"));
+    }
+  }
+
+  return rv;
+}
+
+nsresult nsHTMLMediaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                                        nsIContent* aBindingParent,
+                                        PRBool aCompileEventHandlers)
+{
+  nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, 
+                                                 aParent, 
+                                                 aBindingParent, 
+                                                 aCompileEventHandlers);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (mIsDoneAddingChildren && mNetworkState == nsIDOMHTMLMediaElement::EMPTY) {
+    Load();
+  }
+
+  return rv;
+}
+
+void nsHTMLMediaElement::UnbindFromTree(PRBool aDeep,
+                                        PRBool aNullParent)
+{
+  nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
+}
+
+
+nsresult nsHTMLMediaElement::PickMediaElement(nsAString& aChosenMediaResource)
+{
+  // Implements:
+  // http://www.whatwg.org/specs/web-apps/current-work/#pick-a
+  nsAutoString src;
+  if (HasAttr(kNameSpaceID_None, nsGkAtoms::src)) {
+    nsresult rv = GetAttr(kNameSpaceID_None, nsGkAtoms::src, src);
+    if (NS_SUCCEEDED(rv)) {
+      aChosenMediaResource = src;
+
+      // No decoder available
+      mDecoder = nsnull;
+      return NS_OK;
+    }
+  }
+
+  // Checking of 'source' elements as per:
+  // http://www.whatwg.org/specs/web-apps/current-work/#pick-a
+  PRUint32 count = GetChildCount();
+  for (PRUint32 i = 0; i < count; ++i) {
+    nsIContent* child = GetChildAt(i);
+    NS_ASSERTION(child, "GetChildCount lied!");
+    
+    nsCOMPtr<nsIContent> source = do_QueryInterface(child);
+    if (source) {
+      if (source->HasAttr(kNameSpaceID_None, nsGkAtoms::src)) {
+        nsAutoString type;
+        
+        nsresult rv = source->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type);
+        if (NS_SUCCEEDED(rv)) {
+          // Check type and instantiate for relevant decoders
+          // Currently no decoders supported
+        }
+      }
+    }    
+  }        
+
+  return NS_ERROR_DOM_INVALID_STATE_ERR;
+}
+
+nsresult nsHTMLMediaElement::InitializeDecoder(nsAString& aChosenMediaResource)
+{
+  nsCOMPtr<nsIDocument> doc = GetCurrentDoc();
+  if (!doc) {
+    return NS_ERROR_DOM_INVALID_STATE_ERR;
+  }
+
+  nsresult rv;
+  nsCOMPtr<nsIURI> uri;
+  nsCOMPtr<nsIURI> baseURL = GetBaseURI();
+  const nsAFlatCString &charset = doc->GetDocumentCharacterSet();
+  rv = NS_NewURI(getter_AddRefs(uri), 
+                 aChosenMediaResource, 
+                 charset.IsEmpty() ? nsnull : charset.get(), 
+                 baseURL, 
+                 nsContentUtils::GetIOService());
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (mDecoder) {
+    rv = mDecoder->Load(uri);
+    if (NS_FAILED(rv)) {
+      mDecoder = nsnull;
+    }
+  }
+  return rv;
+}
+
+void nsHTMLMediaElement::MetadataLoaded()
+{
+  mNetworkState = nsIDOMHTMLMediaElement::LOADED_METADATA;
+  DispatchAsyncSimpleEvent(NS_LITERAL_STRING("durationchange"));
+  DispatchAsyncSimpleEvent(NS_LITERAL_STRING("loadedmetadata"));
+}
+
+void nsHTMLMediaElement::FirstFrameLoaded()
+{
+  mNetworkState = nsIDOMHTMLMediaElement::LOADED_FIRST_FRAME;
+  ChangeReadyState(nsIDOMHTMLMediaElement::CAN_SHOW_CURRENT_FRAME);
+  mLoadedFirstFrame = PR_TRUE;
+  DispatchAsyncSimpleEvent(NS_LITERAL_STRING("loadedfirstframe"));
+  DispatchAsyncSimpleEvent(NS_LITERAL_STRING("canshowcurrentframe"));
+}
+
+void nsHTMLMediaElement::ResourceLoaded()
+{
+  mBegun = PR_FALSE;
+  mEnded = PR_FALSE;
+  mNetworkState = nsIDOMHTMLMediaElement::LOADED;
+  ChangeReadyState(nsIDOMHTMLMediaElement::CAN_PLAY_THROUGH);
+
+  DispatchProgressEvent(NS_LITERAL_STRING("load"));
+}
+
+void nsHTMLMediaElement::NetworkError()
+{
+  mError = new (std::nothrow) nsHTMLMediaError(nsHTMLMediaError::MEDIA_ERR_NETWORK);
+  mBegun = PR_FALSE;
+  DispatchProgressEvent(NS_LITERAL_STRING("error"));
+  mNetworkState = nsIDOMHTMLMediaElement::EMPTY;
+  DispatchSimpleEvent(NS_LITERAL_STRING("empty"));
+}
+
+void nsHTMLMediaElement::PlaybackCompleted()
+{
+  mBegun = PR_FALSE;
+  mEnded = PR_TRUE;
+  Pause();
+  SetCurrentTime(0);
+  DispatchSimpleEvent(NS_LITERAL_STRING("ended"));
+}
+
+void nsHTMLMediaElement::ChangeReadyState(nsMediaReadyState aState)
+{
+  mReadyState = aState;
+  if (mNetworkState != nsIDOMHTMLMediaElement::EMPTY) {
+    switch(mReadyState) {
+    case nsIDOMHTMLMediaElement::DATA_UNAVAILABLE:
+      DispatchAsyncSimpleEvent(NS_LITERAL_STRING("dataunavailable"));
+      LOG(PR_LOG_DEBUG, ("Ready state changed to DATA_UNAVAILABLE"));
+      break;
+      
+    case nsIDOMHTMLMediaElement::CAN_SHOW_CURRENT_FRAME:
+      if (mLoadedFirstFrame) {
+        DispatchAsyncSimpleEvent(NS_LITERAL_STRING("canshowcurrentframe"));
+        LOG(PR_LOG_DEBUG, ("Ready state changed to CAN_SHOW_CURRENT_FRAME"));
+      }
+      break;
+
+    case nsIDOMHTMLMediaElement::CAN_PLAY:
+      DispatchAsyncSimpleEvent(NS_LITERAL_STRING("canplay"));
+      LOG(PR_LOG_DEBUG, ("Ready state changed to CAN_PLAY"));
+      break;
+
+    case nsIDOMHTMLMediaElement::CAN_PLAY_THROUGH:
+      DispatchAsyncSimpleEvent(NS_LITERAL_STRING("canplaythrough"));
+      if (mAutoplaying && 
+         mPaused && 
+         HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay)) {
+        mPaused = PR_FALSE;
+        if (mDecoder) {
+          mDecoder->Play();
+        }
+        LOG(PR_LOG_DEBUG, ("Ready state changed to CAN_PLAY_THROUGH"));
+        DispatchAsyncSimpleEvent(NS_LITERAL_STRING("play"));
+      }
+      break;
+    }
+  }  
+}
+
+void nsHTMLMediaElement::Paint(gfxContext* aContext, const gfxRect& aRect) 
+{
+  if (mDecoder)
+    mDecoder->Paint(aContext, aRect);
+}
+
+nsresult nsHTMLMediaElement::DispatchSimpleEvent(const nsAString& aName)
+{
+  return nsContentUtils::DispatchTrustedEvent(GetOwnerDoc(), 
+                                              static_cast<nsIContent*>(this), 
+                                              aName, 
+                                              PR_TRUE, 
+                                              PR_TRUE);
+}
+
+nsresult nsHTMLMediaElement::DispatchAsyncSimpleEvent(const nsAString& aName)
+{
+  nsCOMPtr<nsIRunnable> event = new nsAsyncEventRunner(aName, this, PR_FALSE);
+  if (event)
+    NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); 
+  return NS_OK;                           
+}
+
+nsresult nsHTMLMediaElement::DispatchAsyncProgressEvent(const nsAString& aName)
+{
+  nsCOMPtr<nsIRunnable> event = new nsAsyncEventRunner(aName, this, PR_TRUE);
+  if (event)
+    NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); 
+  return NS_OK;                           
+}
+
+nsresult nsHTMLMediaElement::DispatchProgressEvent(const nsAString& aName)
+{
+  if (!mDecoder)
+    return NS_OK;
+
+  nsCOMPtr<nsIDOMDocumentEvent> docEvent(do_QueryInterface(GetOwnerDoc()));
+  nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(static_cast<nsIContent*>(this)));
+  NS_ENSURE_TRUE(docEvent && target, NS_ERROR_INVALID_ARG);
+
+  nsCOMPtr<nsIDOMEvent> event;
+  nsresult rv = docEvent->CreateEvent(NS_LITERAL_STRING("ProgressEvent"), getter_AddRefs(event));
+  NS_ENSURE_SUCCESS(rv, rv);
+  
+  nsCOMPtr<nsIDOMProgressEvent> progressEvent(do_QueryInterface(event));
+  NS_ENSURE_TRUE(progressEvent, NS_ERROR_FAILURE);
+  
+  rv = progressEvent->InitProgressEvent(aName, PR_TRUE, PR_TRUE, PR_FALSE, mDecoder->GetBytesLoaded(), mDecoder->GetTotalBytes());
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  PRBool dummy;
+  return target->DispatchEvent(event, &dummy);  
+}
+
+nsresult nsHTMLMediaElement::DoneAddingChildren(PRBool aHaveNotified)
+{
+  if (!mIsDoneAddingChildren) {
+    mIsDoneAddingChildren = PR_TRUE;
+  
+    if (mNetworkState == nsIDOMHTMLMediaElement::EMPTY) {
+      Load();
+    }
+  }
+
+  return NS_OK;
+}
+
+PRBool nsHTMLMediaElement::IsDoneAddingChildren()
+{
+  return mIsDoneAddingChildren;
+}
new file mode 100644
--- /dev/null
+++ b/content/html/content/src/nsHTMLMediaError.cpp
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: ML 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 "nsHTMLMediaError.h"
+#include "nsContentUtils.h"
+
+NS_IMPL_ADDREF(nsHTMLMediaError)
+NS_IMPL_RELEASE(nsHTMLMediaError)
+
+NS_INTERFACE_MAP_BEGIN(nsHTMLMediaError)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMHTMLMediaError)
+  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(HTMLMediaError)
+NS_INTERFACE_MAP_END
+
+nsHTMLMediaError::nsHTMLMediaError(PRUint16 aCode) :
+  mCode(aCode)
+{
+}
+
+NS_IMETHODIMP nsHTMLMediaError::GetCode(PRUint16* aCode)
+{
+  if (aCode)
+    *aCode = mCode;
+
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/content/html/content/src/nsHTMLMediaError.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 "nsIDOMHTMLMediaError.h"
+#include "nsISupports.h"
+
+class nsHTMLMediaError : public nsIDOMHTMLMediaError
+{
+public:
+  nsHTMLMediaError(PRUint16 aCode);
+
+  // nsISupports
+  NS_DECL_ISUPPORTS
+
+  // nsIDOMHTMLMediaError
+  NS_DECL_NSIDOMHTMLMEDIAERROR
+
+private:
+  // Error code
+  PRUint16 mCode;
+};
new file mode 100644
--- /dev/null
+++ b/content/html/content/src/nsHTMLSourceElement.cpp
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: ML 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 "nsIDOMHTMLSourceElement.h"
+#include "nsIDOMEventTarget.h"
+#include "nsGenericHTMLElement.h"
+#include "nsGkAtoms.h"
+#include "nsStyleConsts.h"
+#include "nsPresContext.h"
+#include "nsMappedAttributes.h"
+#include "nsRuleData.h"
+
+class nsHTMLSourceElement : public nsGenericHTMLElement,
+                            public nsIDOMHTMLSourceElement
+{
+public:
+  nsHTMLSourceElement(nsINodeInfo *aNodeInfo);
+  virtual ~nsHTMLSourceElement();
+
+  // nsISupports
+  NS_DECL_ISUPPORTS_INHERITED
+
+  // nsIDOMNode
+  NS_FORWARD_NSIDOMNODE(nsGenericHTMLElement::)
+
+  // nsIDOMElement
+  NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLElement::)
+
+  // nsIDOMHTMLElement
+  NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLElement::)
+
+  // nsIDOMHTMLSourceElement
+  NS_DECL_NSIDOMHTMLSOURCEELEMENT
+
+  virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
+                                nsIAtom* aAttribute,
+                                const nsAString& aValue,
+                                nsAttrValue& aResult);
+  virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
+};
+
+
+NS_IMPL_NS_NEW_HTML_ELEMENT(Source)
+
+
+nsHTMLSourceElement::nsHTMLSourceElement(nsINodeInfo *aNodeInfo)
+  : nsGenericHTMLElement(aNodeInfo)
+{
+}
+
+nsHTMLSourceElement::~nsHTMLSourceElement()
+{
+}
+
+
+NS_IMPL_ADDREF_INHERITED(nsHTMLSourceElement, nsGenericElement)
+NS_IMPL_RELEASE_INHERITED(nsHTMLSourceElement, nsGenericElement)
+
+
+// QueryInterface implementation for nsHTMLSourceElement
+NS_HTML_CONTENT_INTERFACE_TABLE_HEAD(nsHTMLSourceElement, nsGenericHTMLElement)
+  NS_INTERFACE_TABLE_INHERITED1(nsHTMLSourceElement, nsIDOMHTMLSourceElement)
+NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLSourceElement)
+
+
+NS_IMPL_ELEMENT_CLONE(nsHTMLSourceElement)
+
+
+NS_IMPL_URI_ATTR(nsHTMLSourceElement, Src, src)
+NS_IMPL_STRING_ATTR(nsHTMLSourceElement, Type, type)
+NS_IMPL_STRING_ATTR(nsHTMLSourceElement, Media, media)
+
+
+PRBool
+nsHTMLSourceElement::ParseAttribute(PRInt32 aNamespaceID,
+                                nsIAtom* aAttribute,
+                                const nsAString& aValue,
+                                nsAttrValue& aResult)
+{
+  if (aNamespaceID == kNameSpaceID_None) {
+    if (aAttribute == nsGkAtoms::src) {
+      static const char* kWhitespace = " \n\r\t\b";
+      aResult.SetTo(nsContentUtils::TrimCharsInSet(kWhitespace, aValue));
+      return PR_TRUE;
+    }
+  }
+
+  return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
+                                              aResult);
+}
+
new file mode 100644
--- /dev/null
+++ b/content/html/content/src/nsHTMLVideoElement.cpp
@@ -0,0 +1,160 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: ML 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 "nsIDOMHTMLVideoElement.h"
+#include "nsIDOMHTMLSourceElement.h"
+#include "nsHTMLVideoElement.h"
+#include "nsGenericHTMLElement.h"
+#include "nsPresContext.h"
+#include "nsIPresShell.h"
+#include "nsGkAtoms.h"
+#include "nsSize.h"
+#include "nsIFrame.h"
+#include "nsIDocument.h"
+#include "nsIDOMDocument.h"
+#include "nsDOMError.h"
+#include "nsNodeInfoManager.h"
+#include "plbase64.h"
+#include "nsNetUtil.h"
+#include "prmem.h"
+#include "nsNetUtil.h"
+#include "nsXPCOMStrings.h"
+#include "prlock.h"
+#include "nsThreadUtils.h"
+
+#include "nsIScriptSecurityManager.h"
+#include "nsIXPConnect.h"
+#include "jsapi.h"
+
+#include "nsIRenderingContext.h"
+#include "nsITimer.h"
+
+#include "nsEventDispatcher.h"
+#include "nsIDOMDocumentEvent.h"
+#include "nsIDOMProgressEvent.h"
+#include "nsHTMLMediaError.h"
+
+NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Video)
+
+NS_IMPL_ADDREF_INHERITED(nsHTMLVideoElement, nsHTMLMediaElement)
+NS_IMPL_RELEASE_INHERITED(nsHTMLVideoElement, nsHTMLMediaElement)
+
+NS_HTML_CONTENT_INTERFACE_TABLE_HEAD(nsHTMLVideoElement, nsHTMLMediaElement)
+  NS_INTERFACE_TABLE_INHERITED1(nsHTMLVideoElement, nsIDOMHTMLVideoElement)
+NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLVideoElement)
+
+NS_IMPL_ELEMENT_CLONE(nsHTMLVideoElement)
+
+// nsIDOMHTMLVideoElement
+NS_IMPL_INT_ATTR(nsHTMLVideoElement, Width, width)
+NS_IMPL_INT_ATTR(nsHTMLVideoElement, Height, height)
+NS_IMPL_URI_ATTR(nsHTMLVideoElement, Poster, poster)
+
+// nsIDOMHTMLVideoElement
+/* readonly attribute unsigned long videoWidth; */
+NS_IMETHODIMP nsHTMLVideoElement::GetVideoWidth(PRUint32 *aVideoWidth)
+{
+  nsIntSize size(0,0);
+  if (mDecoder) 
+    size = mDecoder->GetVideoSize(size);
+
+  *aVideoWidth = size.width;
+  return NS_OK;
+}
+
+/* readonly attribute unsigned long videoHeight; */
+NS_IMETHODIMP nsHTMLVideoElement::GetVideoHeight(PRUint32 *aVideoHeight)
+{
+  nsIntSize size(0,0);
+  if (mDecoder) 
+    size = mDecoder->GetVideoSize(size);
+
+  *aVideoHeight = size.height;
+  return NS_OK;
+}
+
+
+nsHTMLVideoElement::nsHTMLVideoElement(nsINodeInfo *aNodeInfo, PRBool aFromParser)
+  : nsHTMLMediaElement(aNodeInfo, aFromParser)
+{
+}
+
+nsHTMLVideoElement::~nsHTMLVideoElement()
+{
+}
+
+nsIntSize nsHTMLVideoElement::GetVideoSize(nsIntSize defaultSize)
+{
+  return mDecoder ? mDecoder->GetVideoSize(defaultSize) : defaultSize;
+}
+
+double nsHTMLVideoElement::GetVideoFramerate() {
+  return mDecoder ? mDecoder->GetVideoFramerate() : 0.0;
+}
+
+
+nsresult nsHTMLVideoElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                                        nsIContent* aBindingParent,
+                                        PRBool aCompileEventHandlers)
+{
+  if (mDecoder)
+    mDecoder->ElementAvailable(this);
+
+  return nsHTMLMediaElement::BindToTree(aDocument, 
+                                        aParent, 
+                                        aBindingParent, 
+                                        aCompileEventHandlers);
+}
+
+void nsHTMLVideoElement::UnbindFromTree(PRBool aDeep,
+                                        PRBool aNullParent)
+{
+  if (mDecoder) 
+    mDecoder->ElementUnavailable();
+
+  nsHTMLMediaElement::UnbindFromTree(aDeep, aNullParent);
+}
+
+
+nsresult nsHTMLVideoElement::InitializeDecoder(nsAString& aChosenMediaResource)
+{
+  if (mDecoder) 
+    mDecoder->ElementAvailable(this);
+
+  return nsHTMLMediaElement::InitializeDecoder(aChosenMediaResource);
+}
+
--- a/content/html/document/src/nsHTMLContentSink.cpp
+++ b/content/html/document/src/nsHTMLContentSink.cpp
@@ -995,16 +995,20 @@ SinkContext::CloseContainer(const nsHTML
     }
 
     break;
   case eHTMLTag_iframe:
     mSink->mNumOpenIFRAMES--;
 
     break;
 
+#ifdef MOZ_MEDIA
+  case eHTMLTag_video:
+  case eHTMLTag_audio:
+#endif
   case eHTMLTag_select:
   case eHTMLTag_textarea:
   case eHTMLTag_object:
   case eHTMLTag_applet:
     content->DoneAddingChildren(HaveNotifiedForCurrentContent());
     break;
 
   case eHTMLTag_script:
new file mode 100644
--- /dev/null
+++ b/content/media/Makefile.in
@@ -0,0 +1,51 @@
+# ***** 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 code.
+#
+# The Initial Developer of the Original Code is the Mozilla Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2007
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#  Chris Double <chris.double@double.co.nz>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# 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 *****
+
+DEPTH		= ../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+ifdef MOZ_MEDIA
+DIRS 		= \
+		video \
+		$(NULL)
+endif
+
+include $(topsrcdir)/config/rules.mk
+
new file mode 100644
--- /dev/null
+++ b/content/media/video/Makefile.in
@@ -0,0 +1,50 @@
+# ***** 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 code.
+#
+# The Initial Developer of the Original Code is the Mozilla Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2007
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#  Chris Double <chris.double@double.co.nz>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# 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 *****
+
+DEPTH		= ../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+DIRS		= \
+		public \
+		src \
+		$(NULL)
+
+include $(topsrcdir)/config/rules.mk
+
new file mode 100644
--- /dev/null
+++ b/content/media/video/public/Makefile.in
@@ -0,0 +1,50 @@
+# ***** 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 code.
+#
+# The Initial Developer of the Original Code is the Mozilla Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2007
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#  Chris Double <chris.double@double.co.nz>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# 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 *****
+
+DEPTH		= ../../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE		= content
+
+EXPORTS		= \
+		nsVideoDecoder.h \
+		$(NULL)
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/content/media/video/public/nsVideoDecoder.h
@@ -0,0 +1,214 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: ML 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 ***** */
+#if !defined(nsVideoDecoder_h___)
+#define nsVideoDecoder_h___
+
+#include "nsIObserver.h"
+#include "nsSize.h"
+#include "prlog.h"
+#include "gfxContext.h"
+#include "gfxRect.h"
+#include "nsITimer.h"
+
+#ifdef PR_LOGGING
+extern PRLogModuleInfo* gVideoDecoderLog;
+#define LOG(type, msg) PR_LOG(gVideoDecoderLog, type, msg)
+#else
+#define LOG(type, msg)
+#endif
+
+class nsHTMLMediaElement;
+
+// All methods of nsVideoDecoder must be called from the main thread only
+// with the exception of SetRGBData. The latter can be called from any thread.
+class nsVideoDecoder : public nsIObserver
+{
+ public:
+  nsVideoDecoder();
+  virtual ~nsVideoDecoder() { }
+
+  // Initialize the logging object
+  static nsresult InitLogger();
+
+  // Perform any initialization required for the decoder.
+  // Return PR_TRUE on successful initialisation, PR_FALSE
+  // on failure.
+  virtual PRBool Init();
+
+  
+  // Return the current URI being played or downloaded.
+  virtual void GetCurrentURI(nsIURI** aURI) = 0;
+
+  // Return the time position in the video stream being
+  // played measured in seconds.
+  virtual float GetCurrentTime() = 0;
+
+  // Seek to the time position in (seconds) from the start of the video.
+  virtual nsresult Seek(float time) = 0;
+
+  // Called by the element when the playback rate has been changed.
+  // Adjust the speed of the playback, optionally with pitch correction,
+  // when this is called.
+  virtual nsresult PlaybackRateChanged() = 0;
+
+  // Return the duration of the video in seconds.
+  virtual float GetDuration() = 0;
+  
+  // Pause video playback.
+  virtual void Pause() = 0;
+
+  // Return the current audio volume that the video plays at. 
+  // This is a value form 0 through to 1.0.
+  virtual float GetVolume() = 0;
+
+  // Set the audio volume. It should be a value from 0 to 1.0.
+  virtual void SetVolume(float volume) = 0;
+
+  // Returns the current video frame width and height.
+  // If there is no video frame, returns the given default size.
+  virtual nsIntSize GetVideoSize(nsIntSize defaultSize) = 0;
+
+  // Return the current framerate of the video, in frames per second.
+  virtual double GetVideoFramerate() = 0;
+
+  // Start playback of a video. 'Load' must have previously been
+  // called.
+  virtual nsresult Play() = 0;
+
+  // Stop playback of a video, and stop download of video stream.
+  virtual void Stop() = 0;
+
+  // Start downloading the video at the given URI. Decode
+  // the downloaded data up to the point of the first frame
+  // of data. 
+  virtual nsresult Load(nsIURI* aURI) = 0;
+
+  // Draw the latest video data. This is done
+  // here instead of in nsVideoFrame so that the lock around the
+  // RGB buffer doesn't have to be exposed publically.
+  // The current video frame is drawn to fill aRect.
+  // Called in the main thread only.
+  virtual void Paint(gfxContext* aContext, const gfxRect& aRect);
+
+  // Called when the video file has completed downloading.
+  virtual void ResourceLoaded() = 0;
+
+  // Return the current number of bytes loaded from the video file.
+  // This is used for progress events.
+  virtual PRUint32 GetBytesLoaded() = 0;
+
+  // Return the size of the video file in bytes.
+  // This is used for progress events.
+  virtual PRUint32 GetTotalBytes() = 0;
+
+  // Called when the HTML DOM element is bound.
+  virtual void ElementAvailable(nsHTMLMediaElement* anElement);
+
+  // Called when the HTML DOM element is unbound.
+  virtual void ElementUnavailable();
+
+  // Invalidate the frame.
+  virtual void Invalidate();
+
+  // Update progress information.
+  virtual void Progress();
+
+protected:
+  // Cleanup internal data structures
+  virtual void Shutdown();
+
+  // Start invalidating the video frame at the interval required
+  // by the specificed framerate (in frames per second).
+  nsresult StartInvalidating(double aFramerate);
+
+  // Start timer to update download progress information.
+  nsresult StartProgress();
+
+  // Stop progress information timer.
+  nsresult StopProgress();
+
+  // Set the RGB width, height and framerate. The passed RGB buffer is
+  // copied to the mRGB buffer. This also allocates the mRGB buffer if
+  // needed.
+  // This is the only nsVideoDecoder method that may be called 
+  // from threads other than the main thread.
+  void SetRGBData(PRInt32 aWidth, 
+                  PRInt32 aHeight, 
+                  double aFramerate, 
+                  unsigned char* aRGBBuffer);
+
+protected:
+  // Timer used for invalidating the video 
+  nsCOMPtr<nsITimer> mInvalidateTimer;
+
+  // Timer used for updating progress events 
+  nsCOMPtr<nsITimer> mProgressTimer;
+
+  // The element is not reference counted. Instead the decoder is
+  // notified when it is able to be used. It should only ever be
+  // accessed from the main thread.
+  nsHTMLMediaElement* mElement;
+
+  // RGB data for last decoded frame of video data.
+  // The size of the buffer is mRGBWidth*mRGBHeight*4 bytes and
+  // contains bytes in RGBA format.
+  nsAutoArrayPtr<unsigned char> mRGB;
+
+  PRInt32 mRGBWidth;
+  PRInt32 mRGBHeight;
+
+  // Has our size changed since the last repaint?
+  PRPackedBool mSizeChanged;
+
+  // Lock around the video RGB, width and size data. This
+  // is used in the decoder backend threads and the main thread
+  // to ensure that repainting the video does not use these
+  // values while they are out of sync (width changed but
+  // not height yet, etc).
+  // Backends that are updating the height, width or writing
+  // to the RGB buffer must obtain this lock first to ensure that
+  // the video element does not use video data or sizes that are
+  // in the midst of being changed.
+  PRLock* mVideoUpdateLock;
+
+  // Framerate of video being displayed in the element
+  // expressed in numbers of frames per second.
+  double mFramerate;
+};
+
+#endif
new file mode 100644
--- /dev/null
+++ b/content/media/video/src/Makefile.in
@@ -0,0 +1,94 @@
+# ***** 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 code.
+#
+# The Initial Developer of the Original Code is the Mozilla Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2007
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#  Chris Double <chris.double@double.co.nz>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# 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 *****
+
+DEPTH		= ../../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE		= content
+LIBRARY_NAME	= gkconvideo_s
+LIBXUL_LIBRARY 	= 1
+
+REQUIRES	= \
+		xpcom \
+		string \
+		gfx \
+		content \
+		thebes \
+		layout \
+		widget \
+		dom \
+		js \
+		locale \
+		unicharutil \
+		webshell \
+		uriloader \
+		htmlparser \
+		necko \
+		view \
+		pref \
+		docshell \
+		xpconnect \
+		xuldoc \
+		caps \
+		editor \
+		imglib2 \
+		mimetype \
+		exthandler \
+		uconv \
+		intl \
+		plugin \
+		cairo \
+		libpixman \
+		$(NULL)
+
+CPPSRCS		= \
+		nsVideoDecoder.cpp \
+		$(NULL)
+
+FORCE_STATIC_LIB = 1
+
+include $(topsrcdir)/config/rules.mk
+
+INCLUDES	+= \
+		-I$(srcdir)/../../../base/src \
+		-I$(srcdir)/../../../html/content/src \
+		$(NULL)
+
+
new file mode 100644
--- /dev/null
+++ b/content/media/video/src/nsVideoDecoder.cpp
@@ -0,0 +1,255 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: ML 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 <new>
+#include "prlog.h"
+#include "prmem.h"
+#include "nsIFrame.h"
+#include "nsIDocument.h"
+#include "nsThreadUtils.h"
+#include "nsIDOMHTMLMediaElement.h"
+#include "nsNetUtil.h"
+#include "nsHTMLMediaElement.h"
+#include "nsIObserver.h"
+#include "nsIObserverService.h"
+#include "nsAutoLock.h"
+#include "nsIRenderingContext.h"
+#include "gfxContext.h"
+#include "gfxImageSurface.h"
+#include "nsPresContext.h"
+#include "nsVideoDecoder.h"
+
+#ifdef PR_LOGGING
+// Logging object for decoder
+PRLogModuleInfo* gVideoDecoderLog = nsnull;
+#endif
+
+nsVideoDecoder::nsVideoDecoder() :
+  mElement(0),
+  mRGBWidth(-1),
+  mRGBHeight(-1),
+  mSizeChanged(PR_FALSE),
+  mVideoUpdateLock(nsnull),
+  mFramerate(0.0)
+{
+}
+
+PRBool nsVideoDecoder::Init()
+{
+  mVideoUpdateLock = PR_NewLock();
+
+  return mVideoUpdateLock != nsnull;
+}
+
+void nsVideoDecoder::Shutdown()
+{
+  if (mVideoUpdateLock) {
+    PR_DestroyLock(mVideoUpdateLock);
+    mVideoUpdateLock = nsnull;
+  }
+}
+
+
+nsresult nsVideoDecoder::InitLogger() 
+{
+#ifdef PR_LOGGING
+  gVideoDecoderLog = PR_NewLogModule("nsVideoDecoder");
+#endif
+  return NS_OK;
+}
+
+static void InvalidateCallback(nsITimer* aTimer, void* aClosure)
+{
+  nsVideoDecoder* decoder = static_cast<nsVideoDecoder*>(aClosure);
+  decoder->Invalidate();
+}
+
+nsresult nsVideoDecoder::StartInvalidating(double aFramerate)
+{
+  nsresult rv = NS_OK;
+
+  if (!mInvalidateTimer && aFramerate > 0.0) {
+    mInvalidateTimer = do_CreateInstance("@mozilla.org/timer;1");
+    rv = mInvalidateTimer->InitWithFuncCallback(InvalidateCallback, 
+                                                this, 
+                                                static_cast<PRInt32>(1000.0/aFramerate), 
+                                                nsITimer::TYPE_REPEATING_PRECISE);
+  }
+  return rv;
+}
+
+void nsVideoDecoder::Invalidate()
+{
+  if (!mElement)
+    return;
+
+  nsIFrame* frame = mElement->GetPrimaryFrame();
+  if (!frame)
+    return;
+  
+  {
+    nsAutoLock lock(mVideoUpdateLock);
+    if (mSizeChanged) {
+      mSizeChanged = PR_FALSE;
+      nsPresContext* presContext = frame->PresContext();      
+      nsIPresShell *presShell = presContext->PresShell();
+      presShell->FrameNeedsReflow(frame, 
+                                  nsIPresShell::eStyleChange,
+                                  NS_FRAME_IS_DIRTY);
+    }
+  }
+  nsRect r(nsPoint(0,0), frame->GetSize());
+  frame->Invalidate(r, PR_FALSE);
+}
+
+static void ProgressCallback(nsITimer* aTimer, void* aClosure)
+{
+  nsVideoDecoder* decoder = static_cast<nsVideoDecoder*>(aClosure);
+  decoder->Progress();
+}
+
+void nsVideoDecoder::Progress()
+{
+  if (!mElement)
+    return;
+
+  mElement->DispatchProgressEvent(NS_LITERAL_STRING("progress"));
+}
+
+nsresult nsVideoDecoder::StartProgress()
+{
+  nsresult rv = NS_OK;
+
+  if (!mProgressTimer) {
+    mProgressTimer = do_CreateInstance("@mozilla.org/timer;1");
+    rv = mProgressTimer->InitWithFuncCallback(ProgressCallback, 
+                                              this, 
+                                              350, // Number of milliseconds defined in spec
+                                              nsITimer::TYPE_REPEATING_PRECISE);
+  }
+  return rv;
+}
+
+nsresult nsVideoDecoder::StopProgress()
+{
+  return NS_OK;
+  nsresult rv = NS_OK;
+  if (mProgressTimer) {
+    rv = mProgressTimer->Cancel();
+    mProgressTimer = nsnull;
+  }
+  return rv;
+}
+
+void nsVideoDecoder::SetRGBData(PRInt32 aWidth, PRInt32 aHeight, double aFramerate, unsigned char* aRGBBuffer)
+{
+  nsAutoLock lock(mVideoUpdateLock);
+  if (mRGBWidth != aWidth || mRGBHeight != aHeight) {
+    mRGBWidth = aWidth;
+    mRGBHeight = aHeight;
+    mSizeChanged = PR_TRUE;
+    // Delete buffer so we'll reallocate it
+    mRGB = nsnull;
+  }
+  mFramerate = aFramerate;
+
+  if (!mRGB) 
+    mRGB = new (std::nothrow) unsigned char[aWidth * aHeight * 4];
+  if (mRGB && aRGBBuffer) {
+    memcpy(mRGB.get(), aRGBBuffer, aWidth*aHeight*4);
+  }
+}
+
+void nsVideoDecoder::Paint(gfxContext* aContext, const gfxRect& aRect)
+{
+  nsAutoLock lock(mVideoUpdateLock);
+
+  if (!mRGB)
+    return;
+
+  if (mFramerate > 0.0) {
+    StartInvalidating(mFramerate);
+  }
+
+  /* Create a surface backed by the RGB */
+  nsRefPtr<gfxASurface> surface = 
+    new gfxImageSurface(mRGB,
+                        gfxIntSize(mRGBWidth, mRGBHeight), 
+                        mRGBWidth * 4,
+                        gfxASurface::ImageFormatARGB32);    
+
+  if (!surface)
+    return;
+
+  nsRefPtr<gfxPattern> pat = new gfxPattern(surface);
+  if (!pat)
+    return;
+
+  // Make the source image fill the rectangle completely
+  pat->SetMatrix(gfxMatrix().Scale(mRGBWidth/aRect.Width(), mRGBHeight/aRect.Height()));
+
+  /* Draw RGB surface onto frame */
+  aContext->NewPath();
+  aContext->PixelSnappedRectangleAndSetPattern(aRect, pat);
+  aContext->Fill();
+
+#ifdef DEBUG_FRAME_RATE
+  {
+    // Output frame rate
+    static double last = double(PR_IntervalToMilliseconds(PR_IntervalNow()))/1000.0;
+    double now = double(PR_IntervalToMilliseconds(PR_IntervalNow()))/1000.0;
+    static int count = 0;
+    count++;
+    if (now-last > 10.0) {
+      LOG(PR_LOG_DEBUG, ("Paint Frame Rate = %f (should be %f)\n", (float)count / (float)(now-last), mFramerate));
+      count = 0;
+      last = double(PR_IntervalToMilliseconds(PR_IntervalNow()))/1000.0;
+    }
+  }   
+#endif
+}
+
+void nsVideoDecoder::ElementAvailable(nsHTMLMediaElement* anElement)
+{
+  mElement = anElement;
+}
+
+void nsVideoDecoder::ElementUnavailable()
+{
+  mElement = nsnull;
+}
+
--- a/content/xml/document/src/nsXMLContentSink.cpp
+++ b/content/xml/document/src/nsXMLContentSink.cpp
@@ -584,16 +584,20 @@ nsXMLContentSink::CloseElement(nsIConten
 
   nsINodeInfo *nodeInfo = aContent->NodeInfo();
 
   // Some HTML nodes need DoneAddingChildren() called to initialize
   // properly (eg form state restoration).
   if ((nodeInfo->NamespaceID() == kNameSpaceID_XHTML &&
        (nodeInfo->NameAtom() == nsGkAtoms::select ||
         nodeInfo->NameAtom() == nsGkAtoms::textarea ||
+#ifdef MOZ_MEDIA
+        nodeInfo->NameAtom() == nsGkAtoms::video ||
+        nodeInfo->NameAtom() == nsGkAtoms::audio ||
+#endif
         nodeInfo->NameAtom() == nsGkAtoms::object ||
         nodeInfo->NameAtom() == nsGkAtoms::applet))
 #ifdef MOZ_XTF
       || nodeInfo->NamespaceID() > kNameSpaceID_LastBuiltin
 #endif
       ) {
     aContent->DoneAddingChildren(HaveNotifiedForCurrentContent());
   }
--- a/dom/public/idl/events/Makefile.in
+++ b/dom/public/idl/events/Makefile.in
@@ -54,16 +54,22 @@ SDK_XPIDLSRCS =                         
 	nsIDOM3DocumentEvent.idl		\
 	nsIDOM3EventTarget.idl			\
 	nsIDOMEventGroup.idl			\
 	nsIDOMCustomEvent.idl			\
 	nsIDOMMouseEvent.idl			\
 	nsIDOMUIEvent.idl			\
 	$(NULL)
 
+ifdef MOZ_MEDIA
+SDK_XPIDLSRCS +=				\
+	nsIDOMProgressEvent.idl			\
+	$(NULL)
+endif
+
 XPIDLSRCS =					\
 	nsIDOMNSEvent.idl			\
 	nsIDOMDataContainerEvent.idl	\
 	nsIDOMKeyEvent.idl			\
 	nsIDOMMutationEvent.idl			\
 	nsIDOMNSUIEvent.idl			\
 	nsIDOMPopupBlockedEvent.idl		\
 	nsIDOMBeforeUnloadEvent.idl		\
new file mode 100644
--- /dev/null
+++ b/dom/public/idl/events/nsIDOMProgressEvent.idl
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: ML 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 "nsIDOMEvent.idl"
+
+/**
+ * The nsIDOMProgressEvent is used in the media elements (<video> and <audio>
+ * to inform of the progress of the media download. It is currently undefined
+ * in the HTML5 specification. This implementation is a placeholder until
+ * the specification is complete and is compatible with the WebKit ProgressEvent.
+ */
+
+[scriptable, uuid(3fa16b05-81a0-4a17-ab06-98c3a5a5be09)]
+interface nsIDOMProgressEvent : nsIDOMEvent
+{
+  readonly attribute boolean lengthComputable;
+  readonly attribute unsigned long loaded;
+  readonly attribute unsigned long total;
+  void initProgressEvent(in DOMString typeArg,
+                         in boolean canBubbleArg,
+                         in boolean cancelableArg,
+                         in boolean lengthComputableArg,
+                         in unsigned long loadedArg,
+                         in unsigned long totalArg);
+};
--- a/dom/public/idl/html/Makefile.in
+++ b/dom/public/idl/html/Makefile.in
@@ -101,16 +101,28 @@ SDK_XPIDLSRCS =					\
 	nsIDOMHTMLTableElement.idl		\
 	nsIDOMHTMLTableRowElement.idl		\
 	nsIDOMHTMLTableSectionElem.idl		\
 	nsIDOMHTMLTextAreaElement.idl		\
 	nsIDOMHTMLTitleElement.idl		\
 	nsIDOMHTMLUListElement.idl		\
 	$(NULL)
 
+ifdef MOZ_MEDIA
+SDK_XPIDLSRCS +=				\
+	nsIDOMHTMLMediaError.idl		\
+	nsIDOMHTMLTimeRanges.idl		\
+	nsIDOMHTMLMediaElement.idl		\
+	nsIDOMHTMLSourceElement.idl		\
+	nsIDOMHTMLVideoElement.idl		\
+	nsIDOMHTMLAudioElement.idl		\
+	nsIDOMHTMLVoidCallback.idl		\
+	$(NULL)
+endif
+
 XPIDLSRCS = 					\
 	nsIDOMHTMLCanvasElement.idl		\
 	nsIDOMNSHTMLAnchorElement.idl		\
 	nsIDOMNSHTMLAnchorElement2.idl		\
 	nsIDOMNSHTMLAreaElement.idl		\
 	nsIDOMNSHTMLAreaElement2.idl		\
 	nsIDOMNSHTMLButtonElement.idl		\
 	nsIDOMNSHTMLDocument.idl		\
new file mode 100644
--- /dev/null
+++ b/dom/public/idl/html/nsIDOMHTMLAudioElement.idl
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 "nsIDOMHTMLMediaElement.idl"
+
+/**
+ * The nsIDOMHTMLAudioElement interface is the interface to a HTML
+ * <audio> element.
+ *
+ * For more information on this interface, please see
+ * http://www.whatwg.org/specs/web-apps/current-work/#audio
+ *
+ * @status UNDER_DEVELOPMENT
+ */
+
+[scriptable, uuid(5ecd8913-a738-41be-8597-7f3a4ffba017)]
+interface nsIDOMHTMLAudioElement : nsIDOMHTMLMediaElement
+{
+};
+
new file mode 100644
--- /dev/null
+++ b/dom/public/idl/html/nsIDOMHTMLMediaElement.idl
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 "nsIDOMHTMLElement.idl"
+#include "nsIDOMHTMLMediaError.idl"
+#include "nsIDOMHTMLTimeRanges.idl"
+#include "nsIDOMHTMLVoidCallback.idl"
+
+/**
+ * The nsIDOMHTMLMediaElement interface is an interface to be implemented by the HTML
+ * <audio> and <video> elements.
+ *
+ * For more information on this interface, please see
+ * http://www.whatwg.org/specs/web-apps/current-work/#htmlmediaelement
+ *
+ * @status UNDER_DEVELOPMENT
+ */
+
+[scriptable, uuid(c8ce31b9-d18b-48c4-8309-944f0ccb1435)]
+interface nsIDOMHTMLMediaElement : nsIDOMHTMLElement
+{
+  // error state
+  readonly attribute nsIDOMHTMLMediaError error;
+
+  // network state
+           attribute DOMString src;
+  readonly attribute DOMString currentSrc;
+  const unsigned short EMPTY = 0;
+  const unsigned short LOADING = 1;
+  const unsigned short LOADED_METADATA = 2;
+  const unsigned short LOADED_FIRST_FRAME = 3;
+  const unsigned short LOADED = 4;
+  readonly attribute unsigned short networkState;
+  readonly attribute float bufferingRate;
+  readonly attribute nsIDOMHTMLTimeRanges buffered;
+  void load();
+
+  // ready state
+  const unsigned short DATA_UNAVAILABLE = 0;
+  const unsigned short CAN_SHOW_CURRENT_FRAME = 1;
+  const unsigned short CAN_PLAY = 2;
+  const unsigned short CAN_PLAY_THROUGH = 3;
+  readonly attribute unsigned short readyState;
+  readonly attribute boolean seeking;
+
+  // playback state
+           attribute float currentTime;
+  readonly attribute float duration;
+  readonly attribute unsigned short paused;
+           attribute float defaultPlaybackRate;
+           attribute float playbackRate;
+  readonly attribute nsIDOMHTMLTimeRanges played;
+  readonly attribute nsIDOMHTMLTimeRanges seekable;
+  readonly attribute boolean ended;
+           attribute boolean autoplay;
+  void play();
+  void pause();
+
+  // looping
+           attribute float start;
+           attribute float end;
+           attribute float loopStart;
+           attribute float loopEnd;
+           attribute unsigned long loopCount;
+           attribute unsigned long currentLoop;
+
+  // cue points
+  void addCuePoint(in float time, in nsIDOMHTMLVoidCallback callback, in boolean pause);
+  void removeCuePoint(in float time, in nsIDOMHTMLVoidCallback callback);
+
+  // controls
+           attribute boolean controls;
+           attribute float volume;
+           attribute boolean muted;
+};
+
new file mode 100644
--- /dev/null
+++ b/dom/public/idl/html/nsIDOMHTMLMediaError.idl
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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"
+
+[scriptable, uuid(9BEA222F-13CF-42AD-A14E-E01F4F66B833)]
+interface nsIDOMHTMLMediaError : nsISupports
+{
+  /* The download of the media resource was aborted by
+     the user agent at the user's requet */
+  const unsigned short MEDIA_ERR_ABORTED = 1;
+
+  /* A network error of some description caused the 
+     user agent to stop downloading the media resource */
+  const unsigned short MEDIA_ERR_NETWORK = 2;
+
+  /* An error of some description occurred while decoding 
+     the media resource */
+  const unsigned short MEDIA_ERR_DECODE  = 3;
+
+  readonly attribute unsigned short code;
+};
new file mode 100644
--- /dev/null
+++ b/dom/public/idl/html/nsIDOMHTMLSourceElement.idl
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 "nsIDOMHTMLElement.idl"
+
+/**
+ * The nsIDOMHTMLVideoElement interface is the interface to a HTML
+ * <source> element.
+ *
+ * For more information on this interface, please see
+ * http://www.whatwg.org/specs/web-apps/current-work/#source
+ *
+ * @status UNDER_DEVELOPMENT
+ */
+
+[scriptable, uuid(BF80FED9-BDBA-4C5A-AD23-203FAA4C4892)]
+interface nsIDOMHTMLSourceElement : nsIDOMHTMLElement
+{
+           attribute DOMString           src;
+           attribute DOMString           type;
+           attribute DOMString           media;
+};
new file mode 100644
--- /dev/null
+++ b/dom/public/idl/html/nsIDOMHTMLTimeRanges.idl
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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"
+
+[scriptable, uuid(5C9995A1-9FCE-44E8-AA7F-DE52FF4C3F46)]
+interface nsIDOMHTMLTimeRanges : nsISupports
+{
+  /* The number of ranges represented by the time range object */
+  readonly attribute unsigned long length;
+
+  /* The position of the start of the index'd range, in seconds measured
+     from the start of the timeline that this object represents */
+  float start(in unsigned long index);
+
+  /* The position of the end of the index'd range, in seconds measured
+     from the start of the timeline that this object represents */
+  float end(in unsigned long index);
+};
new file mode 100644
--- /dev/null
+++ b/dom/public/idl/html/nsIDOMHTMLVideoElement.idl
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 "nsIDOMHTMLMediaElement.idl"
+
+/**
+ * The nsIDOMHTMLVideoElement interface is the interface to a HTML
+ * <video> element.
+ *
+ * For more information on this interface, please see
+ * http://www.whatwg.org/specs/web-apps/current-work/#video
+ *
+ * @status UNDER_DEVELOPMENT
+ */
+
+[scriptable, uuid(B08457F7-8709-4D70-AC19-90433C77CD1E)]
+interface nsIDOMHTMLVideoElement : nsIDOMHTMLMediaElement
+{
+           attribute long width; 
+           attribute long height;
+  readonly attribute unsigned long videoWidth;
+  readonly attribute unsigned long videoHeight;
+           attribute DOMString poster;
+};
+
new file mode 100644
--- /dev/null
+++ b/dom/public/idl/html/nsIDOMHTMLVoidCallback.idl
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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"
+
+[scriptable, uuid(4A17C0E2-FDD5-4855-A71C-B4C509DFFA13)]
+interface nsIDOMHTMLVoidCallback : nsISupports {
+  void handleEvent();
+};
+
--- a/dom/public/nsDOMClassInfoID.h
+++ b/dom/public/nsDOMClassInfoID.h
@@ -400,17 +400,16 @@ enum nsDOMClassInfoID {
   // default.
 
 #if defined(MOZ_SVG) && defined(MOZ_SVG_FOREIGNOBJECT)
   eDOMClassInfo_SVGForeignObjectElement_id,
 #endif
 
   eDOMClassInfo_XULCommandEvent_id,
   eDOMClassInfo_CommandEvent_id,
-
   eDOMClassInfo_OfflineResourceList_id,
   eDOMClassInfo_LoadStatusList_id,
   eDOMClassInfo_LoadStatus_id,
   eDOMClassInfo_LoadStatusEvent_id,
 
   eDOMClassInfo_FileList_id,
   eDOMClassInfo_File_id,
   eDOMClassInfo_FileException_id,
@@ -420,16 +419,25 @@ enum nsDOMClassInfoID {
 
   // Data Events
   eDOMClassInfo_DataContainerEvent_id,
 
   // event used for cross-domain message-passing and for server-sent events in
   // HTML5
   eDOMClassInfo_MessageEvent_id,
 
+  // WhatWG Video Element
+#if defined(MOZ_MEDIA)
+  eDOMClassInfo_HTMLVideoElement_id,
+  eDOMClassInfo_HTMLSourceElement_id,
+  eDOMClassInfo_ProgressEvent_id,
+  eDOMClassInfo_HTMLMediaError_id,
+  eDOMClassInfo_HTMLAudioElement_id,
+#endif
+
   // 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
@@ -308,16 +308,23 @@
 #include "nsIDOMHTMLTableColElement.h"
 #include "nsIDOMHTMLTableElement.h"
 #include "nsIDOMHTMLTableRowElement.h"
 #include "nsIDOMHTMLTableSectionElem.h"
 #include "nsIDOMHTMLTextAreaElement.h"
 #include "nsIDOMNSHTMLTextAreaElement.h"
 #include "nsIDOMHTMLTitleElement.h"
 #include "nsIDOMHTMLUListElement.h"
+#if defined(MOZ_MEDIA)
+#include "nsIDOMHTMLMediaError.h"
+#include "nsIDOMHTMLSourceElement.h"
+#include "nsIDOMHTMLVideoElement.h"
+#include "nsIDOMHTMLAudioElement.h"
+#include "nsIDOMProgressEvent.h"
+#endif
 #include "nsIDOMNSUIEvent.h"
 #include "nsIDOMCSS2Properties.h"
 #include "nsIDOMCSSCharsetRule.h"
 #include "nsIDOMCSSImportRule.h"
 #include "nsIDOMCSSMediaRule.h"
 #include "nsIDOMCSSMozDocumentRule.h"
 #include "nsIDOMCSSPrimitiveValue.h"
 #include "nsIDOMCSSStyleRule.h"
@@ -1203,17 +1210,16 @@ static nsDOMClassInfoData sClassInfoData
                            ELEMENT_SCRIPTABLE_FLAGS)
 #endif
 
   NS_DEFINE_CLASSINFO_DATA(XULCommandEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(CommandEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
-
   NS_DEFINE_CLASSINFO_DATA(OfflineResourceList, nsOfflineResourceListSH,
                            ARRAY_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(LoadStatusList, nsLoadStatusListSH,
                            ARRAY_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(LoadStatus, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(LoadStatusEvent, nsDOMGenericSH,
@@ -1230,16 +1236,29 @@ static nsDOMClassInfoData sClassInfoData
                            DEFAULT_SCRIPTABLE_FLAGS |
                            WINDOW_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(DataContainerEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(MessageEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
+
+#if defined(MOZ_MEDIA) 
+  NS_DEFINE_CLASSINFO_DATA(HTMLVideoElement, nsHTMLElementSH,
+                           ELEMENT_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(HTMLSourceElement, nsHTMLElementSH,
+                           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
 };
 
 // Objects that shuld be constructable through |new Name();|
 struct nsContractIDMapData
 {
   PRInt32 mDOMClassInfoID;
   const char *mContractID;
 };
@@ -3381,16 +3400,43 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDataContainerEvent)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(MessageEvent, nsIDOMMessageEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMessageEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
+#if defined(MOZ_MEDIA)
+  DOM_CLASSINFO_MAP_BEGIN(HTMLVideoElement, nsIDOMHTMLVideoElement)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLVideoElement)
+    DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
+  DOM_CLASSINFO_MAP_END
+
+  DOM_CLASSINFO_MAP_BEGIN(HTMLSourceElement, nsIDOMHTMLSourceElement)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLSourceElement)
+    DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
+  DOM_CLASSINFO_MAP_END
+
+  DOM_CLASSINFO_MAP_BEGIN(ProgressEvent, nsIDOMProgressEvent)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMProgressEvent)
+    DOM_CLASSINFO_EVENT_MAP_ENTRIES
+  DOM_CLASSINFO_MAP_END
+
+  DOM_CLASSINFO_MAP_BEGIN(HTMLMediaError, nsIDOMHTMLMediaError)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLMediaError)
+    DOM_CLASSINFO_EVENT_MAP_ENTRIES
+  DOM_CLASSINFO_MAP_END
+
+  DOM_CLASSINFO_MAP_BEGIN(HTMLAudioElement, nsIDOMHTMLAudioElement)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLAudioElement)
+    DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
+  DOM_CLASSINFO_MAP_END
+#endif
+
 #ifdef NS_DEBUG
   {
     PRUint32 i = NS_ARRAY_LENGTH(sClassInfoData);
 
     if (i != eDOMClassInfoIDCount) {
       NS_ERROR("The number of items in sClassInfoData doesn't match the "
                "number of nsIDOMClassInfo ID's, this is bad! Fix it!");
 
--- a/editor/libeditor/html/nsHTMLEditUtils.cpp
+++ b/editor/libeditor/html/nsHTMLEditUtils.cpp
@@ -565,16 +565,19 @@ static const nsElementInfo kElements[eHT
   ELEM(a, PR_TRUE, PR_FALSE, GROUP_SPECIAL, GROUP_INLINE_ELEMENT),
   ELEM(abbr, PR_TRUE, PR_TRUE, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
   ELEM(acronym, PR_TRUE, PR_TRUE, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
   ELEM(address, PR_TRUE, PR_TRUE, GROUP_BLOCK,
        GROUP_INLINE_ELEMENT | GROUP_P),
   ELEM(applet, PR_TRUE, PR_TRUE, GROUP_SPECIAL | GROUP_BLOCK,
        GROUP_FLOW_ELEMENT | GROUP_OBJECT_CONTENT),
   ELEM(area, PR_FALSE, PR_FALSE, GROUP_MAP_CONTENT, GROUP_NONE),
+#if defined(MOZ_MEDIA)
+  ELEM(audio, PR_FALSE, PR_FALSE, GROUP_NONE, GROUP_NONE),
+#endif
   ELEM(b, PR_TRUE, PR_TRUE, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT),
   ELEM(base, PR_FALSE, PR_FALSE, GROUP_HEAD_CONTENT, GROUP_NONE),
   ELEM(basefont, PR_FALSE, PR_FALSE, GROUP_SPECIAL, GROUP_NONE),
   ELEM(bdo, PR_TRUE, PR_TRUE, GROUP_SPECIAL, GROUP_INLINE_ELEMENT),
   ELEM(bgsound, PR_FALSE, PR_FALSE, GROUP_NONE, GROUP_NONE),
   ELEM(big, PR_TRUE, PR_TRUE, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT),
   ELEM(blink, PR_FALSE, PR_FALSE, GROUP_NONE, GROUP_NONE),
   ELEM(blockquote, PR_TRUE, PR_TRUE, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
@@ -653,16 +656,19 @@ static const nsElementInfo kElements[eHT
   ELEM(pre, PR_TRUE, PR_TRUE, GROUP_BLOCK, GROUP_INLINE_ELEMENT),
   ELEM(q, PR_TRUE, PR_TRUE, GROUP_SPECIAL, GROUP_INLINE_ELEMENT),
   ELEM(s, PR_TRUE, PR_TRUE, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT),
   ELEM(samp, PR_TRUE, PR_TRUE, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
   ELEM(script, PR_TRUE, PR_FALSE, GROUP_HEAD_CONTENT | GROUP_SPECIAL,
        GROUP_LEAF),
   ELEM(select, PR_TRUE, PR_FALSE, GROUP_FORMCONTROL, GROUP_SELECT_CONTENT),
   ELEM(small, PR_TRUE, PR_TRUE, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT),
+#if defined(MOZ_MEDIA)
+  ELEM(source, PR_FALSE, PR_FALSE, GROUP_NONE, GROUP_NONE),
+#endif
   ELEM(spacer, PR_FALSE, PR_FALSE, GROUP_NONE, GROUP_NONE),
   ELEM(span, PR_TRUE, PR_TRUE, GROUP_SPECIAL, GROUP_INLINE_ELEMENT),
   ELEM(strike, PR_TRUE, PR_TRUE, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT),
   ELEM(strong, PR_TRUE, PR_TRUE, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
   ELEM(style, PR_TRUE, PR_FALSE, GROUP_HEAD_CONTENT, GROUP_LEAF),
   ELEM(sub, PR_TRUE, PR_TRUE, GROUP_SPECIAL, GROUP_INLINE_ELEMENT),
   ELEM(sup, PR_TRUE, PR_TRUE, GROUP_SPECIAL, GROUP_INLINE_ELEMENT),
   ELEM(table, PR_TRUE, PR_FALSE, GROUP_BLOCK, GROUP_TABLE_CONTENT),
@@ -675,16 +681,19 @@ static const nsElementInfo kElements[eHT
   ELEM(title, PR_TRUE, PR_FALSE, GROUP_HEAD_CONTENT, GROUP_LEAF),
   ELEM(tr, PR_TRUE, PR_FALSE, GROUP_TBODY_CONTENT, GROUP_TR_CONTENT),
   ELEM(tt, PR_TRUE, PR_TRUE, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT),
   ELEM(u, PR_TRUE, PR_TRUE, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT),
   // XXX Can contain self and ol because editor does sublists illegally.
   ELEM(ul, PR_TRUE, PR_TRUE, GROUP_BLOCK | GROUP_OL_UL,
        GROUP_LI | GROUP_OL_UL),
   ELEM(var, PR_TRUE, PR_TRUE, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
+#if defined(MOZ_MEDIA)
+  ELEM(video, PR_FALSE, PR_FALSE, GROUP_NONE, GROUP_NONE),
+#endif
   ELEM(wbr, PR_FALSE, PR_FALSE, GROUP_NONE, GROUP_NONE),
   ELEM(xmp, PR_FALSE, PR_FALSE, GROUP_NONE, GROUP_NONE),
 
   // These aren't elements.
   ELEM(text, PR_FALSE, PR_FALSE, GROUP_LEAF, GROUP_NONE),
   ELEM(whitespace, PR_FALSE, PR_FALSE, GROUP_LEAF, GROUP_NONE),
   ELEM(newline, PR_FALSE, PR_FALSE, GROUP_LEAF, GROUP_NONE),
   ELEM(comment, PR_FALSE, PR_FALSE, GROUP_LEAF, GROUP_NONE),
--- a/gfx/thebes/public/gfxImageSurface.h
+++ b/gfx/thebes/public/gfxImageSurface.h
@@ -46,24 +46,33 @@
 /**
  * A raw image buffer. The format can be set in the constructor. Its main
  * purpose is for storing read-only images and using it as a source surface,
  * but it can also be drawn to.
  */
 class THEBES_API gfxImageSurface : public gfxASurface {
 public:
     /**
-     * Construct an image surface.
+     * Construct an image surface around an existing buffer of image data.
+     * @param aData A buffer containing the image data
+     * @param aSize The size of the buffer
+     * @param aStride The stride of the buffer
      * @param format Format of the data
-     * @param width Width of the surface in pixels
-     * @param height Height in pixels
      *
      * @see gfxImageFormat
+     */
+    gfxImageSurface(unsigned char *aData, const gfxIntSize& aSize,
+                    long aStride, gfxImageFormat aFormat);
+
+    /**
+     * Construct an image surface.
+     * @param aSize The size of the buffer
+     * @param format Format of the data
      *
-     * XXX why not unsigned long for the dimensions? And, why not gfxSize?
+     * @see gfxImageFormat
      */
     gfxImageSurface(const gfxIntSize& size, gfxImageFormat format);
     gfxImageSurface(cairo_surface_t *csurf);
 
     virtual ~gfxImageSurface();
 
     // ImageSurface methods
     gfxImageFormat Format() const { return mFormat; }
--- a/gfx/thebes/src/gfxImageSurface.cpp
+++ b/gfx/thebes/src/gfxImageSurface.cpp
@@ -36,16 +36,42 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "prmem.h"
 
 #include "gfxImageSurface.h"
 
 #include "cairo.h"
 
+gfxImageSurface::gfxImageSurface(unsigned char *aData, const gfxIntSize& aSize,
+                                 long aStride, gfxImageFormat aFormat)
+  : mSize(aSize)
+  , mOwnsData(PR_FALSE)
+  , mData(aData)
+  , mFormat(aFormat)
+  , mStride(aStride)
+{
+    if (!CheckSurfaceSize(aSize))
+        return;
+
+    cairo_surface_t *surface =
+        cairo_image_surface_create_for_data((unsigned char*)mData,
+                                            (cairo_format_t)mFormat,
+                                            mSize.width,
+                                            mSize.height,
+                                            mStride);
+
+    // cairo_image_surface_create_for_data can return a 'null' surface
+    // in out of memory conditions. The gfxASurface::Init call checks
+    // the surface it receives to see if there is an error with the
+    // surface and handles it appropriately. That is why there is
+    // no check here.
+    Init(surface);
+}
+
 gfxImageSurface::gfxImageSurface(const gfxIntSize& size, gfxImageFormat format) :
     mSize(size), mOwnsData(PR_FALSE), mFormat(format)
 {
     mStride = ComputeStride();
 
     if (!CheckSurfaceSize(size))
         return;
 
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -146,16 +146,21 @@
 
 #ifdef MOZ_MATHML
 #include "nsMathMLParts.h"
 #endif
 
 nsIFrame*
 NS_NewHTMLCanvasFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
 
+#if defined(MOZ_MEDIA)
+nsIFrame*
+NS_NewHTMLVideoFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
+#endif
+
 #ifdef MOZ_SVG
 #include "nsISVGTextContentMetrics.h"
 
 PRBool
 NS_SVGEnabled();
 nsIFrame*
 NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsStyleContext* aContext);
 nsIFrame*
@@ -5564,17 +5569,25 @@ nsCSSFrameConstructor::ConstructHTMLFram
   }
   else if (nsGkAtoms::canvas == aTag) {
     if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
       ProcessPseudoFrames(aState, aFrameItems); 
     }
     newFrame = NS_NewHTMLCanvasFrame(mPresShell, aStyleContext);
     triedFrame = PR_TRUE;
   }
-
+#if defined(MOZ_MEDIA)
+  else if (nsGkAtoms::video == aTag) {
+    if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
+      ProcessPseudoFrames(aState, aFrameItems); 
+    }
+    newFrame = NS_NewHTMLVideoFrame(mPresShell, aStyleContext);
+    triedFrame = PR_TRUE;
+  }
+#endif
   if (NS_UNLIKELY(triedFrame && !newFrame)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   else if (NS_FAILED(rv) || !newFrame) {
     return rv;
   }
 
   // If we succeeded in creating a frame then initialize it, process its
@@ -5678,16 +5691,19 @@ nsCSSFrameConstructor::CreateAnonymousFr
       aTag != nsGkAtoms::input &&
       aTag != nsGkAtoms::textarea &&
       aTag != nsGkAtoms::combobox &&
       aTag != nsGkAtoms::isindex &&
       aTag != nsGkAtoms::scrollbar
 #ifdef MOZ_SVG
       && aTag != nsGkAtoms::use
 #endif
+#ifdef MOZ_MEDIA
+      && aTag != nsGkAtoms::video
+#endif
       )
     return NS_OK;
 
   return CreateAnonymousFrames(aState, aParent, mDocument, aNewFrame,
                                aAppendToExisting, aChildItems);
 }
 
 // after the node has been constructed and initialized create any
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -158,16 +158,17 @@
 #include "nsIObjectFrame.h"
 #include "nsIObjectLoadingContent.h"
 #include "nsNetUtil.h"
 #include "nsEventDispatcher.h"
 #include "nsThreadUtils.h"
 #include "nsStyleSheetService.h"
 #include "gfxImageSurface.h"
 #include "gfxContext.h"
+#include "nsVideoFrame.h"
 
 // Drag & Drop, Clipboard
 #include "nsWidgetsCID.h"
 #include "nsIClipboard.h"
 #include "nsIClipboardHelper.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIURI.h"
 #include "nsIScrollableFrame.h"
@@ -6055,16 +6056,28 @@ StopPluginInstance(PresShell *aShell, ns
   if (frame)
     CallQueryInterface(frame, &objectFrame);
   if (!objectFrame)
     return;
 
   objectFrame->StopPlugin();
 }
 
+static void
+StopVideoInstance(PresShell *aShell, nsIContent *aContent)
+{
+  nsVideoFrame *frame = static_cast<nsVideoFrame*>(aShell->FrameManager()->GetPrimaryFrameFor(aContent, -1));
+  if (frame) {
+    nsIAtom* frameType = frame->GetType();
+    if (frameType == nsGkAtoms::HTMLVideoFrame) {
+      frame->Freeze();
+    }
+  }
+}
+
 PR_STATIC_CALLBACK(PRBool)
 FreezeSubDocument(nsIDocument *aDocument, void *aData)
 {
   nsIPresShell *shell = aDocument->GetPrimaryShell();
   if (shell)
     shell->Freeze();
 
   return PR_TRUE;
@@ -6073,16 +6086,17 @@ FreezeSubDocument(nsIDocument *aDocument
 void
 PresShell::Freeze()
 {
   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
   if (domDoc) {
     EnumeratePlugins(domDoc, NS_LITERAL_STRING("object"), StopPluginInstance);
     EnumeratePlugins(domDoc, NS_LITERAL_STRING("applet"), StopPluginInstance);
     EnumeratePlugins(domDoc, NS_LITERAL_STRING("embed"), StopPluginInstance);
+    EnumeratePlugins(domDoc, NS_LITERAL_STRING("video"), StopVideoInstance);
   }
 
   if (mCaret)
     mCaret->SetCaretVisible(PR_FALSE);
 
   mPaintingSuppressed = PR_TRUE;
 
   if (mDocument)
@@ -6095,16 +6109,28 @@ StartPluginInstance(PresShell *aShell, n
   nsCOMPtr<nsIObjectLoadingContent> objlc(do_QueryInterface(aContent));
   if (!objlc)
     return;
 
   nsCOMPtr<nsIPluginInstance> inst;
   objlc->EnsureInstantiation(getter_AddRefs(inst));
 }
 
+static void
+StartVideoInstance(PresShell *aShell, nsIContent *aContent)
+{
+  nsVideoFrame *frame = static_cast<nsVideoFrame*>(aShell->FrameManager()->GetPrimaryFrameFor(aContent, -1));
+  if (frame) {
+    nsIAtom* frameType = frame->GetType();
+    if (frameType == nsGkAtoms::HTMLVideoFrame) {
+      frame->Thaw();
+    }
+  }
+}
+
 PR_STATIC_CALLBACK(PRBool)
 ThawSubDocument(nsIDocument *aDocument, void *aData)
 {
   nsIPresShell *shell = aDocument->GetPrimaryShell();
   if (shell)
     shell->Thaw();
 
   return PR_TRUE;
@@ -6113,16 +6139,17 @@ ThawSubDocument(nsIDocument *aDocument, 
 void
 PresShell::Thaw()
 {
   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
   if (domDoc) {
     EnumeratePlugins(domDoc, NS_LITERAL_STRING("object"), StartPluginInstance);
     EnumeratePlugins(domDoc, NS_LITERAL_STRING("applet"), StartPluginInstance);
     EnumeratePlugins(domDoc, NS_LITERAL_STRING("embed"), StartPluginInstance);
+    EnumeratePlugins(domDoc, NS_LITERAL_STRING("video"), StartVideoInstance);
   }
 
   if (mDocument)
     mDocument->EnumerateSubDocuments(ThawSubDocument, nsnull);
 
   UnsuppressPainting();
 }
 
--- a/layout/build/Makefile.in
+++ b/layout/build/Makefile.in
@@ -137,16 +137,22 @@ SHARED_LIBRARY_LIBS = \
 	$(DEPTH)/dom/src/json/$(LIB_PREFIX)json_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/src/jsurl/$(LIB_PREFIX)jsurl_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/src/storage/$(LIB_PREFIX)jsdomstorage_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/src/offline/$(LIB_PREFIX)jsdomoffline_s.$(LIB_SUFFIX) \
 	$(DEPTH)/editor/libeditor/text/$(LIB_PREFIX)texteditor_s.$(LIB_SUFFIX) \
 	$(DEPTH)/editor/libeditor/base/$(LIB_PREFIX)editorbase_s.$(LIB_SUFFIX) \
 	$(NULL)
 
+ifdef MOZ_MEDIA
+SHARED_LIBRARY_LIBS 	+= \
+	$(DEPTH)/content/media/video/src/$(LIB_PREFIX)gkconvideo_s.$(LIB_SUFFIX) \
+	$(NULL)
+endif
+
 ifdef NS_PRINTING
 SHARED_LIBRARY_LIBS += \
 		../printing/$(LIB_PREFIX)gkprinting_s.$(LIB_SUFFIX) \
 		$(NULL)
 endif
 
 ifdef MOZ_XUL
 SHARED_LIBRARY_LIBS += \
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -105,16 +105,20 @@
 PRBool NS_SVGEnabled();
 #endif
 
 #ifndef MOZILLA_PLAINTEXT_EDITOR_ONLY
 #include "nsHTMLEditor.h"
 #include "nsTextServicesDocument.h"
 #endif
 
+#ifdef MOZ_MEDIA
+#include "nsVideoDecoder.h"
+#endif
+
 #include "nsError.h"
 #include "nsTraceRefcnt.h"
 
 #include "nsCycleCollector.h"
 
 static nsrefcnt sLayoutStaticRefcnt;
 
 nsresult
@@ -230,16 +234,25 @@ nsLayoutStatics::Initialize()
 #ifdef MOZ_XUL
   rv = nsXULPopupManager::Init();
   if (NS_FAILED(rv)) {
     NS_ERROR("Could not initialize nsXULPopupManager");
     return rv;
   }
 #endif
 
+#ifdef MOZ_MEDIA
+  rv = nsVideoDecoder::InitLogger();
+  if (NS_FAILED(rv)) {
+    NS_ERROR("Could not initialize nsVideoDecoder");
+    return rv;
+  }
+  
+#endif
+
   return NS_OK;
 }
 
 void
 nsLayoutStatics::Shutdown()
 {
 #ifdef MOZ_XUL
   nsXULPopupManager::Shutdown();
--- a/layout/generic/Makefile.in
+++ b/layout/generic/Makefile.in
@@ -154,16 +154,22 @@ CPPSRCS		= \
 		nsSpacerFrame.cpp \
 		nsSplittableFrame.cpp \
 		nsTextFrameThebes.cpp \
 		nsTextFrameUtils.cpp \
 		nsTextRunTransformations.cpp \
 		nsViewportFrame.cpp \
 		$(NULL)
 
+ifdef MOZ_MEDIA
+CPPSRCS		+= \
+		nsVideoFrame.cpp \
+		$(NULL)
+endif
+
 ifdef IBMBIDI
 CPPSRCS		+= \
 		nsBidiFrames.cpp \
 		$(NULL)
 endif
 
 RESOURCES_HTML = \
 		$(srcdir)/folder.png \
new file mode 100644
--- /dev/null
+++ b/layout/generic/nsVideoFrame.cpp
@@ -0,0 +1,347 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 ***** */
+
+/* rendering object for the HTML <video> element */
+
+#include "nsHTMLParts.h"
+#include "nsCOMPtr.h"
+#include "nsIServiceManager.h"
+#include "nsGkAtoms.h"
+
+#include "nsVideoFrame.h"
+#include "nsHTMLVideoElement.h"
+#include "nsIDOMHTMLVideoElement.h"
+#include "nsDisplayList.h"
+#include "nsIRenderingContext.h"
+#include "gfxContext.h"
+#include "gfxImageSurface.h"
+#include "nsPresContext.h"
+#include "nsTransform2D.h"
+#include "nsContentCreatorFunctions.h"
+#include "nsBoxLayoutState.h"
+#include "nsBoxFrame.h"
+
+nsIFrame*
+NS_NewHTMLVideoFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
+{
+  return new (aPresShell) nsVideoFrame(aContext);
+}
+
+nsVideoFrame::nsVideoFrame(nsStyleContext* aContext) :
+  nsContainerFrame(aContext)
+{
+}
+
+nsVideoFrame::~nsVideoFrame()
+{
+}
+
+NS_INTERFACE_MAP_BEGIN(nsVideoFrame)
+  NS_INTERFACE_MAP_ENTRY(nsIAnonymousContentCreator)
+#ifdef NS_DEBUG
+  NS_INTERFACE_MAP_ENTRY(nsIFrameDebug)
+#endif
+NS_INTERFACE_MAP_END_INHERITING(nsContainerFrame)
+
+NS_IMETHODIMP_(nsrefcnt) 
+nsVideoFrame::AddRef(void)
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP_(nsrefcnt)
+nsVideoFrame::Release(void)
+{
+    return NS_OK;
+}
+
+nsresult
+nsVideoFrame::CreateAnonymousContent(nsTArray<nsIContent*>& aElements)
+{
+  // Set up "videocontrols" XUL element which will be XBL-bound to the
+  // actual controls.
+  nsPresContext* presContext = PresContext();
+  nsNodeInfoManager *nodeInfoManager =
+    presContext->Document()->NodeInfoManager();
+  nsCOMPtr<nsINodeInfo> nodeInfo;
+  nsresult rv = nodeInfoManager->GetNodeInfo(nsGkAtoms::videocontrols, nsnull,
+                                             kNameSpaceID_XUL, getter_AddRefs(nodeInfo));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = NS_NewElement(getter_AddRefs(mVideoControls), kNameSpaceID_XUL, nodeInfo, PR_FALSE);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (!aElements.AppendElement(mVideoControls))
+    return NS_ERROR_OUT_OF_MEMORY;
+  return NS_OK;
+}
+
+void
+nsVideoFrame::Destroy()
+{
+  nsContentUtils::DestroyAnonymousContent(&mVideoControls);
+  nsContainerFrame::Destroy();
+}
+
+PRBool
+nsVideoFrame::IsLeaf() const
+{
+  return PR_TRUE;
+}
+
+void
+nsVideoFrame::PaintVideo(nsIRenderingContext& aRenderingContext,
+                         const nsRect& aDirtyRect, nsPoint aPt) 
+{
+  gfxContext* ctx = static_cast<gfxContext*>(aRenderingContext.GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT));
+  // TODO: handle the situation where the frame size is not the same as the
+  // video size, by drawing to the largest rectangle that fits in the frame
+  // whose aspect ratio equals the video's aspect ratio
+  nsRect area = GetContentRect() - GetPosition() + aPt;
+  nsPresContext* presContext = PresContext();
+  gfxRect r = gfxRect(presContext->AppUnitsToGfxUnits(area.x), 
+                      presContext->AppUnitsToGfxUnits(area.y), 
+                      presContext->AppUnitsToGfxUnits(area.width), 
+                      presContext->AppUnitsToGfxUnits(area.height));
+
+  nsHTMLVideoElement* element = static_cast<nsHTMLVideoElement*>(GetContent());
+  element->Paint(ctx, r);
+}
+
+NS_IMETHODIMP
+nsVideoFrame::Reflow(nsPresContext*           aPresContext,
+                     nsHTMLReflowMetrics&     aMetrics,
+                     const nsHTMLReflowState& aReflowState,
+                     nsReflowStatus&          aStatus)
+{
+  DO_GLOBAL_REFLOW_COUNT("nsVideoFrame");
+  DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
+  NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
+                  ("enter nsVideoFrame::Reflow: availSize=%d,%d",
+                  aReflowState.availableWidth, aReflowState.availableHeight));
+
+  NS_PRECONDITION(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow");
+
+  aStatus = NS_FRAME_COMPLETE;
+
+  aMetrics.width = aReflowState.ComputedWidth();
+  aMetrics.height = aReflowState.ComputedHeight();
+
+  // stash this away so we can compute our inner area later
+  mBorderPadding   = aReflowState.mComputedBorderPadding;
+
+  aMetrics.width += mBorderPadding.left + mBorderPadding.right;
+  aMetrics.height += mBorderPadding.top + mBorderPadding.bottom;
+
+  nsIFrame* child = mFrames.FirstChild();
+  if (child) {
+    NS_ASSERTION(child->GetContent() == mVideoControls,
+                 "What is this child doing here?");
+    nsBoxLayoutState boxState(PresContext(), aReflowState.rendContext);
+    nsBoxFrame::LayoutChildAt(boxState, child,
+                              nsRect(mBorderPadding.left, mBorderPadding.right,
+                                     aReflowState.ComputedWidth(), aReflowState.ComputedHeight()));
+  }
+
+  aMetrics.mOverflowArea.SetRect(0, 0, aMetrics.width, aMetrics.height);
+
+  FinishAndStoreOverflow(&aMetrics);
+
+  if (mRect.width != aMetrics.width || mRect.height != aMetrics.height) {
+    Invalidate(nsRect(0, 0, mRect.width, mRect.height), PR_FALSE);
+  }
+
+  NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
+                  ("exit nsVideoFrame::Reflow: size=%d,%d",
+                  aMetrics.width, aMetrics.height));
+  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
+
+  return NS_OK;
+}
+
+static void PaintVideo(nsIFrame* aFrame, nsIRenderingContext* aCtx,
+                        const nsRect& aDirtyRect, nsPoint aPt)
+{
+#if 0
+  double start = double(PR_IntervalToMilliseconds(PR_IntervalNow()))/1000.0;
+#endif
+
+  static_cast<nsVideoFrame*>(aFrame)->PaintVideo(*aCtx, aDirtyRect, aPt);
+#if 0
+  double end = double(PR_IntervalToMilliseconds(PR_IntervalNow()))/1000.0;
+  printf("PaintVideo: %f\n", (float)end - (float)start);
+
+#endif
+}
+
+NS_IMETHODIMP
+nsVideoFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
+                               const nsRect&           aDirtyRect,
+                               const nsDisplayListSet& aLists)
+{
+  if (!IsVisibleForPainting(aBuilder))
+    return NS_OK;
+
+  DO_GLOBAL_REFLOW_COUNT_DSP("nsVideoFrame");
+
+  nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = aLists.Content()->AppendNewToTop(new (aBuilder) nsDisplayGeneric(this, ::PaintVideo, "Video"));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (mFrames.FirstChild()) {
+    rv = mFrames.FirstChild()->BuildDisplayListForStackingContext(aBuilder, aDirtyRect, aLists.Content());
+  }
+  return rv;
+}
+
+nsIAtom*
+nsVideoFrame::GetType() const
+{
+  return nsGkAtoms::HTMLVideoFrame;
+}
+
+#ifdef ACCESSIBILITY
+NS_IMETHODIMP
+nsVideoFrame::GetAccessible(nsIAccessible** aAccessible)
+{
+  return NS_ERROR_FAILURE;
+}
+#endif
+
+#ifdef DEBUG
+NS_IMETHODIMP
+nsVideoFrame::GetFrameName(nsAString& aResult) const
+{
+  return MakeFrameName(NS_LITERAL_STRING("HTMLVideo"), aResult);
+}
+#endif
+
+nsSize nsVideoFrame::ComputeSize(nsIRenderingContext *aRenderingContext,
+                                     nsSize aCBSize, 
+                                     nscoord aAvailableWidth,
+                                     nsSize aMargin, 
+                                     nsSize aBorder, 
+                                     nsSize aPadding,
+                                     PRBool aShrinkWrap)
+{
+  nsSize size = GetVideoSize();
+
+  IntrinsicSize intrinsicSize;
+  intrinsicSize.width.SetCoordValue(size.width);
+  intrinsicSize.height.SetCoordValue(size.height);
+
+  nsSize& intrinsicRatio = size; // won't actually be used
+
+  return nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(aRenderingContext, 
+                                                           this,
+                                                           intrinsicSize,
+                                                           intrinsicRatio,
+                                                           aCBSize, 
+                                                           aMargin, 
+                                                           aBorder, 
+                                                           aPadding);
+}
+
+nscoord nsVideoFrame::GetMinWidth(nsIRenderingContext *aRenderingContext)
+{
+  // XXX The caller doesn't account for constraints of the height,
+  // min-height, and max-height properties.
+  nscoord result = GetVideoSize().width;
+  DISPLAY_MIN_WIDTH(this, result);
+  return result;
+}
+
+nscoord nsVideoFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext)
+{
+  // XXX The caller doesn't account for constraints of the height,
+  // min-height, and max-height properties.
+  nscoord result = GetVideoSize().width;
+  DISPLAY_PREF_WIDTH(this, result);
+  return result;
+}
+
+nsSize nsVideoFrame::GetIntrinsicRatio()
+{
+  return GetVideoSize();
+}
+
+nsSize nsVideoFrame::GetVideoSize()
+{
+  // Defaulting size to 300x150 if no size given.
+  nsIntSize size(300,150);
+
+  nsHTMLVideoElement* element = static_cast<nsHTMLVideoElement*>(GetContent());
+  if (element) {
+    nsresult rv;
+
+    size = element->GetVideoSize(size);
+    if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::width)) {
+      PRInt32 width = -1;
+      rv = element->GetWidth(&width);
+      if (NS_SUCCEEDED(rv)) {
+        size.width = width;
+      }
+    }
+    if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::height)) {
+      PRInt32 height = -1;
+      rv = element->GetHeight(&height);
+      if (NS_SUCCEEDED(rv)) {
+        size.height = height;
+      }
+    }
+  }
+
+  return nsSize(nsPresContext::CSSPixelsToAppUnits(size.width), 
+                nsPresContext::CSSPixelsToAppUnits(size.height));
+}
+
+NS_IMETHODIMP nsVideoFrame::Freeze()
+{
+  nsHTMLVideoElement* element = static_cast<nsHTMLVideoElement*>(GetContent());
+  element->Pause();
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsVideoFrame::Thaw()
+{
+  nsHTMLVideoElement* element = static_cast<nsHTMLVideoElement*>(GetContent());
+  element->Play();
+  return NS_OK;
+}
+
new file mode 100644
--- /dev/null
+++ b/layout/generic/nsVideoFrame.h
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** 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 code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Double <chris.double@double.co.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 ***** */
+
+/* rendering object for the HTML <video> element */
+
+#ifndef nsVideoFrame_h___
+#define nsVideoFrame_h___
+
+#include "nsContainerFrame.h"
+#include "nsString.h"
+#include "nsAString.h"
+#include "nsPresContext.h"
+#include "nsIIOService.h"
+#include "nsITimer.h"
+#include "nsTArray.h"
+#include "nsIAnonymousContentCreator.h"
+
+nsIFrame* NS_NewVideoFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
+
+class nsVideoFrame : public nsContainerFrame, public nsIAnonymousContentCreator
+{
+public:
+  nsVideoFrame(nsStyleContext* aContext);
+
+  NS_DECL_ISUPPORTS
+  
+  NS_IMETHOD BuildDisplayList(nsDisplayListBuilder*   aBuilder,
+                              const nsRect&           aDirtyRect,
+                              const nsDisplayListSet& aLists);
+
+  void PaintVideo(nsIRenderingContext& aRenderingContext,
+                   const nsRect& aDirtyRect, nsPoint aPt);
+                              
+  /* get the size of the video's display */
+  nsSize GetVideoSize();
+  virtual nsSize GetIntrinsicRatio();
+  virtual nsSize ComputeSize(nsIRenderingContext *aRenderingContext,
+                             nsSize aCBSize, nscoord aAvailableWidth,
+                             nsSize aMargin, nsSize aBorder, nsSize aPadding,
+                             PRBool aShrinkWrap);
+  virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext);
+  virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext);
+  virtual void Destroy();
+  virtual PRBool IsLeaf() const;
+
+  NS_IMETHOD Reflow(nsPresContext*          aPresContext,
+                    nsHTMLReflowMetrics&     aDesiredSize,
+                    const nsHTMLReflowState& aReflowState,
+                    nsReflowStatus&          aStatus);
+
+  NS_IMETHOD Freeze();
+  NS_IMETHOD Thaw();
+
+#ifdef ACCESSIBILITY
+  NS_IMETHOD GetAccessible(nsIAccessible** aAccessible);
+#endif
+
+  virtual nsIAtom* GetType() const;
+
+  virtual PRBool IsFrameOfType(PRUint32 aFlags) const
+  {
+    return nsSplittableFrame::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced));
+  }
+  
+  virtual nsresult CreateAnonymousContent(nsTArray<nsIContent*>& aElements);
+
+#ifdef DEBUG
+  NS_IMETHOD GetFrameName(nsAString& aResult) const;
+#endif
+
+protected:
+  virtual ~nsVideoFrame();
+
+  nsMargin mBorderPadding;
+  nsCOMPtr<nsIContent> mVideoControls;
+};
+
+#endif /* nsVideoFrame_h___ */
--- a/layout/style/forms.css
+++ b/layout/style/forms.css
@@ -589,16 +589,44 @@ input[type="file"] > input[type="text"] 
 @media print {
   input, textarea, select, button {
     -moz-user-input: none !important;
   }
 
   input[type="file"] { height: 2em; }
 }
 
+video {
+  background-color: black;
+}
+
+video > xul|videocontrols {
+  display: none;
+}
+video[controls] > xul|videocontrols {
+  display: -moz-box;
+  -moz-box-orient: vertical;
+  -moz-binding: url("chrome://global/content/bindings/videocontrols.xml#videoControls");
+}
+
+video[controls] > xul|videocontrols xul|button.controlbar {
+  visibility: hidden;
+}
+
+video[controls] > xul|videocontrols xul|button.centerplay {
+  visibility: visible;
+}
+video[controls] > xul|videocontrols.playing xul|button.centerplay {
+  visibility: hidden;
+}
+
+video[controls]:hover > xul|videocontrols.playing xul|button.controlbar {
+  visibility: visible;
+}
+
 %if OSARCH==OS2
 input {
   font: medium serif; font-family: inherit
 }
 
 select {
   font: medium serif; font-family: inherit
 }
--- a/parser/htmlparser/public/nsHTMLTagList.h
+++ b/parser/htmlparser/public/nsHTMLTagList.h
@@ -64,16 +64,19 @@
 
  ******/
 HTML_TAG(a, Anchor)
 HTML_TAG(abbr, Span)
 HTML_TAG(acronym, Span)
 HTML_TAG(address, Span)
 HTML_TAG(applet, SharedObject)
 HTML_TAG(area, Area)
+#if defined(MOZ_MEDIA)
+HTML_TAG(audio, Audio)
+#endif
 HTML_TAG(b, Span)
 HTML_TAG(base, Shared)
 HTML_TAG(basefont, Shared)
 HTML_TAG(bdo, Span)
 HTML_TAG(bgsound, Span)
 HTML_TAG(big, Span)
 HTML_TAG(blink, Span)
 HTML_TAG(blockquote, Shared)
@@ -142,16 +145,19 @@ HTML_TAG(param, Shared)
 HTML_TAG(plaintext, Span)
 HTML_TAG(pre, Pre)
 HTML_TAG(q, Shared)
 HTML_TAG(s, Span)
 HTML_TAG(samp, Span)
 HTML_TAG(script, Script)
 HTML_TAG(select, Select)
 HTML_TAG(small, Span)
+#if defined(MOZ_MEDIA)
+HTML_TAG(source, Source)
+#endif
 HTML_TAG(spacer, Shared)
 HTML_TAG(span, Span)
 HTML_TAG(strike, Span)
 HTML_TAG(strong, Span)
 HTML_TAG(style, Style)
 HTML_TAG(sub, Span)
 HTML_TAG(sup, Span)
 HTML_TAG(table, Table)
@@ -162,16 +168,19 @@ HTML_TAG(tfoot, TableSection)
 HTML_TAG(th, TableCell)
 HTML_TAG(thead, TableSection)
 HTML_TAG(title, Title)
 HTML_TAG(tr, TableRow)
 HTML_TAG(tt, Span)
 HTML_TAG(u, Span)
 HTML_TAG(ul, SharedList)
 HTML_TAG(var, Span)
+#if defined(MOZ_MEDIA)
+HTML_TAG(video, Video)
+#endif
 HTML_TAG(wbr, Shared)
 HTML_TAG(xmp, Span)
 
 
 /* These are not for tags. But they will be included in the nsHTMLTag
    enum anyway */
 
 HTML_OTHER(text)
--- a/parser/htmlparser/src/nsElementTable.cpp
+++ b/parser/htmlparser/src/nsElementTable.cpp
@@ -72,16 +72,19 @@ DECL_TAG_LIST(gOptgroupParents,{eHTMLTag
 DECL_TAG_LIST(gBodyParents,{eHTMLTag_html COMMA eHTMLTag_noframes})
 DECL_TAG_LIST(gColParents,{eHTMLTag_table COMMA eHTMLTag_colgroup})
 DECL_TAG_LIST(gFramesetParents,{eHTMLTag_html COMMA eHTMLTag_frameset})
 DECL_TAG_LIST(gLegendParents,{eHTMLTag_fieldset})
 DECL_TAG_LIST(gAreaParent,{eHTMLTag_map})
 DECL_TAG_LIST(gParamParents,{eHTMLTag_applet COMMA eHTMLTag_object})
 DECL_TAG_LIST(gTRParents,{eHTMLTag_tbody COMMA eHTMLTag_tfoot COMMA eHTMLTag_thead COMMA eHTMLTag_table})
 DECL_TAG_LIST(gTREndParents,{eHTMLTag_tbody COMMA eHTMLTag_tfoot COMMA eHTMLTag_thead COMMA eHTMLTag_table COMMA eHTMLTag_applet})
+#ifdef MOZ_MEDIA
+DECL_TAG_LIST(gSourceParents,{eHTMLTag_video COMMA eHTMLTag_audio})
+#endif
 
 //*********************************************************************************************
 //  Next, define the set of taglists for tags with special kids...
 //*********************************************************************************************
 
 DECL_TAG_LIST(gContainsText,{eHTMLTag_text COMMA eHTMLTag_newline COMMA eHTMLTag_whitespace COMMA eHTMLTag_entity})
 DECL_TAG_LIST(gUnknownKids,{eHTMLTag_html COMMA eHTMLTag_frameset})
 
@@ -116,17 +119,20 @@ DECL_TAG_LIST(gMapKids,{eHTMLTag_area})
 DECL_TAG_LIST(gPreKids,{eHTMLTag_hr COMMA eHTMLTag_center})  //note that CENTER is here for backward compatibility; it's not 4.0 spec.
 
 DECL_TAG_LIST(gTableKids,{eHTMLTag_caption COMMA eHTMLTag_col COMMA eHTMLTag_colgroup COMMA eHTMLTag_form COMMA  eHTMLTag_thead COMMA eHTMLTag_tbody COMMA eHTMLTag_tfoot COMMA eHTMLTag_script})// Removed INPUT - Ref. Bug 20087, 25382
   
 DECL_TAG_LIST(gTableElemKids,{eHTMLTag_form COMMA eHTMLTag_noscript COMMA eHTMLTag_script COMMA eHTMLTag_td COMMA eHTMLTag_th COMMA eHTMLTag_tr})
 DECL_TAG_LIST(gTRKids,{eHTMLTag_td COMMA eHTMLTag_th COMMA eHTMLTag_form COMMA eHTMLTag_script})// Removed INPUT - Ref. Bug 20087, 25382 |  Removed MAP to fix 58942
 DECL_TAG_LIST(gTBodyKids,{eHTMLTag_tr COMMA eHTMLTag_form}) // Removed INPUT - Ref. Bug 20087, 25382
 DECL_TAG_LIST(gULKids,{eHTMLTag_li COMMA eHTMLTag_p})
-
+#ifdef MOZ_MEDIA
+DECL_TAG_LIST(gVideoKids,{eHTMLTag_source})
+DECL_TAG_LIST(gAudioKids,{eHTMLTag_source})
+#endif
 
 //*********************************************************************************************
 // The following tag lists are used to define common set of root notes for the HTML elements...
 //*********************************************************************************************
 
 DECL_TAG_LIST(gRootTags,{eHTMLTag_body COMMA eHTMLTag_td COMMA eHTMLTag_table COMMA eHTMLTag_applet COMMA eHTMLTag_select}) // Added SELECT to fix bug 98645
 DECL_TAG_LIST(gTableRootTags,{eHTMLTag_applet COMMA eHTMLTag_body COMMA eHTMLTag_dl COMMA eHTMLTag_ol COMMA eHTMLTag_td COMMA eHTMLTag_th})
 DECL_TAG_LIST(gHTMLRootTags,{eHTMLTag_unknown})
@@ -156,17 +162,16 @@ DECL_TAG_LIST(gHeadingTags,{eHTMLTag_h1 
 
 DECL_TAG_LIST(gTableCloseTags,{eHTMLTag_td COMMA eHTMLTag_tr COMMA eHTMLTag_th COMMA eHTMLTag_tbody COMMA eHTMLTag_thead COMMA eHTMLTag_tfoot})
 DECL_TAG_LIST(gTRCloseTags,{eHTMLTag_tr COMMA eHTMLTag_td COMMA eHTMLTag_th})
 DECL_TAG_LIST(gTDCloseTags,{eHTMLTag_td COMMA eHTMLTag_th})
 DECL_TAG_LIST(gDTCloseTags,{eHTMLTag_p COMMA eHTMLTag_dd COMMA eHTMLTag_dt})
 DECL_TAG_LIST(gULCloseTags,{eHTMLTag_li})
 DECL_TAG_LIST(gULAutoClose,{eHTMLTag_p COMMA eHTMLTag_ul}) //fix bug 50261..
 
-
 DECL_TAG_LIST(gExcludableParents,{eHTMLTag_pre}) // Ref Bug 22913
 DECL_TAG_LIST(gCaptionExcludableParents,{eHTMLTag_td}) //Ref Bug 26488
 
 //*********************************************************************************************
 //Lastly, bind tags with their rules, their special parents and special kids.
 //*********************************************************************************************
 
 
@@ -249,16 +254,28 @@ const nsHTMLElement gHTMLElements[] = {
     /*req-parent excl-parent*/          eHTMLTag_unknown,eHTMLTag_unknown,
     /*rootnodes,endrootnodes*/          &gAreaParent,&gRootTags,
     /*autoclose starttags and endtags*/ 0,0,0,0,
     /*parent,incl,exclgroups*/          kNone, kInlineEntity, kSelf,
     /*special props, prop-range*/       kNonContainer,kDefaultPropRange,
     /*special parents,kids,skip*/       &gAreaParent,0,eHTMLTag_unknown,
     /*contain-func*/                    0
   },
+#if defined(MOZ_MEDIA)
+  {
+    /*tag*/                             eHTMLTag_audio,
+    /*req-parent excl-parent*/          eHTMLTag_unknown,eHTMLTag_unknown,
+    /*rootnodes,endrootnodes*/          &gRootTags,&gRootTags,
+    /*autoclose starttags and endtags*/ 0, 0, 0,0,
+    /*parent,incl,exclgroups*/          kSpecial, (kFlowEntity|kSelf), kNone,
+    /*special props, prop-range*/       0,kDefaultPropRange,
+    /*special parents,kids,skip*/       0,&gAudioKids,eHTMLTag_unknown,
+    /*contain-func*/                    0
+  },
+#endif
   {
     /*tag*/                             eHTMLTag_b,
     /*req-parent excl-parent*/          eHTMLTag_unknown,eHTMLTag_unknown,
     /*rootnodes,endrootnodes*/          &gRootTags,&gRootTags,
     /*autoclose starttags and endtags*/ 0,0,0,0,
     /*parent,incl,exclgroups*/          kFontStyle, (kInlineEntity|kSelf), kNone,
     /*special props, prop-range*/       0, kDefaultPropRange,
     /*special parents,kids,skip*/       0,0,eHTMLTag_unknown,
@@ -1030,16 +1047,28 @@ const nsHTMLElement gHTMLElements[] = {
     /*req-parent excl-parent*/          eHTMLTag_unknown,eHTMLTag_unknown,
     /*rootnodes,endrootnodes*/          &gRootTags,&gRootTags,
     /*autoclose starttags and endtags*/ 0,0,0,0,
     /*parent,incl,exclgroups*/          kFontStyle, (kSelf|kInlineEntity), kNone,
     /*special props, prop-range*/       0, kDefaultPropRange,
     /*special parents,kids,skip*/       0,0,eHTMLTag_unknown,
     /*contain-func*/                    0
   },
+#if defined(MOZ_MEDIA)
+  {
+    /*tag*/                             eHTMLTag_source,
+    /*req-parent excl-parent*/          eHTMLTag_video,eHTMLTag_unknown,
+    /*rootnodes,endrootnodes*/          &gSourceParents,&gSourceParents,
+    /*autoclose starttags and endtags*/ &gPAutoClose, 0, 0,0,
+    /*parent,incl,exclgroups*/          kNone, kNone, kNone,
+    /*special props, prop-range*/       kNonContainer,kNoPropRange,
+    /*special parents,kids,skip*/       &gSourceParents,0,eHTMLTag_unknown,
+    /*contain-func*/                    0
+  },
+#endif
   {
     
     /*tag*/                             eHTMLTag_spacer,
     /*req-parent excl-parent*/          eHTMLTag_unknown,eHTMLTag_unknown,
     /*rootnodes,endrootnodes*/          &gRootTags,&gRootTags,
     /*autoclose starttags and endtags*/ 0,0,0,0,
     /*parent,incl,exclgroups*/          kExtensions, kNone, kNone,
     /*special props, prop-range*/       kNonContainer,kDefaultPropRange,
@@ -1239,16 +1268,28 @@ const nsHTMLElement gHTMLElements[] = {
     /*req-parent excl-parent*/          eHTMLTag_unknown,eHTMLTag_unknown,
     /*rootnodes,endrootnodes*/          &gRootTags,&gRootTags,
     /*autoclose starttags and endtags*/ 0,0,0,0,
     /*parent,incl,exclgroups*/          kPhrase, (kSelf|kInlineEntity), kNone,
     /*special props, prop-range*/       0,kDefaultPropRange,
     /*special parents,kids,skip*/       0,0,eHTMLTag_unknown,
     /*contain-func*/                    0
   },
+#if defined(MOZ_MEDIA)
+  {
+    /*tag*/                             eHTMLTag_video,
+    /*req-parent excl-parent*/          eHTMLTag_unknown,eHTMLTag_unknown,
+    /*rootnodes,endrootnodes*/          &gRootTags,&gRootTags,
+    /*autoclose starttags and endtags*/ 0, 0, 0,0,
+    /*parent,incl,exclgroups*/          kSpecial, (kFlowEntity|kSelf), kNone,
+    /*special props, prop-range*/       0,kDefaultPropRange,
+    /*special parents,kids,skip*/       0,&gVideoKids,eHTMLTag_unknown,
+    /*contain-func*/                    0
+  },
+#endif
   {
     /*tag*/                             eHTMLTag_wbr,
     /*req-parent excl-parent*/          eHTMLTag_unknown,eHTMLTag_unknown,
     /*rootnodes,endrootnodes*/          &gRootTags,&gRootTags,
     /*autoclose starttags and endtags*/ 0,0,0,0,
     /*parent,incl,exclgroups*/          kExtensions, kNone, kNone,
     /*special props, prop-range*/       kNonContainer|kRequiresBody,kNoPropRange,
     /*special parents,kids,skip*/       0,0,eHTMLTag_unknown,
--- a/parser/htmlparser/src/nsHTMLTags.cpp
+++ b/parser/htmlparser/src/nsHTMLTags.cpp
@@ -52,16 +52,20 @@ static const PRUnichar sHTMLTagUnicodeNa
 static const PRUnichar sHTMLTagUnicodeName_acronym[] =
   {'a', 'c', 'r', 'o', 'n', 'y', 'm', '\0'};
 static const PRUnichar sHTMLTagUnicodeName_address[] =
   {'a', 'd', 'd', 'r', 'e', 's', 's', '\0'};
 static const PRUnichar sHTMLTagUnicodeName_applet[] =
   {'a', 'p', 'p', 'l', 'e', 't', '\0'};
 static const PRUnichar sHTMLTagUnicodeName_area[] =
   {'a', 'r', 'e', 'a', '\0'};
+#if defined(MOZ_MEDIA)
+static const PRUnichar sHTMLTagUnicodeName_audio[] =
+  {'a', 'u', 'd', 'i', 'o', '\0'};
+#endif
 static const PRUnichar sHTMLTagUnicodeName_b[] =
   {'b', '\0'};
 static const PRUnichar sHTMLTagUnicodeName_base[] =
   {'b', 'a', 's', 'e', '\0'};
 static const PRUnichar sHTMLTagUnicodeName_basefont[] =
   {'b', 'a', 's', 'e', 'f', 'o', 'n', 't', '\0'};
 static const PRUnichar sHTMLTagUnicodeName_bdo[] =
   {'b', 'd', 'o', '\0'};
@@ -210,16 +214,20 @@ static const PRUnichar sHTMLTagUnicodeNa
 static const PRUnichar sHTMLTagUnicodeName_samp[] =
   {'s', 'a', 'm', 'p', '\0'};
 static const PRUnichar sHTMLTagUnicodeName_script[] =
   {'s', 'c', 'r', 'i', 'p', 't', '\0'};
 static const PRUnichar sHTMLTagUnicodeName_select[] =
   {'s', 'e', 'l', 'e', 'c', 't', '\0'};
 static const PRUnichar sHTMLTagUnicodeName_small[] =
   {'s', 'm', 'a', 'l', 'l', '\0'};
+#if defined(MOZ_MEDIA)
+static const PRUnichar sHTMLTagUnicodeName_source[] =
+  {'s', 'o', 'u', 'r', 'c', 'e', '\0'};
+#endif
 static const PRUnichar sHTMLTagUnicodeName_spacer[] =
   {'s', 'p', 'a', 'c', 'e', 'r', '\0'};
 static const PRUnichar sHTMLTagUnicodeName_span[] =
   {'s', 'p', 'a', 'n', '\0'};
 static const PRUnichar sHTMLTagUnicodeName_strike[] =
   {'s', 't', 'r', 'i', 'k', 'e', '\0'};
 static const PRUnichar sHTMLTagUnicodeName_strong[] =
   {'s', 't', 'r', 'o', 'n', 'g', '\0'};
@@ -250,16 +258,20 @@ static const PRUnichar sHTMLTagUnicodeNa
 static const PRUnichar sHTMLTagUnicodeName_tt[] =
   {'t', 't', '\0'};
 static const PRUnichar sHTMLTagUnicodeName_u[] =
   {'u', '\0'};
 static const PRUnichar sHTMLTagUnicodeName_ul[] =
   {'u', 'l', '\0'};
 static const PRUnichar sHTMLTagUnicodeName_var[] =
   {'v', 'a', 'r', '\0'};
+#if defined(MOZ_MEDIA)
+static const PRUnichar sHTMLTagUnicodeName_video[] =
+  {'v', 'i', 'd', 'e', 'o', '\0'};
+#endif
 static const PRUnichar sHTMLTagUnicodeName_wbr[] =
   {'w', 'b', 'r', '\0'};
 static const PRUnichar sHTMLTagUnicodeName_xmp[] =
   {'x', 'm', 'p', '\0'};
 
 // static array of unicode tag names
 #define HTML_TAG(_tag, _classname) sHTMLTagUnicodeName_##_tag,
 #define HTML_OTHER(_tag)
--- a/toolkit/content/jar.mn
+++ b/toolkit/content/jar.mn
@@ -63,16 +63,17 @@ toolkit.jar:
 *+ content/global/bindings/spinbuttons.xml     (widgets/spinbuttons.xml)
 *+ content/global/bindings/stringbundle.xml    (widgets/stringbundle.xml)
 *+ content/global/bindings/tabbox.xml          (widgets/tabbox.xml)
 *+ content/global/bindings/text.xml            (widgets/text.xml)
 *+ content/global/bindings/textbox.xml         (widgets/textbox.xml)
 *+ content/global/bindings/toolbar.xml         (widgets/toolbar.xml)
 *+ content/global/bindings/toolbarbutton.xml   (widgets/toolbarbutton.xml)
 *+ content/global/bindings/tree.xml            (widgets/tree.xml)
+*+ content/global/bindings/videocontrols.xml   (widgets/videocontrols.xml)
 *+ content/global/bindings/wizard.xml          (widgets/wizard.xml)
 *+ content/global/bindings/findbar.xml         (widgets/findbar.xml)
 #ifdef XP_MACOSX
 *  content/global/macWindowMenu.js             (macWindowMenu.js)
 #endif
 #ifdef MOZ_SVG
    content/global/svg/svgBindings.xml          (/layout/svg/base/src/resources/content/svgBindings.xml)
 #endif
new file mode 100644
--- /dev/null
+++ b/toolkit/content/widgets/videocontrols.xml
@@ -0,0 +1,271 @@
+<?xml version="1.0"?>
+
+<!-- 
+     SVG Icons from the BSD Licensed BlueSphere Icon Theme: 
+     http://svgicons.sourceforge.net/
+-->
+<bindings id="videoContolBindings"
+   xmlns="http://www.mozilla.org/xbl"
+   xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+   xmlns:xbl="http://www.mozilla.org/xbl"
+   xmlns:svg="http://www.w3.org/2000/svg">
+
+  <binding id="videoControls">
+    <content>
+      <xul:vbox flex="1"/>
+      <xul:hbox flex="0" pack="center">
+        <xul:button class="centerplay" flex="0" style="opacity:0.6;" vcattr="center-play" label="Play">
+	  <svg:svg 
+	     width="32px" 
+	     height="32px" 
+	     viewBox="0 0 508 508" 
+	     xmlns="http://www.w3.org/2000/svg">
+	    <defs>
+	      <radialGradient 
+		 cx="220"
+		 cy="220"
+		 r="151"
+		 fx="220"
+		 fy="220"
+		 gradientUnits="userSpaceOnUse"
+		 style="stroke:#000000;stroke-width:1;">
+		<stop
+		   offset="0"
+		   style="stop-color:#73ffff;stroke:#000000;stroke-width:1;" />
+		<stop
+		   offset="0.28"
+		   style="stop-color:#2EA6B9;stroke:#000000;stroke-width:1;" />
+		<stop
+		   offset="1"
+		   style="stop-color:#006b8b;stroke:#000000;stroke-width:1;" />
+	      </radialGradient>
+	      <linearGradient
+		 id="gradient"
+		 x1="0.380952"
+		 y1="0.0859375"
+		 x2="-0.111111"
+		 y2="1.00781"
+		 gradientUnits="objectBoundingBox"
+		 spreadMethod="pad" />
+	    </defs>
+	    <g transform="translate(24,-1.6)">
+	      <path
+		 style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#a4c9ee;stroke-width:10.824;stroke-linejoin:round;stroke-opacity:0.701961;"
+		 d="M 338.593 175.32 L 435.492 261.836 L 339.257 355.345 L 338.593 175.32 z "
+		 transform="matrix(1.72603,0,0,1.94683,-397.314,-245.978)"
+		 />
+	      <path
+		 style="fill:url(#gradient);fill-opacity:0.992157;fill-rule:evenodd;stroke:#0c6671;stroke-width:9.60304;stroke-opacity:0.992157;"
+		 d="M 355.635 183.469 L 437.887 259.936 L 355.817 342.102 L 355.635 183.469 z "
+		 transform="matrix(1.67014,0,0,1.75639,-395.375,-194.413)"
+		 />
+	    </g>
+	  </svg:svg>
+	</xul:button>
+      </xul:hbox>
+      <xul:vbox flex="2" pack="end">
+        <xul:hbox flex="0" pack="center" style="opacity:0.6;">
+          <xul:button class="controlbar" flex="0" vcattr="pause" label="Pause">
+	    <svg:svg
+	       width="32px"
+	       height="32px"
+	       viewBox="0 0 508 508"
+	       xmlns="http://www.w3.org/2000/svg">
+	      <defs>
+		<radialGradient
+		   cx="220"
+		   cy="220"
+		   r="151"
+		   fx="220"
+		   fy="220"
+		   gradientUnits="userSpaceOnUse"
+		   style="stroke:#000000;stroke-width:1;">
+		  <stop
+		     offset="0"
+		     style="stop-color:#73ffff;stroke:#000000;stroke-width:1;" />
+		  <stop
+		     offset="0.28"
+		     style="stop-color:#2EA6B9;stroke:#000000;stroke-width:1;" />
+		  <stop
+		     offset="1"
+		     style="stop-color:#006b8b;stroke:#000000;stroke-width:1;" />
+		</radialGradient>
+		<linearGradient
+		   id="gradient"
+		   x1="0.506276"
+		   y1="0.046875"
+		   x2="0.506276"
+		   y2="0.984375"
+		   gradientUnits="objectBoundingBox"
+		   spreadMethod="pad" />
+	      </defs>
+	      <g transform="matrix(0,-1,1,0,-205,520)">
+		<rect
+		   style="fill-rule:evenodd;stroke:#a4c9ee;stroke-width:16;stroke-opacity:0.701961;"
+		   x="121"
+		   y="297"
+		   width="256"
+		   height="147" />
+		<rect
+		   style="fill:url(#gradient);fill-rule:evenodd;stroke:#0c6671;stroke-width:14;"
+		   x="135"
+		   y="308"
+		   width="232"
+		   height="125"/>
+	      </g>
+	      <g transform="matrix(0,-1,1,0,-22,520)">
+		<rect
+		   style="fill-rule:evenodd;stroke:#a4c9ee;stroke-width:16;stroke-opacity:0.701961;"
+		   x="121"
+		   y="297"
+		   width="256"
+		   height="147"/>
+		<rect
+		   style="fill:url(#gradient);fill-rule:evenodd;stroke:#0c6671;stroke-width:14;"
+		   x="135"
+		   y="308"
+		   width="232"
+		   height="125"/>
+	      </g>
+	    </svg:svg>
+	  </xul:button>
+          <xul:button class="controlbar" flex="0" vcattr="stop" label="Stop">
+	    <svg:svg
+	       width="32px"
+	       height="32px"
+	       viewBox="0 0 508 508"
+	       xmlns="http://www.w3.org/2000/svg">
+	      <defs>
+		<radialGradient
+		   cx="220"
+		   cy="220"
+		   r="151"
+		   fx="220"
+		   fy="220"
+		   gradientUnits="userSpaceOnUse"
+		   style="stroke:#000000;stroke-width:1;">
+		  <stop
+		     offset="0"
+		     style="stop-color:#73ffff;stroke:#000000;stroke-width:1;" />
+		  <stop
+		     offset="0.2809"
+		     style="stop-color:#2EA6B9;stroke:#000000;stroke-width:1;" />
+		  <stop
+		     offset="1"
+		     style="stop-color:#006b8b;stroke:#000000;stroke-width:1;" />
+		</radialGradient>
+		<linearGradient
+		   id="gradient"
+		   x1="0.506276"
+		   y1="0.046875"
+		   x2="0.506276"
+		   y2="0.984375"
+		   gradientUnits="objectBoundingBox"
+		   spreadMethod="pad" />
+	      </defs>
+	      <g transform="matrix(0,-1,1.5,0,-340,497)">
+		<rect
+		   style="fill-rule:evenodd;stroke:#a4c9ee;stroke-width:16;stroke-opacity:0.701961;"
+		   x="121"
+		   y="297"
+		   width="256"
+		   height="147"/>
+		<rect
+		   style="fill:url(#gradient);fill-rule:evenodd;stroke:#0c6671;stroke-width:14;"
+		   x="135"
+		   y="308"
+		   width="232"
+		   height="125"/>
+	      </g>
+	    </svg:svg>
+	  </xul:button>
+        </xul:hbox>
+      </xul:vbox>
+    </content>
+
+    <implementation implements="nsISecurityCheckedComponent">
+      <!-- nsISecurityCheckedComponent -->
+      <method name="canCreateWrapper">
+	<parameter name="aIID"/>
+	<body>
+	  return "AllAccess";
+	 </body>
+      </method>	
+
+      <method name="canCallMethod">
+	<parameter name="aIID"/>
+	<parameter name="aMethodName"/> 
+	<body>
+	  return "AllAccess";
+	 </body>
+      </method>	
+
+      <method name="canGetProperty">
+	<parameter name="aIID"/>
+	<parameter name="aPropertyName"/> 
+	<body>
+	  return "AllAccess";
+	 </body>
+      </method>	
+
+      <method name="canSetProperty">
+	<parameter name="aIID"/>
+	<parameter name="aPropertyName"/>
+	<body>
+	  return "AllAccess";
+	 </body>
+      </method>	
+
+      <method name="QueryInterface">
+	<parameter name="aIID"/>
+	<body>
+          <![CDATA[
+	  if(!iid.equals(Components.interfaces.nsISecurityCheckedComponent))
+	    throw Components.results.NS_ERROR_NO_INTERFACE;
+	  return this;
+         ]]>
+	 </body>
+      </method>	
+
+      <constructor>
+        this.init();
+      </constructor>
+
+      <method name="init">
+        <body>
+          <![CDATA[
+            var self = this;
+            var video = this.parentNode;
+
+            var centerPlay = document.getAnonymousElementByAttribute(this, "vcattr", "center-play");
+            video.addEventListener("play", function() {
+              self.setAttribute("class", "playing");
+            }, false);
+            video.addEventListener("pause", function() {
+              self.setAttribute("class", "");
+            }, false);
+            video.addEventListener("ended", function() {
+              self.setAttribute("class", "");
+            }, false);
+            
+            centerPlay.addEventListener("click", function() {
+              video.play(); 
+            }, false);
+
+            var pause = document.getAnonymousElementByAttribute(this, "vcattr", "pause");
+            pause.addEventListener("click", function() {
+              video.pause(); 
+            }, false);
+            var stop = document.getAnonymousElementByAttribute(this, "vcattr", "stop");
+            stop.addEventListener("click", function() {
+              video.pause();
+              video.currentTime = 0.0;
+            }, false);
+          ]]>
+        </body>
+      </method>
+      <destructor>
+      </destructor>      
+    </implementation>
+  </binding>
+</bindings>
--- a/toolkit/toolkit-makefiles.sh
+++ b/toolkit/toolkit-makefiles.sh
@@ -1129,8 +1129,17 @@ if [ "$MOZ_COMPONENTLIB" ]; then
   "
 else
   if [ "$MOZ_STATIC_COMPONENTS" -o "$MOZ_META_COMPONENTS" ]; then
     add_makefiles "
       modules/staticmod/Makefile
     "
   fi
 fi # MOZ_COMPONENTLIB
+
+if [ "$MOZ_MEDIA" ]; then
+ add_makefiles "
+   content/media/Makefile
+   content/media/video/Makefile
+   content/media/video/public/Makefile
+   content/media/video/src/Makefile
+ "
+fi
--- a/widget/public/nsGUIEvent.h
+++ b/widget/public/nsGUIEvent.h
@@ -100,16 +100,19 @@ class nsHashKey;
 #define NS_QUERYCARETRECT_EVENT           28
 #define NS_PAGETRANSITION_EVENT           29
 #ifdef MOZ_SVG
 #define NS_SVG_EVENT                      30
 #define NS_SVGZOOM_EVENT                  31
 #endif // MOZ_SVG
 #define NS_XUL_COMMAND_EVENT              32
 #define NS_QUERY_CONTENT_EVENT            33
+#ifdef MOZ_MEDIA
+#define NS_MEDIA_EVENT                    34
+#endif // MOZ_MEDIA
 
 // These flags are sort of a mess. They're sort of shared between event
 // listener flags and event flags, but only some of them. You've been
 // warned!
 #define NS_EVENT_FLAG_NONE                0x0000
 #define NS_EVENT_FLAG_TRUSTED             0x0001
 #define NS_EVENT_FLAG_BUBBLE              0x0002
 #define NS_EVENT_FLAG_CAPTURE             0x0004
@@ -353,16 +356,43 @@ class nsHashKey;
 // Query for the character rect of nth character. If there is no character at
 // the offset, the query will be failed. The offset of the result is relative
 // position from the top level widget.
 #define NS_QUERY_CHARACTER_RECT         (NS_QUERY_CONTENT_EVENT_START + 2)
 // Query for the caret rect of nth insertion point. The offset of the result is
 // relative position from the top level widget.
 #define NS_QUERY_CARET_RECT             (NS_QUERY_CONTENT_EVENT_START + 3)
 
+// Video events
+#ifdef MOZ_MEDIA
+#define NS_MEDIA_EVENT_START            3300
+#define NS_LOADSTART           (NS_MEDIA_EVENT_START)
+#define NS_PROGRESS            (NS_MEDIA_EVENT_START+1)
+#define NS_LOADEDMETADATA      (NS_MEDIA_EVENT_START+2)
+#define NS_LOADEDFIRSTFRAME    (NS_MEDIA_EVENT_START+3)
+#define NS_EMPTIED             (NS_MEDIA_EVENT_START+4)
+#define NS_STALLED             (NS_MEDIA_EVENT_START+5)
+#define NS_PLAY                (NS_MEDIA_EVENT_START+6)
+#define NS_PAUSE               (NS_MEDIA_EVENT_START+7)
+#define NS_WAITING             (NS_MEDIA_EVENT_START+8)
+#define NS_SEEKING             (NS_MEDIA_EVENT_START+9)
+#define NS_SEEKED              (NS_MEDIA_EVENT_START+10)
+#define NS_TIMEUPDATE          (NS_MEDIA_EVENT_START+11)
+#define NS_ENDED               (NS_MEDIA_EVENT_START+12)
+#define NS_DATAUNAVAILABLE     (NS_MEDIA_EVENT_START+13)
+#define NS_CANSHOWCURRENTFRAME (NS_MEDIA_EVENT_START+14)
+#define NS_CANPLAY             (NS_MEDIA_EVENT_START+15)
+#define NS_CANPLAYTHROUGH      (NS_MEDIA_EVENT_START+16)
+#define NS_RATECHANGE          (NS_MEDIA_EVENT_START+17)
+#define NS_DURATIONCHANGE      (NS_MEDIA_EVENT_START+18)
+#define NS_VOLUMECHANGE        (NS_MEDIA_EVENT_START+19)
+#define NS_MEDIA_ABORT         (NS_MEDIA_EVENT_START+20)
+#define NS_MEDIA_ERROR         (NS_MEDIA_EVENT_START+21)
+#endif // MOZ_MEDIA
+
 /**
  * Return status for event processors, nsEventStatus, is defined in
  * nsEvent.h.
  */
 
 /**
  * sizemode is an adjunct to widget size
  */