[RICHED20]
authorAleksey Bragin <aleksey@reactos.org>
Sun, 21 Mar 2010 22:44:26 +0000 (22:44 +0000)
committerAleksey Bragin <aleksey@reactos.org>
Sun, 21 Mar 2010 22:44:26 +0000 (22:44 +0000)
- Sync riched20 with Wine-1.1.41.

svn path=/trunk/; revision=46328

20 files changed:
reactos/dll/win32/riched20/caret.c
reactos/dll/win32/riched20/clipboard.c
reactos/dll/win32/riched20/editor.c
reactos/dll/win32/riched20/editor.h
reactos/dll/win32/riched20/editstr.h
reactos/dll/win32/riched20/list.c
reactos/dll/win32/riched20/paint.c
reactos/dll/win32/riched20/para.c
reactos/dll/win32/riched20/reader.c
reactos/dll/win32/riched20/richole.c
reactos/dll/win32/riched20/rtf.h
reactos/dll/win32/riched20/run.c
reactos/dll/win32/riched20/style.c
reactos/dll/win32/riched20/table.c
reactos/dll/win32/riched20/txthost.c
reactos/dll/win32/riched20/txtsrv.c
reactos/dll/win32/riched20/undo.c
reactos/dll/win32/riched20/wrap.c
reactos/dll/win32/riched20/writer.c
reactos/media/doc/README.WINE

index 1cb44bc..a72a42b 100644 (file)
 
 WINE_DEFAULT_DEBUG_CHANNEL(richedit);
 
-static BOOL
-ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs);
+void ME_SetCursorToStart(ME_TextEditor *editor, ME_Cursor *cursor)
+{
+  cursor->pPara = editor->pBuffer->pFirst->member.para.next_para;
+  cursor->pRun = ME_FindItemFwd(cursor->pPara, diRun);
+  cursor->nOffset = 0;
+}
 
-void ME_GetSelection(ME_TextEditor *editor, int *from, int *to)
+static void ME_SetCursorToEnd(ME_TextEditor *editor, ME_Cursor *cursor)
 {
-  *from = ME_GetCursorOfs(editor, 0);
-  *to =   ME_GetCursorOfs(editor, 1);
-  
+  cursor->pPara = editor->pBuffer->pLast->member.para.prev_para;
+  cursor->pRun = ME_FindItemBack(editor->pBuffer->pLast, diRun);
+  cursor->nOffset = 0;
+}
+
+
+int ME_GetSelectionOfs(ME_TextEditor *editor, int *from, int *to)
+{
+  *from = ME_GetCursorOfs(&editor->pCursors[0]);
+  *to =   ME_GetCursorOfs(&editor->pCursors[1]);
+
   if (*from > *to)
   {
     int tmp = *from;
     *from = *to;
-    *to = tmp;    
+    *to = tmp;
+    return 1;
+  }
+  return 0;
+}
+
+int ME_GetSelection(ME_TextEditor *editor, ME_Cursor **from, ME_Cursor **to)
+{
+  if (ME_GetCursorOfs(&editor->pCursors[0]) < ME_GetCursorOfs(&editor->pCursors[1]))
+  {
+    *from = &editor->pCursors[0];
+    *to = &editor->pCursors[1];
+    return 0;
+  } else {
+    *from = &editor->pCursors[1];
+    *to = &editor->pCursors[0];
+    return 1;
   }
 }
 
 int ME_GetTextLength(ME_TextEditor *editor)
 {
-  ME_DisplayItem *pLast = editor->pBuffer->pLast;
-  return ME_CharOfsFromRunOfs(editor, pLast->member.para.prev_para,
-                              ME_FindItemBack(pLast, diRun), 0);
+  ME_Cursor cursor;
+  ME_SetCursorToEnd(editor, &cursor);
+  return ME_GetCursorOfs(&cursor);
 }
 
 
@@ -63,8 +91,10 @@ int ME_GetTextLengthEx(ME_TextEditor *editor, const GETTEXTLENGTHEX *how)
         && (how->flags & GTL_USECRLF)
         && !editor->bEmulateVersion10) /* Ignore GTL_USECRLF flag in 1.0 emulation */
     length += editor->nParagraphs - 1;
-  
-  if (how->flags & GTL_NUMBYTES)
+
+  if (how->flags & GTL_NUMBYTES ||
+      (how->flags & GTL_PRECISE &&     /* GTL_PRECISE seems to imply GTL_NUMBYTES */
+       !(how->flags & GTL_NUMCHARS)))  /* unless GTL_NUMCHARS is given */
   {
     CPINFO cpinfo;
     
@@ -95,12 +125,8 @@ int ME_SetSelection(ME_TextEditor *editor, int from, int to)
   /* select all */
   if (from == 0 && to == -1)
   {
-    editor->pCursors[1].pPara = editor->pBuffer->pFirst->member.para.next_para;
-    editor->pCursors[1].pRun = ME_FindItemFwd(editor->pCursors[1].pPara, diRun);
-    editor->pCursors[1].nOffset = 0;
-    editor->pCursors[0].pPara = editor->pBuffer->pLast->member.para.prev_para;
-    editor->pCursors[0].pRun = ME_FindItemBack(editor->pBuffer->pLast, diRun);
-    editor->pCursors[0].nOffset = 0;
+    ME_SetCursorToStart(editor, &editor->pCursors[1]);
+    ME_SetCursorToEnd(editor, &editor->pCursors[0]);
     ME_InvalidateSelection(editor);
     ME_ClearTempStyle(editor);
     return len + 1;
@@ -119,7 +145,7 @@ int ME_SetSelection(ME_TextEditor *editor, int from, int to)
     if (from < 0)
     {
       int start, end;
-      ME_GetSelection(editor, &start, &end);
+      ME_GetSelectionOfs(editor, &start, &end);
       editor->pCursors[1] = editor->pCursors[0];
       ME_Repaint(editor);
       ME_ClearTempStyle(editor);
@@ -148,9 +174,7 @@ int ME_SetSelection(ME_TextEditor *editor, int from, int to)
 
   if (selectionEnd)
   {
-    editor->pCursors[0].pPara = editor->pBuffer->pLast->member.para.prev_para;
-    editor->pCursors[0].pRun = ME_FindItemBack(editor->pBuffer->pLast, diRun);
-    editor->pCursors[0].nOffset = 0;
+    ME_SetCursorToEnd(editor, &editor->pCursors[0]);
     editor->pCursors[1] = editor->pCursors[0];
     ME_InvalidateSelection(editor);
     ME_ClearTempStyle(editor);
@@ -158,7 +182,8 @@ int ME_SetSelection(ME_TextEditor *editor, int from, int to)
   }
 
   ME_CursorFromCharOfs(editor, from, &editor->pCursors[1]);
-  ME_CursorFromCharOfs(editor, to, &editor->pCursors[0]);
+  editor->pCursors[0] = editor->pCursors[1];
+  ME_MoveCursorChars(editor, &editor->pCursors[0], to - from);
   /* Selection is not allowed in the middle of an end paragraph run. */
   if (editor->pCursors[1].pRun->member.run.nFlags & MERF_ENDPARA)
     editor->pCursors[1].nOffset = 0;
@@ -258,23 +283,22 @@ void ME_HideCaret(ME_TextEditor *ed)
   }
 }
 
-BOOL ME_InternalDeleteText(ME_TextEditor *editor, int nOfs, int nChars,
-                           BOOL bForce)
+BOOL ME_InternalDeleteText(ME_TextEditor *editor, ME_Cursor *start,
+                           int nChars, BOOL bForce)
 {
-  ME_Cursor c;
+  ME_Cursor c = *start;
+  int nOfs = ME_GetCursorOfs(start);
   int shift = 0;
   int totalChars = nChars;
   ME_DisplayItem *start_para;
 
   /* Prevent deletion past last end of paragraph run. */
   nChars = min(nChars, ME_GetTextLength(editor) - nOfs);
-
-  ME_CursorFromCharOfs(editor, nOfs, &c);
   start_para = c.pPara;
 
   if (!bForce)
   {
-    ME_ProtectPartialTableDeletion(editor, nOfs, &nChars);
+    ME_ProtectPartialTableDeletion(editor, &c, &nChars);
     if (nChars == 0)
       return FALSE;
   }
@@ -289,8 +313,7 @@ BOOL ME_InternalDeleteText(ME_TextEditor *editor, int nOfs, int nChars,
     {
       /* We aren't deleting anything in this run, so we will go back to the
        * last run we are deleting text in. */
-      c.pRun = ME_FindItemBack(c.pRun, diRun);
-      c.pPara = ME_GetParagraph(c.pRun);
+      ME_PrevRun(&c.pPara, &c.pRun);
       c.nOffset = c.pRun->member.run.strText->nLen;
     }
     run = &c.pRun->member.run;
@@ -422,12 +445,12 @@ BOOL ME_InternalDeleteText(ME_TextEditor *editor, int nOfs, int nChars,
 }
 
 BOOL ME_DeleteTextAtCursor(ME_TextEditor *editor, int nCursor, int nChars)
-{  
+{
   assert(nCursor>=0 && nCursor<editor->nCursors);
   /* text operations set modified state */
   editor->nModifyStep = 1;
-  return ME_InternalDeleteText(editor, ME_GetCursorOfs(editor, nCursor), nChars,
-                               FALSE);
+  return ME_InternalDeleteText(editor, &editor->pCursors[nCursor],
+                               nChars, FALSE);
 }
 
 static ME_DisplayItem *
@@ -459,7 +482,7 @@ void ME_InsertOLEFromCursor(ME_TextEditor *editor, const REOBJECT* reo, int nCur
                                        MERF_GRAPHICS);
   di->member.run.ole_obj = ALLOC_OBJ(*reo);
   ME_CopyReObject(di->member.run.ole_obj, reo);
-  ME_SendSelChange(editor);
+  ME_ReleaseStyle(pStyle);
 }
 
 
@@ -475,7 +498,7 @@ void ME_InsertEndRowFromCursor(ME_TextEditor *editor, int nCursor)
 
   di = ME_InternalInsertTextFromCursor(editor, nCursor, &space, 1, pStyle,
                                        MERF_ENDROW);
-  ME_SendSelChange(editor);
+  ME_ReleaseStyle(pStyle);
 }
 
 
@@ -565,7 +588,7 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
         /* ME_SplitParagraph increases style refcount */
         tp = ME_SplitParagraph(editor, p->pRun, p->pRun->member.run.style, eol_str, 0);
         p->pRun = ME_FindItemFwd(tp, diRun);
-        p->pPara = ME_GetParagraph(p->pRun);
+        p->pPara = tp;
         end_run = ME_FindItemBack(tp, diRun);
         ME_ReleaseStyle(end_run->member.run.style);
         end_run->member.run.style = tmp_style;
@@ -577,77 +600,85 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
   }
 }
 
-
-static BOOL
-ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs)
+/* Move the cursor nRelOfs characters (either forwards or backwards)
+ *
+ * returns the actual number of characters moved.
+ **/
+int ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs)
 {
-  ME_DisplayItem *pRun = pCursor->pRun;
-
-  if (nRelOfs == -1)
+  cursor->nOffset += nRelOfs;
+  if (cursor->nOffset < 0)
   {
-    if (!pCursor->nOffset)
+    cursor->nOffset += cursor->pRun->member.run.nCharOfs;
+    if (cursor->nOffset >= 0)
     {
-      ME_DisplayItem *pPara = pCursor->pPara;
+      /* new offset in the same paragraph */
       do {
-        pRun = ME_FindItemBack(pRun, diRunOrParagraph);
-        assert(pRun);
-        switch (pRun->type)
-        {
-          case diRun:
-            break;
-          case diParagraph:
-            pPara = pRun;
-            if (pPara->member.para.prev_para->type == diTextStart)
-              return FALSE;
-            pRun = ME_FindItemBack(pPara, diRunOrParagraph);
-            pPara = pPara->member.para.prev_para;
-            /* every paragraph ought to have at least one run */
-            assert(pRun && pRun->type == diRun);
-            assert(pRun->member.run.nFlags & MERF_ENDPARA);
-            break;
-          default:
-            assert(pRun->type != diRun && pRun->type != diParagraph);
-            return FALSE;
-        }
-      } while (RUN_IS_HIDDEN(&pRun->member.run) ||
-               pRun->member.run.nFlags & MERF_HIDDEN);
-      pCursor->pPara = pPara;
-      pCursor->pRun = pRun;
-      if (pRun->member.run.nFlags & MERF_ENDPARA)
-        pCursor->nOffset = 0;
-      else
-        pCursor->nOffset = pRun->member.run.strText->nLen;
+        cursor->pRun = ME_FindItemBack(cursor->pRun, diRun);
+      } while (cursor->nOffset < cursor->pRun->member.run.nCharOfs);
+      cursor->nOffset -= cursor->pRun->member.run.nCharOfs;
+      return nRelOfs;
     }
 
-    if (pCursor->nOffset)
-      pCursor->nOffset = pCursor->nOffset + nRelOfs;
-    return TRUE;
-  }
-  else
-  {
-    if (!(pRun->member.run.nFlags & MERF_ENDPARA))
+    cursor->nOffset += cursor->pPara->member.para.nCharOfs;
+    if (cursor->nOffset <= 0)
     {
-      int new_ofs = pCursor->nOffset + nRelOfs;
+      /* moved to the start of the text */
+      nRelOfs -= cursor->nOffset;
+      ME_SetCursorToStart(editor, cursor);
+      return nRelOfs;
+    }
 
-      if (new_ofs < pRun->member.run.strText->nLen)
-      {
-        pCursor->nOffset = new_ofs;
-        return TRUE;
-      }
+    /* new offset in a previous paragraph */
+    do {
+      cursor->pPara = cursor->pPara->member.para.prev_para;
+    } while (cursor->nOffset < cursor->pPara->member.para.nCharOfs);
+    cursor->nOffset -= cursor->pPara->member.para.nCharOfs;
+
+    cursor->pRun = ME_FindItemBack(cursor->pPara->member.para.next_para, diRun);
+    while (cursor->nOffset < cursor->pRun->member.run.nCharOfs) {
+      cursor->pRun = ME_FindItemBack(cursor->pRun, diRun);
     }
+    cursor->nOffset -= cursor->pRun->member.run.nCharOfs;
+  } else if (cursor->nOffset >= cursor->pRun->member.run.strText->nLen) {
+    ME_DisplayItem *next_para;
+    int new_offset;
+
+    new_offset = ME_GetCursorOfs(cursor);
+    next_para = cursor->pPara->member.para.next_para;
+    if (new_offset < next_para->member.para.nCharOfs)
+    {
+      /* new offset in the same paragraph */
+      do {
+        cursor->nOffset -= cursor->pRun->member.run.strText->nLen;
+        cursor->pRun = ME_FindItemFwd(cursor->pRun, diRun);
+      } while (cursor->nOffset >= cursor->pRun->member.run.strText->nLen);
+      return nRelOfs;
+    }
+
+    if (new_offset >= ME_GetTextLength(editor))
+    {
+      /* new offset at the end of the text */
+      ME_SetCursorToEnd(editor, cursor);
+      nRelOfs -= new_offset - ME_GetTextLength(editor);
+      return nRelOfs;
+    }
+
+    /* new offset in a following paragraph */
     do {
-      pRun = ME_FindItemFwd(pRun, diRun);
-    } while (pRun && (RUN_IS_HIDDEN(&pRun->member.run) ||
-                      pRun->member.run.nFlags & MERF_HIDDEN));
-    if (pRun)
+      cursor->pPara = next_para;
+      next_para = next_para->member.para.next_para;
+    } while (new_offset >= next_para->member.para.nCharOfs);
+
+    cursor->nOffset = new_offset - cursor->pPara->member.para.nCharOfs;
+    cursor->pRun = ME_FindItemFwd(cursor->pPara, diRun);
+    while (cursor->nOffset >= cursor->pRun->member.run.strText->nLen)
     {
-      pCursor->pPara = ME_GetParagraph(pRun);
-      pCursor->pRun = pRun;
-      pCursor->nOffset = 0;
-      return TRUE;
+      cursor->nOffset -= cursor->pRun->member.run.strText->nLen;
+      cursor->pRun = ME_FindItemFwd(cursor->pRun, diRun);
     }
-  }
-  return FALSE;
+  } /* else new offset is in the same run */
+  return nRelOfs;
 }
 
 
@@ -655,8 +686,9 @@ static BOOL
 ME_MoveCursorWords(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs)
 {
   ME_DisplayItem *pRun = cursor->pRun, *pOtherRun;
+  ME_DisplayItem *pPara = cursor->pPara;
   int nOffset = cursor->nOffset;
-  
+
   if (nRelOfs == -1)
   {
     /* Backward movement */
@@ -684,14 +716,16 @@ ME_MoveCursorWords(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs)
       {
         if (cursor->pRun == pRun && cursor->nOffset == 0)
         {
+          pPara = pOtherRun;
           /* Skip empty start of table row paragraph */
-          if (pOtherRun->member.para.prev_para->member.para.nFlags & MEPF_ROWSTART)
-            pOtherRun = pOtherRun->member.para.prev_para;
+          if (pPara->member.para.prev_para->member.para.nFlags & MEPF_ROWSTART)
+            pPara = pPara->member.para.prev_para;
           /* Paragraph breaks are treated as separate words */
-          if (pOtherRun->member.para.prev_para->type == diTextStart)
+          if (pPara->member.para.prev_para->type == diTextStart)
             return FALSE;
 
-          pRun = ME_FindItemBack(pOtherRun, diRun);
+          pRun = ME_FindItemBack(pPara, diRun);
+          pPara = pPara->member.para.prev_para;
         }
         break;
       }
@@ -723,8 +757,10 @@ ME_MoveCursorWords(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs)
       {
         if (pOtherRun->member.para.nFlags & MEPF_ROWSTART)
             pOtherRun = pOtherRun->member.para.next_para;
-        if (cursor->pRun == pRun)
-          pRun = ME_FindItemFwd(pOtherRun, diRun);
+        if (cursor->pRun == pRun) {
+          pPara = pOtherRun;
+          pRun = ME_FindItemFwd(pPara, diRun);
+        }
         nOffset = 0;
         break;
       }
@@ -737,7 +773,7 @@ ME_MoveCursorWords(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs)
       }
     }
   }
-  cursor->pPara = ME_GetParagraph(pRun);
+  cursor->pPara = pPara;
   cursor->pRun = pRun;
   cursor->nOffset = nOffset;
   return TRUE;
@@ -793,12 +829,8 @@ ME_SelectByType(ME_TextEditor *editor, ME_SelectionType selectionType)
     case stDocument:
       /* Select everything with cursor anchored from the start of the text */
       editor->nSelectionType = stDocument;
-      editor->pCursors[1].pPara = editor->pBuffer->pFirst->member.para.next_para;
-      editor->pCursors[1].pRun = ME_FindItemFwd(editor->pCursors[1].pPara, diRun);
-      editor->pCursors[1].nOffset = 0;
-      editor->pCursors[0].pPara = editor->pBuffer->pLast->member.para.prev_para;
-      editor->pCursors[0].pRun = ME_FindItemBack(editor->pBuffer->pLast, diRun);
-      editor->pCursors[0].nOffset = 0;
+      ME_SetCursorToStart(editor, &editor->pCursors[1]);
+      ME_SetCursorToEnd(editor, &editor->pCursors[0]);
       break;
     default: assert(0);
   }
@@ -807,11 +839,10 @@ ME_SelectByType(ME_TextEditor *editor, ME_SelectionType selectionType)
   editor->pCursors[3] = editor->pCursors[1];
 }
 
-int ME_GetCursorOfs(ME_TextEditor *editor, int nCursor)
+int ME_GetCursorOfs(const ME_Cursor *cursor)
 {
-  ME_Cursor *pCursor = &editor->pCursors[nCursor];
-  return pCursor->pPara->member.para.nCharOfs
-         + pCursor->pRun->member.run.nCharOfs + pCursor->nOffset;
+  return cursor->pPara->member.para.nCharOfs
+         + cursor->pRun->member.run.nCharOfs + cursor->nOffset;
 }
 
 /* Helper function for ME_FindPixelPos to find paragraph within tables */
