Bug 985915 - Vertically move up closed caption to not overlap control bar. r?rillian draft
authorRay Lin <ralin@mozilla.com>
Mon, 27 Jun 2016 11:22:15 +0800
changeset 382155 b9edceb06e1cfbd213d5fd0366f399f51c58d318
parent 381597 2ab57664bf7cafdd64e136e341527c275fc8c3aa
child 524114 df62ac58237e3b909b612a9384ec74d7a7f349a2
push id21638
push userbmo:ralin@mozilla.com
push dateWed, 29 Jun 2016 02:20:58 +0000
reviewersrillian
bugs985915
milestone50.0a1
Bug 985915 - Vertically move up closed caption to not overlap control bar. r?rillian MozReview-Commit-ID: HzJ3ppbmQnk
dom/html/TextTrackManager.cpp
dom/media/webvtt/WebVTTParserWrapper.js
dom/media/webvtt/nsIWebVTTParserWrapper.idl
dom/media/webvtt/vtt.jsm
layout/generic/nsVideoFrame.h
toolkit/content/widgets/videocontrols.xml
--- a/dom/html/TextTrackManager.cpp
+++ b/dom/html/TextTrackManager.cpp
@@ -225,16 +225,17 @@ TextTrackManager::UpdateCueDisplay()
 
   nsIFrame* frame = mMediaElement->GetPrimaryFrame();
   nsVideoFrame* videoFrame = do_QueryFrame(frame);
   if (!videoFrame) {
     return;
   }
 
   nsCOMPtr<nsIContent> overlay = videoFrame->GetCaptionOverlay();
+  nsCOMPtr<nsIContent> controls = videoFrame->GetVideoControls();
   if (!overlay) {
     return;
   }
 
   nsTArray<RefPtr<TextTrackCue> > activeCues;
   mTextTracks->UpdateAndGetShowingCues(activeCues);
 
   if (activeCues.Length() > 0) {
@@ -242,17 +243,17 @@ TextTrackManager::UpdateCueDisplay()
 
     jsCues->SetAsArray(nsIDataType::VTYPE_INTERFACE,
                        &NS_GET_IID(nsIDOMEventTarget),
                        activeCues.Length(),
                        static_cast<void*>(activeCues.Elements()));
 
     nsPIDOMWindowInner* window = mMediaElement->OwnerDoc()->GetInnerWindow();
     if (window) {
-      sParserWrapper->ProcessCues(window, jsCues, overlay);
+      sParserWrapper->ProcessCues(window, jsCues, overlay, controls);
     }
   } else if (overlay->Length() > 0) {
     nsContentUtils::SetNodeTextContent(overlay, EmptyString(), true);
   }
 }
 
 void
 TextTrackManager::NotifyCueAdded(TextTrackCue& aCue)
@@ -291,16 +292,20 @@ TextTrackManager::PopulatePendingList()
 }
 
 void
 TextTrackManager::AddListeners()
 {
   if (mMediaElement) {
     mMediaElement->AddEventListener(NS_LITERAL_STRING("resizevideocontrols"),
                                     this, false, false);
+    mMediaElement->AddEventListener(NS_LITERAL_STRING("seeked"),
+                                    this, false, false);
+    mMediaElement->AddEventListener(NS_LITERAL_STRING("controlbarchange"),
+                                    this, false, true);
   }
 }
 
 void
 TextTrackManager::HonorUserPreferencesForTrackSelection()
 {
   if (performedTrackSelection || !mTextTracks) {
     return;
@@ -400,21 +405,27 @@ NS_IMETHODIMP
 TextTrackManager::HandleEvent(nsIDOMEvent* aEvent)
 {
   if (!mTextTracks) {
     return NS_OK;
   }
 
   nsAutoString type;
   aEvent->GetType(type);
-  if (type.EqualsLiteral("resizevideocontrols")) {
+  if (type.EqualsLiteral("resizevideocontrols") ||
+      type.EqualsLiteral("seeked")) {
     for (uint32_t i = 0; i< mTextTracks->Length(); i++) {
       ((*mTextTracks)[i])->SetCuesDirty();
     }
   }
+
+  if (type.EqualsLiteral("controlbarchange")) {
+    UpdateCueDisplay();
+  }
+
   return NS_OK;
 }
 
 
 class SimpleTextTrackEvent : public Runnable
 {
 public:
   friend class CompareSimpleTextTrackEvents;
--- a/dom/media/webvtt/WebVTTParserWrapper.js
+++ b/dom/media/webvtt/WebVTTParserWrapper.js
@@ -49,19 +49,19 @@ WebVTTParserWrapper.prototype =
     };
   },
 
   convertCueToDOMTree: function(window, cue)
   {
     return WebVTT.convertCueToDOMTree(window, cue.text);
   },
 
-  processCues: function(window, cues, overlay)
+  processCues: function(window, cues, overlay, controls)
   {
-    WebVTT.processCues(window, cues, overlay);
+    WebVTT.processCues(window, cues, overlay, controls);
   },
 
   classDescription: "Wrapper for the JS WebVTT implementation (vtt.js)",
   classID: Components.ID(WEBVTTPARSERWRAPPER_CID),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebVTTParserWrapper]),
   classInfo: XPCOMUtils.generateCI({
     classID:    WEBVTTPARSERWRAPPER_CID,
     contractID: WEBVTTPARSERWRAPPER_CONTRACTID,
--- a/dom/media/webvtt/nsIWebVTTParserWrapper.idl
+++ b/dom/media/webvtt/nsIWebVTTParserWrapper.idl
@@ -72,16 +72,17 @@ interface nsIWebVTTParserWrapper : nsISu
    * overlap avoidance using the dimensions of 'overlay'. Finally, it adds the
    * computed divs to the VTTCues display state property for use later.
    *
    * @param window  A window object with which it will create the DOM tree
    *                and containing div element.
    * @param cues    An array of VTTCues who need there display state to be
    *                computed.
    * @param overlay The HTMLElement that the cues will be displayed within.
+   * @param controls The video control element that will affect cues position.
    */
   void processCues(in mozIDOMWindow window, in nsIVariant cues,
-                   in nsISupports overlay);
+                   in nsISupports overlay, in nsISupports controls);
 };
 
 %{C++
 #define NS_WEBVTTPARSERWRAPPER_CONTRACTID "@mozilla.org/webvttParserWrapper;1"
 %}
