From 26ffed03d9bfa361f4a7c8cfae3b9ae729cf1abf Mon Sep 17 00:00:00 2001
From: James McKenzie <jamesmckenzie@Macintosh-5.local>
Date: Sun, 29 Nov 2009 11:28:15 -0700
Subject: EM_FORMATRANGE Patch for Wine-1.1.33

This fixes the EM_FORMATRANGE errors encountered by several programs and is a
proposed solution to Bug 6254.
---
 dlls/riched20/context.c      |   16 +++
 dlls/riched20/editor.c       |    8 +-
 dlls/riched20/editor.h       |    8 ++
 dlls/riched20/editstr.h      |   26 ++++
 dlls/riched20/list.c         |  109 +++++++++++++++++
 dlls/riched20/paint.c        |  274 ++++++++++++++++++++++++++++++++++++++++--
 dlls/riched20/style.c        |  113 +++++++++++++-----
 dlls/riched20/tests/editor.c |   10 --
 dlls/riched20/wrap.c         |    2 +-
 9 files changed, 509 insertions(+), 57 deletions(-)

diff --git a/dlls/riched20/context.c b/dlls/riched20/context.c
index 93d5caa..5af3afd 100644
--- a/dlls/riched20/context.c
+++ b/dlls/riched20/context.c
@@ -24,6 +24,22 @@ void ME_InitContext(ME_Context *c, ME_TextEditor *editor, HDC hDC)
 {
   c->nSequence = editor->nSequence++;
   c->hDC = hDC;
+  c->hdcMeasure = hDC;
+  c->fr.hdc = hDC;
+  c->fr.hdcTarget = hDC;
+  c->fr.rc.left = 0;
+  c->fr.rc.top = editor->vert_si.nPos;
+  c->fr.rc.right = editor->sizeWindow.cx;
+  c->fr.rc.bottom = editor->sizeWindow.cy + editor->vert_si.nPos;
+  c->fr.rcPage = c->fr.rc;
+  c->fr.chrg.cpMin = 0;
+  c->fr.chrg.cpMax = -1;
+  c->bClip = FALSE;
+  c->bHideSelection = FALSE;
+  c->dDraw.cx = GetDeviceCaps(hDC, LOGPIXELSX);
+  c->dDraw.cy = GetDeviceCaps(hDC, LOGPIXELSY);
+  c->dTarget = c->dDraw;
+  c->mRender = 0;
   c->editor = editor;
   c->pt.x = 0;
   c->pt.y = 0;
diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c
index 4bc901e..a3a694f 100644
--- a/dlls/riched20/editor.c
+++ b/dlls/riched20/editor.c
@@ -40,7 +40,7 @@
   + EM_FINDTEXTEX (only FR_DOWN flag implemented)
   - EM_FINDWORDBREAK
   - EM_FMTLINES
-  - EM_FORMATRANGE
+  + EM_FORMATRANGE
   + EM_GETAUTOURLDETECT 2.0
   - EM_GETBIDIOPTIONS 3.0
   - EM_GETCHARFORMAT (partly done)
@@ -201,7 +201,7 @@
  * - calculate heights of pictures (half-done)
  * - hysteresis during wrapping (related to scrollbars appearing/disappearing)
  * - find/replace
- * - how to implement EM_FORMATRANGE and EM_DISPLAYBAND ? (Mission Impossible)
+ * - how to implement EM_DISPLAYBAND ? (Mission Impossible)
  * - italic caret with italic fonts
  * - IME
  * - most notifications aren't sent at all (the most important ones are)
@@ -2878,7 +2878,6 @@ static const char * const richedit_messages[] = {
   "EM_EXLINEFROMCHAR",
   "EM_EXSETSEL",
   "EM_FINDTEXT",
-  "EM_FORMATRANGE",
   "EM_GETCHARFORMAT",
   "EM_GETEVENTMASK",
   "EM_GETOLEINTERFACE",
@@ -3010,7 +3009,6 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
   UNSUPPORTED_MSG(EM_DISPLAYBAND)
   UNSUPPORTED_MSG(EM_FINDWORDBREAK)
   UNSUPPORTED_MSG(EM_FMTLINES)
-  UNSUPPORTED_MSG(EM_FORMATRANGE)
   UNSUPPORTED_MSG(EM_GETBIDIOPTIONS)
   UNSUPPORTED_MSG(EM_GETEDITSTYLE)
   UNSUPPORTED_MSG(EM_GETIMECOMPMODE)
@@ -3899,6 +3897,8 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
     }
     return (wParam >= 0x40000) ? 0 : MAKELONG( pt.x, pt.y );
   }
