Bug 902762 pt 7 - Draw caret appropriately for vertical textruns. r=smontagu
authorJonathan Kew <jkew@mozilla.com>
Wed, 01 Oct 2014 20:25:50 +0100
changeset 208249 e7422ba80faad9eea1ea4847f279f6aa833ec2a3
parent 208248 6232edca52e2f542582af9ba11806c820a51780e
child 208250 af6c928893c09c6d8d6a0db7e82f04042b283497
push id27580
push userkwierso@gmail.com
push dateWed, 01 Oct 2014 23:26:55 +0000
treeherderautoland@af6c928893c0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmontagu
bugs902762
milestone35.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 902762 pt 7 - Draw caret appropriately for vertical textruns. r=smontagu
layout/base/nsCaret.cpp
layout/generic/nsTextFrame.cpp
--- a/layout/base/nsCaret.cpp
+++ b/layout/base/nsCaret.cpp
@@ -300,36 +300,50 @@ nsCaret::GetGeometryForFrame(nsIFrame* a
   nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm),
     nsLayoutUtils::FontSizeInflationFor(aFrame));
   NS_ASSERTION(fm, "We should be able to get the font metrics");
   if (fm) {
     ascent = fm->MaxAscent();
     descent = fm->MaxDescent();
   }
   nscoord height = ascent + descent;
-  framePos.y = baseline - ascent;
+  bool vertical = aFrame->GetWritingMode().IsVertical();
+  if (vertical) {
+    framePos.x = baseline - ascent;
+  } else {
+    framePos.y = baseline - ascent;
+  }
   Metrics caretMetrics = ComputeMetrics(aFrame, aFrameOffset, height);
-  rect = nsRect(framePos, nsSize(caretMetrics.mCaretWidth, height));
+  rect = nsRect(framePos, vertical ? nsSize(height, caretMetrics.mCaretWidth) :
+                                     nsSize(caretMetrics.mCaretWidth, height));
 
-  // Clamp the x-position to be within our scroll frame. If we don't, then it
-  // clips us, and we don't appear at all. See bug 335560.
+  // Clamp the inline-position to be within our scroll frame. If we don't, then
+  // it clips us, and we don't appear at all. See bug 335560.
   nsIFrame *scrollFrame =
     nsLayoutUtils::GetClosestFrameOfType(aFrame, nsGkAtoms::scrollFrame);
   if (scrollFrame) {
     // First, use the scrollFrame to get at the scrollable view that we're in.
     nsIScrollableFrame *sf = do_QueryFrame(scrollFrame);
     nsIFrame *scrolled = sf->GetScrolledFrame();
     nsRect caretInScroll = rect + aFrame->GetOffsetTo(scrolled);
 
-    // Now see if thet caret extends beyond the view's bounds. If it does,
+    // Now see if the caret extends beyond the view's bounds. If it does,
     // then snap it back, put it as close to the edge as it can.
-    nscoord overflow = caretInScroll.XMost() -
-      scrolled->GetVisualOverflowRectRelativeToSelf().width;
-    if (overflow > 0) {
-      rect.x -= overflow;
+    if (vertical) {
+      nscoord overflow = caretInScroll.YMost() -
+        scrolled->GetVisualOverflowRectRelativeToSelf().height;
+      if (overflow > 0) {
+        rect.y -= overflow;
+      }
+    } else {
+      nscoord overflow = caretInScroll.XMost() -
+        scrolled->GetVisualOverflowRectRelativeToSelf().width;
+      if (overflow > 0) {
+        rect.x -= overflow;
+      }
     }
   }
 
   if (aBidiIndicatorSize) {
     *aBidiIndicatorSize = caretMetrics.mBidiIndicatorSize;
   }
   return rect;
 }