@@ -862,9 +893,9 @@ static BOOL ME_ReturnFoundPos(ME_TextEditor *editor, ME_DisplayItem *found,
     rx = 0;
   result->pRun = found;
   result->nOffset = ME_CharFromPointCursor(editor, rx, &found->member.run);
-  if (editor->pCursors[0].nOffset == found->member.run.strText->nLen && rx)
+  if (result->nOffset == found->member.run.strText->nLen && rx)
   {
-    result->pRun = ME_FindItemFwd(editor->pCursors[0].pRun, diRun);
+    result->pRun = ME_FindItemFwd(result->pRun, diRun);
     result->nOffset = 0;
   }
   result->pPara = ME_GetParagraph(result->pRun);
@@ -975,30 +1006,32 @@ static BOOL ME_FindPixelPos(ME_TextEditor *editor, int x, int y,
 }
 
 
-/* Returns the character offset closest to the pixel position
+/* Sets the cursor to the position closest to the pixel position
  *
  * x & y are pixel positions in client coordinates.
  *
  * isExact will be set to TRUE if the run is directly under the pixel
  * position, FALSE if it not, unless isExact is set to NULL.
+ *
+ * return FALSE if outside client area and the cursor is not set,
+ * otherwise TRUE is returned.
  */
-int ME_CharFromPos(ME_TextEditor *editor, int x, int y, BOOL *isExact)
+BOOL ME_CharFromPos(ME_TextEditor *editor, int x, int y,
+                    ME_Cursor *cursor, BOOL *isExact)
 {
-  ME_Cursor cursor;
   RECT rc;
   BOOL bResult;
 
   ITextHost_TxGetClientRect(editor->texthost, &rc);
   if (x < 0 || y < 0 || x >= rc.right || y >= rc.bottom) {
     if (isExact) *isExact = FALSE;
-    return -1;
+    return FALSE;
   }
   x += editor->horz_si.nPos;
   y += editor->vert_si.nPos;
-  bResult = ME_FindPixelPos(editor, x, y, &cursor, NULL);
+  bResult = ME_FindPixelPos(editor, x, y, cursor, NULL);
   if (isExact) *isExact = bResult;
-  return cursor.pPara->member.para.nCharOfs
-         + cursor.pRun->member.run.nCharOfs + cursor.nOffset;
+  return TRUE;
 }
 
 
@@ -1019,9 +1052,9 @@ static void ME_ExtendAnchorSelection(ME_TextEditor *editor)
   int curOfs, anchorStartOfs, anchorEndOfs;
   if (editor->nSelectionType == stPosition || editor->nSelectionType == stDocument)
       return;
-  curOfs = ME_GetCursorOfs(editor, 0);
-  anchorStartOfs = ME_GetCursorOfs(editor, 3);
-  anchorEndOfs = ME_GetCursorOfs(editor, 2);
+  curOfs = ME_GetCursorOfs(&editor->pCursors[0]);
+  anchorStartOfs = ME_GetCursorOfs(&editor->pCursors[3]);
+  anchorEndOfs = ME_GetCursorOfs(&editor->pCursors[2]);
 
   tmp_cursor = editor->pCursors[0];
   editor->pCursors[0] = editor->pCursors[2];
@@ -1231,14 +1264,14 @@ static void
 ME_MoveCursorLines(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs)
 {
   ME_DisplayItem *pRun = pCursor->pRun;
-  ME_DisplayItem *pItem, *pOldPara, *pNewPara;
+  ME_DisplayItem *pOldPara = pCursor->pPara;
+  ME_DisplayItem *pItem, *pNewPara;
   int x = ME_GetXForArrow(editor, pCursor);
 
   if (editor->bCaretAtEnd && !pCursor->nOffset)
-    pRun = ME_FindItemBack(pRun, diRun);
-  if (!pRun)
-    return;
-  pOldPara = ME_GetParagraph(pRun);
+    if (!ME_PrevRun(&pOldPara, &pRun))
+      return;
+
   if (nRelOfs == -1)
   {
     /* start of this row */
@@ -1313,9 +1346,7 @@ static void ME_ArrowPageUp(ME_TextEditor *editor, ME_Cursor *pCursor)
 
   if (editor->vert_si.nPos < p->member.row.nHeight)
   {
-    pCursor->pPara = editor->pBuffer->pFirst->member.para.next_para;
-    pCursor->pRun = ME_FindItemFwd(pCursor->pPara, diRun);
-    pCursor->nOffset = 0;
+    ME_SetCursorToStart(editor, pCursor);
     editor->bCaretAtEnd = FALSE;
     /* Native clears seems to clear this x value on page up at the top
      * of the text, but not on page down at the end of the text.
@@ -1380,9 +1411,7 @@ static void ME_ArrowPageDown(ME_TextEditor *editor, ME_Cursor *pCursor)
 
   if (editor->vert_si.nPos >= y - editor->sizeWindow.cy)
   {
-    pCursor->pPara = editor->pBuffer->pLast->member.para.prev_para;
-    pCursor->pRun = ME_FindItemBack(editor->pBuffer->pLast, diRun);
-    pCursor->nOffset = 0;
+    ME_SetCursorToEnd(editor, pCursor);
     editor->bCaretAtEnd = FALSE;
   } else {
     ME_DisplayItem *pRun = pCursor->pRun;
@@ -1451,9 +1480,7 @@ static void ME_ArrowHome(ME_TextEditor *editor, ME_Cursor *pCursor)
 
 static void ME_ArrowCtrlHome(ME_TextEditor *editor, ME_Cursor *pCursor)
 {
-  pCursor->pPara = editor->pBuffer->pFirst->member.para.next_para;
-  pCursor->pRun = ME_FindItemFwd(pCursor->pPara, diRun);
-  pCursor->nOffset = 0;
+  ME_SetCursorToStart(editor, pCursor);
   editor->bCaretAtEnd = FALSE;
 }
 
@@ -1484,33 +1511,21 @@ static void ME_ArrowEnd(ME_TextEditor *editor, ME_Cursor *pCursor)
 
 static void ME_ArrowCtrlEnd(ME_TextEditor *editor, ME_Cursor *pCursor)
 {
-  pCursor->pPara = editor->pBuffer->pLast->member.para.prev_para;
-  pCursor->pRun = ME_FindItemBack(editor->pBuffer->pLast, diRun);
-  assert(pCursor->pRun->member.run.nFlags & MERF_ENDPARA);
-  pCursor->nOffset = 0;
+  ME_SetCursorToEnd(editor, pCursor);
   editor->bCaretAtEnd = FALSE;
 }
 
 BOOL ME_IsSelection(ME_TextEditor *editor)
 {
-  return memcmp(&editor->pCursors[0], &editor->pCursors[1], sizeof(ME_Cursor))!=0;
-}
-
-static int ME_GetSelCursor(ME_TextEditor *editor, int dir)
-{
-  int cdir = ME_GetCursorOfs(editor, 0) - ME_GetCursorOfs(editor, 1);
-  
-  if (cdir*dir>0)
-    return 0;
-  else
-    return 1;
+  return editor->pCursors[0].pRun != editor->pCursors[1].pRun ||
+         editor->pCursors[0].nOffset != editor->pCursors[1].nOffset;
 }
 
 void ME_DeleteSelection(ME_TextEditor *editor)
 {
   int from, to;
-  ME_GetSelection(editor, &from, &to);
-  ME_DeleteTextAtCursor(editor, ME_GetSelCursor(editor,-1), to-from);
+  int nStartCursor = ME_GetSelectionOfs(editor, &from, &to);
+  ME_DeleteTextAtCursor(editor, nStartCursor, to - from);
 }
 
 ME_Style *ME_GetSelectionInsertStyle(ME_TextEditor *editor)
@@ -1525,12 +1540,14 @@ void ME_SendSelChange(ME_TextEditor *editor)
   if (!(editor->nEventMask & ENM_SELCHANGE))
     return;
 
+  sc.nmhdr.hwndFrom = NULL;
+  sc.nmhdr.idFrom = 0;
   sc.nmhdr.code = EN_SELCHANGE;
-  ME_GetSelection(editor, &sc.chrg.cpMin, &sc.chrg.cpMax);
+  ME_GetSelectionOfs(editor, &sc.chrg.cpMin, &sc.chrg.cpMax);
   sc.seltyp = SEL_EMPTY;
   if (sc.chrg.cpMin != sc.chrg.cpMax)
     sc.seltyp |= SEL_TEXT;
-  if (sc.chrg.cpMin < sc.chrg.cpMax+1) /* wth were RICHEDIT authors thinking ? */
+  if (sc.chrg.cpMin < sc.chrg.cpMax+1) /* what were RICHEDIT authors thinking ? */
     sc.seltyp |= SEL_MULTICHAR;
   TRACE("cpMin=%d cpMax=%d seltyp=%d (%s %s)\n",
     sc.chrg.cpMin, sc.chrg.cpMax, sc.seltyp,
index cf4fe4b..15ce97b 100644 (file)
@@ -326,18 +326,23 @@ static const IDataObjectVtbl VT_DataObjectImpl =
     DataObjectImpl_EnumDAdvise
 };
 
-static HGLOBAL get_unicode_text(ME_TextEditor *editor, const CHARRANGE *lpchrg)
+static HGLOBAL get_unicode_text(ME_TextEditor *editor, const ME_Cursor *start, int nChars)
 {
-    int pars, len;
+    int pars = 0;
     WCHAR *data;
     HANDLE ret;
+    ME_DisplayItem *para;
+    int nEnd = ME_GetCursorOfs(start) + nChars;
 
-    pars = ME_CountParagraphsBetween(editor, lpchrg->cpMin, lpchrg->cpMax);
-    len = lpchrg->cpMax-lpchrg->cpMin;
-    ret = GlobalAlloc(GMEM_MOVEABLE, sizeof(WCHAR)*(len+pars+1));
+    /* count paragraphs in range */
+    para = start->pPara;
+    while((para = para->member.para.next_para) &&
+          para->member.para.nCharOfs <= nEnd)
+        pars++;
+
+    ret = GlobalAlloc(GMEM_MOVEABLE, sizeof(WCHAR) * (nChars + pars + 1));
     data = GlobalLock(ret);
-    len = ME_GetTextW(editor, data, lpchrg->cpMin, len, TRUE);
-    data[len] = 0;
+    ME_GetTextW(editor, data, nChars + pars, start, nChars, TRUE);
     GlobalUnlock(ret);
     return ret;
 }
@@ -370,7 +375,7 @@ static DWORD CALLBACK ME_AppendToHGLOBAL(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG
     return 0;
 }
 
-static HGLOBAL get_rtf_text(ME_TextEditor *editor, const CHARRANGE *lpchrg)
+static HGLOBAL get_rtf_text(ME_TextEditor *editor, const ME_Cursor *start, int nChars)
 {
     EDITSTREAM es;
     ME_GlobalDestStruct gds;
@@ -379,15 +384,16 @@ static HGLOBAL get_rtf_text(ME_TextEditor *editor, const CHARRANGE *lpchrg)
     gds.nLength = 0;
     es.dwCookie = (DWORD_PTR)&gds;
     es.pfnCallback = ME_AppendToHGLOBAL;
-    ME_StreamOutRange(editor, SF_RTF, lpchrg->cpMin, lpchrg->cpMax, &es);
+    ME_StreamOutRange(editor, SF_RTF, start, nChars, &es);
     GlobalReAlloc(gds.hData, gds.nLength+1, 0);
     return gds.hData;
 }
 
-HRESULT ME_GetDataObject(ME_TextEditor *editor, const CHARRANGE *lpchrg, LPDATAOBJECT *lplpdataobj)
+HRESULT ME_GetDataObject(ME_TextEditor *editor, const ME_Cursor *start,
+                         int nChars, LPDATAOBJECT *lplpdataobj)
 {
     DataObjectImpl *obj;
-    TRACE("(%p,%d,%d)\n", editor, lpchrg->cpMin, lpchrg->cpMax);
+    TRACE("(%p,%d,%d)\n", editor, ME_GetCursorOfs(start), nChars);
 
     obj = heap_alloc(sizeof(DataObjectImpl));
     if(cfRTF == 0)
@@ -395,7 +401,7 @@ HRESULT ME_GetDataObject(ME_TextEditor *editor, const CHARRANGE *lpchrg, LPDATAO
 
     obj->lpVtbl = &VT_DataObjectImpl;
     obj->ref = 1;
-    obj->unicode = get_unicode_text(editor, lpchrg);
+    obj->unicode = get_unicode_text(editor, start, nChars);
     obj->rtf = NULL;
 
     obj->fmtetc_cnt = 1;
@@ -404,7 +410,7 @@ HRESULT ME_GetDataObject(ME_TextEditor *editor, const CHARRANGE *lpchrg, LPDATAO
     obj->fmtetc = GlobalAlloc(GMEM_ZEROINIT, obj->fmtetc_cnt*sizeof(FORMATETC));
     InitFormatEtc(obj->fmtetc[0], CF_UNICODETEXT, TYMED_HGLOBAL);
     if(editor->mode & TM_RICHTEXT) {
-        obj->rtf = get_rtf_text(editor, lpchrg);
+        obj->rtf = get_rtf_text(editor, start, nChars);
         InitFormatEtc(obj->fmtetc[1], cfRTF, TYMED_HGLOBAL);
     }
 
index 278b9aa..7a11647 100644 (file)
   + WM_PASTE
   + WM_SETFONT
   + WM_SETTEXT (resets undo stack !) (proper style?) ANSI&Unicode
-  - WM_STYLECHANGING
-  - WM_STYLECHANGED (things like read-only flag)
+  + WM_STYLECHANGING (seems to do nothing)
+  + WM_STYLECHANGED (seems to do nothing)
   + WM_UNICHAR
   + WM_VSCROLL
 
 WINE_DEFAULT_DEBUG_CHANNEL(richedit);
 
 static BOOL ME_RegisterEditorClass(HINSTANCE);
-static BOOL ME_UpdateLinkAttribute(ME_TextEditor *editor, int sel_min, int sel_max);
+static BOOL ME_UpdateLinkAttribute(ME_TextEditor *editor, ME_Cursor *start, int nChars);
 
-static const WCHAR RichEdit20W[] = {'R', 'i', 'c', 'h', 'E', 'd', 'i', 't', '2', '0', 'W', 0};
-static const WCHAR RichEdit50W[] = {'R', 'i', 'c', 'h', 'E', 'd', 'i', 't', '5', '0', 'W', 0};
 static const WCHAR REListBox20W[] = {'R','E','L','i','s','t','B','o','x','2','0','W', 0};
 static const WCHAR REComboBox20W[] = {'R','E','C','o','m','b','o','B','o','x','2','0','W', 0};
 static HCURSOR hLeft;
@@ -422,7 +420,10 @@ void ME_RTFCharAttrHook(RTF_Info *info)
       else if (info->rtfParam != rtfNoParam)
       {
         RTFColor *c = RTFGetColor(info, info->rtfParam);
-        fmt.crTextColor = (c->rtfCBlue<<16)|(c->rtfCGreen<<8)|(c->rtfCRed);
+        if (c && c->rtfCBlue >= 0)
+          fmt.crTextColor = (c->rtfCBlue<<16)|(c->rtfCGreen<<8)|(c->rtfCRed);
+        else
+          fmt.dwEffects = CFE_AUTOBACKCOLOR;
       }
       break;
     case rtfForeColor:
@@ -433,10 +434,11 @@ void ME_RTFCharAttrHook(RTF_Info *info)
       else if (info->rtfParam != rtfNoParam)
       {
         RTFColor *c = RTFGetColor(info, info->rtfParam);
-        if (c)
+        if (c && c->rtfCBlue >= 0)
           fmt.crTextColor = (c->rtfCBlue<<16)|(c->rtfCGreen<<8)|(c->rtfCRed);
-        else
-          fmt.crTextColor = 0;
+        else {
+          fmt.dwEffects = CFE_AUTOCOLOR;
+        }
       }
       break;
     case rtfFontNum:
@@ -1011,9 +1013,10 @@ void ME_RTFSpecialCharHook(RTF_Info *info)
           info->editor->pCursors[1].pRun = run;
           info->editor->pCursors[1].pPara = ME_GetParagraph(run);
           info->editor->pCursors[1].nOffset = 0;
-          nOfs = ME_GetCursorOfs(info->editor, 1);
-          nChars = ME_GetCursorOfs(info->editor, 0) - nOfs;
-          ME_InternalDeleteText(info->editor, nOfs, nChars, TRUE);
+          nOfs = ME_GetCursorOfs(&info->editor->pCursors[1]);
+          nChars = ME_GetCursorOfs(&info->editor->pCursors[0]) - nOfs;
+          ME_InternalDeleteText(info->editor, &info->editor->pCursors[1],
+                                nChars, TRUE);
         }
 
         para = ME_InsertTableRowEndFromCursor(info->editor);
@@ -1146,8 +1149,8 @@ static BOOL ME_RTFInsertOleObject(RTF_Info *info, HENHMETAFILE hemf, HBITMAP hbm
     reobject.dwFlags = 0; /* FIXME */
     reobject.dwUser = 0;
 
-    /* FIXME: could be simpler */
-    ret = IRichEditOle_InsertObject(info->lpRichEditOle, &reobject) == S_OK;
+    ME_InsertOLEFromCursor(info->editor, &reobject, 0);
+    ret = TRUE;
   }
 
   if (lpObject)       IOleObject_Release(lpObject);
@@ -1341,7 +1344,8 @@ static void ME_RTFReadHook(RTF_Info *info)
       {
         case rtfBeginGroup:
           if (info->stackTop < maxStack) {
-            info->stack[info->stackTop].fmt = info->style->fmt;
+            info->stack[info->stackTop].style = info->style;
+            ME_AddRefStyle(info->style);
             info->stack[info->stackTop].codePage = info->codePage;
             info->stack[info->stackTop].unicodeLength = info->unicodeLength;
           }
@@ -1350,23 +1354,17 @@ static void ME_RTFReadHook(RTF_Info *info)
           break;
         case rtfEndGroup:
         {
-          ME_Style *s;
           RTFFlushOutputBuffer(info);
           info->stackTop--;
-          if (info->stackTop<=0) {
+          if (info->stackTop <= 0)
             info->rtfClass = rtfEOF;
+          if (info->stackTop < 0)
             return;
-          }
-          assert(info->stackTop >= 0);
-          if (info->styleChanged)
-          {
-            /* FIXME too slow ? how come ? */
-            s = ME_ApplyStyle(info->style, &info->stack[info->stackTop].fmt);
-            ME_ReleaseStyle(info->style);
-            info->style = s;
-            info->codePage = info->stack[info->stackTop].codePage;
-            info->unicodeLength = info->stack[info->stackTop].unicodeLength;
-          }
+
+          ME_ReleaseStyle(info->style);
+          info->style = info->stack[info->stackTop].style;
+          info->codePage = info->stack[info->stackTop].codePage;
+          info->unicodeLength = info->stack[info->stackTop].unicodeLength;
           break;
         }
       }
@@ -1388,19 +1386,22 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre
 {
   RTF_Info parser;
   ME_Style *style;
-  int from, to, to2, nUndoMode;
+  int from, to, nUndoMode;
   int nEventMask = editor->nEventMask;
   ME_InStream inStream;
   BOOL invalidRTF = FALSE;
+  ME_Cursor *selStart, *selEnd;
 
   TRACE("stream==%p editor==%p format==0x%X\n", stream, editor, format);
   editor->nEventMask = 0;
 
-  ME_GetSelection(editor, &from, &to);
-  if ((format & SFF_SELECTION) && (editor->mode & TM_RICHTEXT)) {
+  ME_GetSelectionOfs(editor, &from, &to);
+  if (format & SFF_SELECTION && editor->mode & TM_RICHTEXT)
+  {
+    ME_GetSelection(editor, &selStart, &selEnd);
     style = ME_GetSelectionInsertStyle(editor);
 
-    ME_InternalDeleteText(editor, from, to-from, FALSE);
+    ME_InternalDeleteText(editor, selStart, to - from, FALSE);
 
     /* Don't insert text at the end of the table row */
     if (!editor->bEmulateVersion10) { /* v4.1 */
@@ -1425,12 +1426,12 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre
           ME_IsInTable(editor->pCursors[0].pRun))
         return 0;
     }
-  }
-  else {
+  } else {
     style = editor->pBuffer->pDefaultStyle;
     ME_AddRefStyle(style);
     ME_SetSelection(editor, 0, 0);
-    ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor), FALSE);
+    ME_InternalDeleteText(editor, &editor->pCursors[1],
+                          ME_GetTextLength(editor), FALSE);
     from = to = 0;
     ME_ClearTempStyle(editor);
     ME_SetDefaultParaFormat(editor->pCursors[0].pPara->member.para.pFmt);
@@ -1519,9 +1520,9 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre
           editor->pCursors[1].pPara = para;
           editor->pCursors[1].pRun = ME_FindItemFwd(para, diRun);
           editor->pCursors[1].nOffset = 0;
-          nOfs = ME_GetCursorOfs(editor, 1);
-          nChars = ME_GetCursorOfs(editor, 0) - nOfs;
-          ME_InternalDeleteText(editor, nOfs, nChars, TRUE);
+          nOfs = ME_GetCursorOfs(&editor->pCursors[1]);
+          nChars = ME_GetCursorOfs(&editor->pCursors[0]) - nOfs;
+          ME_InternalDeleteText(editor, &editor->pCursors[1], nChars, TRUE);
           if (parser.tableDef)
             parser.tableDef->tableRowStart = NULL;
         }
@@ -1531,23 +1532,34 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre
       if (parser.lpRichEditOle)
         IRichEditOle_Release(parser.lpRichEditOle);
 
-      if (!inStream.editstream->dwError && parser.stackTop > 0)
-        inStream.editstream->dwError = HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
+      if (parser.stackTop > 0)
+      {
+        while (--parser.stackTop >= 0)
+        {
+          ME_ReleaseStyle(parser.style);
+          parser.style = parser.stack[parser.stackTop].style;
+        }
+        if (!inStream.editstream->dwError)
+          inStream.editstream->dwError = HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
+      }
 
       /* Remove last line break, as mandated by tests. This is not affected by
          CR/LF counters, since RTF streaming presents only \para tokens, which
          are converted according to the standard rules: \r for 2.0, \r\n for 1.0
        */
       if (stripLastCR) {
-        int newfrom, newto;
-        ME_GetSelection(editor, &newfrom, &newto);
+        int newto;
+        ME_GetSelection(editor, &selStart, &selEnd);
+        newto = ME_GetCursorOfs(selEnd);
         if (newto > to + (editor->bEmulateVersion10 ? 1 : 0)) {
           WCHAR lastchar[3] = {'\0', '\0'};
           int linebreakSize = editor->bEmulateVersion10 ? 2 : 1;
+          ME_Cursor linebreakCursor = *selEnd;
 
-          ME_GetTextW(editor, lastchar, newto - linebreakSize, linebreakSize, 0);
+          ME_MoveCursorChars(editor, &linebreakCursor, -linebreakSize);
+          ME_GetTextW(editor, lastchar, 2, &linebreakCursor, linebreakSize, 0);
           if (lastchar[0] == '\r' && (lastchar[1] == '\n' || lastchar[1] == '\0')) {
-            ME_InternalDeleteText(editor, newto - linebreakSize, linebreakSize, FALSE);
+            ME_InternalDeleteText(editor, &linebreakCursor, linebreakSize, FALSE);
           }
         }
       }
@@ -1558,7 +1570,6 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre
       ME_StreamInText(editor, format, &inStream, style);
     else
       ERR("EM_STREAMIN without SF_TEXT or SF_RTF\n");
-    ME_GetSelection(editor, &to, &to2);
     /* put the cursor at the top */
     if (!(format & SFF_SELECTION))
       ME_SetSelection(editor, 0, 0);
@@ -1629,10 +1640,8 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH
 {
   const int nLen = lstrlenW(text);
   const int nTextLen = ME_GetTextLength(editor);
-  int nStart, nEnd;
   int nMin, nMax;
-  ME_DisplayItem *item;
-  ME_DisplayItem *para;
+  ME_Cursor cursor;
   WCHAR wLastChar = ' ';
 
   TRACE("flags==0x%08x, chrg->cpMin==%d, chrg->cpMax==%d text==%s\n",
@@ -1693,17 +1702,17 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH
     /* If possible, find the character before where the search starts */
     if ((flags & FR_WHOLEWORD) && nMin)
     {
-      ME_RunOfsFromCharOfs(editor, nMin - 1, NULL, &item, &nStart);
-      wLastChar = item->member.run.strText->szData[nStart];
+      ME_CursorFromCharOfs(editor, nMin - 1, &cursor);
+      wLastChar = cursor.pRun->member.run.strText->szData[cursor.nOffset];
+      ME_MoveCursorChars(editor, &cursor, 1);
+    } else {
+      ME_CursorFromCharOfs(editor, nMin, &cursor);
     }
 
-    ME_RunOfsFromCharOfs(editor, nMin, &para, &item, &nStart);
-
-    while (item
-           && para->member.para.nCharOfs + item->member.run.nCharOfs + nStart + nLen <= nMax)
+    while (cursor.pRun && ME_GetCursorOfs(&cursor) + nLen <= nMax)
     {
-      ME_DisplayItem *pCurItem = item;
-      int nCurStart = nStart;
+      ME_DisplayItem *pCurItem = cursor.pRun;
+      int nCurStart = cursor.nOffset;
       int nMatched = 0;
     
       while (pCurItem && ME_CharCompare(pCurItem->member.run.strText->szData[nCurStart + nMatched], text[nMatched], (flags & FR_MATCHCASE)))
@@ -1736,14 +1745,14 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH
               break;
           }
 
-          nStart += para->member.para.nCharOfs + item->member.run.nCharOfs;
+          cursor.nOffset += cursor.pPara->member.para.nCharOfs + cursor.pRun->member.run.nCharOfs;
           if (chrgText)
           {
-            chrgText->cpMin = nStart;
-            chrgText->cpMax = nStart + nLen;
+            chrgText->cpMin = cursor.nOffset;
+            chrgText->cpMax = cursor.nOffset + nLen;
           }
-          TRACE("found at %d-%d\n", nStart, nStart + nLen);
-          return nStart;
+          TRACE("found at %d-%d\n", cursor.nOffset, cursor.nOffset + nLen);
+          return cursor.nOffset;
         }
         if (nCurStart + nMatched == pCurItem->member.run.strText->nLen)
         {
@@ -1756,12 +1765,11 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH
       else
         wLastChar = ' ';
 
-      nStart++;
-      if (nStart == item->member.run.strText->nLen)
+      cursor.nOffset++;
+      if (cursor.nOffset == cursor.pRun->member.run.strText->nLen)
       {
-        item = ME_FindItemFwd(item, diRun);
-        para = ME_GetParagraph(item);
-        nStart = 0;
+        ME_NextRun(&cursor.pPara, &cursor.pRun);
+        cursor.nOffset = 0;
       }
     }
   }
@@ -1770,22 +1778,23 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH
     /* If possible, find the character after where the search ends */
     if ((flags & FR_WHOLEWORD) && nMax < nTextLen - 1)
     {
-      ME_RunOfsFromCharOfs(editor, nMax + 1, NULL, &item, &nEnd);
-      wLastChar = item->member.run.strText->szData[nEnd];
+      ME_CursorFromCharOfs(editor, nMax + 1, &cursor);
+      wLastChar = cursor.pRun->member.run.strText->szData[cursor.nOffset];
+      ME_MoveCursorChars(editor, &cursor, -1);
+    } else {
+      ME_CursorFromCharOfs(editor, nMax, &cursor);
     }
 
-    ME_RunOfsFromCharOfs(editor, nMax, &para, &item, &nEnd);
-
-    while (item
-           && para->member.para.nCharOfs + item->member.run.nCharOfs + nEnd - nLen >= nMin)
+    while (cursor.pRun && ME_GetCursorOfs(&cursor) - nLen >= nMin)
     {
-      ME_DisplayItem *pCurItem = item;
-      int nCurEnd = nEnd;
+      ME_DisplayItem *pCurItem = cursor.pRun;
+      ME_DisplayItem *pCurPara = cursor.pPara;
+      int nCurEnd = cursor.nOffset;
       int nMatched = 0;
 
       if (nCurEnd == 0)
       {
-        pCurItem = ME_FindItemBack(pCurItem, diRun);
+        ME_PrevRun(&pCurPara, &pCurItem);
         nCurEnd = pCurItem->member.run.strText->nLen + nMatched;
       }
 
@@ -1800,6 +1809,7 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH
           ME_DisplayItem *pPrevItem = pCurItem;
           int nPrevEnd = nCurEnd;
           WCHAR wPrevChar;
+          int nStart;
 
           /* Check to see if previous character is a whitespace */
           if (flags & FR_WHOLEWORD)
@@ -1820,7 +1830,7 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH
               break;
           }
 
-          nStart = ME_GetParagraph(pCurItem)->member.para.nCharOfs
+          nStart = pCurPara->member.para.nCharOfs
                    + pCurItem->member.run.nCharOfs + nCurEnd - nMatched;
           if (chrgText)
           {
@@ -1832,7 +1842,7 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH
         }
         if (nCurEnd - nMatched == 0)
         {
-          pCurItem = ME_FindItemBack(pCurItem, diRun);
+          ME_PrevRun(&pCurPara, &pCurItem);
           /* Don't care about pCurItem becoming NULL here; it's already taken
            * care of in the exterior loop condition */
           nCurEnd = pCurItem->member.run.strText->nLen + nMatched;
@@ -1843,12 +1853,11 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH
       else
         wLastChar = ' ';
 
-      nEnd--;
-      if (nEnd < 0)
+      cursor.nOffset--;
+      if (cursor.nOffset < 0)
       {
-        item = ME_FindItemBack(item, diRun);
-        para = ME_GetParagraph(item);
-        nEnd = item->member.run.strText->nLen;
+        ME_PrevRun(&cursor.pPara, &cursor.pRun);
+        cursor.nOffset = cursor.pRun->member.run.strText->nLen;
       }
     }
   }
@@ -1860,25 +1869,30 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH
 
 static int ME_GetTextEx(ME_TextEditor *editor, GETTEXTEX *ex, LPARAM pText)
 {
-    int nStart, nCount; /* in chars */
+    int nChars;
+    ME_Cursor start;
+
+    if (!ex->cb || !pText) return 0;
 
     if (ex->flags & ~(GT_SELECTION | GT_USECRLF))
       FIXME("GETTEXTEX flags 0x%08x not supported\n", ex->flags & ~(GT_SELECTION | GT_USECRLF));
 
     if (ex->flags & GT_SELECTION)
     {
-      ME_GetSelection(editor, &nStart, &nCount);
-      nCount -= nStart;
+      int from, to;
+      int nStartCur = ME_GetSelectionOfs(editor, &from, &to);
+      start = editor->pCursors[nStartCur];
+      nChars = to - from;
     }
     else
     {
-      nStart = 0;
-      nCount = 0x7fffffff;
+      ME_SetCursorToStart(editor, &start);
+      nChars = INT_MAX;
     }
     if (ex->codepage == 1200)
     {
-      nCount = min(nCount, ex->cb / sizeof(WCHAR) - 1);
-      return ME_GetTextW(editor, (LPWSTR)pText, nStart, nCount, ex->flags & GT_USECRLF);
+      return ME_GetTextW(editor, (LPWSTR)pText, ex->cb / sizeof(WCHAR) - 1,
+                         &start, nChars, ex->flags & GT_USECRLF);
     }
     else
     {
@@ -1888,16 +1902,15 @@ static int ME_GetTextEx(ME_TextEditor *editor, GETTEXTEX *ex, LPARAM pText)
         occurs only in richedit 2.0 mode, in which line breaks have only one CR
        */
       int crlfmul = (ex->flags & GT_USECRLF) ? 2 : 1;
+      DWORD buflen;
       LPWSTR buffer;
-      DWORD buflen = ex->cb;
       LRESULT rc;
-      DWORD flags = 0;
 
-      nCount = min(nCount, ex->cb - 1);
-      buffer = heap_alloc((crlfmul*nCount + 1) * sizeof(WCHAR));
+      buflen = min(crlfmul * nChars, ex->cb - 1);
+      buffer = heap_alloc((buflen + 1) * sizeof(WCHAR));
 
-      buflen = ME_GetTextW(editor, buffer, nStart, nCount, ex->flags & GT_USECRLF);
-      rc = WideCharToMultiByte(ex->codepage, flags, buffer, buflen+1,
+      nChars = ME_GetTextW(editor, buffer, buflen, &start, nChars, ex->flags & GT_USECRLF);
+      rc = WideCharToMultiByte(ex->codepage, 0, buffer, nChars + 1,
                                (LPSTR)pText, ex->cb, ex->lpDefaultChar, ex->lpUsedDefChar);
       if (rc) rc--; /* do not count 0 terminator */
 
@@ -1907,13 +1920,16 @@ static int ME_GetTextEx(ME_TextEditor *editor, GETTEXTEX *ex, LPARAM pText)
 }
 
 static int ME_GetTextRange(ME_TextEditor *editor, WCHAR *strText,
-                           int start, int nLen, BOOL unicode)
+                           const ME_Cursor *start, int nLen, BOOL unicode)
 {
+    if (!strText) return 0;
     if (unicode) {
-      return ME_GetTextW(editor, strText, start, nLen, 0);
+      return ME_GetTextW(editor, strText, INT_MAX, start, nLen, 0);
     } else {
+      int nChars;
       WCHAR *p = ALLOC_N_OBJ(WCHAR, nLen+1);
-      int nChars = ME_GetTextW(editor, p, start, nLen, 0);
+      if (!p) return 0;
+      nChars = ME_GetTextW(editor, p, nLen, start, nLen, 0);
       WideCharToMultiByte(CP_ACP, 0, p, nChars+1, (char *)strText,
                           nLen+1, NULL, NULL);
       FREE_OBJ(p);
@@ -1989,7 +2005,7 @@ static BOOL ME_Paste(ME_TextEditor *editor)
   return TRUE;
 }
 
-static BOOL ME_Copy(ME_TextEditor *editor, CHARRANGE *range)
+static BOOL ME_Copy(ME_TextEditor *editor, const ME_Cursor *start, int nChars)
 {
   LPDATAOBJECT dataObj = NULL;
   HRESULT hr = S_OK;
@@ -1998,9 +2014,14 @@ static BOOL ME_Copy(ME_TextEditor *editor, CHARRANGE *range)
     return FALSE; /* Copying or Cutting masked text isn't allowed */
 
   if(editor->lpOleCallback)
-    hr = IRichEditOleCallback_GetClipboardData(editor->lpOleCallback, range, RECO_COPY, &dataObj);
+  {
+    CHARRANGE range;
+    range.cpMin = ME_GetCursorOfs(start);
+    range.cpMax = range.cpMin + nChars;
+    hr = IRichEditOleCallback_GetClipboardData(editor->lpOleCallback, &range, RECO_COPY, &dataObj);
+  }
   if(FAILED(hr) || !dataObj)
-    hr = ME_GetDataObject(editor, range, &dataObj);
+    hr = ME_GetDataObject(editor, start, nChars, &dataObj);
   if(SUCCEEDED(hr)) {
     hr = OleSetClipboard(dataObj);
     IDataObject_Release(dataObj);
@@ -2014,14 +2035,14 @@ ME_FilterEvent(ME_TextEditor *editor, UINT msg, WPARAM* wParam, LPARAM* lParam)
 {
     MSGFILTER msgf;
 
-    if (!editor->hWnd) return FALSE;
+    if (!editor->hWnd || !editor->hwndParent) return FALSE;
     msgf.nmhdr.hwndFrom = editor->hWnd;
     msgf.nmhdr.idFrom = GetWindowLongW(editor->hWnd, GWLP_ID);
     msgf.nmhdr.code = EN_MSGFILTER;
     msgf.msg = msg;
     msgf.wParam = *wParam;
     msgf.lParam = *lParam;
-    if (SendMessageW(GetParent(editor->hWnd), WM_NOTIFY, msgf.nmhdr.idFrom, (LPARAM)&msgf))
+    if (SendMessageW(editor->hwndParent, WM_NOTIFY, msgf.nmhdr.idFrom, (LPARAM)&msgf))
         return FALSE;
     *wParam = msgf.wParam;
     *lParam = msgf.lParam;
@@ -2034,24 +2055,28 @@ static void ME_UpdateSelectionLinkAttribute(ME_TextEditor *editor)
 {
   ME_DisplayItem *startPara, *endPara;
   ME_DisplayItem *prev_para;
-  int from, to;
+  ME_Cursor *from, *to;
+  ME_Cursor start;
+  int nChars;
 
   if (!editor->AutoURLDetect_bEnable) return;
 
   ME_GetSelection(editor, &from, &to);
 
   /* Find paragraph previous to the one that contains start cursor */
-  ME_RunOfsFromCharOfs(editor, from, &startPara, NULL, NULL);
+  startPara = from->pPara;
   prev_para = startPara->member.para.prev_para;
   if (prev_para->type == diParagraph) startPara = prev_para;
 
   /* Find paragraph that contains end cursor */
-  ME_RunOfsFromCharOfs(editor, to, &endPara, NULL, NULL);
-  endPara = endPara->member.para.next_para;
+  endPara = to->pPara->member.para.next_para;
 
-  ME_UpdateLinkAttribute(editor,
-                         startPara->member.para.nCharOfs,
-                         endPara->member.para.nCharOfs);
+  start.pPara = startPara;
+  start.pRun = ME_FindItemFwd(startPara, diRun);
+  start.nOffset = 0;
+  nChars = endPara->member.para.nCharOfs - startPara->member.para.nCharOfs;
+
+  ME_UpdateLinkAttribute(editor, &start, nChars);
 }
 
 static BOOL
@@ -2120,6 +2145,31 @@ ME_KeyDown(ME_TextEditor *editor, WORD nKey)
       ME_SendRequestResize(editor, FALSE);
       return TRUE;
     case VK_RETURN:
+      if (editor->bDialogMode)
+      {
+        if (ctrl_is_down)
+          return TRUE;
+
+        if (!(editor->styleFlags & ES_WANTRETURN))
+        {
+          if (editor->hwndParent)
+          {
+            DWORD dw;
+            dw = SendMessageW(editor->hwndParent, DM_GETDEFID, 0, 0);
+            if (HIWORD(dw) == DC_HASDEFID)
+            {
+                HWND hwDefCtrl = GetDlgItem(editor->hwndParent, LOWORD(dw));
+                if (hwDefCtrl)
+                {
+                    SendMessageW(editor->hwndParent, WM_NEXTDLGCTL, (WPARAM)hwDefCtrl, TRUE);
+                    PostMessageW(hwDefCtrl, WM_KEYDOWN, VK_RETURN, 0);
+                }
+            }
+          }
+          return TRUE;
+        }
+      }
+
       if (editor->styleFlags & ES_MULTILINE)
       {
         ME_Cursor cursor = editor->pCursors[0];
@@ -2133,7 +2183,7 @@ ME_KeyDown(ME_TextEditor *editor, WORD nKey)
           return TRUE;
         }
 
-        ME_GetSelection(editor, &from, &to);
+        ME_GetSelectionOfs(editor, &from, &to);
         if (editor->nTextLimit > ME_GetTextLength(editor) - (to-from))
         {
           if (!editor->bEmulateVersion10) { /* v4.1 */
@@ -2239,6 +2289,14 @@ ME_KeyDown(ME_TextEditor *editor, WORD nKey)
         return TRUE;
       }
       break;
+    case VK_ESCAPE:
+      if (editor->bDialogMode && editor->hwndParent)
+        PostMessageW(editor->hwndParent, WM_CLOSE, 0, 0);
+      return TRUE;
+    case VK_TAB:
+      if (editor->bDialogMode && editor->hwndParent)
+        SendMessageW(editor->hwndParent, WM_NEXTDLGCTL, shift_is_down, 0);
+      return TRUE;
     case 'A':
       if (ctrl_is_down)
       {
@@ -2254,14 +2312,16 @@ ME_KeyDown(ME_TextEditor *editor, WORD nKey)
     case 'X':
       if (ctrl_is_down)
       {
-        CHARRANGE range;
         BOOL result;
+        int nOfs, nChars;
+        int nStartCur = ME_GetSelectionOfs(editor, &nOfs, &nChars);
+        ME_Cursor *selStart = &editor->pCursors[nStartCur];
 
-        ME_GetSelection(editor, &range.cpMin, &range.cpMax);
-        result = ME_Copy(editor, &range);
+        nChars -= nOfs;
+        result = ME_Copy(editor, selStart, nChars);
         if (result && nKey == 'X')
         {
-          ME_InternalDeleteText(editor, range.cpMin, range.cpMax-range.cpMin, FALSE);
+          ME_InternalDeleteText(editor, selStart, nChars, FALSE);
           ME_CommitUndo(editor);
           ME_UpdateRepaint(editor);
         }
@@ -2334,7 +2394,7 @@ static LRESULT ME_Char(ME_TextEditor *editor, WPARAM charCode,
     ME_DisplayItem *para = cursor.pPara;
     int from, to;
     BOOL ctrl_is_down = GetKeyState(VK_CONTROL) & 0x8000;
-    ME_GetSelection(editor, &from, &to);
+    ME_GetSelectionOfs(editor, &from, &to);
     if (wstr == '\t' &&
         /* v4.1 allows tabs to be inserted with ctrl key down */
         !(ctrl_is_down && !editor->bEmulateVersion10))
@@ -2345,7 +2405,7 @@ static LRESULT ME_Char(ME_TextEditor *editor, WPARAM charCode,
       para = cursor.pPara;
       if (ME_IsSelection(editor) &&
           cursor.pRun->member.run.nCharOfs + cursor.nOffset == 0 &&
-          to == ME_GetCursorOfs(editor, 0) &&
+          to == ME_GetCursorOfs(&editor->pCursors[0]) &&
           para->member.para.prev_para->type == diParagraph)
       {
         para = para->member.para.prev_para;
@@ -2453,9 +2513,9 @@ static int ME_CalculateClickCount(ME_TextEditor *editor, UINT msg, WPARAM wParam
 
 static BOOL ME_SetCursor(ME_TextEditor *editor)
 {
+  ME_Cursor cursor;
   POINT pt;
   BOOL isExact;
-  int offset;
   SCROLLBARINFO sbi;
   DWORD messagePos = GetMessagePos();
   pt.x = (short)LOWORD(messagePos);
@@ -2510,13 +2570,11 @@ static BOOL ME_SetCursor(ME_TextEditor *editor)
       ITextHost_TxSetCursor(editor->texthost, hLeft, FALSE);
       return TRUE;
   }
-  offset = ME_CharFromPos(editor, pt.x, pt.y, &isExact);
+  ME_CharFromPos(editor, pt.x, pt.y, &cursor, &isExact);
   if (isExact)
   {
-      ME_Cursor cursor;
       ME_Run *run;
 
-      ME_CursorFromCharOfs(editor, offset, &cursor);
       run = &cursor.pRun->member.run;
       if (run->style->fmt.dwMask & CFM_LINK &&
           run->style->fmt.dwEffects & CFE_LINK)
@@ -2530,7 +2588,9 @@ static BOOL ME_SetCursor(ME_TextEditor *editor)
       if (ME_IsSelection(editor))
       {
           int selStart, selEnd;
-          ME_GetSelection(editor, &selStart, &selEnd);
+          int offset = ME_GetCursorOfs(&cursor);
+
+          ME_GetSelectionOfs(editor, &selStart, &selEnd);
           if (selStart <= offset && selEnd >= offset) {
               ITextHost_TxSetCursor(editor->texthost,
                                     LoadCursorW(NULL, (WCHAR*)IDC_ARROW),
@@ -2559,7 +2619,7 @@ static BOOL ME_ShowContextMenu(ME_TextEditor *editor, int x, int y)
   int seltype = 0;
   if(!editor->lpOleCallback || !editor->hWnd)
     return FALSE;
-  ME_GetSelection(editor, &selrange.cpMin, &selrange.cpMax);
+  ME_GetSelectionOfs(editor, &selrange.cpMin, &selrange.cpMax);
   if(selrange.cpMin == selrange.cpMax)
     seltype |= SEL_EMPTY;
   else
@@ -2571,7 +2631,7 @@ static BOOL ME_ShowContextMenu(ME_TextEditor *editor, int x, int y)
   }
   if(SUCCEEDED(IRichEditOleCallback_GetContextMenu(editor->lpOleCallback, seltype, NULL, &selrange, &menu)))
   {
-    TrackPopupMenu(menu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, x, y, 0, GetParent(editor->hWnd), NULL);
+    TrackPopupMenu(menu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, x, y, 0, editor->hwndParent, NULL);
     DestroyMenu(menu);
   }
   return TRUE;
@@ -2585,8 +2645,11 @@ ME_TextEditor *ME_MakeEditor(ITextHost *texthost, BOOL bEmulateVersion10)
   LONG selbarwidth;
 
   ed->hWnd = NULL;
+  ed->hwndParent = NULL;
+  ed->sizeWindow.cx = ed->sizeWindow.cy = 0;
   ed->texthost = texthost;
   ed->bEmulateVersion10 = bEmulateVersion10;
+  ed->styleFlags = 0;
   ITextHost_TxGetPropertyBits(texthost,
                               (TXTBIT_RICHTEXT|TXTBIT_MULTILINE|
                                TXTBIT_READONLY|TXTBIT_USEPASSWORD|
@@ -2599,6 +2662,7 @@ ME_TextEditor *ME_MakeEditor(ITextHost *texthost, BOOL bEmulateVersion10)
                      ES_AUTOHSCROLL|ES_DISABLENOSCROLL);
   ed->pBuffer = ME_MakeText();
   ed->nZoomNumerator = ed->nZoomDenominator = 0;
+  ed->nAvailWidth = 0; /* wrap to client area */
   ME_MakeFirstParagraph(ed);
   /* The four cursors are for:
    * 0 - The position where the caret is shown
@@ -2608,9 +2672,7 @@ ME_TextEditor *ME_MakeEditor(ITextHost *texthost, BOOL bEmulateVersion10)
    */
   ed->nCursors = 4;
   ed->pCursors = ALLOC_N_OBJ(ME_Cursor, ed->nCursors);
-  ed->pCursors[0].pPara = ed->pBuffer->pFirst->member.para.next_para;
-  ed->pCursors[0].pRun = ME_FindItemFwd(ed->pCursors[0].pPara, diRun);
-  ed->pCursors[0].nOffset = 0;
+  ME_SetCursorToStart(ed, &ed->pCursors[0]);
   ed->pCursors[1] = ed->pCursors[0];
   ed->pCursors[2] = ed->pCursors[0];
   ed->pCursors[3] = ed->pCursors[1];
@@ -2630,8 +2692,7 @@ ME_TextEditor *ME_MakeEditor(ITextHost *texthost, BOOL bEmulateVersion10)
   ed->nUndoMode = umAddToUndo;
   ed->nParagraphs = 1;
   ed->nLastSelStart = ed->nLastSelEnd = 0;
-  ed->pLastSelStartPara = ed->pLastSelEndPara = ME_FindItemFwd(ed->pBuffer->pFirst, diParagraph);
-  ed->nAvailWidth = 0; /* wrap to client area */
+  ed->pLastSelStartPara = ed->pLastSelEndPara = ed->pCursors[0].pPara;
   ed->bHideSelection = FALSE;
   ed->pfnWordBreak = NULL;
   ed->lpOleCallback = NULL;
@@ -2639,6 +2700,7 @@ ME_TextEditor *ME_MakeEditor(ITextHost *texthost, BOOL bEmulateVersion10)
   ed->mode |= (props & TXTBIT_RICHTEXT) ? TM_RICHTEXT : TM_PLAINTEXT;
   ed->AutoURLDetect_bEnable = FALSE;
   ed->bHaveFocus = FALSE;
+  ed->bDialogMode = FALSE;
   ed->bMouseCaptured = FALSE;
   for (i=0; i<HFONT_CACHE_SIZE; i++)
   {
@@ -2748,9 +2810,9 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
       break;
 
     case DLL_PROCESS_DETACH:
-      UnregisterClassW(RichEdit20W, 0);
-      UnregisterClassW(RichEdit50W, 0);
-      UnregisterClassA("RichEdit20A", 0);
+      UnregisterClassW(RICHEDIT_CLASS20W, 0);
+      UnregisterClassW(MSFTEDIT_CLASS, 0);
+      UnregisterClassA(RICHEDIT_CLASS20A, 0);
       UnregisterClassA("RichEdit50A", 0);
       if (ME_ListBoxRegistered)
           UnregisterClassW(REListBox20W, 0);
@@ -2904,30 +2966,28 @@ get_msg_name(UINT msg)
 static void ME_LinkNotify(ME_TextEditor *editor, UINT msg, WPARAM wParam, LPARAM lParam)
 {
   int x,y;
-  ME_DisplayItem *para, *run;
   BOOL isExact;
-  int nCharOfs; /* The start of the clicked text. Absolute character offset */
+  ME_Cursor cursor; /* The start of the clicked text. */
 
   ENLINK info;
   x = (short)LOWORD(lParam);
   y = (short)HIWORD(lParam);
-  nCharOfs = ME_CharFromPos(editor, x, y, &isExact);
+  ME_CharFromPos(editor, x, y, &cursor, &isExact);
   if (!isExact) return;
 
-  ME_RunOfsFromCharOfs(editor, nCharOfs, &para, &run, NULL);
-
-  if ((run->member.run.style->fmt.dwMask & CFM_LINK)
-    && (run->member.run.style->fmt.dwEffects & CFE_LINK))
+  if (cursor.pRun->member.run.style->fmt.dwMask & CFM_LINK &&
+      cursor.pRun->member.run.style->fmt.dwEffects & CFE_LINK)
   { /* The clicked run has CFE_LINK set */
-    info.nmhdr.hwndFrom = editor->hWnd;
-    info.nmhdr.idFrom = GetWindowLongW(editor->hWnd, GWLP_ID);
+    info.nmhdr.hwndFrom = NULL;
+    info.nmhdr.idFrom = 0;
     info.nmhdr.code = EN_LINK;
     info.msg = msg;
     info.wParam = wParam;
     info.lParam = lParam;
-    info.chrg.cpMin = ME_CharOfsFromRunOfs(editor, para, run, 0);
-    info.chrg.cpMax = info.chrg.cpMin + run->member.run.strText->nLen;
-    SendMessageW(GetParent(editor->hWnd), WM_NOTIFY,info.nmhdr.idFrom, (LPARAM)&info);
+    cursor.nOffset = 0;
+    info.chrg.cpMin = ME_GetCursorOfs(&cursor);
+    info.chrg.cpMax = info.chrg.cpMin + cursor.pRun->member.run.strText->nLen;
+    ITextHost_TxNotify(editor->texthost, info.nmhdr.code, &info);
   }
 }
 
@@ -2974,8 +3034,6 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
   UNSUPPORTED_MSG(EM_SETTABSTOPS)
   UNSUPPORTED_MSG(EM_SETTYPOGRAPHYOPTIONS)
   UNSUPPORTED_MSG(EM_SETWORDBREAKPROCEX)
-  UNSUPPORTED_MSG(WM_STYLECHANGING)
-  UNSUPPORTED_MSG(WM_STYLECHANGED)
 
 /* Messages specific to Richedit controls */
 
@@ -2986,6 +3044,8 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
   case WM_GETDLGCODE:
   {
     UINT code = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL;
+    if (lParam)
+      editor->bDialogMode = TRUE;
     if (editor->styleFlags & ES_MULTILINE)
       code |= DLGC_WANTMESSAGE;
     return code;
@@ -2999,7 +3059,7 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
     UINT from, to;
     PUINT pfrom = wParam ? (PUINT)wParam : &from;
     PUINT pto = lParam ? (PUINT)lParam : &to;
-    ME_GetSelection(editor, (int *)pfrom, (int *)pto);
+    ME_GetSelectionOfs(editor, (int *)pfrom, (int *)pto);
     if ((*pfrom|*pto) & 0xFFFF0000)
       return -1;
     return MAKELONG(*pfrom,*pto);
@@ -3007,7 +3067,7 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
   case EM_EXGETSEL:
   {
     CHARRANGE *pRange = (CHARRANGE *)lParam;
-    ME_GetSelection(editor, &pRange->cpMin, &pRange->cpMax);
+    ME_GetSelectionOfs(editor, &pRange->cpMin, &pRange->cpMax);
     TRACE("EM_EXGETSEL = (%d,%d)\n", pRange->cpMin, pRange->cpMax);
     return 0;
   }
@@ -3194,7 +3254,7 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
     /* If we detect ascii rtf at the start of the string,
      * we know it isn't unicode. */
     bRtf = (lParam && (!strncmp((char *)lParam, "{\\rtf", 5) ||
-                         !strncmp((char *)lParam, "{\\urtf}", 6)));
+                         !strncmp((char *)lParam, "{\\urtf", 6)));
     bUnicode = !bRtf && pStruct->codepage == 1200;
 
     TRACE("EM_SETTEXTEX - %s, flags %d, cp %d\n",
@@ -3203,18 +3263,20 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
 
     bSelection = (pStruct->flags & ST_SELECTION) != 0;
     if (bSelection) {
-      ME_GetSelection(editor, &from, &to);
+      int nStartCursor = ME_GetSelectionOfs(editor, &from, &to);
       style = ME_GetSelectionInsertStyle(editor);
-      ME_InternalDeleteText(editor, from, to - from, FALSE);
+      ME_InternalDeleteText(editor, &editor->pCursors[nStartCursor], to - from, FALSE);
     } else {
-      ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor), FALSE);
+      ME_Cursor start;
+      ME_SetCursorToStart(editor, &start);
+      ME_InternalDeleteText(editor, &start, ME_GetTextLength(editor), FALSE);
       style = editor->pBuffer->pDefaultStyle;
     }
 
     if (bRtf) {
       ME_StreamInRTFString(editor, bSelection, (char *)lParam);
       if (bSelection) {
-        /* FIXME: The length returned is doesn't include the rtf control
+        /* FIXME: The length returned doesn't include the rtf control
          * characters, only the actual text. */
         len = lParam ? strlen((char *)lParam) : 0;
       }
@@ -3223,14 +3285,17 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
       wszText = lParam ? ME_ToUnicode(bUnicode, (void *)lParam) : NULL;
       len = wszText ? lstrlenW(wszText) : 0;
       ME_InsertTextFromCursor(editor, 0, wszText, len, style);
+      ME_EndToUnicode(bUnicode, wszText);
     }
 
     if (bSelection) {
       ME_ReleaseStyle(style);
       ME_UpdateSelectionLinkAttribute(editor);
     } else {
+      ME_Cursor cursor;
       len = 1;
-      ME_UpdateLinkAttribute(editor, 0, -1);
+      ME_SetCursorToStart(editor, &cursor);
+      ME_UpdateLinkAttribute(editor, &cursor, INT_MAX);
     }
     ME_CommitUndo(editor);
     if (!(pStruct->flags & ST_KEEPUNDO))
@@ -3307,17 +3372,17 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
       if (editor->mode & TM_PLAINTEXT)
         ME_SetDefaultCharFormat(editor, p);
       else {
-        ME_SetCharFormat(editor, 0, ME_GetTextLength(editor), p);
+        ME_Cursor start;
+        ME_SetCursorToStart(editor, &start);
+        ME_SetCharFormat(editor, &start, NULL, p);
         editor->nModifyStep = 1;
       }
     } else if (editor->mode & TM_PLAINTEXT) {
       return 0;
     } else {
-      int from, to;
-      ME_GetSelection(editor, &from, &to);
-      bRepaint = (from != to);
+      bRepaint = ME_IsSelection(editor);
       ME_SetSelectionCharFormat(editor, p);
-      if (from != to) editor->nModifyStep = 1;
+      if (bRepaint) editor->nModifyStep = 1;
     }
     ME_CommitUndo(editor);
     if (bRepaint)
@@ -3396,23 +3461,23 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
   case WM_CLEAR:
   {
     int from, to;
-    ME_GetSelection(editor, &from, &to);
-    ME_InternalDeleteText(editor, from, to-from, FALSE);
+    int nStartCursor = ME_GetSelectionOfs(editor, &from, &to);
+    ME_InternalDeleteText(editor, &editor->pCursors[nStartCursor], to-from, FALSE);
     ME_CommitUndo(editor);
     ME_UpdateRepaint(editor);
     return 0;
   }
   case EM_REPLACESEL:
   {
-    int from, to;
+    int from, to, nStartCursor;
     ME_Style *style;
     LPWSTR wszText = lParam ? ME_ToUnicode(unicode, (void *)lParam) : NULL;
     size_t len = wszText ? lstrlenW(wszText) : 0;
     TRACE("EM_REPLACESEL - %s\n", debugstr_w(wszText));
 
-    ME_GetSelection(editor, &from, &to);
+    nStartCursor = ME_GetSelectionOfs(editor, &from, &to);
     style = ME_GetSelectionInsertStyle(editor);
-    ME_InternalDeleteText(editor, from, to-from, FALSE);
+    ME_InternalDeleteText(editor, &editor->pCursors[nStartCursor], to-from, FALSE);
     ME_InsertTextFromCursor(editor, 0, wszText, len, style);
     ME_ReleaseStyle(style);
     /* drop temporary style if line end */
@@ -3439,6 +3504,7 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
     CHARFORMAT2W fmt;
     HDC hDC;
     BOOL bRepaint = LOWORD(lParam);
+    ME_Cursor start;
 
     if (!wParam)
       wParam = (WPARAM)GetStockObject(SYSTEM_FONT); 
@@ -3446,7 +3512,8 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
     hDC = ITextHost_TxGetDC(editor->texthost);
     ME_CharFormatFromLogFont(hDC, &lf, &fmt); 
     ITextHost_TxReleaseDC(editor->texthost, hDC);
-    ME_SetCharFormat(editor, 0, ME_GetTextLength(editor), &fmt);
+    ME_SetCursorToStart(editor, &start);
+    ME_SetCharFormat(editor, &start, NULL, &fmt);
     ME_SetDefaultCharFormat(editor, &fmt);
 
     ME_CommitUndo(editor);
@@ -3459,11 +3526,14 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
   }
   case WM_SETTEXT:
   {
-    ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor), FALSE);
+    ME_Cursor cursor;
+    ME_SetCursorToStart(editor, &cursor);
+    ME_InternalDeleteText(editor, &cursor, ME_GetTextLength(editor), FALSE);
     if (lParam)
     {
       TRACE("WM_SETTEXT lParam==%lx\n",lParam);
-      if (!unicode && !strncmp((char *)lParam, "{\\rtf", 5))
+      if (!strncmp((char *)lParam, "{\\rtf", 5) ||
+          !strncmp((char *)lParam, "{\\urtf", 6))
       {
         /* Undocumented: WM_SETTEXT supports RTF text */
         ME_StreamInRTFString(editor, 0, (char *)lParam);
@@ -3492,7 +3562,8 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
     }
     else
       TRACE("WM_SETTEXT - NULL\n");
-    ME_UpdateLinkAttribute(editor, 0, -1);
+    ME_SetCursorToStart(editor, &cursor);
+    ME_UpdateLinkAttribute(editor, &cursor, INT_MAX);
     ME_SetSelection(editor, 0, 0);
     editor->nModifyStep = 0;
     ME_CommitUndo(editor);
@@ -3515,12 +3586,13 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
   case WM_CUT:
   case WM_COPY:
   {
-    CHARRANGE range;
-    ME_GetSelection(editor, &range.cpMin, &range.cpMax);
+    int nFrom, nTo, nStartCur = ME_GetSelectionOfs(editor, &nFrom, &nTo);
+    int nChars = nTo - nFrom;
+    ME_Cursor *selStart = &editor->pCursors[nStartCur];
 
-    if (ME_Copy(editor, &range) && msg == WM_CUT)
+    if (ME_Copy(editor, selStart, nChars) && msg == WM_CUT)
     {
-      ME_InternalDeleteText(editor, range.cpMin, range.cpMax-range.cpMin, FALSE);
+      ME_InternalDeleteText(editor, selStart, nChars, FALSE);
       ME_CommitUndo(editor);
       ME_UpdateRepaint(editor);
     }
@@ -3540,67 +3612,51 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
   case WM_GETTEXT:
   {
     GETTEXTEX ex;
-    LRESULT rc;
-    LPSTR bufferA = NULL;
-    LPWSTR bufferW = NULL;
-
-    if (unicode)
-        bufferW = heap_alloc((wParam + 2) * sizeof(WCHAR));
-    else
-        bufferA = heap_alloc(wParam + 2);
-
-    ex.cb = (wParam + 2) * (unicode ? sizeof(WCHAR) : sizeof(CHAR));
+    ex.cb = wParam * (unicode ? sizeof(WCHAR) : sizeof(CHAR));
     ex.flags = GT_USECRLF;
     ex.codepage = unicode ? 1200 : CP_ACP;
     ex.lpDefaultChar = NULL;
     ex.lpUsedDefChar = NULL;
-
-    rc = ME_GetTextEx(editor, &ex, unicode ? (LPARAM)bufferW : (LPARAM)bufferA);
-
-    if (unicode)
-    {
-        memcpy((LPWSTR)lParam, bufferW, wParam * sizeof(WCHAR));
-        if (strlenW(bufferW) >= wParam) rc = 0;
-    }
-    else
-    {
-        memcpy((LPSTR)lParam, bufferA, wParam);
-        if (strlen(bufferA) >= wParam) rc = 0;
-    }
-    heap_free(bufferA);
-    heap_free(bufferW);
-    return rc;
+    return ME_GetTextEx(editor, &ex, lParam);
   }
   case EM_GETTEXTEX:
     return ME_GetTextEx(editor, (GETTEXTEX*)wParam, lParam);
   case EM_GETSELTEXT:
   {
-    int from, to;
-    ME_GetSelection(editor, &from, &to);
+    int nFrom, nTo, nStartCur = ME_GetSelectionOfs(editor, &nFrom, &nTo);
+    ME_Cursor *from = &editor->pCursors[nStartCur];
     return ME_GetTextRange(editor, (WCHAR *)lParam, from,
-                           to - from, unicode);
+                           nTo - nFrom, unicode);
   }
   case EM_GETSCROLLPOS:
   {
     POINT *point = (POINT *)lParam;
     point->x = editor->horz_si.nPos;
     point->y = editor->vert_si.nPos;
+    /* 16-bit scaled value is returned as stored in scrollinfo */
+    if (editor->horz_si.nMax > 0xffff)
+      point->x = MulDiv(point->x, 0xffff, editor->horz_si.nMax);
+    if (editor->vert_si.nMax > 0xffff)
+      point->y = MulDiv(point->y, 0xffff, editor->vert_si.nMax);
     return 1;
   }
   case EM_GETTEXTRANGE:
   {
     TEXTRANGEW *rng = (TEXTRANGEW *)lParam;
-    int start = rng->chrg.cpMin;
-    int end = rng->chrg.cpMax;
+    ME_Cursor start;
+    int nStart = rng->chrg.cpMin;
+    int nEnd = rng->chrg.cpMax;
     int textlength = ME_GetTextLength(editor);
-    TRACE("EM_GETTEXTRANGE min=%d max=%d unicode=%d emul1.0=%d length=%d\n",
-      rng->chrg.cpMin, rng->chrg.cpMax, unicode,
-      editor->bEmulateVersion10, ME_GetTextLength(editor));
-    if (start < 0) return 0;
-    if ((start == 0 && end == -1) || end > textlength)
-      end = textlength;
-    if (start >= end) return 0;
-    return ME_GetTextRange(editor, rng->lpstrText, start, end - start, unicode);
+
+    TRACE("EM_GETTEXTRANGE min=%d max=%d unicode=%d textlength=%d\n",
+          rng->chrg.cpMin, rng->chrg.cpMax, unicode, textlength);
+    if (nStart < 0) return 0;
+    if ((nStart == 0 && nEnd == -1) || nEnd > textlength)
+      nEnd = textlength;
+    if (nStart >= nEnd) return 0;
+
+    ME_CursorFromCharOfs(editor, nStart, &start);
+    return ME_GetTextRange(editor, rng->lpstrText, &start, nEnd - nStart, unicode);
   }
   case EM_GETLINE:
   {
@@ -3686,14 +3742,14 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
   case EM_LINEFROMCHAR:
   {
     if (wParam == -1)
-      return ME_RowNumberFromCharOfs(editor, ME_GetCursorOfs(editor, 1));
+      return ME_RowNumberFromCharOfs(editor, ME_GetCursorOfs(&editor->pCursors[1]));
     else
       return ME_RowNumberFromCharOfs(editor, wParam);
   }
   case EM_EXLINEFROMCHAR:
   {
     if (lParam == -1)
-      return ME_RowNumberFromCharOfs(editor, ME_GetCursorOfs(editor,1));
+      return ME_RowNumberFromCharOfs(editor, ME_GetCursorOfs(&editor->pCursors[1]));
     else    
       return ME_RowNumberFromCharOfs(editor, lParam);
   }
@@ -3809,7 +3865,14 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
   case EM_SETZOOM:
     return ME_SetZoom(editor, wParam, lParam);
   case EM_CHARFROMPOS:
-    return ME_CharFromPos(editor, ((POINTL *)lParam)->x, ((POINTL *)lParam)->y, NULL);
+  {
+    ME_Cursor cursor;
+    if (ME_CharFromPos(editor, ((POINTL *)lParam)->x, ((POINTL *)lParam)->y,
+                       &cursor, NULL))
+      return ME_GetCursorOfs(&cursor);
+    else
+      return -1;
+  }
   case EM_POSFROMCHAR:
   {
     ME_DisplayItem *pPara, *pRun;
@@ -3841,23 +3904,29 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
   }
   case WM_CREATE:
   {
-    SCROLLINFO si;
+    INT max;
 
     ME_SetDefaultFormatRect(editor);
 
-    si.cbSize = sizeof(si);
-    si.fMask = SIF_PAGE | SIF_RANGE;
+    max = (editor->styleFlags & ES_DISABLENOSCROLL) ? 1 : 0;
+    if (~editor->styleFlags & ES_DISABLENOSCROLL || editor->styleFlags & WS_VSCROLL)
+      ITextHost_TxSetScrollRange(editor->texthost, SB_VERT, 0, max, TRUE);
+
+    if (~editor->styleFlags & ES_DISABLENOSCROLL || editor->styleFlags & WS_HSCROLL)
+      ITextHost_TxSetScrollRange(editor->texthost, SB_HORZ, 0, max, TRUE);
+
     if (editor->styleFlags & ES_DISABLENOSCROLL)
-      si.fMask |= SIF_DISABLENOSCROLL;
-    si.nMax = (si.fMask & SIF_DISABLENOSCROLL) ? 1 : 0;
-    si.nMin = 0;
-    si.nPage = 0;
-    if (editor->hWnd) {
-      SetScrollInfo(editor->hWnd, SB_VERT, &si, TRUE);
-      SetScrollInfo(editor->hWnd, SB_HORZ, &si, TRUE);
-    } else {
-      ITextHost_TxSetScrollRange(editor->texthost, SB_VERT, si.nMin, si.nMax, TRUE);
-      ITextHost_TxSetScrollRange(editor->texthost, SB_HORZ, si.nMin, si.nMax, TRUE);
+    {
+      if (editor->styleFlags & WS_VSCROLL)
+      {
+        ITextHost_TxEnableScrollBar(editor->texthost, SB_VERT, ESB_DISABLE_BOTH);
+        ITextHost_TxShowScrollBar(editor->texthost, SB_VERT, TRUE);
+      }
+      if (editor->styleFlags & WS_HSCROLL)
+      {
+        ITextHost_TxEnableScrollBar(editor->texthost, SB_HORZ, ESB_DISABLE_BOTH);
+        ITextHost_TxShowScrollBar(editor->texthost, SB_HORZ, TRUE);
+      }
     }
 
     ME_CommitUndo(editor);
@@ -4004,15 +4073,10 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
       case SB_THUMBTRACK:
       case SB_THUMBPOSITION:
       {
-        SCROLLINFO sbi;
-        sbi.cbSize = sizeof(sbi);
-        sbi.fMask = SIF_TRACKPOS;
-        /* Try to get 32-bit track position value. */
-        if (!GetScrollInfo(editor->hWnd, SB_HORZ, &sbi))
-          /* GetScrollInfo failed, settle for 16-bit value in wParam. */
-          sbi.nTrackPos = HIWORD(wParam);
-
-        ME_HScrollAbs(editor, sbi.nTrackPos);
+        int pos = HIWORD(wParam);
+        if (editor->horz_si.nMax > 0xffff)
+          pos = MulDiv(pos, editor->horz_si.nMax, 0xffff);
+        ME_HScrollAbs(editor, pos);
         break;
       }
     }
@@ -4056,15 +4120,10 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
       case SB_THUMBTRACK:
       case SB_THUMBPOSITION:
       {
-        SCROLLINFO sbi;
-        sbi.cbSize = sizeof(sbi);
-        sbi.fMask = SIF_TRACKPOS;
-        /* Try to get 32-bit track position value. */
-        if (!GetScrollInfo(editor->hWnd, SB_VERT, &sbi))
-          /* GetScrollInfo failed, settle for 16-bit value in wParam. */
-          sbi.nTrackPos = HIWORD(wParam);
-
-        ME_VScrollAbs(editor, sbi.nTrackPos);
+        int pos = HIWORD(wParam);
+        if (editor->vert_si.nMax > 0xffff)
+          pos = MulDiv(pos, editor->vert_si.nMax, 0xffff);
+        ME_VScrollAbs(editor, pos);
         break;
       }
     }
@@ -4186,7 +4245,7 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
     return 0;
   case WM_IME_STARTCOMPOSITION:
   {
-    editor->imeStartIndex=ME_GetCursorOfs(editor,0);
+    editor->imeStartIndex=ME_GetCursorOfs(&editor->pCursors[0]);
     ME_DeleteSelection(editor);
     ME_CommitUndo(editor);
     ME_UpdateRepaint(editor);
@@ -4350,7 +4409,7 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
       ITextHost *texthost;
 
       TRACE("WM_NCCREATE: hWnd %p style 0x%08x\n", hWnd, pcs->style);
-      texthost = ME_CreateTextHost(hWnd, FALSE);
+      texthost = ME_CreateTextHost(hWnd, pcs, FALSE);
       return texthost != NULL;
     }
     else if (msg != WM_NCDESTROY)
@@ -4480,7 +4539,7 @@ LRESULT WINAPI RichEdit10ANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
     CREATESTRUCTW *pcs = (CREATESTRUCTW *)lParam;
 
     TRACE("WM_NCCREATE: hWnd %p style 0x%08x\n", hWnd, pcs->style);
-    texthost = ME_CreateTextHost(hWnd, TRUE);
+    texthost = ME_CreateTextHost(hWnd, pcs, TRUE);
     return texthost != NULL;
   }
   return RichEditANSIWndProc(hWnd, msg, wParam, lParam);
@@ -4491,81 +4550,71 @@ void ME_SendOldNotify(ME_TextEditor *editor, int nCode)
   ITextHost_TxNotify(editor->texthost, nCode, NULL);
 }
 
-int ME_CountParagraphsBetween(ME_TextEditor *editor, int from, int to)
-{
-  ME_DisplayItem *item = ME_FindItemFwd(editor->pBuffer->pFirst, diParagraph);
-  int i = 0;
-  
-  while(item && item->member.para.next_para->member.para.nCharOfs <= from)
-    item = item->member.para.next_para;
-  if (!item)
-    return 0;
-  while(item && item->member.para.next_para->member.para.nCharOfs <= to) {
-    item = item->member.para.next_para;
-    i++;
-  }
-  return i;
-}
-
-
-int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart,
-                int nChars, int bCRLF)
+/* Fill buffer with srcChars unicode characters from the start cursor.
+ *
+ * buffer: destination buffer
+ * buflen: length of buffer in characters excluding the NULL terminator.
+ * start: start of editor text to copy into buffer.
+ * srcChars: Number of characters to use from the editor text.
+ * bCRLF: if true, replaces all end of lines with \r\n pairs.
+ *
+ * returns the number of characters written excluding the NULL terminator.
+ *
+ * The written text is always NULL terminated.
+ */
+int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int buflen,
+                const ME_Cursor *start, int srcChars, BOOL bCRLF)
 {
-  ME_DisplayItem *pRun;
-  int nOffset, nWritten = 0;
-  WCHAR *pStart = buffer;
-
-  ME_RunOfsFromCharOfs(editor, nStart, NULL, &pRun, &nOffset);
+  ME_DisplayItem *pRun, *pNextRun;
+  const WCHAR *pStart = buffer;
+  const WCHAR cr_lf[] = {'\r', '\n', 0};
+  const WCHAR *str;
+  int nLen;
 
   /* bCRLF flag is only honored in 2.0 and up. 1.0 must always return text verbatim */
   if (editor->bEmulateVersion10) bCRLF = 0;
 
-  while (nChars && pRun)
+  pRun = start->pRun;
+  assert(pRun);
+  pNextRun = ME_FindItemFwd(pRun, diRun);
+
+  nLen = pRun->member.run.strText->nLen - start->nOffset;
+  str = pRun->member.run.strText->szData + start->nOffset;
+
+  /* No '\r' is appended to the last paragraph. */
+  while (srcChars && buflen && pNextRun)
   {
-    int nLen;
+    int nFlags = pRun->member.run.nFlags;
 
-    if (pRun->member.run.nFlags & MERF_ENDCELL &&
-        pRun->member.run.nFlags & MERF_ENDPARA)
+    if (bCRLF && nFlags & MERF_ENDPARA && ~nFlags & MERF_ENDCELL)
     {
-      *buffer = '\t';
-      nLen = 1;
-    } else if (pRun->member.run.nFlags & MERF_ENDPARA) {
-      if (!ME_FindItemFwd(pRun, diRun)) {
-        /* No '\r' is appended to the last paragraph. */
-        nLen = 0;
-      } else if (bCRLF && nChars == 1) {
-        nLen = 0;
-        nChars = 0;
-      } else {
-        WCHAR cr_lf[] = {'\r', '\n', 0};
-        WCHAR *szData;
-
-        if (bCRLF)
-        {
-          nLen = 2;
-          szData = cr_lf;
-        } else {
-          nLen = pRun->member.run.strText->nLen;
-          szData = pRun->member.run.strText->szData;
-        }
-        nLen = min(nChars, nLen - nOffset);
-        CopyMemory(buffer, szData + nOffset, sizeof(WCHAR) * nLen);
-      }
+      if (buflen == 1) break;
+      /* FIXME: native fails to reduce srcChars here for WM_GETTEXT or
+       *        EM_GETTEXTEX, however, this is done for copying text which
+       *        also uses this function. */
+      srcChars -= min(nLen, srcChars);
+      nLen = 2;
+      str = cr_lf;
     } else {
-      nLen = min(nChars, pRun->member.run.strText->nLen - nOffset);
-      CopyMemory(buffer, pRun->member.run.strText->szData + nOffset,
-                 sizeof(WCHAR) * nLen);
+      nLen = min(nLen, srcChars);
+      srcChars -= nLen;
     }
-    nChars -= nLen;
-    nWritten += nLen;
+
+    nLen = min(nLen, buflen);
+    buflen -= nLen;
+
+    CopyMemory(buffer, str, sizeof(WCHAR) * nLen);
+
     buffer += nLen;
-    nOffset = 0;
 
-    pRun = ME_FindItemFwd(pRun, diRun);
+    pRun = pNextRun;
+    pNextRun = ME_FindItemFwd(pRun, diRun);
+
+    nLen = pRun->member.run.strText->nLen;
+    str = pRun->member.run.strText->szData;
   }
   *buffer = 0;
-  TRACE("nWritten=%d, actual=%d\n", nWritten, buffer-pStart);
-  return nWritten;
+  return buffer - pStart;
 }
 
 static BOOL ME_RegisterEditorClass(HINSTANCE hInstance)
@@ -4585,9 +4634,9 @@ static BOOL ME_RegisterEditorClass(HINSTANCE hInstance)
 
   if (is_version_nt())
   {
-    wcW.lpszClassName = RichEdit20W;
+    wcW.lpszClassName = RICHEDIT_CLASS20W;
     if (!RegisterClassW(&wcW)) return FALSE;
-    wcW.lpszClassName = RichEdit50W;
+    wcW.lpszClassName = MSFTEDIT_CLASS;
     if (!RegisterClassW(&wcW)) return FALSE;
   }
   else
@@ -4608,7 +4657,7 @@ static BOOL ME_RegisterEditorClass(HINSTANCE hInstance)
   wcA.hCursor = LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_IBEAM));
   wcA.hbrBackground = GetStockObject(NULL_BRUSH);
   wcA.lpszMenuName = NULL;
-  wcA.lpszClassName = "RichEdit20A";
+  wcA.lpszClassName = RICHEDIT_CLASS20A;
   if (!RegisterClassA(&wcA)) return FALSE;
   wcA.lpszClassName = "RichEdit50A";
   if (!RegisterClassA(&wcA)) return FALSE;
@@ -4688,145 +4737,135 @@ static BOOL isurlspecial(WCHAR c)
  * or one of the following special characters: *|/\+%#@ and must consist entirely
  * of the characters allowed to start the URL, plus : (colon) which may occur
  * at most once, and not at either end.
- *
- * sel_max == -1 indicates scan to end of text.
  */
-static BOOL ME_FindNextURLCandidate(ME_TextEditor *editor, int sel_min, int sel_max,
-        int * candidate_min, int * candidate_max)
+static BOOL ME_FindNextURLCandidate(ME_TextEditor *editor,
+                                    const ME_Cursor *start,
+                                    int nChars,
+                                    ME_Cursor *candidate_min,
+                                    ME_Cursor *candidate_max)
 {
-  ME_DisplayItem * item;
-  ME_DisplayItem * para;
-  int nStart;
+  ME_Cursor cursor = *start;
   BOOL foundColon = FALSE;
+  BOOL candidateStarted = FALSE;
   WCHAR lastAcceptedChar = '\0';
 
-  TRACE("sel_min = %d sel_max = %d\n", sel_min, sel_max);
-
-  *candidate_min = *candidate_max = -1;
-  ME_RunOfsFromCharOfs(editor, sel_min, &para, &item, &nStart);
-  TRACE("nStart = %d\n", nStart);
-  if (sel_max == -1) sel_max = ME_GetTextLength(editor);
-  while (item && para->member.para.nCharOfs + item->member.run.nCharOfs + nStart < sel_max)
+  while (nChars > 0)
   {
-    ME_DisplayItem * next_item;
+    WCHAR *strStart = cursor.pRun->member.run.strText->szData;
+    WCHAR *str = strStart + cursor.nOffset;
+    int nLen = cursor.pRun->member.run.strText->nLen - cursor.nOffset;
+    nChars -= nLen;
 
-    if (!(item->member.run.nFlags & MERF_ENDPARA)) {
+    if (~cursor.pRun->member.run.nFlags & MERF_ENDPARA)
+    {
       /* Find start of candidate */
-      if (*candidate_min == -1) {
-        while (nStart < item->member.run.strText->nLen &&
-                !(isalnumW(item->member.run.strText->szData[nStart]) ||
-                  isurlspecial(item->member.run.strText->szData[nStart]))) {
-          nStart++;
-        }
-        if (nStart < item->member.run.strText->nLen &&
-                (isalnumW(item->member.run.strText->szData[nStart]) ||
-                 isurlspecial(item->member.run.strText->szData[nStart]))) {
-          *candidate_min = para->member.para.nCharOfs + item->member.run.nCharOfs + nStart;
-          lastAcceptedChar = item->member.run.strText->szData[nStart];
-          nStart++;
+      if (!candidateStarted)
+      {
+        while (nLen)
+        {
+          nLen--;
+          if (isalnumW(*str) || isurlspecial(*str))
+          {
+            cursor.nOffset = str - strStart;
+            *candidate_min = cursor;
+            candidateStarted = TRUE;
+            lastAcceptedChar = *str++;
+            break;
+          }
+          str++;
         }
       }
 
       /* Find end of candidate */
-      if (*candidate_min >= 0) {
-        while (nStart < item->member.run.strText->nLen &&
-                (isalnumW(item->member.run.strText->szData[nStart]) ||
-                 isurlspecial(item->member.run.strText->szData[nStart]) ||
-                 (!foundColon && item->member.run.strText->szData[nStart] == ':') )) {
-          if (item->member.run.strText->szData[nStart] == ':') foundColon = TRUE;
-          lastAcceptedChar = item->member.run.strText->szData[nStart];
-          nStart++;
-        }
-        if (nStart < item->member.run.strText->nLen &&
-                !(isalnumW(item->member.run.strText->szData[nStart]) ||
-                 isurlspecial(item->member.run.strText->szData[nStart]) )) {
-          *candidate_max = para->member.para.nCharOfs + item->member.run.nCharOfs + nStart;
-          nStart++;
-          if (lastAcceptedChar == ':') (*candidate_max)--;
-          return TRUE;
+      if (candidateStarted) {
+        while (nLen)
+        {
+          nLen--;
+          if (*str == ':' && !foundColon) {
+            foundColon = TRUE;
+          } else if (!isalnumW(*str) && !isurlspecial(*str)) {
+            cursor.nOffset = str - strStart;
+            if (lastAcceptedChar == ':')
+              ME_MoveCursorChars(editor, &cursor, -1);
+            *candidate_max = cursor;
+            return TRUE;
+          }
+          lastAcceptedChar = *str++;
         }
       }
     } else {
       /* End of paragraph: skip it if before candidate span, or terminates
          current active span */
-      if (*candidate_min >= 0) {
-        *candidate_max = para->member.para.nCharOfs + item->member.run.nCharOfs;
-        if (lastAcceptedChar == ':') (*candidate_max)--;
+      if (candidateStarted) {
+        if (lastAcceptedChar == ':')
+          ME_MoveCursorChars(editor, &cursor, -1);
+        *candidate_max = cursor;
         return TRUE;
       }
     }
 
     /* Reaching this point means no span was found, so get next span */
-    next_item = ME_FindItemFwd(item, diRun);
-    if (!next_item) {
-      if (*candidate_min >= 0) {
+    if (!ME_NextRun(&cursor.pPara, &cursor.pRun)) {
+      if (candidateStarted) {
         /* There are no further runs, so take end of text as end of candidate */
-        *candidate_max = para->member.para.nCharOfs + item->member.run.nCharOfs + nStart;
-        if (lastAcceptedChar == ':') (*candidate_max)--;
+        cursor.nOffset = str - strStart;
+        if (lastAcceptedChar == ':')
+          ME_MoveCursorChars(editor, &cursor, -1);
+        *candidate_max = cursor;
         return TRUE;
       }
+      *candidate_max = *candidate_min = cursor;
+      return FALSE;
     }
-    item = next_item;
-    para = ME_GetParagraph(item);
-    nStart = 0;
+    cursor.nOffset = 0;
   }
 
-  if (item) {
-    if (*candidate_min >= 0) {
-      /* There are no further runs, so take end of text as end of candidate */
-      *candidate_max = para->member.para.nCharOfs + item->member.run.nCharOfs + nStart;
-      if (lastAcceptedChar == ':') (*candidate_max)--;
-      return TRUE;
-    }
+  if (candidateStarted) {
+    /* There are no further runs, so take end of text as end of candidate */
+    if (lastAcceptedChar == ':')
+      ME_MoveCursorChars(editor, &cursor, -1);
+    *candidate_max = cursor;
+    return TRUE;
   }
+  *candidate_max = *candidate_min = cursor;
   return FALSE;
 }
 
 /**
  * This proc evaluates the selection and returns TRUE if it can be considered an URL
  */
-static BOOL ME_IsCandidateAnURL(ME_TextEditor *editor, int sel_min, int sel_max)
+static BOOL ME_IsCandidateAnURL(ME_TextEditor *editor, const ME_Cursor *start, int nChars)
 {
+#define MAX_PREFIX_LEN 9
   struct prefix_s {
-    const char *text;
+    const WCHAR text[MAX_PREFIX_LEN];
     int length;
-  } prefixes[12] = {
-    /* Code below depends on these being in decreasing length order! */
-    {"prospero:", 10},
-    {"telnet:", 8},
-    {"gopher:", 8},
-    {"mailto:", 8},
-    {"https:", 7},
-    {"file:", 6},
-    {"news:", 6},
-    {"wais:", 6},
-    {"nntp:", 6},
-    {"http:", 5},
-    {"www.", 5},
-    {"ftp:", 5},
+  }prefixes[] = {
+    {{'p','r','o','s','p','e','r','o',':'}, 9},
+    {{'t','e','l','n','e','t',':'}, 7},
+    {{'g','o','p','h','e','r',':'}, 7},
+    {{'m','a','i','l','t','o',':'}, 7},
+    {{'h','t','t','p','s',':'}, 6},
+    {{'f','i','l','e',':'}, 5},
+    {{'n','e','w','s',':'}, 5},
+    {{'w','a','i','s',':'}, 5},
+    {{'n','n','t','p',':'}, 5},
+    {{'h','t','t','p',':'}, 5},
+    {{'w','w','w','.'}, 4},
+    {{'f','t','p',':'}, 4},
   };
-  LPWSTR bufferW = NULL;
-  WCHAR bufW[32];
+  WCHAR bufferW[MAX_PREFIX_LEN + 1];
   unsigned int i;
 
-  if (sel_max == -1) sel_max = ME_GetTextLength(editor);
-  assert(sel_min <= sel_max);
-  for (i = 0; i < sizeof(prefixes) / sizeof(struct prefix_s); i++)
+  ME_GetTextW(editor, bufferW, MAX_PREFIX_LEN, start, nChars, 0);
+  for (i = 0; i < sizeof(prefixes) / sizeof(*prefixes); i++)
   {
-    if (sel_max - sel_min < prefixes[i].length) continue;
-    if (bufferW == NULL) {
-      bufferW = heap_alloc((sel_max - sel_min + 1) * sizeof(WCHAR));
-    }
-    ME_GetTextW(editor, bufferW, sel_min, min(sel_max - sel_min, lstrlenA(prefixes[i].text)), 0);
-    MultiByteToWideChar(CP_ACP, 0, prefixes[i].text, -1, bufW, 32);
-    if (!lstrcmpW(bufW, bufferW))
-    {
-      heap_free(bufferW);
+    if (nChars < prefixes[i].length) continue;
+    if (!memcmp(prefixes[i].text, bufferW, prefixes[i].length * sizeof(WCHAR)))
       return TRUE;
-    }
   }
-  heap_free(bufferW);
   return FALSE;
+#undef MAX_PREFIX_LEN
 }
 
 /**
@@ -4835,53 +4874,48 @@ static BOOL ME_IsCandidateAnURL(ME_TextEditor *editor, int sel_min, int sel_max)
  * their proper CFE_LINK attributes set or unset. If the CFE_LINK attribute is
  * not what it is supposed to be, this proc sets or unsets it as appropriate.
  *
+ * Since this function can cause runs to be split, do not depend on the value
+ * of the start cursor at the end of the function.
+ *
+ * nChars may be set to INT_MAX to update to the end of the text.
+ *
  * Returns TRUE if at least one section was modified.
  */
-static BOOL ME_UpdateLinkAttribute(ME_TextEditor *editor, int sel_min, int sel_max)
+static BOOL ME_UpdateLinkAttribute(ME_TextEditor *editor, ME_Cursor *start, int nChars)
 {
   BOOL modified = FALSE;
-  int cMin, cMax;
+  ME_Cursor startCur = *start;
 
   if (!editor->AutoURLDetect_bEnable) return FALSE;
 
-  if (sel_max == -1) sel_max = ME_GetTextLength(editor);
   do
   {
-    int beforeURL[2];
-    int inURL[2];
     CHARFORMAT2W link;
+    ME_Cursor candidateStart, candidateEnd;
 
-    if (ME_FindNextURLCandidate(editor, sel_min, sel_max, &cMin, &cMax))
+    if (ME_FindNextURLCandidate(editor, &startCur, nChars,
+                                &candidateStart, &candidateEnd))
     {
       /* Section before candidate is not an URL */
-      beforeURL[0] = sel_min;
-      beforeURL[1] = cMin;
+      int cMin = ME_GetCursorOfs(&candidateStart);
+      int cMax = ME_GetCursorOfs(&candidateEnd);
 
-      if (ME_IsCandidateAnURL(editor, cMin, cMax))
-      {
-        inURL[0] = cMin; inURL[1] = cMax;
-      }
-      else
-      {
-        beforeURL[1] = cMax;
-        inURL[0] = inURL[1] = -1;
-      }
-      sel_min = cMax;
+      if (!ME_IsCandidateAnURL(editor, &candidateStart, cMax - cMin))
+        candidateStart = candidateEnd;
+      nChars -= cMax - ME_GetCursorOfs(&startCur);
     }
     else
     {
       /* No more candidates until end of selection */
-      beforeURL[0] = sel_min;
-      beforeURL[1] = sel_max;
-      inURL[0] = inURL[1] = -1;
-      sel_min = sel_max;
+      nChars = 0;
     }
 
-    if (beforeURL[0] < beforeURL[1])
+    if (startCur.pRun != candidateStart.pRun ||
+        startCur.nOffset != candidateStart.nOffset)
     {
       /* CFE_LINK effect should be consistently unset */
       link.cbSize = sizeof(link);
-      ME_GetCharFormat(editor, beforeURL[0], beforeURL[1], &link);
+      ME_GetCharFormat(editor, &startCur, &candidateStart, &link);
       if (!(link.dwMask & CFM_LINK) || (link.dwEffects & CFE_LINK))
       {
         /* CFE_LINK must be unset from this range */
@@ -4889,15 +4923,24 @@ static BOOL ME_UpdateLinkAttribute(ME_TextEditor *editor, int sel_min, int sel_m
         link.cbSize = sizeof(link);
         link.dwMask = CFM_LINK;
         link.dwEffects = 0;
-        ME_SetCharFormat(editor, beforeURL[0], beforeURL[1] - beforeURL[0], &link);
+        ME_SetCharFormat(editor, &startCur, &candidateStart, &link);
+        /* Update candidateEnd since setting character formats may split
+         * runs, which can cause a cursor to be at an invalid offset within
+         * a split run. */
+        while (candidateEnd.nOffset >= candidateEnd.pRun->member.run.strText->nLen)
+        {
+          candidateEnd.nOffset -= candidateEnd.pRun->member.run.strText->nLen;
+          candidateEnd.pRun = ME_FindItemFwd(candidateEnd.pRun, diRun);
+        }
         modified = TRUE;
       }
     }
-    if (inURL[0] < inURL[1])
+    if (candidateStart.pRun != candidateEnd.pRun ||
+        candidateStart.nOffset != candidateEnd.nOffset)
     {
       /* CFE_LINK effect should be consistently set */
       link.cbSize = sizeof(link);
-      ME_GetCharFormat(editor, inURL[0], inURL[1], &link);
+      ME_GetCharFormat(editor, &candidateStart, &candidateEnd, &link);
       if (!(link.dwMask & CFM_LINK) || !(link.dwEffects & CFE_LINK))
       {
         /* CFE_LINK must be set on this range */
@@ -4905,10 +4948,11 @@ static BOOL ME_UpdateLinkAttribute(ME_TextEditor *editor, int sel_min, int sel_m
         link.cbSize = sizeof(link);
         link.dwMask = CFM_LINK;
         link.dwEffects = CFE_LINK;
-        ME_SetCharFormat(editor, inURL[0], inURL[1] - inURL[0], &link);
+        ME_SetCharFormat(editor, &candidateStart, &candidateEnd, &link);
         modified = TRUE;
       }
     }
-  } while (sel_min < sel_max);
+    startCur = candidateEnd;
+  } while (nChars > 0);
   return modified;
 }
index 0929e82..9739eea 100644 (file)
@@ -77,6 +77,8 @@ void ME_CharFormatFromLogFont(HDC hDC, const LOGFONTW *lf, CHARFORMAT2W *fmt); /
 /* list.c */
 void ME_InsertBefore(ME_DisplayItem *diWhere, ME_DisplayItem *diWhat);
 void ME_Remove(ME_DisplayItem *diWhere);
+BOOL ME_NextRun(ME_DisplayItem **para, ME_DisplayItem **run);
+BOOL ME_PrevRun(ME_DisplayItem **para, ME_DisplayItem **run);
 ME_DisplayItem *ME_FindItemBack(ME_DisplayItem *di, ME_DIType nTypeOrClass);
 ME_DisplayItem *ME_FindItemFwd(ME_DisplayItem *di, ME_DIType nTypeOrClass);
 ME_DisplayItem *ME_FindItemBackOrHere(ME_DisplayItem *di, ME_DIType nTypeOrClass);
@@ -95,7 +97,6 @@ ME_String *ME_VSplitString(ME_String *orig, int nVPos);
 int ME_IsWhitespaces(const ME_String *s);
 int ME_IsSplitable(const ME_String *s);
 int ME_FindNonWhitespaceV(const ME_String *s, int nVChar);
-int ME_FindWhitespaceV(ME_String *s, int nVChar);
 int ME_CallWordBreakProc(ME_TextEditor *editor, ME_String *str, INT start, INT code);
 void ME_StrDeleteV(ME_String *s, int nVChar, int nChars);
 /* smart helpers for A<->W conversions, they reserve/free memory and call MultiByte<->WideChar functions */
@@ -120,14 +121,11 @@ int ME_ReverseFindWhitespaceV(const ME_String *s, int nVChar);
 /* row.c */
 ME_DisplayItem *ME_RowStart(ME_DisplayItem *item);
 /* ME_DisplayItem *ME_RowEnd(ME_DisplayItem *item); */
-void ME_RenumberParagraphs(ME_DisplayItem *item); /* TODO */
 ME_DisplayItem *ME_FindRowWithNumber(ME_TextEditor *editor, int nRow);
 int ME_RowNumberFromCharOfs(ME_TextEditor *editor, int nOfs);
 
 /* run.c */
 ME_DisplayItem *ME_MakeRun(ME_Style *s, ME_String *strData, int nFlags);
-/* note: ME_InsertRun inserts a copy of the specified run - so you need to destroy the original */
-ME_DisplayItem *ME_InsertRun(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem *pItem);
 ME_DisplayItem *ME_InsertRunAtCursor(ME_TextEditor *editor, ME_Cursor *cursor,
                                      ME_Style *style, const WCHAR *str, int len, int flags);
 void ME_CheckCharOffsets(ME_TextEditor *editor);
@@ -136,49 +134,49 @@ int ME_CharFromPoint(ME_Context *c, int cx, ME_Run *run);
 /* this one accounts for 1/2 char tolerance */
 int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run);
 int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset);
-int ME_GetLastSplittablePlace(ME_Context *c, ME_Run *run);
 int ME_CanJoinRuns(const ME_Run *run1, const ME_Run *run2);
 void ME_JoinRuns(ME_TextEditor *editor, ME_DisplayItem *p);
 ME_DisplayItem *ME_SplitRun(ME_WrapContext *wc, ME_DisplayItem *item, int nChar);
 ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, int nChar);
-int ME_FindSplitPoint(ME_Context *c, POINT *pt, ME_Run *run, int desperate);
 void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run);
-ME_DisplayItem *ME_SplitFurther(ME_TextEditor *editor, ME_DisplayItem *run);
 void ME_CalcRunExtent(ME_Context *c, const ME_Paragraph *para, int startx, ME_Run *run);
 SIZE ME_GetRunSize(ME_Context *c, const ME_Paragraph *para, ME_Run *run, int nLen, int startx);
 void ME_CursorFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_Cursor *pCursor);
 void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **ppPara, ME_DisplayItem **ppRun, int *pOfs);
 int ME_CharOfsFromRunOfs(ME_TextEditor *editor, const ME_DisplayItem *pPara, const ME_DisplayItem *pRun, int nOfs);
 void ME_SkipAndPropagateCharOffset(ME_DisplayItem *p, int shift);
-void ME_SetCharFormat(ME_TextEditor *editor, int nFrom, int nLen, CHARFORMAT2W *pFmt);
+void ME_SetCharFormat(ME_TextEditor *editor, ME_Cursor *start, ME_Cursor *end, CHARFORMAT2W *pFmt);
 void ME_SetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt);
-void ME_GetCharFormat(ME_TextEditor *editor, int nFrom, int nLen, CHARFORMAT2W *pFmt);
+void ME_GetCharFormat(ME_TextEditor *editor, const ME_Cursor *from,
+                      const ME_Cursor *to, CHARFORMAT2W *pFmt);
 void ME_GetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt);
 void ME_GetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt);
 void ME_SetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *mod);
 
 /* caret.c */
+void ME_SetCursorToStart(ME_TextEditor *editor, ME_Cursor *cursor);
 int ME_SetSelection(ME_TextEditor *editor, int from, int to);
 void ME_HideCaret(ME_TextEditor *ed);
 void ME_ShowCaret(ME_TextEditor *ed);
 void ME_MoveCaret(ME_TextEditor *ed);
-int ME_CharFromPos(ME_TextEditor *editor, int x, int y, BOOL *isExact);
+BOOL ME_CharFromPos(ME_TextEditor *editor, int x, int y, ME_Cursor *cursor, BOOL *isExact);
 void ME_LButtonDown(ME_TextEditor *editor, int x, int y, int clickNum);
 void ME_MouseMove(ME_TextEditor *editor, int x, int y);
 BOOL ME_DeleteTextAtCursor(ME_TextEditor *editor, int nCursor, int nChars);
 void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, 
                              const WCHAR *str, int len, ME_Style *style);
 void ME_InsertEndRowFromCursor(ME_TextEditor *editor, int nCursor);
+int ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs);
 BOOL ME_ArrowKey(ME_TextEditor *ed, int nVKey, BOOL extend, BOOL ctrl);
 
-int ME_GetCursorOfs(ME_TextEditor *editor, int nCursor);
-void ME_GetSelection(ME_TextEditor *editor, int *from, int *to);
-int ME_CountParagraphsBetween(ME_TextEditor *editor, int from, int to);
+int ME_GetCursorOfs(const ME_Cursor *cursor);
+int ME_GetSelectionOfs(ME_TextEditor *editor, int *from, int *to);
+int ME_GetSelection(ME_TextEditor *editor, ME_Cursor **from, ME_Cursor **to);
 BOOL ME_IsSelection(ME_TextEditor *editor);
 void ME_DeleteSelection(ME_TextEditor *editor);
 void ME_SendSelChange(ME_TextEditor *editor);
 void ME_InsertOLEFromCursor(ME_TextEditor *editor, const REOBJECT* reo, int nCursor);
-BOOL ME_InternalDeleteText(ME_TextEditor *editor, int nOfs, int nChars, BOOL bForce);
+BOOL ME_InternalDeleteText(ME_TextEditor *editor, ME_Cursor *start, int nChars, BOOL bForce);
 int ME_GetTextLength(ME_TextEditor *editor);
 int ME_GetTextLengthEx(ME_TextEditor *editor, const GETTEXTLENGTHEX *how);
 ME_Style *ME_GetSelectionInsertStyle(ME_TextEditor *editor);
@@ -231,8 +229,7 @@ void ME_ScrollRight(ME_TextEditor *editor, int cx);
 void ME_UpdateScrollBar(ME_TextEditor *editor);
 
 /* other functions in paint.c */
-int  ME_GetParaBorderWidth(ME_TextEditor *editor, int);
-int  ME_GetParaLineSpace(ME_Context *c, ME_Paragraph*);
+int ME_GetParaBorderWidth(ME_Context *c, int flags);
 
 /* richole.c */
 LRESULT CreateIRichEditOle(ME_TextEditor *editor, LPVOID *);
@@ -246,14 +243,14 @@ ME_TextEditor *ME_MakeEditor(ITextHost *texthost, BOOL bEmulateVersion10);
 LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
                          LPARAM lParam, BOOL unicode, HRESULT* phresult);
 void ME_SendOldNotify(ME_TextEditor *editor, int nCode);
-int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, BOOL bCRLF);
+int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int buflen,
+                const ME_Cursor *start, int srcChars, BOOL bCRLF);
 void ME_RTFCharAttrHook(struct _RTF_Info *info);
 void ME_RTFParAttrHook(struct _RTF_Info *info);
 void ME_RTFTblAttrHook(struct _RTF_Info *info);
 void ME_RTFSpecialCharHook(struct _RTF_Info *info);
 void ME_StreamInFill(ME_InStream *stream);
 extern int me_debug;
-extern void DoWrap(ME_TextEditor *editor);
 
 /* table.c */
 BOOL ME_IsInTable(ME_DisplayItem *pItem);
@@ -265,7 +262,7 @@ ME_DisplayItem *ME_InsertTableRowEndFromCursor(ME_TextEditor *editor);
 ME_DisplayItem *ME_GetTableRowEnd(ME_DisplayItem *para);
 ME_DisplayItem *ME_GetTableRowStart(ME_DisplayItem *para);
 void ME_CheckTablesForCorruption(ME_TextEditor *editor);
-void ME_ProtectPartialTableDeletion(ME_TextEditor *editor, int nOfs,int *nChars);
+void ME_ProtectPartialTableDeletion(ME_TextEditor *editor, ME_Cursor *c, int *nChars);
 ME_DisplayItem* ME_AppendTableRow(ME_TextEditor *editor, ME_DisplayItem *table_row);
 void ME_TabPressedInTable(ME_TextEditor *editor, BOOL bSelectedRow);
 void ME_MoveCursorFromTableRowStartParagraph(ME_TextEditor *editor);
@@ -273,7 +270,7 @@ struct RTFTable *ME_MakeTableDef(ME_TextEditor *editor);
 void ME_InitTableDef(ME_TextEditor *editor, struct RTFTable *tableDef);
 
 /* txthost.c */
-ITextHost *ME_CreateTextHost(HWND hwnd, BOOL bEmulateVersion10);
+ITextHost *ME_CreateTextHost(HWND hwnd, CREATESTRUCTW *cs, BOOL bEmulateVersion10);
 #ifdef __i386__ /* Use wrappers to perform thiscall on i386 */
 #define TXTHOST_VTABLE(This) (&itextHostStdcallVtbl)
 #else /* __i386__ */
@@ -330,8 +327,8 @@ BOOL ME_Redo(ME_TextEditor *editor);
 void ME_EmptyUndoStack(ME_TextEditor *editor);
 
 /* writer.c */
-LRESULT ME_StreamOutRange(ME_TextEditor *editor, DWORD dwFormat, int nStart, int nTo, EDITSTREAM *stream);
+LRESULT ME_StreamOutRange(ME_TextEditor *editor, DWORD dwFormat, const ME_Cursor *start, int nChars, EDITSTREAM *stream);
 LRESULT ME_StreamOut(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM *stream);
 
 /* clipboard.c */
-HRESULT ME_GetDataObject(ME_TextEditor *editor, const CHARRANGE *lpchrg, LPDATAOBJECT *lplpdataobj);
+HRESULT ME_GetDataObject(ME_TextEditor *editor, const ME_Cursor *start, int nChars, LPDATAOBJECT *lplpdataobj);
index a4af8fe..9b8d645 100644 (file)
@@ -29,6 +29,7 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <limits.h>
 
 #define COBJMACROS
 #define NONAMELESSUNION
@@ -50,7 +51,7 @@
 #include "wine/debug.h"
 
 #ifdef __i386__
-extern struct ITextHostVtbl itextHostStdcallVtbl;
+extern const struct ITextHostVtbl itextHostStdcallVtbl;
 #endif /* __i386__ */
 
 typedef struct tagME_String
@@ -325,7 +326,7 @@ typedef struct tagME_FontCacheItem
 
 typedef struct tagME_TextEditor
 {
-  HWND hWnd;
+  HWND hWnd, hwndParent;
   ITextHost *texthost;
   BOOL bEmulateVersion10;
   ME_TextBuffer *pBuffer;
@@ -369,6 +370,7 @@ typedef struct tagME_TextEditor
   BOOL AutoURLDetect_bEnable;
   WCHAR cPasswordMask;
   BOOL bHaveFocus;
+  BOOL bDialogMode; /* Indicates that we are inside a dialog window */
   /*for IME */
   int imeStartIndex;
   DWORD selofs; /* The size of the selection bar on the left side of control */
index d3d9463..bb91bc4 100644 (file)
@@ -44,22 +44,63 @@ void ME_Remove(ME_DisplayItem *diWhere)
 
 static BOOL ME_DITypesEqual(ME_DIType type, ME_DIType nTypeOrClass)
 {
-  if (type==nTypeOrClass)
-    return TRUE;
-  if (nTypeOrClass==diRunOrParagraph && (type==diRun || type==diParagraph))
-    return TRUE;
-  if (nTypeOrClass==diRunOrStartRow && (type==diRun || type==diStartRow))
-    return TRUE;
-  if (nTypeOrClass==diParagraphOrEnd && (type==diTextEnd || type==diParagraph))
-    return TRUE;
-  if (nTypeOrClass==diStartRowOrParagraph && (type==diStartRow || type==diParagraph))
-    return TRUE;
-  if (nTypeOrClass==diStartRowOrParagraphOrEnd
-    && (type==diStartRow || type==diParagraph || type==diTextEnd))
-    return TRUE;
-  if (nTypeOrClass==diRunOrParagraphOrEnd
-    && (type==diRun || type==diParagraph || type==diTextEnd))
-    return TRUE;
+  switch (nTypeOrClass)
+  {
+    case diRunOrParagraph:
+      return type == diRun || type == diParagraph;
+    case diRunOrStartRow:
+      return type == diRun || type == diStartRow;
+    case diParagraphOrEnd:
+      return type == diTextEnd || type == diParagraph;
+    case diStartRowOrParagraph:
+      return type == diStartRow || type == diParagraph;
+    case diStartRowOrParagraphOrEnd:
+      return type == diStartRow || type == diParagraph || type == diTextEnd;
+    case diRunOrParagraphOrEnd:
+      return type == diRun || type == diParagraph || type == diTextEnd;
+    default:
+      return type == nTypeOrClass;
+  }
+}
+
+/* Modifies run pointer to point to the next run, and modify the
+ * paragraph pointer if moving into the next paragraph.
+ *
+ * Returns TRUE if next run is found, otherwise returns FALSE. */
+BOOL ME_NextRun(ME_DisplayItem **para, ME_DisplayItem **run)
+{
+  ME_DisplayItem *p = (*run)->next;
+  while (p->type != diTextEnd)
+  {
+    if (p->type == diParagraph) {
+      *para = p;
+    } else if (p->type == diRun) {
+      *run = p;
+      return TRUE;
+    }
+    p = p->next;
+  }
+  return FALSE;
+}
+
+/* Modifies run pointer to point to the previous run, and modify the
+ * paragraph pointer if moving into the previous paragraph.
+ *
+ * Returns TRUE if previous run is found, otherwise returns FALSE. */
+BOOL ME_PrevRun(ME_DisplayItem **para, ME_DisplayItem **run)
+{
+  ME_DisplayItem *p = (*run)->prev;
+  while (p->type != diTextStart)
+  {
+    if (p->type == diParagraph) {
+      if (p->member.para.prev_para->type == diParagraph)
+        *para = p->member.para.prev_para;
+    } else if (p->type == diRun) {
+      *run = p;
+      return TRUE;
+    }
+    p = p->prev;
+  }
   return FALSE;
 }
 
index 620ac69..2b01e3c 100644 (file)
@@ -413,7 +413,7 @@ static void ME_DrawRun(ME_Context *c, int x, int y, ME_DisplayItem *rundi, ME_Pa
     return;
 
   start = ME_FindItemBack(rundi, diStartRow);
-  ME_GetSelection(c->editor, &nSelFrom, &nSelTo);
+  ME_GetSelectionOfs(c->editor, &nSelFrom, &nSelTo);
 
   /* Draw selected end-of-paragraph mark */
   if (run->nFlags & MERF_ENDPARA)
@@ -461,19 +461,21 @@ static void ME_DrawRun(ME_Context *c, int x, int y, ME_DisplayItem *rundi, ME_Pa
   }
 }
 
-static const struct {unsigned width_num : 4, width_den : 4, pen_style : 4, dble : 1;} border_details[] = {
-  /* none */            {0, 1, PS_SOLID, FALSE},
-  /* 3/4 */             {3, 4, PS_SOLID, FALSE},
-  /* 1 1/2 */           {3, 2, PS_SOLID, FALSE},
-  /* 2 1/4 */           {9, 4, PS_SOLID, FALSE},
-  /* 3 */               {3, 1, PS_SOLID, FALSE},
-  /* 4 1/2 */           {9, 2, PS_SOLID, FALSE},
-  /* 6 */               {6, 1, PS_SOLID, FALSE},
-  /* 3/4 double */      {3, 4, PS_SOLID, TRUE},
-  /* 1 1/2 double */    {3, 2, PS_SOLID, TRUE},
-  /* 2 1/4 double */    {9, 4, PS_SOLID, TRUE},
-  /* 3/4 gray */        {3, 4, PS_DOT /* FIXME */, FALSE},
-  /* 1 1/2 dashed */    {3, 2, PS_DASH, FALSE},
+/* The documented widths are in points (72 dpi), but converting them to
+ * 96 dpi (standard display resolution) avoids dealing with fractions. */
+static const struct {unsigned width : 8, pen_style : 4, dble : 1;} border_details[] = {
+  /* none */            {0, PS_SOLID, FALSE},
+  /* 3/4 */             {1, PS_SOLID, FALSE},
+  /* 1 1/2 */           {2, PS_SOLID, FALSE},
+  /* 2 1/4 */           {3, PS_SOLID, FALSE},
+  /* 3 */               {4, PS_SOLID, FALSE},
+  /* 4 1/2 */           {6, PS_SOLID, FALSE},
+  /* 6 */               {8, PS_SOLID, FALSE},
+  /* 3/4 double */      {1, PS_SOLID, TRUE},
+  /* 1 1/2 double */    {2, PS_SOLID, TRUE},
+  /* 2 1/4 double */    {3, PS_SOLID, TRUE},
+  /* 3/4 gray */        {1, PS_DOT /* FIXME */, FALSE},
+  /* 1 1/2 dashed */    {2, PS_DASH, FALSE},
 };
 
 static const COLORREF pen_colors[16] = {
@@ -487,25 +489,20 @@ static const COLORREF pen_colors[16] = {
   /* Dark gray */       RGB(0x80, 0x80, 0x80),  /* Light gray */      RGB(0xc0, 0xc0, 0xc0),
 };
 
-static int ME_GetBorderPenWidth(ME_TextEditor* editor, int idx)
+static int ME_GetBorderPenWidth(ME_Context* c, int idx)
 {
-  int width;
+  int width = border_details[idx].width;
+
+  if (c->dpi.cx != 96)
+    width = MulDiv(width, c->dpi.cx, 96);
+
+  if (c->editor->nZoomNumerator != 0)
+    width = MulDiv(width, c->editor->nZoomNumerator, c->editor->nZoomDenominator);
 
-  if (editor->nZoomNumerator == 0)
-  {
-      width = border_details[idx].width_num + border_details[idx].width_den / 2;
-      width /= border_details[idx].width_den;
-  }
-  else
-  {
-      width = border_details[idx].width_num * editor->nZoomNumerator;
-      width += border_details[idx].width_den * editor->nZoomNumerator / 2;
-      width /= border_details[idx].width_den * editor->nZoomDenominator;
-  }
   return width;
 }
 
-int  ME_GetParaBorderWidth(ME_TextEditor* editor, int flags)
+int ME_GetParaBorderWidth(ME_Context* c, int flags)
 {
   int idx = (flags >> 8) & 0xF;
   int width;
@@ -515,34 +512,11 @@ int  ME_GetParaBorderWidth(ME_TextEditor* editor, int flags)
       FIXME("Unsupported border value %d\n", idx);
       return 0;
   }
-  width = ME_GetBorderPenWidth(editor, idx);
+  width = ME_GetBorderPenWidth(c, idx);
   if (border_details[idx].dble) width = width * 2 + 1;
   return width;
 }
 
-int  ME_GetParaLineSpace(ME_Context* c, ME_Paragraph* para)
-{
-  int   sp = 0, ls = 0;
-  if (!(para->pFmt->dwMask & PFM_LINESPACING)) return 0;
-
-  /* FIXME: how to compute simply the line space in ls ??? */
-  /* FIXME: does line spacing include the line itself ??? */
-  switch (para->pFmt->bLineSpacingRule)
-  {
-  case 0:       sp = ls; break;
-  case 1:       sp = (3 * ls) / 2; break;
-  case 2:       sp = 2 * ls; break;
-  case 3:       sp = ME_twips2pointsY(c, para->pFmt->dyLineSpacing); if (sp < ls) sp = ls; break;
-  case 4:       sp = ME_twips2pointsY(c, para->pFmt->dyLineSpacing); break;
-  case 5:       sp = para->pFmt->dyLineSpacing / 20; break;
-  default: FIXME("Unsupported spacing rule value %d\n", para->pFmt->bLineSpacingRule);
-  }
-  if (c->editor->nZoomNumerator == 0)
-    return sp;
-  else
-    return sp * c->editor->nZoomNumerator / c->editor->nZoomDenominator;
-}
-
 static void ME_DrawParaDecoration(ME_Context* c, ME_Paragraph* para, int y, RECT* bounds)
 {
   int           idx, border_width, top_border, bottom_border;
@@ -588,7 +562,7 @@ static void ME_DrawParaDecoration(ME_Context* c, ME_Paragraph* para, int y, RECT
      */
     if (para->pFmt->wBorders & 0x00B0)
       FIXME("Unsupported border flags %x\n", para->pFmt->wBorders);
-    border_width = ME_GetParaBorderWidth(c->editor, para->pFmt->wBorders);
+    border_width = ME_GetParaBorderWidth(c, para->pFmt->wBorders);
     if (para->pFmt->wBorders & 4)       top_border = border_width;
     if (para->pFmt->wBorders & 8)       bottom_border = border_width;
   }
@@ -630,7 +604,7 @@ static void ME_DrawParaDecoration(ME_Context* c, ME_Paragraph* para, int y, RECT
     rightEdge = c->pt.x + max(c->editor->sizeWindow.cx,
                               c->editor->nTotalWidth);
 
-    pen_width = ME_GetBorderPenWidth(c->editor, idx);
+    pen_width = ME_GetBorderPenWidth(c, idx);
     pen = CreatePen(border_details[idx].pen_style, pen_width, pencr);
     oldpen = SelectObject(c->hDC, pen);
     MoveToEx(c->hDC, 0, 0, &pt);
@@ -1036,17 +1010,21 @@ void ME_ScrollAbs(ME_TextEditor *editor, int x, int y)
   if (editor->horz_si.nPos != x) {
     x = min(x, editor->horz_si.nMax);
     x = max(x, editor->horz_si.nMin);
-    ITextHost_TxSetScrollPos(editor->texthost, SB_HORZ, x, TRUE);
     scrollX = editor->horz_si.nPos - x;
     editor->horz_si.nPos = x;
+    if (editor->horz_si.nMax > 0xFFFF) /* scale to 16-bit value */
+      x = MulDiv(x, 0xFFFF, editor->horz_si.nMax);
+    ITextHost_TxSetScrollPos(editor->texthost, SB_HORZ, x, TRUE);
   }
 
   if (editor->vert_si.nPos != y) {
     y = min(y, editor->vert_si.nMax - (int)editor->vert_si.nPage);
     y = max(y, editor->vert_si.nMin);
-    ITextHost_TxSetScrollPos(editor->texthost, SB_VERT, y, TRUE);
     scrollY = editor->vert_si.nPos - y;
     editor->vert_si.nPos = y;
+    if (editor->vert_si.nMax > 0xFFFF) /* scale to 16-bit value */
+      y = MulDiv(y, 0xFFFF, editor->vert_si.nMax);
+    ITextHost_TxSetScrollPos(editor->texthost, SB_VERT, y, TRUE);
   }
 
   if (abs(scrollX) > editor->sizeWindow.cx ||
@@ -1061,22 +1039,28 @@ void ME_ScrollAbs(ME_TextEditor *editor, int x, int y)
   if (editor->hWnd)
   {
     LONG winStyle = GetWindowLongW(editor->hWnd, GWL_STYLE);
-    bScrollBarIsVisible = (winStyle & WS_HSCROLL) != 0;
-    bScrollBarWillBeVisible = (editor->nTotalWidth > editor->sizeWindow.cx
-                               && (editor->styleFlags & WS_HSCROLL))
-                              || (editor->styleFlags & ES_DISABLENOSCROLL);
-    if (bScrollBarIsVisible != bScrollBarWillBeVisible)
-      ITextHost_TxShowScrollBar(editor->texthost, SB_HORZ,
-                                bScrollBarWillBeVisible);
+    if (editor->styleFlags & WS_HSCROLL)
+    {
+      bScrollBarIsVisible = (winStyle & WS_HSCROLL) != 0;
+      bScrollBarWillBeVisible = (editor->nTotalWidth > editor->sizeWindow.cx
+                                 && (editor->styleFlags & WS_HSCROLL))
+                                || (editor->styleFlags & ES_DISABLENOSCROLL);
+      if (bScrollBarIsVisible != bScrollBarWillBeVisible)
+        ITextHost_TxShowScrollBar(editor->texthost, SB_HORZ,
+                                  bScrollBarWillBeVisible);
+    }
 
-    bScrollBarIsVisible = (winStyle & WS_VSCROLL) != 0;
-    bScrollBarWillBeVisible = (editor->nTotalLength > editor->sizeWindow.cy
-                               && (editor->styleFlags & WS_VSCROLL)
-                               && (editor->styleFlags & ES_MULTILINE))
-                              || (editor->styleFlags & ES_DISABLENOSCROLL);
-    if (bScrollBarIsVisible != bScrollBarWillBeVisible)
-      ITextHost_TxShowScrollBar(editor->texthost, SB_VERT,
-                                bScrollBarWillBeVisible);
+    if (editor->styleFlags & WS_VSCROLL)
+    {
+      bScrollBarIsVisible = (winStyle & WS_VSCROLL) != 0;
+      bScrollBarWillBeVisible = (editor->nTotalLength > editor->sizeWindow.cy
+                                 && (editor->styleFlags & WS_VSCROLL)
+                                 && (editor->styleFlags & ES_MULTILINE))
+                                || (editor->styleFlags & ES_DISABLENOSCROLL);
+      if (bScrollBarIsVisible != bScrollBarWillBeVisible)
+        ITextHost_TxShowScrollBar(editor->texthost, SB_VERT,
+                                  bScrollBarWillBeVisible);
+    }
   }
   ME_UpdateScrollBar(editor);
 }
@@ -1136,6 +1120,7 @@ void ME_UpdateScrollBar(ME_TextEditor *editor)
 
   si.cbSize = sizeof(si);
   si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
+  si.nMin = 0;
   if (editor->styleFlags & ES_DISABLENOSCROLL)
     si.fMask |= SIF_DISABLENOSCROLL;
 
@@ -1150,20 +1135,25 @@ void ME_UpdateScrollBar(ME_TextEditor *editor)
     return;
   }
 
-  si.nMin = 0;
   si.nMax = editor->nTotalWidth;
   si.nPos = editor->horz_si.nPos;
   si.nPage = editor->sizeWindow.cx;
 
-  if (si.nMin != editor->horz_si.nMin ||
-      si.nMax != editor->horz_si.nMax ||
+  if (si.nMax != editor->horz_si.nMax ||
       si.nPage != editor->horz_si.nPage)
   {
     TRACE("min=%d max=%d page=%d\n", si.nMin, si.nMax, si.nPage);
-    editor->horz_si.nMin = si.nMin;
     editor->horz_si.nMax = si.nMax;
     editor->horz_si.nPage = si.nPage;
-    if (bScrollBarWillBeVisible || bScrollBarWasVisible) {
+    if ((bScrollBarWillBeVisible || bScrollBarWasVisible) &&
+        editor->styleFlags & WS_HSCROLL)
+    {
+      if (si.nMax > 0xFFFF)
+      {
+        /* Native scales the scrollbar info to 16-bit external values. */
+        si.nPos = MulDiv(si.nPos, 0xFFFF, si.nMax);
+        si.nMax = 0xFFFF;
+      }
       if (editor->hWnd) {
         SetScrollInfo(editor->hWnd, SB_HORZ, &si, TRUE);
       } else {
@@ -1175,14 +1165,17 @@ void ME_UpdateScrollBar(ME_TextEditor *editor)
     }
   }
 
-  if (si.fMask & SIF_DISABLENOSCROLL) {
-    bScrollBarWillBeVisible = TRUE;
-  } else if (!(editor->styleFlags & WS_HSCROLL)) {
-    bScrollBarWillBeVisible = FALSE;
-  }
+  if (editor->styleFlags & WS_HSCROLL)
+  {
+    if (si.fMask & SIF_DISABLENOSCROLL) {
+      bScrollBarWillBeVisible = TRUE;
+    } else if (!(editor->styleFlags & WS_HSCROLL)) {
+      bScrollBarWillBeVisible = FALSE;
+    }
 
-  if (bScrollBarWasVisible != bScrollBarWillBeVisible)
-    ITextHost_TxShowScrollBar(editor->texthost, SB_HORZ, bScrollBarWillBeVisible);
+    if (bScrollBarWasVisible != bScrollBarWillBeVisible)
+      ITextHost_TxShowScrollBar(editor->texthost, SB_HORZ, bScrollBarWillBeVisible);
+  }
 
   /* Update vertical scrollbar */
   bScrollBarWasVisible = editor->vert_si.nMax > editor->vert_si.nPage;
@@ -1201,15 +1194,21 @@ void ME_UpdateScrollBar(ME_TextEditor *editor)
   si.nPos = editor->vert_si.nPos;
   si.nPage = editor->sizeWindow.cy;
 
-  if (si.nMin != editor->vert_si.nMin ||
-      si.nMax != editor->vert_si.nMax ||
+  if (si.nMax != editor->vert_si.nMax ||
       si.nPage != editor->vert_si.nPage)
   {
     TRACE("min=%d max=%d page=%d\n", si.nMin, si.nMax, si.nPage);
-    editor->vert_si.nMin = si.nMin;
     editor->vert_si.nMax = si.nMax;
     editor->vert_si.nPage = si.nPage;
-    if (bScrollBarWillBeVisible || bScrollBarWasVisible) {
+    if ((bScrollBarWillBeVisible || bScrollBarWasVisible) &&
+        editor->styleFlags & WS_VSCROLL)
+    {
+      if (si.nMax > 0xFFFF)
+      {
+        /* Native scales the scrollbar info to 16-bit external values. */
+        si.nPos = MulDiv(si.nPos, 0xFFFF, si.nMax);
+        si.nMax = 0xFFFF;
+      }
       if (editor->hWnd) {
         SetScrollInfo(editor->hWnd, SB_VERT, &si, TRUE);
       } else {
@@ -1221,15 +1220,18 @@ void ME_UpdateScrollBar(ME_TextEditor *editor)
     }
   }
 
-  if (si.fMask & SIF_DISABLENOSCROLL) {
-    bScrollBarWillBeVisible = TRUE;
-  } else if (!(editor->styleFlags & WS_VSCROLL)) {
-    bScrollBarWillBeVisible = FALSE;
-  }
+  if (editor->styleFlags & WS_VSCROLL)
+  {
+    if (si.fMask & SIF_DISABLENOSCROLL) {
+      bScrollBarWillBeVisible = TRUE;
+    } else if (!(editor->styleFlags & WS_VSCROLL)) {
+      bScrollBarWillBeVisible = FALSE;
+    }
 
-  if (bScrollBarWasVisible != bScrollBarWillBeVisible)
-    ITextHost_TxShowScrollBar(editor->texthost, SB_VERT,
-                              bScrollBarWillBeVisible);
+    if (bScrollBarWasVisible != bScrollBarWillBeVisible)
+      ITextHost_TxShowScrollBar(editor->texthost, SB_VERT,
+                                bScrollBarWillBeVisible);
+  }
 }
 
 void ME_EnsureVisible(ME_TextEditor *editor, ME_Cursor *pCursor)
@@ -1242,11 +1244,24 @@ void ME_EnsureVisible(ME_TextEditor *editor, ME_Cursor *pCursor)
   assert(pRow);
   assert(pPara);
 
-  x = pRun->pt.x + ME_PointFromChar(editor, pRun, pCursor->nOffset);
-  if (x > editor->horz_si.nPos + editor->sizeWindow.cx)
-    x = x + 1 - editor->sizeWindow.cx;
-  else if (x > editor->horz_si.nPos)
+  if (editor->styleFlags & ES_AUTOHSCROLL)
+  {
+    x = pRun->pt.x + ME_PointFromChar(editor, pRun, pCursor->nOffset);
+    if (x > editor->horz_si.nPos + editor->sizeWindow.cx)
+      x = x + 1 - editor->sizeWindow.cx;
+    else if (x > editor->horz_si.nPos)
+      x = editor->horz_si.nPos;
+
+    if (~editor->styleFlags & ES_AUTOVSCROLL)
+    {
+      ME_HScrollAbs(editor, x);
+      return;
+    }
+  } else {
+    if (~editor->styleFlags & ES_AUTOVSCROLL)
+      return;
     x = editor->horz_si.nPos;
+  }
 
   y = pPara->member.para.pt.y + pRow->member.row.pt.y;
   yheight = pRow->member.row.nHeight;
@@ -1267,7 +1282,7 @@ ME_InvalidateSelection(ME_TextEditor *editor)
   int nStart, nEnd;
   int len = ME_GetTextLength(editor);
 
-  ME_GetSelection(editor, &nStart, &nEnd);
+  ME_GetSelectionOfs(editor, &nStart, &nEnd);
   /* if both old and new selection are 0-char (= caret only), then
   there's no (inverted) area to be repainted, neither old nor new */
   if (nStart == nEnd && editor->nLastSelStart == editor->nLastSelEnd)
@@ -1300,7 +1315,7 @@ ME_InvalidateSelection(ME_TextEditor *editor)
 
   ME_InvalidateMarkedParagraphs(editor);
   /* remember the last invalidated position */
-  ME_GetSelection(editor, &editor->nLastSelStart, &editor->nLastSelEnd);
+  ME_GetSelectionOfs(editor, &editor->nLastSelStart, &editor->nLastSelEnd);
   ME_GetSelectionParas(editor, &editor->pLastSelStartPara, &editor->pLastSelEndPara);
   assert(editor->pLastSelStartPara->type == diParagraph);
   assert(editor->pLastSelEndPara->type == diParagraph);
index 94ef7ae..b6319e7 100644 (file)
@@ -335,6 +335,8 @@ ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp,
   int i, shift;
   ME_UndoItem *undo = NULL;
   int end_len;
+  CHARFORMAT2W fmt;
+  ME_Cursor startCur, endCur;
 
   assert(tp->type == diParagraph);
   assert(tp->member.para.next_para);
@@ -351,12 +353,15 @@ ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp,
 
   end_len = pRun->member.run.strText->nLen;
 
-  {
-    /* null char format operation to store the original char format for the ENDPARA run */
-    CHARFORMAT2W fmt;
-    ME_InitCharFormat2W(&fmt);
-    ME_SetCharFormat(editor, pNext->member.para.nCharOfs - end_len, end_len, &fmt);
-  }
+  /* null char format operation to store the original char format for the ENDPARA run */
+  ME_InitCharFormat2W(&fmt);
+  endCur.pPara = pNext;
+  endCur.pRun = ME_FindItemFwd(pNext, diRun);
+  endCur.nOffset = 0;
+  startCur = endCur;
+  ME_PrevRun(&startCur.pPara, &startCur.pRun);
+  ME_SetCharFormat(editor, &startCur, &endCur, &fmt);
+
   undo = ME_AddUndoItem(editor, diUndoSplitParagraph, pNext);
   if (undo)
   {
index b6a6f44..9f88cf7 100644 (file)
@@ -442,7 +442,11 @@ static void RTFUngetToken(RTF_Info *info)
         * increment the value to compensate for it being decremented
         * twice due to the RTFUngetToken. */
        if(RTFCheckCM (info, rtfGroup, rtfEndGroup))
+       {
+               info->stack[info->stackTop].style = info->style;
+               ME_AddRefStyle(info->style);
                info->stackTop++;
+       }
 }
 
 
@@ -783,7 +787,6 @@ static void ReadFontTbl(RTF_Info *info)
        RTFFont         *fp = NULL;
        char            buf[rtfBufSiz], *bp;
        int             old = -1;
-       const char      *fn = "ReadFontTbl";
 
        for (;;)
        {
@@ -799,19 +802,19 @@ static void ReadFontTbl(RTF_Info *info)
                        else if (RTFCheckCM (info, rtfGroup, rtfBeginGroup))
                                old = 0;        /* brace */
                        else                    /* can't tell! */
-                               ERR ( "%s: Cannot determine format\n", fn);
+                               ERR ("cannot determine format\n");
                }
                if (old == 0)           /* need to find "{" here */
                {
                        if (!RTFCheckCM (info, rtfGroup, rtfBeginGroup))
-                               ERR ( "%s: missing \"{\"\n", fn);
+                               ERR ("missing \"{\"\n");
                        RTFGetToken (info);     /* yes, skip to next token */
                        if (info->rtfClass == rtfEOF)
                                break;
                }
                fp = New (RTFFont);
                if (fp == NULL) {
-                       ERR ( "%s: cannot allocate font entry\n", fn);
+                       ERR ("cannot allocate font entry\n");
                        break;
                }
 
@@ -837,8 +840,8 @@ static void ReadFontTbl(RTF_Info *info)
                                {
                                default:
                                        /* ignore token but announce it */
-                                       WARN ("%s: unknown token \"%s\"\n",
-                                               fn, info->rtfTextBuf);
+                                       WARN ("unknown token \"%s\"\n",
+                                               info->rtfTextBuf);
                                         break;
                                case rtfFontFamily:
                                        fp->rtfFFamily = info->rtfMinor;
@@ -899,7 +902,7 @@ static void ReadFontTbl(RTF_Info *info)
                                *bp = '\0';
                                fp->rtfFName = RTFStrSave (buf);
                                if (fp->rtfFName == NULL)
-                                       ERR ( "%s: cannot allocate font name\n", fn);
+                                       ERR ("cannot allocate font name\n");
                                /* already have next token; don't read one */
                                /* at bottom of loop */
                                continue;
@@ -907,8 +910,7 @@ static void ReadFontTbl(RTF_Info *info)
                        else
                        {
                                /* ignore token but announce it */
-                               WARN ( "%s: unknown token \"%s\"\n",
-                                                       fn,info->rtfTextBuf);
+                               WARN ("unknown token \"%s\"\n", info->rtfTextBuf);
                        }
                        RTFGetToken (info);
                        if (info->rtfClass == rtfEOF)
@@ -920,7 +922,7 @@ static void ReadFontTbl(RTF_Info *info)
                {
                        RTFGetToken (info);
                        if (!RTFCheckCM (info, rtfGroup, rtfEndGroup))
-                               ERR ( "%s: missing \"}\"\n", fn);
+                               ERR ("missing \"}\"\n");
                        if (info->rtfClass == rtfEOF)
                                break;
                }
@@ -934,7 +936,7 @@ static void ReadFontTbl(RTF_Info *info)
                 }
        }
        if (!fp || (fp->rtfFNum == -1))
-               ERR( "%s: missing font number\n", fn);
+               ERR("missing font number\n");
 /*
  * Could check other pieces of structure here, too, I suppose.
  */
@@ -963,7 +965,6 @@ static void ReadColorTbl(RTF_Info *info)
 {
        RTFColor        *cp;
        int             cnum = 0;
-       const char      *fn = "ReadColorTbl";
         int group_level = 1;
 
        for (;;)
@@ -986,27 +987,30 @@ static void ReadColorTbl(RTF_Info *info)
 
                cp = New (RTFColor);
                if (cp == NULL) {
-                       ERR ( "%s: cannot allocate color entry\n", fn);
+                       ERR ("cannot allocate color entry\n");
                        break;
                }
                cp->rtfCNum = cnum++;
-               cp->rtfCRed = cp->rtfCGreen = cp->rtfCBlue = -1;
                cp->rtfNextColor = info->colorList;
                info->colorList = cp;
-               while (RTFCheckCM (info, rtfControl, rtfColorName))
-               {
-                       switch (info->rtfMinor)
-                       {
-                       case rtfRed:    cp->rtfCRed = info->rtfParam; break;
-                       case rtfGreen:  cp->rtfCGreen = info->rtfParam; break;
-                       case rtfBlue:   cp->rtfCBlue = info->rtfParam; break;
-                       }
-                       RTFGetToken (info);
+               if (!RTFCheckCM (info, rtfControl, rtfColorName))
+                       cp->rtfCRed = cp->rtfCGreen = cp->rtfCBlue = -1;
+               else {
+                       cp->rtfCRed = cp->rtfCGreen = cp->rtfCBlue = 0;
+                       do {
+                               switch (info->rtfMinor)
+                               {
+                               case rtfRed:    cp->rtfCRed = info->rtfParam & 0xFF; break;
+                               case rtfGreen:  cp->rtfCGreen = info->rtfParam & 0xFF; break;
+                               case rtfBlue:   cp->rtfCBlue = info->rtfParam & 0xFF; break;
+                               }
+                               RTFGetToken (info);
+                       } while (RTFCheckCM (info, rtfControl, rtfColorName));
                }
                if (info->rtfClass == rtfEOF)
                        break;
                if (!RTFCheckCM (info, rtfText, ';'))
-                       ERR ("%s: malformed entry\n", fn);
+                       ERR ("malformed entry\n");
        }
        RTFRouteToken (info);   /* feed "}" back to router */
 }
@@ -1022,7 +1026,6 @@ static void ReadStyleSheet(RTF_Info *info)
        RTFStyle        *sp;
        RTFStyleElt     *sep, *sepLast;
        char            buf[rtfBufSiz], *bp;
-       const char      *fn = "ReadStyleSheet";
        int             real_style;
 
        for (;;)
@@ -1034,7 +1037,7 @@ static void ReadStyleSheet(RTF_Info *info)
                        break;
                sp = New (RTFStyle);
                if (sp == NULL) {
-                       ERR ( "%s: cannot allocate stylesheet entry\n", fn);
+                       ERR ("cannot allocate stylesheet entry\n");
                        break;
                }
                sp->rtfSName = NULL;
@@ -1048,7 +1051,7 @@ static void ReadStyleSheet(RTF_Info *info)
                sp->rtfExpanding = 0;
                info->styleList = sp;
                if (!RTFCheckCM (info, rtfGroup, rtfBeginGroup))
-                       ERR ( "%s: missing \"{\"\n", fn);
+                       ERR ("missing \"{\"\n");
                real_style = TRUE;
                for (;;)
                {
@@ -1060,7 +1063,7 @@ static void ReadStyleSheet(RTF_Info *info)
                        {
                                if (RTFCheckMM (info, rtfSpecialChar, rtfOptDest)) {
                                        RTFGetToken(info);
-                                       ERR( "%s: skipping optional destination\n", fn);
+                                       ERR("skipping optional destination\n");
                                        RTFSkipGroup(info);
                                        info->rtfClass = rtfGroup;
                                        info->rtfMajor = rtfEndGroup;
@@ -1102,14 +1105,17 @@ static void ReadStyleSheet(RTF_Info *info)
                                }
                                sep = New (RTFStyleElt);
                                if (sep == NULL)
-                                       ERR ( "%s: cannot allocate style element\n", fn);
+                                {
+                                       ERR ("cannot allocate style element\n");
+                                       break;
+                               }
                                sep->rtfSEClass = info->rtfClass;
                                sep->rtfSEMajor = info->rtfMajor;
                                sep->rtfSEMinor = info->rtfMinor;
                                sep->rtfSEParam = info->rtfParam;
                                sep->rtfSEText = RTFStrSave (info->rtfTextBuf);
                                if (sep->rtfSEText == NULL)
-                                       ERR ( "%s: cannot allocate style element text\n", fn);
+                                       ERR ("cannot allocate style element text\n");
                                if (sepLast == NULL)
                                        sp->rtfSSEList = sep;   /* first element */
                                else                            /* add to end */
@@ -1123,7 +1129,7 @@ static void ReadStyleSheet(RTF_Info *info)
                                 * This passes over "{\*\keycode ... }, among
                                 * other things. A temporary (perhaps) hack.
                                 */
-                                ERR( "%s: skipping begin\n", fn);
+                               ERR("skipping begin\n");
                                RTFSkipGroup (info);
                                continue;
                        }
@@ -1144,19 +1150,18 @@ static void ReadStyleSheet(RTF_Info *info)
                                *bp = '\0';
                                sp->rtfSName = RTFStrSave (buf);
                                if (sp->rtfSName == NULL)
-                                       ERR ( "%s: cannot allocate style name\n", fn);
+                                       ERR ("cannot allocate style name\n");
                        }
                        else            /* unrecognized */
                        {
                                /* ignore token but announce it */
-                               WARN ( "%s: unknown token \"%s\"\n",
-                                                       fn, info->rtfTextBuf);
+                               WARN ("unknown token \"%s\"\n", info->rtfTextBuf);
                        }
                }
                if (real_style) {
                        RTFGetToken (info);
                        if (!RTFCheckCM (info, rtfGroup, rtfEndGroup))
-                               ERR ( "%s: missing \"}\"\n", fn);
+                               ERR ("missing \"}\"\n");
                        /*
                         * Check over the style structure.  A name is a must.
                         * If no style number was specified, check whether it's the
@@ -1168,12 +1173,12 @@ static void ReadStyleSheet(RTF_Info *info)
                         * Some German RTF writers use "Standard" instead of "Normal".
                         */
                        if (sp->rtfSName == NULL)
-                               ERR ( "%s: missing style name\n", fn);
+                               ERR ("missing style name\n");
                        if (sp->rtfSNum < 0)
                        {
                                if (strncmp (buf, "Normal", 6) != 0
                                        && strncmp (buf, "Standard", 8) != 0)
-                                       ERR ( "%s: missing style number\n", fn);
+                                       ERR ("missing style number\n");
                                sp->rtfSNum = rtfNormalStyleNum;
                        }
                        if (sp->rtfSNextPar == -1)      /* if \snext not given, */
index 326ecc5..5b6b2b6 100644 (file)
@@ -315,16 +315,21 @@ IRichEditOle_fnGetClipboardData(IRichEditOle *me, CHARRANGE *lpchrg,
                DWORD reco, LPDATAOBJECT *lplpdataobj)
 {
     IRichEditOleImpl *This = impl_from_IRichEditOle(me);
-    CHARRANGE tmpchrg;
+    ME_Cursor start;
+    int nChars;
 
     TRACE("(%p,%p,%d)\n",This, lpchrg, reco);
     if(!lplpdataobj)
         return E_INVALIDARG;
     if(!lpchrg) {
-        ME_GetSelection(This->editor, &tmpchrg.cpMin, &tmpchrg.cpMax);
-        lpchrg = &tmpchrg;
+        int nFrom, nTo, nStartCur = ME_GetSelectionOfs(This->editor, &nFrom, &nTo);
+        start = This->editor->pCursors[nStartCur];
+        nChars = nTo - nFrom;
+    } else {
+        ME_CursorFromCharOfs(This->editor, lpchrg->cpMin, &start);
+        nChars = lpchrg->cpMax - lpchrg->cpMin;
     }
-    return ME_GetDataObject(This->editor, lpchrg, lplpdataobj);
+    return ME_GetDataObject(This->editor, &start, nChars, lplpdataobj);
 }
 
 static LONG WINAPI IRichEditOle_fnGetLinkCount(IRichEditOle *me)
@@ -383,11 +388,10 @@ IRichEditOle_fnInsertObject(IRichEditOle *me, REOBJECT *reo)
     TRACE("(%p,%p)\n", This, reo);
 
     if (reo->cbStruct < sizeof(*reo)) return STG_E_INVALIDPARAMETER;
-    if (reo->poleobj)   IOleObject_AddRef(reo->poleobj);
-    if (reo->pstg)      IStorage_AddRef(reo->pstg);
-    if (reo->polesite)  IOleClientSite_AddRef(reo->polesite);
 
     ME_InsertOLEFromCursor(This->editor, reo, 0);
+    ME_CommitUndo(This->editor);
+    ME_UpdateRepaint(This->editor);
     return S_OK;
 }
 
@@ -1725,6 +1729,11 @@ void ME_GetOLEObjectSize(ME_Context *c, ME_Run *run, SIZE *pSize)
   if (run->ole_obj->sizel.cx != 0 || run->ole_obj->sizel.cy != 0)
   {
     convert_sizel(c, &run->ole_obj->sizel, pSize);
+    if (c->editor->nZoomNumerator != 0)
+    {
+      pSize->cx = MulDiv(pSize->cx, c->editor->nZoomNumerator, c->editor->nZoomDenominator);
+      pSize->cy = MulDiv(pSize->cy, c->editor->nZoomNumerator, c->editor->nZoomDenominator);
+    }
     return;
   }
 
@@ -1815,53 +1824,45 @@ void ME_DrawOLE(ME_Context *c, int x, int y, ME_Run *run,
     GetObjectW(stgm.u.hBitmap, sizeof(dibsect), &dibsect);
     hMemDC = CreateCompatibleDC(c->hDC);
     SelectObject(hMemDC, stgm.u.hBitmap);
-    if (!has_size && c->editor->nZoomNumerator == 0)
+    if (has_size)
     {
-      sz.cx = dibsect.dsBm.bmWidth;
-      sz.cy = dibsect.dsBm.bmHeight;
-      BitBlt(c->hDC, x, y - dibsect.dsBm.bmHeight,
-             dibsect.dsBm.bmWidth, dibsect.dsBm.bmHeight,
-             hMemDC, 0, 0, SRCCOPY);
+      convert_sizel(c, &run->ole_obj->sizel, &sz);
+    } else {
+      sz.cx = MulDiv(dibsect.dsBm.bmWidth, c->dpi.cx, 96);
+      sz.cy = MulDiv(dibsect.dsBm.bmHeight, c->dpi.cy, 96);
     }
-    else
+    if (c->editor->nZoomNumerator != 0)
     {
-      if (has_size)
-      {
-        convert_sizel(c, &run->ole_obj->sizel, &sz);
-      }
-      else
-      {
-        sz.cx = MulDiv(dibsect.dsBm.bmWidth,
-                       c->editor->nZoomNumerator, c->editor->nZoomDenominator);
-        sz.cy = MulDiv(dibsect.dsBm.bmHeight,
-                       c->editor->nZoomNumerator, c->editor->nZoomDenominator);
-      }
+      sz.cx = MulDiv(sz.cx, c->editor->nZoomNumerator, c->editor->nZoomDenominator);
+      sz.cy = MulDiv(sz.cy, c->editor->nZoomNumerator, c->editor->nZoomDenominator);
+    }
+    if (sz.cx == dibsect.dsBm.bmWidth && sz.cy == dibsect.dsBm.bmHeight)
+    {
+      BitBlt(c->hDC, x, y - sz.cy,
+             dibsect.dsBm.bmWidth, dibsect.dsBm.bmHeight,
+             hMemDC, 0, 0, SRCCOPY);
+    } else {
       StretchBlt(c->hDC, x, y - sz.cy, sz.cx, sz.cy,
-                 hMemDC, 0, 0, dibsect.dsBm.bmWidth, dibsect.dsBm.bmHeight, SRCCOPY);
+                 hMemDC, 0, 0, dibsect.dsBm.bmWidth,
+                 dibsect.dsBm.bmHeight, SRCCOPY);
     }
     if (!stgm.pUnkForRelease) DeleteObject(stgm.u.hBitmap);
     break;
   case TYMED_ENHMF:
     GetEnhMetaFileHeader(stgm.u.hEnhMetaFile, sizeof(emh), &emh);
-    if (!has_size && c->editor->nZoomNumerator == 0)
+    if (has_size)
     {
-      sz.cy = emh.rclBounds.bottom - emh.rclBounds.top;
-      sz.cx = emh.rclBounds.right - emh.rclBounds.left;
+      convert_sizel(c, &run->ole_obj->sizel, &sz);
+    } else {
+      sz.cy = MulDiv(emh.rclBounds.bottom - emh.rclBounds.top, c->dpi.cx, 96);
+      sz.cx = MulDiv(emh.rclBounds.right - emh.rclBounds.left, c->dpi.cy, 96);
     }
-    else
+    if (c->editor->nZoomNumerator != 0)
     {
-      if (has_size)
-      {
-        convert_sizel(c, &run->ole_obj->sizel, &sz);
-      }
-      else
-      {
-        sz.cy = MulDiv(emh.rclBounds.bottom - emh.rclBounds.top,
-                       c->editor->nZoomNumerator, c->editor->nZoomDenominator);
-        sz.cx = MulDiv(emh.rclBounds.right - emh.rclBounds.left,
-                       c->editor->nZoomNumerator, c->editor->nZoomDenominator);
-      }
+      sz.cx = MulDiv(sz.cx, c->editor->nZoomNumerator, c->editor->nZoomDenominator);
+      sz.cy = MulDiv(sz.cy, c->editor->nZoomNumerator, c->editor->nZoomDenominator);
     }
+
     {
       RECT    rc;
 
index 3277301..d8ac323 100644 (file)
@@ -1095,7 +1095,7 @@ typedef   void (*RTFFuncPtr) (RTF_Info *);                /* generic function pointer */
 
 /* RTF parser stack element */
 struct tagRTFState {
-        CHARFORMAT2W fmt;
+        ME_Style *style;
         int codePage;
         int unicodeLength;
 };
index cf6c1fc..cd282ec 100644 (file)
@@ -347,27 +347,6 @@ ME_DisplayItem *ME_MakeRun(ME_Style *s, ME_String *strData, int nFlags)
   return item;
 }
 
-/******************************************************************************
- * ME_InsertRun
- * 
- * Inserts a run at a given character position (offset).
- */   
-ME_DisplayItem *ME_InsertRun(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem *pItem)
-{
-  ME_Cursor tmp;
-  ME_DisplayItem *pDI;
-
-  assert(pItem->type == diRun || pItem->type == diUndoInsertRun);
-
-  ME_CursorFromCharOfs(editor, nCharOfs, &tmp);
-  pDI = ME_InsertRunAtCursor(editor, &tmp, pItem->member.run.style,
-                             pItem->member.run.strText->szData,
-                             pItem->member.run.strText->nLen,
-                             pItem->member.run.nFlags);
-  
-  return pDI;
-}
-
 /******************************************************************************
  * ME_InsertRunAtCursor
  *
@@ -571,9 +550,14 @@ int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run)
 static void ME_GetTextExtent(ME_Context *c, LPCWSTR szText, int nChars, ME_Style *s, SIZE *size)
 {
   HGDIOBJ hOldFont;
-  hOldFont = ME_SelectStyleFont(c, s);
-  GetTextExtentPoint32W(c->hDC, szText, nChars, size);
-  ME_UnselectStyleFont(c, s, hOldFont);
+  if (c->hDC) {
+    hOldFont = ME_SelectStyleFont(c, s);
+    GetTextExtentPoint32W(c->hDC, szText, nChars, size);
+    ME_UnselectStyleFont(c, s, hOldFont);
+  } else {
+    size->cx = 0;
+    size->cy = 0;
+  }
 }
 
 /******************************************************************************
@@ -726,15 +710,13 @@ void ME_CalcRunExtent(ME_Context *c, const ME_Paragraph *para, int startx, ME_Ru
 
 /******************************************************************************
  * ME_SetSelectionCharFormat
- * 
+ *
  * Applies a style change, either to a current selection, or to insert cursor
  * (ie. the style next typed characters will use).
- */     
+ */
 void ME_SetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt)
 {
-  int nFrom, nTo;
-  ME_GetSelection(editor, &nFrom, &nTo);
-  if (nFrom == nTo)
+  if (!ME_IsSelection(editor))
   {
     ME_Style *s;
     if (!editor->pBuffer->pCharStyle)
@@ -742,57 +724,85 @@ void ME_SetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt)
     s = ME_ApplyStyle(editor->pBuffer->pCharStyle, pFmt);
     ME_ReleaseStyle(editor->pBuffer->pCharStyle);
     editor->pBuffer->pCharStyle = s;
+  } else {
+    ME_Cursor *from, *to;
+    ME_GetSelection(editor, &from, &to);
+    ME_SetCharFormat(editor, from, to, pFmt);
   }
-  else
-    ME_SetCharFormat(editor, nFrom, nTo-nFrom, pFmt);
 }
 
 /******************************************************************************
  * ME_SetCharFormat
- * 
+ *
  * Applies a style change to the specified part of the text
- */     
-void ME_SetCharFormat(ME_TextEditor *editor, int nOfs, int nChars, CHARFORMAT2W *pFmt)
+ *
+ * The start and end cursors specify the part of the text.  These cursors will
+ * be updated to stay valid, but this function may invalidate other
+ * non-selection cursors. The end cursor may be NULL to specify all the text
+ * following the start cursor.
+ *
+ * If no text is selected, then nothing is done.
+ */
+void ME_SetCharFormat(ME_TextEditor *editor, ME_Cursor *start, ME_Cursor *end, CHARFORMAT2W *pFmt)
 {
-  ME_Cursor tmp, tmp2;
   ME_DisplayItem *para;
+  ME_DisplayItem *run;
+  ME_DisplayItem *end_run = NULL;
 
-  ME_CursorFromCharOfs(editor, nOfs, &tmp);
-  if (tmp.nOffset)
-    tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset);
+  if (end && start->pRun == end->pRun && start->nOffset == end->nOffset)
+    return;
+
+  if (start->nOffset)
+  {
+    /* SplitRunSimple may or may not update the cursors, depending on whether they
+     * are selection cursors, but we need to make sure they are valid. */
+    ME_DisplayItem *split_run = start->pRun;
+    int split_offset = start->nOffset;
+    start->pRun = ME_SplitRunSimple(editor, split_run, split_offset);
+    start->nOffset = 0;
+    if (end && end->pRun == split_run)
+    {
+      end->pRun = start->pRun;
+      end->nOffset -= split_offset;
+    }
+  }
 
-  ME_CursorFromCharOfs(editor, nOfs+nChars, &tmp2);
-  if (tmp2.nOffset)
-    tmp2.pRun = ME_SplitRunSimple(editor, tmp2.pRun, tmp2.nOffset);
+  if (end && end->nOffset)
+  {
+    end_run = end->pRun = ME_SplitRunSimple(editor, end->pRun, end->nOffset);
+    end->nOffset = 0;
+  } else if (end) {
+    end_run = end->pRun;
+  }
 
-  para = tmp.pPara;
+  run = start->pRun;
+  para = start->pPara;
   para->member.para.nFlags |= MEPF_REWRAP;
 
-  while(tmp.pRun != tmp2.pRun)
+  while(run != end_run)
   {
     ME_UndoItem *undo = NULL;
-    ME_Style *new_style = ME_ApplyStyle(tmp.pRun->member.run.style, pFmt);
+    ME_Style *new_style = ME_ApplyStyle(run->member.run.style, pFmt);
     /* ME_DumpStyle(new_style); */
     undo = ME_AddUndoItem(editor, diUndoSetCharFormat, NULL);
     if (undo) {
-      undo->nStart = tmp.pRun->member.run.nCharOfs+para->member.para.nCharOfs;
-      undo->nLen = tmp.pRun->member.run.strText->nLen;
-      undo->di.member.ustyle = tmp.pRun->member.run.style;
+      undo->nStart = run->member.run.nCharOfs+para->member.para.nCharOfs;
+      undo->nLen = run->member.run.strText->nLen;
+      undo->di.member.ustyle = run->member.run.style;
       /* we'd have to addref undo...ustyle and release tmp...style
          but they'd cancel each other out so we can do nothing instead */
     }
     else
-      ME_ReleaseStyle(tmp.pRun->member.run.style);
-    tmp.pRun->member.run.style = new_style;
-    tmp.pRun = ME_FindItemFwd(tmp.pRun, diRunOrParagraph);
-    if (tmp.pRun->type == diParagraph)
+      ME_ReleaseStyle(run->member.run.style);
+    run->member.run.style = new_style;
+    run = ME_FindItemFwd(run, diRunOrParagraph);
+    if (run && run->type == diParagraph)
     {
-      para = tmp.pRun;
-      tmp.pRun = ME_FindItemFwd(tmp.pRun, diRun);
-      if (tmp.pRun != tmp2.pRun)
+      para = run;
+      run = ME_FindItemFwd(run, diRun);
+      if (run != end_run)
         para->member.para.nFlags |= MEPF_REWRAP;
     }
-    assert(tmp.pRun);
   }
 }
 
@@ -842,20 +852,20 @@ void ME_GetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt)
 
 /******************************************************************************
  * ME_GetSelectionCharFormat
- * 
+ *
  * If selection exists, it returns all style elements that are set consistently
- * in the whole selection. If not, it just returns the current style.  
- */     
+ * in the whole selection. If not, it just returns the current style.
+ */
 void ME_GetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt)
 {
-  int nFrom, nTo;
-  ME_GetSelection(editor, &nFrom, &nTo);
-  if (nFrom == nTo && editor->pBuffer->pCharStyle)
+  ME_Cursor *from, *to;
+  if (!ME_IsSelection(editor) && editor->pBuffer->pCharStyle)
   {
     ME_CopyCharFormat(pFmt, &editor->pBuffer->pCharStyle->fmt);
     return;
   }
-  ME_GetCharFormat(editor, nFrom, nTo, pFmt);
+  ME_GetSelection(editor, &from, &to);
+  ME_GetCharFormat(editor, from, to, pFmt);
 }
 
 /******************************************************************************
@@ -864,16 +874,17 @@ void ME_GetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt)
  * Returns the style consisting of those attributes which are consistently set
  * in the whole character range.
  */
-void ME_GetCharFormat(ME_TextEditor *editor, int nFrom, int nTo, CHARFORMAT2W *pFmt)
+void ME_GetCharFormat(ME_TextEditor *editor, const ME_Cursor *from,
+                      const ME_Cursor *to, CHARFORMAT2W *pFmt)
 {
   ME_DisplayItem *run, *run_end;
-  int nOffset, nOffset2;
   CHARFORMAT2W tmp;
 
-  ME_RunOfsFromCharOfs(editor, nFrom, NULL, &run, &nOffset);
-  if (nFrom == nTo) /* special case - if selection is empty, take previous char's formatting */
+  run = from->pRun;
+  /* special case - if selection is empty, take previous char's formatting */
+  if (from->pRun == to->pRun && from->nOffset == to->nOffset)
   {
-    if (!nOffset)
+    if (!from->nOffset)
     {
       ME_DisplayItem *tmp_run = ME_FindItemBack(run, diRunOrParagraph);
       if (tmp_run->type == diRun) {
@@ -884,10 +895,10 @@ void ME_GetCharFormat(ME_TextEditor *editor, int nFrom, int nTo, CHARFORMAT2W *p
     ME_GetRunCharFormat(editor, run, pFmt);
     return;
   }
-  
-  if (nTo>nFrom) /* selection consists of chars from nFrom up to nTo-1 */
-    nTo--;
-  ME_RunOfsFromCharOfs(editor, nTo, NULL, &run_end, &nOffset2);
+
+  run_end = to->pRun;
+  if (!to->nOffset)
+    run_end = ME_FindItemBack(run_end, diRun);
 
   ME_GetRunCharFormat(editor, run, pFmt);
 
index a3b532e..bb2f808 100644 (file)
@@ -156,6 +156,7 @@ ME_Style *ME_MakeStyle(CHARFORMAT2W *style) {
   s->hFont = NULL;
   s->tm.tmAscent = -1;
   all_refs++;
+  TRACE_(richedit_style)("ME_MakeStyle %p, total refs=%d\n", s, all_refs);
   return s;
 }
 
@@ -449,6 +450,7 @@ void ME_AddRefStyle(ME_Style *s)
   assert(s->nRefs>0); /* style with 0 references isn't supposed to exist */
   s->nRefs++;
   all_refs++;
+  TRACE_(richedit_style)("ME_AddRefStyle %p, new refs=%d, total refs=%d\n", s, s->nRefs, all_refs);
 }
 
 void ME_ReleaseStyle(ME_Style *s)
@@ -465,16 +467,15 @@ void ME_ReleaseStyle(ME_Style *s)
     ME_DestroyStyle(s);
 }
 
-ME_Style *ME_GetInsertStyle(ME_TextEditor *editor, int nCursor) {
+ME_Style *ME_GetInsertStyle(ME_TextEditor *editor, int nCursor)
+{
   if (ME_IsSelection(editor))
   {
-    ME_Cursor c;
-    int from, to;
-    
+    ME_Cursor *from, *to;
+
     ME_GetSelection(editor, &from, &to);
-    ME_CursorFromCharOfs(editor, from, &c);
-    ME_AddRefStyle(c.pRun->member.run.style);
-    return c.pRun->member.run.style;
+    ME_AddRefStyle(from->pRun->member.run.style);
+    return from->pRun->member.run.style;
   }
   if (editor->pBuffer->pCharStyle) {
     ME_AddRefStyle(editor->pBuffer->pCharStyle);
index 6c8ca76..cbfa2b3 100644 (file)
@@ -70,6 +70,7 @@ static ME_DisplayItem* ME_InsertEndParaFromCursor(ME_TextEditor *editor,
   }
 
   tp = ME_SplitParagraph(editor, cursor->pRun, pStyle, eol_str, paraFlags);
+  ME_ReleaseStyle(pStyle);
   cursor->pPara = tp;
   cursor->pRun = ME_FindItemFwd(tp, diRun);
   return tp;
@@ -95,6 +96,7 @@ ME_DisplayItem* ME_InsertTableRowStartAtParagraph(ME_TextEditor *editor,
   editor->pCursors[0].nOffset = 0;
   editor->pCursors[1] = editor->pCursors[0];
   startRowPara = ME_InsertTableRowStartFromCursor(editor);
+  savedCursor.pPara = ME_GetParagraph(savedCursor.pRun);
   editor->pCursors[0] = savedCursor;
   editor->pCursors[1] = editor->pCursors[0];
 
@@ -121,8 +123,8 @@ ME_DisplayItem* ME_InsertTableRowStartAtParagraph(ME_TextEditor *editor,
 ME_DisplayItem* ME_InsertTableCellFromCursor(ME_TextEditor *editor)
 {
   ME_DisplayItem *para;
-  WCHAR cr = '\r';
-  ME_String *eol_str = ME_MakeStringN(&cr, 1);
+  WCHAR tab = '\t';
+  ME_String *eol_str = ME_MakeStringN(&tab, 1);
   para = ME_InsertEndParaFromCursor(editor, 0, eol_str, MEPF_CELL);
   return para;
 }
@@ -273,13 +275,14 @@ BOOL ME_IsInTable(ME_DisplayItem *pItem)
 }
 
 /* Table rows should either be deleted completely or not at all. */
-void ME_ProtectPartialTableDeletion(ME_TextEditor *editor, int nOfs,int *nChars)
+void ME_ProtectPartialTableDeletion(ME_TextEditor *editor, ME_Cursor *c, int *nChars)
 {
-  ME_Cursor c, c2;
-  ME_DisplayItem *this_para, *end_para;
-  ME_CursorFromCharOfs(editor, nOfs, &c);
-  this_para = c.pPara;
-  ME_CursorFromCharOfs(editor, nOfs + *nChars, &c2);
+  int nOfs = ME_GetCursorOfs(c);
+  ME_Cursor c2 = *c;
+  ME_DisplayItem *this_para = c->pPara;
+  ME_DisplayItem *end_para;
+
+  ME_MoveCursorChars(editor, &c2, *nChars);
   end_para = c2.pPara;
   if (c2.pRun->member.run.nFlags & MERF_ENDPARA) {
     /* End offset might be in the middle of the end paragraph run.
@@ -355,27 +358,32 @@ void ME_ProtectPartialTableDeletion(ME_TextEditor *editor, int nOfs,int *nChars)
         this_para->member.para.pFmt->dwMask & PFM_TABLE &&
         this_para->member.para.pFmt->wEffects & PFE_TABLE)
     {
-      pRun = c.pRun;
+      pRun = c->pRun;
       /* Find the next tab or end paragraph to use as a delete boundary */
       while (!(pRun->member.run.nFlags & (MERF_TAB|MERF_ENDPARA)))
         pRun = ME_FindItemFwd(pRun, diRun);
       nCharsToBoundary = pRun->member.run.nCharOfs
-                         - c.pRun->member.run.nCharOfs
-                         - c.nOffset;
+                         - c->pRun->member.run.nCharOfs
+                         - c->nOffset;
       *nChars = min(*nChars, nCharsToBoundary);
     } else if (end_para->member.para.pFmt->dwMask & PFM_TABLE &&
                end_para->member.para.pFmt->wEffects & PFE_TABLE)
     {
       /* The deletion starts from before the row, so don't join it with
        * previous non-empty paragraphs. */
+      ME_DisplayItem *curPara;
       pRun = NULL;
-      if (nOfs > this_para->member.para.nCharOfs)
+      if (nOfs > this_para->member.para.nCharOfs) {
         pRun = ME_FindItemBack(end_para, diRun);
-      if (!pRun)
+        curPara = end_para->member.para.prev_para;
+      }
+      if (!pRun) {
         pRun = ME_FindItemFwd(end_para, diRun);
+        curPara = end_para;
+      }
       if (pRun)
       {
-        nCharsToBoundary = ME_GetParagraph(pRun)->member.para.nCharOfs
+        nCharsToBoundary = curPara->member.para.nCharOfs
                            + pRun->member.run.nCharOfs
                            - nOfs;
         if (nCharsToBoundary >= 0)
@@ -549,8 +557,8 @@ void ME_TabPressedInTable(ME_TextEditor *editor, BOOL bSelectedRow)
   ME_InvalidateSelection(editor);
   {
     int from, to;
-    from = ME_GetCursorOfs(editor, 0);
-    to = ME_GetCursorOfs(editor, 1);
+    from = ME_GetCursorOfs(&editor->pCursors[0]);
+    to = ME_GetCursorOfs(&editor->pCursors[1]);
     if (from <= to)
     {
       fromCursor = editor->pCursors[0];
index 8fabd83..68f4437 100644 (file)
@@ -42,9 +42,9 @@ typedef struct ITextHostImpl {
     BOOL bEmulateVersion10;
 } ITextHostImpl;
 
-static ITextHostVtbl textHostVtbl;
+static const ITextHostVtbl textHostVtbl;
 
-ITextHost *ME_CreateTextHost(HWND hwnd, BOOL bEmulateVersion10)
+ITextHost *ME_CreateTextHost(HWND hwnd, CREATESTRUCTW *cs, BOOL bEmulateVersion10)
 {
     ITextHostImpl *texthost;
     texthost = CoTaskMemAlloc(sizeof(*texthost));
@@ -59,7 +59,9 @@ ITextHost *ME_CreateTextHost(HWND hwnd, BOOL bEmulateVersion10)
 
         editor = ME_MakeEditor((ITextHost*)texthost, bEmulateVersion10);
         editor->exStyleFlags = GetWindowLongW(hwnd, GWL_EXSTYLE);
+        editor->styleFlags |= GetWindowLongW(hwnd, GWL_STYLE) & ES_WANTRETURN;
         editor->hWnd = hwnd; /* FIXME: Remove editor's dependence on hWnd */
+        editor->hwndParent = cs->hwndParent;
         SetWindowLongPtrW(hwnd, 0, (LONG_PTR)editor);
     }
 
@@ -448,9 +450,13 @@ HRESULT WINAPI ITextHostImpl_TxNotify(ITextHost *iface,
                                       void *pv)
 {
     ITextHostImpl *This = (ITextHostImpl *)iface;
+    ME_TextEditor *editor = (ME_TextEditor*)GetWindowLongPtrW(This->hWnd, 0);
     HWND hwnd = This->hWnd;
-    HWND parent = GetParent(hwnd);
-    UINT id = GetWindowLongW(hwnd, GWLP_ID);
+    UINT id;
+
+    if (!editor || !editor->hwndParent) return S_OK;
+
+    id = GetWindowLongW(hwnd, GWLP_ID);
 
     switch (iNotify)
     {
@@ -471,13 +477,13 @@ HRESULT WINAPI ITextHostImpl_TxNotify(ITextHost *iface,
             info->hwndFrom = hwnd;
             info->idFrom = id;
             info->code = iNotify;
-            SendMessageW(parent, WM_NOTIFY, id, (LPARAM)info);
+            SendMessageW(editor->hwndParent, WM_NOTIFY, id, (LPARAM)info);
             break;
         }
 
         case EN_UPDATE:
             /* Only sent when the window is visible. */
-            if (!IsWindowVisible(This->hWnd))
+            if (!IsWindowVisible(hwnd))
                 break;
             /* Fall through */
         case EN_CHANGE:
@@ -487,7 +493,7 @@ HRESULT WINAPI ITextHostImpl_TxNotify(ITextHost *iface,
         case EN_MAXTEXT:
         case EN_SETFOCUS:
         case EN_VSCROLL:
-            SendMessageW(parent, WM_COMMAND, MAKEWPARAM(id, iNotify), (LPARAM)hwnd);
+            SendMessageW(editor->hwndParent, WM_COMMAND, MAKEWPARAM(id, iNotify), (LPARAM)hwnd);
             break;
 
         case EN_MSGFILTER:
@@ -528,159 +534,114 @@ HRESULT WINAPI ITextHostImpl_TxGetSelectionBarWidth(ITextHost *iface,
 #ifdef __i386__  /* thiscall functions are i386-specific */
 
 #define THISCALL(func) __thiscall_ ## func
-#define DEFINE_THISCALL_WRAPPER(func) \
+#define DEFINE_THISCALL_WRAPPER(func,args) \
    extern typeof(func) THISCALL(func); \
-   __ASM_GLOBAL_FUNC(__thiscall_ ## func, \
+   __ASM_STDCALL_FUNC(__thiscall_ ## func, args, \
                    "popl %eax\n\t" \
                    "pushl %ecx\n\t" \
                    "pushl %eax\n\t" \
-                   "jmp " __ASM_NAME(#func) )
+                   "jmp " __ASM_NAME(#func) __ASM_STDCALL(args) )
 
 #else /* __i386__ */
 
 #define THISCALL(func) func
-#define DEFINE_THISCALL_WRAPPER(func) /* nothing */
+#define DEFINE_THISCALL_WRAPPER(func,args) /* nothing */
 
 #endif /* __i386__ */
 
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetDC);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxReleaseDC);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxShowScrollBar);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxEnableScrollBar);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetScrollRange);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetScrollPos);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxInvalidateRect);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxViewChange);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxCreateCaret);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxShowCaret);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetCaretPos);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetTimer);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxKillTimer);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxScrollWindowEx);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetCapture);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetFocus);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetCursor);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxScreenToClient);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxClientToScreen);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxActivate);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxDeactivate);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetClientRect);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetViewInset);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetCharFormat);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetParaFormat);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetSysColor);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetBackStyle);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetMaxLength);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetScrollBars);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetPasswordChar);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetAcceleratorPos);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetExtent);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_OnTxCharFormatChange);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_OnTxParaFormatChange);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetPropertyBits);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxNotify);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxImmGetContext);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxImmReleaseContext);
-DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetSelectionBarWidth);
-
-static ITextHostVtbl textHostVtbl = {
-    ITextHostImpl_QueryInterface,
-    ITextHostImpl_AddRef,
-    ITextHostImpl_Release,
-    THISCALL(ITextHostImpl_TxGetDC),
-    THISCALL(ITextHostImpl_TxReleaseDC),
-    THISCALL(ITextHostImpl_TxShowScrollBar),
-    THISCALL(ITextHostImpl_TxEnableScrollBar),
-    THISCALL(ITextHostImpl_TxSetScrollRange),
-    THISCALL(ITextHostImpl_TxSetScrollPos),
-    THISCALL(ITextHostImpl_TxInvalidateRect),
-    THISCALL(ITextHostImpl_TxViewChange),
-    THISCALL(ITextHostImpl_TxCreateCaret),
-    THISCALL(ITextHostImpl_TxShowCaret),
-    THISCALL(ITextHostImpl_TxSetCaretPos),
-    THISCALL(ITextHostImpl_TxSetTimer),
-    THISCALL(ITextHostImpl_TxKillTimer),
-    THISCALL(ITextHostImpl_TxScrollWindowEx),
-    THISCALL(ITextHostImpl_TxSetCapture),
-    THISCALL(ITextHostImpl_TxSetFocus),
-    THISCALL(ITextHostImpl_TxSetCursor),
-    THISCALL(ITextHostImpl_TxScreenToClient),
-    THISCALL(ITextHostImpl_TxClientToScreen),
-    THISCALL(ITextHostImpl_TxActivate),
-    THISCALL(ITextHostImpl_TxDeactivate),
-    THISCALL(ITextHostImpl_TxGetClientRect),
-    THISCALL(ITextHostImpl_TxGetViewInset),
-    THISCALL(ITextHostImpl_TxGetCharFormat),
-    THISCALL(ITextHostImpl_TxGetParaFormat),
-    THISCALL(ITextHostImpl_TxGetSysColor),
-    THISCALL(ITextHostImpl_TxGetBackStyle),
-    THISCALL(ITextHostImpl_TxGetMaxLength),
-    THISCALL(ITextHostImpl_TxGetScrollBars),
-    THISCALL(ITextHostImpl_TxGetPasswordChar),
-    THISCALL(ITextHostImpl_TxGetAcceleratorPos),
-    THISCALL(ITextHostImpl_TxGetExtent),
-    THISCALL(ITextHostImpl_OnTxCharFormatChange),
-    THISCALL(ITextHostImpl_OnTxParaFormatChange),
-    THISCALL(ITextHostImpl_TxGetPropertyBits),
-    THISCALL(ITextHostImpl_TxNotify),
-    THISCALL(ITextHostImpl_TxImmGetContext),
-    THISCALL(ITextHostImpl_TxImmReleaseContext),
-    THISCALL(ITextHostImpl_TxGetSelectionBarWidth),
-};
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetDC,4)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxReleaseDC,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxShowScrollBar,12)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxEnableScrollBar,12)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetScrollRange,20)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetScrollPos,16)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxInvalidateRect,12)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxViewChange,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxCreateCaret,16)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxShowCaret,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetCaretPos,12)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetTimer,12)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxKillTimer,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxScrollWindowEx,32)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetCapture,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetFocus,4)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetCursor,12)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxScreenToClient,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxClientToScreen,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxActivate,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxDeactivate,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetClientRect,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetViewInset,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetCharFormat,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetParaFormat,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetSysColor,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetBackStyle,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetMaxLength,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetScrollBars,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetPasswordChar,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetAcceleratorPos,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetExtent,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_OnTxCharFormatChange,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_OnTxParaFormatChange,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetPropertyBits,12)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxNotify,12)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxImmGetContext,4)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxImmReleaseContext,8)
+DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetSelectionBarWidth,8)
 
 #ifdef __i386__  /* thiscall functions are i386-specific */
 
 #define STDCALL(func) __stdcall_ ## func
