Bug 472878. Allow nsMediaDecoder::Invalidate to UpdateMediaSize on the element even if there is no frame for the element. r=doublec
authorRobert O'Callahan <robert@ocallahan.org>
Fri, 16 Jan 2009 20:57:37 +1300
changeset 23851 d198affa5573e02c9aae0303c5d639dc98373986
parent 23850 9f94446dd65a135be12fd16d28fb9df167c69e3e
child 23852 07c89c67e4b9ea468df439b748e7a4395a5412c3
push idunknown
push userunknown
push dateunknown
reviewersdoublec
bugs472878
milestone1.9.2a1pre
Bug 472878. Allow nsMediaDecoder::Invalidate to UpdateMediaSize on the element even if there is no frame for the element. r=doublec
content/html/content/public/nsHTMLAudioElement.h
content/html/content/public/nsHTMLVideoElement.h
content/html/content/src/nsHTMLAudioElement.cpp
content/html/content/src/nsHTMLMediaElement.cpp
content/html/content/src/nsHTMLVideoElement.cpp
content/media/video/public/nsMediaDecoder.h
content/media/video/public/nsOggDecoder.h
content/media/video/src/nsMediaDecoder.cpp
content/media/video/src/nsOggDecoder.cpp
layout/reftests/ogg-video/canvas-1a.html
layout/reftests/ogg-video/canvas-1b.html
layout/reftests/ogg-video/reftest.list
--- a/content/html/content/public/nsHTMLAudioElement.h
+++ b/content/html/content/public/nsHTMLAudioElement.h
@@ -62,14 +62,9 @@ public:
 
   // 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);
 };
--- a/content/html/content/public/nsHTMLVideoElement.h
+++ b/content/html/content/public/nsHTMLVideoElement.h
@@ -59,18 +59,13 @@ public:
 
   // 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);
 };
