Bug 1021499 - Enlarge touch/selection carets touch area. r=roc, a=bajaj
authorMorris Tseng <mtseng@mozilla.com>
Wed, 22 Apr 2015 23:49:00 -0400
changeset 238229 07daccc4b2b090e0cdf96cdcc161b83e39e58048
parent 238228 81eb2d8b3cb6dbd00ebc8dcf0a380b907595e0f4
child 238230 7343618cc119583da60413858db0b7e327761e9f
push id528
push userryanvm@gmail.com
push dateFri, 24 Apr 2015 14:48:27 +0000
treeherdermozilla-b2g37_v2_2@7343618cc119 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, bajaj
bugs1021499
milestone37.0
Bug 1021499 - Enlarge touch/selection carets touch area. r=roc, a=bajaj
layout/base/SelectionCarets.cpp
layout/base/SelectionCarets.h
layout/base/TouchCaret.cpp
layout/base/TouchCaret.h
layout/generic/nsCanvasFrame.cpp
layout/style/ua.css
--- a/layout/base/SelectionCarets.cpp
+++ b/layout/base/SelectionCarets.cpp
@@ -525,18 +525,18 @@ SelectionCarets::UpdateSelectionCarets()
   nsRect firstRectInRootFrame = firstRectInStartFrame;
   nsRect lastRectInRootFrame = lastRectInEndFrame;
   nsLayoutUtils::TransformRect(startFrame, rootFrame, firstRectInRootFrame);
   nsLayoutUtils::TransformRect(endFrame, rootFrame, lastRectInRootFrame);
 
   SetStartFrameVisibility(startFrameVisible);
   SetEndFrameVisibility(endFrameVisible);
 
-  SetStartFramePos(firstRectInRootFrame.BottomLeft());
-  SetEndFramePos(lastRectInRootFrame.BottomRight());
+  SetStartFramePos(firstRectInRootFrame);
+  SetEndFramePos(lastRectInRootFrame);
   SetVisibility(true);
 
   // Use half of the first(last) rect as the dragup(dragdown) boundary
   mDragUpYBoundary =
     (firstRectInRootFrame.BottomLeft().y + firstRectInRootFrame.TopLeft().y) / 2;
   mDragDownYBoundary =
     (lastRectInRootFrame.BottomRight().y + lastRectInRootFrame.TopRight().y) / 2;
 
@@ -869,47 +869,51 @@ SelectionCarets::SetSelectionDirection(b
 {
   nsRefPtr<dom::Selection> selection = GetSelection();
   if (selection) {
     selection->SetDirection(aForward ? eDirNext : eDirPrevious);
   }
 }
 
 static void
-SetFramePos(dom::Element* aElement, const nsPoint& aPosition)
+SetFramePos(dom::Element* aElement, const nsRect& aCaretRect)
 {
   if (!aElement) {
     return;
   }
 
   nsAutoString styleStr;
   styleStr.AppendLiteral("left: ");
-  styleStr.AppendFloat(nsPresContext::AppUnitsToFloatCSSPixels(aPosition.x));
+  styleStr.AppendFloat(nsPresContext::AppUnitsToFloatCSSPixels(aCaretRect.Center().x));
   styleStr.AppendLiteral("px; top: ");
-  styleStr.AppendFloat(nsPresContext::AppUnitsToFloatCSSPixels(aPosition.y));
+  styleStr.AppendFloat(nsPresContext::AppUnitsToFloatCSSPixels(aCaretRect.y));
+  styleStr.AppendLiteral("px; padding-top: ");
+  styleStr.AppendFloat(nsPresContext::AppUnitsToFloatCSSPixels(aCaretRect.height));
   styleStr.AppendLiteral("px;");
 
   SELECTIONCARETS_LOG_STATIC("Set style: %s",
                              NS_ConvertUTF16toUTF8(styleStr).get());
 
   aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::style, styleStr, true);
 }
 
 void
