Sync riched20 to Wine 1.0-rc1

Samuel Serapión got some apps like 7-Zip and PowerISO installed with the new version.

svn path=/trunk/; revision=33419
This commit is contained in:
Colin Finck 2008-05-10 19:50:28 +00:00
parent 620f89d44b
commit 32a2579694
13 changed files with 417 additions and 168 deletions

View file

@ -57,7 +57,9 @@ int ME_GetTextLengthEx(ME_TextEditor *editor, const GETTEXTLENGTHEX *how)
length = ME_GetTextLength(editor);
if ((GetWindowLongW(editor->hWnd, GWL_STYLE) & ES_MULTILINE) && (how->flags & GTL_USECRLF))
if ((GetWindowLongW(editor->hWnd, GWL_STYLE) & ES_MULTILINE)
&& (how->flags & GTL_USECRLF)
&& !editor->bEmulateVersion10) /* Ignore GTL_USECRLF flag in 1.0 emulation */
length += editor->nParagraphs - 1;
if (how->flags & GTL_NUMBYTES)
@ -270,6 +272,8 @@ void ME_InternalDeleteText(ME_TextEditor *editor, int nOfs,
ME_CursorFromCharOfs(editor, nOfs, &c);
run = &c.pRun->member.run;
if (run->nFlags & MERF_ENDPARA) {
int eollen = run->nCR + run->nLF;
if (!ME_FindItemFwd(c.pRun, diParagraph))
{
return;
@ -277,9 +281,7 @@ void ME_InternalDeleteText(ME_TextEditor *editor, int nOfs,
ME_JoinParagraphs(editor, ME_GetParagraph(c.pRun));
/* ME_SkipAndPropagateCharOffset(p->pRun, shift); */
ME_CheckCharOffsets(editor);
nChars--;
if (editor->bEmulateVersion10 && nChars)
nChars--;
nChars -= (eollen < nChars) ? eollen : nChars;
continue;
}
else
@ -522,6 +524,8 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
if (pos-str < len) { /* handle EOLs */
ME_DisplayItem *tp, *end_run;
ME_Style *tmp_style;
int numCR, numLF;
if (pos!=str)
ME_InternalInsertTextFromCursor(editor, nCursor, str, pos-str, style, 0);
p = &editor->pCursors[nCursor];
@ -531,16 +535,48 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
}
tmp_style = ME_GetInsertStyle(editor, nCursor);
/* ME_SplitParagraph increases style refcount */
tp = ME_SplitParagraph(editor, p->pRun, p->pRun->member.run.style);
/* Encode and fill number of CR and LF according to emulation mode */
if (editor->bEmulateVersion10) {
const WCHAR * tpos;
/* We have to find out how many consecutive \r are there, and if there
is a \n terminating the run of \r's. */
numCR = 0; numLF = 0;
tpos = pos;
while (tpos-str < len && *tpos == '\r') {
tpos++;
numCR++;
}
if (tpos-str >= len) {
/* Reached end of text without finding anything but '\r' */
if (tpos != pos) {
pos++;
}
numCR = 1; numLF = 0;
} else if (*tpos == '\n') {
/* The entire run of \r's plus the one \n is one single line break */
pos = tpos + 1;
numLF = 1;
} else {
/* Found some other content past the run of \r's */
pos++;
numCR = 1; numLF = 0;
}
} else {
if(pos-str < len && *pos =='\r')
pos++;
if(pos-str < len && *pos =='\n')
pos++;
numCR = 1; numLF = 0;
}
tp = ME_SplitParagraph(editor, p->pRun, p->pRun->member.run.style, numCR, numLF);
p->pRun = ME_FindItemFwd(tp, diRun);
end_run = ME_FindItemBack(tp, diRun);
ME_ReleaseStyle(end_run->member.run.style);
end_run->member.run.style = tmp_style;
p->nOffset = 0;
if(pos-str < len && *pos =='\r')
pos++;
if(pos-str < len && *pos =='\n')
pos++;
if(pos-str <= len) {
len -= pos - str;
str = pos;
@ -1294,7 +1330,15 @@ void ME_SendSelChange(ME_TextEditor *editor)
sc.seltyp |= SEL_TEXT;
if (sc.chrg.cpMin < sc.chrg.cpMax+1) /* wth were RICHEDIT authors thinking ? */
sc.seltyp |= SEL_MULTICHAR;
SendMessageW(GetParent(editor->hWnd), WM_NOTIFY, sc.nmhdr.idFrom, (LPARAM)&sc);
TRACE("cpMin=%d cpMax=%d seltyp=%d (%s %s)\n",
sc.chrg.cpMin, sc.chrg.cpMax, sc.seltyp,
(sc.seltyp & SEL_TEXT) ? "SEL_TEXT" : "",
(sc.seltyp & SEL_MULTICHAR) ? "SEL_MULTICHAR" : "");
if (sc.chrg.cpMin != editor->notified_cr.cpMin || sc.chrg.cpMax != editor->notified_cr.cpMax)
{
editor->notified_cr = sc.chrg;
SendMessageW(GetParent(editor->hWnd), WM_NOTIFY, sc.nmhdr.idFrom, (LPARAM)&sc);
}
}
BOOL

View file

@ -115,7 +115,7 @@
+ EM_SETSCROLLPOS 3.0
- EM_SETTABSTOPS 3.0
- EM_SETTARGETDEVICE (partial)
+ EM_SETTEXTEX 3.0 (no rich text insertion handling, proper style?)
+ EM_SETTEXTEX 3.0 (proper style?)
- EM_SETTEXTMODE 2.0
- EM_SETTYPOGRAPHYOPTIONS 3.0
+ EM_SETUNDOLIMIT 2.0
@ -620,31 +620,31 @@ static void ME_RTFParAttrHook(RTF_Info *info)
case rtfBorderSingle:
ME_GetSelectionParaFormat(info->editor, &fmt);
/* we assume that borders have been created before (RTF spec) */
fmt.wBorders &= ~0x70;
fmt.wBorders &= ~0x700;
fmt.wBorders |= 1 << 8;
break;
case rtfBorderThick:
ME_GetSelectionParaFormat(info->editor, &fmt);
/* we assume that borders have been created before (RTF spec) */
fmt.wBorders &= ~0x70;
fmt.wBorders &= ~0x700;
fmt.wBorders |= 2 << 8;
break;
case rtfBorderShadow:
ME_GetSelectionParaFormat(info->editor, &fmt);
/* we assume that borders have been created before (RTF spec) */
fmt.wBorders &= ~0x70;
fmt.wBorders &= ~0x700;
fmt.wBorders |= 10 << 8;
break;
case rtfBorderDouble:
ME_GetSelectionParaFormat(info->editor, &fmt);
/* we assume that borders have been created before (RTF spec) */
fmt.wBorders &= ~0x70;
fmt.wBorders &= ~0x700;
fmt.wBorders |= 7 << 8;
break;
case rtfBorderDot:
ME_GetSelectionParaFormat(info->editor, &fmt);
/* we assume that borders have been created before (RTF spec) */
fmt.wBorders &= ~0x70;
fmt.wBorders &= ~0x700;
fmt.wBorders |= 11 << 8;
break;
case rtfBorderWidth:
@ -1022,13 +1022,14 @@ ME_StreamInFill(ME_InStream *stream)
stream->dwUsed = 0;
}
static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stream)
static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stream, BOOL stripLastCR)
{
RTF_Info parser;
ME_Style *style;
int from, to, to2, nUndoMode;
int nEventMask = editor->nEventMask;
ME_InStream inStream;
BOOL invalidRTF = FALSE;
TRACE("stream==%p hWnd==%p format==0x%X\n", stream, editor->hWnd, format);
editor->nEventMask = 0;
@ -1068,15 +1069,16 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre
ME_StreamInFill(&inStream);
if (!inStream.editstream->dwError)
{
if (strncmp(inStream.buffer, "{\\rtf", 5) && strncmp(inStream.buffer, "{\\urtf", 6))
if ((!editor->bEmulateVersion10 && strncmp(inStream.buffer, "{\\rtf", 5) && strncmp(inStream.buffer, "{\\urtf", 6))
|| (editor->bEmulateVersion10 && *inStream.buffer != '{'))
{
format &= ~SF_RTF;
format |= SF_TEXT;
invalidRTF = TRUE;
inStream.editstream->dwError = -16;
}
}
}
if (!inStream.editstream->dwError)
if (!invalidRTF && !inStream.editstream->dwError)
{
if (format & SF_RTF) {
/* setup the RTF parser */
@ -1100,6 +1102,24 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre
if (parser.lpRichEditOle)
IRichEditOle_Release(parser.lpRichEditOle);
/* 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);
if (newto > to + (editor->bEmulateVersion10 ? 1 : 0)) {
WCHAR lastchar[3] = {'\0', '\0'};
int linebreakSize = editor->bEmulateVersion10 ? 2 : 1;
ME_GetTextW(editor, lastchar, newto - linebreakSize, linebreakSize, 0);
if (lastchar[0] == '\r' && (lastchar[1] == '\n' || lastchar[1] == '\0')) {
ME_InternalDeleteText(editor, newto - linebreakSize, linebreakSize);
}
}
}
style = parser.style;
}
else if (format & SF_TEXT)
@ -1124,10 +1144,7 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre
ME_ReleaseStyle(style);
editor->nEventMask = nEventMask;
if (editor->bRedraw)
{
ME_UpdateRepaint(editor);
}
ME_UpdateRepaint(editor);
if (!(format & SFF_SELECTION)) {
ME_ClearTempStyle(editor);
}
@ -1169,7 +1186,7 @@ ME_StreamInRTFString(ME_TextEditor *editor, BOOL selection, char *string)
data.pos = 0;
es.dwCookie = (DWORD)&data;
es.pfnCallback = ME_ReadFromRTFString;
ME_StreamIn(editor, SF_RTF | (selection ? SFF_SELECTION : 0), &es);
ME_StreamIn(editor, SF_RTF | (selection ? SFF_SELECTION : 0), &es, FALSE);
}
@ -1177,6 +1194,7 @@ ME_DisplayItem *
ME_FindItemAtOffset(ME_TextEditor *editor, ME_DIType nItemType, int nOffset, int *nItemOffset)
{
ME_DisplayItem *item = ME_FindItemFwd(editor->pBuffer->pFirst, diParagraph);
int runLength;
while (item && item->member.para.next_para->member.para.nCharOfs <= nOffset)
item = ME_FindItemFwd(item, diParagraph);
@ -1193,9 +1211,27 @@ ME_FindItemAtOffset(ME_TextEditor *editor, ME_DIType nItemType, int nOffset, int
do {
item = ME_FindItemFwd(item, diRun);
} while (item && (item->member.run.nCharOfs + ME_StrLen(item->member.run.strText) <= nOffset));
runLength = ME_StrLen(item->member.run.strText);
if (item->member.run.nFlags & MERF_ENDPARA)
runLength = item->member.run.nCR + item->member.run.nLF;
} while (item && (item->member.run.nCharOfs + runLength <= nOffset));
if (item) {
nOffset -= item->member.run.nCharOfs;
/* Special case: nOffset may not point exactly at the division between the
\r and the \n in 1.0 emulation. If such a case happens, it is sent
into the next run, if one exists
*/
if ( item->member.run.nFlags & MERF_ENDPARA
&& nOffset == item->member.run.nCR
&& item->member.run.nLF > 0) {
ME_DisplayItem *nextItem;
nextItem = ME_FindItemFwd(item, diRun);
if (nextItem) {
nOffset = 0;
item = nextItem;
}
}
if (nItemOffset)
*nItemOffset = nOffset;
}
@ -1227,12 +1263,29 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH
else
nMax = chrg->cpMax > nTextLen ? nTextLen : chrg->cpMax;
/* In 1.0 emulation, if cpMax reaches end of text, add the FR_DOWN flag */
if (editor->bEmulateVersion10 && nMax == nTextLen)
{
flags |= FR_DOWN;
}
/* In 1.0 emulation, cpMin must always be no greater than cpMax */
if (editor->bEmulateVersion10 && nMax < nMin)
{
if (chrgText)
{
chrgText->cpMin = -1;
chrgText->cpMax = -1;
}
return -1;
}
/* when searching up, if cpMin < cpMax, then instead of searching
* on [cpMin,cpMax], we search on [0,cpMin], otherwise, search on
* [cpMax, cpMin]. The exception is when cpMax is -1, in which
* case, it is always bigger than cpMin.
*/
if (!(flags & FR_DOWN))
if (!editor->bEmulateVersion10 && !(flags & FR_DOWN))
{
int nSwap = nMax;
@ -1630,6 +1683,8 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) {
else
ed->cPasswordMask = 0;
ed->notified_cr.cpMin = ed->notified_cr.cpMax = 0;
return ed;
}
@ -1922,7 +1977,7 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
/* Messages specific to Richedit controls */
case EM_STREAMIN:
return ME_StreamIn(editor, wParam, (EDITSTREAM*)lParam);
return ME_StreamIn(editor, wParam, (EDITSTREAM*)lParam, TRUE);
case EM_STREAMOUT:
return ME_StreamOut(editor, wParam, (EDITSTREAM *)lParam);
case WM_GETDLGCODE:
@ -2117,17 +2172,20 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
wszText = lParam ? ME_ToUnicode(pStruct->codepage == 1200, (void *)lParam) : NULL;
len = wszText ? lstrlenW(wszText) : 0;
/* FIXME: this should support RTF strings too, according to MSDN */
if (pStruct->flags & ST_SELECTION) {
ME_GetSelection(editor, &from, &to);
style = ME_GetSelectionInsertStyle(editor);
ME_InternalDeleteText(editor, from, to - from);
ME_InsertTextFromCursor(editor, 0, wszText, len, style);
if (pStruct->codepage != 1200 && lParam && !strncmp((char *)lParam, "{\\rtf", 5))
ME_StreamInRTFString(editor, 0, (char *)lParam);
else ME_InsertTextFromCursor(editor, 0, wszText, len, style);
ME_ReleaseStyle(style);
}
else {
ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor));
ME_InsertTextFromCursor(editor, 0, wszText, len, editor->pBuffer->pDefaultStyle);
if (pStruct->codepage != 1200 && lParam && !strncmp((char *)lParam, "{\\rtf", 5))
ME_StreamInRTFString(editor, 0, (char *)lParam);
else ME_InsertTextFromCursor(editor, 0, wszText, len, editor->pBuffer->pDefaultStyle);
len = 1;
}
ME_CommitUndo(editor);
@ -2166,7 +2224,7 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
return lColor;
}
case EM_GETMODIFY:
return editor->nModifyStep == 0 ? 0 : 1;
return editor->nModifyStep == 0 ? 0 : -1;
case EM_SETMODIFY:
{
if (wParam)
@ -2209,8 +2267,10 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
} else if (wParam == SCF_ALL) {
if (editor->mode & TM_PLAINTEXT)
ME_SetDefaultCharFormat(editor, p);
else
else {
ME_SetCharFormat(editor, 0, ME_GetTextLength(editor), p);
editor->nModifyStep = 1;
}
} else if (editor->mode & TM_PLAINTEXT) {
return 0;
} else {
@ -2218,8 +2278,8 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
ME_GetSelection(editor, &from, &to);
bRepaint = (from != to);
ME_SetSelectionCharFormat(editor, p);
if (from != to) editor->nModifyStep = 1;
}
editor->nModifyStep = 1;
ME_CommitUndo(editor);
if (bRepaint)
ME_RewrapRepaint(editor);
@ -2394,10 +2454,10 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
}
else
TRACE("WM_SETTEXT - NULL\n");
ME_CommitUndo(editor);
ME_EmptyUndoStack(editor);
ME_SetSelection(editor, 0, 0);
editor->nModifyStep = 0;
ME_CommitUndo(editor);
ME_EmptyUndoStack(editor);
ME_UpdateRepaint(editor);
return 1;
}
@ -2431,7 +2491,7 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
gds.nLength = 0;
es.dwCookie = (DWORD)&gds;
es.pfnCallback = dwFormat == SF_RTF ? ME_ReadFromHGLOBALRTF : ME_ReadFromHGLOBALUnicode;
ME_StreamIn(editor, dwFormat|SFF_SELECTION, &es);
ME_StreamIn(editor, dwFormat|SFF_SELECTION, &es, FALSE);
CloseClipboard();
return 0;
@ -2467,6 +2527,7 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
{
GETTEXTLENGTHEX how;
/* CR/LF conversion required in 2.0 mode, verbatim in 1.0 mode */
how.flags = GTL_CLOSE | (editor->bEmulateVersion10 ? 0 : GTL_USECRLF) | GTL_NUMCHARS;
how.codepage = unicode ? 1200 : CP_ACP;
return ME_GetTextLengthEx(editor, &how);
@ -2532,7 +2593,10 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
else
{
/* potentially each char may be a CR, why calculate the exact value with O(N) when
we can just take a bigger buffer? :) */
we can just take a bigger buffer? :)
The above assumption still holds with CR/LF counters, since CR->CRLF expansion
occurs only in richedit 2.0 mode, in which line breaks have only one CR
*/
int crlfmul = (ex->flags & GT_USECRLF) ? 2 : 1;
LPWSTR buffer;
DWORD buflen = ex->cb;
@ -2574,12 +2638,12 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
rng->chrg.cpMin, rng->chrg.cpMax, unicode,
editor->bEmulateVersion10, ME_GetTextLength(editor));
if (unicode)
return ME_GetTextW(editor, rng->lpstrText, rng->chrg.cpMin, rng->chrg.cpMax-rng->chrg.cpMin, editor->bEmulateVersion10);
return ME_GetTextW(editor, rng->lpstrText, rng->chrg.cpMin, rng->chrg.cpMax-rng->chrg.cpMin, 0);
else
{
int nLen = rng->chrg.cpMax-rng->chrg.cpMin;
WCHAR *p = ALLOC_N_OBJ(WCHAR, nLen+1);
int nChars = ME_GetTextW(editor, p, rng->chrg.cpMin, nLen, editor->bEmulateVersion10);
int nChars = ME_GetTextW(editor, p, rng->chrg.cpMin, nLen, 0);
/* FIXME this is a potential security hole (buffer overrun)
if you know more about wchar->mbyte conversion please explain
*/
@ -2592,11 +2656,9 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
{
ME_DisplayItem *run;
const unsigned int nMaxChars = *(WORD *) lParam;
unsigned int nEndChars, nCharsLeft = nMaxChars;
unsigned int nCharsLeft = nMaxChars;
char *dest = (char *) lParam;
/* rich text editor 1.0 uses \r\n for line end, 2.0 uses just \r;
we need to know how if we have the extra \n or not */
int nLF = editor->bEmulateVersion10;
BOOL wroteNull = FALSE;
TRACE("EM_GETLINE: row=%d, nMaxChars=%d (%s)\n", (int) wParam, nMaxChars,
unicode ? "Unicode" : "Ansi");
@ -2624,36 +2686,68 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
nCharsLeft -= nCopy;
}
/* append \r\0 (or \r\n\0 in 1.0), space allowing */
nEndChars = min(nCharsLeft, 2 + nLF);
nCharsLeft -= nEndChars;
if (unicode)
/* append line termination, space allowing */
if (nCharsLeft > 0)
{
const WCHAR src[] = {'\r', '\0'};
const WCHAR src10[] = {'\r', '\n', '\0'};
lstrcpynW((LPWSTR) dest, nLF ? src10 : src, nEndChars);
if (run && (run->member.run.nFlags & MERF_ENDPARA))
{
unsigned int i;
/* Write as many \r as encoded in end-of-paragraph, space allowing */
for (i = 0; i < run->member.run.nCR && nCharsLeft > 0; i++, nCharsLeft--)
{
*((WCHAR *)dest) = '\r';
dest += unicode ? sizeof(WCHAR) : 1;
}
/* Write as many \n as encoded in end-of-paragraph, space allowing */
for (i = 0; i < run->member.run.nLF && nCharsLeft > 0; i++, nCharsLeft--)
{
*((WCHAR *)dest) = '\n';
dest += unicode ? sizeof(WCHAR) : 1;
}
}
if (nCharsLeft > 0)
{
if (unicode)
*((WCHAR *)dest) = '\0';
else
*dest = '\0';
nCharsLeft--;
wroteNull = TRUE;
}
}
else
lstrcpynA(dest, nLF ? "\r\n" : "\r", nEndChars);
TRACE("EM_GETLINE: got %u bytes\n", nMaxChars - nCharsLeft);
if (nEndChars == 2 + nLF)
return nMaxChars - nCharsLeft - 1; /* don't count \0 */
else
return nMaxChars - nCharsLeft;
TRACE("EM_GETLINE: got %u characters\n", nMaxChars - nCharsLeft);
return nMaxChars - nCharsLeft - (wroteNull ? 1 : 0);
}
case EM_GETLINECOUNT:
{
ME_DisplayItem *item = editor->pBuffer->pFirst->next;
int nRows = 0;
ME_DisplayItem *prev_para = NULL, *last_para = NULL;
while (item != editor->pBuffer->pLast)
{
assert(item->type == diParagraph);
prev_para = ME_FindItemBack(item, diRun);
if (prev_para) {
assert(prev_para->member.run.nFlags & MERF_ENDPARA);
}
nRows += item->member.para.nRows;
item = item->member.para.next_para;
}
last_para = ME_FindItemBack(item, diRun);
assert(last_para);
assert(last_para->member.run.nFlags & MERF_ENDPARA);
if (editor->bEmulateVersion10 && prev_para && last_para->member.run.nCharOfs == 0
&& prev_para->member.run.nCR == 1 && prev_para->member.run.nLF == 0)
{
/* In 1.0 emulation, the last solitary \r at the very end of the text
(if one exists) is NOT a line break.
FIXME: this is an ugly hack. This should have a more regular model. */
nRows--;
}
TRACE("EM_GETLINECOUNT: nRows==%d\n", nRows);
return max(1, nRows);
}
@ -2707,8 +2801,17 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
if (item_end->type == diStartRow)
nNextLineOfs = ME_CharOfsFromRunOfs(editor, ME_FindItemFwd(item_end, diRun), 0);
else
nNextLineOfs = ME_FindItemFwd(item, diParagraphOrEnd)->member.para.nCharOfs
- (editor->bEmulateVersion10?2:1);
{
ME_DisplayItem *endPara;
nNextLineOfs = ME_FindItemFwd(item, diParagraphOrEnd)->member.para.nCharOfs;
endPara = ME_FindItemFwd(item, diParagraphOrEnd);
endPara = ME_FindItemBack(endPara, diRun);
assert(endPara);
assert(endPara->type == diRun);
assert(endPara->member.run.nFlags & MERF_ENDPARA);
nNextLineOfs -= endPara->member.run.nCR + endPara->member.run.nLF;
}
nChars = nNextLineOfs - nThisLineOfs;
TRACE("EM_LINELENGTH(%ld)==%d\n",wParam, nChars);
return nChars;
@ -3207,7 +3310,12 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
case EM_SETTARGETDEVICE:
if (wParam == 0)
{
editor->bWordWrap = (lParam == 0);
BOOL new = (lParam == 0);
if (editor->bWordWrap != new)
{
editor->bWordWrap = new;
ME_RewrapRepaint(editor);
}
}
else FIXME("Unsupported yet non NULL device in EM_SETTARGETDEVICE\n");
break;
@ -3257,6 +3365,9 @@ LRESULT WINAPI RichEdit10ANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
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;
}
@ -3327,6 +3438,9 @@ int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, in
return 0;
}
/* bCRLF flag is only honored in 2.0 and up. 1.0 must always return text verbatim */
if (editor->bEmulateVersion10) bCRLF = 0;
if (nStart)
{
int nLen = ME_StrLen(item->member.run.strText) - nStart;
@ -3345,6 +3459,8 @@ int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, in
while(nChars && item)
{
int nLen = ME_StrLen(item->member.run.strText);
if (item->member.run.nFlags & MERF_ENDPARA)
nLen = item->member.run.nCR + item->member.run.nLF;
if (nLen > nChars)
nLen = nChars;
@ -3357,16 +3473,30 @@ int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, in
nLen = 0;
nChars = 0;
} else {
*buffer = '\r';
if (bCRLF)
{
*(++buffer) = '\n';
/* richedit 2.0 case - actual line-break is \r but should report \r\n */
assert(nLen == 1);
*buffer++ = '\r';
*buffer = '\n'; /* Later updated by nLen==1 at the end of the loop */
nWritten++;
}
assert(nLen == 1);
/* our end paragraph consists of 2 characters now */
if (editor->bEmulateVersion10)
nChars--;
else
{
int i, j;
/* richedit 2.0 verbatim has only \r. richedit 1.0 should honor encodings */
i = 0;
while (nChars - i > 0 && i < item->member.run.nCR)
{
buffer[i] = '\r'; i++;
}
j = 0;
while (nChars - i - j > 0 && j < item->member.run.nLF)
{
buffer[i+j] = '\n'; j++;
}
}
}
}
else
@ -3522,7 +3652,6 @@ int ME_AutoURLDetect(ME_TextEditor *editor, WCHAR curChar)
int car_pos = 0;
int text_pos=-1;
int URLmin, URLmax = 0;
CHARRANGE url;
FINDTEXTA ft;
CHARFORMAT2W cur_format;
CHARFORMAT2W default_format;
@ -3576,8 +3705,6 @@ int ME_AutoURLDetect(ME_TextEditor *editor, WCHAR curChar)
}
if (text_pos != -1)
{
url.cpMin=text_pos;
url.cpMax=car_pos-1;
ME_SetCharFormat(editor, text_pos, (URLmax-text_pos), &link);
ME_RewrapRepaint(editor);
break;

View file

@ -189,9 +189,6 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
void ME_InsertEndRowFromCursor(ME_TextEditor *editor, int nCursor);
BOOL ME_ArrowKey(ME_TextEditor *ed, int nVKey, BOOL extend, BOOL ctrl);
void ME_InitContext(ME_Context *c, ME_TextEditor *editor, HDC hDC);
void ME_DestroyContext(ME_Context *c, HWND release);
ME_Style *GetInsertStyle(ME_TextEditor *editor, int nCursor);
void ME_MustBeWrapped(ME_Context *c, ME_DisplayItem *para);
void ME_GetCursorCoordinates(ME_TextEditor *editor, ME_Cursor *pCursor,
int *x, int *y, int *height);
@ -209,6 +206,10 @@ int ME_GetTextLengthEx(ME_TextEditor *editor, const GETTEXTLENGTHEX *how);
ME_Style *ME_GetSelectionInsertStyle(ME_TextEditor *editor);
BOOL ME_UpdateSelection(ME_TextEditor *editor, const ME_Cursor *pTempCursor);
/* context.c */
void ME_InitContext(ME_Context *c, ME_TextEditor *editor, HDC hDC);
void ME_DestroyContext(ME_Context *c, HWND release);
/* wrap.c */
BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor);
void ME_InvalidateMarkedParagraphs(ME_TextEditor *editor);
@ -220,7 +221,7 @@ int ME_twips2pointsY(ME_Context *c, int y);
ME_DisplayItem *ME_GetParagraph(ME_DisplayItem *run);
void ME_GetSelectionParas(ME_TextEditor *editor, ME_DisplayItem **para, ME_DisplayItem **para_end);
void ME_MakeFirstParagraph(ME_TextEditor *editor);
ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *rp, ME_Style *style);
ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *rp, ME_Style *style, int numCR, int numLF);
ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp);
void ME_DumpParaStyle(ME_Paragraph *s);
void ME_DumpParaStyleToBuf(const PARAFORMAT2 *pFmt, char buf[2048]);
@ -272,11 +273,6 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd);
void ME_DestroyEditor(ME_TextEditor *editor);
void ME_SendOldNotify(ME_TextEditor *editor, int nCode);
void ME_LinkNotify(ME_TextEditor *editor, UINT msg, WPARAM wParam, LPARAM lParam);
ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, const ME_DisplayItem *pdi);
void ME_CommitUndo(ME_TextEditor *editor);
void ME_Undo(ME_TextEditor *editor);
void ME_Redo(ME_TextEditor *editor);
void ME_EmptyUndoStack(ME_TextEditor *editor);
int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, BOOL bCRLF);
ME_DisplayItem *ME_FindItemAtOffset(ME_TextEditor *editor, ME_DIType nItemType, int nOffset, int *nItemOffset);
void ME_StreamInFill(ME_InStream *stream);
@ -284,6 +280,13 @@ int ME_AutoURLDetect(ME_TextEditor *editor, WCHAR curChar);
extern int me_debug;
extern void DoWrap(ME_TextEditor *editor);
/* undo.c */
ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, const ME_DisplayItem *pdi);
void ME_CommitUndo(ME_TextEditor *editor);
void ME_Undo(ME_TextEditor *editor);
void 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_StreamOut(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM *stream);

