Bug 1536762 - part2 : use first line box's size as positioning basic unit. r=heycam,baku
authoralwu <alwu@mozilla.com>
Thu, 09 May 2019 19:22:33 +0000
changeset 473315 1fa720d18b38e35831de185ac2f55356c88a7d21
parent 473314 2d810269b72e198765af3d997f3b117d832afd38
child 473316 9250cfd8c4e498475dd7351aed3ca391103b4087
push id113072
push usernbeleuzu@mozilla.com
push dateFri, 10 May 2019 02:59:17 +0000
treeherdermozilla-inbound@f71645b9b3e0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam, baku
bugs1536762
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1536762 - part2 : use first line box's size as positioning basic unit. r=heycam,baku According to the spec [1] 7.2.10.2, we should use the first line box's height or width as positioning unit to adjust box's position. We will also use this value to adjust box when `snap-to-line` is false. There, we implement a new chrome-only API to acquire this information, which would return the first line box's size in the `block` frame. [1] https://www.w3.org/TR/webvtt1/#ref-for-webvtt-cue-snap-to-lines-flag-12 Differential Revision: https://phabricator.services.mozilla.com/D29745
dom/base/Element.cpp
dom/base/Element.h
dom/media/webvtt/vtt.jsm
dom/webidl/Element.webidl
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -159,16 +159,17 @@
 #include "nsIDOMXULMultSelectCntrlEl.h"
 #include "nsIDOMXULSelectCntrlEl.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsIBrowser.h"
 #include "nsIAutoCompletePopup.h"
 
 #include "nsISpeculativeConnect.h"
 #include "nsIIOService.h"
+#include "nsBlockFrame.h"
 
 #include "DOMMatrix.h"
 
 using mozilla::gfx::Matrix4x4;
 
 namespace mozilla {
 namespace dom {
 
@@ -3151,18 +3152,18 @@ nsresult Element::PostHandleEventForLink
         aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
       }
     } break;
 
     case eKeyPress: {
       WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
       if (keyEvent && keyEvent->mKeyCode == NS_VK_RETURN) {
         nsEventStatus status = nsEventStatus_eIgnore;
-        rv = DispatchClickEvent(MOZ_KnownLive(aVisitor.mPresContext), keyEvent, this, false,
-                                nullptr, &status);
+        rv = DispatchClickEvent(MOZ_KnownLive(aVisitor.mPresContext), keyEvent,
+                                this, false, nullptr, &status);
         if (NS_SUCCEEDED(rv)) {
           aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
         }
       }
     } break;
 
     default:
       // switch not in sync with the optimization switch earlier in this
@@ -4395,10 +4396,22 @@ void Element::NoteDescendantsNeedFramesF
   // Since lazy frame construction can be required for non-element nodes, this
   // Note() method operates on the parent of the frame-requiring content, unlike
   // the other Note() methods above (which operate directly on the element that
   // needs processing).
   NoteDirtyElement(this, NODE_DESCENDANTS_NEED_FRAMES);
   SetFlags(NODE_DESCENDANTS_NEED_FRAMES);
 }
 
+double Element::FirstLineBoxBSize() const {
+  const nsBlockFrame* frame = do_QueryFrame(GetPrimaryFrame());
+  if (!frame) {
+    return 0.0;
+  }
+  nsBlockFrame::ConstLineIterator line = frame->LinesBegin();
+  nsBlockFrame::ConstLineIterator lineEnd = frame->LinesEnd();
+  return line != lineEnd
+             ? nsPresContext::AppUnitsToDoubleCSSPixels(line->BSize())
+             : 0.0;
+}
+
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -1305,16 +1305,21 @@ class Element : public FragmentOrElement
         GetClientAreaRect().Height());
   }
 
   MOZ_CAN_RUN_SCRIPT double ClientWidthDouble() {
     return nsPresContext::AppUnitsToDoubleCSSPixels(
         GetClientAreaRect().Width());
   }
 
