Bug 898984 - Part 2: Support surrogate pair in XUL cropped element. r=jfkthame
authorXidorn Quan <quanxunzhen@gmail.com>
Sun, 11 Aug 2013 03:41:00 +0900
changeset 315215 9a0a1b105571f3f29af09cd686ce88ca76d6f676
parent 315214 00a900605c52a89d263683f8a1edb2dcb34b37cb
child 315216 0be22294cfd825fb949866185169621f500110ee
push id32563
push userihsiao@mozilla.com
push dateMon, 26 Sep 2016 11:18:33 +0000
treeherderautoland@eb840c87b5fd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame
bugs898984
milestone52.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 898984 - Part 2: Support surrogate pair in XUL cropped element. r=jfkthame
intl/unicharutil/util/nsBidiUtils.h
layout/xul/nsTextBoxFrame.cpp
widget/cocoa/TextInputHandler.mm
--- a/intl/unicharutil/util/nsBidiUtils.h
+++ b/intl/unicharutil/util/nsBidiUtils.h
@@ -268,13 +268,14 @@ typedef enum nsCharType nsCharType;
  */
 
 #define IS_IN_BMP_RTL_BLOCK(c) ((0x590 <= (c)) && ((c) <= 0x8ff))
 #define IS_RTL_PRESENTATION_FORM(c) (((0xfb1d <= (c)) && ((c) <= 0xfdff)) || \
                                      ((0xfe70 <= (c)) && ((c) <= 0xfefc)))
 #define IS_IN_SMP_RTL_BLOCK(c) (((0x10800 <= (c)) && ((c) <= 0x10fff)) || \
                                 ((0x1e800 <= (c)) && ((c) <= 0x1eFFF)))
 #define UCS2_CHAR_IS_BIDI(c) ((IS_IN_BMP_RTL_BLOCK(c)) || \
-                              (IS_RTL_PRESENTATION_FORM(c)))
+                              (IS_RTL_PRESENTATION_FORM(c)) || \
+                              (c) == 0xD802 || (c) == 0xD803)
 #define UTF32_CHAR_IS_BIDI(c)  ((IS_IN_BMP_RTL_BLOCK(c)) || \
                                (IS_RTL_PRESENTATION_FORM(c)) || \
                                (IS_IN_SMP_RTL_BLOCK(c)))
 #endif  /* nsBidiUtils_h__ */
--- a/layout/xul/nsTextBoxFrame.cpp
+++ b/layout/xul/nsTextBoxFrame.cpp
@@ -1,9 +1,10 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=4 sw=4 sts=4 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsTextBoxFrame.h"
 
 #include "gfx2DGlue.h"
 #include "gfxUtils.h"
@@ -29,16 +30,17 @@
 #include "nsContentUtils.h"
 #include "nsDisplayList.h"
 #include "nsCSSRendering.h"
 #include "nsIReflowCallback.h"
 #include "nsBoxFrame.h"
 #include "mozilla/Preferences.h"
 #include "nsLayoutUtils.h"
 #include "mozilla/Attributes.h"
+#include "nsUnicodeProperties.h"
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 
 #include "nsBidiUtils.h"
 #include "nsBidiPresUtils.h"
 
@@ -669,77 +671,93 @@ nsTextBoxFrame::CalculateTitleForWidth(n
           return titleWidth;
 
       aWidth -= titleWidth;
     } else {
       mCroppedTitle.Truncate(0);
       titleWidth = 0;
     }
 