-SelectionCarets::SetStartFramePos(const nsPoint& aPosition)
+SelectionCarets::SetStartFramePos(const nsRect& aCaretRect)
 {
-  SELECTIONCARETS_LOG("x=%d, y=%d", aPosition.x, aPosition.y);
-  SetFramePos(mPresShell->GetSelectionCaretsStartElement(), aPosition);
+  SELECTIONCARETS_LOG("x=%d, y=%d, w=%d, h=%d",
+    aCaretRect.x, aCaretRect.y, aCaretRect.width, aCaretRect.height);
+  SetFramePos(mPresShell->GetSelectionCaretsStartElement(), aCaretRect);
 }
 
 void
-SelectionCarets::SetEndFramePos(const nsPoint& aPosition)
+SelectionCarets::SetEndFramePos(const nsRect& aCaretRect)
 {
-  SELECTIONCARETS_LOG("x=%d, y=%d", aPosition.y, aPosition.y);
-  SetFramePos(mPresShell->GetSelectionCaretsEndElement(), aPosition);
+  SELECTIONCARETS_LOG("x=%d, y=%d, w=%d, h=%d",
+    aCaretRect.x, aCaretRect.y, aCaretRect.width, aCaretRect.height);
+  SetFramePos(mPresShell->GetSelectionCaretsEndElement(), aCaretRect);
 }
 
 bool
 SelectionCarets::IsOnStartFrameInner(const nsPoint& aPosition)
 {
   return mVisible &&
     nsLayoutUtils::ContainsPoint(GetStartFrameRectInner(), aPosition,
                                  SelectionCaretsInflateSize());
--- a/layout/base/SelectionCarets.h
+++ b/layout/base/SelectionCarets.h
@@ -141,26 +141,26 @@ private:
    * Simulate drag state when we change the selection range.
    * Hence, the selection change event will fire normally.
    */
   void SetSelectionDragState(bool aState);
 
   void SetSelectionDirection(bool aForward);
 
   /**
-   * Move start frame of selection caret to given position.
+   * Move start frame of selection caret based on current caret pos.
    * In app units.
    */
-  void SetStartFramePos(const nsPoint& aPosition);
+  void SetStartFramePos(const nsRect& aCaretRect);
 
   /**
-   * Move end frame of selection caret to given position.
+   * Move end frame of selection caret based on current caret pos.
    * In app units.
    */
-  void SetEndFramePos(const nsPoint& aPosition);
+  void SetEndFramePos(const nsRect& aCaretRect);
 
   /**
    * Check if aPosition is on the start or end frame of the
    * selection caret's inner div element.
    *
    * @param aPosition should be relative to document's root frame
    * in app units
    */
--- a/layout/base/TouchCaret.cpp
+++ b/layout/base/TouchCaret.cpp
@@ -250,38 +250,41 @@ TouchCaret::GetCaretYCenterPosition()
   nsIFrame* canvasFrame = GetCanvasFrame();
 
   nsLayoutUtils::TransformRect(focusFrame, canvasFrame, caretRect);
 
   return (caretRect.y + caretRect.height / 2);
 }
 
 void
-TouchCaret::SetTouchFramePos(const nsPoint& aOrigin)
+TouchCaret::SetTouchFramePos(const nsRect& aCaretRect)
 {
   nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
   if (!presShell) {
     return;
   }
 
   mozilla::dom::Element* touchCaretElement = presShell->GetTouchCaretElement();
   if (!touchCaretElement) {
     return;
   }
 
   // Convert aOrigin to CSS pixels.
   nsRefPtr<nsPresContext> presContext = presShell->GetPresContext();
-  int32_t x = presContext->AppUnitsToIntCSSPixels(aOrigin.x);
-  int32_t y = presContext->AppUnitsToIntCSSPixels(aOrigin.y);
+  int32_t x = presContext->AppUnitsToIntCSSPixels(aCaretRect.Center().x);
+  int32_t y = presContext->AppUnitsToIntCSSPixels(aCaretRect.y);
+  int32_t padding = presContext->AppUnitsToIntCSSPixels(aCaretRect.height);
 
   nsAutoString styleStr;
   styleStr.AppendLiteral("left: ");
   styleStr.AppendInt(x);
   styleStr.AppendLiteral("px; top: ");
   styleStr.AppendInt(y);
+  styleStr.AppendLiteral("px; padding-top: ");
+  styleStr.AppendInt(padding);
   styleStr.AppendLiteral("px;");
 
   TOUCHCARET_LOG("Set style: %s", NS_ConvertUTF16toUTF8(styleStr).get());
 
   touchCaretElement->SetAttr(kNameSpaceID_None, nsGkAtoms::style,
                              styleStr, true);
 }
 