+  case EM_FORMATRANGE:
+    return ME_FormatContent(editor, (FORMATRANGE *) lParam, (BOOL) wParam);
   case WM_CREATE:
   {
     INT max;
diff --git a/dlls/riched20/editor.h b/dlls/riched20/editor.h
index 8a5304b..e6e9f4c 100644
--- a/dlls/riched20/editor.h
+++ b/dlls/riched20/editor.h
@@ -73,6 +73,9 @@ CHARFORMAT2W *ME_ToCF2W(CHARFORMAT2W *to, CHARFORMAT2W *from);
 void ME_CopyToCFAny(CHARFORMAT2W *to, CHARFORMAT2W *from);
 void ME_CopyCharFormat(CHARFORMAT2W *pDest, const CHARFORMAT2W *pSrc); /* only works with 2W structs */
 void ME_CharFormatFromLogFont(HDC hDC, const LOGFONTW *lf, CHARFORMAT2W *fmt); /* ditto */
+ME_Style *ME_MapStyle(ME_StyleMap *m, ME_Style *s);
+ME_StyleMap *ME_MakeStyleMap(void);
+void ME_FreeStyleMap(ME_StyleMap *m);
 
 /* list.c */
 void ME_InsertBefore(ME_DisplayItem *diWhere, ME_DisplayItem *diWhat);
@@ -86,6 +89,7 @@ ME_DisplayItem *ME_MakeDI(ME_DIType type);
 void ME_DestroyDisplayItem(ME_DisplayItem *item);
 void ME_DumpDocument(ME_TextBuffer *buffer);
 const char *ME_GetDITypeName(ME_DIType type);
+void ME_DuplicateText(ME_DisplayItem *pFirst, ME_DisplayItem *pLast, ME_DisplayItem **ppNew, ME_DisplayItem **ppNewLast);
 
 /* string.c */
 ME_String *ME_MakeStringN(LPCWSTR szText, int nMaxChars);
@@ -130,6 +134,8 @@ 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);
 void ME_PropagateCharOffset(ME_DisplayItem *p, int shift);
+/*void ME_GetGraphicsSize(ME_TextEditor *editor, ME_Run *run, SIZE *pSize, ME_Di
+mension *pd); */
 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);
@@ -186,6 +192,7 @@ void ME_InitContext(ME_Context *c, ME_TextEditor *editor, HDC hDC);
 void ME_DestroyContext(ME_Context *c);
 
 /* wrap.c */
+void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp);
 BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor);
 void ME_InvalidateMarkedParagraphs(ME_TextEditor *editor);
 void ME_SendRequestResize(ME_TextEditor *editor, BOOL force);
@@ -207,6 +214,7 @@ void ME_MarkAllForWrapping(ME_TextEditor *editor);
 void ME_SetDefaultParaFormat(PARAFORMAT2 *pFmt);
 
 /* paint.c */
+LPARAM ME_FormatContent(ME_TextEditor *editor, FORMATRANGE *pfr, BOOL bNoOutput);
 void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, const RECT *rcUpdate);
 void ME_Repaint(ME_TextEditor *editor);
 void ME_RewrapRepaint(ME_TextEditor *editor);
diff --git a/dlls/riched20/editstr.h b/dlls/riched20/editstr.h
index 9b8d645..4653312 100644
--- a/dlls/riched20/editstr.h
+++ b/dlls/riched20/editstr.h
@@ -385,9 +385,35 @@ typedef struct tagME_TextEditor
   BOOL bMouseCaptured;
 } ME_TextEditor;
 