--- a/content/html/content/src/nsHTMLAudioElement.cpp
+++ b/content/html/content/src/nsHTMLAudioElement.cpp
@@ -85,30 +85,8 @@ 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);
-}
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -204,17 +204,16 @@ NS_IMETHODIMP nsHTMLMediaElement::GetNet
   *aNetworkState = mNetworkState;
 
   return NS_OK;
 }
 
 PRBool nsHTMLMediaElement::AbortExistingLoads()
 {
   if (mDecoder) {
-    mDecoder->ElementUnavailable();
     mDecoder->Shutdown();
     mDecoder = nsnull;
   }
 
   if (mBegun) {
     mBegun = PR_FALSE;
     mError = new nsHTMLMediaError(nsHTMLMediaError::MEDIA_ERR_ABORTED);
     DispatchProgressEvent(NS_LITERAL_STRING("abort"));
@@ -801,25 +800,25 @@ void nsHTMLMediaElement::ShutdownMediaTy
   }
 }
 
 PRBool nsHTMLMediaElement::CreateDecoder(const nsACString& aType)
 {
 #ifdef MOZ_OGG
   if (IsOggType(aType)) {
     mDecoder = new nsOggDecoder();
-    if (mDecoder && !mDecoder->Init()) {
+    if (mDecoder && !mDecoder->Init(this)) {
       mDecoder = nsnull;
     }
   }
 #endif
 #ifdef MOZ_WAVE
   if (IsWaveType(aType)) {
     mDecoder = new nsWaveDecoder();
-    if (mDecoder && !mDecoder->Init()) {
+    if (mDecoder && !mDecoder->Init(this)) {
       mDecoder = nsnull;
     }
   }
 #endif
   return mDecoder != nsnull;
 }
 
 nsresult nsHTMLMediaElement::InitializeDecoderForChannel(nsIChannel *aChannel,
@@ -827,17 +826,16 @@ nsresult nsHTMLMediaElement::InitializeD
 {
   nsCAutoString mimeType;
   aChannel->GetContentType(mimeType);
 
   if (!CreateDecoder(mimeType))
     return NS_ERROR_FAILURE;
 
   mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
-  mDecoder->ElementAvailable(this);
 
   return mDecoder->Load(nsnull, aChannel, aListener);
 }
 
 nsresult nsHTMLMediaElement::NewURIFromString(const nsAutoString& aURISpec, nsIURI** aURI)
 {
   NS_ENSURE_ARG_POINTER(aURI);
 
--- a/content/html/content/src/nsHTMLVideoElement.cpp
+++ b/content/html/content/src/nsHTMLVideoElement.cpp
@@ -108,30 +108,8 @@ nsHTMLVideoElement::nsHTMLVideoElement(n
 nsHTMLVideoElement::~nsHTMLVideoElement()
 {
 }
 
 nsIntSize nsHTMLVideoElement::GetVideoSize(nsIntSize aDefaultSize)
 {
   return mMediaSize.width == -1 && mMediaSize.height == -1 ? aDefaultSize : mMediaSize;
 }
-
-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)
-{
-  nsHTMLMediaElement::UnbindFromTree(aDeep, aNullParent);
-
-  if (mDecoder) 
-    mDecoder->ElementUnavailable();
-}
--- a/content/media/video/public/nsMediaDecoder.h
+++ b/content/media/video/public/nsMediaDecoder.h
@@ -64,17 +64,17 @@ class nsMediaDecoder : public nsIObserve
   virtual ~nsMediaDecoder();
 
   // 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();
+  virtual PRBool Init(nsHTMLMediaElement* aElement);
 
   // Return the current URI being played or downloaded.
   virtual void GetCurrentURI(nsIURI** aURI) = 0;
 
   // Return the principal of the current URI being played or downloaded.
   virtual nsIPrincipal* GetCurrentPrincipal() = 0;
 
   // Return the time position in the video stream being
@@ -150,22 +150,16 @@ class nsMediaDecoder : public nsIObserve
   virtual void SetTotalBytes(PRInt64 aBytes) = 0;
 
   // Set a flag indicating whether seeking is supported
   virtual void SetSeekable(PRBool aSeekable) = 0;
 
   // Return PR_TRUE if seeking is supported.
   virtual PRBool GetSeekable() = 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();
 
   // Fire progress events if needed according to the time and byte
   // constraints outlined in the specification. aTimer is PR_TRUE
   // if the method is called as a result of the progress timer rather
   // than the result of downloaded data.
   virtual void Progress(PRBool aTimer);
--- a/content/media/video/public/nsOggDecoder.h
+++ b/content/media/video/public/nsOggDecoder.h
@@ -288,17 +288,17 @@ class nsOggDecoder : public nsMediaDecod
     PLAY_STATE_PLAYING,
     PLAY_STATE_SEEKING,
     PLAY_STATE_ENDED,
     PLAY_STATE_SHUTDOWN
   };
 
   nsOggDecoder();
   ~nsOggDecoder();
-  PRBool Init();
+  virtual PRBool Init(nsHTMLMediaElement* aElement);
 
   // This method must be called by the owning object before that
   // object disposes of this decoder object.
   virtual void Shutdown();
   
   virtual float GetCurrentTime();
 
   virtual nsresult Load(nsIURI* aURI,
--- a/content/media/video/src/nsMediaDecoder.cpp
+++ b/content/media/video/src/nsMediaDecoder.cpp
@@ -82,61 +82,64 @@ nsMediaDecoder::~nsMediaDecoder()
 {
   if (mVideoUpdateLock) {
     PR_DestroyLock(mVideoUpdateLock);
     mVideoUpdateLock = nsnull;
   }
   MOZ_COUNT_DTOR(nsMediaDecoder);
 }
 
-PRBool nsMediaDecoder::Init()
+PRBool nsMediaDecoder::Init(nsHTMLMediaElement* aElement)
 {
+  mElement = aElement;
   mVideoUpdateLock = PR_NewLock();
 
   return mVideoUpdateLock != nsnull;
 }
 
 void nsMediaDecoder::Shutdown()
 {
   StopProgress();
-  ElementUnavailable();
+  mElement = nsnull;
 }
 
-
 nsresult nsMediaDecoder::InitLogger() 
 {
 #ifdef PR_LOGGING
   gVideoDecoderLog = PR_NewLogModule("nsMediaDecoder");
 #endif
   return NS_OK;
 }
 
 void nsMediaDecoder::Invalidate()
 {
   if (!mElement)
     return;
 
   nsIFrame* frame = mElement->GetPrimaryFrame();
-  if (!frame)
-    return;
   
   {
     nsAutoLock lock(mVideoUpdateLock);
     if (mSizeChanged) {
       mElement->UpdateMediaSize(nsIntSize(mRGBWidth, mRGBHeight));
       mSizeChanged = PR_FALSE;
-      nsPresContext* presContext = frame->PresContext();      
-      nsIPresShell *presShell = presContext->PresShell();
-      presShell->FrameNeedsReflow(frame, 
-                                  nsIPresShell::eStyleChange,
-                                  NS_FRAME_IS_DIRTY);
+      if (frame) {
+        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);
+
+  if (frame) {
+    nsRect r(nsPoint(0,0), frame->GetSize());
+    frame->Invalidate(r);
+  }
 }
 
 static void ProgressCallback(nsITimer* aTimer, void* aClosure)
 {
   nsMediaDecoder* decoder = static_cast<nsMediaDecoder*>(aClosure);
   decoder->Progress(PR_TRUE);
 }
 
@@ -250,18 +253,8 @@ void nsMediaDecoder::Paint(gfxContext* a
       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 nsMediaDecoder::ElementAvailable(nsHTMLMediaElement* anElement)
-{
-  mElement = anElement;
-}
-
-void nsMediaDecoder::ElementUnavailable()
-{
-  mElement = nsnull;
-}
-
--- a/content/media/video/src/nsOggDecoder.cpp
+++ b/content/media/video/src/nsOggDecoder.cpp
@@ -1204,20 +1204,20 @@ nsOggDecoder::nsOggDecoder() :
   mPlayState(PLAY_STATE_PAUSED),
   mNextState(PLAY_STATE_PAUSED),
   mResourceLoaded(PR_FALSE),
   mIgnoreProgressData(PR_FALSE)
 {
   MOZ_COUNT_CTOR(nsOggDecoder);
 }
 
-PRBool nsOggDecoder::Init() 
+PRBool nsOggDecoder::Init(nsHTMLMediaElement* aElement)
 {
   mMonitor = nsAutoMonitor::NewMonitor("media.decoder");
-  return mMonitor && nsMediaDecoder::Init();
+  return mMonitor && nsMediaDecoder::Init(aElement);
 }
 
 void nsOggDecoder::Shutdown() 
 {
   mShuttingDown = PR_TRUE;
 
   ChangeState(PLAY_STATE_SHUTDOWN);
   nsMediaDecoder::Shutdown();
new file mode 100644
--- /dev/null
+++ b/layout/reftests/ogg-video/canvas-1a.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<body>
+<canvas id="canvas" width="200" height="200"></canvas>
+<script>
+var video = document.createElement("video");
+video.src = "black140x100.ogv";
+video.load();
+function draw() {
+  var canvas = document.getElementById("canvas");
+  var ctx = canvas.getContext("2d");
+  ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
+  document.documentElement.removeAttribute("class");
+}
+video.addEventListener("loadeddata", draw, false);
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/ogg-video/canvas-1b.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<body>
+<canvas id="canvas" width="200" height="200"></canvas>
+<script>
+function draw() {
+  var video = document.getElementById("video");
+  var canvas = document.getElementById("canvas");
+  var ctx = canvas.getContext("2d");
+  ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
+  document.documentElement.removeAttribute("class");
+}
+</script>
+<video id="video" src="black140x100.ogv" onloadeddata="draw()" style="opacity:0"></video>
+</body>
+</html>
--- a/layout/reftests/ogg-video/reftest.list
+++ b/layout/reftests/ogg-video/reftest.list
@@ -1,8 +1,10 @@
 == aspect-ratio-1a.html aspect-ratio-1-ref.html
 == aspect-ratio-1b.html aspect-ratio-1-ref.html
 == aspect-ratio-2a.html aspect-ratio-2-ref.html
 == aspect-ratio-2b.html aspect-ratio-2-ref.html
 == basic-1.html basic-1-ref.html
+== canvas-1a.html basic-1-ref.html
+== canvas-1b.html basic-1-ref.html
 == empty-1a.html empty-1-ref.html
 == empty-1b.html empty-1-ref.html
 == zoomed-1.html zoomed-1-ref.html