@@ -817,23 +831,29 @@ bool nsCaret::IsMenuPopupHidingCaret()
 }
 
 void
 nsCaret::ComputeCaretRects(nsIFrame* aFrame, int32_t aFrameOffset,
                            nsRect* aCaretRect, nsRect* aHookRect)
 {
   NS_ASSERTION(aFrame, "Should have a frame here");
 
+  bool isVertical = aFrame->GetWritingMode().IsVertical();
+
   nscoord bidiIndicatorSize;
   *aCaretRect = GetGeometryForFrame(aFrame, aFrameOffset, &bidiIndicatorSize);
 
   // on RTL frames the right edge of mCaretRect must be equal to framePos
   const nsStyleVisibility* vis = aFrame->StyleVisibility();
   if (NS_STYLE_DIRECTION_RTL == vis->mDirection) {
-    aCaretRect->x -= aCaretRect->width;
+    if (isVertical) {
+      aCaretRect->y -= aCaretRect->height;
+    } else {
+      aCaretRect->x -= aCaretRect->width;
+    }
   }
 
   // Simon -- make a hook to draw to the left or right of the caret to show keyboard language direction
   aHookRect->SetEmpty();
   if (!IsBidiUI()) {
     return;
   }
 
@@ -841,20 +861,29 @@ nsCaret::ComputeCaretRects(nsIFrame* aFr
   nsIBidiKeyboard* bidiKeyboard = nsContentUtils::GetBidiKeyboard();
   // if bidiKeyboard->IsLangRTL() fails, there is no way to tell the
   // keyboard direction, or the user has no right-to-left keyboard
   // installed, so we never draw the hook.
   if (bidiKeyboard && NS_SUCCEEDED(bidiKeyboard->IsLangRTL(&isCaretRTL))) {
     // If keyboard language is RTL, draw the hook on the left; if LTR, to the right
     // The height of the hook rectangle is the same as the width of the caret
     // rectangle.
-    aHookRect->SetRect(aCaretRect->x + (isCaretRTL ? bidiIndicatorSize * -1 : aCaretRect->width),
-                       aCaretRect->y + bidiIndicatorSize,
-                       bidiIndicatorSize,
-                       aCaretRect->width);
+    if (isVertical) {
+      aHookRect->SetRect(aCaretRect->XMost() - bidiIndicatorSize,
+                         aCaretRect->y + (isCaretRTL ? bidiIndicatorSize * -1 :
+                                                       aCaretRect->height),
+                         aCaretRect->height,
+                         bidiIndicatorSize);
+    } else {
+      aHookRect->SetRect(aCaretRect->x + (isCaretRTL ? bidiIndicatorSize * -1 :
+                                                       aCaretRect->width),
+                         aCaretRect->y + bidiIndicatorSize,
+                         bidiIndicatorSize,
+                         aCaretRect->width);
+    }
   }
 }
 
 /* static */
 void nsCaret::CaretBlinkCallback(nsITimer* aTimer, void* aClosure)
 {
   nsCaret* theCaret = reinterpret_cast<nsCaret*>(aClosure);
   if (!theCaret) {
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -6524,28 +6524,35 @@ nsTextFrame::GetPointFromOffset(int32_t 
 
   if (inOffset < trimmedEnd &&
       !iter.IsOriginalCharSkipped() &&
       !mTextRun->IsClusterStart(iter.GetSkippedOffset())) {
     NS_WARNING("GetPointFromOffset called for non-cluster boundary");
     FindClusterStart(mTextRun, trimmedOffset, &iter);
   }
 
-  gfxFloat advanceWidth =
+  gfxFloat advance =
     mTextRun->GetAdvanceWidth(properties.GetStart().GetSkippedOffset(),
                               GetSkippedDistance(properties.GetStart(), iter),
                               &properties);
-  nscoord width = NSToCoordCeilClamped(advanceWidth);
-
-  if (mTextRun->IsRightToLeft()) {
-    outPoint->x = mRect.width - width;
+  nscoord iSize = NSToCoordCeilClamped(advance);
+
+  if (mTextRun->IsVertical()) {
+    if (mTextRun->IsRightToLeft()) {
+      outPoint->y = mRect.height - iSize;
+    } else {
+      outPoint->y = iSize;
+    }
   } else {
-    outPoint->x = width;
-  }
-  outPoint->y = 0;
+    if (mTextRun->IsRightToLeft()) {
+      outPoint->x = mRect.width - iSize;
+    } else {
+      outPoint->x = iSize;
+    }
+  }
 
   return NS_OK;
 }
 
 nsresult
 nsTextFrame::GetChildFrameContainingOffset(int32_t   aContentOffset,
                                            bool      aHint,
                                            int32_t*  aOutOffset,