+typedef struct tagME_Dimension
+{
+	unsigned cx;
+	unsigned cy;
+} ME_Dimension;
+
+typedef struct tagME_StyleMapping
+{
+  ME_Style *from;
+  ME_Style *to;
+  struct tagME_StyleMapping *next;
+} ME_StyleMapping;
+
+typedef struct tagME_StyleMap
+{
+  ME_StyleMapping *first;
+} ME_StyleMap;
+
+
 typedef struct tagME_Context
 {
   HDC hDC;
+  HDC hdcMeasure;
+  FORMATRANGE fr;
+  BOOL	bClip;
+  BOOL	bHideSelection;
+  ME_Dimension dDraw;
+  ME_Dimension dTarget;
+  ME_StyleMap *mRender;
   POINT pt;
   POINT ptRowOffset;
   RECT rcView;
diff --git a/dlls/riched20/list.c b/dlls/riched20/list.c
index bb91bc4..636bd17 100644
--- a/dlls/riched20/list.c
+++ b/dlls/riched20/list.c
@@ -2,6 +2,7 @@
  * RichEdit - Basic operations on double linked lists.
  *
  * Copyright 2004 by Krzysztof Foltman
+ * Copyright 2006 CorVu Corporation
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -159,6 +160,114 @@ void ME_DestroyDisplayItem(ME_DisplayItem *item) {
   FREE_OBJ(item);
 }
 
+static ME_DisplayItem *ME_DuplicateDisplayItem(ME_DisplayItem *item,
+                                               ME_DisplayItem *prev,
+                                               ME_StyleMap *m)
+{
+  ME_DisplayItem *mdi = ALLOC_OBJ(ME_DisplayItem);
+
+  *mdi = *item;
+  mdi->prev = prev;
+  mdi->next = 0;
+  if (prev)
+    prev->next = mdi;
+
+  if (item->type == diParagraph || item->type == diUndoSplitParagraph)
+  {
+    mdi->member.para.pFmt = ALLOC_OBJ(PARAFORMAT2);
+    *mdi->member.para.pFmt = *item->member.para.pFmt;
+    mdi->member.para.next_para = 0;
+  }
+
+  if (item->type == diRun || item->type == diUndoInsertRun)
+  {
+    /* We need to copy the style and text, in the case of styles
+     * we need to reduce duplication which we can do with a style
+     * map.
+     */
+    mdi->member.run.style = ME_MapStyle(m, mdi->member.run.style);
+    mdi->member.run.strText = ME_StrDup(item->member.run.strText);
+
+    /*if (mdi->member.run.pCell)
+    {
+      /* Find the right ME_TableCell to link to by walking both the
+       * old and new list backwards.
+       *
+      ME_DisplayItem *from, *to;
+      ME_TableCell *target = mdi->member.run.pCell;
+
+      mdi->member.run.pCell = 0;
+      for (from = item, to = mdi;
+           !mdi->member.run.pCell && from && to;
+           from = from->prev, to = to->prev)
+      {
+        ME_TableCell *tt, *tf;
+
+	if (from->type != diParagraph && from->type != diUndoSplitParagraph)
+	    continue;
+
+        for (tf = from->member.para.pCells, tt = from->member.para.pCells;
+             tf && tt;
+             tf = tf->next, tt = tt->next)
+        {
+          if (tf == target)
+          {
+            mdi->member.run.pCell = tt;
+            break;
+          }
+        }
+      }
+    }*/
+  }
+
+  if (item->type == diUndoSetCharFormat)
+  {
+    /* Just map the style back */
+    mdi->member.ustyle = ME_MapStyle(m, mdi->member.ustyle);
+  }
+  if (item->type == diTextEnd  || item->type == diParagraph)
+  {
+    /* Make sure the last top level paragraph is linked up */
+    ME_DisplayItem *from, *to;
+
+    mdi->member.para.prev_para = 0;
+
+    for (from = item, to = mdi;
+         from && to;
+         from = from->prev, to = to->prev)
+    {
+      if ((from->type == diParagraph || from->type == diUndoSplitParagraph) &&
+          from->member.para.next_para == item)
+      {
+        to->member.para.next_para = mdi;
+        mdi->member.para.prev_para = to;
+        break;
+      }
+    }
+  }
+  return mdi;
+}
+
+/* ME_DuplicateText makes a duplicate of all ME_DisplayItem structures starting
+ * with pFirst and ending with pLast.
+ */
+void ME_DuplicateText(ME_DisplayItem *pFirst, ME_DisplayItem *pLast, ME_DisplayItem
+                      **ppNew, ME_DisplayItem **ppNewLast)
+{
+  ME_DisplayItem *pNow;
+  ME_StyleMap *m = ME_MakeStyleMap();
+
+  pNow = ME_DuplicateDisplayItem(pFirst, NULL, m);
+  *ppNew = pNow;
+  while (pFirst != pLast)
+  {
+    pFirst = pFirst->next;
+    pNow = ME_DuplicateDisplayItem(pFirst, pNow, m);
+    *ppNewLast = pNow;
+  }
+  ME_FreeStyleMap(m);
+}
+
 ME_DisplayItem *ME_MakeDI(ME_DIType type) {
   ME_DisplayItem *item = ALLOC_OBJ(ME_DisplayItem);
   ZeroMemory(item, sizeof(ME_DisplayItem));
diff --git a/dlls/riched20/paint.c b/dlls/riched20/paint.c
index 52127d7..75e4887 100644
--- a/dlls/riched20/paint.c
+++ b/dlls/riched20/paint.c
@@ -3,6 +3,7 @@
  *
  * Copyright 2004 by Krzysztof Foltman
  * Copyright 2005 by Phil Krylov
+ * Copyright 2006 CorVu Corporation
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -22,9 +23,191 @@
 #include "editor.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(richedit);
+WINE_DECLARE_DEBUG_CHANNEL(richedit_paint);
 
 static void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph);
 
+static int transform_x(ME_Context *c, int x)
+{
+        if (c->dTarget.cx == c->dDraw.cx)
+                return x;
+        return MulDiv(x, c->dDraw.cx, c->dTarget.cx);
+}
+
+static int transform_y(ME_Context *c, int y)
+{
+        if (c->dTarget.cy == c->dDraw.cy)
+                return y;
+        return MulDiv(y, c->dDraw.cy, c->dTarget.cy);
+}
+
+/*
+ * Support EM_FORMATRANGE.
+ *
+ * *** Notes on tables ***
+ *
+ * The CHARRANGE structure passed in the FORMATRANGE structure is not
+ * sufficient to deal with tables, where we would need information on the
+ * start position for text in each column of the table.
+ *
+ * Testing on Windows NT shows that the Microsoft Rich Edit control gives
+ * pathological results when there are tables in the document - both in edit
+ * mode and for EM_FORMATRANGE. The Microsoft Rich Edit control uses the
+ * table solely as a hint to where the paragraph should start. The table
+ * does not expand to fit its text. Long paragraphs wrap when you hit the
+ * right page margin and continue at the left page margin.
+ *
+ * If the paragraph ends outside its cell, the paragraph in the next cell
+ * continues at the X position immediately after the next cell boundary after
+ * the position of the last character in the paragraph. This may not be the
+ * cell associated with the paragraph, and may be the right hand table
+ * boundary (so that the paragraph commences after the right hand edge of the
+ * table). If the paragraph ends after the right hand table boundary, then the
+ * next paragraph begins on the next row of output at the X position for the
+ * second cell in the table.
+ *
+ * While all this wrapping is going on, the table borders will be positioned
+ * as if there were only one line of text in each cell of the table and the
+ * text fits neatly within the cells.
+ *
+ * This behaviour is sufficiently useless that it is probably not worth trying
+ * to duplicate, and given that CHARRANGE is insufficient to deal with tables,
+ * there seems little point in attempting to make our implementation of
+ * EM_FORMATRANGE do something sensible for tables. A lot of effort would be
+ * involved in doing so, and we would be doing something Microsoft has not
+ * done.
+ */
+
+LPARAM ME_FormatContent(ME_TextEditor *editor, FORMATRANGE *pfr, BOOL bDraw)
+{
+  ME_Context c;
+  int   iBGMode;
+  ME_DisplayItem *pFirst;
+  ME_DisplayItem *pLast;
+  ME_DisplayItem *pNow;
+  ME_DisplayItem *pIntra;
+  int   local_pt_y;
+  int   cyRow;
+  int   cyOffset = -1;
+  int   iEndOffset = -1;
+
+  if (!pfr)
+    return 0;
+
+  ME_InitContext(&c, editor, pfr->hdcTarget);
+  c.fr = *pfr;
+  c.bHideSelection = TRUE;
+  c.bClip = TRUE;
+
+  c.rcView.left = MulDiv(c.fr.rc.left, c.dTarget.cx, 1440);
+  c.rcView.right = MulDiv(c.fr.rc.right, c.dTarget.cx, 1440);
+  c.rcView.top = MulDiv(c.fr.rc.top, c.dTarget.cy, 1440);
+  c.rcView.bottom = MulDiv(c.fr.rc.bottom, c.dTarget.cy, 1440);
+
+  c.pt.x = 0;
+  c.pt.y = 0;
+
+  /* Get a copy of all the text in the control so we can perform calculations
+   * without interfering with the values cached for the on-screen data.
+   */
+
+  ME_DuplicateText(editor->pBuffer->pFirst, editor->pBuffer->pLast, &pFirst, &pLast);
+
+  /* Now perform wrapping on the resulting data, and find the vertical offset of
+   * the row at the start of the character range, and the character offset of the
+   * first non-printable character.
+   */
+
+  for (pNow = pFirst->next; pNow != pLast; pNow = pNow->member.para.next_para)
+  {
+    pNow->member.para.pt.y = c.pt.y;
+    pNow->member.para.nFlags |= MEPF_REWRAP;
+    ME_WrapTextParagraph(&c, pNow);
+    if (iEndOffset == -1)
+    {
+      int iParaOfs = pNow->member.para.nCharOfs;
+
+      local_pt_y = c.pt.y;
+      cyRow = 0;
+
+      for (pIntra = pNow; pIntra != pNow->member.para.next_para; pIntra = pIntra->next)
+      {
+        if (pIntra->type == diStartRow)
+        {
+              local_pt_y += cyRow;
+          cyRow = pIntra->member.row.nHeight;
+        }
+        else if (pIntra->type == diRun)
+        {
+          int iRunOfs = iParaOfs + pIntra->member.run.nCharOfs;
+          int iRunEndOfs = iRunOfs + (pIntra->member.run.strText ?
+                                     pIntra->member.run.strText->nLen : 1);
+          if (cyOffset == -1 && iRunEndOfs > c.fr.chrg.cpMin)
+            cyOffset = local_pt_y;
+          if (cyOffset != -1 && iEndOffset == -1)
+          {
+            if (local_pt_y > cyOffset &&
+                local_pt_y + cyRow > c.rcView.bottom - c.rcView.top + cyOffset)
+            {
+              iEndOffset = iRunOfs;
+              break;
+            }
+            if (c.fr.chrg.cpMax >= 0 &&
+                iRunEndOfs > c.fr.chrg.cpMax)
+            {
+              int iBottom = local_pt_y + cyRow - cyOffset + c.rcView.top;;
+
+              if (c.rcView.bottom > iBottom)
+                        c.rcView.bottom = iBottom;
+              iEndOffset = iRunOfs;
+              break;
+            }
+          }
+        }
+      }
+    }
+
+    c.pt.y += pNow->member.para.nHeight;
+  }
+
+  if (iEndOffset == -1)
+    iEndOffset = ME_GetTextLength(editor);
+
+  /* Then draw the data */
+  /* FIXME - transformation of non-text runs is not done yet */
+
+  if (bDraw)
+  {
+    c.mRender = ME_MakeStyleMap();
+    iBGMode = SetBkMode(c.hDC, TRANSPARENT);
+    c.dDraw.cx = GetDeviceCaps(c.fr.hdc, LOGPIXELSX);
+    c.dDraw.cy = GetDeviceCaps(c.fr.hdc, LOGPIXELSY);
+    c.hDC = c.fr.hdc;
+    c.hdcMeasure = c.fr.hdcTarget;
+    c.pt.x = 0;
+    c.pt.y = c.rcView.top - cyOffset;
+
+    for (pNow = pFirst->next; pNow != pLast; pNow = pNow->member.para.next_para)
+    {
+      if (c.pt.y + pNow->member.para.nHeight > c.rcView.top &&
+          c.pt.y < c.rcView.bottom)
+        ME_DrawParagraph(&c, pNow);
+      c.pt.y += pNow->member.para.nHeight;
+    }
+    SetBkMode(c.hDC, iBGMode);
+    ME_FreeStyleMap(c.mRender);
+  }
+
+  while (pFirst)
+  {
+    pNow = pFirst;
+    pFirst = pFirst->next;
+    ME_DestroyDisplayItem(pNow);
+  }
+
+  return iEndOffset;
+}
+
 void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, const RECT *rcUpdate)
 {
   ME_DisplayItem *item;
@@ -235,10 +418,12 @@ static void ME_HighlightSpace(ME_Context *c, int x, int y, LPCWSTR szText,
 }
 
 static void ME_DrawTextWithStyle(ME_Context *c, int x, int y, LPCWSTR szText,
-                                 int nChars, ME_Style *s, int width,
+                                 int nChars, ME_Style *sIn, int width,
                                  int nSelFrom, int nSelTo, int ymin, int cy)
 {
+  ME_Style *s = (c->mRender ? ME_MapStyle(c->mRender, sIn) : sIn);
   HDC hDC = c->hDC;
+  HDC hdcTarget = c->hdcMeasure;
   HGDIOBJ hOldFont;
   COLORREF rgbOld;
   int yOffset = 0, yTwipsOffset = 0;
@@ -266,6 +451,8 @@ static void ME_DrawTextWithStyle(ME_Context *c, int x, int y, LPCWSTR szText,
   }
   if (yTwipsOffset)
     yOffset = ME_twips2pointsY(c, yTwipsOffset);
+  TRACE_(richedit_paint)("%d is the current value of y, %d is the current value of yoffset\n", y, yOffset);
+  TRACE_(richedit_paint)("%d is the value of transformed y\n",transform_y(c,y-yOffset));
 
   if ((s->fmt.dwMask & CFM_LINK) && (s->fmt.dwEffects & CFE_LINK))
     rgb = RGB(0,0,255);
@@ -339,9 +526,25 @@ static void ME_DrawTextWithStyle(ME_Context *c, int x, int y, LPCWSTR szText,
       MoveToEx(hDC, x, y - yOffset + 1, NULL);
     if (xSelStart > x)
     {
-      ExtTextOutW(hDC, x, y-yOffset, 0, NULL, szText, nSelFrom, NULL);
-      if (hPen)
-        LineTo(hDC, xSelStart, y - yOffset + 1);
+      if (hDC != hdcTarget && nChars > 1 )
+      {
+        /*if it is not then glyphs were used and now we calculate positions for them */
+        ExtTextOutW(hDC, transform_x(c, x), transform_y(c, y - yOffset),
+                    0, NULL, szText, nSelFrom, NULL);
+      }
+      else if (hDC != hdcTarget && nChars==1) /*Target is not current window and
+                                               character is a tab */
+      {
+        width = transform_x(c,width);
+        ExtTextOutW(hDC, transform_x(c,x), transform_y(c,y-yOffset),
+                   0, NULL, szText, nSelFrom, NULL);
+      }
+      else  /*Target is current window */
+      {
+        ExtTextOutW(hDC, x, y-yOffset, 0, NULL, szText, nSelFrom, NULL);
+        if (hPen)
+          LineTo(hDC, xSelStart, y - yOffset + 1);
+      }
     }
     dim.top = ymin;
     dim.bottom = ymin + cy;
@@ -351,8 +554,24 @@ static void ME_DrawTextWithStyle(ME_Context *c, int x, int y, LPCWSTR szText,
                                               COLOR_HIGHLIGHTTEXT));
     rgbBackOld = SetBkColor(hDC, ITextHost_TxGetSysColor(c->editor->texthost,
                                                          COLOR_HIGHLIGHT));
-    ExtTextOutW(hDC, xSelStart, y-yOffset, ETO_OPAQUE, &dim,
-                szText+nSelFrom, nSelTo-nSelFrom, lpDx);
+    if (hDC != hdcTarget && nChars > 1 )
+    /*if it is not then glyphs were used and now we calculate positions for them */
+    {
+      ExtTextOutW(hDC, transform_x(c, xSelStart), transform_y(c, y - yOffset),
+                  ETO_OPAQUE, &dim, szText+nSelFrom, nSelTo-nSelFrom, lpDx);
+    }
+    else if (hDC != hdcTarget && nChars==1) /*Target is not current window and
+                                             character is a tab */
+    {
+      width = transform_x(c,width);
+      ExtTextOutW(hDC, transform_x(c,xSelStart), transform_y(c,y-yOffset),
+                  ETO_OPAQUE, &dim, szText+nSelFrom, nSelTo-nSelFrom, lpDx);
+    }
+    else  /*Target is current window */
+    {
+      ExtTextOutW(hDC, xSelStart, y-yOffset, ETO_OPAQUE, &dim,
+                  szText+nSelFrom, nSelTo-nSelFrom, lpDx);
+    }
     if (hPen)
       LineTo(hDC, xSelEnd, y - yOffset + 1);
     SetBkColor(hDC, rgbBackOld);
@@ -365,9 +584,17 @@ static void ME_DrawTextWithStyle(ME_Context *c, int x, int y, LPCWSTR szText,
         LineTo(hDC, x + width, y - yOffset + 1);
     }
   }
-  else
+  else  /* Version 1.0 code */
   {
-    ExtTextOutW(hDC, x, y-yOffset, 0, NULL, szText, nChars, lpDx);
+    if (hDC != hdcTarget && nChars > 1 )
+    /*if it is not then glyphs were used and now we calculate positions for them */
+    {
+      ExtTextOutW(hDC, transform_x(c,x), transform_y(c,y-yOffset), 0, NULL, szText, nChars, lpDx);
+    }
+    else  /*Target is current window */
+    {
+      ExtTextOutW(hDC, x, y-yOffset, 0, NULL, szText, nChars, lpDx);
+    }
 
     /* FIXME: should use textmetrics info for Descent info */
     if (hPen)
@@ -378,7 +605,17 @@ static void ME_DrawTextWithStyle(ME_Context *c, int x, int y, LPCWSTR szText,
 
     if (bHighlightedText) /* v1.0 inverts the selection */
     {
-      PatBlt(hDC, xSelStart, ymin, xSelEnd-xSelStart, cy, DSTINVERT);
+      if (hDC != hdcTarget)
+      {
+        TRACE_(richedit_paint)("Working with 1.0 emulation code and Transform Code\n");
+      /*if it is not then glyphs were used and now we calculate positions for them */
+        PatBlt(hDC, transform_x(c,xSelStart), transform_y(c,ymin), xSelEnd-xSelStart, cy, DSTINVERT);
+      }
+      else
+      {
+        TRACE_(richedit_paint)("Working with 1.0 empulating code without Transform Code\n");
+        PatBlt(hDC, xSelStart, ymin, xSelEnd-xSelStart, cy, DSTINVERT);
+      }
     }
   }
 
@@ -389,6 +626,9 @@ static void ME_DrawTextWithStyle(ME_Context *c, int x, int y, LPCWSTR szText,
   }
   SetTextColor(hDC, rgbOld);
   ME_UnselectStyleFont(c, s, hOldFont);
+  /*Clean up and exit */
+  if (c->mRender)
+    ME_ReleaseStyle(s);
 }
 
 static void ME_DebugWrite(HDC hDC, const POINT *pt, LPCWSTR szText) {
@@ -438,8 +678,10 @@ static void ME_DrawRun(ME_Context *c, int x, int y, ME_DisplayItem *rundi, ME_Pa
     return;
   }
 
+/* Add check for text and graphics to hide/unhide them */
   if (run->nFlags & MERF_GRAPHICS)
-    ME_DrawOLE(c, x, y, run, para, (runofs >= nSelFrom) && (runofs < nSelTo));
+/*    ME_DrawOLE(c, x, y, run, para, (runofs >= nSelFrom) && (runofs < nSelTo));*/
+    ME_DrawOLE(c,x,y,run,para, !c->editor->bHideSelection && !c->bHideSelection && (runofs >= nSelFrom) && (runofs < nSelTo));
   else
   {
     if (c->editor->cPasswordMask)
@@ -980,10 +1222,15 @@ static void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph)
         run = &p->member.run;
         if (visible && me_debug) {
           RECT rc;
+/* use transform to create margins
           rc.left = c->pt.x + run->pt.x;
           rc.right = rc.left + run->nWidth;
           rc.top = c->pt.y + para->pt.y + run->pt.y;
-          rc.bottom = rc.bottom + height;
+          rc.bottom = rc.bottom + height; */
+          rc.left = transform_x(c, c->pt.x + run->pt.x);
+          rc.right = transform_x(c, c->pt.x + run->pt.x + run->nWidth);
+          rc.top = transform_y(c, c->pt.y + para->pt.y + run->pt.y);
+          rc.bottom = transform_y(c, c->pt.y + para->pt.y + height);
           TRACE("rc = (%d, %d, %d, %d)\n", rc.left, rc.top, rc.right, rc.bottom);
           if (run->nFlags & MERF_SKIPPED)
             DrawFocusRect(c->hDC, &rc);
@@ -999,8 +1246,11 @@ static void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph)
           const WCHAR wszRunDebug[] = {'[','%','d',':','%','x',']',' ','%','l','s',0};
           WCHAR buf[2560];
           POINT pt;
+/* use transform call to create location on window
           pt.x = c->pt.x + run->pt.x;
-          pt.y = c->pt.y + para->pt.y + run->pt.y;
+          pt.y = c->pt.y + para->pt.y + run->pt.y; */
+          pt.x = transform_x(c, c->pt.x + run->pt.x);
+          pt.y = transform_y(c, c->pt.y + para->pt.y + run->pt.y);
           wsprintfW(buf, wszRunDebug, no, p->member.run.nFlags, p->member.run.strText->szData);
           ME_DebugWrite(c->hDC, &pt, buf);
         }
diff --git a/dlls/riched20/style.c b/dlls/riched20/style.c
index bb2f808..38bf466 100644
--- a/dlls/riched20/style.c
+++ b/dlls/riched20/style.c
@@ -372,43 +372,50 @@ HFONT ME_SelectStyleFont(ME_Context *c, ME_Style *s)
   
   ME_LogFontFromStyle(c, &lf, s);
   
-  for (i=0; i<HFONT_CACHE_SIZE; i++)
-    c->editor->pFontCache[i].nAge++;
-  for (i=0, nEmpty=-1, nAge=0; i<HFONT_CACHE_SIZE; i++)
+  if (c->editor)
   {
-    item = &c->editor->pFontCache[i];
-    if (!item->nRefs)
-    {
-      if (item->nAge > nAge)
-        nEmpty = i, nAge = item->nAge;
-    }
+    for (i=0; i<HFONT_CACHE_SIZE; i++)
+      c->editor->pFontCache[i].nAge++;
+    for (i=0, nEmpty=-1, nAge=0; i<HFONT_CACHE_SIZE; i++)
+	{
+      item = &c->editor->pFontCache[i];
+      if (!item->nRefs)
+      {
+        if (item->nAge > nAge)
+          nEmpty = i, nAge = item->nAge;
+      }
     if (item->hFont && ME_IsFontEqual(&item->lfSpecs, &lf))
       break;
-  }
-  if (i < HFONT_CACHE_SIZE) /* found */
-  {
-    item = &c->editor->pFontCache[i];
-    TRACE_(richedit_style)("font reused %d\n", i);
+    }
+    if (i < HFONT_CACHE_SIZE) /* found */
+    {
+      item = &c->editor->pFontCache[i];
+      TRACE_(richedit_style)("font reused %d\n", i);
 
-    s->hFont = item->hFont;
-    item->nRefs++;
+      s->hFont = item->hFont;
+      item->nRefs++;
+    }
+    else
+    {
+      item = &c->editor->pFontCache[nEmpty]; /* this legal even when nEmpty == -1, as we don't dereference it */
+
+      assert(nEmpty != -1); /* otherwise we leak cache entries or get too many fonts at once*/
+      if (item->hFont) {
+        TRACE_(richedit_style)("font deleted %d\n", nEmpty);
+        DeleteObject(item->hFont);
+        item->hFont = NULL;
+      }
+      s->hFont = CreateFontIndirectW(&lf);
+      assert(s->hFont);
+      TRACE_(richedit_style)("font created %d\n", nEmpty);
+      item->hFont = s->hFont;
+      item->nRefs = 1;
+      item->lfSpecs = lf;
+      }
   }
-  else
+  else if (!s->hFont)
   {
-    item = &c->editor->pFontCache[nEmpty]; /* this legal even when nEmpty == -1, as we don't dereference it */
-
-    assert(nEmpty != -1); /* otherwise we leak cache entries or get too many fonts at once*/
-    if (item->hFont) {
-      TRACE_(richedit_style)("font deleted %d\n", nEmpty);
-      DeleteObject(item->hFont);
-      item->hFont = NULL;
-    }
     s->hFont = CreateFontIndirectW(&lf);
-    assert(s->hFont);
-    TRACE_(richedit_style)("font created %d\n", nEmpty);
-    item->hFont = s->hFont;
-    item->nRefs = 1;
-    item->lfSpecs = lf;
   }
   hOldFont = SelectObject(c->hDC, s->hFont);
   /* should be cached too, maybe ? */
@@ -422,6 +429,8 @@ void ME_UnselectStyleFont(ME_Context *c, ME_Style *s, HFONT hOldFont)
   
   assert(s);
   SelectObject(c->hDC, hOldFont);
+  if (!c->editor)
+    return;
   for (i=0; i<HFONT_CACHE_SIZE; i++)
   {
     ME_FontCacheItem *pItem = &c->editor->pFontCache[i];
@@ -467,6 +476,50 @@ void ME_ReleaseStyle(ME_Style *s)
     ME_DestroyStyle(s);
 }
 
+ME_Style *ME_MapStyle(ME_StyleMap *m, ME_Style *s)
+{
+  ME_StyleMapping **tail;
+
+  if (!s)
+    return s;
+
+  for (tail = &m->first; *tail; tail = &(*tail)->next)
+  {
+    if ((*tail)->from == s)
+    {
+      ME_AddRefStyle((*tail)->to);
+      return (*tail)->to;
+    }
+  }
+  *tail = ALLOC_OBJ(ME_StyleMapping);
+  (*tail)->from = s;
+  (*tail)->to = ME_MakeStyle(&s->fmt);
+  ME_AddRefStyle((*tail)->to);
+  (*tail)->next = 0;
+  return (*tail)->to;
+}
+
+ME_StyleMap *ME_MakeStyleMap(void)
+{
+  ME_StyleMap *sm = ALLOC_OBJ(ME_StyleMap);
+
+  sm->first = 0;
+  return sm;
+}
+
+void ME_FreeStyleMap(ME_StyleMap *m)
+{
+  while (m->first)
+  {
+    ME_StyleMapping *p = m->first;
+
+    m->first = p->next;
+    ME_ReleaseStyle(p->to);
+    FREE_OBJ(p);
+  }
+  FREE_OBJ(m);
+}
+
 ME_Style *ME_GetInsertStyle(ME_TextEditor *editor, int nCursor)
 {
   if (ME_IsSelection(editor))
diff --git a/dlls/riched20/tests/editor.c b/dlls/riched20/tests/editor.c
index 70c100a..8fdc2c8 100644
--- a/dlls/riched20/tests/editor.c
+++ b/dlls/riched20/tests/editor.c
@@ -4870,9 +4870,7 @@ static void test_EM_FORMATRANGE(void)
     fr.rc.bottom = fr.rcPage.bottom = (stringsize.cy + 10) * tpp_y;
 
     r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, 0);
-    todo_wine {
     ok(r == len, "Expected %d, got %d\n", len, r);
-    }
 
     /* We know that the page can't hold the full string. See how many characters
      * are on the first one
@@ -4880,13 +4878,9 @@ static void test_EM_FORMATRANGE(void)
     fr.chrg.cpMin = 0;
     fr.chrg.cpMax = -1;
     r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) &fr);
-    todo_wine {
     ok(fr.rc.bottom == (stringsize.cy * tpp_y), "Expected bottom to be %d, got %d\n", (stringsize.cy * tpp_y), fr.rc.bottom);
-    }
     if (fmtstrings[i].first)
-      todo_wine {
       ok(r == fmtstrings[i].first, "Expected %d, got %d\n", fmtstrings[i].first, r);
-      }
     else
       ok(r < len, "Expected < %d, got %d\n", len, r);
 
@@ -4894,18 +4888,14 @@ static void test_EM_FORMATRANGE(void)
     fr.chrg.cpMin = r;
     r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) &fr);
     if (fmtstrings[i].second)
-      todo_wine {
       ok(r == fmtstrings[i].second, "Expected %d, got %d\n", fmtstrings[i].second, r);
-      }
     else
       ok (r < len, "Expected < %d, got %d\n", len, r);
 
     /* There is at least on more page, but we don't care */
 
     r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, 0);
-    todo_wine {
     ok(r == len, "Expected %d, got %d\n", len, r);
-    }
   }
 
   ReleaseDC(NULL, hdc);
diff --git a/dlls/riched20/wrap.c b/dlls/riched20/wrap.c
index 00229b2..3e76439 100644
--- a/dlls/riched20/wrap.c
+++ b/dlls/riched20/wrap.c
@@ -458,7 +458,7 @@ static ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
 
 static void ME_PrepareParagraphForWrapping(ME_Context *c, ME_DisplayItem *tp);
 
-static void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) {
+void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) {
   ME_DisplayItem *p;
   ME_WrapContext wc;
   int border = 0;
-- 
1.6.1