@@ -484,64 +487,59 @@ TouchCaret::IsDisplayable()
   return true;
 }
 
 void
 TouchCaret::UpdatePosition()
 {
   MOZ_ASSERT(mVisible);
 
-  nsPoint pos = GetTouchCaretPosition();
-  pos = ClampPositionToScrollFrame(pos);
-  SetTouchFramePos(pos);
+  nsRect rect = GetTouchCaretRect();
+  rect = ClampRectToScrollFrame(rect);
+  SetTouchFramePos(rect);
 }
 
-nsPoint
-TouchCaret::GetTouchCaretPosition()
+nsRect
+TouchCaret::GetTouchCaretRect()
 {
   nsRect focusRect;
   nsIFrame* focusFrame = GetCaretFocusFrame(&focusRect);
   nsIFrame* rootFrame = GetRootFrame();
-
-  // Position of the touch caret relative to focusFrame.
-  nsPoint pos = nsPoint(focusRect.x + (focusRect.width / 2),
-                        focusRect.y + focusRect.height);
+  // Transform the position to make it relative to root frame.
+  nsLayoutUtils::TransformRect(focusFrame, rootFrame, focusRect);
 
-  // Transform the position to make it relative to root frame.
-  nsLayoutUtils::TransformPoint(focusFrame, rootFrame, pos);
-
-  return pos;
+  return focusRect;
 }
 