-#define DEFINE_STDCALL_WRAPPER(num,func) \
+#define DEFINE_STDCALL_WRAPPER(num,func,args) \
    extern typeof(func) __stdcall_ ## func; \
-   __ASM_GLOBAL_FUNC(__stdcall_ ## func, \
+   __ASM_STDCALL_FUNC(__stdcall_ ## func, args, \
                    "popl %eax\n\t" \
                    "popl %ecx\n\t" \
                    "pushl %eax\n\t" \
                    "movl (%ecx), %eax\n\t" \
                    "jmp *(4*(" #num "))(%eax)" )
 
-DEFINE_STDCALL_WRAPPER(3,ITextHostImpl_TxGetDC);
-DEFINE_STDCALL_WRAPPER(4,ITextHostImpl_TxReleaseDC);
-DEFINE_STDCALL_WRAPPER(5,ITextHostImpl_TxShowScrollBar);
-DEFINE_STDCALL_WRAPPER(6,ITextHostImpl_TxEnableScrollBar);
-DEFINE_STDCALL_WRAPPER(7,ITextHostImpl_TxSetScrollRange);
-DEFINE_STDCALL_WRAPPER(8,ITextHostImpl_TxSetScrollPos);
-DEFINE_STDCALL_WRAPPER(9,ITextHostImpl_TxInvalidateRect);
-DEFINE_STDCALL_WRAPPER(10,ITextHostImpl_TxViewChange);
-DEFINE_STDCALL_WRAPPER(11,ITextHostImpl_TxCreateCaret);
-DEFINE_STDCALL_WRAPPER(12,ITextHostImpl_TxShowCaret);
-DEFINE_STDCALL_WRAPPER(13,ITextHostImpl_TxSetCaretPos);
-DEFINE_STDCALL_WRAPPER(14,ITextHostImpl_TxSetTimer);
-DEFINE_STDCALL_WRAPPER(15,ITextHostImpl_TxKillTimer);
-DEFINE_STDCALL_WRAPPER(16,ITextHostImpl_TxScrollWindowEx);
-DEFINE_STDCALL_WRAPPER(17,ITextHostImpl_TxSetCapture);
-DEFINE_STDCALL_WRAPPER(18,ITextHostImpl_TxSetFocus);
-DEFINE_STDCALL_WRAPPER(19,ITextHostImpl_TxSetCursor);
-DEFINE_STDCALL_WRAPPER(20,ITextHostImpl_TxScreenToClient);
-DEFINE_STDCALL_WRAPPER(21,ITextHostImpl_TxClientToScreen);
-DEFINE_STDCALL_WRAPPER(22,ITextHostImpl_TxActivate);
-DEFINE_STDCALL_WRAPPER(23,ITextHostImpl_TxDeactivate);
-DEFINE_STDCALL_WRAPPER(24,ITextHostImpl_TxGetClientRect);
-DEFINE_STDCALL_WRAPPER(25,ITextHostImpl_TxGetViewInset);
-DEFINE_STDCALL_WRAPPER(26,ITextHostImpl_TxGetCharFormat);
-DEFINE_STDCALL_WRAPPER(27,ITextHostImpl_TxGetParaFormat);
-DEFINE_STDCALL_WRAPPER(28,ITextHostImpl_TxGetSysColor);
-DEFINE_STDCALL_WRAPPER(29,ITextHostImpl_TxGetBackStyle);
-DEFINE_STDCALL_WRAPPER(30,ITextHostImpl_TxGetMaxLength);
-DEFINE_STDCALL_WRAPPER(31,ITextHostImpl_TxGetScrollBars);
-DEFINE_STDCALL_WRAPPER(32,ITextHostImpl_TxGetPasswordChar);
-DEFINE_STDCALL_WRAPPER(33,ITextHostImpl_TxGetAcceleratorPos);
-DEFINE_STDCALL_WRAPPER(34,ITextHostImpl_TxGetExtent);
-DEFINE_STDCALL_WRAPPER(35,ITextHostImpl_OnTxCharFormatChange);
-DEFINE_STDCALL_WRAPPER(36,ITextHostImpl_OnTxParaFormatChange);
-DEFINE_STDCALL_WRAPPER(37,ITextHostImpl_TxGetPropertyBits);
-DEFINE_STDCALL_WRAPPER(38,ITextHostImpl_TxNotify);
-DEFINE_STDCALL_WRAPPER(39,ITextHostImpl_TxImmGetContext);
-DEFINE_STDCALL_WRAPPER(40,ITextHostImpl_TxImmReleaseContext);
-DEFINE_STDCALL_WRAPPER(41,ITextHostImpl_TxGetSelectionBarWidth);
-
-ITextHostVtbl itextHostStdcallVtbl = {
+DEFINE_STDCALL_WRAPPER(3,ITextHostImpl_TxGetDC,4)
+DEFINE_STDCALL_WRAPPER(4,ITextHostImpl_TxReleaseDC,8)
+DEFINE_STDCALL_WRAPPER(5,ITextHostImpl_TxShowScrollBar,12)
+DEFINE_STDCALL_WRAPPER(6,ITextHostImpl_TxEnableScrollBar,12)
+DEFINE_STDCALL_WRAPPER(7,ITextHostImpl_TxSetScrollRange,20)
+DEFINE_STDCALL_WRAPPER(8,ITextHostImpl_TxSetScrollPos,16)
+DEFINE_STDCALL_WRAPPER(9,ITextHostImpl_TxInvalidateRect,12)
+DEFINE_STDCALL_WRAPPER(10,ITextHostImpl_TxViewChange,8)
+DEFINE_STDCALL_WRAPPER(11,ITextHostImpl_TxCreateCaret,16)
+DEFINE_STDCALL_WRAPPER(12,ITextHostImpl_TxShowCaret,8)
+DEFINE_STDCALL_WRAPPER(13,ITextHostImpl_TxSetCaretPos,12)
+DEFINE_STDCALL_WRAPPER(14,ITextHostImpl_TxSetTimer,12)
+DEFINE_STDCALL_WRAPPER(15,ITextHostImpl_TxKillTimer,8)
+DEFINE_STDCALL_WRAPPER(16,ITextHostImpl_TxScrollWindowEx,32)
+DEFINE_STDCALL_WRAPPER(17,ITextHostImpl_TxSetCapture,8)
+DEFINE_STDCALL_WRAPPER(18,ITextHostImpl_TxSetFocus,4)
+DEFINE_STDCALL_WRAPPER(19,ITextHostImpl_TxSetCursor,12)
+DEFINE_STDCALL_WRAPPER(20,ITextHostImpl_TxScreenToClient,8)
+DEFINE_STDCALL_WRAPPER(21,ITextHostImpl_TxClientToScreen,8)
+DEFINE_STDCALL_WRAPPER(22,ITextHostImpl_TxActivate,8)
+DEFINE_STDCALL_WRAPPER(23,ITextHostImpl_TxDeactivate,8)
+DEFINE_STDCALL_WRAPPER(24,ITextHostImpl_TxGetClientRect,8)
+DEFINE_STDCALL_WRAPPER(25,ITextHostImpl_TxGetViewInset,8)
+DEFINE_STDCALL_WRAPPER(26,ITextHostImpl_TxGetCharFormat,8)
+DEFINE_STDCALL_WRAPPER(27,ITextHostImpl_TxGetParaFormat,8)
+DEFINE_STDCALL_WRAPPER(28,ITextHostImpl_TxGetSysColor,8)
+DEFINE_STDCALL_WRAPPER(29,ITextHostImpl_TxGetBackStyle,8)
+DEFINE_STDCALL_WRAPPER(30,ITextHostImpl_TxGetMaxLength,8)
+DEFINE_STDCALL_WRAPPER(31,ITextHostImpl_TxGetScrollBars,8)
+DEFINE_STDCALL_WRAPPER(32,ITextHostImpl_TxGetPasswordChar,8)
+DEFINE_STDCALL_WRAPPER(33,ITextHostImpl_TxGetAcceleratorPos,8)
+DEFINE_STDCALL_WRAPPER(34,ITextHostImpl_TxGetExtent,8)
+DEFINE_STDCALL_WRAPPER(35,ITextHostImpl_OnTxCharFormatChange,8)
+DEFINE_STDCALL_WRAPPER(36,ITextHostImpl_OnTxParaFormatChange,8)
+DEFINE_STDCALL_WRAPPER(37,ITextHostImpl_TxGetPropertyBits,12)
+DEFINE_STDCALL_WRAPPER(38,ITextHostImpl_TxNotify,12)
+DEFINE_STDCALL_WRAPPER(39,ITextHostImpl_TxImmGetContext,4)
+DEFINE_STDCALL_WRAPPER(40,ITextHostImpl_TxImmReleaseContext,8)
+DEFINE_STDCALL_WRAPPER(41,ITextHostImpl_TxGetSelectionBarWidth,8)
+
+const ITextHostVtbl itextHostStdcallVtbl = {
     NULL,
     NULL,
     NULL,
@@ -726,3 +687,48 @@ ITextHostVtbl itextHostStdcallVtbl = {
 };
 
 #endif /* __i386__ */
+
+static const ITextHostVtbl textHostVtbl = {
+    ITextHostImpl_QueryInterface,
+    ITextHostImpl_AddRef,
+    ITextHostImpl_Release,
+    THISCALL(ITextHostImpl_TxGetDC),
+    THISCALL(ITextHostImpl_TxReleaseDC),
+    THISCALL(ITextHostImpl_TxShowScrollBar),
+    THISCALL(ITextHostImpl_TxEnableScrollBar),
+    THISCALL(ITextHostImpl_TxSetScrollRange),
+    THISCALL(ITextHostImpl_TxSetScrollPos),
+    THISCALL(ITextHostImpl_TxInvalidateRect),
+    THISCALL(ITextHostImpl_TxViewChange),
+    THISCALL(ITextHostImpl_TxCreateCaret),
+    THISCALL(ITextHostImpl_TxShowCaret),
+    THISCALL(ITextHostImpl_TxSetCaretPos),
+    THISCALL(ITextHostImpl_TxSetTimer),
+    THISCALL(ITextHostImpl_TxKillTimer),
+    THISCALL(ITextHostImpl_TxScrollWindowEx),
+    THISCALL(ITextHostImpl_TxSetCapture),
+    THISCALL(ITextHostImpl_TxSetFocus),
+    THISCALL(ITextHostImpl_TxSetCursor),
+    THISCALL(ITextHostImpl_TxScreenToClient),
+    THISCALL(ITextHostImpl_TxClientToScreen),
+    THISCALL(ITextHostImpl_TxActivate),
+    THISCALL(ITextHostImpl_TxDeactivate),
+    THISCALL(ITextHostImpl_TxGetClientRect),
+    THISCALL(ITextHostImpl_TxGetViewInset),
+    THISCALL(ITextHostImpl_TxGetCharFormat),
+    THISCALL(ITextHostImpl_TxGetParaFormat),
+    THISCALL(ITextHostImpl_TxGetSysColor),
+    THISCALL(ITextHostImpl_TxGetBackStyle),
+    THISCALL(ITextHostImpl_TxGetMaxLength),
+    THISCALL(ITextHostImpl_TxGetScrollBars),
+    THISCALL(ITextHostImpl_TxGetPasswordChar),
+    THISCALL(ITextHostImpl_TxGetAcceleratorPos),
+    THISCALL(ITextHostImpl_TxGetExtent),
+    THISCALL(ITextHostImpl_OnTxCharFormatChange),
+    THISCALL(ITextHostImpl_OnTxParaFormatChange),
+    THISCALL(ITextHostImpl_TxGetPropertyBits),
+    THISCALL(ITextHostImpl_TxNotify),
+    THISCALL(ITextHostImpl_TxImmGetContext),
+    THISCALL(ITextHostImpl_TxImmReleaseContext),
+    THISCALL(ITextHostImpl_TxGetSelectionBarWidth),
+};
index a6d8170..7ab2af4 100644 (file)
 #ifdef __i386__  /* thiscall functions are i386-specific */
 
 #define THISCALL(func) __thiscall_ ## func
-#define DEFINE_THISCALL_WRAPPER(func) \
+#define DEFINE_THISCALL_WRAPPER(func,args) \
    extern typeof(func) THISCALL(func); \
-   __ASM_GLOBAL_FUNC(__thiscall_ ## func, \
+   __ASM_STDCALL_FUNC(__thiscall_ ## func, args, \
                    "popl %eax\n\t" \
                    "pushl %ecx\n\t" \
                    "pushl %eax\n\t" \
-                   "jmp " __ASM_NAME(#func) )
+                   "jmp " __ASM_NAME(#func) __ASM_STDCALL(args) )
 #else /* __i386__ */
 
 #define THISCALL(func) func
-#define DEFINE_THISCALL_WRAPPER(func) /* nothing */
+#define DEFINE_THISCALL_WRAPPER(func,args) /* nothing */
 
 #endif /* __i386__ */
 
@@ -87,6 +87,8 @@ HRESULT WINAPI CreateTextServices(IUnknown  * pUnkOuter,
    ITextImpl->pMyHost = pITextHost;
    ITextImpl->lpVtbl = &textservices_Vtbl;
    ITextImpl->editor = ME_MakeEditor(pITextHost, FALSE);
+   ITextImpl->editor->exStyleFlags = 0;
+   ITextImpl->editor->rcFormat = (RECT){0,0,0,0};
    ME_HandleMessage(ITextImpl->editor, WM_CREATE, 0, 0, TRUE, &hres);
 
    if (pUnkOuter)
@@ -292,12 +294,14 @@ HRESULT WINAPI fnTextSrv_TxGetText(ITextServices *iface,
    length = ME_GetTextLength(This->editor);
    if (length)
    {
+      ME_Cursor start;
       BSTR bstr;
       bstr = SysAllocStringByteLen(NULL, length * sizeof(WCHAR));
       if (bstr == NULL)
          return E_OUTOFMEMORY;
 
-      ME_GetTextW(This->editor, bstr , 0, length, FALSE);
+      ME_CursorFromCharOfs(This->editor, 0, &start);
+      ME_GetTextW(This->editor, bstr, length, &start, INT_MAX, FALSE);
       *pbstrText = bstr;
    } else {
       *pbstrText = NULL;
@@ -310,9 +314,11 @@ HRESULT WINAPI fnTextSrv_TxSetText(ITextServices *iface,
                                    LPCWSTR pszText)
 {
    ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
+   ME_Cursor cursor;
 
-   ME_InternalDeleteText(This->editor, 0, ME_GetTextLength(This->editor),
-                         FALSE);
+   ME_SetCursorToStart(This->editor, &cursor);
+   ME_InternalDeleteText(This->editor, &cursor,
+                         ME_GetTextLength(This->editor), FALSE);
    ME_InsertTextFromCursor(This->editor, 0, pszText, -1,
                            This->editor->pBuffer->pDefaultStyle);
    ME_SetSelection(This->editor, 0, 0);
@@ -387,24 +393,24 @@ HRESULT WINAPI fnTextSrv_TxGetCachedSize(ITextServices *iface,
    return E_NOTIMPL;
 }
 
-DEFINE_THISCALL_WRAPPER(fnTextSrv_TxSendMessage)
-DEFINE_THISCALL_WRAPPER(fnTextSrv_TxDraw)
-DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetHScroll)
-DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetVScroll)
-DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxSetCursor)
-DEFINE_THISCALL_WRAPPER(fnTextSrv_TxQueryHitPoint)
-DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxInplaceActivate)
-DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxInplaceDeactivate)
-DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxUIActivate)
-DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxUIDeactivate)
-DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetText)
-DEFINE_THISCALL_WRAPPER(fnTextSrv_TxSetText)
-DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetCurrentTargetX)
-DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetBaseLinePos)
-DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetNaturalSize)
-DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetDropTarget)
-DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxPropertyBitsChange)
-DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetCachedSize)
+DEFINE_THISCALL_WRAPPER(fnTextSrv_TxSendMessage,20)
+DEFINE_THISCALL_WRAPPER(fnTextSrv_TxDraw,52)
+DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetHScroll,24)
+DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetVScroll,24)
+DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxSetCursor,40)
+DEFINE_THISCALL_WRAPPER(fnTextSrv_TxQueryHitPoint,44)
+DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxInplaceActivate,8)
+DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxInplaceDeactivate,4)
+DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxUIActivate,4)
+DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxUIDeactivate,4)
+DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetText,8)
+DEFINE_THISCALL_WRAPPER(fnTextSrv_TxSetText,8)
+DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetCurrentTargetX,8)
+DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetBaseLinePos,8)
+DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetNaturalSize,36)
+DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetDropTarget,8)
+DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxPropertyBitsChange,12)
+DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetCachedSize,12)
 
 static const ITextServicesVtbl textservices_Vtbl =
 {
index c2f7125..8db9711 100644 (file)
@@ -298,17 +298,28 @@ static void ME_PlayUndoItem(ME_TextEditor *editor, ME_DisplayItem *pItem)
   }
   case diUndoSetCharFormat:
   {
-    ME_SetCharFormat(editor, pUItem->nStart, pUItem->nLen, &pItem->member.ustyle->fmt);
+    ME_Cursor start, end;
+    ME_CursorFromCharOfs(editor, pUItem->nStart, &start);
+    end = start;
+    ME_MoveCursorChars(editor, &end, pUItem->nLen);
+    ME_SetCharFormat(editor, &start, &end, &pItem->member.ustyle->fmt);
     break;
   }
   case diUndoInsertRun:
   {
-    ME_InsertRun(editor, pItem->member.run.nCharOfs, pItem);
+    ME_Cursor tmp;
+    ME_CursorFromCharOfs(editor, pItem->member.run.nCharOfs, &tmp);
+    ME_InsertRunAtCursor(editor, &tmp, pItem->member.run.style,
+                         pItem->member.run.strText->szData,
+                         pItem->member.run.strText->nLen,
+                         pItem->member.run.nFlags);
     break;
   }
   case diUndoDeleteRun:
   {
-    ME_InternalDeleteText(editor, pUItem->nStart, pUItem->nLen, TRUE);
+    ME_Cursor tmp;
+    ME_CursorFromCharOfs(editor, pUItem->nStart, &tmp);
+    ME_InternalDeleteText(editor, &tmp, pUItem->nLen, TRUE);
     break;
   }
   case diUndoJoinParagraphs:
index 579f33a..3b15490 100644 (file)
@@ -456,6 +456,29 @@ static ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
   return p->next;
 }
 
+static int ME_GetParaLineSpace(ME_Context* c, ME_Paragraph* para)
+{
+  int   sp = 0, ls = 0;
+  if (!(para->pFmt->dwMask & PFM_LINESPACING)) return 0;
+
+  /* FIXME: how to compute simply the line space in ls ??? */
+  /* FIXME: does line spacing include the line itself ??? */
+  switch (para->pFmt->bLineSpacingRule)
+  {
+  case 0:       sp = ls; break;
+  case 1:       sp = (3 * ls) / 2; break;
+  case 2:       sp = 2 * ls; break;
+  case 3:       sp = ME_twips2pointsY(c, para->pFmt->dyLineSpacing); if (sp < ls) sp = ls; break;
+  case 4:       sp = ME_twips2pointsY(c, para->pFmt->dyLineSpacing); break;
+  case 5:       sp = para->pFmt->dyLineSpacing / 20; break;
+  default: FIXME("Unsupported spacing rule value %d\n", para->pFmt->bLineSpacingRule);
+  }
+  if (c->editor->nZoomNumerator == 0)
+    return sp;
+  else
+    return sp * c->editor->nZoomNumerator / c->editor->nZoomDenominator;
+}
+
 static void ME_PrepareParagraphForWrapping(ME_Context *c, ME_DisplayItem *tp);
 
 static void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) {
@@ -499,7 +522,7 @@ static void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) {
   if (!(pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE) &&
       pFmt->dwMask & PFM_BORDER)
   {
-    border = ME_GetParaBorderWidth(c->editor, tp->member.para.pFmt->wBorders);
+    border = ME_GetParaBorderWidth(c, tp->member.para.pFmt->wBorders);
     if (pFmt->wBorders & 1) {
       wc.nFirstMargin += border;
       wc.nLeftMargin += border;
@@ -580,7 +603,6 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor)
   ME_DisplayItem *item;
   ME_Context c;
   BOOL bModified = FALSE;
-  int yStart = -1;
   int totalWidth = 0;
 
   ME_InitContext(&c, editor, ITextHost_TxGetDC(editor->texthost));
@@ -598,11 +620,7 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor)
     ME_WrapTextParagraph(&c, item);
 
     if (bRedraw)
-    {
       item->member.para.nFlags |= MEPF_REPAINT;
-      if (yStart == -1)
-        yStart = c.pt.y;
-    }
 
     bModified = bModified | bRedraw;
 
@@ -776,6 +794,8 @@ ME_SendRequestResize(ME_TextEditor *editor, BOOL force)
     {
       REQRESIZE info;
 
+      info.nmhdr.hwndFrom = NULL;
+      info.nmhdr.idFrom = 0;
       info.nmhdr.code = EN_REQUESTRESIZE;
       info.rc = rc;
       info.rc.right = editor->nTotalWidth;
index 6cadbd4..107fadf 100644 (file)
@@ -762,23 +762,23 @@ ME_StreamOutRTFText(ME_OutStream *pStream, const WCHAR *text, LONG nChars)
 }
 
 
-static BOOL
-ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream, int nStart, int nChars, int dwFormat)
+static BOOL ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream,
+                            const ME_Cursor *start, int nChars, int dwFormat)
 {
-  ME_DisplayItem *p, *pEnd, *pPara;
-  int nOffset, nEndLen;
+  ME_Cursor cursor = *start;
+  ME_DisplayItem *prev_para = cursor.pPara;
+  ME_Cursor endCur = cursor;
 
-  ME_RunOfsFromCharOfs(editor, nStart, &pPara, &p, &nOffset);
-  ME_RunOfsFromCharOfs(editor, nStart+nChars, NULL, &pEnd, &nEndLen);
+  ME_MoveCursorChars(editor, &endCur, nChars);
 
   if (!ME_StreamOutRTFHeader(pStream, dwFormat))
     return FALSE;
 
-  if (!ME_StreamOutRTFFontAndColorTbl(pStream, p, pEnd))
+  if (!ME_StreamOutRTFFontAndColorTbl(pStream, cursor.pRun, endCur.pRun))
     return FALSE;
-  
+
   /* TODO: stylesheet table */
-  
+
   /* FIXME: maybe emit something smarter for the generator? */
   if (!ME_StreamOutPrint(pStream, "{\\*\\generator Wine Riched20 2.0.????;}"))
     return FALSE;
@@ -791,138 +791,129 @@ ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream, int nStart, int nC
 
   /* TODO: section formatting properties */
 
-  if (!ME_StreamOutRTFParaProps(editor, pStream, ME_GetParagraph(p)))
+  if (!ME_StreamOutRTFParaProps(editor, pStream, cursor.pPara))
     return FALSE;
 
-  while(1)
-  {
-    switch(p->type)
+  do {
+    if (cursor.pPara != prev_para)
     {
-      case diParagraph:
-        if (!editor->bEmulateVersion10) { /* v4.1 */
-          if (p->member.para.nFlags & MEPF_ROWSTART) {
-            pStream->nNestingLevel++;
-            if (pStream->nNestingLevel == 1) {
-              if (!ME_StreamOutRTFTableProps(editor, pStream, p))
-                return FALSE;
-            }
-          } else if (p->member.para.nFlags & MEPF_ROWEND) {
-            pStream->nNestingLevel--;
-            if (pStream->nNestingLevel >= 1) {
-              if (!ME_StreamOutPrint(pStream, "{\\*\\nesttableprops"))
-                return FALSE;
-              if (!ME_StreamOutRTFTableProps(editor, pStream, p))
-                return FALSE;
-              if (!ME_StreamOutPrint(pStream, "\\nestrow}{\\nonesttables\\par}\r\n"))
-                return FALSE;
-            } else {
-              if (!ME_StreamOutPrint(pStream, "\\row \r\n"))
-                return FALSE;
-            }
-          } else if (!ME_StreamOutRTFParaProps(editor, pStream, p)) {
-            return FALSE;
-          }
-        } else { /* v1.0 - 3.0 */
-          if (p->member.para.pFmt->dwMask & PFM_TABLE &&
-              p->member.para.pFmt->wEffects & PFE_TABLE)
-          {
-            if (!ME_StreamOutRTFTableProps(editor, pStream, p))
+      prev_para = cursor.pPara;
+      if (!editor->bEmulateVersion10) { /* v4.1 */
+        if (cursor.pPara->member.para.nFlags & MEPF_ROWSTART) {
+          pStream->nNestingLevel++;
+          if (pStream->nNestingLevel == 1) {
+            if (!ME_StreamOutRTFTableProps(editor, pStream, cursor.pPara))
               return FALSE;
           }
-          if (!ME_StreamOutRTFParaProps(editor, pStream, p))
-            return FALSE;
-        }
-        pPara = p;
-        break;
-      case diRun:
-        if (p == pEnd && !nEndLen)
-          break;
-        TRACE("flags %xh\n", p->member.run.nFlags);
-        /* TODO: emit embedded objects */
-        if (pPara->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND))
-          break;
-        if (p->member.run.nFlags & MERF_GRAPHICS) {
-          FIXME("embedded objects are not handled\n");
-        } else if (p->member.run.nFlags & MERF_TAB) {
-          if (editor->bEmulateVersion10 && /* v1.0 - 3.0 */
-              pPara->member.para.pFmt->dwMask & PFM_TABLE &&
-              pPara->member.para.pFmt->wEffects & PFE_TABLE)
-          {
-            if (!ME_StreamOutPrint(pStream, "\\cell "))
+        } else if (cursor.pPara->member.para.nFlags & MEPF_ROWEND) {
+          pStream->nNestingLevel--;
+          if (pStream->nNestingLevel >= 1) {
+            if (!ME_StreamOutPrint(pStream, "{\\*\\nesttableprops"))
               return FALSE;
-          } else {
-            if (!ME_StreamOutPrint(pStream, "\\tab "))
+            if (!ME_StreamOutRTFTableProps(editor, pStream, cursor.pPara))
               return FALSE;
-          }
-        } else if (p->member.run.nFlags & MERF_ENDCELL) {
-          if (pStream->nNestingLevel > 1) {
-            if (!ME_StreamOutPrint(pStream, "\\nestcell "))
+            if (!ME_StreamOutPrint(pStream, "\\nestrow}{\\nonesttables\\par}\r\n"))
               return FALSE;
           } else {
-            if (!ME_StreamOutPrint(pStream, "\\cell "))
-              return FALSE;
-          }
-          nChars--;
-        } else if (p->member.run.nFlags & MERF_ENDPARA) {
-          if (pPara->member.para.pFmt->dwMask & PFM_TABLE &&
-              pPara->member.para.pFmt->wEffects & PFE_TABLE &&
-              !(pPara->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND|MEPF_CELL)))
-          {
             if (!ME_StreamOutPrint(pStream, "\\row \r\n"))
               return FALSE;
-          } else {
-            if (!ME_StreamOutPrint(pStream, "\r\n\\par"))
-              return FALSE;
           }
-          /* Skip as many characters as required by current line break */
-          nChars = max(0, nChars - p->member.run.strText->nLen);
-        } else if (p->member.run.nFlags & MERF_ENDROW) {
-          if (!ME_StreamOutPrint(pStream, "\\line \r\n"))
-            return FALSE;
-          nChars--;
-        } else {
-          int nEnd;
-          
-          if (!ME_StreamOutPrint(pStream, "{"))
-            return FALSE;
-          TRACE("style %p\n", p->member.run.style);
-          if (!ME_StreamOutRTFCharProps(pStream, &p->member.run.style->fmt))
-            return FALSE;
-        
-          nEnd = (p == pEnd) ? nEndLen : p->member.run.strText->nLen;
-          if (!ME_StreamOutRTFText(pStream, p->member.run.strText->szData + nOffset, nEnd - nOffset))
-            return FALSE;
-          nOffset = 0;
-          if (!ME_StreamOutPrint(pStream, "}"))
+        } else if (!ME_StreamOutRTFParaProps(editor, pStream, cursor.pPara)) {
+          return FALSE;
+        }
+      } else { /* v1.0 - 3.0 */
+        if (cursor.pPara->member.para.pFmt->dwMask & PFM_TABLE &&
+            cursor.pPara->member.para.pFmt->wEffects & PFE_TABLE)
+        {
+          if (!ME_StreamOutRTFTableProps(editor, pStream, cursor.pPara))
             return FALSE;
         }
-        break;
-      default: /* we missed the last item */
-        assert(0);
+        if (!ME_StreamOutRTFParaProps(editor, pStream, cursor.pPara))
+          return FALSE;
+      }
     }
-    if (p == pEnd)
+
+    if (cursor.pRun == endCur.pRun && !endCur.nOffset)
       break;
-    p = ME_FindItemFwd(p, diRunOrParagraphOrEnd);
-  }
+    TRACE("flags %xh\n", cursor.pRun->member.run.nFlags);
+    /* TODO: emit embedded objects */
+    if (cursor.pPara->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND))
+      break;
+    if (cursor.pRun->member.run.nFlags & MERF_GRAPHICS) {
+      FIXME("embedded objects are not handled\n");
+    } else if (cursor.pRun->member.run.nFlags & MERF_TAB) {
+      if (editor->bEmulateVersion10 && /* v1.0 - 3.0 */
+          cursor.pPara->member.para.pFmt->dwMask & PFM_TABLE &&
+          cursor.pPara->member.para.pFmt->wEffects & PFE_TABLE)
+      {
+        if (!ME_StreamOutPrint(pStream, "\\cell "))
+          return FALSE;
+      } else {
+        if (!ME_StreamOutPrint(pStream, "\\tab "))
+          return FALSE;
+      }
+    } else if (cursor.pRun->member.run.nFlags & MERF_ENDCELL) {
+      if (pStream->nNestingLevel > 1) {
+        if (!ME_StreamOutPrint(pStream, "\\nestcell "))
+          return FALSE;
+      } else {
+        if (!ME_StreamOutPrint(pStream, "\\cell "))
+          return FALSE;
+      }
+      nChars--;
+    } else if (cursor.pRun->member.run.nFlags & MERF_ENDPARA) {
+      if (cursor.pPara->member.para.pFmt->dwMask & PFM_TABLE &&
+          cursor.pPara->member.para.pFmt->wEffects & PFE_TABLE &&
+          !(cursor.pPara->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND|MEPF_CELL)))
+      {
+        if (!ME_StreamOutPrint(pStream, "\\row \r\n"))
+          return FALSE;
+      } else {
+        if (!ME_StreamOutPrint(pStream, "\r\n\\par"))
+          return FALSE;
+      }
+      /* Skip as many characters as required by current line break */
+      nChars = max(0, nChars - cursor.pRun->member.run.strText->nLen);
+    } else if (cursor.pRun->member.run.nFlags & MERF_ENDROW) {
+      if (!ME_StreamOutPrint(pStream, "\\line \r\n"))
+        return FALSE;
+      nChars--;
+    } else {
+      int nEnd;
+
+      if (!ME_StreamOutPrint(pStream, "{"))
+        return FALSE;
+      TRACE("style %p\n", cursor.pRun->member.run.style);
+      if (!ME_StreamOutRTFCharProps(pStream, &cursor.pRun->member.run.style->fmt))
+        return FALSE;
+
+      nEnd = (cursor.pRun == endCur.pRun) ? endCur.nOffset : cursor.pRun->member.run.strText->nLen;
+      if (!ME_StreamOutRTFText(pStream, cursor.pRun->member.run.strText->szData + cursor.nOffset,
+                               nEnd - cursor.nOffset))
+        return FALSE;
+      cursor.nOffset = 0;
+      if (!ME_StreamOutPrint(pStream, "}"))
+        return FALSE;
+    }
+  } while (cursor.pRun != endCur.pRun && ME_NextRun(&cursor.pPara, &cursor.pRun));
+
   if (!ME_StreamOutMove(pStream, "}\0", 2))
     return FALSE;
   return TRUE;
 }
 
 
