The actual patch that brings in the EM_FORMATRANGE function. Tested with programs reported to have problems in Bug 6254.
James McKenzie
jjmckenzie51 at earthlink.net
Sat Feb 20 19:47:25 CST 2010
---
dlls/riched20/editor.c | 7 +-
dlls/riched20/editor.h | 5 ++
dlls/riched20/list.c | 95 ++++++++++++++++++++++++++
dlls/riched20/paint.c | 154 +++++++++++++++++++++++++++++++++++++++++-
dlls/riched20/style.c | 46 +++++++++++++
dlls/riched20/tests/editor.c | 15 ++---
6 files changed, 308 insertions(+), 14 deletions(-)
diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c
index 7a11647..3ad6d86 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)
@@ -3012,7 +3012,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)
@@ -3902,6 +3901,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 cdb5544..0843a00 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);
@@ -208,6 +212,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/list.c b/dlls/riched20/list.c
index bb91bc4..8b877c8 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,100 @@ 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 **pPrevCell,
+ ME_DisplayItem **pPrevPara)
+{
+ ME_DisplayItem *mdi = ALLOC_OBJ(ME_DisplayItem);
+
+ *mdi = *item;
+ mdi->prev = prev;
+ mdi->next = NULL;
+ if (prev)
+ prev->next = mdi;
+
+ switch (item->type)
+ {
+ case diCell:
+ {
+ ME_DisplayItem *prev_cell = *pPrevCell;
+ if (mdi->member.cell.prev_cell)
+ {
+ prev_cell->member.cell.next_cell = mdi;
+ mdi->member.cell.prev_cell = prev_cell;
+ mdi->member.cell.parent_cell = prev_cell->member.cell.parent_cell;
+ } else {
+ mdi->member.cell.parent_cell = prev_cell;
+ }
+ if (mdi->member.cell.next_cell)
+ *pPrevCell = mdi;
+ else
+ *pPrevCell = prev_cell->member.cell.parent_cell;
+ break;
+ }
+
+ case diParagraph:
+ mdi->member.para.pFmt = ALLOC_OBJ(PARAFORMAT2);
+ *mdi->member.para.pFmt = *item->member.para.pFmt;
+ mdi->member.para.next_para = 0;
+ if (mdi->member.para.pCell)
+ mdi->member.para.pCell = *pPrevCell;
+ /* fall-through */
+ case diTextEnd:
+ /* Make sure the paragraphs are linked up within duplicated text */
+ mdi->member.para.next_para = NULL;
+ mdi->member.para.prev_para = *pPrevPara;
+ if (*pPrevPara)
+ (*pPrevPara)->member.para.next_para = mdi;
+ *pPrevPara = mdi;
+ break;
+
+ case diRun:
+ /* 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 (item->member.run.ole_obj)
+ {
+ mdi->member.run.ole_obj = ALLOC_OBJ(*item->member.run.ole_obj);
+ ME_CopyReObject(mdi->member.run.ole_obj, item->member.run.ole_obj);
+ }
+ break;
+
+ default:
+ 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();
+ ME_DisplayItem *prev_cell = NULL;
+ ME_DisplayItem *prev_para = NULL;
+
+ pNow = ME_DuplicateDisplayItem(pFirst, NULL, m, &prev_cell, &prev_para);
+ *ppNew = pNow;
+ while (pFirst != pLast)
+ {
+ pFirst = pFirst->next;
+ pNow = ME_DuplicateDisplayItem(pFirst, pNow, m, &prev_cell, &prev_para);
+ *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 e17c2bd..6b22722 100644
--- a/dlls/riched20/paint.c
+++ b/dlls/riched20/paint.c
@@ -72,6 +72,157 @@ int ME_twips2pointsY(ME_Context *c, int y)
return y;
}
+LPARAM ME_FormatContent(ME_TextEditor *editor, FORMATRANGE *pfr, BOOL bDraw)
+{
+ ME_Context c;
+ ME_DisplayItem *pFirst;
+ ME_DisplayItem *pLast;
+ ME_DisplayItem *pNow;
+ ME_DisplayItem *pIntra;
+ int cyRow;
+ int cyOffset = -1;
+ int iEndOffset = -1;
+ int textlength = ME_GetTextLength(editor);
+ int targetBottom, numCharPrintable = 0;
+
+ if (!pfr || pfr->chrg.cpMin >= textlength)
+ return textlength;
+
+ ME_InitContext(&c, editor, pfr->hdc, pfr->hdcTarget);
+ c.bHideSelection = TRUE;
+ c.bClip = TRUE;
+ c.bWordWrap = TRUE;
+ c.nZoomNumerator = 0;
+ c.nZoomDenominator = 0;
+
+ c.rcView.left = ME_twips2targetX(&c, pfr->rc.left);
+ c.rcView.right = ME_twips2targetX(&c, pfr->rc.right);
+ c.rcView.top = ME_twips2targetY(&c, pfr->rc.top);
+ c.rcView.bottom = ME_twips2targetY(&c, pfr->rc.bottom);
+ c.nAvailWidth = c.rcView.right - c.rcView.left;
+ numCharPrintable = c.nAvailWidth / (1440/c.dpiTarget.cy);
+
+ targetBottom = c.rcView.bottom;
+
+ 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)
+ {
+ int local_pt_y = pNow->member.para.pt.y = c.pt.y;
+ pNow->member.para.nFlags |= MEPF_REWRAP;
+ ME_WrapTextParagraph(&c, pNow);
+ if (iEndOffset == -1)
+ {
+ 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 = pNow->member.para.nCharOfs + pIntra->member.run.nCharOfs;
+ int iRunEndOfs = iRunOfs + (pIntra->member.run.strText ?
+ pIntra->member.run.strText->nLen : 1);
+ if (cyOffset == -1 && iRunEndOfs > pfr->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;
+ targetBottom = local_pt_y - cyOffset;
+ break;
+ }
+ if (pfr->chrg.cpMax >= 0 &&
+ iRunEndOfs > pfr->chrg.cpMax)
+ {
+ int iBottom = local_pt_y + cyRow - cyOffset + c.rcView.top;
+ targetBottom = local_pt_y + cyRow - cyOffset;
+
+ if (c.rcView.bottom > iBottom)
+ c.rcView.bottom = iBottom;
+ iEndOffset = iRunOfs;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (iEndOffset == -1)
+ {
+ iEndOffset = numCharPrintable + 1;
+ targetBottom = c.pt.y - cyOffset;
+ }
+ pfr->rc.bottom = (LONGLONG)targetBottom * 1440 / c.dpiTarget.cy + pfr->rc.top;
+ c.rcView.bottom = targetBottom + c.rcView.top;
+
+ /* Then draw the data */
+
+ if (bDraw)
+ {
+ HRGN oldRgn;
+ int iBGMode = SetBkMode(c.hDC, TRANSPARENT);
+ int savedTotalWidth = editor->nTotalWidth;
+ editor->nTotalWidth = c.rcView.right - c.rcView.left;
+
+ oldRgn = CreateRectRgn(0, 0, 0, 0);
+ if (!GetClipRgn(c.hDC, oldRgn))
+ {
+ DeleteObject(oldRgn);
+ oldRgn = NULL;
+ }
+ IntersectClipRect(c.hDC,
+ ME_twips2pointsX(&c, pfr->rcPage.left),
+ ME_twips2pointsY(&c, pfr->rc.top),
+ ME_twips2pointsX(&c, pfr->rcPage.right),
+ ME_target2pointsY(&c, c.rcView.bottom));
+
+ c.pt.x = ME_twips2targetX(&c, pfr->rc.left);
+ c.pt.y = ME_twips2targetY(&c, pfr->rc.top) - cyOffset;
+
+ for (pNow = pFirst->next; pNow != pLast; pNow = pNow->member.para.next_para)
+ {
+ int y = c.pt.y + pNow->member.para.pt.y;
+ if (y + pNow->member.para.nHeight > c.rcView.top &&
+ y < c.rcView.bottom)
+ ME_DrawParagraph(&c, pNow);
+ }
+ SelectClipRgn(c.hDC, oldRgn);
+ if (oldRgn)
+ DeleteObject(oldRgn);
+ SetBkMode(c.hDC, iBGMode);
+ editor->nTotalWidth = savedTotalWidth;
+ }
+
+ 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;
@@ -483,8 +634,9 @@ 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, !c->bHideSelection && runofs >= nSelFrom && runofs < nSelTo);
else
{
if (c->editor->cPasswordMask)
diff --git a/dlls/riched20/style.c b/dlls/riched20/style.c
index 7545b42..6247fc6 100644
--- a/dlls/riched20/style.c
+++ b/dlls/riched20/style.c
@@ -472,6 +472,52 @@ 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);
+ // Insert new style mapping at the front of the linked list.
+ tail->next = m->first;
+ m->first = tail;
+ 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 8aa1c39..ffc5822 100644
--- a/dlls/riched20/tests/editor.c
+++ b/dlls/riched20/tests/editor.c
@@ -4859,12 +4859,11 @@ static void test_EM_FORMATRANGE(void)
fr.hdc = fr.hdcTarget = hdc;
fr.rc.top = fr.rcPage.top = fr.rc.left = fr.rcPage.left = 0;
fr.rc.right = fr.rcPage.right = (stringsize.cx / 2) * tpp_x;
+ trace("%d is the value of stringsize.cx and %d is the right margin\n", stringsize.cx, fr.rc.right);
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
@@ -4872,13 +4871,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);
@@ -4886,18 +4881,18 @@ 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 */
+ /* Value returned by SendMessage should be equal to the length of the
+ original string when EM_FORMATRANGE is called with the lparam
+ variable is set to NULL or 0 even if fr.chrg.cpMin is set to the end
+ of the string */
r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, 0);
- todo_wine {
ok(r == len, "Expected %d, got %d\n", len, r);
- }
}
ReleaseDC(NULL, hdc);
--
1.6.6
--------------060706040408000303030306--
More information about the wine-patches
mailing list