Bug 226784 Caret display problems with Korean input methods in Windows r=VYV03354+ere, sr=roc
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 17 Dec 2008 17:05:44 +0900
changeset 22879 79136a417a3a02212320410b7c3442008de1a482
parent 22878 05bf7c30877e68432efedaed9fc75852a4e4649a
child 22880 c368f6264e50357c7ad4d922424a874746626147
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersVYV03354, roc
bugs226784
milestone1.9.2a1pre
Bug 226784 Caret display problems with Korean input methods in Windows r=VYV03354+ere, sr=roc
content/events/public/nsIPrivateTextRange.h
widget/public/nsGUIEvent.h
widget/src/windows/nsWindow.cpp
--- a/content/events/public/nsIPrivateTextRange.h
+++ b/content/events/public/nsIPrivateTextRange.h
@@ -44,16 +44,19 @@
 
 #define NS_IPRIVATETEXTRANGE_IID \
 {0xb471ab41, 0x2a79, 0x11d3, \
 { 0x9e, 0xa4, 0x0, 0x60, 0x8, 0x9f, 0xe5, 0x9b } } 
 
 class nsIPrivateTextRange : public nsISupports {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IPRIVATETEXTRANGE_IID)
+
+  // Note that the range array may not specify a caret position; in that
+  // case there will be no range of type TEXTRANGE_CARETPOSITION in the array.
   enum {
     TEXTRANGE_CARETPOSITION = 1,
     TEXTRANGE_RAWINPUT = 2,
     TEXTRANGE_SELECTEDRAWTEXT = 3,
     TEXTRANGE_CONVERTEDTEXT = 4,
     TEXTRANGE_SELECTEDCONVERTEDTEXT = 5
   };
 
--- a/widget/public/nsGUIEvent.h
+++ b/widget/public/nsGUIEvent.h
@@ -860,16 +860,19 @@ public:
     : nsInputEvent(isTrusted, msg, w, NS_TEXT_EVENT),
       theText(nsnull), rangeCount(0), rangeArray(nsnull), isChar(PR_FALSE)
   {
   }
 
   const PRUnichar*  theText;
   nsTextEventReply  theReply;
   PRUint32          rangeCount;
+  // Note that the range array may not specify a caret position; in that
+  // case there will be no range of type NS_TEXTRANGE_CARETPOSITION in the
+  // array.
   nsTextRangeArray  rangeArray;
   PRBool            isChar;
 };
 
 class nsCompositionEvent : public nsInputEvent
 {
 public:
   nsCompositionEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w)