+  // This function will return the block size of first line box, no matter if
+  // the box is 'block' or 'inline'. The return unit is pixel. If the element
+  // can't get a primary frame, we will return be zero.
+  double FirstLineBoxBSize() const;
+
   already_AddRefed<Flex> GetAsFlexContainer();
   void GetGridFragments(nsTArray<RefPtr<Grid>>& aResult);
 
   already_AddRefed<DOMMatrixReadOnly> GetTransformToAncestor(
       Element& aAncestor);
   already_AddRefed<DOMMatrixReadOnly> GetTransformToParent();
   already_AddRefed<DOMMatrixReadOnly> GetTransformToViewport();
 
--- a/dom/media/webvtt/vtt.jsm
+++ b/dom/media/webvtt/vtt.jsm
@@ -550,16 +550,23 @@ XPCOMUtils.defineLazyPreferenceGetter(th
             this.containerWidth * this._tranferPercentageToFloat(this.div.style.width) :
             this.div.clientWidthDouble,
           height = isWritingDirectionHorizontal ?
             this.div.clientHeightDouble :
             this.containerHeight * this._tranferPercentageToFloat(this.div.style.height);
       return { top, left, width, height };
     }
 
+    getFirstLineBoxSize() {
+      // This size would be automatically adjusted by writing direction. When
+      // direction is horizontal, it represents box's height. When direction is
+      // vertical, it represents box's width.
+      return this.div.firstLineBoxBSize;
+    }
+
     /**
      * Following methods are private functions, should not use them outside this
      * class.
      */
     _tranferPercentageToFloat(input) {
       return input.replace("%", "") / 100.0;
     }
 
@@ -891,17 +898,17 @@ XPCOMUtils.defineLazyPreferenceGetter(th
     const fullDimension = isWritingDirectionHorizontal ?
       containerBox.height : containerBox.width;
     if (cue.snapToLines) {
       // The step is the height or width of the line box. We should use font
       // size directly, instead of using text box's width or height, because the
       // width or height of the box would be changed when the text is wrapped to
       // different line. Ex. if text is wrapped to two line, the height or width
       // of the box would become 2 times of font size.
-      let step = parseFloat(styleBox.fontSize.replace("px", ""));
+      let step = styleBox.getFirstLineBoxSize();
       if (step == 0) {
         return;
       }
 
       // spec 7.2.10.4 ~ 7.2.10.6
       let line = Math.floor(cue.computedLine + 0.5);
       if (cue.vertical == "rl") {
         line = -1 * (line + 1);
@@ -991,17 +998,17 @@ XPCOMUtils.defineLazyPreferenceGetter(th
       }
 
       // spec 7.2.10.3
       let bestPosition = {},
           specifiedPosition = box.clone(),
           outsideAreaPercentage = 1; // Highest possible so the first thing we get is better.
       let hasFoundBestPosition = false;
       const axis = ["-y", "-x", "+x", "+y"];
-      const toMove = parseFloat(styleBox.fontSize.replace("px", ""));
+      const toMove = styleBox.getFirstLineBoxSize();
       for (let i = 0; i < axis.length && !hasFoundBestPosition; i++) {
         while (box.overlapsOppositeAxis(containerBox, axis[i]) ||
                (!box.within(containerBox) || box.overlapsAny(outputBoxes))) {
           box.move(axis[i], toMove);
         }
         // We found a spot where we aren't overlapping anything. This is our
         // best position.
         if (box.within(containerBox)) {
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -317,9 +317,14 @@ partial interface Element {
 // These variables are used in vtt.js, they are used for positioning vtt cues.
 partial interface Element {
   // These two attributes are a double version of the clientHeight and the
   // clientWidth.
   [ChromeOnly]
   readonly attribute double clientHeightDouble;
   [ChromeOnly]
   readonly attribute double clientWidthDouble;
+  // This attribute returns the block size of the first line box under the different
+  // writing directions. If the direction is horizontal, it represents box's
+  // height. If the direction is vertical, it represents box's width.
+  [ChromeOnly]
+  readonly attribute double firstLineBoxBSize;
 };