Bug 1228601 - [Part3] Handle video rotation while building layer from nsVideoFrame.; r?mattwoodrow draft
authorKilik Kuo <kikuo@mozilla.com>
Mon, 09 May 2016 18:48:54 +0800
changeset 364794 40394df3d1b76b6e6d21b2996713695dffff4be5
parent 364793 3ea2145529e6484d0888abed20af374643a80dab
child 520388 8d0e63caa69428428e1d4df5d3da2db1aac1c4ed
push id17565
push userkikuo@mozilla.com
push dateMon, 09 May 2016 10:49:17 +0000
reviewersmattwoodrow
bugs1228601
milestone49.0a1
Bug 1228601 - [Part3] Handle video rotation while building layer from nsVideoFrame.; r?mattwoodrow MozReview-Commit-ID: JWZoZscAdvS
dom/html/HTMLVideoElement.cpp
layout/generic/nsVideoFrame.cpp
layout/generic/nsVideoFrame.h
--- a/dom/html/HTMLVideoElement.cpp
+++ b/dom/html/HTMLVideoElement.cpp
@@ -55,18 +55,33 @@ nsresult HTMLVideoElement::GetVideoSize(
   if (!mMediaInfo.HasVideo()) {
     return NS_ERROR_FAILURE;
   }
 
   if (mDisableVideo) {
     return NS_ERROR_FAILURE;
   }
 
-  size->height = mMediaInfo.mVideo.mDisplay.height;
-  size->width = mMediaInfo.mVideo.mDisplay.width;
+  layers::ImageContainer* container = GetImageContainer();
+  uint32_t rotationDeg = container ? container->GetRotationDegrees() : 0;
+  switch (rotationDeg) {
+    case 90:
+    case 270: {
+      size->width = mMediaInfo.mVideo.mDisplay.height;
+      size->height = mMediaInfo.mVideo.mDisplay.width;
+      break;
+    }
+    case 0:
+    case 180:
+    default: {
+      size->height = mMediaInfo.mVideo.mDisplay.height;
+      size->width = mMediaInfo.mVideo.mDisplay.width;
+      break;
+    }
+  }
   return NS_OK;
 }
 
 bool
 HTMLVideoElement::ParseAttribute(int32_t aNamespaceID,
                                  nsIAtom* aAttribute,
                                  const nsAString& aValue,
                                  nsAttrValue& aResult)
--- a/layout/generic/nsVideoFrame.cpp
+++ b/layout/generic/nsVideoFrame.cpp
@@ -149,16 +149,32 @@ nsVideoFrame::DestroyFrom(nsIFrame* aDes
 }
 
 bool
 nsVideoFrame::IsLeaf() const
 {
   return true;
 }
 
+Matrix
+nsVideoFrame::RotationByVideoInfo(gfxFloat aWidth, gfxFloat aHeight, uint32_t aDegrees)
+{
+  Matrix shiftVideoCenterToOrigin;
+  if (aDegrees == 90 || aDegrees == 270) {
+    shiftVideoCenterToOrigin = Matrix::Translation(-aHeight / 2.0, -aWidth / 2.0);
+  } else {
+    shiftVideoCenterToOrigin = Matrix::Translation(-aWidth / 2.0, -aHeight / 2.0);
+  }
+
+  Matrix rotation = Matrix::Rotation(gfx::Float(aDegrees / 180.0 * M_PI));
+  Matrix shiftLeftTopToOrigin = Matrix::Translation(aWidth / 2.0, aHeight / 2.0);
+
+  return shiftVideoCenterToOrigin * rotation * shiftLeftTopToOrigin;
+}
+
 already_AddRefed<Layer>
 nsVideoFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
                          LayerManager* aManager,
                          nsDisplayItem* aItem,
                          const ContainerLayerParameters& aContainerParameters)
 {
   nsRect area = GetContentRectRelativeToSelf() + aItem->ToReferenceFrame();
   HTMLVideoElement* element = static_cast<HTMLVideoElement*>(GetContent());
@@ -195,33 +211,47 @@ nsVideoFrame::BuildLayer(nsDisplayListBu
                                                      aspectRatio,
                                                      StylePosition());
 
   gfxRect destGFXRect = PresContext()->AppUnitsToGfxUnits(dest);
   destGFXRect.Round();
   if (destGFXRect.IsEmpty()) {
     return nullptr;
   }
-  IntSize scaleHint(static_cast<int32_t>(destGFXRect.Width()),
-                    static_cast<int32_t>(destGFXRect.Height()));
+
+  IntSize scaleHint(0, 0);
+  uint32_t rotationDegrees = container->GetRotationDegrees();
+  if (rotationDegrees == 90 || rotationDegrees == 270) {
+    scaleHint.width = static_cast<int32_t>(destGFXRect.Height());
+    scaleHint.height = static_cast<int32_t>(destGFXRect.Width());
+  } else {
+    scaleHint.width = static_cast<int32_t>(destGFXRect.Width());
+    scaleHint.height = static_cast<int32_t>(destGFXRect.Height());
+  }
   container->SetScaleHint(scaleHint);
 
   RefPtr<ImageLayer> layer = static_cast<ImageLayer*>
     (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem));
   if (!layer) {
     layer = aManager->CreateImageLayer();
     if (!layer)
       return nullptr;
   }
 
   layer->SetContainer(container);
   layer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this));
   // Set a transform on the layer to draw the video in the right place
+
   gfxPoint p = destGFXRect.TopLeft() + aContainerParameters.mOffset;
-  Matrix transform = Matrix::Translation(p.x, p.y);
+
+  Matrix preTransform = RotationByVideoInfo(destGFXRect.Width(),
+                                            destGFXRect.Height(),
+                                            rotationDegrees);
+  Matrix transform = preTransform * Matrix::Translation(p.x, p.y);
+
   layer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
   layer->SetScaleToSize(scaleHint, ScaleMode::STRETCH);
   RefPtr<Layer> result = layer.forget();
   return result.forget();
 }
 
 class DispatchResizeToControls : public Runnable
 {
--- a/layout/generic/nsVideoFrame.h
+++ b/layout/generic/nsVideoFrame.h
@@ -121,16 +121,19 @@ protected:
   // element for a media which is audio-only.
   bool HasVideoData();
 
   // Sets the mPosterImage's src attribute to be the video's poster attribute,
   // if we're the frame for a video element. Only call on frames for video
   // elements, not for frames for audio elements.
   void UpdatePosterSource(bool aNotify);
 
+  // A matrix to obtain a correct-rotated video frame.
+  Matrix RotationByVideoInfo(gfxFloat aWidth, gfxFloat aHeight, uint32_t aDegrees);
+
   virtual ~nsVideoFrame();
 
   nsMargin mBorderPadding;
 
   // Anonymous child which is bound via XBL to the video controls.
   nsCOMPtr<nsIContent> mVideoControls;
 
   // Anonymous child which is the image element of the poster frame.