-static BOOL
-ME_StreamOutText(ME_TextEditor *editor, ME_OutStream *pStream, int nStart, int nChars, DWORD dwFormat)
+static BOOL ME_StreamOutText(ME_TextEditor *editor, ME_OutStream *pStream,
+                             const ME_Cursor *start, int nChars, DWORD dwFormat)
 {
-  ME_DisplayItem *item;
+  ME_Cursor cursor = *start;
   int nLen;
   UINT nCodePage = CP_ACP;
   char *buffer = NULL;
   int nBufLen = 0;
   BOOL success = TRUE;
 
-  ME_RunOfsFromCharOfs(editor, nStart, NULL, &item, &nStart);
-
-  if (!item)
+  if (!cursor.pRun)
     return FALSE;
 
   if (dwFormat & SF_USECODEPAGE)
@@ -930,10 +921,10 @@ ME_StreamOutText(ME_TextEditor *editor, ME_OutStream *pStream, int nStart, int n
 
   /* TODO: Handle SF_TEXTIZED */
 
-  while (success && nChars && item) {
-    nLen = min(nChars, item->member.run.strText->nLen - nStart);
+  while (success && nChars && cursor.pRun) {
+    nLen = min(nChars, cursor.pRun->member.run.strText->nLen - cursor.nOffset);
 
-    if (!editor->bEmulateVersion10 && item->member.run.nFlags & MERF_ENDPARA)
+    if (!editor->bEmulateVersion10 && cursor.pRun->member.run.nFlags & MERF_ENDPARA)
     {
       static const WCHAR szEOL[2] = { '\r', '\n' };
 
@@ -944,27 +935,27 @@ ME_StreamOutText(ME_TextEditor *editor, ME_OutStream *pStream, int nStart, int n
         success = ME_StreamOutMove(pStream, "\r\n", 2);
     } else {
       if (dwFormat & SF_UNICODE)
-        success = ME_StreamOutMove(pStream, (const char *)(item->member.run.strText->szData + nStart),
+        success = ME_StreamOutMove(pStream, (const char *)(cursor.pRun->member.run.strText->szData + cursor.nOffset),
                                    sizeof(WCHAR) * nLen);
       else {
         int nSize;
 
-        nSize = WideCharToMultiByte(nCodePage, 0, item->member.run.strText->szData + nStart,
+        nSize = WideCharToMultiByte(nCodePage, 0, cursor.pRun->member.run.strText->szData + cursor.nOffset,
                                     nLen, NULL, 0, NULL, NULL);
         if (nSize > nBufLen) {
           FREE_OBJ(buffer);
           buffer = ALLOC_N_OBJ(char, nSize);
           nBufLen = nSize;
         }
-        WideCharToMultiByte(nCodePage, 0, item->member.run.strText->szData + nStart,
+        WideCharToMultiByte(nCodePage, 0, cursor.pRun->member.run.strText->szData + cursor.nOffset,
                             nLen, buffer, nSize, NULL, NULL);
         success = ME_StreamOutMove(pStream, buffer, nSize);
       }
     }
 
     nChars -= nLen;
-    nStart = 0;
-    item = ME_FindItemFwd(item, diRun);
+    cursor.nOffset = 0;
+    cursor.pRun = ME_FindItemFwd(cursor.pRun, diRun);
   }
 
   FREE_OBJ(buffer);
@@ -972,24 +963,16 @@ ME_StreamOutText(ME_TextEditor *editor, ME_OutStream *pStream, int nStart, int n
 }
 
 
-LRESULT
-ME_StreamOutRange(ME_TextEditor *editor, DWORD dwFormat, int nStart, int nTo, EDITSTREAM *stream)
+LRESULT ME_StreamOutRange(ME_TextEditor *editor, DWORD dwFormat,
+                          const ME_Cursor *start,
+                          int nChars, EDITSTREAM *stream)
 {
   ME_OutStream *pStream = ME_StreamOutInit(editor, stream);
 
-  if (nTo == -1)
-  {
-    nTo = ME_GetTextLength(editor);
-    /* Generate an end-of-paragraph at the end of SCF_ALL RTF output */
-    if (dwFormat & SF_RTF)
-      nTo++;
-  }
-  TRACE("from %d to %d\n", nStart, nTo);
-
   if (dwFormat & SF_RTF)
-    ME_StreamOutRTF(editor, pStream, nStart, nTo - nStart, dwFormat);
+    ME_StreamOutRTF(editor, pStream, start, nChars, dwFormat);
   else if (dwFormat & SF_TEXT || dwFormat & SF_TEXTIZED)
-    ME_StreamOutText(editor, pStream, nStart, nTo - nStart, dwFormat);
+    ME_StreamOutText(editor, pStream, start, nChars, dwFormat);
   if (!pStream->stream->dwError)
     ME_StreamOutFlush(pStream);
   return ME_StreamOutFree(pStream);
@@ -998,13 +981,19 @@ ME_StreamOutRange(ME_TextEditor *editor, DWORD dwFormat, int nStart, int nTo, ED
 LRESULT
 ME_StreamOut(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM *stream)
 {
-  int nStart, nTo;
+  ME_Cursor start;
+  int nChars;
 
-  if (dwFormat & SFF_SELECTION)
-    ME_GetSelection(editor, &nStart, &nTo);
-  else {
-    nStart = 0;
-    nTo = -1;
+  if (dwFormat & SFF_SELECTION) {
+    int nStart, nTo;
+    start = editor->pCursors[ME_GetSelectionOfs(editor, &nStart, &nTo)];
+    nChars = nTo - nStart;
+  } else {
+    ME_SetCursorToStart(editor, &start);
+    nChars = ME_GetTextLength(editor);
+    /* Generate an end-of-paragraph at the end of SCF_ALL RTF output */
+    if (dwFormat & SF_RTF)
+      nChars++;
   }
-  return ME_StreamOutRange(editor, dwFormat, nStart, nTo, stream);
+  return ME_StreamOutRange(editor, dwFormat, &start, nChars, stream);
 }
index a588c56..828e413 100644 (file)
@@ -22,7 +22,7 @@ When porting a new DLL from Wine to ReactOS, please do the following steps
 The following build tools are shared with Wine.
 
 reactos/tools/unicode             # Synced to Wine-20081105 (~Wine-1.1.7)
-reactos/tools/widl                # Synced to Wine-1_1_39
+reactos/tools/widl                # Synced to Wine-1_1_41
 reactos/tools/winebuild           # Synced to Wine-1_1_13
 reactos/tools/wmc                 # Synced to Wine-20081105 (~Wine-1.1.7)
 reactos/tools/wpp                 # Synced to Wine-20081105 (~Wine-1.1.7)
@@ -137,7 +137,7 @@ reactos/dll/win32/pstorec         # Autosync
 reactos/dll/win32/query           # Autosync
 reactos/dll/win32/rasapi32        # Autosync
 reactos/dll/win32/resutils        # Autosync
-reactos/dll/win32/riched20        # Autosync ??
+reactos/dll/win32/riched20        # Autosync
 reactos/dll/win32/riched32        # Autosync
 reactos/dll/win32/rpcrt4          # Synced to Wine-0_9_55
 reactos/dll/win32/rsabase         # Autosync