View file

@ -148,6 +148,7 @@ typedef struct tagME_Run
POINT pt; /* relative to para's position */
struct tagME_TableCell *pCell; /* for MERF_CELL: points to respective cell in ME_Paragraph */
REOBJECT *ole_obj; /* FIXME: should be a union with strText (at least) */
int nCR; int nLF; /* for MERF_ENDPARA: number of \r and \n characters encoded by run */
} ME_Run;
typedef struct tagME_Document {
@ -217,6 +218,7 @@ typedef struct tagME_UndoItem
{
ME_DisplayItem di;
int nStart, nLen;
int nCR, nLF; /* used by diUndoSplitParagraph */
} ME_UndoItem;
typedef struct tagME_TextBuffer
@ -329,6 +331,9 @@ typedef struct tagME_TextEditor
/*for IME */
int imeStartIndex;
DWORD selofs, linesel, sely;
/* Track previous notified selection */
CHARRANGE notified_cr;
} ME_TextEditor;
typedef struct tagME_Context

View file

@ -200,6 +200,8 @@ void ME_DumpDocument(ME_TextBuffer *buffer)
case diRun:
TRACE(" - Run(\"%s\", %d)\n", debugstr_w(pItem->member.run.strText->szData),
pItem->member.run.nCharOfs);
if (pItem->member.run.nFlags & MERF_ENDPARA)
TRACE(" - Paragraph end: %d CR, %d LF\n", pItem->member.run.nCR, pItem->member.run.nLF);
break;
case diTextEnd:
TRACE("End(ofs=%d)\n", pItem->member.para.nCharOfs);