--- a/dom/media/webvtt/vtt.jsm
+++ b/dom/media/webvtt/vtt.jsm
@@ -1115,39 +1115,54 @@ this.EXPORTED_SYMBOLS = ["WebVTT"];
 
   var FONT_SIZE_PERCENT = 0.05;
   var FONT_STYLE = "sans-serif";
   var CUE_BACKGROUND_PADDING = "1.5%";
 
   // Runs the processing model over the cues and regions passed to it.
   // @param overlay A block level element (usually a div) that the computed cues
   //                and regions will be placed into.
-  WebVTT.processCues = function(window, cues, overlay) {
+  // @param controls  A Control bar element. Cues' position will be
+  //                 affected and repositioned according to it.
+  WebVTT.processCues = function(window, cues, overlay, controls) {
     if (!window || !cues || !overlay) {
       return null;
     }
 
     // Remove all previous children.
     while (overlay.firstChild) {
       overlay.removeChild(overlay.firstChild);
     }
 
+    var controlBar;
+    var controlBarShown;
+
+    if (controls) {
+      controlBar = controls.ownerDocument.getAnonymousElementByAttribute(
+        controls, "class", "controlBar");
+      controlBarShown = controlBar ? !!controlBar.clientHeight : false;
+    }
+
     var paddedOverlay = window.document.createElement("div");
     paddedOverlay.style.position = "absolute";
     paddedOverlay.style.left = "0";
     paddedOverlay.style.right = "0";
     paddedOverlay.style.top = "0";
     paddedOverlay.style.bottom = "0";
     paddedOverlay.style.margin = CUE_BACKGROUND_PADDING;
     overlay.appendChild(paddedOverlay);
 
     // Determine if we need to compute the display states of the cues. This could
     // be the case if a cue's state has been changed since the last computation or
     // if it has not been computed yet.
     function shouldCompute(cues) {
+      if (controlBarShown) {
+        return true;
+      }
+
       for (var i = 0; i < cues.length; i++) {
         if (cues[i].hasBeenReset || !cues[i].displayState) {
           return true;
         }
       }
       return false;
     }
 
@@ -1164,16 +1179,21 @@ this.EXPORTED_SYMBOLS = ["WebVTT"];
         fontSize = Math.round(containerBox.height * FONT_SIZE_PERCENT * 100) / 100;
     var styleOptions = {
       font: fontSize + "px " + FONT_STYLE
     };
 
     (function() {
       var styleBox, cue;
 
+      if (controlBarShown) {
+        // Add an empty output box that cover the same region as video control bar.
+        boxPositions.push(BoxPosition.getSimpleBoxPosition(controlBar));
+      }
+
       for (var i = 0; i < cues.length; i++) {
         cue = cues[i];
 
         // Compute the intial position and styles of the cue div.
         styleBox = new CueStyleBox(window, cue, styleOptions);
         paddedOverlay.appendChild(styleBox.div);
 
         // Move the cue div to it's correct line position.
--- a/layout/generic/nsVideoFrame.h
+++ b/layout/generic/nsVideoFrame.h
@@ -97,16 +97,18 @@ public:
   nsIContent* GetPosterImage() { return mPosterImage; }
 
   // Returns true if we should display the poster. Note that once we show
   // a video frame, the poster will never be displayed again.
   bool ShouldDisplayPoster();
 
   nsIContent *GetCaptionOverlay() { return mCaptionDiv; }
 
+  nsIContent *GetVideoControls() { return mVideoControls; }
+
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
 #endif
 
   already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                      LayerManager* aManager,
                                      nsDisplayItem* aItem,
                                      const ContainerLayerParameters& aContainerParameters);
--- a/toolkit/content/widgets/videocontrols.xml
+++ b/toolkit/content/widgets/videocontrols.xml
@@ -1318,16 +1318,17 @@
                   }
 
                   this.textTrackList.setAttribute("hidden", "true");
                   this.setClosedCaptionButtonState();
                 },
 
                 onControlBarTransitioned : function () {
                   this.textTrackList.setAttribute("hidden", "true");
+                  this.video.dispatchEvent(new CustomEvent("controlbarchange"));
                 },
 
                 toggleClosedCaption : function () {
                   if (this.overlayableTextTracks.length === 1) {
                     const lastTTIdx = this.overlayableTextTracks[0].index;
 
                     return this.changeTextTrack(this.isClosedCaptionOn() ? 0 : lastTTIdx);
                   }