-nsPoint
-TouchCaret::ClampPositionToScrollFrame(const nsPoint& aPosition)
+nsRect
+TouchCaret::ClampRectToScrollFrame(const nsRect& aRect)
 {
-  nsPoint pos = aPosition;
+  nsRect rect = aRect;
   nsIFrame* focusFrame = GetCaretFocusFrame();
   nsIFrame* rootFrame = GetRootFrame();
 
   // Clamp the touch caret position to the scrollframe boundary.
   nsIFrame* closestScrollFrame =
     nsLayoutUtils::GetClosestFrameOfType(focusFrame, nsGkAtoms::scrollFrame);
 
   while (closestScrollFrame) {
     nsIScrollableFrame* sf = do_QueryFrame(closestScrollFrame);
     nsRect visualRect = sf->GetScrollPortRect();
 
     // Clamp the touch caret in the scroll port.
     nsLayoutUtils::TransformRect(closestScrollFrame, rootFrame, visualRect);
-    pos = visualRect.ClampPoint(pos);
+    rect = rect.Intersect(visualRect);
 
     // Get next ancestor scroll frame.
     closestScrollFrame =
       nsLayoutUtils::GetClosestFrameOfType(closestScrollFrame->GetParent(),
                                            nsGkAtoms::scrollFrame);
   }
 
-  return pos;
+  return rect;
 }
 
 /* static */void
 TouchCaret::DisableTouchCaretCallback(nsITimer* aTimer, void* aTouchCaret)
 {
   nsRefPtr<TouchCaret> self = static_cast<TouchCaret*>(aTouchCaret);
   NS_PRECONDITION(aTimer == self->mTouchCaretExpirationTimer,
                   "Unexpected timer");
--- a/layout/base/TouchCaret.h
+++ b/layout/base/TouchCaret.h
@@ -112,32 +112,32 @@ private:
 
   /**
    * Retrieve the center y position of the caret.
    * The returned point is relative to the canvas frame.
    */
   nscoord GetCaretYCenterPosition();
 
   /**
-   * Retrieve the position of the touch caret.
-   * The returned point is relative to the canvas frame.
+   * Retrieve the rect of the touch caret.
+   * The returned rect is relative to the canvas frame.
    */
-  nsPoint GetTouchCaretPosition();
+  nsRect GetTouchCaretRect();
 
   /**
    * Clamp the position of the touch caret to the scroll frame boundary.
-   * The returned point is relative to the canvas frame.
+   * The returned rect is relative to the canvas frame.
    */
-  nsPoint ClampPositionToScrollFrame(const nsPoint& aPosition);
+  nsRect ClampRectToScrollFrame(const nsRect& aRect);
 
   /**
    * Set the position of the touch caret.
    * Touch caret is an absolute positioned div.
    */
-  void SetTouchFramePos(const nsPoint& aOrigin);
+  void SetTouchFramePos(const nsRect& aRect);
 
   void LaunchExpirationTimer();
   void CancelExpirationTimer();
   static void DisableTouchCaretCallback(nsITimer* aTimer, void* aPresShell);
 
   /**
    * Move the caret to movePoint which is relative to the canvas frame.
    * Caret will be scrolled into view.
--- a/layout/generic/nsCanvasFrame.cpp
+++ b/layout/generic/nsCanvasFrame.cpp
@@ -480,19 +480,23 @@ nsCanvasFrame::BuildDisplayList(nsDispla
     if (needBlendContainer) {
       aLists.BorderBackground()->AppendNewToTop(
         new (aBuilder) nsDisplayBlendContainer(aBuilder, this, aLists.BorderBackground()));
     }
   }
 
   nsIFrame* kid;
   for (kid = GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) {
-    // Skip touch caret frame if we do not build caret.
-    if (!aBuilder->IsBuildingCaret() && kid->GetContent() == mTouchCaretElement) {
-      continue;
+    // Skip touch/selection caret frame if we do not build caret.
+    if (!aBuilder->IsBuildingCaret()) {
+      if(kid->GetContent() == mTouchCaretElement ||
+         kid->GetContent() == mSelectionCaretsStartElement||
+         kid->GetContent() == mSelectionCaretsEndElement) {
+        continue;
+      }
     }
 
     // Put our child into its own pseudo-stack.
     BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
   }
 
 #ifdef DEBUG_CANVAS_FOCUS
   nsCOMPtr<nsIContent> focusContent;
--- a/layout/style/ua.css
+++ b/layout/style/ua.css
@@ -309,32 +309,36 @@ parsererror|sourcetext {
   font-weight: bold;
   font-size: 12pt;
 }
 
 div:-moz-native-anonymous.moz-touchcaret,
 div:-moz-native-anonymous.moz-selectioncaret-left,
 div:-moz-native-anonymous.moz-selectioncaret-right {
   position: fixed;
+  width: 44px;
+  height: 47px;
 }
 
 div:-moz-native-anonymous.moz-selectioncaret-left > div,
 div:-moz-native-anonymous.moz-selectioncaret-right > div {
   position: absolute;
+  width: 100%;
+  height: 100%;
+  bottom: 0;
 }
 
 div:-moz-native-anonymous.moz-touchcaret,
 div:-moz-native-anonymous.moz-selectioncaret-left,
 div:-moz-native-anonymous.moz-selectioncaret-right,
 div:-moz-native-anonymous.moz-selectioncaret-left > div,
 div:-moz-native-anonymous.moz-selectioncaret-right > div {
-  width: 44px;
-  height: 47px;
-  background-position: center center;
-  background-size: 100% 100%;
+  background-position: center bottom;
+  background-size: 100%;
+  background-repeat: no-repeat;
   z-index: 2147483647;
 }
 
 div:-moz-native-anonymous.moz-touchcaret,
 div:-moz-native-anonymous.moz-selectioncaret-left > div,
 div:-moz-native-anonymous.moz-selectioncaret-right > div {
   background-image: url("resource://gre/res/text_caret.png");
 }