View file

@ -43,8 +43,7 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, const RECT *
{
BOOL bPaint = (rcUpdate == NULL);
if (rcUpdate)
bPaint = c.pt.y<rcUpdate->bottom &&
c.pt.y+item->member.para.nHeight>rcUpdate->top;
bPaint = c.pt.y<rcUpdate->bottom && ye>rcUpdate->top;
if (bPaint)
{
ME_DrawParagraph(&c, item);
@ -85,8 +84,6 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, const RECT *
rc.bottom = ye;
FillRect(hDC, &rc, c.editor->hbrBackground);
}
if (ys == c.pt.y) /* don't overwrite the top bar */
ys++;
}
if (editor->nTotalLength != editor->nLastTotalLength)
ME_SendRequestResize(editor, FALSE);
@ -109,9 +106,11 @@ void ME_UpdateRepaint(ME_TextEditor *editor)
{
/* Should be called whenever the contents of the control have changed */
ME_Cursor *pCursor;
BOOL wrappedParagraphs;
wrappedParagraphs = ME_WrapMarkedParagraphs(editor);
if (!editor->bRedraw) return;
if (ME_WrapMarkedParagraphs(editor))
if (wrappedParagraphs)
ME_UpdateScrollBar(editor);
/* Ensure that the cursor is visible */
@ -371,47 +370,51 @@ int ME_GetParaLineSpace(ME_Context* c, ME_Paragraph* para)
return sp * c->editor->nZoomNumerator / c->editor->nZoomDenominator;
}
static int ME_DrawParaDecoration(ME_Context* c, ME_Paragraph* para, int y)
static void ME_DrawParaDecoration(ME_Context* c, ME_Paragraph* para, int y, RECT* bounds)
{
int idx, border_width;
int ybefore, yafter;
int idx, border_width, top_border, bottom_border;
RECT rc;
if (!(para->pFmt->dwMask & (PFM_BORDER | PFM_SPACEBEFORE | PFM_SPACEAFTER))) return 0;
SetRectEmpty(bounds);
if (!(para->pFmt->dwMask & (PFM_BORDER | PFM_SPACEBEFORE | PFM_SPACEAFTER))) return;
border_width = top_border = bottom_border = 0;
idx = (para->pFmt->wBorders >> 8) & 0xF;
if ((para->pFmt->dwMask & PFM_BORDER) && idx != 0 && (para->pFmt->wBorders & 0xF))
{
if (para->pFmt->wBorders & 0x00B0)
FIXME("Unsupported border flags %x\n", para->pFmt->wBorders);
border_width = ME_GetParaBorderWidth(c->editor, para->pFmt->wBorders);
if (para->pFmt->wBorders & 4) top_border = border_width;
if (para->pFmt->wBorders & 8) bottom_border = border_width;
}
if (para->pFmt->dwMask & PFM_SPACEBEFORE)
{
rc.left = c->rcView.left;
rc.right = c->rcView.right;
rc.top = y;
ybefore = ME_twips2pointsY(c, para->pFmt->dySpaceBefore);
rc.bottom = y + ybefore;
bounds->top = ME_twips2pointsY(c, para->pFmt->dySpaceBefore);
rc.bottom = y + bounds->top + top_border;
FillRect(c->hDC, &rc, c->editor->hbrBackground);
}
else ybefore = 0;
if (para->pFmt->dwMask & PFM_SPACEAFTER)
{
rc.left = c->rcView.left;
rc.right = c->rcView.right;
rc.bottom = y + para->nHeight;
yafter = ME_twips2pointsY(c, para->pFmt->dySpaceAfter);
rc.top = rc.bottom - yafter;
bounds->bottom = ME_twips2pointsY(c, para->pFmt->dySpaceAfter);
rc.top = rc.bottom - bounds->bottom - bottom_border;
FillRect(c->hDC, &rc, c->editor->hbrBackground);
}
else yafter = 0;
border_width = 0;
idx = (para->pFmt->wBorders >> 8) & 0xF;
if ((para->pFmt->dwMask & PFM_BORDER) && idx != 0 && (para->pFmt->wBorders & 0xF)) {
int pen_width;
COLORREF pencr;
HPEN pen = NULL, oldpen = NULL;
POINT pt;
if (para->pFmt->wBorders & 0x00B0)
FIXME("Unsupported border flags %x\n", para->pFmt->wBorders);
border_width = ME_GetParaBorderWidth(c->editor, para->pFmt->wBorders);
if (para->pFmt->wBorders & 64) /* autocolor */
pencr = GetSysColor(COLOR_WINDOWTEXT);
else
@ -423,50 +426,66 @@ static int ME_DrawParaDecoration(ME_Context* c, ME_Paragraph* para, int y)
MoveToEx(c->hDC, 0, 0, &pt);
/* before & after spaces are not included in border */
/* helper to draw the double lines in case of corner */
#define DD(x) ((para->pFmt->wBorders & (x)) ? (pen_width + 1) : 0)
if (para->pFmt->wBorders & 1)
{
MoveToEx(c->hDC, c->rcView.left, y + ybefore, NULL);
LineTo(c->hDC, c->rcView.left, y + para->nHeight - yafter);
MoveToEx(c->hDC, c->rcView.left, y + bounds->top, NULL);
LineTo(c->hDC, c->rcView.left, y + para->nHeight - bounds->bottom);
if (border_details[idx].dble) {
MoveToEx(c->hDC, c->rcView.left + pen_width + 1, y + ybefore + pen_width + 1, NULL);
LineTo(c->hDC, c->rcView.left + pen_width + 1, y + para->nHeight - yafter - pen_width - 1);
rc.left = c->rcView.left + 1;
rc.right = rc.left + border_width;
rc.top = y + bounds->top;
rc.bottom = y + para->nHeight - bounds->bottom;
FillRect(c->hDC, &rc, c->editor->hbrBackground);
MoveToEx(c->hDC, c->rcView.left + pen_width + 1, y + bounds->top + DD(4), NULL);
LineTo(c->hDC, c->rcView.left + pen_width + 1, y + para->nHeight - bounds->bottom - DD(8));
}
bounds->left += border_width;
}
if (para->pFmt->wBorders & 2)
{
MoveToEx(c->hDC, c->rcView.right, y + ybefore, NULL);
LineTo(c->hDC, c->rcView.right, y + para->nHeight - yafter);
MoveToEx(c->hDC, c->rcView.right - 1, y + bounds->top, NULL);
LineTo(c->hDC, c->rcView.right - 1, y + para->nHeight - bounds->bottom);
if (border_details[idx].dble) {
MoveToEx(c->hDC, c->rcView.right - pen_width - 1, y + ybefore + pen_width + 1, NULL);
LineTo(c->hDC, c->rcView.right - pen_width - 1, y + para->nHeight - yafter - pen_width - 1);
rc.left = c->rcView.right - pen_width - 1;
rc.right = c->rcView.right - 1;
rc.top = y + bounds->top;
rc.bottom = y + para->nHeight - bounds->bottom;
FillRect(c->hDC, &rc, c->editor->hbrBackground);
MoveToEx(c->hDC, c->rcView.right - 1 - pen_width - 1, y + bounds->top + DD(4), NULL);
LineTo(c->hDC, c->rcView.right - 1 - pen_width - 1, y + para->nHeight - bounds->bottom - DD(8));
}
bounds->right += border_width;
}
if (para->pFmt->wBorders & 4)
{
MoveToEx(c->hDC, c->rcView.left, y + ybefore, NULL);
LineTo(c->hDC, c->rcView.right, y + ybefore);
MoveToEx(c->hDC, c->rcView.left, y + bounds->top, NULL);
LineTo(c->hDC, c->rcView.right, y + bounds->top);
if (border_details[idx].dble) {
MoveToEx(c->hDC, c->rcView.left + pen_width + 1, y + ybefore + pen_width + 1, NULL);
LineTo(c->hDC, c->rcView.right - pen_width - 1, y + ybefore + pen_width + 1);
MoveToEx(c->hDC, c->rcView.left + DD(1), y + bounds->top + pen_width + 1, NULL);
LineTo(c->hDC, c->rcView.right - DD(2), y + bounds->top + pen_width + 1);
}
bounds->top += border_width;
}
if (para->pFmt->wBorders & 8)
{
MoveToEx(c->hDC, c->rcView.left, y + para->nHeight - yafter - 1, NULL);
LineTo(c->hDC, c->rcView.right, y + para->nHeight - yafter - 1);
MoveToEx(c->hDC, c->rcView.left, y + para->nHeight - bounds->bottom - 1, NULL);
LineTo(c->hDC, c->rcView.right, y + para->nHeight - bounds->bottom - 1);
if (border_details[idx].dble) {
MoveToEx(c->hDC, c->rcView.left + pen_width + 1, y + para->nHeight - yafter - 1 - pen_width - 1, NULL);
LineTo(c->hDC, c->rcView.right - pen_width - 1, y + para->nHeight - yafter - 1 - pen_width - 1);
MoveToEx(c->hDC, c->rcView.left + DD(1), y + para->nHeight - bounds->bottom - 1 - pen_width - 1, NULL);
LineTo(c->hDC, c->rcView.right - DD(2), y + para->nHeight - bounds->bottom - 1 - pen_width - 1);
}
bounds->bottom += border_width;
}
#undef DD
MoveToEx(c->hDC, pt.x, pt.y, NULL);
SelectObject(c->hDC, oldpen);
DeleteObject(pen);
}
return ybefore +
((para->pFmt->dwMask & PFM_BORDER) && (para->pFmt->wBorders & 4) ?
border_width : 0);
}
void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) {
@ -474,12 +493,11 @@ void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) {
ME_DisplayItem *p;
ME_Run *run;
ME_Paragraph *para = NULL;
RECT rc, rcPara;
RECT rc, rcPara, bounds;
int y = c->pt.y;
int height = 0, baseline = 0, no=0, pno = 0;
int xs = 0, xe = 0;
BOOL visible = FALSE;
int nMargWidth = 0;
c->pt.x = c->rcView.left;
rcPara.left = c->rcView.left;
@ -489,12 +507,11 @@ void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) {
case diParagraph:
para = &p->member.para;
assert(para);
nMargWidth = ME_twips2pointsX(c, para->pFmt->dxStartIndent);
if (pno != 0)
nMargWidth += ME_twips2pointsX(c, para->pFmt->dxOffset);
xs = c->rcView.left+nMargWidth;
pno = 0;
xs = c->rcView.left + ME_twips2pointsX(c, para->pFmt->dxStartIndent);
xe = c->rcView.right - ME_twips2pointsX(c, para->pFmt->dxRightIndent);
y += ME_DrawParaDecoration(c, para, y);
ME_DrawParaDecoration(c, para, y, &bounds);
y += bounds.top;
break;
case diStartRow:
y += height;
@ -503,16 +520,16 @@ void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) {
visible = RectVisible(c->hDC, &rcPara);
if (visible) {
/* left margin */
rc.left = c->rcView.left;
rc.right = c->rcView.left+nMargWidth;
rc.left = c->rcView.left + bounds.left;
rc.right = xs;
rc.top = y;
rc.bottom = y+p->member.row.nHeight;
FillRect(c->hDC, &rc, c->editor->hbrBackground);
/* right margin */
rc.left = xe;
rc.right = c->rcView.right;
rc.right = c->rcView.right - bounds.right;
FillRect(c->hDC, &rc, c->editor->hbrBackground);
rc.left = c->rcView.left+nMargWidth;
rc.left = xs;
rc.right = xe;
FillRect(c->hDC, &rc, c->editor->hbrBackground);
}
@ -528,7 +545,8 @@ void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) {
height = p->member.row.nHeight;
baseline = p->member.row.nBaseline;
pno++;
if (!pno++)
xe += ME_twips2pointsX(c, para->pFmt->dxOffset);
break;
case diRun:
assert(para);
@ -595,7 +613,7 @@ void ME_Scroll(ME_TextEditor *editor, int value, int type)
switch (type)
{
case 1:
/*Scroll absolutly*/
/*Scroll absolutely*/
si.nPos = value;
break;
case 2:
@ -628,7 +646,7 @@ void ME_Scroll(ME_TextEditor *editor, int value, int type)
void ME_UpdateScrollBar(ME_TextEditor *editor)
{
/* Note that this is the only funciton that should ever call SetScrolLInfo
/* Note that this is the only function that should ever call SetScrolLInfo
* with SIF_PAGE or SIF_RANGE. SetScrollPos and SetScrollRange should never
* be used at all. */

View file

@ -73,6 +73,8 @@ void ME_MakeFirstParagraph(ME_TextEditor *editor)
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);
@ -110,7 +112,7 @@ void ME_MarkForPainting(ME_TextEditor *editor, ME_DisplayItem *first, const ME_D
}
/* split paragraph at the beginning of the run */
ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, ME_Style *style)
ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, ME_Style *style, int numCR, int numLF)
{
ME_DisplayItem *next_para = NULL;
ME_DisplayItem *run_para = NULL;
@ -119,10 +121,12 @@ ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, ME
ME_UndoItem *undo = NULL;
int ofs;
ME_DisplayItem *pp;
int end_len = (editor->bEmulateVersion10 ? 2 : 1);
int end_len = numCR + numLF;
assert(run->type == diRun);
end_run->member.run.nCR = numCR;
end_run->member.run.nLF = numLF;
run_para = ME_GetParagraph(run);
assert(run_para->member.para.pFmt->cbSize == sizeof(PARAFORMAT2));
@ -204,7 +208,7 @@ ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp)
ME_DisplayItem *pNext, *pFirstRunInNext, *pRun, *pTmp;
int i, shift;
ME_UndoItem *undo = NULL;
int end_len = (editor->bEmulateVersion10 ? 2 : 1);
int end_len;
assert(tp->type == diParagraph);
assert(tp->member.para.next_para);
@ -212,6 +216,15 @@ ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp)
pNext = tp->member.para.next_para;
/* Need to locate end-of-paragraph run here, in order to know end_len */
pRun = ME_FindItemBack(pNext, diRunOrParagraph);
assert(pRun);
assert(pRun->type == diRun);
assert(pRun->member.run.nFlags & MERF_ENDPARA);
end_len = pRun->member.run.nCR + pRun->member.run.nLF;
{
/* null char format operation to store the original char format for the ENDPARA run */
CHARFORMAT2W fmt;
@ -222,18 +235,16 @@ ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp)
if (undo)
{
undo->nStart = pNext->member.para.nCharOfs - end_len;
undo->nCR = pRun->member.run.nCR;
undo->nLF = pRun->member.run.nLF;
assert(pNext->member.para.pFmt->cbSize == sizeof(PARAFORMAT2));
*undo->di.member.para.pFmt = *pNext->member.para.pFmt;
}
shift = pNext->member.para.nCharOfs - tp->member.para.nCharOfs - end_len;
pRun = ME_FindItemBack(pNext, diRunOrParagraph);
pFirstRunInNext = ME_FindItemFwd(pNext, diRunOrParagraph);
assert(pRun);
assert(pRun->type == diRun);
assert(pRun->member.run.nFlags & MERF_ENDPARA);
assert(pFirstRunInNext->type == diRun);
/* if some cursor points at end of paragraph, make it point to the first

View file

@ -2605,7 +2605,8 @@ static void SpecialChar (RTF_Info *info)
case rtfSect:
case rtfRow:
case rtfPar:
RTFPutUnicodeChar (info, '\n');
RTFPutUnicodeChar (info, '\r');
if (info->editor->bEmulateVersion10) RTFPutUnicodeChar (info, '\n');
break;
case rtfNoBrkSpace:
RTFPutUnicodeChar (info, 0x00A0);

View file

@ -127,8 +127,10 @@ void ME_CheckCharOffsets(ME_TextEditor *editor)
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;
@ -209,10 +211,12 @@ void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **
}
*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;
}

View file

@ -327,10 +327,9 @@ ME_LogFontFromStyle(ME_Context* c, LOGFONTW *lf, const ME_Style *s)
void ME_CharFormatFromLogFont(HDC hDC, const LOGFONTW *lf, CHARFORMAT2W *fmt)
{
int rx, ry;
int ry;
ME_InitCharFormat2W(fmt);
rx = GetDeviceCaps(hDC, LOGPIXELSX);
ry = GetDeviceCaps(hDC, LOGPIXELSY);
lstrcpyW(fmt->szFaceName, lf->lfFaceName);
fmt->dwEffects = 0;
@ -341,7 +340,7 @@ void ME_CharFormatFromLogFont(HDC hDC, const LOGFONTW *lf, CHARFORMAT2W *fmt)
if (lf->lfItalic) fmt->dwEffects |= CFM_ITALIC;
if (lf->lfUnderline) fmt->dwEffects |= CFM_UNDERLINE;
/* notice that if a logfont was created with underline due to CFM_LINK, this
would add an erronious CFM_UNDERLINE. This isn't currently ever a problem */
would add an erroneous CFM_UNDERLINE. This isn't currently ever a problem. */
if (lf->lfStrikeOut) fmt->dwEffects |= CFM_STRIKEOUT;
fmt->bPitchAndFamily = lf->lfPitchAndFamily;
fmt->bCharSet = lf->lfCharSet;