-    // XXX: This whole block should probably take surrogates into account
-    // XXX and clusters!
+    using mozilla::unicode::ClusterIterator;
+    using mozilla::unicode::ClusterReverseIterator;
+
     // ok crop things
     switch (mCropType)
     {
         case CropAuto:
         case CropNone:
         case CropRight:
         {
-            nscoord cwidth;
-            nscoord twidth = 0;
-            int length = mTitle.Length();
-            int i;
-            for (i = 0; i < length; ++i) {
-                char16_t ch = mTitle.CharAt(i);
-                // still in LTR mode
-                cwidth = nsLayoutUtils::AppUnitWidthOfString(ch, *fm,
-                                                             drawTarget);
-                if (twidth + cwidth > aWidth)
+            ClusterIterator iter(mTitle.Data(), mTitle.Length());
+            const char16_t* dataBegin = iter;
+            const char16_t* pos = dataBegin;
+            nscoord charWidth;
+            nscoord totalWidth = 0;
+
+            while (!iter.AtEnd()) {
+                iter.Next();
+                const char16_t* nextPos = iter;
+                ptrdiff_t length = nextPos - pos;
+                charWidth = nsLayoutUtils::AppUnitWidthOfString(pos, length,
+                                                                *fm,
+                                                                drawTarget);
+                if (totalWidth + charWidth > aWidth) {
                     break;
+                }
 
-                twidth += cwidth;
-                if (UCS2_CHAR_IS_BIDI(ch) ) {
-                  mState |= NS_FRAME_IS_BIDI;
+                if (UCS2_CHAR_IS_BIDI(*pos)) {
+                    mState |= NS_FRAME_IS_BIDI;
                 }
+                pos = nextPos;
+                totalWidth += charWidth;
             }
 
-            if (i == 0)
+            if (pos == dataBegin) {
                 return titleWidth;
+            }
 
             // insert what character we can in.
-            nsAutoString title( mTitle );
-            title.Truncate(i);
+            nsAutoString title(mTitle);
+            title.Truncate(pos - dataBegin);
             mCroppedTitle.Insert(title, 0);
         }
         break;
 
         case CropLeft:
         {
-            nscoord cwidth;
-            nscoord twidth = 0;
-            int length = mTitle.Length();
-            int i;
-            for (i=length-1; i >= 0; --i) {
-                char16_t ch = mTitle.CharAt(i);
-                cwidth = nsLayoutUtils::AppUnitWidthOfString(ch, *fm,
-                                                             drawTarget);
-                if (twidth + cwidth > aWidth)
+            ClusterReverseIterator iter(mTitle.Data(), mTitle.Length());
+            const char16_t* dataEnd = iter;
+            const char16_t* prevPos = dataEnd;
+            nscoord charWidth;
+            nscoord totalWidth = 0;
+
+            while (!iter.AtEnd()) {
+                iter.Next();
+                const char16_t* pos = iter;
+                ptrdiff_t length = prevPos - pos;
+                charWidth = nsLayoutUtils::AppUnitWidthOfString(pos, length,
+                                                                *fm,
+                                                                drawTarget);
+                if (totalWidth + charWidth > aWidth) {
                     break;
+                }
 
-                twidth += cwidth;
-                if (UCS2_CHAR_IS_BIDI(ch) ) {
-                  mState |= NS_FRAME_IS_BIDI;
+                if (UCS2_CHAR_IS_BIDI(*pos)) {
+                    mState |= NS_FRAME_IS_BIDI;
                 }
+                prevPos = pos;
+                totalWidth += charWidth;
             }
 
-            if (i == length-1)
+            if (prevPos == dataEnd) {
                 return titleWidth;
+            }
 
             nsAutoString copy;
-            mTitle.Right(copy, length-1-i);
+            mTitle.Right(copy, dataEnd - prevPos);
             mCroppedTitle += copy;
         }
         break;
 
         case CropCenter:
         {
             nscoord stringWidth =
                 nsLayoutUtils::AppUnitWidthOfStringBidi(mTitle, this, *fm,
@@ -748,56 +766,66 @@ nsTextBoxFrame::CalculateTitleForWidth(n
                 // the entire string will fit in the maximum width
                 mCroppedTitle.Insert(mTitle, 0);
                 break;
             }
 
             // determine how much of the string will fit in the max width
             nscoord charWidth = 0;
             nscoord totalWidth = 0;
-            char16_t ch;
-            int leftPos, rightPos;
+            ClusterIterator leftIter(mTitle.Data(), mTitle.Length());
+            ClusterReverseIterator rightIter(mTitle.Data(), mTitle.Length());
+            const char16_t* dataBegin = leftIter;
+            const char16_t* dataEnd = rightIter;
+            const char16_t* leftPos = dataBegin;
+            const char16_t* rightPos = dataEnd;
+            const char16_t* pos;
+            ptrdiff_t length;
             nsAutoString leftString, rightString;
 
-            rightPos = mTitle.Length() - 1;
-            fm->SetTextRunRTL(false);
-            for (leftPos = 0; leftPos <= rightPos;) {
-                // look at the next character on the left end
-                ch = mTitle.CharAt(leftPos);
-                charWidth = nsLayoutUtils::AppUnitWidthOfString(ch, *fm,
+            while (leftPos < rightPos) {
+                leftIter.Next();
+                pos = leftIter;
+                length = pos - leftPos;
+                charWidth = nsLayoutUtils::AppUnitWidthOfString(leftPos, length,
+                                                                *fm,
                                                                 drawTarget);
-                totalWidth += charWidth;
-                if (totalWidth > aWidth)
-                    // greater than the allowable width
+                if (totalWidth + charWidth > aWidth) {
                     break;
-                leftString.Insert(ch, leftString.Length());
-
-                if (UCS2_CHAR_IS_BIDI(ch))
-                    mState |= NS_FRAME_IS_BIDI;
+                }
 
-                // look at the next character on the right end
-                if (rightPos > leftPos) {
-                    // haven't looked at this character yet
-                    ch = mTitle.CharAt(rightPos);
-                    charWidth =
-                        nsLayoutUtils::AppUnitWidthOfString(ch, *fm,
-                                                            drawTarget);
-                    totalWidth += charWidth;
-                    if (totalWidth > aWidth)
-                        // greater than the allowable width
-                        break;
-                    rightString.Insert(ch, 0);
-
-                    if (UCS2_CHAR_IS_BIDI(ch))
-                        mState |= NS_FRAME_IS_BIDI;
+                if (UCS2_CHAR_IS_BIDI(*leftPos)) {
+                    mState |= NS_FRAME_IS_BIDI;
                 }
 
-                // look at the next two characters
-                leftPos++;
-                rightPos--;
+                leftString.Append(leftPos, length);
+                leftPos = pos;
+                totalWidth += charWidth;
+
+                if (leftPos >= rightPos) {
+                    break;
+                }
+
+                rightIter.Next();
+                pos = rightIter;
+                length = rightPos - pos;
+                charWidth = nsLayoutUtils::AppUnitWidthOfString(pos, length,
+                                                                *fm,
+                                                                drawTarget);
+                if (totalWidth + charWidth > aWidth) {
+                    break;
+                }
+
+                if (UCS2_CHAR_IS_BIDI(*pos)) {
+                    mState |= NS_FRAME_IS_BIDI;
+                }
+
+                rightString.Insert(pos, 0, length);
+                rightPos = pos;
+                totalWidth += charWidth;
             }
 
             mCroppedTitle = leftString + kEllipsis + rightString;
         }
         break;
     }
 
     return nsLayoutUtils::AppUnitWidthOfStringBidi(mCroppedTitle, this, *fm,
--- a/widget/cocoa/TextInputHandler.mm
+++ b/widget/cocoa/TextInputHandler.mm
@@ -693,17 +693,17 @@ bool
 TISInputSourceWrapper::IsForRTLLanguage()
 {
   if (mIsRTL < 0) {
     // Get the input character of the 'A' key of ANSI keyboard layout.
     nsAutoString str;
     bool ret = TranslateToString(kVK_ANSI_A, 0, eKbdType_ANSI, str);
     NS_ENSURE_TRUE(ret, ret);
     char16_t ch = str.IsEmpty() ? char16_t(0) : str.CharAt(0);
-    mIsRTL = UCS2_CHAR_IS_BIDI(ch) || ch == 0xD802 || ch == 0xD803;
+    mIsRTL = UCS2_CHAR_IS_BIDI(ch);
   }
   return mIsRTL != 0;
 }
 
 bool
 TISInputSourceWrapper::IsInitializedByCurrentInputSource()
 {
   return mInputSource == ::TISCopyCurrentKeyboardInputSource();