Text streamout now honors CR and LF counters.
Tests to pin down required EM_STREAMOUT behavior.
editor->bEmulateVersion10 = TRUE;
editor->pBuffer->pLast->member.para.nCharOfs = 2;
+ assert(editor->pBuffer->pLast->prev->type == diRun);
+ assert(editor->pBuffer->pLast->prev->member.run.nFlags & MERF_ENDPARA);
+ editor->pBuffer->pLast->prev->member.run.nLF = 1;
}
return result;
}
run = ME_MakeRun(style, ME_MakeString(wszParagraphSign), MERF_ENDPARA);
run->member.run.nCharOfs = 0;
+ run->member.run.nCR = 1;
+ run->member.run.nLF = (editor->bEmulateVersion10) ? 1 : 0;
ME_InsertBefore(text->pLast, para);
ME_InsertBefore(text->pLast, run);
p->member.run.nFlags,
p->member.run.style->fmt.dwMask & p->member.run.style->fmt.dwEffects);
assert(ofs == p->member.run.nCharOfs);
- if (p->member.run.nFlags & MERF_ENDPARA)
- ofs += (editor->bEmulateVersion10 ? 2 : 1);
+ if (p->member.run.nFlags & MERF_ENDPARA) {
+ assert(p->member.run.nCR + p->member.run.nLF > 0);
+ ofs += p->member.run.nCR + p->member.run.nLF;
+ }
else
ofs += ME_StrLen(p->member.run.strText);
break;
}
*ppRun = pNext;
}
- /* the handling of bEmulateVersion10 may be a source of many bugs, I'm afraid */
- eollen = (editor->bEmulateVersion10 ? 2 : 1);
+ /* Recover proper character length of this line break */
+ eollen = (*ppRun)->member.run.nCR + (*ppRun)->member.run.nLF;
if (nCharOfs >= nParaOfs + (*ppRun)->member.run.nCharOfs &&
nCharOfs < nParaOfs + (*ppRun)->member.run.nCharOfs + eollen) {
+ /* FIXME: Might cause problems when actually requiring an offset in the
+ middle of a run that is considered a single line break */
*pOfs = 0;
return;
}
DestroyWindow(hwndRichEdit);
}
+static void test_EM_STREAMOUT(void)
+{
+ HWND hwndRichEdit = new_richedit(NULL);
+ int r;
+ EDITSTREAM es;
+ char buf[1024] = {0};
+ char * p;
+
+ const char * TestItem1 = "TestSomeText";
+ const char * TestItem2 = "TestSomeText\r";
+ const char * TestItem3 = "TestSomeText\r\n";
+
+ SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem1);
+ p = buf;
+ es.dwCookie = (DWORD_PTR)&p;
+ es.dwError = 0;
+ es.pfnCallback = test_WM_SETTEXT_esCallback;
+ memset(buf, 0, sizeof(buf));
+ SendMessage(hwndRichEdit, EM_STREAMOUT,
+ (WPARAM)(SF_TEXT), (LPARAM)&es);
+ r = strlen(buf);
+ ok(r == 12, "streamed text length is %d, expecting 12\n", r);
+ ok(strcmp(buf, TestItem1) == 0,
+ "streamed text different, got %s\n", buf);
+
+ SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem2);
+ p = buf;
+ es.dwCookie = (DWORD_PTR)&p;
+ es.dwError = 0;
+ es.pfnCallback = test_WM_SETTEXT_esCallback;
+ memset(buf, 0, sizeof(buf));
+ SendMessage(hwndRichEdit, EM_STREAMOUT,
+ (WPARAM)(SF_TEXT), (LPARAM)&es);
+ r = strlen(buf);
+ /* Here again, \r gets converted to \r\n, like WM_GETTEXT */
+ ok(r == 14, "streamed text length is %d, expecting 14\n", r);
+ ok(strcmp(buf, TestItem3) == 0,
+ "streamed text different from, got %s\n", buf);
+ SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem3);
+ p = buf;
+ es.dwCookie = (DWORD_PTR)&p;
+ es.dwError = 0;
+ es.pfnCallback = test_WM_SETTEXT_esCallback;
+ memset(buf, 0, sizeof(buf));
+ SendMessage(hwndRichEdit, EM_STREAMOUT,
+ (WPARAM)(SF_TEXT), (LPARAM)&es);
+ r = strlen(buf);
+ ok(r == 14, "streamed text length is %d, expecting 14\n", r);
+ ok(strcmp(buf, TestItem3) == 0,
+ "streamed text different, got %s\n", buf);
+
+ DestroyWindow(hwndRichEdit);
+}
+
static void test_EM_SETTEXTEX(void)
{
HWND hwndRichEdit = new_richedit(NULL);
test_EM_EXSETSEL();
test_WM_PASTE();
test_EM_STREAMIN();
+ test_EM_STREAMOUT();
test_EM_StreamIn_Undo();
test_EM_FORMATRANGE();
test_unicode_conversions();
if (!ME_StreamOutPrint(pStream, "\r\n\\par"))
return FALSE;
}
- nChars--;
- if (editor->bEmulateVersion10 && nChars)
- nChars--;
+ /* Skip as many characters as required by current line break */
+ nChars -= (p->member.run.nCR <= nChars) ? p->member.run.nCR : nChars;
+ nChars -= (p->member.run.nLF <= nChars) ? p->member.run.nLF : nChars;
} else if (p->member.run.nFlags & MERF_ENDROW) {
if (!ME_StreamOutPrint(pStream, "\\line \r\n"))
return FALSE;
if (item->member.run.nFlags & MERF_ENDPARA) {
static const WCHAR szEOL[2] = { '\r', '\n' };
- if (dwFormat & SF_UNICODE)
- success = ME_StreamOutMove(pStream, (const char *)szEOL, sizeof(szEOL));
- else
- success = ME_StreamOutMove(pStream, "\r\n", 2);
+ if (!editor->bEmulateVersion10) {
+ /* richedit 2.0 - all line breaks are \r\n */
+ if (dwFormat & SF_UNICODE)
+ success = ME_StreamOutMove(pStream, (const char *)szEOL, sizeof(szEOL));
+ else
+ success = ME_StreamOutMove(pStream, "\r\n", 2);
+ assert(nLen == 1);
+ } else {
+ int i; int tnLen;
+
+ /* richedit 1.0 - need to honor actual \r and \n amounts */
+ nLen = item->member.run.nCR + item->member.run.nLF;
+ if (nLen > nChars)
+ nLen = nChars;
+ tnLen = nLen;
+
+ i = 0;
+ while (tnLen > 0 && i < item->member.run.nCR) {
+ if (dwFormat & SF_UNICODE)
+ success = ME_StreamOutMove(pStream, (const char *)(&szEOL[0]), sizeof(WCHAR));
+ else
+ success = ME_StreamOutMove(pStream, "\r", 1);
+ tnLen--; i++;
+ }
+ i = 0;
+ while (tnLen > 0 && i < item->member.run.nLF) {
+ if (dwFormat & SF_UNICODE)
+ success = ME_StreamOutMove(pStream, (const char *)(&szEOL[1]), sizeof(WCHAR));
+ else
+ success = ME_StreamOutMove(pStream, "\n", 1);
+ tnLen--; i++;
+ }
+ }
} else {
if (dwFormat & SF_UNICODE)
success = ME_StreamOutMove(pStream, (const char *)(item->member.run.strText->szData + nStart),
}
nChars -= nLen;
- if (editor->bEmulateVersion10 && nChars && item->member.run.nFlags & MERF_ENDPARA)
- nChars--;
nStart = 0;
item = ME_FindItemFwd(item, diRun);
}
DestroyWindow(hwndRichEdit);
}
+static DWORD CALLBACK test_WM_SETTEXT_esCallback(DWORD_PTR dwCookie,
+ LPBYTE pbBuff,
+ LONG cb,
+ LONG *pcb)
+{
+ char** str = (char**)dwCookie;
+ *pcb = cb;
+ if (*pcb > 0) {
+ memcpy(*str, pbBuff, *pcb);
+ *str += *pcb;
+ }
+ return 0;
+}
+
+static void test_EM_STREAMOUT(void)
+{
+ HWND hwndRichEdit = new_richedit(NULL);
+ int r;
+ EDITSTREAM es;
+ char buf[1024] = {0};
+ char * p;
+
+ const char * TestItem1 = "TestSomeText";
+ const char * TestItem2 = "TestSomeText\r";
+ const char * TestItem3 = "TestSomeText\r\n";
+
+ SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem1);
+ p = buf;
+ es.dwCookie = (DWORD_PTR)&p;
+ es.dwError = 0;
+ es.pfnCallback = test_WM_SETTEXT_esCallback;
+ memset(buf, 0, sizeof(buf));
+ SendMessage(hwndRichEdit, EM_STREAMOUT,
+ (WPARAM)(SF_TEXT), (LPARAM)&es);
+ r = strlen(buf);
+ ok(r == 12, "streamed text length is %d, expecting 12\n", r);
+ ok(strcmp(buf, TestItem1) == 0,
+ "streamed text different, got %s\n", buf);
+
+ SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem2);
+ p = buf;
+ es.dwCookie = (DWORD_PTR)&p;
+ es.dwError = 0;
+ es.pfnCallback = test_WM_SETTEXT_esCallback;
+ memset(buf, 0, sizeof(buf));
+ SendMessage(hwndRichEdit, EM_STREAMOUT,
+ (WPARAM)(SF_TEXT), (LPARAM)&es);
+ r = strlen(buf);
+ todo_wine { /* Currently fails because of solitary \r mangling */
+ ok(r == 13, "streamed text length is %d, expecting 13\n", r);
+ ok(strcmp(buf, TestItem2) == 0,
+ "streamed text different, got %s\n", buf);
+ }
+ SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem3);
+ p = buf;
+ es.dwCookie = (DWORD_PTR)&p;
+ es.dwError = 0;
+ es.pfnCallback = test_WM_SETTEXT_esCallback;
+ memset(buf, 0, sizeof(buf));
+ SendMessage(hwndRichEdit, EM_STREAMOUT,
+ (WPARAM)(SF_TEXT), (LPARAM)&es);
+ r = strlen(buf);
+ ok(r == 14, "streamed text length is %d, expecting 14\n", r);
+ ok(strcmp(buf, TestItem3) == 0,
+ "streamed text different, got %s\n", buf);
+
+ DestroyWindow(hwndRichEdit);
+}
START_TEST( editor )
{
test_WM_SETTEXT();
test_WM_GETTEXTLENGTH();
test_EM_STREAMIN();
+ test_EM_STREAMOUT();
/* Set the environment variable WINETEST_RICHED32 to keep windows
* responsive and open for 30 seconds. This is useful for debugging.