@@ -1380,22 +1383,22 @@ enum nsDragDropEventStatus {
 #define NS_VK_BACK_QUOTE     nsIDOMKeyEvent::DOM_VK_BACK_QUOTE
 #define NS_VK_OPEN_BRACKET   nsIDOMKeyEvent::DOM_VK_OPEN_BRACKET
 #define NS_VK_BACK_SLASH     nsIDOMKeyEvent::DOM_VK_BACK_SLASH
 #define NS_VK_CLOSE_BRACKET  nsIDOMKeyEvent::DOM_VK_CLOSE_BRACKET
 #define NS_VK_QUOTE          nsIDOMKeyEvent::DOM_VK_QUOTE
 
 #define NS_VK_META           nsIDOMKeyEvent::DOM_VK_META
 
-// IME Constants  -- keep in synch with nsIDOMTextRange.h
-#define NS_TEXTRANGE_CARETPOSITION				0x01
-#define NS_TEXTRANGE_RAWINPUT					0X02
-#define NS_TEXTRANGE_SELECTEDRAWTEXT			0x03
-#define NS_TEXTRANGE_CONVERTEDTEXT				0x04
-#define NS_TEXTRANGE_SELECTEDCONVERTEDTEXT		0x05
+// IME Constants  -- keep in synch with nsIPrivateTextRange.h
+#define NS_TEXTRANGE_CARETPOSITION         0x01
+#define NS_TEXTRANGE_RAWINPUT              0x02
+#define NS_TEXTRANGE_SELECTEDRAWTEXT       0x03
+#define NS_TEXTRANGE_CONVERTEDTEXT         0x04
+#define NS_TEXTRANGE_SELECTEDCONVERTEDTEXT 0x05
 
 inline PRBool NS_TargetUnfocusedEventToLastFocusedContent(nsEvent* aEvent)
 {
 #if defined(MOZ_X11) || defined(XP_MACOSX)
   // bug 52416 (MOZ_X11)
   // Lookup region (candidate window) of UNIX IME grabs
   // input focus from Mozilla but wants to send IME event
   // to redraw pre-edit (composed) string
--- a/widget/src/windows/nsWindow.cpp
+++ b/widget/src/windows/nsWindow.cpp
@@ -292,17 +292,21 @@ PRBool     nsWindow::sIMEIsStatusChanged
 
 nsString*  nsWindow::sIMECompUnicode           = NULL;
 PRUint8*   nsWindow::sIMEAttributeArray        = NULL;
 PRInt32    nsWindow::sIMEAttributeArrayLength  = 0;
 PRInt32    nsWindow::sIMEAttributeArraySize    = 0;
 PRUint32*  nsWindow::sIMECompClauseArray       = NULL;
 PRInt32    nsWindow::sIMECompClauseArrayLength = 0;
 PRInt32    nsWindow::sIMECompClauseArraySize   = 0;
-long       nsWindow::sIMECursorPosition        = 0;
+
+// Some IMEs (e.g., the standard IME for Korean) don't have caret position,
+// then, we should not set caret position to text event.
+#define NO_IME_CARET -1
+long       nsWindow::sIMECursorPosition        = NO_IME_CARET;
 
 RECT*      nsWindow::sIMECompCharPos           = nsnull;
 
 PRBool     nsWindow::gSwitchKeyboardLayout     = PR_FALSE;
 
 static KeyboardLayout gKbdLayout;
 
 TriStateBool nsWindow::sCanQuit = TRI_UNKNOWN;
@@ -6681,17 +6685,17 @@ nsWindow::HandleTextEvent(HIMC hIMEConte
       CreateCaret(mWnd, nsnull, 1, 1);
       SetCaretPos(candForm.ptCurrentPos.x, candForm.ptCurrentPos.y);
       DestroyCaret();
     }
 
     // Record previous composing char position
     // The cursor is always on the right char before it, but not necessarily on the
     // left of next char, as what happens in wrapping.
-    if (sIMECursorPosition && sIMECompCharPos &&
+    if (sIMECursorPosition > 0 && sIMECompCharPos &&
         sIMECursorPosition < IME_MAX_CHAR_POS) {
       sIMECompCharPos[sIMECursorPosition-1].right = cursorPosition.x;
       sIMECompCharPos[sIMECursorPosition-1].top = cursorPosition.y;
       sIMECompCharPos[sIMECursorPosition-1].bottom = cursorPosition.YMost();
       if (sIMECompCharPos[sIMECursorPosition-1].top != cursorPosition.y) {
         // wrapping, invalidate left position
         sIMECompCharPos[sIMECursorPosition-1].left = -1;
       }
@@ -6818,78 +6822,72 @@ static PRUint32 PlatformToNSAttr(PRUint8
       return NS_TEXTRANGE_SELECTEDRAWTEXT;
     case ATTR_TARGET_CONVERTED:
       return NS_TEXTRANGE_SELECTEDCONVERTEDTEXT;
     default:
       NS_ASSERTION(PR_FALSE, "unknown attribute");
       return NS_TEXTRANGE_CARETPOSITION;
   }
 }
-//
-// This function converts the composition string (CGS_COMPSTR) into Unicode while mapping the
-//  attribute (GCS_ATTR) string t
+
+
 void
-nsWindow::GetTextRangeList(PRUint32* textRangeListLengthResult,nsTextRangeArray* textRangeListResult)
+nsWindow::GetTextRangeList(PRUint32* aListLength,
+                           nsTextRangeArray* textRangeListResult)
 {
   NS_ASSERTION(sIMECompUnicode, "sIMECompUnicode is null");
 
   if (!sIMECompUnicode)
     return;
 
   long maxlen = sIMECompUnicode->Length();
   long cursor = sIMECursorPosition;
   NS_ASSERTION(cursor <= maxlen, "wrong cursor position");
   if (cursor > maxlen)
     cursor = maxlen;
 
-  //
-  // figure out the ranges from the compclause string
-  //
   if (sIMECompClauseArrayLength == 0) {
-    *textRangeListLengthResult = 2;
-    *textRangeListResult = new nsTextRange[2];
+    // Some IMEs don't return clause array information, then, we assume that
+    // all characters in the composition string are in one clause.
+    *aListLength = 1;
+    // need one more room for caret
+    *textRangeListResult = new nsTextRange[*aListLength + 1];
     (*textRangeListResult)[0].mStartOffset = 0;
     (*textRangeListResult)[0].mEndOffset = maxlen;
     (*textRangeListResult)[0].mRangeType = NS_TEXTRANGE_RAWINPUT;
-    (*textRangeListResult)[1].mStartOffset = cursor;
-    (*textRangeListResult)[1].mEndOffset = cursor;
-    (*textRangeListResult)[1].mRangeType = NS_TEXTRANGE_CARETPOSITION;
   } else {
-    *textRangeListLengthResult = sIMECompClauseArrayLength;
-
-    //
-    //  allocate the offset array
-    //
-    *textRangeListResult = new nsTextRange[*textRangeListLengthResult];
-
-    //
-    // figure out the cursor position
-    //
-    (*textRangeListResult)[0].mStartOffset = cursor;
-    (*textRangeListResult)[0].mEndOffset = cursor;
-    (*textRangeListResult)[0].mRangeType = NS_TEXTRANGE_CARETPOSITION;
-
-    //
-    // iterate over the attributes and convert them into unicode 
-    //
+    *aListLength = sIMECompClauseArrayLength - 1;
+
+    // need one more room for caret
+    *textRangeListResult = new nsTextRange[*aListLength + 1];
+
+    // iterate over the attributes
     int lastOffset = 0;
-    for(int i = 1; i < sIMECompClauseArrayLength; i++) {
-      long current = sIMECompClauseArray[i];
+    for (int i = 0; i < *aListLength; i++) {
+      long current = sIMECompClauseArray[i + 1];
       NS_ASSERTION(current <= maxlen, "wrong offset");
       if(current > maxlen)
         current = maxlen;
 
       (*textRangeListResult)[i].mRangeType = 
         PlatformToNSAttr(sIMEAttributeArray[lastOffset]);
       (*textRangeListResult)[i].mStartOffset = lastOffset;
       (*textRangeListResult)[i].mEndOffset = current;
 
       lastOffset = current;
     } // for
   } // if else
+
+  if (cursor == NO_IME_CARET)
+    return;
+
+  (*textRangeListResult)[*aListLength].mStartOffset = cursor;
+  (*textRangeListResult)[*aListLength].mEndOffset = cursor;
+  (*textRangeListResult)[*aListLength].mRangeType = NS_TEXTRANGE_CARETPOSITION;
+  ++(*aListLength);
 }
 
 
 //==========================================================================
 BOOL nsWindow::OnInputLangChange(HKL aHKL)
 {
 #ifdef KE_DEBUG
   printf("OnInputLanguageChange\n");
@@ -7145,22 +7143,33 @@ BOOL nsWindow::OnIMEComposition(LPARAM a
 
     // attrStrLen may be negative. I.e., ImmGetCompositionStringW may return an
     // error code.
     sIMEAttributeArrayLength = PR_MAX(0, attrStrLen);
 
     //--------------------------------------------------------
     // 4. Get GCS_CURSOPOS
     //--------------------------------------------------------
-    sIMECursorPosition = ::ImmGetCompositionStringW(hIMEContext, GCS_CURSORPOS, NULL, 0);
+    // Some IMEs (e.g., the standard IME for Korean) don't have caret position.
+    if (aGCS & GCS_CURSORPOS) {
+      sIMECursorPosition =
+        ::ImmGetCompositionStringW(hIMEContext, GCS_CURSORPOS, NULL, 0);
+      if (sIMECursorPosition < 0)
+        sIMECursorPosition = NO_IME_CARET; // The result is error
+    } else {
+      sIMECursorPosition = NO_IME_CARET;
+    }
 
     NS_ASSERTION(sIMECursorPosition <= (long)sIMECompUnicode->Length(), "illegal pos");
 
 #ifdef DEBUG_IME
-    printf("sIMECursorPosition(Unicode): %d\n", sIMECursorPosition);
+    if (aGCS & GCS_CURSORPOS)
+      printf("sIMECursorPosition(Unicode): %d\n", sIMECursorPosition);
+    else
+      printf("sIMECursorPosition: None\n");
 #endif
     //--------------------------------------------------------
     // 5. Send the text event
     //--------------------------------------------------------
     HandleTextEvent(hIMEContext);
     result = PR_TRUE;
   }
   if (!result) {