Sync to Wine-20050419: Krzysztof Foltman wdev@foltman.com - removed trailing spaces from some files - tab support - indent support - PageUp key support. - Support for "normal" scroll bar functionality (line and page scrolling). - made string operations consistent wrt whitespace handling (which should greatly improve stability of the wrap code and eliminate regressions of the most recent versions) - completely new scrollbar handling (much more reliable) and related redraw fixes - Page Down handler (no Page Up yet, fixing wrap/redraw/scrollbar bugs was of higher priority) - RTF reader doesn't use RichEdit messages anymore (which saves on unnecessary repaints) - added unicode character support to RTF import (like: \u12345 ?) - small fixes - fixed whitespace identification bug - removed drawing of paragraph marks - improved stub implementations for IRichEditOle - Unknown destinations are now correctly skipped (so loading an RTF file generated by, for example, OpenOffice doesn't produce lots of garbage anymore). - Format stack for RTF groups (so that RTF reader can correctly read what RTF writer wrote :) ) - EM_STREAMIN can now deal with undo in a reasonable manner (no multiple undo actions in one EM_STREAMIN). - Related changes to undo code (umIgnore mode is now handled correctly). - Numerous improvements in the RTF reader: it reads some character attributes now (you will have proper small print in license agreements now). - Fixed a memory overwrite bug in conversion from CHARFORMAT2A to CHARFORMAT2W. - Optimized repaint of the area below the text. - ME_JoinRuns didn't mark the paragraph for rewrapping, fixed. - Removed PostQuitMessage(0) from WM_DESTROY handler (duh!). - Use of EM_GETOLEINTERFACE is reported with FIXME instead of TRACE (any app using this message is likely to encounter major problems). - WM_COPY (and WM_CUT) can now put both Unicode and RTF format (thanks to Phil Krylov's RTF generator code). - New message implemented - WM_PASTE. - RTF reader: rtfPlain implemented (kind of). - RTF writer: rewritten main loop (the old one crashed in some circumstances when SFF_SELECTION was used). - The meaning of the rewrap flag got inverted (MEPF_REWRAP instead of MEPF_WRAPPED) for consistency. - Major code cleanups in rewrap/repaint code, leading to "smarter" behaviour wrt repainting selections. - Old font management replaced by the cache-based one, which keeps maximum of 10 HFONTs at once, instead of one per a couple of runs. - EM_CANPASTE implemented - updated TODO list (including list of (un)implemented messages) - fixed WM_PASTE (the previous version might not close the clipboard if it didn't contain a usable format) - scrollbar operations (like clicking on arrows) should update scrollbar's current position Gerald Pfeifer gerald@pfeifer.com - Make ME_ArrowLeft() return a value in every case. Phil Krylov phil@newstar.rinet.ru - Make RTF reader fall back to simple text if a correct RTF header is not detected. This should fix some installers. - Made RTF reader and writer handle codepages mostly similar to the original riched20.dll. - Fixed support for RTF documents using ANSI charset and added support for multibyte charsets, so that BIG5 and UTF-8 RTF documents are working now. - Replaced slow and outdated character set handling in RTF reader by Unicode/codepages support. Added charset->codepage conversion. - Implemented hash table lookup for RTF keywords in RTF reader. - Added "generator" RTF destination handling. - Initial implementation of EM_STREAMOUT and RTF writer. - Fixed \u keyword to output signed 16-bit values. Also fixed CP_SYMBOL conversion and the detection of the default font's codepage. - Improved RTF export. Mike McCormack mike@codeweavers.com - Remove casts and unused code. Hannu Valtonen Hannu.Valtonen@hut.fi - Added mousewheel support. Vincent Beron vberon@mecano.gme.usherb.ca - Use "" for Windows includes in dlls, instead of <>. Jakob Eriksson jakov@vmlinux.org - Get rid of HeapAlloc casts. Jason Edmeades us@the-edmeades.demon.co.uk - Correct memory allocation macro. Modified: trunk/reactos/lib/riched20/Makefile.in Modified: trunk/reactos/lib/riched20/caret.c Modified: trunk/reactos/lib/riched20/editor.c Modified: trunk/reactos/lib/riched20/editor.h Modified: trunk/reactos/lib/riched20/editstr.h Modified: trunk/reactos/lib/riched20/paint.c Modified: trunk/reactos/lib/riched20/para.c Modified: trunk/reactos/lib/riched20/reader.c Modified: trunk/reactos/lib/riched20/richole.c Modified: trunk/reactos/lib/riched20/rtf.h Modified: trunk/reactos/lib/riched20/run.c Modified: trunk/reactos/lib/riched20/string.c Modified: trunk/reactos/lib/riched20/style.c Modified: trunk/reactos/lib/riched20/undo.c Modified: trunk/reactos/lib/riched20/wrap.c Added: trunk/reactos/lib/riched20/writer.c Modified: trunk/reactos/w32api/include/richedit.h _____
Modified: trunk/reactos/lib/riched20/Makefile.in --- trunk/reactos/lib/riched20/Makefile.in 2005-05-05 18:59:14 UTC (rev 15013) +++ trunk/reactos/lib/riched20/Makefile.in 2005-05-05 19:00:49 UTC (rev 15014) @@ -20,7 +20,8 @@
string.c \ style.c \ undo.c \ - wrap.c + wrap.c \ + writer.c
@MAKE_DLL_RULES@
_____
Modified: trunk/reactos/lib/riched20/caret.c --- trunk/reactos/lib/riched20/caret.c 2005-05-05 18:59:14 UTC (rev 15013) +++ trunk/reactos/lib/riched20/caret.c 2005-05-05 19:00:49 UTC (rev 15014) @@ -104,15 +104,15 @@
{ row = ME_FindItemBack(tmp, diStartRow); pSizeRun = run = tmp; - sz = ME_GetRunSize(&c, &run->member.run, ME_StrLen(run->member.run.strText)); + sz = ME_GetRunSize(&c, ¶->member.para, &run->member.run, ME_StrLen(run->member.run.strText)); } } if (pCursor->nOffset && !(run->member.run.nFlags & MERF_SKIPPED)) { - sz = ME_GetRunSize(&c, &run->member.run, pCursor->nOffset); + sz = ME_GetRunSize(&c, ¶->member.para, &run->member.run, pCursor->nOffset); } CreateCaret(editor->hWnd, NULL, 0, pSizeRun->member.run.nAscent+pSizeRun->member.run.nDescent); SetCaretPos(run->member.run.pt.x+sz.cx, - para->member.para.nYPos+row->member.row.nBaseline+pSizeRun->member.run.p t.y-pSizeRun->member.run.nAscent-GetScrollPos(editor->hWnd, SB_VERT)); + para->member.para.nYPos+row->member.row.nBaseline+pSizeRun->member.run.p t.y-pSizeRun->member.run.nAscent-ME_GetYScrollPos(editor)); } else { assert(0 == "Wrapped paragraph run without a row?"); CreateCaret(editor->hWnd, NULL, 0, 10); @@ -300,12 +300,6 @@ assert(style); editor->bCaretAtEnd = FALSE;
- /* - if (!style) - style = ME_GetInsertStyle(editor, nCursor); - else - ME_AddRefStyle(style); - */ ME_AddRefStyle(style);
/* FIXME really HERE ? */ @@ -317,10 +311,30 @@ len = lstrlenW(str); pos = str; /* FIXME this sucks - no respect for unicode (what else can be a line separator in unicode?) */ - while(pos-str < len && *pos != '\r' && *pos != '\n') + while(pos-str < len && *pos != '\r' && *pos != '\n' && *pos != '\t') pos++; - /* handle EOLs */ - if (pos-str < len) { + if (pos-str < len && *pos == '\t') { /* handle tabs */ + ME_DisplayItem *pNewRun = NULL; + WCHAR tab = '\t'; + + if (pos!=str) + ME_InsertTextFromCursor(editor, nCursor, str, pos-str, style); + + p = &editor->pCursors[nCursor]; + assert(style); + assert(p->pRun->type == diRun); + pNewRun = ME_MakeRun(style, ME_MakeStringN(&tab, 1), MERF_TAB); /* addrefs style */ + ME_InsertRun(editor, ME_CharOfsFromRunOfs(editor, p->pRun, p->nOffset), pNewRun); + ME_DestroyDisplayItem(pNewRun); + ME_ReleaseStyle(style); + + pos++; + if(pos-str < len) { + ME_InsertTextFromCursor(editor, nCursor, pos, len-(pos-str), style); + } + return; + } + if (pos-str < len) { /* handle EOLs */ ME_DisplayItem *tp, *end_run; ME_Paragraph *para; ME_Style *tmp_style; @@ -404,6 +418,7 @@ } assert(0); } + return FALSE; }
BOOL ME_ArrowRight(ME_TextEditor *editor, ME_Cursor *p) @@ -537,7 +552,7 @@
editor->nUDArrowX = -1;
- y += GetScrollPos(editor->hWnd, SB_VERT); + y += ME_GetYScrollPos(editor);
tmp_cursor = editor->pCursors[0]; is_selection = ME_IsSelection(editor); @@ -568,7 +583,7 @@ { ME_Cursor tmp_cursor;
- y += GetScrollPos(editor->hWnd, SB_VERT); + y += ME_GetYScrollPos(editor);
tmp_cursor = editor->pCursors[0]; if (!ME_FindPixelPos(editor, x, y, &editor->pCursors[0], &editor->bCaretAtEnd)) @@ -702,6 +717,109 @@ assert(pCursor->pRun->type == diRun); }
+void ME_ArrowPageUp(ME_TextEditor *editor, ME_Cursor *pCursor) +{ + ME_DisplayItem *pRun = pCursor->pRun; + ME_DisplayItem *pLast, *p; + int x, y, ys, yd, yp, yprev; + ME_Cursor tmp_curs = *pCursor; + + x = ME_GetXForArrow(editor, pCursor); + if (!pCursor->nOffset && editor->bCaretAtEnd) + pRun = ME_FindItemBack(pRun, diRun); + + p = ME_FindItemBack(pRun, diStartRowOrParagraph); + assert(p->type == diStartRow); + yp = ME_FindItemBack(p, diParagraph)->member.para.nYPos; + yprev = ys = y = yp + p->member.row.nYPos; + yd = y - editor->sizeWindow.cy; + pLast = p; + + do { + p = ME_FindItemBack(p, diStartRowOrParagraph); + if (!p) + break; + if (p->type == diParagraph) { /* crossing paragraphs */ + if (p->member.para.prev_para == NULL) + break; + yp = p->member.para.prev_para->member.para.nYPos; + continue; + } + y = yp + p->member.row.nYPos; + if (y < yd) + break; + pLast = p; + yprev = y; + } while(1); + + pCursor->pRun = ME_FindRunInRow(editor, pLast, x, &pCursor->nOffset, &editor->bCaretAtEnd); + ME_UpdateSelection(editor, &tmp_curs); + if (yprev < editor->sizeWindow.cy) + { + ME_EnsureVisible(editor, ME_FindItemFwd(editor->pBuffer->pFirst, diRun)); + ME_Repaint(editor); + } + else { + ME_Scroll(editor, 0, ys-yprev); + ME_Repaint(editor); + } + assert(pCursor->pRun); + assert(pCursor->pRun->type == diRun); +} + +/* FIXME: in the original RICHEDIT, PageDown always scrolls by the same amount + of pixels, even if it makes the scroll bar position exceed its normal maximum. + In such a situation, clicking the scrollbar restores its position back to the + normal range (ie. sets it to (doclength-screenheight)). */ + +void ME_ArrowPageDown(ME_TextEditor *editor, ME_Cursor *pCursor) +{ + ME_DisplayItem *pRun = pCursor->pRun; + ME_DisplayItem *pLast, *p; + int x, y, ys, yd, yp, yprev; + ME_Cursor tmp_curs = *pCursor; + + x = ME_GetXForArrow(editor, pCursor); + if (!pCursor->nOffset && editor->bCaretAtEnd) + pRun = ME_FindItemBack(pRun, diRun); + + p = ME_FindItemBack(pRun, diStartRowOrParagraph); + assert(p->type == diStartRow); + yp = ME_FindItemBack(p, diParagraph)->member.para.nYPos; + yprev = ys = y = yp + p->member.row.nYPos; + yd = y + editor->sizeWindow.cy; + pLast = p; + + do { + p = ME_FindItemFwd(p, diStartRowOrParagraph); + if (!p) + break; + if (p->type == diParagraph) { + yp = p->member.para.nYPos; + continue; + } + y = yp + p->member.row.nYPos; + if (y >= yd) + break; + pLast = p; + yprev = y; + } while(1); + + pCursor->pRun = ME_FindRunInRow(editor, pLast, x, &pCursor->nOffset, &editor->bCaretAtEnd); + ME_UpdateSelection(editor, &tmp_curs); + if (yprev >= editor->nTotalLength-editor->sizeWindow.cy) + { + ME_EnsureVisible(editor, ME_FindItemBack(editor->pBuffer->pLast, diRun)); + ME_Repaint(editor); + } + else { + ME_Scroll(editor, 0, ys-yprev); + ME_Repaint(editor); + } + assert(pCursor->pRun); + assert(pCursor->pRun->type == diRun); +} + void ME_ArrowHome(ME_TextEditor *editor, ME_Cursor *pCursor) { ME_DisplayItem *pRow = ME_FindItemBack(pCursor->pRun, diStartRow); @@ -799,45 +917,44 @@ editor->pCursors[1] = editor->pCursors[0]; else editor->pCursors[0] = editor->pCursors[1]; - /* FIXME optimize */ - ME_MarkAllForWrapping(editor); ME_Repaint(editor); return TRUE; }
-void ME_RepaintSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor) +BOOL ME_UpdateSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor) { ME_Cursor old_anchor = editor->pCursors[1]; - BOOL bRedraw = FALSE; - bRedraw = memcmp(&editor->pCursors[0], &editor->pCursors[1], sizeof(ME_Cursor));
- if (bRedraw) - { - /* FIXME optimize */ - ME_MarkAllForWrapping(editor); - } - if (GetKeyState(VK_SHIFT)>=0) /* cancelling selection */ { /* any selection was present ? if so, it's no more, repaint ! */ editor->pCursors[1] = editor->pCursors[0]; if (memcmp(pTempCursor, &old_anchor, sizeof(ME_Cursor))) { - ME_Repaint(editor); - return; + return TRUE; } - return; + return FALSE; } else { if (!memcmp(pTempCursor, &editor->pCursors[1], sizeof(ME_Cursor))) /* starting selection */ { editor->pCursors[1] = *pTempCursor; + return TRUE; } }
ME_Repaint(editor); + return TRUE; }
+void ME_RepaintSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor) +{ + if (ME_UpdateSelection(editor, pTempCursor)) { + ME_EnsureVisible(editor, editor->pCursors[0].pRun); + ME_Repaint(editor); + } +} + void ME_DeleteSelection(ME_TextEditor *editor) { int from, to; @@ -898,6 +1015,16 @@ ME_RepaintSelection(editor, &tmp_curs); ME_SendSelChange(editor); return TRUE; + case VK_PRIOR: + ME_ArrowPageUp(editor, p); + ME_ClearTempStyle(editor); + ME_SendSelChange(editor); + return TRUE; + case VK_NEXT: + ME_ArrowPageDown(editor, p); + ME_ClearTempStyle(editor); + ME_SendSelChange(editor); + return TRUE; }
editor->nUDArrowX = -1; @@ -914,6 +1041,7 @@ } if (ME_ArrowLeft(editor, p)) { editor->bCaretAtEnd = FALSE; /* FIXME or maybe not */ + ME_ClearTempStyle(editor); ME_MoveCaret(editor); ME_DeleteTextAtCursor(editor, nCursor, 1); ME_UpdateRepaint(editor); @@ -927,10 +1055,12 @@ if (ME_IsSelection(editor)) { ME_DeleteSelection(editor); + ME_ClearTempStyle(editor); ME_UpdateRepaint(editor); return TRUE; } ME_DeleteTextAtCursor(editor, nCursor, 1); + ME_ClearTempStyle(editor); ME_UpdateRepaint(editor); return TRUE; } _____
Modified: trunk/reactos/lib/riched20/editor.c --- trunk/reactos/lib/riched20/editor.c 2005-05-05 18:59:14 UTC (rev 15013) +++ trunk/reactos/lib/riched20/editor.c 2005-05-05 19:00:49 UTC (rev 15014) @@ -23,7 +23,7 @@
Messages (ANSI versions not done yet) - EM_AUTOURLDETECT 2.0 - - EM_CANPASTE + + EM_CANPASTE + EM_CANREDO 2.0 + EM_CANUNDO - EM_CHARFROMPOS @@ -73,7 +73,7 @@ - EM_LINESCROLL - EM_PASTESPECIAL - EM_POSFROMCHARS - - EM_REDO 2.0 + + EM_REDO 2.0 - EM_REQUESTRESIZE + EM_REPLACESEL (proper style?) ANSI&Unicode - EM_SCROLL @@ -102,17 +102,17 @@ - EM_SETWORDBREAKPROCEX - EM_SETWORDWRAPMODE 1.0asian - EM_STOPGROUPTYPING 2.0 - - EM_STREAMIN - - EM_STREAMOUT - - EM_UNDO + + EM_STREAMIN (can't fall back to text when the RTF isn't really RTF) + + EM_STREAMOUT + + EM_UNDO + WM_CHAR + WM_CLEAR - - WM_COPY (lame implementation, no RTF support) - - WM_CUT (lame implementation, no RTF support) + + WM_COPY + + WM_CUT + WM_GETDLGCODE (the current implementation is incomplete) + WM_GETTEXT (ANSI&Unicode) + WM_GETTEXTLENGTH (ANSI version sucks) - - WM_PASTE + + WM_PASTE - WM_SETFONT + WM_SETTEXT (resets undo stack !) (proper style?) ANSI&Unicode - WM_STYLECHANGING @@ -166,30 +166,25 @@ /* * RICHED20 TODO (incomplete): * - * - font caching + * - messages/styles/notifications listed above + * - Undo coalescing * - add remaining CHARFORMAT/PARAFORMAT fields * - right/center align should strip spaces from the beginning - * - more advanced navigation (Ctrl-arrows, PageUp/PageDn) + * - more advanced navigation (Ctrl-arrows) * - tabs - * - pictures (not just smiling faces that lack API support ;-) ) - * - OLE objects + * - pictures/OLE objects (not just smiling faces that lack API support ;-) ) + * - COM interface (looks like a major pain in the TODO list) * - calculate heights of pictures (half-done) - * - EM_STREAMIN/EM_STREAMOUT * - horizontal scrolling (not even started) - * - fix scrollbars and refresh (it sucks bigtime) * - hysteresis during wrapping (related to scrollbars appearing/disappearing) - * - should remember maximum row width for wrap hysteresis * - find/replace * - how to implement EM_FORMATRANGE and EM_DISPLAYBAND ? (Mission Impossible) - * - italic cursor with italic fonts + * - italic caret with italic fonts * - IME * - most notifications aren't sent at all (the most important ones are) * - when should EN_SELCHANGE be sent after text change ? (before/after EN_UPDATE?) * - WM_SETTEXT may use wrong style (but I'm 80% sure it's OK) * - EM_GETCHARFORMAT with SCF_SELECTION may not behave 100% like in original (but very close) - * - bugs in end-of-text handling (the gray bar) could get me in jail ;-) - * - determination of row size - * - end-of-paragraph marks should be of reasonable size * * Bugs that are probably fixed, but not so easy to verify: * - EN_UPDATE/EN_CHANGE are handled very incorrectly (should be OK now) @@ -203,11 +198,11 @@ */
#include "editor.h" -#include <ole2.h> -#include <richole.h> -#include <winreg.h> +#include "ole2.h" +#include "richole.h" +#include "winreg.h" #define NO_SHLWAPI_STREAM -#include <shlwapi.h> +#include "shlwapi.h"
#include "rtf.h"
@@ -238,91 +233,388 @@ return buf; }
-#define STREAMIN_BUFFER_SIZE 4096 /* M$ compatibility */
-static LRESULT ME_StreamInText(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM *stream, ME_Style *style) +static LRESULT ME_StreamInText(ME_TextEditor *editor, DWORD dwFormat, ME_InStream *stream, ME_Style *style) { - BYTE buffer[STREAMIN_BUFFER_SIZE+1]; WCHAR wszText[STREAMIN_BUFFER_SIZE+1]; + WCHAR *pText;
TRACE("%08lx %p\n", dwFormat, stream); - stream->dwError = 0;
do { - long nDataSize = 0, nWideChars = 0; - stream->dwError = stream->pfnCallback(stream->dwCookie, - (dwFormat & SF_UNICODE ? (BYTE *)wszText : buffer), - STREAMIN_BUFFER_SIZE, &nDataSize); - - if (stream->dwError) - break; - if (!nDataSize) - break; + long nWideChars = 0; + + if (!stream->dwSize) + { + ME_StreamInFill(stream); + if (stream->editstream->dwError) + break; + if (!stream->dwSize) + break; + }
if (!(dwFormat & SF_UNICODE)) { /* FIXME? this is doomed to fail on true MBCS like UTF-8, luckily they're unlikely to be used as CP_ACP */ - nWideChars = MultiByteToWideChar(CP_ACP, 0, buffer, nDataSize, wszText, STREAMIN_BUFFER_SIZE); + nWideChars = MultiByteToWideChar(CP_ACP, 0, stream->buffer, stream->dwSize, wszText, STREAMIN_BUFFER_SIZE); + pText = wszText; } else - nWideChars = nDataSize>>1; - ME_InsertTextFromCursor(editor, 0, wszText, nWideChars, style); - if (nDataSize<STREAMIN_BUFFER_SIZE) + { + nWideChars = stream->dwSize >> 1; + pText = (WCHAR *)stream->buffer; + } + + ME_InsertTextFromCursor(editor, 0, pText, nWideChars, style); + if (stream->dwSize < STREAMIN_BUFFER_SIZE) break; } while(1); - ME_CommitUndo(editor); + ME_CommitUndo(editor); + ME_Repaint(editor); return 0; }
+void ME_RTFCharAttrHook(RTF_Info *info) +{ + CHARFORMAT2W fmt; + fmt.cbSize = sizeof(fmt); + fmt.dwMask = 0; + + switch(info->rtfMinor) + { + case rtfPlain: + /* FIXME add more flags once they're implemented */ + fmt.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR | CFM_BACKCOLOR | CFM_SIZE | CFM_WEIGHT; + fmt.dwEffects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR; + fmt.yHeight = 12*20; /* 12pt */ + fmt.wWeight = 400; + break; + case rtfBold: + fmt.dwMask = CFM_BOLD; + fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0; + break; + case rtfItalic: + fmt.dwMask = CFM_ITALIC; + fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0; + break; + case rtfUnderline: + fmt.dwMask = CFM_UNDERLINE; + fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0; + break; + case rtfStrikeThru: + fmt.dwMask = CFM_STRIKEOUT; + fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0; + break; + case rtfBackColor: + fmt.dwMask = CFM_BACKCOLOR; + fmt.dwEffects = 0; + if (info->rtfParam == 0) + fmt.dwEffects = CFE_AUTOBACKCOLOR; + else if (info->rtfParam != rtfNoParam) + { + RTFColor *c = RTFGetColor(info, info->rtfParam); + fmt.crTextColor = (c->rtfCBlue<<16)|(c->rtfCGreen<<8)|(c->rtfCRed); + } + break; + case rtfForeColor: + fmt.dwMask = CFM_COLOR; + fmt.dwEffects = 0; + if (info->rtfParam == 0) + fmt.dwEffects = CFE_AUTOCOLOR; + else if (info->rtfParam != rtfNoParam) + { + RTFColor *c = RTFGetColor(info, info->rtfParam); + fmt.crTextColor = (c->rtfCBlue<<16)|(c->rtfCGreen<<8)|(c->rtfCRed); + } + break; + case rtfFontNum: + if (info->rtfParam != rtfNoParam) + { + RTFFont *f = RTFGetFont(info, info->rtfParam); + if (f) + { + MultiByteToWideChar(CP_ACP, 0, f->rtfFName, -1, fmt.szFaceName, sizeof(fmt.szFaceName)/sizeof(WCHAR)); + fmt.szFaceName[sizeof(fmt.szFaceName)/sizeof(WCHAR)-1] = '\0'; + fmt.bCharSet = f->rtfFCharSet; + fmt.dwMask = CFM_FACE | CFM_CHARSET; + } + } + break; + case rtfFontSize: + fmt.dwMask = CFM_SIZE; + if (info->rtfParam != rtfNoParam) + fmt.yHeight = info->rtfParam*10; + break; + } + if (fmt.dwMask) { + ME_Style *style2; + RTFFlushOutputBuffer(info); + /* FIXME too slow ? how come ? */ + style2 = ME_ApplyStyle(info->style, &fmt); + ME_ReleaseStyle(info->style); + info->style = style2; + } +} + +/* FIXME this function doesn't get any information about context of the RTF tag, which is very bad, + the same tags mean different things in different contexts */ +void ME_RTFParAttrHook(RTF_Info *info) +{ + PARAFORMAT2 fmt; + fmt.cbSize = sizeof(fmt); + fmt.dwMask = 0; + + switch(info->rtfMinor) + { + case rtfParDef: /* I'm not 100% sure what does it do, but I guess it restores default paragraph attributes */ + fmt.dwMask = PFM_ALIGNMENT | PFM_TABSTOPS | PFM_OFFSET | PFM_STARTINDENT; + fmt.wAlignment = PFA_LEFT; + fmt.cTabCount = 0; + fmt.dxOffset = fmt.dxStartIndent = 0; + break; + case rtfFirstIndent: + ME_GetSelectionParaFormat(info->editor, &fmt); + fmt.dwMask = PFM_STARTINDENT; + fmt.dxStartIndent = info->rtfParam + fmt.dxOffset; + break; + case rtfLeftIndent: + { + int first, left; + ME_GetSelectionParaFormat(info->editor, &fmt); + first = fmt.dxStartIndent; + left = info->rtfParam; + fmt.dwMask = PFM_STARTINDENT|PFM_OFFSET; + fmt.dxStartIndent = first + left; + fmt.dxOffset = -first; + break; + } + case rtfRightIndent: + fmt.dwMask = PFM_RIGHTINDENT; + fmt.dxRightIndent = info->rtfParam; + break; + case rtfQuadLeft: + case rtfQuadJust: + fmt.dwMask = PFM_ALIGNMENT; + fmt.wAlignment = PFA_LEFT; + break; + case rtfQuadRight: + fmt.dwMask = PFM_ALIGNMENT; + fmt.wAlignment = PFA_RIGHT; + break; + case rtfQuadCenter: + fmt.dwMask = PFM_ALIGNMENT; + fmt.wAlignment = PFA_CENTER; + break; + case rtfTabPos: + ME_GetSelectionParaFormat(info->editor, &fmt); + if (!(fmt.dwMask & PFM_TABSTOPS)) + { + fmt.dwMask |= PFM_TABSTOPS; + fmt.cTabCount = 0; + } + if (fmt.cTabCount < MAX_TAB_STOPS) + fmt.rgxTabs[fmt.cTabCount++] = info->rtfParam; + break; + } + if (fmt.dwMask) { + RTFFlushOutputBuffer(info); + /* FIXME too slow ? how come ?*/ + ME_SetSelectionParaFormat(info->editor, &fmt); + } +} + +void ME_RTFReadHook(RTF_Info *info) { + switch(info->rtfClass) + { + case rtfGroup: + switch(info->rtfMajor) + { + case rtfBeginGroup: + if (info->stackTop < maxStack) { + memcpy(&info->stack[info->stackTop].fmt, &info->style->fmt, sizeof(CHARFORMAT2W)); + info->stack[info->stackTop].codePage = info->codePage; + info->stack[info->stackTop].unicodeLength = info->unicodeLength; + } + info->stackTop++; + break; + case rtfEndGroup: + { + ME_Style *s; + RTFFlushOutputBuffer(info); + info->stackTop--; + /* FIXME too slow ? how come ? */ + s = ME_ApplyStyle(info->style, &info->stack[info->stackTop].fmt); + ME_ReleaseStyle(info->style); + info->style = s; + info->codePage = info->stack[info->stackTop].codePage; + info->unicodeLength = info->stack[info->stackTop].unicodeLength; + break; + } + } + break; + case rtfControl: + switch(info->rtfMajor) + { + case rtfCharAttr: + ME_RTFCharAttrHook(info); + break; + case rtfParAttr: + ME_RTFParAttrHook(info); + break; + } + break; + } +} + +void +ME_StreamInFill(ME_InStream *stream) +{ + stream->editstream->dwError = stream->editstream->pfnCallback(stream->editstream->dwCookie, + stream->buffer, + sizeof(stream->buffer), + &stream->dwSize); + stream->dwUsed = 0; +} + static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stream) { RTF_Info parser; ME_Style *style; + int from, to, to2, nUndoMode; + ME_UndoItem *pUI; + int nEventMask = editor->nEventMask; + ME_InStream inStream;
TRACE("%p %p\n", stream, editor->hWnd); + editor->nEventMask = 0;
+ ME_GetSelection(editor, &from, &to); if (format & SFF_SELECTION) { style = ME_GetSelectionInsertStyle(editor); - SendMessageW(editor->hWnd, WM_CLEAR, 0, 0); + + ME_InternalDeleteText(editor, from, to-from); } else { style = editor->pBuffer->pDefaultStyle; ME_AddRefStyle(style); SendMessageA(editor->hWnd, EM_SETSEL, 0, 0); - SetWindowTextA(editor->hWnd, ""); + ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor)); + from = to = 0; ME_ClearTempStyle(editor); + /* FIXME restore default paragraph formatting ! */ } + + nUndoMode = editor->nUndoMode; + editor->nUndoMode = umIgnore;
- if (format & SF_RTF) { - /* setup the RTF parser */ - memset(&parser, 0, sizeof parser); - RTFSetEditStream(&parser, stream); - parser.rtfFormat = format&(SF_TEXT|SF_RTF); - parser.hwndEdit = editor->hWnd; - WriterInit(&parser); - RTFInit(&parser); - BeginFile(&parser); + inStream.editstream = stream; + inStream.editstream->dwError = 0; + inStream.dwSize = 0; + inStream.dwUsed = 0; + + if (format & SF_RTF) + { + /* Check if it's really RTF, and if it is not, use plain text */ + ME_StreamInFill(&inStream); + if (!inStream.editstream->dwError) + { + if (strncmp(inStream.buffer, "{\rtf1", 6) && strncmp(inStream.buffer, "{\urtf", 6)) + { + format &= ~SF_RTF; + format |= SF_TEXT; + } + } + } + + if (!inStream.editstream->dwError) + { + if (format & SF_RTF) { + /* setup the RTF parser */ + memset(&parser, 0, sizeof parser); + RTFSetEditStream(&parser, &inStream); + parser.rtfFormat = format&(SF_TEXT|SF_RTF); + parser.hwndEdit = editor->hWnd; + parser.editor = editor; + parser.style = style; + WriterInit(&parser); + RTFInit(&parser); + RTFSetReadHook(&parser, ME_RTFReadHook); + BeginFile(&parser);
- /* do the parsing */ - RTFRead(&parser); - RTFFlushOutputBuffer(&parser); + /* do the parsing */ + RTFRead(&parser); + RTFFlushOutputBuffer(&parser); + RTFDestroy(&parser); + + style = parser.style; + } + else if (format & SF_TEXT) + ME_StreamInText(editor, format, &inStream, style); + else + ERR("EM_STREAMIN without SF_TEXT or SF_RTF\n"); + ME_GetSelection(editor, &to, &to2); + /* put the cursor at the top */ + if (!(format & SFF_SELECTION)) + SendMessageA(editor->hWnd, EM_SETSEL, 0, 0); + else + { + /* FIXME where to put cursor now ? */ + } } - else if (format & SF_TEXT) - ME_StreamInText(editor, format, stream, style); - else - ERR("EM_STREAMIN without SF_TEXT or SF_RTF\n"); - /* put the cursor at the top */ - if (!(format & SFF_SELECTION)) - SendMessageA(editor->hWnd, EM_SETSEL, 0, 0); - else + + editor->nUndoMode = nUndoMode; + pUI = ME_AddUndoItem(editor, diUndoDeleteRun, NULL); + TRACE("from %d to %d\n", from, to); + if (pUI && from < to) { - /* FIXME where to put cursor now ? */ + pUI->nStart = from; + pUI->nLen = to-from; } - ME_ReleaseStyle(style); + ME_CommitUndo(editor); + ME_ReleaseStyle(style); + editor->nEventMask = nEventMask; + InvalidateRect(editor->hWnd, NULL, TRUE); + ME_UpdateRepaint(editor); + if (!(format & SFF_SELECTION)) { + ME_ClearTempStyle(editor); + } + ME_MoveCaret(editor); + ME_SendSelChange(editor);
return 0; }
+ +ME_DisplayItem * +ME_FindItemAtOffset(ME_TextEditor *editor, ME_DIType nItemType, int nOffset, int *nItemOffset) +{ + ME_DisplayItem *item = ME_FindItemFwd(editor->pBuffer->pFirst, diParagraph); + + while (item && item->member.para.next_para->member.para.nCharOfs <= nOffset) + item = ME_FindItemFwd(item, diParagraph); + + if (!item) + return item; + + nOffset -= item->member.para.nCharOfs; + if (nItemType == diParagraph) { + if (nItemOffset) + *nItemOffset = nOffset; + return item; + } + + do { + item = ME_FindItemFwd(item, diRun); + } while (item && (item->member.run.nCharOfs + ME_StrLen(item->member.run.strText) <= nOffset)); + if (item) { + nOffset -= item->member.run.nCharOfs; + if (nItemOffset) + *nItemOffset = nOffset; + } + return item; +} + + ME_TextEditor *ME_MakeEditor(HWND hWnd) { ME_TextEditor *ed = ALLOC_OBJ(ME_TextEditor); HDC hDC; @@ -340,7 +632,6 @@ ed->pCursors[1].pRun = ME_FindItemFwd(ed->pBuffer->pFirst, diRun); ed->pCursors[1].nOffset = 0; ed->nLastTotalLength = ed->nTotalLength = 0; - ed->nScrollPos = 0; ed->nUDArrowX = -1; ed->nSequence = 0; ed->rgbBackColor = -1; @@ -351,6 +642,7 @@ ed->nUndoMode = umAddToUndo; ed->nParagraphs = 1; ed->nLastSelStart = ed->nLastSelEnd = 0; + ed->nScrollPosY = 0; for (i=0; i<HFONT_CACHE_SIZE; i++) { ed->pFontCache[i].nRefs = 0; @@ -361,6 +653,70 @@ return ed; }
+typedef struct tagME_GlobalDestStruct +{ + HGLOBAL hData; + int nLength; +} ME_GlobalDestStruct; + +static DWORD CALLBACK ME_AppendToHGLOBAL(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb) +{ + ME_GlobalDestStruct *pData = (ME_GlobalDestStruct *)dwCookie; + int nMaxSize; + BYTE *pDest; + + nMaxSize = GlobalSize(pData->hData); + if (pData->nLength+cb+1 >= cb) + { + /* round up to 2^17 */ + int nNewSize = (((nMaxSize+cb+1)|0x1FFFF)+1) & 0xFFFE0000; + pData->hData = GlobalReAlloc(pData->hData, nNewSize, 0); + } + pDest = (BYTE *)GlobalLock(pData->hData); + memcpy(pDest + pData->nLength, lpBuff, cb); + pData->nLength += cb; + pDest[pData->nLength] = '\0'; + GlobalUnlock(pData->hData); + *pcb = cb; + + return 0; +} + +static DWORD CALLBACK ME_ReadFromHGLOBALUnicode(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb) +{ + ME_GlobalDestStruct *pData = (ME_GlobalDestStruct *)dwCookie; + int i; + WORD *pSrc, *pDest; + + cb = cb >> 1; + pDest = (WORD *)lpBuff; + pSrc = (WORD *)GlobalLock(pData->hData); + for (i = 0; i<cb && pSrc[pData->nLength+i]; i++) { + pDest[i] = pSrc[pData->nLength+i]; + } + pData->nLength += i; + *pcb = 2*i; + GlobalUnlock(pData->hData); + return 0; +} + +static DWORD CALLBACK ME_ReadFromHGLOBALRTF(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb) +{ + ME_GlobalDestStruct *pData = (ME_GlobalDestStruct *)dwCookie; + int i; + BYTE *pSrc, *pDest; + + pDest = lpBuff; + pSrc = (BYTE *)GlobalLock(pData->hData); + for (i = 0; i<cb && pSrc[pData->nLength+i]; i++) { + pDest[i] = pSrc[pData->nLength+i]; + } + pData->nLength += i; + *pcb = i; + GlobalUnlock(pData->hData); + return 0; +} + void ME_DestroyEditor(ME_TextEditor *editor) { ME_DisplayItem *pFirst = editor->pBuffer->pFirst; @@ -401,7 +757,6 @@ switch(msg) {
UNSUPPORTED_MSG(EM_AUTOURLDETECT) - UNSUPPORTED_MSG(EM_CANPASTE) UNSUPPORTED_MSG(EM_CHARFROMPOS) UNSUPPORTED_MSG(EM_DISPLAYBAND) UNSUPPORTED_MSG(EM_EXLIMITTEXT) @@ -448,9 +803,7 @@ UNSUPPORTED_MSG(EM_SETUNDOLIMIT) UNSUPPORTED_MSG(EM_SETWORDBREAKPROC) UNSUPPORTED_MSG(EM_SETWORDBREAKPROCEX) - UNSUPPORTED_MSG(EM_STREAMOUT) UNSUPPORTED_MSG(WM_SETFONT) - UNSUPPORTED_MSG(WM_PASTE) UNSUPPORTED_MSG(WM_STYLECHANGING) UNSUPPORTED_MSG(WM_STYLECHANGED) /* UNSUPPORTED_MSG(WM_UNICHAR) FIXME missing in Wine headers */ @@ -459,6 +812,8 @@
case EM_STREAMIN: return ME_StreamIn(editor, wParam, (EDITSTREAM*)lParam); + case EM_STREAMOUT: + return ME_StreamOut(editor, wParam, (EDITSTREAM *)lParam); case WM_GETDLGCODE: { UINT code = DLGC_WANTCHARS|DLGC_WANTARROWS; @@ -557,6 +912,7 @@ case EM_SETCHARFORMAT: { CHARFORMAT2W buf, *p; + BOOL bRepaint = TRUE; p = ME_ToCF2W(&buf, (CHARFORMAT2W *)lParam); if (!wParam) ME_SetDefaultCharFormat(editor, p); @@ -564,10 +920,15 @@ FIXME("word selection not supported\n"); else if (wParam == SCF_ALL) ME_SetCharFormat(editor, 0, ME_GetTextLength(editor), p); - else + else { + int from, to; + ME_GetSelection(editor, &from, &to); + bRepaint = (from != to); ME_SetSelectionCharFormat(editor, p); + } ME_CommitUndo(editor); - ME_UpdateRepaint(editor); + if (bRepaint) + ME_UpdateRepaint(editor); return 0; } case EM_GETCHARFORMAT: @@ -583,6 +944,7 @@ } case EM_SETPARAFORMAT: ME_SetSelectionParaFormat(editor, (PARAFORMAT2 *)lParam); + ME_UpdateRepaint(editor); ME_CommitUndo(editor); return 0; case EM_GETPARAFORMAT: @@ -635,12 +997,49 @@ ME_UpdateRepaint(editor); return 0; } + case EM_CANPASTE: [truncated at 1000 lines; 4802 more skipped]