View file

@ -56,6 +56,7 @@ ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, const ME_Disp
else
{
ME_DisplayItem *pItem = (ME_DisplayItem *)ALLOC_OBJ(ME_UndoItem);
((ME_UndoItem *)pItem)->nCR = ((ME_UndoItem *)pItem)->nLF = -1;
switch(type)
{
case diUndoEndTransaction:
@ -225,7 +226,10 @@ static void ME_PlayUndoItem(ME_TextEditor *editor, ME_DisplayItem *pItem)
ME_CursorFromCharOfs(editor, pUItem->nStart, &tmp);
if (tmp.nOffset)
tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset);
new_para = ME_SplitParagraph(editor, tmp.pRun, tmp.pRun->member.run.style);
assert(pUItem->nCR >= 0);
assert(pUItem->nLF >= 0);
new_para = ME_SplitParagraph(editor, tmp.pRun, tmp.pRun->member.run.style,
pUItem->nCR, pUItem->nLF);
assert(pItem->member.para.pFmt->cbSize == sizeof(PARAFORMAT2));
*new_para->member.para.pFmt = *pItem->member.para.pFmt;
break;
@ -247,7 +251,7 @@ void ME_Undo(ME_TextEditor *editor) {
if (!editor->pUndoStack)
return;
/* watch out for uncommited transactions ! */
/* watch out for uncommitted transactions ! */
assert(editor->pUndoStack->type == diUndoEndTransaction);
editor->nUndoMode = umAddToRedo;
@ -280,7 +284,7 @@ void ME_Redo(ME_TextEditor *editor) {
if (!editor->pRedoStack)
return;
/* watch out for uncommited transactions ! */
/* watch out for uncommitted transactions ! */
assert(editor->pRedoStack->type == diUndoEndTransaction);
editor->nUndoMode = umAddBackToUndo;

View file

@ -470,11 +470,9 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
ME_DisplayItem *item;
ME_Context c;
BOOL bModified = FALSE;
int yStart = -1, yEnd = -1;
int yStart = -1;
ME_InitContext(&c, editor, GetDC(editor->hWnd));
c.pt.x = 0;
c.pt.y = 0;
editor->nHeight = 0;
item = editor->pBuffer->pFirst->next;
while(item != editor->pBuffer->pLast) {
@ -499,8 +497,6 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
bModified = bModified | bRedraw;
c.pt.y += item->member.para.nHeight;
if (bRedraw)
yEnd = c.pt.y;
item = item->member.para.next_para;
}
editor->sizeWindow.cx = c.rcView.right-c.rcView.left;
@ -510,6 +506,14 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
ME_DestroyContext(&c, editor->hWnd);
/* Each paragraph may contain multiple rows, which should be scrollable, even
if the containing paragraph has nYPos == 0 */
item = editor->pBuffer->pFirst;
while ((item = ME_FindItemFwd(item, diStartRow)) != NULL) {
assert(item->type == diStartRow);
editor->nHeight = max(editor->nHeight, item->member.row.nYPos);
}
if (bModified || editor->nTotalLength < editor->nLastTotalLength)
ME_InvalidateMarkedParagraphs(editor);
return bModified;

View file

@ -711,9 +711,9 @@ ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream, int nStart, int nC
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;
@ -775,10 +775,39 @@ ME_StreamOutText(ME_TextEditor *editor, ME_OutStream *pStream, int nStart, int n
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),
@ -800,8 +829,6 @@ ME_StreamOutText(ME_TextEditor *editor, ME_OutStream *pStream, int nStart, int n
}
nChars -= nLen;
if (editor->bEmulateVersion10 && nChars && item->member.run.nFlags & MERF_ENDPARA)
nChars--;
nStart = 0;
item = ME_FindItemFwd(item, diRun);
}