diff --git a/reactos/lib/riched20/Makefile.in b/reactos/lib/riched20/Makefile.in index 03602d91916..9cc9fe9844b 100644 --- a/reactos/lib/riched20/Makefile.in +++ b/reactos/lib/riched20/Makefile.in @@ -20,7 +20,8 @@ C_SRCS = \ string.c \ style.c \ undo.c \ - wrap.c + wrap.c \ + writer.c @MAKE_DLL_RULES@ diff --git a/reactos/lib/riched20/caret.c b/reactos/lib/riched20/caret.c index e3ba8b101f0..8181f0a385f 100644 --- a/reactos/lib/riched20/caret.c +++ b/reactos/lib/riched20/caret.c @@ -104,15 +104,15 @@ void ME_MoveCaret(ME_TextEditor *editor) { 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.pt.y-pSizeRun->member.run.nAscent-GetScrollPos(editor->hWnd, SB_VERT)); + para->member.para.nYPos+row->member.row.nBaseline+pSizeRun->member.run.pt.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 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, 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 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, 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 @@ BOOL ME_ArrowLeft(ME_TextEditor *editor, ME_Cursor *p) } assert(0); } + return FALSE; } BOOL ME_ArrowRight(ME_TextEditor *editor, ME_Cursor *p) @@ -537,7 +552,7 @@ void ME_LButtonDown(ME_TextEditor *editor, int x, int y) 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 @@ void ME_MouseMove(ME_TextEditor *editor, int x, int y) { 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 @@ void ME_ArrowDown(ME_TextEditor *editor, ME_Cursor *pCursor) 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,43 +917,42 @@ BOOL ME_CancelSelection(ME_TextEditor *editor, int dir) 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) @@ -898,6 +1015,16 @@ BOOL ME_ArrowKey(ME_TextEditor *editor, int nVKey, int nCtrl) 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 @@ BOOL ME_ArrowKey(ME_TextEditor *editor, int nVKey, int nCtrl) } 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 @@ BOOL ME_ArrowKey(ME_TextEditor *editor, int nVKey, int nCtrl) 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; } diff --git a/reactos/lib/riched20/editor.c b/reactos/lib/riched20/editor.c index eec98474719..33eb9ecde71 100644 --- a/reactos/lib/riched20/editor.c +++ b/reactos/lib/riched20/editor.c @@ -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 -#include -#include +#include "ole2.h" +#include "richole.h" +#include "winreg.h" #define NO_SHLWAPI_STREAM -#include +#include "shlwapi.h" #include "rtf.h" @@ -238,91 +233,388 @@ ME_TextBuffer *ME_MakeText() { 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 (nDataSizedwSize >> 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; + + 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 (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); - - /* do the parsing */ - RTFRead(&parser); - RTFFlushOutputBuffer(&parser); - } - 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 + if (!inStream.editstream->dwError) { - /* FIXME where to put cursor now ? */ + 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); + 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 ? */ + } } - ME_ReleaseStyle(style); + + editor->nUndoMode = nUndoMode; + pUI = ME_AddUndoItem(editor, diUndoDeleteRun, NULL); + TRACE("from %d to %d\n", from, to); + if (pUI && from < to) + { + pUI->nStart = from; + pUI->nLen = to-from; + } + 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 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) { 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 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) { ed->nUndoMode = umAddToUndo; ed->nParagraphs = 1; ed->nLastSelStart = ed->nLastSelEnd = 0; + ed->nScrollPosY = 0; for (i=0; ipFontCache[i].nRefs = 0; @@ -361,6 +653,70 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) { 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; inLength+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; inLength+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 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP 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 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP 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 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP 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 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP 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 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP 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 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP } case EM_SETPARAFORMAT: ME_SetSelectionParaFormat(editor, (PARAFORMAT2 *)lParam); + ME_UpdateRepaint(editor); ME_CommitUndo(editor); return 0; case EM_GETPARAFORMAT: @@ -635,12 +997,49 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP ME_UpdateRepaint(editor); return 0; } + case EM_CANPASTE: + { + UINT nRTFFormat = RegisterClipboardFormatA("Rich Text Format"); + if (IsClipboardFormatAvailable(nRTFFormat)) + return TRUE; + if (IsClipboardFormatAvailable(CF_UNICODETEXT)) + return TRUE; + return FALSE; + } + case WM_PASTE: + { + DWORD dwFormat = 0; + EDITSTREAM es; + ME_GlobalDestStruct gds; + UINT nRTFFormat = RegisterClipboardFormatA("Rich Text Format"); + UINT cf = 0; + + if (IsClipboardFormatAvailable(nRTFFormat)) + cf = nRTFFormat, dwFormat = SF_RTF; + else if (IsClipboardFormatAvailable(CF_UNICODETEXT)) + cf = CF_UNICODETEXT, dwFormat = SF_TEXT|SF_UNICODE; + else + return 0; + + if (!OpenClipboard(hWnd)) + return 0; + gds.hData = GetClipboardData(cf); + gds.nLength = 0; + es.dwCookie = (DWORD)&gds; + es.pfnCallback = dwFormat == SF_RTF ? ME_ReadFromHGLOBALRTF : ME_ReadFromHGLOBALUnicode; + SendMessageW(hWnd, EM_STREAMIN, dwFormat|SFF_SELECTION, (LPARAM)&es); + + CloseClipboard(); + return 0; + } case WM_CUT: case WM_COPY: { int from, to, pars; WCHAR *data; HANDLE hData; + EDITSTREAM es; + ME_GlobalDestStruct gds; if (!OpenClipboard(hWnd)) return 0; @@ -652,7 +1051,17 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP data = (WCHAR *)GlobalLock(hData); ME_GetTextW(editor, data, from, to-from, TRUE); GlobalUnlock(hData); - SetClipboardData(CF_UNICODETEXT, hData); + + gds.hData = GlobalAlloc(GMEM_MOVEABLE, 0); + gds.nLength = 0; + es.dwCookie = (DWORD)&gds; + es.pfnCallback = ME_AppendToHGLOBAL; + SendMessageW(hWnd, EM_STREAMOUT, SFF_SELECTION|SF_RTF, (LPARAM)&es); + GlobalReAlloc(gds.hData, gds.nLength+1, 0); + + SetClipboardData(CF_UNICODETEXT, hData); + SetClipboardData(RegisterClipboardFormatA("Rich Text Format"), gds.hData); + CloseClipboard(); if (msg == WM_CUT) { @@ -785,7 +1194,7 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP return 0; /* FIXME really 0 ? */ } wstr = LOWORD(wParam); - if (((unsigned)wstr)>=' ' || wstr=='\r') { + if (((unsigned)wstr)>=' ' || wstr=='\r' || wstr=='\t') { /* FIXME maybe it would make sense to call EM_REPLACESEL instead ? */ ME_Style *style = ME_GetInsertStyle(editor, 0); ME_SaveTempStyle(editor); @@ -798,22 +1207,69 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP } case WM_VSCROLL: { + int nPos = editor->nScrollPosY; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_PAGE|SIF_POS|SIF_RANGE|SIF_TRACKPOS; GetScrollInfo(hWnd, SB_VERT, &si); switch(LOWORD(wParam)) { - case SB_THUMBTRACK: - SetScrollPos(hWnd, SB_VERT, si.nTrackPos, FALSE); - ScrollWindow(hWnd, 0, si.nPos-si.nTrackPos, NULL, NULL); - /* InvalidateRect(hWnd, NULL, TRUE); */ - UpdateWindow(hWnd); + case SB_LINEUP: + nPos -= 24; /* FIXME follow the original */ + if (nPos<0) nPos = 0; break; + case SB_LINEDOWN: + { + int nEnd = editor->nTotalLength - editor->sizeWindow.cy; + nPos += 24; /* FIXME follow the original */ + if (nPos>=nEnd) nPos = nEnd; + break; + } + case SB_PAGEUP: + nPos -= editor->sizeWindow.cy; + if (nPos<0) nPos = 0; + break; + case SB_PAGEDOWN: + nPos += editor->sizeWindow.cy; + if (nPos>=editor->nTotalLength) nPos = editor->nTotalLength-1; + break; + case SB_THUMBTRACK: + case SB_THUMBPOSITION: + nPos = si.nTrackPos; + break; + } + if (nPos != editor->nScrollPosY) { + ScrollWindow(hWnd, 0, editor->nScrollPosY-nPos, NULL, NULL); + editor->nScrollPosY = nPos; + SetScrollPos(hWnd, SB_VERT, nPos, TRUE); + UpdateWindow(hWnd); + } + break; + } + case WM_MOUSEWHEEL: + { + int gcWheelDelta = 0, nPos = editor->nScrollPosY; + UINT pulScrollLines; + + SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0); + gcWheelDelta -= GET_WHEEL_DELTA_WPARAM(wParam); + if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines) + nPos += pulScrollLines * (gcWheelDelta / WHEEL_DELTA) * 8; + if(nPos>=editor->nTotalLength) + nPos = editor->nTotalLength - 1; + if (nPos<0) + nPos = 0; + if (nPos != editor->nScrollPosY) { + ScrollWindow(hWnd, 0, editor->nScrollPosY-nPos, NULL, NULL); + editor->nScrollPosY = nPos; + SetScrollPos(hWnd, SB_VERT, nPos, TRUE); + UpdateWindow(hWnd); } break; } case WM_SIZE: { ME_MarkAllForWrapping(editor); + ME_WrapMarkedParagraphs(editor); + ME_UpdateScrollBar(editor); ME_Repaint(editor); return DefWindowProcW(hWnd, msg, wParam, lParam); } @@ -861,26 +1317,18 @@ int ME_CountParagraphsBetween(ME_TextEditor *editor, int from, int to) return i; } + int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, int bCRLF) { - ME_DisplayItem *item = ME_FindItemFwd(editor->pBuffer->pFirst, diParagraph); + ME_DisplayItem *item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart); int nWritten = 0; - while(item && item->member.para.next_para->member.para.nCharOfs <= nStart) - item = ME_FindItemFwd(item, diParagraph); if (!item) { *buffer = L'\0'; return 0; } - nStart -= item->member.para.nCharOfs; - - do { - item = ME_FindItemFwd(item, diRun); - } while(item && (item->member.run.nCharOfs + ME_StrLen(item->member.run.strText) <= nStart)); assert(item); - nStart -= item->member.run.nCharOfs; - if (nStart) { int nLen = ME_StrLen(item->member.run.strText) - nStart; diff --git a/reactos/lib/riched20/editor.h b/reactos/lib/riched20/editor.h index 8749fd2a04f..5cbcfbde224 100644 --- a/reactos/lib/riched20/editor.h +++ b/reactos/lib/riched20/editor.h @@ -20,8 +20,8 @@ #include "editstr.h" -#define ALLOC_OBJ(type) (type *)HeapAlloc(me_heap, 0, sizeof(type)) -#define ALLOC_N_OBJ(type, count) (type *)HeapAlloc(me_heap, 0, count*sizeof(type)) +#define ALLOC_OBJ(type) HeapAlloc(me_heap, 0, sizeof(type)) +#define ALLOC_N_OBJ(type, count) HeapAlloc(me_heap, 0, (count)*sizeof(type)) #define FREE_OBJ(ptr) HeapFree(me_heap, 0, ptr) /* style.c */ @@ -85,6 +85,10 @@ void ME_EndToUnicode(HWND hWnd, LPVOID psz); LPSTR ME_ToAnsi(HWND hWnd, LPVOID psz); void ME_EndToAnsi(HWND hWnd, LPVOID psz); +static inline int ME_IsWSpace(WCHAR ch) +{ + return ch > '\0' && ch <= ' '; +} /* note: those two really return the first matching offset (starting from EOS)+1 * in other words, an offset of the first trailing white/black */ @@ -104,7 +108,7 @@ ME_DisplayItem *ME_InsertRun(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem void ME_CheckCharOffsets(ME_TextEditor *editor); void ME_PropagateCharOffset(ME_DisplayItem *p, int shift); void ME_GetGraphicsSize(ME_TextEditor *editor, ME_Run *run, SIZE *pSize); -int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run); +int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Paragraph *para, ME_Run *run); /* this one accounts for 1/2 char tolerance */ int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run); int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset); @@ -116,8 +120,8 @@ ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, i int ME_FindSplitPoint(ME_Context *c, POINT *pt, ME_Run *run, int desperate); void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run); ME_DisplayItem *ME_SplitFurther(ME_TextEditor *editor, ME_DisplayItem *run); -void ME_CalcRunExtent(ME_Context *c, ME_Run *run); -SIZE ME_GetRunSize(ME_Context *c, ME_Run *run, int nLen); +void ME_CalcRunExtent(ME_Context *c, ME_Paragraph *para, ME_Run *run); +SIZE ME_GetRunSize(ME_Context *c, ME_Paragraph *para, ME_Run *run, int nLen); void ME_CursorFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_Cursor *pCursor); void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **ppRun, int *pOfs); int ME_CharOfsFromRunOfs(ME_TextEditor *editor, ME_DisplayItem *pRun, int nOfs); @@ -157,13 +161,14 @@ void ME_InsertGraphicsFromCursor(ME_TextEditor *editor, int nCursor); void ME_InternalDeleteText(ME_TextEditor *editor, int nOfs, int nChars); int ME_GetTextLength(ME_TextEditor *editor); ME_Style *ME_GetSelectionInsertStyle(ME_TextEditor *editor); +BOOL ME_UpdateSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor); /* wrap.c */ void ME_PrepareParagraphForWrapping(ME_Context *c, ME_DisplayItem *tp); ME_DisplayItem *ME_MakeRow(int height, int baseline, int width); void ME_InsertRowStart(ME_WrapContext *wc, ME_DisplayItem *pEnd); void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp); -void ME_WrapMarkedParagraphs(ME_TextEditor *editor); +BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor); /* para.c */ ME_DisplayItem *ME_GetParagraph(ME_DisplayItem *run); @@ -185,10 +190,11 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, RECT *rcUpda void ME_Repaint(ME_TextEditor *editor); void ME_UpdateRepaint(ME_TextEditor *editor); void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph); -void ME_UpdateScrollBar(ME_TextEditor *editor, int ypos); -int ME_GetScrollPos(ME_TextEditor *editor); +void ME_UpdateScrollBar(ME_TextEditor *editor); +int ME_GetYScrollPos(ME_TextEditor *editor); void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun); COLORREF ME_GetBackColor(ME_TextEditor *editor); +void ME_Scroll(ME_TextEditor *editor, int cx, int cy); /* richole.c */ extern LRESULT CreateIRichEditOle(LPVOID *); @@ -206,7 +212,12 @@ 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); extern int me_debug; extern HANDLE me_heap; extern void DoWrap(ME_TextEditor *editor); + +/* writer.c */ +LRESULT ME_StreamOut(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM *stream); diff --git a/reactos/lib/riched20/editstr.h b/reactos/lib/riched20/editstr.h index d1f48198303..00329fb9628 100644 --- a/reactos/lib/riched20/editstr.h +++ b/reactos/lib/riched20/editstr.h @@ -86,6 +86,8 @@ typedef enum { #define MERF_STYLEFLAGS 0x0FFF /* run contains non-text content, which has its own rules for wrapping, sizing etc */ #define MERF_GRAPHICS 1 +/* run is a tab (or, in future, any kind of content whose size is dependent on run position) */ +#define MERF_TAB 2 /* run is splittable (contains white spaces in the middle or end) */ #define MERF_SPLITTABLE 0x001000 @@ -102,6 +104,11 @@ typedef enum { /* the "end of paragraph" run, contains 1 character */ #define MERF_ENDPARA 0x100000 +/* runs with any of these flags set cannot be joined */ +#define MERF_NOJOIN (MERF_GRAPHICS|MERF_TAB|MERF_ENDPARA) +/* runs that don't contain real text */ +#define MERF_NOTEXT (MERF_GRAPHICS|MERF_TAB|MERF_ENDPARA) + /* those flags are kept when the row is split */ #define MERF_SPLITMASK (~(0)) @@ -192,6 +199,40 @@ typedef enum { umAddBackToUndo } ME_UndoMode; +typedef struct tagME_FontTableItem { + BYTE bCharSet; + WCHAR *szFaceName; +} ME_FontTableItem; + + +#define STREAMIN_BUFFER_SIZE 4096 /* M$ compatibility */ + +struct tagME_InStream { + EDITSTREAM *editstream; + DWORD dwSize; + DWORD dwUsed; + BYTE buffer[STREAMIN_BUFFER_SIZE]; +}; +typedef struct tagME_InStream ME_InStream; + + +#define STREAMOUT_BUFFER_SIZE 4096 +#define STREAMOUT_FONTTBL_SIZE 8192 +#define STREAMOUT_COLORTBL_SIZE 1024 + +typedef struct tagME_OutStream { + EDITSTREAM *stream; + char buffer[STREAMOUT_BUFFER_SIZE]; + UINT pos, written; + UINT nCodePage; + UINT nFontTblLen; + ME_FontTableItem fonttbl[STREAMOUT_FONTTBL_SIZE]; + UINT nColorTblLen; + COLORREF colortbl[STREAMOUT_COLORTBL_SIZE]; + UINT nDefaultFont; + UINT nDefaultCodePage; +} ME_OutStream; + typedef struct tagME_FontCacheItem { LOGFONTW lfSpecs; @@ -210,7 +251,6 @@ typedef struct tagME_TextEditor ME_Cursor *pCursors; int nCursors; SIZE sizeWindow; - int nScrollPos; int nTotalLength, nLastTotalLength; int nUDArrowX; int nSequence; @@ -224,6 +264,9 @@ typedef struct tagME_TextEditor int nParagraphs; int nLastSelStart, nLastSelEnd; ME_FontCacheItem pFontCache[HFONT_CACHE_SIZE]; + ME_OutStream *pStream; + BOOL bScrollX, bScrollY; + int nScrollPosY; } ME_TextEditor; typedef struct tagME_Context diff --git a/reactos/lib/riched20/paint.c b/reactos/lib/riched20/paint.c index 90b8d9d36c6..7d5e387d20d 100644 --- a/reactos/lib/riched20/paint.c +++ b/reactos/lib/riched20/paint.c @@ -28,14 +28,16 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, RECT *rcUpda int yoffset; editor->nSequence++; - yoffset = GetScrollPos(editor->hWnd, SB_VERT); + yoffset = ME_GetYScrollPos(editor); ME_InitContext(&c, editor, hDC); SetBkMode(hDC, TRANSPARENT); ME_MoveCaret(editor); item = editor->pBuffer->pFirst->next; c.pt.y -= yoffset; while(item != editor->pBuffer->pLast) { + int ye; assert(item->type == diParagraph); + ye = c.pt.y + item->member.para.nHeight; if (!bOnlyNew || (item->member.para.nFlags & MEPF_REPAINT)) { BOOL bPaint = (rcUpdate == NULL); @@ -45,10 +47,11 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, RECT *rcUpda if (bPaint) { ME_DrawParagraph(&c, item); - item->member.para.nFlags &= ~MEPF_REPAINT; + if (!rcUpdate || (rcUpdate->top<=c.pt.y && rcUpdate->bottom>=ye)) + item->member.para.nFlags &= ~MEPF_REPAINT; } } - c.pt.y += item->member.para.nHeight; + c.pt.y = ye; item = item->member.para.next_para; } if (c.pt.ypRun, pCursor->nOffset); + ME_RunOfsFromCharOfs(editor, nCharOfs, &pRun, &nOffset); assert(pRun == pCursor->pRun); assert(nOffset == pCursor->nOffset); ME_MarkSelectionForRepaint(editor); - ME_WrapMarkedParagraphs(editor); + if (ME_WrapMarkedParagraphs(editor)) { + ME_UpdateScrollBar(editor); + } hDC = GetDC(editor->hWnd); ME_HideCaret(editor); ME_PaintContent(editor, hDC, TRUE, NULL); ReleaseDC(editor->hWnd, hDC); ME_ShowCaret(editor); + ME_EnsureVisible(editor, pCursor->pRun); } void ME_UpdateRepaint(ME_TextEditor *editor) @@ -244,6 +250,9 @@ void ME_DrawRun(ME_Context *c, int x, int y, ME_DisplayItem *rundi, ME_Paragraph ME_Run *run = &rundi->member.run; int runofs = run->nCharOfs+para->nCharOfs; + /* you can always comment it out if you need visible paragraph marks */ + if (run->nFlags & (MERF_ENDPARA|MERF_TAB)) + return; if (run->nFlags & MERF_GRAPHICS) { int blfrom, blto; ME_GetSelection(c->editor, &blfrom, &blto); @@ -302,19 +311,19 @@ void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) { visible = RectVisible(c->hDC, &rcPara); if (visible) { HBRUSH hbr; + hbr = CreateSolidBrush(ME_GetBackColor(c->editor)); /* left margin */ rc.left = c->rcView.left; rc.right = c->rcView.left+nMargWidth; rc.top = y; rc.bottom = y+p->member.row.nHeight; - FillRect(c->hDC, &rc, c->hbrMargin); + FillRect(c->hDC, &rc, hbr/* c->hbrMargin */); /* right margin */ rc.left = xe; rc.right = c->rcView.right; - FillRect(c->hDC, &rc, c->hbrMargin); - rc.left = c->rcView.left+para->nLeftMargin; + FillRect(c->hDC, &rc, hbr/* c->hbrMargin */); + rc.left = c->rcView.left+nMargWidth; rc.right = xe; - hbr = CreateSolidBrush(ME_GetBackColor(c->editor)); FillRect(c->hDC, &rc, hbr); DeleteObject(hbr); } @@ -369,62 +378,103 @@ void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) { SetTextAlign(c->hDC, align); } -void ME_UpdateScrollBar(ME_TextEditor *editor, int ypos) +void ME_Scroll(ME_TextEditor *editor, int cx, int cy) { - float perc = 0.0; SCROLLINFO si; HWND hWnd = editor->hWnd; - int overflow = editor->nTotalLength - editor->sizeWindow.cy; - si.cbSize = sizeof(SCROLLINFO); - si.fMask = SIF_PAGE|SIF_POS|SIF_RANGE|SIF_TRACKPOS; - GetScrollInfo(hWnd, SB_VERT, &si); - - if (ypos < 0) { - if (si.nMax<1) si.nMax = 1; - perc = 1.0*si.nPos/si.nMax; - ypos = perc*overflow; - } - if (ypos >= overflow && overflow > 0) - ypos = overflow - 1; - if (overflow > 0) { - EnableScrollBar(hWnd, SB_VERT, ESB_ENABLE_BOTH); - SetScrollRange(hWnd, SB_VERT, 0, overflow, FALSE); - SetScrollPos(hWnd, SB_VERT, ypos, TRUE); - } else { - EnableScrollBar(hWnd, SB_VERT, ESB_DISABLE_BOTH); - SetScrollRange(hWnd, SB_VERT, 0, 0, FALSE); - SetScrollPos(hWnd, SB_VERT, 0, TRUE); - } - if (ypos != si.nPos) + si.cbSize = sizeof(SCROLLINFO); + si.fMask = SIF_POS; + GetScrollInfo(hWnd, SB_VERT, &si); + si.nPos = editor->nScrollPosY -= cy; + SetScrollInfo(hWnd, SB_VERT, &si, TRUE); + if (abs(cy) > editor->sizeWindow.cy) + InvalidateRect(editor->hWnd, NULL, TRUE); + else + ScrollWindowEx(hWnd, cx, cy, NULL, NULL, NULL, NULL, SW_ERASE|SW_INVALIDATE); +} + +void ME_UpdateScrollBar(ME_TextEditor *editor) +{ + HWND hWnd = editor->hWnd; + SCROLLINFO si; + int nOldLen = editor->nTotalLength; + BOOL bScrollY = (editor->nTotalLength > editor->sizeWindow.cy); + BOOL bUpdateScrollBars; + si.cbSize = sizeof(si); + si.fMask = SIF_POS | SIF_RANGE; + GetScrollInfo(hWnd, SB_VERT, &si); + bUpdateScrollBars = (bScrollY || editor->bScrollY)&& ((si.nMax != nOldLen) || (si.nPage != editor->sizeWindow.cy)); + + if (bScrollY != editor->bScrollY) { - TRACE("ScrollWindow(%d, %d, %d, %0.4f)\n", si.nPos, si.nMax, ypos, perc); - ScrollWindow(hWnd, 0, si.nPos - ypos, NULL, NULL); - UpdateWindow(hWnd); + si.fMask = SIF_RANGE | SIF_PAGE; + si.nMin = 0; + si.nPage = editor->sizeWindow.cy; + if (bScrollY) { + si.nMax = editor->nTotalLength; + } else { + si.nMax = 0; + } + SetScrollInfo(hWnd, SB_VERT, &si, FALSE); + ME_MarkAllForWrapping(editor); + editor->bScrollY = bScrollY; + ME_WrapMarkedParagraphs(editor); + bUpdateScrollBars = TRUE; + } + if (bUpdateScrollBars) { + int nScroll = 0; + si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; + if (editor->nTotalLength > editor->sizeWindow.cy) { + si.nMax = editor->nTotalLength; + si.nPage = editor->sizeWindow.cy; + if (si.nPos > si.nMax-si.nPage) { + nScroll = (si.nMax-si.nPage)-si.nPos; + si.nPos = si.nMax-si.nPage; + } + } + else { + si.nMax = 0; + si.nPage = 0; + si.nPos = 0; + } + TRACE("min=%d max=%d page=%d pos=%d shift=%d\n", si.nMin, si.nMax, si.nPage, si.nPos, nScroll); + editor->nScrollPosY = si.nPos; + SetScrollInfo(hWnd, SB_VERT, &si, TRUE); + if (nScroll) + ScrollWindow(hWnd, 0, -nScroll, NULL, NULL); } } -int ME_GetScrollPos(ME_TextEditor *editor) +int ME_GetYScrollPos(ME_TextEditor *editor) { - return GetScrollPos(editor->hWnd, SB_VERT); + return editor->nScrollPosY; } void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun) { ME_DisplayItem *pRow = ME_FindItemBack(pRun, diStartRow); ME_DisplayItem *pPara = ME_FindItemBack(pRun, diParagraph); - int y, yrel, yheight; + int y, yrel, yheight, yold; + HWND hWnd = editor->hWnd; assert(pRow); assert(pPara); y = pPara->member.para.nYPos+pRow->member.row.nYPos; yheight = pRow->member.row.nHeight; - yrel = y - ME_GetScrollPos(editor); - if (yrel < 0) - ME_UpdateScrollBar(editor, y); - else if (yrel + yheight > editor->sizeWindow.cy) - { - ME_UpdateScrollBar(editor, y + yheight - editor->sizeWindow.cy); + yold = ME_GetYScrollPos(editor); + yrel = y - yold; + if (yrel < 0) { + editor->nScrollPosY = y; + SetScrollPos(hWnd, SB_VERT, y, TRUE); + ScrollWindow(hWnd, 0, -yrel, NULL, NULL); + UpdateWindow(hWnd); + } else if (yrel + yheight > editor->sizeWindow.cy) { + int newy = y+yheight-editor->sizeWindow.cy; + editor->nScrollPosY = newy; + SetScrollPos(hWnd, SB_VERT, newy, TRUE); + ScrollWindow(hWnd, 0, -(newy-yold), NULL, NULL); + UpdateWindow(hWnd); } } diff --git a/reactos/lib/riched20/para.c b/reactos/lib/riched20/para.c index ecd8e49e58b..4b1947ce797 100644 --- a/reactos/lib/riched20/para.c +++ b/reactos/lib/riched20/para.c @@ -57,7 +57,7 @@ void ME_MakeFirstParagraph(HDC hDC, ME_TextBuffer *text) ZeroMemory(&fmt, sizeof(fmt)); fmt.cbSize = sizeof(fmt); - fmt.dwMask = PFM_ALIGNMENT | PFM_OFFSET | PFM_STARTINDENT | PFM_RIGHTINDENT; + fmt.dwMask = PFM_ALIGNMENT | PFM_OFFSET | PFM_STARTINDENT | PFM_RIGHTINDENT | PFM_TABSTOPS; CopyMemory(para->member.para.pFmt, &fmt, sizeof(PARAFORMAT2)); @@ -282,6 +282,18 @@ void ME_SetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, PARAFORMAT2 * if (pFmt->dwMask & PFM_ALIGNMENT) para->member.para.pFmt->wAlignment = pFmt->wAlignment; + if (pFmt->dwMask & PFM_STARTINDENT) + para->member.para.pFmt->dxStartIndent = pFmt->dxStartIndent; + if (pFmt->dwMask & PFM_OFFSET) + para->member.para.pFmt->dxOffset = pFmt->dxOffset; + if (pFmt->dwMask & PFM_OFFSETINDENT) + para->member.para.pFmt->dxStartIndent += pFmt->dxStartIndent; + + if (pFmt->dwMask & PFM_TABSTOPS) + { + para->member.para.pFmt->cTabCount = pFmt->cTabCount; + memcpy(para->member.para.pFmt->rgxTabs, pFmt->rgxTabs, pFmt->cTabCount*sizeof(int)); + } /* FIXME to be continued (indents, bulleting and such) */ @@ -310,7 +322,6 @@ void ME_SetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt) break; para = para->member.para.next_para; } while(1); - ME_Repaint(editor); } void ME_GetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, PARAFORMAT2 *pFmt) @@ -346,11 +357,28 @@ void ME_GetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt) ZeroMemory(&tmp, sizeof(tmp)); tmp.cbSize = sizeof(tmp); ME_GetParaFormat(editor, para, &tmp); - assert(tmp.dwMask & PFM_ALIGNMENT); + assert(tmp.dwMask & PFM_ALIGNMENT); if (pFmt->wAlignment != tmp.wAlignment) pFmt->dwMask &= ~PFM_ALIGNMENT; + assert(tmp.dwMask & PFM_STARTINDENT); + if (pFmt->dxStartIndent != tmp.dxStartIndent) + pFmt->dwMask &= ~PFM_STARTINDENT; + + assert(tmp.dwMask & PFM_OFFSET); + if (pFmt->dxOffset != tmp.dxOffset) + pFmt->dwMask &= ~PFM_OFFSET; + + assert(tmp.dwMask & PFM_TABSTOPS); + if (pFmt->dwMask & PFM_TABSTOPS) { + if (pFmt->cTabCount != tmp.cTabCount) + pFmt->dwMask &= ~PFM_TABSTOPS; + else + if (memcmp(pFmt->rgxTabs, tmp.rgxTabs, tmp.cTabCount*sizeof(int))) + pFmt->dwMask &= ~PFM_TABSTOPS; + } + if (para == para_end) return; para = para->member.para.next_para; diff --git a/reactos/lib/riched20/reader.c b/reactos/lib/riched20/reader.c index 3f800b658de..caecb52f8d3 100644 --- a/reactos/lib/riched20/reader.c +++ b/reactos/lib/riched20/reader.c @@ -40,18 +40,20 @@ #include #include #include - -#include "rtf.h" +#include #include "windef.h" #include "winbase.h" #include "wine/debug.h" +#include "editor.h" +#include "rtf.h" + WINE_DEFAULT_DEBUG_CHANNEL(richedit); extern HANDLE me_heap; -static int _RTFGetChar(RTF_Info *); +static int _RTFGetChar(RTF_Info *); static void _RTFGetToken (RTF_Info *); static void _RTFGetToken2 (RTF_Info *); static int GetChar (RTF_Info *); @@ -65,910 +67,145 @@ static void LookupInit (void); static void Lookup (RTF_Info *, char *); static int Hash (char*); -static void CharSetInit (RTF_Info *); -static void ReadCharSetMaps (RTF_Info *); +static void CharAttr(RTF_Info *info); +static void CharSet(RTF_Info *info); +static void DocAttr(RTF_Info *info); +static void RTFFlushCPOutputBuffer(RTF_Info *info); +static void RTFPutCodePageChar(RTF_Info *info, int c); + +/* ---------------------------------------------------------------------- */ /* - RTF ANSI character set (\ansi) general map - These are taken from the ISO-Latin-1 (ISO-8859-1) encodings, with - a few additions - - Field 1 is the standard character name which the character value in - field 2 maps onto. (It doesn't mean "to produce the character in field 1, - use the value in field 2.) - - The character value may be given either as a single character (which will be - converted to the ASCII value of the character), or in numeric format, either - in decimal or 0xyy as hex yy. Single or double quotes may be used to quote - characters.*/ - -int ansi_gen[] = -{ - rtfSC_formula ,0x06, - rtfSC_nobrkhyphen ,0x1e, - rtfSC_opthyphen ,0x1f, - rtfSC_space ,' ', - rtfSC_exclam ,'!', - rtfSC_quotedbl ,'"', - rtfSC_numbersign ,'#', - rtfSC_dollar ,'$', - rtfSC_percent ,'%', - rtfSC_ampersand ,'&', - rtfSC_quoteright ,'\'', - rtfSC_parenleft ,'(', - rtfSC_parenright ,')', - rtfSC_asterisk ,'*', - rtfSC_plus ,'+', - rtfSC_comma ,',', - rtfSC_hyphen ,'-', - rtfSC_period ,'.', - rtfSC_slash ,'/', - rtfSC_zero ,'0', - rtfSC_one ,'1', - rtfSC_two ,'2', - rtfSC_three ,'3', - rtfSC_four ,'4', - rtfSC_five ,'5', - rtfSC_six ,'6', - rtfSC_seven ,'7', - rtfSC_eight ,'8', - rtfSC_nine ,'9', - rtfSC_colon ,':', - rtfSC_semicolon ,';', - rtfSC_less ,'<', - rtfSC_equal ,'=', - rtfSC_greater ,'>', - rtfSC_question ,'?', - rtfSC_at ,'@', - rtfSC_A ,'A', - rtfSC_B ,'B', - rtfSC_C ,'C', - rtfSC_D ,'D', - rtfSC_E ,'E', - rtfSC_F ,'F', - rtfSC_G ,'G', - rtfSC_H ,'H', - rtfSC_I ,'I', - rtfSC_J ,'J', - rtfSC_K ,'K', - rtfSC_L ,'L', - rtfSC_M ,'M', - rtfSC_N ,'N', - rtfSC_O ,'O', - rtfSC_P ,'P', - rtfSC_Q ,'Q', - rtfSC_R ,'R', - rtfSC_S ,'S', - rtfSC_T ,'T', - rtfSC_U ,'U', - rtfSC_V ,'V', - rtfSC_W ,'W', - rtfSC_X ,'X', - rtfSC_Y ,'Y', - rtfSC_Z ,'Z', - rtfSC_bracketleft ,'[', - rtfSC_backslash ,'\\', - rtfSC_bracketright ,']', - rtfSC_asciicircum ,'^', - rtfSC_underscore ,'_', - rtfSC_quoteleft ,'`', - rtfSC_a ,'a', - rtfSC_b ,'b', - rtfSC_c ,'c', - rtfSC_d ,'d', - rtfSC_e ,'e', - rtfSC_f ,'f', - rtfSC_g ,'g', - rtfSC_h ,'h', - rtfSC_i ,'i', - rtfSC_j ,'j', - rtfSC_k ,'k', - rtfSC_l ,'l', - rtfSC_m ,'m', - rtfSC_n ,'n', - rtfSC_o ,'o', - rtfSC_p ,'p', - rtfSC_q ,'q', - rtfSC_r ,'r', - rtfSC_s ,'s', - rtfSC_t ,'t', - rtfSC_u ,'u', - rtfSC_v ,'v', - rtfSC_w ,'w', - rtfSC_x ,'x', - rtfSC_y ,'y', - rtfSC_z ,'z', - rtfSC_braceleft ,'{', - rtfSC_bar ,'|', - rtfSC_braceright ,'}', - rtfSC_asciitilde ,'~', - rtfSC_nobrkspace ,0xa0, - rtfSC_exclamdown ,0xa1, - rtfSC_cent ,0xa2, - rtfSC_sterling ,0xa3, - rtfSC_currency ,0xa4, - rtfSC_yen ,0xa5, - rtfSC_brokenbar ,0xa6, - rtfSC_section ,0xa7, - rtfSC_dieresis ,0xa8, - rtfSC_copyright ,0xa9, - rtfSC_ordfeminine ,0xaa, - rtfSC_guillemotleft ,0xab, - rtfSC_logicalnot ,0xac, - rtfSC_opthyphen ,0xad, - rtfSC_registered ,0xae, - rtfSC_macron ,0xaf, - rtfSC_degree ,0xb0, - rtfSC_plusminus ,0xb1, - rtfSC_twosuperior ,0xb2, - rtfSC_threesuperior ,0xb3, - rtfSC_acute ,0xb4, - rtfSC_mu ,0xb5, - rtfSC_paragraph ,0xb6, - rtfSC_periodcentered ,0xb7, - rtfSC_cedilla ,0xb8, - rtfSC_onesuperior ,0xb9, - rtfSC_ordmasculine ,0xba, - rtfSC_guillemotright ,0xbb, - rtfSC_onequarter ,0xbc, - rtfSC_onehalf ,0xbd, - rtfSC_threequarters ,0xbe, - rtfSC_questiondown ,0xbf, - rtfSC_Agrave ,0xc0, - rtfSC_Aacute ,0xc1, - rtfSC_Acircumflex ,0xc2, - rtfSC_Atilde ,0xc3, - rtfSC_Adieresis ,0xc4, - rtfSC_Aring ,0xc5, - rtfSC_AE ,0xc6, - rtfSC_Ccedilla ,0xc7, - rtfSC_Egrave ,0xc8, - rtfSC_Eacute ,0xc9, - rtfSC_Ecircumflex ,0xca, - rtfSC_Edieresis ,0xcb, - rtfSC_Igrave ,0xcc, - rtfSC_Iacute ,0xcd, - rtfSC_Icircumflex ,0xce, - rtfSC_Idieresis ,0xcf, - rtfSC_Eth ,0xd0, - rtfSC_Ntilde ,0xd1, - rtfSC_Ograve ,0xd2, - rtfSC_Oacute ,0xd3, - rtfSC_Ocircumflex ,0xd4, - rtfSC_Otilde ,0xd5, - rtfSC_Odieresis ,0xd6, - rtfSC_multiply ,0xd7, - rtfSC_Oslash ,0xd8, - rtfSC_Ugrave ,0xd9, - rtfSC_Uacute ,0xda, - rtfSC_Ucircumflex ,0xdb, - rtfSC_Udieresis ,0xdc, - rtfSC_Yacute ,0xdd, - rtfSC_Thorn ,0xde, - rtfSC_germandbls ,0xdf, - rtfSC_agrave ,0xe0, - rtfSC_aacute ,0xe1, - rtfSC_acircumflex ,0xe2, - rtfSC_atilde ,0xe3, - rtfSC_adieresis ,0xe4, - rtfSC_aring ,0xe5, - rtfSC_ae ,0xe6, - rtfSC_ccedilla ,0xe7, - rtfSC_egrave ,0xe8, - rtfSC_eacute ,0xe9, - rtfSC_ecircumflex ,0xea, - rtfSC_edieresis ,0xeb, - rtfSC_igrave ,0xec, - rtfSC_iacute ,0xed, - rtfSC_icircumflex ,0xee, - rtfSC_idieresis ,0xef, - rtfSC_eth ,0xf0, - rtfSC_ntilde ,0xf1, - rtfSC_ograve ,0xf2, - rtfSC_oacute ,0xf3, - rtfSC_ocircumflex ,0xf4, - rtfSC_otilde ,0xf5, - rtfSC_odieresis ,0xf6, - rtfSC_divide ,0xf7, - rtfSC_oslash ,0xf8, - rtfSC_ugrave ,0xf9, - rtfSC_uacute ,0xfa, - rtfSC_ucircumflex ,0xfb, - rtfSC_udieresis ,0xfc, - rtfSC_yacute ,0xfd, - rtfSC_thorn ,0xfe, - rtfSC_ydieresis ,0xff -}; - -/* - * RTF ANSI character set (\ansi) Symbol font map - * - * Field 1 is the standard character name which the character value in - * field 2 maps onto. (It doesn't mean "to produce the character in field 1, - * use the value in field 2.) - * - * The character value may be given either as a single character (which will be - * converted to the ASCII value of the character), or in numeric format, either - * in decimal or 0xyy as hex yy. Single or double quotes may be used to quote - * characters. - * + * Memory allocation routines */ -int ansi_sym[] = -{ - rtfSC_formula ,0x06, - rtfSC_nobrkhyphen ,0x1e, - rtfSC_opthyphen ,0x1f, - rtfSC_space ,' ', - rtfSC_exclam ,'!', - rtfSC_universal ,'"', - rtfSC_mathnumbersign ,'#', - rtfSC_existential ,'$', - rtfSC_percent ,'%', - rtfSC_ampersand ,'&', - rtfSC_suchthat ,'\\', - rtfSC_parenleft ,'(', - rtfSC_parenright ,')', - rtfSC_mathasterisk ,'*', - rtfSC_mathplus ,'+', - rtfSC_comma ,',', - rtfSC_mathminus ,'-', - rtfSC_period ,'.', - rtfSC_slash ,'/', - rtfSC_zero ,'0', - rtfSC_one ,'1', - rtfSC_two ,'2', - rtfSC_three ,'3', - rtfSC_four ,'4', - rtfSC_five ,'5', - rtfSC_six ,'6', - rtfSC_seven ,'7', - rtfSC_eight ,'8', - rtfSC_nine ,'9', - rtfSC_colon ,':', - rtfSC_semicolon ,';', - rtfSC_less ,'<', - rtfSC_mathequal ,'=', - rtfSC_greater ,'>', - rtfSC_question ,'?', - rtfSC_congruent ,'@', - rtfSC_Alpha ,'A', - rtfSC_Beta ,'B', - rtfSC_Chi ,'C', - rtfSC_Delta ,'D', - rtfSC_Epsilon ,'E', - rtfSC_Phi ,'F', - rtfSC_Gamma ,'G', - rtfSC_Eta ,'H', - rtfSC_Iota ,'I', - rtfSC_Kappa ,'K', - rtfSC_Lambda ,'L', - rtfSC_Mu ,'M', - rtfSC_Nu ,'N', - rtfSC_Omicron ,'O', - rtfSC_Pi ,'P', - rtfSC_Theta ,'Q', - rtfSC_Rho ,'R', - rtfSC_Sigma ,'S', - rtfSC_Tau ,'T', - rtfSC_Upsilon ,'U', - rtfSC_varsigma ,'V', - rtfSC_Omega ,'W', - rtfSC_Xi ,'X', - rtfSC_Psi ,'Y', - rtfSC_Zeta ,'Z', - rtfSC_bracketleft ,'[', - rtfSC_backslash ,'\\', - rtfSC_bracketright ,']', - rtfSC_asciicircum ,'^', - rtfSC_underscore ,'_', - rtfSC_quoteleft ,'`', - rtfSC_alpha ,'a', - rtfSC_beta ,'b', - rtfSC_chi ,'c', - rtfSC_delta ,'d', - rtfSC_epsilon ,'e', - rtfSC_phi ,'f', - rtfSC_gamma ,'g', - rtfSC_eta ,'h', - rtfSC_iota ,'i', - rtfSC_kappa ,'k', - rtfSC_lambda ,'l', - rtfSC_mu ,'m', - rtfSC_nu ,'n', - rtfSC_omicron ,'o', - rtfSC_pi ,'p', - rtfSC_theta ,'q', - rtfSC_rho ,'r', - rtfSC_sigma ,'s', - rtfSC_tau ,'t', - rtfSC_upsilon ,'u', - rtfSC_omega ,'w', - rtfSC_xi ,'x', - rtfSC_psi ,'y', - rtfSC_zeta ,'z', - rtfSC_braceleft ,'{', - rtfSC_bar ,'|', - rtfSC_braceright ,'}', - rtfSC_mathtilde ,'~' -}; /* - * Output sequence map for rtf2text - * - * Field 1 is the standard character name. Field 2 is the output sequence - * to produce for that character. - * - * The output sequence is simply a string of characters. If it contains - * whitespace, it may be quoted. If it contains quotes, it may be quoted - * with a different quote character. - * - * characters in ASCII range (32-127 + * Return pointer to block of size bytes, or NULL if there's + * not enough memory available. */ +static inline void *RTFAlloc(int size) +{ + return HeapAlloc(me_heap, 0, size); +} + + +static inline void * RTFReAlloc(void *ptr, int size) +{ + return HeapReAlloc(me_heap, 0, ptr, size); +} -const char *text_map[] = { - "space" ," ", - "exclam" ,"!", - "quotedbl" ,"\"", - "numbersign" ,"#", - "dollar" ,"$", - "percent" ,"%", - "ampersand" ,"&", - "quoteright" ,"'", - "parenleft" ,"(", - "parenright" ,")", - "asterisk" ,"*", - "plus" ,"+", - "comma" ,",", - "hyphen" ,"-", - "period" ,".", - "slash" ,"/", - "zero" ,"0", - "one" ,"1", - "two" ,"2", - "three" ,"3", - "four" ,"4", - "five" ,"5", - "six" ,"6", - "seven" ,"7", - "eight" ,"8", - "nine" ,"9", - "colon" ,":", - "semicolon" ,";", - "less" ,"<", - "equal" ,"=", - "greater" ,">", - "question" ,"?", - "at" ,"@", - "A" ,"A", - "B" ,"B", - "C" ,"C", - "D" ,"D", - "E" ,"E", - "F" ,"F", - "G" ,"G", - "H" ,"H", - "I" ,"I", - "J" ,"J", - "K" ,"K", - "L" ,"L", - "M" ,"M", - "N" ,"N", - "O" ,"O", - "P" ,"P", - "Q" ,"Q", - "R" ,"R", - "S" ,"S", - "T" ,"T", - "U" ,"U", - "V" ,"V", - "W" ,"W", - "X" ,"X", - "Y" ,"Y", - "Z" ,"Z", - "bracketleft" ,"[", - "backslash" ,"\\", - "bracketright" ,"]", - "asciicircum" ,"^", - "underscore" ,"_", - "quoteleft" ,"`", - "a" ,"a", - "b" ,"b", - "c" ,"c", - "d" ,"d", - "e" ,"e", - "f" ,"f", - "g" ,"g", - "h" ,"h", - "i" ,"i", - "j" ,"j", - "k" ,"k", - "l" ,"l", - "m" ,"m", - "n" ,"n", - "o" ,"o", - "p" ,"p", - "q" ,"q", - "r" ,"r", - "s" ,"s", - "t" ,"t", - "u" ,"u", - "v" ,"v", - "w" ,"w", - "x" ,"x", - "y" ,"y", - "z" ,"z", - "braceleft" ,"{", - "bar" ,"|", - "braceright" ,"}", - "asciitilde" ,"~", - "AE" ,"AE", - "OE" ,"OE", - "acute" ,"'", - "ae" ,"ae", - "angleleft" ,"<", - "angleright" ,">", - "arrowboth" ,"<->", - "arrowdblboth" ,"<=>", - "arrowdblleft" ,"<=", - "arrowdblright" ,"=>", - "arrowleft" ,"<-", - "arrowright" ,"->", - "bullet" ,"o", - "cent" ,"cent", - "circumflex" ,"^", - "copyright" ,"(c)", - "copyrightsans" ,"(c)", - "degree" ,"deg.", - "divide" ,"/", - "dotlessi" ,"i", - "ellipsis" ,"...", - "emdash" ,"--", - "endash" ,"-", - "fi" ,"fi", - "fl" ,"fl", - "fraction" ,"/", - "germandbls" ,"ss", - "grave" ,"`", - "greaterequal" ,">=", - "guillemotleft" ,"<<", - "guillemotright" ,">>", - "guilsinglleft" ,"<", - "guilsinglright" ,">", - "lessequal" ,"<=", - "logicalnot" ,"~", - "mathasterisk" ,"*", - "mathequal" ,"=", - "mathminus" ,"-", - "mathnumbersign" ,"#", - "mathplus" ,"+", - "mathtilde" ,"~", - "minus" ,"-", - "mu" ,"u", - "multiply" ,"x", - "nobrkhyphen" ,"-", - "nobrkspace" ," ", - "notequal" ,"!=", - "oe" ,"oe", - "onehalf" ,"1/2", - "onequarter" ,"1/4", - "periodcentered" ,".", - "plusminus" ,"+/-", - "quotedblbase" ,",,", - "quotedblleft" ,"\"", - "quotedblright" ,"\"", - "quotesinglbase" ,",", - "registered" ,"reg.", - "registersans" ,"reg.", - "threequarters" ,"3/4", - "tilde" ,"~", - "trademark" ,"(TM)", - "trademarksans" ,"(TM)" -}; /* - * This array is used to map standard character names onto their numeric codes. - * The position of the name within the array is the code. - * stdcharnames.h is generated in the ../h directory. + * Saves a string on the heap and returns a pointer to it. */ - -const char *stdCharName[] = +static inline char *RTFStrSave(char *s) { - "nothing", - "space", - "exclam", - "quotedbl", - "numbersign", - "dollar", - "percent", - "ampersand", - "quoteright", - "parenleft", - "parenright", - "asterisk", - "plus", - "comma", - "hyphen", - "period", - "slash", - "zero", - "one", - "two", - "three", - "four", - "five", - "six", - "seven", - "eight", - "nine", - "colon", - "semicolon", - "less", - "equal", - "greater", - "question", - "at", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "bracketleft", - "backslash", - "bracketright", - "asciicircum", - "underscore", - "quoteleft", - "a", - "b", - "c", - "d", - "e", - "f", - "g", - "h", - "i", - "j", - "k", - "l", - "m", - "n", - "o", - "p", - "q", - "r", - "s", - "t", - "u", - "v", - "w", - "x", - "y", - "z", - "braceleft", - "bar", - "braceright", - "asciitilde", - "exclamdown", - "cent", - "sterling", - "fraction", - "yen", - "florin", - "section", - "currency", - "quotedblleft", - "guillemotleft", - "guilsinglleft", - "guilsinglright", - "fi", - "fl", - "endash", - "dagger", - "daggerdbl", - "periodcentered", - "paragraph", - "bullet", - "quotesinglbase", - "quotedblbase", - "quotedblright", - "guillemotright", - "ellipsis", - "perthousand", - "questiondown", - "grave", - "acute", - "circumflex", - "tilde", - "macron", - "breve", - "dotaccent", - "dieresis", - "ring", - "cedilla", - "hungarumlaut", - "ogonek", - "caron", - "emdash", - "AE", - "ordfeminine", - "Lslash", - "Oslash", - "OE", - "ordmasculine", - "ae", - "dotlessi", - "lslash", - "oslash", - "oe", - "germandbls", - "Aacute", - "Acircumflex", - "Adieresis", - "Agrave", - "Aring", - "Atilde", - "Ccedilla", - "Eacute", - "Ecircumflex", - "Edieresis", - "Egrave", - "Eth", - "Iacute", - "Icircumflex", - "Idieresis", - "Igrave", - "Ntilde", - "Oacute", - "Ocircumflex", - "Odieresis", - "Ograve", - "Otilde", - "Scaron", - "Thorn", - "Uacute", - "Ucircumflex", - "Udieresis", - "Ugrave", - "Yacute", - "Ydieresis", - "aacute", - "acircumflex", - "adieresis", - "agrave", - "aring", - "atilde", - "brokenbar", - "ccedilla", - "copyright", - "degree", - "divide", - "eacute", - "ecircumflex", - "edieresis", - "egrave", - "eth", - "iacute", - "icircumflex", - "idieresis", - "igrave", - "logicalnot", - "minus", - "multiply", - "ntilde", - "oacute", - "ocircumflex", - "odieresis", - "ograve", - "onehalf", - "onequarter", - "onesuperior", - "otilde", - "plusminus", - "registered", - "thorn", - "threequarters", - "threesuperior", - "trademark", - "twosuperior", - "uacute", - "ucircumflex", - "udieresis", - "ugrave", - "yacute", - "ydieresis", - "Alpha", - "Beta", - "Chi", - "Delta", - "Epsilon", - "Phi", - "Gamma", - "Eta", - "Iota", - "Kappa", - "Lambda", - "Mu", - "Nu", - "Omicron", - "Pi", - "Theta", - "Rho", - "Sigma", - "Tau", - "Upsilon", - "varUpsilon", - "Omega", - "Xi", - "Psi", - "Zeta", - "alpha", - "beta", - "chi", - "delta", - "epsilon", - "phi", - "varphi", - "gamma", - "eta", - "iota", - "kappa", - "lambda", - "mu", - "nu", - "omicron", - "pi", - "varpi", - "theta", - "vartheta", - "rho", - "sigma", - "varsigma", - "tau", - "upsilon", - "omega", - "xi", - "psi", - "zeta", - "nobrkspace", - "nobrkhyphen", - "lessequal", - "greaterequal", - "infinity", - "integral", - "notequal", - "radical", - "radicalex", - "approxequal", - "apple", - "partialdiff", - "opthyphen", - "formula", - "lozenge", - "universal", - "existential", - "suchthat", - "congruent", - "therefore", - "perpendicular", - "minute", - "club", - "diamond", - "heart", - "spade", - "arrowboth", - "arrowleft", - "arrowup", - "arrowright", - "arrowdown", - "second", - "proportional", - "equivalence", - "arrowvertex", - "arrowhorizex", - "carriagereturn", - "aleph", - "Ifraktur", - "Rfraktur", - "weierstrass", - "circlemultiply", - "circleplus", - "emptyset", - "intersection", - "union", - "propersuperset", - "reflexsuperset", - "notsubset", - "propersubset", - "reflexsubset", - "element", - "notelement", - "angle", - "gradient", - "product", - "logicaland", - "logicalor", - "arrowdblboth", - "arrowdblleft", - "arrowdblup", - "arrowdblright", - "arrowdbldown", - "angleleft", - "registersans", - "copyrightsans", - "trademarksans", - "angleright", - "mathplus", - "mathminus", - "mathasterisk", - "mathnumbersign", - "dotmath", - "mathequal", - "mathtilde", - (char *) NULL -}; + char *p; + + p = RTFAlloc (lstrlenA(s) + 1); + if (p == NULL) + return NULL; + return lstrcpyA (p, s); +} + + +static inline void RTFFree(void *p) +{ + HeapFree(me_heap, 0, p); +} + + +/* ---------------------------------------------------------------------- */ + int _RTFGetChar(RTF_Info *info) { int ch; + ME_InStream *stream = info->stream; TRACE("\n"); /* if the last buffer wasn't full, it's EOF */ - if (info->dwInputSize > 0 && - info->dwInputSize == info->dwInputUsed && info->dwInputSize < sizeof(info->InputBuffer)) - return EOF; - if (info->dwInputSize <= info->dwInputUsed) + if (stream->dwSize > 0 && stream->dwSize == stream->dwUsed + && stream->dwSize < sizeof(stream->buffer)) + return EOF; + if (stream->dwSize <= stream->dwUsed) { - long count = 0; - info->editstream.dwError = info->editstream.pfnCallback(info->editstream.dwCookie, - info->InputBuffer, sizeof(info->InputBuffer), &count); - /* if error, it's EOF */ - if (info->editstream.dwError) - return EOF; - /* if no bytes read, it's EOF */ - if(count == 0) + ME_StreamInFill(stream); + /* if error, it's EOF */ + if (stream->editstream->dwError) + return EOF; + /* if no bytes read, it's EOF */ + if (stream->dwSize == 0) return EOF; - info->dwInputSize = count; - info->dwInputUsed = 0; } - ch = info->InputBuffer[info->dwInputUsed++]; + ch = stream->buffer[stream->dwUsed++]; if (!ch) return EOF; return ch; } -void RTFSetEditStream(RTF_Info *info, EDITSTREAM *es) +void RTFSetEditStream(RTF_Info *info, ME_InStream *stream) { TRACE("\n"); - info->editstream.dwCookie = es->dwCookie; - info->editstream.dwError = es->dwError; - info->editstream.pfnCallback = es->pfnCallback; + info->stream = stream; } +static void +RTFDestroyAttrs(RTF_Info *info) +{ + RTFColor *cp; + RTFFont *fp; + RTFStyle *sp; + RTFStyleElt *eltList, *ep; + + while (info->fontList) + { + fp = info->fontList->rtfNextFont; + RTFFree (info->fontList->rtfFName); + RTFFree (info->fontList); + info->fontList = fp; + } + while (info->colorList) + { + cp = info->colorList->rtfNextColor; + RTFFree (info->colorList); + info->colorList = cp; + } + while (info->styleList) + { + sp = info->styleList->rtfNextStyle; + eltList = info->styleList->rtfSSEList; + while (eltList) + { + ep = eltList->rtfNextSE; + RTFFree (eltList->rtfSEText); + RTFFree (eltList); + eltList = ep; + } + RTFFree (info->styleList->rtfSName); + RTFFree (info->styleList); + info->styleList = sp; + } +} + + +void +RTFDestroy(RTF_Info *info) +{ + if (info->rtfTextBuf) + { + RTFFree(info->rtfTextBuf); + RTFFree(info->pushedTextBuf); + } + RTFDestroyAttrs(info); + RTFFree(info->cpOutputBuffer); +} + + /* * Initialize the reader. This may be called multiple times, * to read multiple files. The only thing not reset is the input @@ -978,34 +215,29 @@ void RTFSetEditStream(RTF_Info *info, EDITSTREAM *es) void RTFInit(RTF_Info *info) { int i; - RTFColor *cp; - RTFFont *fp; - RTFStyle *sp; - RTFStyleElt *eltList, *ep; TRACE("\n"); - if (info->rtfTextBuf == (char *) NULL) /* initialize the text buffers */ + if (info->rtfTextBuf == NULL) /* initialize the text buffers */ { info->rtfTextBuf = RTFAlloc (rtfBufSiz); info->pushedTextBuf = RTFAlloc (rtfBufSiz); - if (info->rtfTextBuf == (char *) NULL - || info->pushedTextBuf == (char *) NULL) + if (info->rtfTextBuf == NULL || info->pushedTextBuf == NULL) RTFPanic (info,"Cannot allocate text buffers."); info->rtfTextBuf[0] = info->pushedTextBuf[0] = '\0'; } RTFFree (info->inputName); RTFFree (info->outputName); - info->inputName = info->outputName = (char *) NULL; + info->inputName = info->outputName = NULL; /* initialize lookup table */ LookupInit (); for (i = 0; i < rtfMaxClass; i++) - RTFSetClassCallback (info, i, (RTFFuncPtr) NULL); + RTFSetClassCallback (info, i, NULL); for (i = 0; i < rtfMaxDestination; i++) - RTFSetDestinationCallback (info, i, (RTFFuncPtr) NULL); + RTFSetDestinationCallback (info, i, NULL); /* install built-in destination readers */ RTFSetDestinationCallback (info, rtfFontTbl, ReadFontTbl); @@ -1016,38 +248,15 @@ void RTFInit(RTF_Info *info) RTFSetDestinationCallback (info, rtfObject, ReadObjGroup); - RTFSetReadHook (info, (RTFFuncPtr) NULL); + RTFSetReadHook (info, NULL); /* dump old lists if necessary */ - while (info->fontList != (RTFFont *) NULL) - { - fp = info->fontList->rtfNextFont; - RTFFree (info->fontList->rtfFName); - RTFFree ((char *) info->fontList); - info->fontList = fp; - } - while (info->colorList != (RTFColor *) NULL) - { - cp = info->colorList->rtfNextColor; - RTFFree ((char *) info->colorList); - info->colorList = cp; - } - while (info->styleList != (RTFStyle *) NULL) - { - sp = info->styleList->rtfNextStyle; - eltList = info->styleList->rtfSSEList; - while (eltList != (RTFStyleElt *) NULL) - { - ep = eltList->rtfNextSE; - RTFFree (eltList->rtfSEText); - RTFFree ((char *) eltList); - eltList = ep; - } - RTFFree (info->styleList->rtfSName); - RTFFree ((char *) info->styleList); - info->styleList = sp; - } + RTFDestroyAttrs(info); + + info->ansiCodePage = 1252; /* Latin-1; actually unused */ + info->unicodeLength = 1; /* \uc1 is the default */ + info->codePage = info->ansiCodePage; info->rtfClass = -1; info->pushedClass = -1; @@ -1058,8 +267,12 @@ void RTFInit(RTF_Info *info) info->prevChar = EOF; info->bumpLine = 0; - CharSetInit (info); - info->csTop = 0; + info->dwCPOutputCount = 0; + if (!info->cpOutputBuffer) + { + info->dwMaxCPOutputCount = 0x1000; + info->cpOutputBuffer = RTFAlloc(info->dwMaxCPOutputCount); + } } /* @@ -1071,7 +284,8 @@ void RTFSetInputName(RTF_Info *info, char *name) { TRACE("\n"); - if ((info->inputName = RTFStrSave (name)) == (char *) NULL) + info->inputName = RTFStrSave (name); + if (info->inputName == NULL) RTFPanic (info,"RTFSetInputName: out of memory"); } @@ -1086,7 +300,8 @@ void RTFSetOutputName(RTF_Info *info, char *name) { TRACE("\n"); - if ((info->outputName = RTFStrSave (name)) == (char *) NULL) + info->outputName = RTFStrSave (name); + if (info->outputName == NULL) RTFPanic (info, "RTFSetOutputName: out of memory"); } @@ -1119,8 +334,8 @@ void RTFSetClassCallback(RTF_Info *info, int class, RTFFuncPtr callback) RTFFuncPtr RTFGetClassCallback(RTF_Info *info, int class) { if (class >= 0 && class < rtfMaxClass) - return (info->ccb[class]); - return ((RTFFuncPtr) NULL); + return info->ccb[class]; + return NULL; } @@ -1138,8 +353,8 @@ void RTFSetDestinationCallback(RTF_Info *info, int dest, RTFFuncPtr callback) RTFFuncPtr RTFGetDestinationCallback(RTF_Info *info, int dest) { if (dest >= 0 && dest < rtfMaxDestination) - return (info->dcb[dest]); - return ((RTFFuncPtr) NULL); + return info->dcb[dest]; + return NULL; } @@ -1182,15 +397,16 @@ void RTFRouteToken(RTF_Info *info) if (RTFCheckCM (info, rtfControl, rtfDestination)) { /* invoke destination-specific callback if there is one */ - if ((p = RTFGetDestinationCallback (info, info->rtfMinor)) - != (RTFFuncPtr) NULL) + p = RTFGetDestinationCallback (info, info->rtfMinor); + if (p != NULL) { (*p) (info); return; } } /* invoke class callback if there is one */ - if ((p = RTFGetClassCallback (info, info->rtfClass)) != (RTFFuncPtr) NULL) + p = RTFGetClassCallback (info, info->rtfClass); + if (p != NULL) (*p) (info); } @@ -1239,7 +455,8 @@ int RTFGetToken(RTF_Info *info) for (;;) { _RTFGetToken (info); - if ((p = RTFGetReadHook (info)) != (RTFFuncPtr) NULL) + p = RTFGetReadHook (info); + if (p != NULL) (*p) (info); /* give read hook a look at token */ /* Silently discard newlines, carriage returns, nulls. */ @@ -1279,7 +496,7 @@ void RTFUngetToken(RTF_Info *info) info->pushedMajor = info->rtfMajor; info->pushedMinor = info->rtfMinor; info->pushedParam = info->rtfParam; - (void) strcpy (info->pushedTextBuf, info->rtfTextBuf); + lstrcpyA (info->pushedTextBuf, info->rtfTextBuf); } @@ -1293,20 +510,19 @@ int RTFPeekToken(RTF_Info *info) static void _RTFGetToken(RTF_Info *info) { - RTFFont *fp; - TRACE("\n"); - if (info->rtfFormat == SF_TEXT) { - info->rtfMajor = GetChar (info); - info->rtfMinor = rtfSC_nothing; - info->rtfParam = rtfNoParam; - info->rtfTextBuf[info->rtfTextLen = 0] = '\0'; - if (info->rtfMajor == EOF) - info->rtfClass = rtfEOF; - else - info->rtfClass = rtfText; - return; + if (info->rtfFormat == SF_TEXT) + { + info->rtfMajor = GetChar (info); + info->rtfMinor = 0; + info->rtfParam = rtfNoParam; + info->rtfTextBuf[info->rtfTextLen = 0] = '\0'; + if (info->rtfMajor == EOF) + info->rtfClass = rtfEOF; + else + info->rtfClass = rtfText; + return; } /* first check for pushed token from RTFUngetToken() */ @@ -1317,8 +533,8 @@ static void _RTFGetToken(RTF_Info *info) info->rtfMajor = info->pushedMajor; info->rtfMinor = info->pushedMinor; info->rtfParam = info->pushedParam; - (void) strcpy (info->rtfTextBuf, info->pushedTextBuf); - info->rtfTextLen = strlen (info->rtfTextBuf); + lstrcpyA (info->rtfTextBuf, info->pushedTextBuf); + info->rtfTextLen = lstrlenA(info->rtfTextBuf); info->pushedClass = -1; return; } @@ -1329,61 +545,66 @@ static void _RTFGetToken(RTF_Info *info) */ _RTFGetToken2 (info); - if (info->rtfClass == rtfText) /* map RTF char to standard code */ - info->rtfMinor = RTFMapChar (info, info->rtfMajor); +} - /* - * If auto-charset stuff is activated, see if anything needs doing, - * like reading the charset maps or switching between them. - */ - if (info->autoCharSetFlags == 0) - return; - - if ((info->autoCharSetFlags & rtfReadCharSet) - && RTFCheckCM (info, rtfControl, rtfCharSet)) - { - ReadCharSetMaps (info); - } - else if ((info->autoCharSetFlags & rtfSwitchCharSet) - && RTFCheckCMM (info, rtfControl, rtfCharAttr, rtfFontNum)) - { - if ((fp = RTFGetFont (info, info->rtfParam)) != (RTFFont *) NULL) +int +RTFCharSetToCodePage(RTF_Info *info, int charset) +{ + switch (charset) + { + case ANSI_CHARSET: + return 1252; + case DEFAULT_CHARSET: + return CP_ACP; + case SYMBOL_CHARSET: + return CP_SYMBOL; + case MAC_CHARSET: + return CP_MACCP; + case SHIFTJIS_CHARSET: + return 932; + case HANGEUL_CHARSET: + return 949; + case JOHAB_CHARSET: + return 1361; + case GB2312_CHARSET: + return 936; + case CHINESEBIG5_CHARSET: + return 950; + case GREEK_CHARSET: + return 1253; + case TURKISH_CHARSET: + return 1254; + case VIETNAMESE_CHARSET: + return 1258; + case HEBREW_CHARSET: + return 1255; + case ARABIC_CHARSET: + return 1256; + case BALTIC_CHARSET: + return 1257; + case RUSSIAN_CHARSET: + return 1251; + case THAI_CHARSET: + return 874; + case EASTEUROPE_CHARSET: + return 1250; + case OEM_CHARSET: + return CP_OEMCP; + default: { - if (strncmp (fp->rtfFName, "Symbol", 6) == 0) - info->curCharSet = rtfCSSymbol; + CHARSETINFO csi; + DWORD n = charset; + + /* FIXME: TranslateCharsetInfo does not work as good as it + * should, so let's use it only when all else fails */ + if (!TranslateCharsetInfo(&n, &csi, TCI_SRCCHARSET)) + RTFMsg(info, "%s: unknown charset %u\n", __FUNCTION__, charset); else - info->curCharSet = rtfCSGeneral; - RTFSetCharSet (info, info->curCharSet); - } - } - else if ((info->autoCharSetFlags & rtfSwitchCharSet) && info->rtfClass == rtfGroup) - { - switch (info->rtfMajor) - { - case rtfBeginGroup: - if (info->csTop >= maxCSStack) - RTFPanic (info, "_RTFGetToken: stack overflow"); - info->csStack[info->csTop++] = info->curCharSet; - break; - case rtfEndGroup: - /* - * If stack top is 1 at this point, we are ending the - * group started by the initial {, which ends the - * RTF stream - */ - if (info->csTop <= 0) - RTFPanic (info,"_RTFGetToken: stack underflow"); - else if (info->csTop == 1) - info->rtfClass = rtfEOF; - else - { - info->curCharSet = info->csStack[--info->csTop]; - RTFSetCharSet (info, info->curCharSet); - } - break; + return csi.ciACP; } } + return 0; } @@ -1470,8 +691,7 @@ static void _RTFGetToken2(RTF_Info *info) { /* should do isxdigit check! */ info->rtfClass = rtfText; - info->rtfMajor = RTFCharToHex (c) * 16 - + RTFCharToHex (c2); + info->rtfMajor = RTFCharToHex (c) * 16 + RTFCharToHex (c2); return; } /* early eof, whoops (class is rtfUnknown) */ @@ -1614,251 +834,10 @@ void RTFSetToken(RTF_Info *info, int class, int major, int minor, int param, con info->rtfMinor = minor; info->rtfParam = param; if (param == rtfNoParam) - (void) strcpy (info->rtfTextBuf, text); + lstrcpyA(info->rtfTextBuf, text); else sprintf (info->rtfTextBuf, "%s%d", text, param); - info->rtfTextLen = strlen (info->rtfTextBuf); -} - - -/* ---------------------------------------------------------------------- */ - -/* - * Routines to handle mapping of RTF character sets - * onto standard characters. - * - * RTFStdCharCode(name) given char name, produce numeric code - * RTFStdCharName(code) given char code, return name - * RTFMapChar(c) map input (RTF) char code to std code - * RTFSetCharSet(id) select given charset map - * RTFGetCharSet() get current charset map - * - * See ../h/README for more information about charset names and codes. - */ - - -/* - * Initialize charset stuff. - */ - -static void CharSetInit(RTF_Info *info) -{ - TRACE("\n"); - - info->autoCharSetFlags = (rtfReadCharSet | rtfSwitchCharSet); - RTFFree (info->genCharSetFile); - info->genCharSetFile = (char *) NULL; - info->haveGenCharSet = 0; - RTFFree (info->symCharSetFile); - info->symCharSetFile = (char *) NULL; - info->haveSymCharSet = 0; - info->curCharSet = rtfCSGeneral; - info->curCharCode = info->genCharCode; -} - - -/* - * Specify the name of a file to be read when auto-charset-file reading is - * done. - */ - -void RTFSetCharSetMap (RTF_Info *info, char *name, int csId) -{ - TRACE("\n"); - - if ((name = RTFStrSave (name)) == (char *) NULL) /* make copy */ - RTFPanic (info,"RTFSetCharSetMap: out of memory"); - switch (csId) - { - case rtfCSGeneral: - RTFFree (info->genCharSetFile); /* free any previous value */ - info->genCharSetFile = name; - break; - case rtfCSSymbol: - RTFFree (info->symCharSetFile); /* free any previous value */ - info->symCharSetFile = name; - break; - } -} - - -/* - * Do auto-charset-file reading. - * will always use the ansi charset no mater what the value - * of the rtfTextBuf is. - * - * TODO: add support for other charset in the future. - * - */ - -static void ReadCharSetMaps(RTF_Info *info) -{ - char buf[rtfBufSiz]; - - TRACE("\n"); - - if (info->genCharSetFile != (char *) NULL) - (void) strcpy (buf, info->genCharSetFile); - else - sprintf (buf, "%s-gen", &info->rtfTextBuf[1]); - if (RTFReadCharSetMap (info, rtfCSGeneral) == 0) - RTFPanic (info,"ReadCharSetMaps: Cannot read charset map %s", buf); - if (info->symCharSetFile != (char *) NULL) - (void) strcpy (buf, info->symCharSetFile); - else - sprintf (buf, "%s-sym", &info->rtfTextBuf[1]); - if (RTFReadCharSetMap (info, rtfCSSymbol) == 0) - RTFPanic (info,"ReadCharSetMaps: Cannot read charset map %s", buf); -} - - - -/* - * Convert a CharSetMap (character_name, character) into - * this form : array[character_ident] = character; - */ - -int RTFReadCharSetMap(RTF_Info *info, int csId) -{ - int *stdCodeArray; - unsigned int i; - - TRACE("\n"); - - switch (csId) - { - default: - return (0); /* illegal charset id */ - case rtfCSGeneral: - - info->haveGenCharSet = 1; - stdCodeArray = info->genCharCode; - for (i = 0; i < charSetSize; i++) - { - stdCodeArray[i] = rtfSC_nothing; - } - - for ( i = 0 ; i< sizeof(ansi_gen)/(sizeof(int));i+=2) - { - stdCodeArray[ ansi_gen[i+1] ] = ansi_gen[i]; - } - break; - - case rtfCSSymbol: - - info->haveSymCharSet = 1; - stdCodeArray = info->symCharCode; - for (i = 0; i < charSetSize; i++) - { - stdCodeArray[i] = rtfSC_nothing; - } - - for ( i = 0 ; i< sizeof(ansi_sym)/(sizeof(int));i+=2) - { - stdCodeArray[ ansi_sym[i+1] ] = ansi_sym[i]; - } - break; - } - - return (1); -} - - -/* - * Given a standard character name (a string), find its code (a number). - * Return -1 if name is unknown. - */ - -int RTFStdCharCode(RTF_Info *info, const char *name) -{ - int i; - - TRACE("\n"); - - for (i = 0; i < rtfSC_MaxChar; i++) - { - if (strcmp (name, stdCharName[i]) == 0) - return (i); - } - return (-1); -} - - -/* - * Given a standard character code (a number), find its name (a string). - * Return NULL if code is unknown. - */ - -const char *RTFStdCharName(RTF_Info *info, int code) -{ - if (code < 0 || code >= rtfSC_MaxChar) - return ((char *) NULL); - return (stdCharName[code]); -} - - -/* - * Given an RTF input character code, find standard character code. - * The translator should read the appropriate charset maps when it finds a - * charset control. However, the file might not contain one. In this - * case, no map will be available. When the first attempt is made to - * map a character under these circumstances, RTFMapChar() assumes ANSI - * and reads the map as necessary. - */ - -int RTFMapChar(RTF_Info *info, int c) -{ - TRACE("\n"); - - switch (info->curCharSet) - { - case rtfCSGeneral: - if (!info->haveGenCharSet) - { - if (RTFReadCharSetMap (info, rtfCSGeneral) == 0) - RTFPanic (info,"RTFMapChar: cannot read ansi-gen"); - } - break; - case rtfCSSymbol: - if (!info->haveSymCharSet) - { - if (RTFReadCharSetMap (info, rtfCSSymbol) == 0) - RTFPanic (info,"RTFMapChar: cannot read ansi-sym"); - } - break; - } - if (c < 0 || c >= charSetSize) - return (rtfSC_nothing); - return (info->curCharCode[c]); -} - - -/* - * Set the current character set. If csId is illegal, uses general charset. - */ - -void RTFSetCharSet(RTF_Info *info, int csId) -{ - TRACE("\n"); - - switch (csId) - { - default: /* use general if csId unknown */ - case rtfCSGeneral: - info->curCharCode = info->genCharCode; - info->curCharSet = csId; - break; - case rtfCSSymbol: - info->curCharCode = info->symCharCode; - info->curCharSet = csId; - break; - } -} - - -int RTFGetCharSet(RTF_Info *info) -{ - return (info->curCharSet); + info->rtfTextLen = lstrlenA (info->rtfTextBuf); } @@ -1901,7 +880,7 @@ static void ReadFontTbl(RTF_Info *info) for (;;) { - (void) RTFGetToken (info); + RTFGetToken (info); if (RTFCheckCM (info, rtfGroup, rtfEndGroup)) break; if (old < 0) /* first entry - determine tbl type */ @@ -1917,22 +896,23 @@ static void ReadFontTbl(RTF_Info *info) { if (!RTFCheckCM (info, rtfGroup, rtfBeginGroup)) RTFPanic (info, "%s: missing \"{\"", fn); - (void) RTFGetToken (info); /* yes, skip to next token */ + RTFGetToken (info); /* yes, skip to next token */ } - if ((fp = New (RTFFont)) == (RTFFont *) NULL) + fp = New (RTFFont); + if (fp == NULL) RTFPanic (info, "%s: cannot allocate font entry", fn); fp->rtfNextFont = info->fontList; info->fontList = fp; - fp->rtfFName = (char *) NULL; - fp->rtfFAltName = (char *) NULL; + fp->rtfFName = NULL; + fp->rtfFAltName = NULL; fp->rtfFNum = -1; fp->rtfFFamily = 0; - fp->rtfFCharSet = 0; + fp->rtfFCharSet = DEFAULT_CHARSET; /* 1 */ fp->rtfFPitch = 0; fp->rtfFType = 0; - fp->rtfFCodePage = 0; + fp->rtfFCodePage = CP_ACP; while (info->rtfClass != rtfEOF && !RTFCheckCM (info, rtfText, ';') @@ -1967,6 +947,8 @@ static void ReadFontTbl(RTF_Info *info) break; /* ignore unknown? */ case rtfFontCharSet: fp->rtfFCharSet = info->rtfParam; + if (!fp->rtfFCodePage) + fp->rtfFCodePage = RTFCharSetToCodePage(info, info->rtfParam); break; case rtfFontPitch: fp->rtfFPitch = info->rtfParam; @@ -1993,17 +975,17 @@ static void ReadFontTbl(RTF_Info *info) && !RTFCheckCM (info, rtfText, ';')) { *bp++ = info->rtfMajor; - (void) RTFGetToken (info); + RTFGetToken (info); } /* FIX: in some cases the isn't finished with a semi-column */ if(RTFCheckCM (info, rtfGroup, rtfEndGroup)) { - RTFUngetToken (info); + RTFUngetToken (info); } *bp = '\0'; fp->rtfFName = RTFStrSave (buf); - if (fp->rtfFName == (char *) NULL) + if (fp->rtfFName == NULL) RTFPanic (info, "%s: cannot allocate font name", fn); /* already have next token; don't read one */ /* at bottom of loop */ @@ -2015,11 +997,11 @@ static void ReadFontTbl(RTF_Info *info) RTFMsg (info, "%s: unknown token \"%s\"\n", fn,info->rtfTextBuf); } - (void) RTFGetToken (info); + RTFGetToken (info); } if (old == 0) /* need to see "}" here */ { - (void) RTFGetToken (info); + RTFGetToken (info); if (!RTFCheckCM (info, rtfGroup, rtfEndGroup)) RTFPanic (info, "%s: missing \"}\"", fn); } @@ -2052,10 +1034,11 @@ static void ReadColorTbl(RTF_Info *info) for (;;) { - (void) RTFGetToken (info); + RTFGetToken (info); if (RTFCheckCM (info, rtfGroup, rtfEndGroup)) break; - if ((cp = New (RTFColor)) == (RTFColor *) NULL) + cp = New (RTFColor); + if (cp == NULL) RTFPanic (info,"%s: cannot allocate color entry", fn); cp->rtfCNum = cnum++; cp->rtfCRed = cp->rtfCGreen = cp->rtfCBlue = -1; @@ -2071,7 +1054,7 @@ static void ReadColorTbl(RTF_Info *info) } RTFGetToken (info); } - if (!RTFCheckCM (info, rtfText, (int) ';')) + if (!RTFCheckCM (info, rtfText, ';')) RTFPanic (info,"%s: malformed entry", fn); } RTFRouteToken (info); /* feed "}" back to router */ @@ -2094,18 +1077,19 @@ static void ReadStyleSheet(RTF_Info *info) for (;;) { - (void) RTFGetToken (info); + RTFGetToken (info); if (RTFCheckCM (info, rtfGroup, rtfEndGroup)) break; - if ((sp = New (RTFStyle)) == (RTFStyle *) NULL) + sp = New (RTFStyle); + if (sp == NULL) RTFPanic (info,"%s: cannot allocate stylesheet entry", fn); - sp->rtfSName = (char *) NULL; + sp->rtfSName = NULL; sp->rtfSNum = -1; sp->rtfSType = rtfParStyle; sp->rtfSAdditive = 0; sp->rtfSBasedOn = rtfNoStyleNum; sp->rtfSNextPar = -1; - sp->rtfSSEList = sepLast = (RTFStyleElt *) NULL; + sp->rtfSSEList = sepLast = NULL; sp->rtfNextStyle = info->styleList; sp->rtfExpanding = 0; info->styleList = sp; @@ -2113,7 +1097,7 @@ static void ReadStyleSheet(RTF_Info *info) RTFPanic (info,"%s: missing \"{\"", fn); for (;;) { - (void) RTFGetToken (info); + RTFGetToken (info); if (info->rtfClass == rtfEOF || RTFCheckCM (info, rtfText, ';')) break; @@ -2154,20 +1138,21 @@ static void ReadStyleSheet(RTF_Info *info) sp->rtfSNextPar = info->rtfParam; continue; } - if ((sep = New (RTFStyleElt)) == (RTFStyleElt *) NULL) + sep = New (RTFStyleElt); + if (sep == NULL) RTFPanic (info,"%s: cannot allocate style element", fn); sep->rtfSEClass = info->rtfClass; sep->rtfSEMajor = info->rtfMajor; sep->rtfSEMinor = info->rtfMinor; sep->rtfSEParam = info->rtfParam; - if ((sep->rtfSEText = RTFStrSave (info->rtfTextBuf)) - == (char *) NULL) + sep->rtfSEText = RTFStrSave (info->rtfTextBuf); + if (sep->rtfSEText == NULL) RTFPanic (info,"%s: cannot allocate style element text", fn); - if (sepLast == (RTFStyleElt *) NULL) + if (sepLast == NULL) sp->rtfSSEList = sep; /* first element */ else /* add to end */ sepLast->rtfNextSE = sep; - sep->rtfNextSE = (RTFStyleElt *) NULL; + sep->rtfNextSE = NULL; sepLast = sep; } else if (RTFCheckCM (info, rtfGroup, rtfBeginGroup)) @@ -2187,14 +1172,15 @@ static void ReadStyleSheet(RTF_Info *info) if (info->rtfMajor == ';') { /* put back for "for" loop */ - (void) RTFUngetToken (info); + RTFUngetToken (info); break; } *bp++ = info->rtfMajor; - (void) RTFGetToken (info); + RTFGetToken (info); } *bp = '\0'; - if ((sp->rtfSName = RTFStrSave (buf)) == (char *) NULL) + sp->rtfSName = RTFStrSave (buf); + if (sp->rtfSName == NULL) RTFPanic (info, "%s: cannot allocate style name", fn); } else /* unrecognized */ @@ -2204,7 +1190,7 @@ static void ReadStyleSheet(RTF_Info *info) fn, info->rtfTextBuf); } } - (void) RTFGetToken (info); + RTFGetToken (info); if (!RTFCheckCM (info, rtfGroup, rtfEndGroup)) RTFPanic (info, "%s: missing \"}\"", fn); @@ -2218,7 +1204,7 @@ static void ReadStyleSheet(RTF_Info *info) * * Some German RTF writers use "Standard" instead of "Normal". */ - if (sp->rtfSName == (char *) NULL) + if (sp->rtfSName == NULL) RTFPanic (info,"%s: missing style name", fn); if (sp->rtfSNum < 0) { @@ -2269,7 +1255,7 @@ RTFStyle *RTFGetStyle(RTF_Info *info, int num) if (num == -1) return (info->styleList); - for (s = info->styleList; s != (RTFStyle *) NULL; s = s->rtfNextStyle) + for (s = info->styleList; s != NULL; s = s->rtfNextStyle) { if (s->rtfSNum == num) break; @@ -2284,7 +1270,7 @@ RTFFont *RTFGetFont(RTF_Info *info, int num) if (num == -1) return (info->fontList); - for (f = info->fontList; f != (RTFFont *) NULL; f = f->rtfNextFont) + for (f = info->fontList; f != NULL; f = f->rtfNextFont) { if (f->rtfFNum == num) break; @@ -2299,7 +1285,7 @@ RTFColor *RTFGetColor(RTF_Info *info, int num) if (num == -1) return (info->colorList); - for (c = info->colorList; c != (RTFColor *) NULL; c = c->rtfNextColor) + for (c = info->colorList; c != NULL; c = c->rtfNextColor) { if (c->rtfCNum == num) break; @@ -2322,7 +1308,10 @@ void RTFExpandStyle(RTF_Info *info, int n) TRACE("\n"); - if (n == -1 || (s = RTFGetStyle (info, n)) == (RTFStyle *) NULL) + if (n == -1) + return; + s = RTFGetStyle (info, n); + if (s == NULL) return; if (s->rtfExpanding != 0) RTFPanic (info,"Style expansion loop, style %d", n); @@ -2346,14 +1335,14 @@ void RTFExpandStyle(RTF_Info *info, int n) * isn't used because it would add the param value to the end * of the token text, which already has it in. */ - for (se = s->rtfSSEList; se != (RTFStyleElt *) NULL; se = se->rtfNextSE) + for (se = s->rtfSSEList; se != NULL; se = se->rtfNextSE) { info->rtfClass = se->rtfSEClass; info->rtfMajor = se->rtfSEMajor; info->rtfMinor = se->rtfSEMinor; info->rtfParam = se->rtfSEParam; - (void) strcpy (info->rtfTextBuf, se->rtfSEText); - info->rtfTextLen = strlen (info->rtfTextBuf); + lstrcpyA (info->rtfTextBuf, se->rtfSEText); + info->rtfTextLen = lstrlenA (info->rtfTextBuf); RTFRouteToken (info); } s->rtfExpanding = 0; /* done - clear expansion flag */ @@ -2451,6 +1440,7 @@ static RTFKey rtfKey[] = { rtfSpecialChar, rtfNoWidthNonJoiner, "zwnj", 0 }, /* is this valid? */ { rtfSpecialChar, rtfCurHeadPict, "chpict", 0 }, + { rtfSpecialChar, rtfUnicode, "u", 0 }, /* * Character formatting attributes @@ -2493,6 +1483,7 @@ static RTFKey rtfKey[] = { rtfCharAttr, rtfLanguage, "lang", 0 }, /* this has disappeared from spec 1.2 */ { rtfCharAttr, rtfGray, "gray", 0 }, + { rtfCharAttr, rtfUnicodeLength, "uc", 0 }, /* * Paragraph formatting attributes @@ -2781,6 +1772,9 @@ static RTFKey rtfKey[] = { rtfDocAttr, rtfRTLDoc, "rtldoc", 0 }, { rtfDocAttr, rtfLTRDoc, "ltrdoc", 0 }, + + { rtfDocAttr, rtfAnsiCodePage, "ansicpg", 0 }, + { rtfDocAttr, rtfUTF8RTF, "urtf", 0 }, /* * Style attributes @@ -2844,6 +1838,7 @@ static RTFKey rtfKey[] = { rtfDestination, rtfStyleSheet, "stylesheet", 0 }, { rtfDestination, rtfKeyCode, "keycode", 0 }, { rtfDestination, rtfRevisionTbl, "revtbl", 0 }, + { rtfDestination, rtfGenerator, "generator", 0 }, { rtfDestination, rtfInfo, "info", 0 }, { rtfDestination, rtfITitle, "title", 0 }, { rtfDestination, rtfISubject, "subject", 0 }, @@ -3272,6 +2267,14 @@ static RTFKey rtfKey[] = { 0, -1, (char *) NULL, 0 } }; +#define RTF_KEY_COUNT (sizeof(rtfKey) / sizeof(RTFKey)) + +typedef struct tagRTFHashTableEntry { + int count; + RTFKey **value; +} RTFHashTableEntry; + +static RTFHashTableEntry rtfHashTable[RTF_KEY_COUNT * 2]; /* @@ -3285,8 +2288,18 @@ static void LookupInit(void) if (inited == 0) { - for (rp = rtfKey; rp->rtfKStr != (char *) NULL; rp++) + memset(rtfHashTable, 0, RTF_KEY_COUNT * 2 * sizeof(*rtfHashTable)); + for (rp = rtfKey; rp->rtfKStr != NULL; rp++) { + int index; + rp->rtfKHash = Hash ((char*)rp->rtfKStr); + index = rp->rtfKHash % (RTF_KEY_COUNT * 2); + if (!rtfHashTable[index].count) + rtfHashTable[index].value = RTFAlloc(sizeof(RTFKey *)); + else + rtfHashTable[index].value = RTFReAlloc(rtfHashTable[index].value, sizeof(RTFKey *) * (rtfHashTable[index].count + 1)); + rtfHashTable[index].value[rtfHashTable[index].count++] = rp; + } ++inited; } } @@ -3301,12 +2314,16 @@ static void Lookup(RTF_Info *info, char *s) { RTFKey *rp; int hash; + RTFHashTableEntry *entry; + int i; TRACE("\n"); ++s; /* skip over the leading \ character */ hash = Hash (s); - for (rp = rtfKey; rp->rtfKStr != (char *) NULL; rp++) + entry = &rtfHashTable[hash % (RTF_KEY_COUNT * 2)]; + for (i = 0; i < entry->count; i++) { + rp = entry->value[i]; if (hash == rp->rtfKHash && strcmp (s, rp->rtfKStr) == 0) { info->rtfClass = rtfControl; @@ -3329,53 +2346,11 @@ static int Hash(char *s) int val = 0; while ((c = *s++) != '\0') - val += (int) c; + val += c; return (val); } -/* ---------------------------------------------------------------------- */ - -/* - * Memory allocation routines - */ - - -/* - * Return pointer to block of size bytes, or NULL if there's - * not enough memory available. - * - * This is called through RTFAlloc(), a define which coerces the - * argument to int. This avoids the persistent problem of allocation - * failing under THINK C when a long is passed. - */ - -char *_RTFAlloc(int size) -{ - return HeapAlloc(me_heap, 0, size); -} - - -/* - * Saves a string on the heap and returns a pointer to it. - */ - - -char *RTFStrSave(char *s) -{ - char *p; - - if ((p = RTFAlloc ((int) (strlen (s) + 1))) == (char *) NULL) - return ((char *) NULL); - return (strcpy (p, s)); -} - - -void RTFFree(char *p) -{ - HeapFree(me_heap, 0, p); -} - /* ---------------------------------------------------------------------- */ @@ -3426,79 +2401,9 @@ int RTFHexToChar(int i) /* ---------------------------------------------------------------------- */ /* - * RTFReadOutputMap() -- Read output translation map - */ - -/* - * Read in an array describing the relation between the standard character set - * and an RTF translator's corresponding output sequences. Each line consists - * of a standard character name and the output sequence for that character. + * Print message. * - * outMap is an array of strings into which the sequences should be placed. - * It should be declared like this in the calling program: - * - * char *outMap[rtfSC_MaxChar]; - * - * reinit should be non-zero if outMap should be initialized - * zero otherwise. - * - */ - -int RTFReadOutputMap(RTF_Info *info, char *outMap[], int reinit) -{ - unsigned int i; - int stdCode; - - if (reinit) - { - for (i = 0; i < rtfSC_MaxChar; i++) - { - outMap[i] = (char *) NULL; - } - } - - for (i=0 ;i< sizeof(text_map)/sizeof(char*); i+=2) - { - const char *name = text_map[i]; - const char *seq = text_map[i+1]; - stdCode = RTFStdCharCode( info, name ); - outMap[stdCode] = (char*)seq; - } - - return (1); -} - -/* ---------------------------------------------------------------------- */ - -/* - * Open a library file. - */ - - -void RTFSetOpenLibFileProc(RTF_Info *info, FILE *(*proc)()) -{ - info->libFileOpen = proc; -} - - -FILE *RTFOpenLibFile (RTF_Info *info, char *file, char *mode) -{ - if (info->libFileOpen == NULL) - return ((FILE *) NULL); - return ((*info->libFileOpen) (file, mode)); -} - - -/* ---------------------------------------------------------------------- */ - -/* - * Print message. Default is to send message to stderr - * but this may be overridden with RTFSetMsgProc(). - * - * Message should include linefeeds as necessary. If the default - * function is overridden, the overriding function may want to - * map linefeeds to another line ending character or sequence if - * the host system doesn't use linefeeds. + * Message should include linefeeds as necessary. */ @@ -3540,10 +2445,10 @@ void RTFPanic(RTF_Info *info, const char *fmt, ...) va_start (args,fmt); vsprintf (buf, fmt, args); va_end (args); - (void) strcat (buf, "\n"); - if (info->prevChar != EOF && info->rtfTextBuf != (char *) NULL) + lstrcatA (buf, "\n"); + if (info->prevChar != EOF && info->rtfTextBuf != NULL) { - sprintf (buf + strlen (buf), + sprintf (buf + lstrlenA (buf), "Last token read was \"%s\" near line %ld, position %d.\n", info->rtfTextBuf, info->rtfLineNum, info->rtfLinePos); } @@ -3564,9 +2469,7 @@ static void TextClass (RTF_Info *info); static void ControlClass (RTF_Info *info); static void Destination (RTF_Info *info); static void SpecialChar (RTF_Info *info); -static void PutStdChar (RTF_Info *info, int stdCode); -static void PutLitChar (RTF_Info *info, int c); -static void PutLitStr (RTF_Info *info, char *s); +static void RTFPutUnicodeChar (RTF_Info *info, int c); /* * Initialize the writer. @@ -3575,7 +2478,6 @@ static void PutLitStr (RTF_Info *info, char *s); void WriterInit (RTF_Info *info ) { - RTFReadOutputMap (info, info->outMap,1); } @@ -3590,34 +2492,14 @@ BeginFile (RTF_Info *info ) return (1); } - /* - * Write out a character. rtfMajor contains the input character, rtfMinor - * contains the corresponding standard character code. - * - * If the input character isn't in the charset map, try to print some - * representation of it. + * Write out a character. */ static void TextClass (RTF_Info *info) { - char buf[rtfBufSiz]; - - TRACE("\n"); - - if (info->rtfFormat == SF_TEXT) - PutLitChar (info, info->rtfMajor); - else if (info->rtfMinor != rtfSC_nothing) - PutStdChar (info, info->rtfMinor); - else - { - if (info->rtfMajor < 128) /* in ASCII range */ - sprintf (buf, "[[%c]]", info->rtfMajor); - else - sprintf (buf, "[[\\'%02x]]", info->rtfMajor); - PutLitStr (info, buf); - } + RTFPutCodePageChar(info, info->rtfMajor); } @@ -3628,18 +2510,71 @@ ControlClass (RTF_Info *info) switch (info->rtfMajor) { + case rtfCharAttr: + CharAttr(info); + break; + case rtfCharSet: + CharSet(info); + break; case rtfDestination: Destination (info); break; + case rtfDocAttr: + DocAttr(info); + break; case rtfSpecialChar: - SpecialChar (info); + SpecialChar (info); break; } } +static void +CharAttr(RTF_Info *info) +{ + RTFFont *font; + + switch (info->rtfMinor) + { + case rtfFontNum: + font = RTFGetFont(info, info->rtfParam); + if (font) + { + if (info->ansiCodePage != CP_UTF8) + info->codePage = font->rtfFCodePage; + } + else + RTFMsg(info, "unknown font %d\n", info->rtfParam); + break; + case rtfUnicodeLength: + info->unicodeLength = info->rtfParam; + break; + } +} + + +static void +CharSet(RTF_Info *info) +{ + switch (info->rtfMinor) + { + case rtfAnsiCharSet: + info->ansiCodePage = 1252; /* Latin-1 */ + break; + case rtfMacCharSet: + info->ansiCodePage = 10000; /* MacRoman */ + break; + case rtfPcCharSet: + info->ansiCodePage = 437; + break; + case rtfPcaCharSet: + info->ansiCodePage = 850; + break; + } +} + /* - * This function notices destinations that should be ignored + * This function notices destinations that aren't explicitly handled * and skips to their ends. This keeps, for instance, picture * data from being considered as plain text. */ @@ -3648,139 +2583,178 @@ static void Destination (RTF_Info *info) { TRACE("\n"); - - switch (info->rtfMinor) - { - case rtfPict: - case rtfFNContSep: - case rtfFNContNotice: - case rtfInfo: - case rtfIndexRange: - case rtfITitle: - case rtfISubject: - case rtfIAuthor: - case rtfIOperator: - case rtfIKeywords: - case rtfIComment: - case rtfIVersion: - case rtfIDoccomm: - RTFSkipGroup (info); - break; - } + if (!RTFGetDestinationCallback(info, info->rtfMinor)) + RTFSkipGroup (info); } -/* - * The reason these use the rtfSC_xxx thingies instead of just writing - * out ' ', '-', '"', etc., is so that the mapping for these characters - * can be controlled by the text-map file. - */ +static void +DocAttr(RTF_Info *info) +{ + switch (info->rtfMinor) + { + case rtfAnsiCodePage: + info->ansiCodePage = info->rtfParam; + break; + case rtfUTF8RTF: + info->ansiCodePage = CP_UTF8; + break; + } +} -void SpecialChar (RTF_Info *info) + +static void SpecialChar (RTF_Info *info) { TRACE("\n"); switch (info->rtfMinor) { + case rtfOptDest: + /* the next token determines destination, if it's unknown, skip the group */ + /* this way we filter out the garbage coming from unknown destinations */ + RTFGetToken(info); + if (info->rtfClass != rtfDestination) + RTFSkipGroup(info); + else + RTFRouteToken(info); /* "\*" is ignored with known destinations */ + break; + case rtfUnicode: + { + int i; + + RTFPutUnicodeChar(info, info->rtfParam); + + /* After \u we must skip number of character tokens set by \ucN */ + for (i = 0; i < info->unicodeLength; i++) + { + RTFGetToken(info); + if (info->rtfClass != rtfText) + { + ERR("The token behind \\u is not text, but (%d,%d,%d)\n", + info->rtfClass, info->rtfMajor, info->rtfMinor); + RTFUngetToken(info); + break; + } + } + break; + } case rtfPage: case rtfSect: case rtfRow: case rtfLine: case rtfPar: - PutLitChar (info, '\n'); + RTFPutUnicodeChar (info, '\n'); break; case rtfCell: - PutStdChar (info, rtfSC_space); /* make sure cells are separated */ + RTFPutUnicodeChar (info, ' '); /* make sure cells are separated */ break; case rtfNoBrkSpace: - PutStdChar (info, rtfSC_nobrkspace); + RTFPutUnicodeChar (info, 0x00A0); break; case rtfTab: - PutLitChar (info, '\t'); + RTFPutUnicodeChar (info, '\t'); break; case rtfNoBrkHyphen: - PutStdChar (info, rtfSC_nobrkhyphen); + RTFPutUnicodeChar (info, 0x2011); break; case rtfBullet: - PutStdChar (info, rtfSC_bullet); + RTFPutUnicodeChar (info, 0x2022); break; case rtfEmDash: - PutStdChar (info, rtfSC_emdash); + RTFPutUnicodeChar (info, 0x2014); break; case rtfEnDash: - PutStdChar (info, rtfSC_endash); + RTFPutUnicodeChar (info, 0x2013); break; case rtfLQuote: - PutStdChar (info, rtfSC_quoteleft); + RTFPutUnicodeChar (info, 0x2018); break; case rtfRQuote: - PutStdChar (info, rtfSC_quoteright); + RTFPutUnicodeChar (info, 0x2019); break; case rtfLDblQuote: - PutStdChar (info, rtfSC_quotedblleft); + RTFPutUnicodeChar (info, 0x201C); break; case rtfRDblQuote: - PutStdChar (info, rtfSC_quotedblright); + RTFPutUnicodeChar (info, 0x201D); break; } } -/* - * Eventually this should keep track of the destination of the - * current state and only write text when in the initial state. - * - * If the output sequence is unspecified in the output map, write - * the character's standard name instead. This makes map deficiencies - * obvious and provides incentive to fix it. :-) - */ - -void PutStdChar (RTF_Info *info, int stdCode) +static void +RTFFlushUnicodeOutputBuffer(RTF_Info *info) { - - char *oStr = (char *) NULL; - char buf[rtfBufSiz]; - -/* if (stdCode == rtfSC_nothing) - RTFPanic ("Unknown character code, logic error\n"); -*/ - TRACE("\n"); - - oStr = info->outMap[stdCode]; - if (oStr == (char *) NULL) /* no output sequence in map */ - { - sprintf (buf, "[[%s]]", RTFStdCharName (info, stdCode)); - oStr = buf; - } - PutLitStr (info, oStr); + if (info->dwOutputCount) + { + ME_InsertTextFromCursor(info->editor, 0, info->OutputBuffer, + info->dwOutputCount, info->style); + info->dwOutputCount = 0; + } } -void PutLitChar (RTF_Info *info, int c) +static void +RTFPutUnicodeString(RTF_Info *info, WCHAR *string, int length) { - if( info->dwOutputCount >= ( sizeof info->OutputBuffer - 1 ) ) - RTFFlushOutputBuffer( info ); + if (info->dwCPOutputCount) + RTFFlushCPOutputBuffer(info); + while (length) + { + int fit = min(length, sizeof(info->OutputBuffer) / sizeof(WCHAR) - info->dwOutputCount); + + memmove(info->OutputBuffer + info->dwOutputCount, string, fit * sizeof(WCHAR)); + if (fit == sizeof(info->OutputBuffer) / sizeof(WCHAR) - info->dwOutputCount) + RTFFlushUnicodeOutputBuffer(info); + else + info->dwOutputCount += fit; + length -= fit; + string += fit; + } +} + +static void +RTFFlushCPOutputBuffer(RTF_Info *info) +{ + int bufferMax = info->dwCPOutputCount * 2 * sizeof(WCHAR); + WCHAR *buffer = (WCHAR *)RTFAlloc(bufferMax); + int length; + + length = MultiByteToWideChar(info->codePage, 0, info->cpOutputBuffer, + info->dwCPOutputCount, buffer, bufferMax); + info->dwCPOutputCount = 0; + + RTFPutUnicodeString(info, buffer, length); + RTFFree((char *)buffer); +} + +void +RTFFlushOutputBuffer(RTF_Info *info) +{ + if (info->dwCPOutputCount) + RTFFlushCPOutputBuffer(info); + RTFFlushUnicodeOutputBuffer(info); +} + +static void +RTFPutUnicodeChar(RTF_Info *info, int c) +{ + if (info->dwCPOutputCount) + RTFFlushCPOutputBuffer(info); + if (info->dwOutputCount * sizeof(WCHAR) >= ( sizeof info->OutputBuffer - 1 ) ) + RTFFlushUnicodeOutputBuffer( info ); info->OutputBuffer[info->dwOutputCount++] = c; } -void RTFFlushOutputBuffer( RTF_Info *info ) +static void +RTFPutCodePageChar(RTF_Info *info, int c) { - info->OutputBuffer[info->dwOutputCount] = 0; - SendMessageA( info->hwndEdit, EM_REPLACESEL, FALSE, (LPARAM) info->OutputBuffer ); - info->dwOutputCount = 0; -} - -static void PutLitStr (RTF_Info *info, char *str ) -{ - int len = strlen( str ); - - if( ( len + info->dwOutputCount + 1 ) > sizeof info->OutputBuffer ) - RTFFlushOutputBuffer( info ); - if( ( len + 1 ) >= sizeof info->OutputBuffer ) - { - SendMessageA( info->hwndEdit, EM_REPLACESEL, FALSE, (LPARAM) str ); - return; - } - strcpy( &info->OutputBuffer[info->dwOutputCount], str ); - info->dwOutputCount += len; + /* Use dynamic buffer here because it's the best way to handle + * MBCS codepages without having to worry about partial chars */ + if (info->dwCPOutputCount >= info->dwMaxCPOutputCount) + { + info->dwMaxCPOutputCount *= 2; + info->cpOutputBuffer = RTFReAlloc(info->cpOutputBuffer, info->dwMaxCPOutputCount); + } + info->cpOutputBuffer[info->dwCPOutputCount++] = c; } diff --git a/reactos/lib/riched20/richole.c b/reactos/lib/riched20/richole.c index 1c9e4509a75..21e50cb4a23 100644 --- a/reactos/lib/riched20/richole.c +++ b/reactos/lib/riched20/richole.c @@ -64,6 +64,7 @@ IRichEditOle_fnQueryInterface(IRichEditOle *me, REFIID riid, LPVOID *ppvObj) *ppvObj = (LPVOID) This; return S_OK; } + FIXME("%p: unhandled interface %s\n", This, debugstr_guid(riid) ); return E_NOINTERFACE; } @@ -215,7 +216,7 @@ static HRESULT WINAPI IRichEditOle_fnSetHostNames(IRichEditOle *me, LPCSTR lpstrContainerApp, LPCSTR lpstrContainerObj) { IRichEditOleImpl *This = (IRichEditOleImpl *)me; - FIXME("stub %p\n",This); + FIXME("stub %p %s %s\n",This, lpstrContainerApp, lpstrContainerObj); return E_NOTIMPL; } diff --git a/reactos/lib/riched20/rtf.h b/reactos/lib/riched20/rtf.h index 2704ae0504d..53ec6eeac21 100644 --- a/reactos/lib/riched20/rtf.h +++ b/reactos/lib/riched20/rtf.h @@ -11,365 +11,6 @@ #include "richedit.h" -/* The following defines are automatically generated. Do not edit. */ - - -/* These must be sequential beginning from zero */ - -#define rtfSC_nothing 0 -#define rtfSC_space 1 -#define rtfSC_exclam 2 -#define rtfSC_quotedbl 3 -#define rtfSC_numbersign 4 -#define rtfSC_dollar 5 -#define rtfSC_percent 6 -#define rtfSC_ampersand 7 -#define rtfSC_quoteright 8 -#define rtfSC_parenleft 9 -#define rtfSC_parenright 10 -#define rtfSC_asterisk 11 -#define rtfSC_plus 12 -#define rtfSC_comma 13 -#define rtfSC_hyphen 14 -#define rtfSC_period 15 -#define rtfSC_slash 16 -#define rtfSC_zero 17 -#define rtfSC_one 18 -#define rtfSC_two 19 -#define rtfSC_three 20 -#define rtfSC_four 21 -#define rtfSC_five 22 -#define rtfSC_six 23 -#define rtfSC_seven 24 -#define rtfSC_eight 25 -#define rtfSC_nine 26 -#define rtfSC_colon 27 -#define rtfSC_semicolon 28 -#define rtfSC_less 29 -#define rtfSC_equal 30 -#define rtfSC_greater 31 -#define rtfSC_question 32 -#define rtfSC_at 33 -#define rtfSC_A 34 -#define rtfSC_B 35 -#define rtfSC_C 36 -#define rtfSC_D 37 -#define rtfSC_E 38 -#define rtfSC_F 39 -#define rtfSC_G 40 -#define rtfSC_H 41 -#define rtfSC_I 42 -#define rtfSC_J 43 -#define rtfSC_K 44 -#define rtfSC_L 45 -#define rtfSC_M 46 -#define rtfSC_N 47 -#define rtfSC_O 48 -#define rtfSC_P 49 -#define rtfSC_Q 50 -#define rtfSC_R 51 -#define rtfSC_S 52 -#define rtfSC_T 53 -#define rtfSC_U 54 -#define rtfSC_V 55 -#define rtfSC_W 56 -#define rtfSC_X 57 -#define rtfSC_Y 58 -#define rtfSC_Z 59 -#define rtfSC_bracketleft 60 -#define rtfSC_backslash 61 -#define rtfSC_bracketright 62 -#define rtfSC_asciicircum 63 -#define rtfSC_underscore 64 -#define rtfSC_quoteleft 65 -#define rtfSC_a 66 -#define rtfSC_b 67 -#define rtfSC_c 68 -#define rtfSC_d 69 -#define rtfSC_e 70 -#define rtfSC_f 71 -#define rtfSC_g 72 -#define rtfSC_h 73 -#define rtfSC_i 74 -#define rtfSC_j 75 -#define rtfSC_k 76 -#define rtfSC_l 77 -#define rtfSC_m 78 -#define rtfSC_n 79 -#define rtfSC_o 80 -#define rtfSC_p 81 -#define rtfSC_q 82 -#define rtfSC_r 83 -#define rtfSC_s 84 -#define rtfSC_t 85 -#define rtfSC_u 86 -#define rtfSC_v 87 -#define rtfSC_w 88 -#define rtfSC_x 89 -#define rtfSC_y 90 -#define rtfSC_z 91 -#define rtfSC_braceleft 92 -#define rtfSC_bar 93 -#define rtfSC_braceright 94 -#define rtfSC_asciitilde 95 -#define rtfSC_exclamdown 96 -#define rtfSC_cent 97 -#define rtfSC_sterling 98 -#define rtfSC_fraction 99 -#define rtfSC_yen 100 -#define rtfSC_florin 101 -#define rtfSC_section 102 -#define rtfSC_currency 103 -#define rtfSC_quotedblleft 104 -#define rtfSC_guillemotleft 105 -#define rtfSC_guilsinglleft 106 -#define rtfSC_guilsinglright 107 -#define rtfSC_fi 108 -#define rtfSC_fl 109 -#define rtfSC_endash 110 -#define rtfSC_dagger 111 -#define rtfSC_daggerdbl 112 -#define rtfSC_periodcentered 113 -#define rtfSC_paragraph 114 -#define rtfSC_bullet 115 -#define rtfSC_quotesinglbase 116 -#define rtfSC_quotedblbase 117 -#define rtfSC_quotedblright 118 -#define rtfSC_guillemotright 119 -#define rtfSC_ellipsis 120 -#define rtfSC_perthousand 121 -#define rtfSC_questiondown 122 -#define rtfSC_grave 123 -#define rtfSC_acute 124 -#define rtfSC_circumflex 125 -#define rtfSC_tilde 126 -#define rtfSC_macron 127 -#define rtfSC_breve 128 -#define rtfSC_dotaccent 129 -#define rtfSC_dieresis 130 -#define rtfSC_ring 131 -#define rtfSC_cedilla 132 -#define rtfSC_hungarumlaut 133 -#define rtfSC_ogonek 134 -#define rtfSC_caron 135 -#define rtfSC_emdash 136 -#define rtfSC_AE 137 -#define rtfSC_ordfeminine 138 -#define rtfSC_Lslash 139 -#define rtfSC_Oslash 140 -#define rtfSC_OE 141 -#define rtfSC_ordmasculine 142 -#define rtfSC_ae 143 -#define rtfSC_dotlessi 144 -#define rtfSC_lslash 145 -#define rtfSC_oslash 146 -#define rtfSC_oe 147 -#define rtfSC_germandbls 148 -#define rtfSC_Aacute 149 -#define rtfSC_Acircumflex 150 -#define rtfSC_Adieresis 151 -#define rtfSC_Agrave 152 -#define rtfSC_Aring 153 -#define rtfSC_Atilde 154 -#define rtfSC_Ccedilla 155 -#define rtfSC_Eacute 156 -#define rtfSC_Ecircumflex 157 -#define rtfSC_Edieresis 158 -#define rtfSC_Egrave 159 -#define rtfSC_Eth 160 -#define rtfSC_Iacute 161 -#define rtfSC_Icircumflex 162 -#define rtfSC_Idieresis 163 -#define rtfSC_Igrave 164 -#define rtfSC_Ntilde 165 -#define rtfSC_Oacute 166 -#define rtfSC_Ocircumflex 167 -#define rtfSC_Odieresis 168 -#define rtfSC_Ograve 169 -#define rtfSC_Otilde 170 -#define rtfSC_Scaron 171 -#define rtfSC_Thorn 172 -#define rtfSC_Uacute 173 -#define rtfSC_Ucircumflex 174 -#define rtfSC_Udieresis 175 -#define rtfSC_Ugrave 176 -#define rtfSC_Yacute 177 -#define rtfSC_Ydieresis 178 -#define rtfSC_aacute 179 -#define rtfSC_acircumflex 180 -#define rtfSC_adieresis 181 -#define rtfSC_agrave 182 -#define rtfSC_aring 183 -#define rtfSC_atilde 184 -#define rtfSC_brokenbar 185 -#define rtfSC_ccedilla 186 -#define rtfSC_copyright 187 -#define rtfSC_degree 188 -#define rtfSC_divide 189 -#define rtfSC_eacute 190 -#define rtfSC_ecircumflex 191 -#define rtfSC_edieresis 192 -#define rtfSC_egrave 193 -#define rtfSC_eth 194 -#define rtfSC_iacute 195 -#define rtfSC_icircumflex 196 -#define rtfSC_idieresis 197 -#define rtfSC_igrave 198 -#define rtfSC_logicalnot 199 -#define rtfSC_minus 200 -#define rtfSC_multiply 201 -#define rtfSC_ntilde 202 -#define rtfSC_oacute 203 -#define rtfSC_ocircumflex 204 -#define rtfSC_odieresis 205 -#define rtfSC_ograve 206 -#define rtfSC_onehalf 207 -#define rtfSC_onequarter 208 -#define rtfSC_onesuperior 209 -#define rtfSC_otilde 210 -#define rtfSC_plusminus 211 -#define rtfSC_registered 212 -#define rtfSC_thorn 213 -#define rtfSC_threequarters 214 -#define rtfSC_threesuperior 215 -#define rtfSC_trademark 216 -#define rtfSC_twosuperior 217 -#define rtfSC_uacute 218 -#define rtfSC_ucircumflex 219 -#define rtfSC_udieresis 220 -#define rtfSC_ugrave 221 -#define rtfSC_yacute 222 -#define rtfSC_ydieresis 223 -#define rtfSC_Alpha 224 -#define rtfSC_Beta 225 -#define rtfSC_Chi 226 -#define rtfSC_Delta 227 -#define rtfSC_Epsilon 228 -#define rtfSC_Phi 229 -#define rtfSC_Gamma 230 -#define rtfSC_Eta 231 -#define rtfSC_Iota 232 -#define rtfSC_Kappa 233 -#define rtfSC_Lambda 234 -#define rtfSC_Mu 235 -#define rtfSC_Nu 236 -#define rtfSC_Omicron 237 -#define rtfSC_Pi 238 -#define rtfSC_Theta 239 -#define rtfSC_Rho 240 -#define rtfSC_Sigma 241 -#define rtfSC_Tau 242 -#define rtfSC_Upsilon 243 -#define rtfSC_varUpsilon 244 -#define rtfSC_Omega 245 -#define rtfSC_Xi 246 -#define rtfSC_Psi 247 -#define rtfSC_Zeta 248 -#define rtfSC_alpha 249 -#define rtfSC_beta 250 -#define rtfSC_chi 251 -#define rtfSC_delta 252 -#define rtfSC_epsilon 253 -#define rtfSC_phi 254 -#define rtfSC_varphi 255 -#define rtfSC_gamma 256 -#define rtfSC_eta 257 -#define rtfSC_iota 258 -#define rtfSC_kappa 259 -#define rtfSC_lambda 260 -#define rtfSC_mu 261 -#define rtfSC_nu 262 -#define rtfSC_omicron 263 -#define rtfSC_pi 264 -#define rtfSC_varpi 265 -#define rtfSC_theta 266 -#define rtfSC_vartheta 267 -#define rtfSC_rho 268 -#define rtfSC_sigma 269 -#define rtfSC_varsigma 270 -#define rtfSC_tau 271 -#define rtfSC_upsilon 272 -#define rtfSC_omega 273 -#define rtfSC_xi 274 -#define rtfSC_psi 275 -#define rtfSC_zeta 276 -#define rtfSC_nobrkspace 277 -#define rtfSC_nobrkhyphen 278 -#define rtfSC_lessequal 279 -#define rtfSC_greaterequal 280 -#define rtfSC_infinity 281 -#define rtfSC_integral 282 -#define rtfSC_notequal 283 -#define rtfSC_radical 284 -#define rtfSC_radicalex 285 -#define rtfSC_approxequal 286 -#define rtfSC_apple 287 -#define rtfSC_partialdiff 288 -#define rtfSC_opthyphen 289 -#define rtfSC_formula 290 -#define rtfSC_lozenge 291 -#define rtfSC_universal 292 -#define rtfSC_existential 293 -#define rtfSC_suchthat 294 -#define rtfSC_congruent 295 -#define rtfSC_therefore 296 -#define rtfSC_perpendicular 297 -#define rtfSC_minute 298 -#define rtfSC_club 299 -#define rtfSC_diamond 300 -#define rtfSC_heart 301 -#define rtfSC_spade 302 -#define rtfSC_arrowboth 303 -#define rtfSC_arrowleft 304 -#define rtfSC_arrowup 305 -#define rtfSC_arrowright 306 -#define rtfSC_arrowdown 307 -#define rtfSC_second 308 -#define rtfSC_proportional 309 -#define rtfSC_equivalence 310 -#define rtfSC_arrowvertex 311 -#define rtfSC_arrowhorizex 312 -#define rtfSC_carriagereturn 313 -#define rtfSC_aleph 314 -#define rtfSC_Ifraktur 315 -#define rtfSC_Rfraktur 316 -#define rtfSC_weierstrass 317 -#define rtfSC_circlemultiply 318 -#define rtfSC_circleplus 319 -#define rtfSC_emptyset 320 -#define rtfSC_intersection 321 -#define rtfSC_union 322 -#define rtfSC_propersuperset 323 -#define rtfSC_reflexsuperset 324 -#define rtfSC_notsubset 325 -#define rtfSC_propersubset 326 -#define rtfSC_reflexsubset 327 -#define rtfSC_element 328 -#define rtfSC_notelement 329 -#define rtfSC_angle 330 -#define rtfSC_gradient 331 -#define rtfSC_product 332 -#define rtfSC_logicaland 333 -#define rtfSC_logicalor 334 -#define rtfSC_arrowdblboth 335 -#define rtfSC_arrowdblleft 336 -#define rtfSC_arrowdblup 337 -#define rtfSC_arrowdblright 338 -#define rtfSC_arrowdbldown 339 -#define rtfSC_angleleft 340 -#define rtfSC_registersans 341 -#define rtfSC_copyrightsans 342 -#define rtfSC_trademarksans 343 -#define rtfSC_angleright 344 -#define rtfSC_mathplus 345 -#define rtfSC_mathminus 346 -#define rtfSC_mathasterisk 347 -#define rtfSC_mathnumbersign 348 -#define rtfSC_dotmath 349 -#define rtfSC_mathequal 350 -#define rtfSC_mathtilde 351 - -#define rtfSC_MaxChar 352 /* * rtf.h - RTF document processing stuff. Release 1.10. */ @@ -418,13 +59,7 @@ */ -# ifdef THINK_C -# define rtfNoParam (-32768) /* 16-bit max. neg. value */ -# endif -# ifndef rtfNoParam # define rtfNoParam (-1000000) -# endif - @@ -546,7 +181,8 @@ # define rtfIndexRange 71 # define rtfTOC 72 # define rtfNeXTGraphic 73 -# define rtfMaxDestination 74 /* highest dest + 1 */ +# define rtfGenerator 74 +# define rtfMaxDestination 75 /* highest dest + 1 */ # define rtfFontFamily 4 # define rtfFFNil 0 @@ -624,6 +260,7 @@ # define rtfNoWidthNonJoiner 56 /* new in 1.10 */ # define rtfCurHeadPict 57 /* valid? */ /*# define rtfCurAnnot 58*/ /* apparently not used */ +# define rtfUnicode 58 /* no better category*/ # define rtfStyleAttr 7 # define rtfAdditive 0 /* new in 1.10 */ @@ -709,6 +346,8 @@ # define rtfAnnotProtected 75 /* new in 1.10 */ # define rtfRTLDoc 76 /* new in 1.10 */ # define rtfLTRDoc 77 /* new in 1.10 */ +# define rtfAnsiCodePage 78 +# define rtfUTF8RTF 79 # define rtfSectAttr 9 # define rtfSectDef 0 @@ -950,6 +589,7 @@ # define rtfCharCharSet 33 /* new in 1.10 */ # define rtfLanguage 34 # define rtfGray 35 +# define rtfUnicodeLength 36 # define rtfPictAttr 13 # define rtfMacQD 0 @@ -1287,20 +927,6 @@ # define rtfLangTurkish 0x041f # define rtfLangUrdu 0x0420 -/* - * CharSet indices - */ - -# define rtfCSGeneral 0 /* general (default) charset */ -# define rtfCSSymbol 1 /* symbol charset */ - -/* - * Flags for auto-charset-processing. Both are on by default. - */ - -# define rtfReadCharSet 0x01 /* auto-read charset files */ -# define rtfSwitchCharSet 0x02 /* auto-switch charset maps */ - /* * Style types */ @@ -1381,20 +1007,25 @@ struct RTFStyleElt # define New(t) ((t *) RTFAlloc ((int) sizeof (t))) -/* maximum number of character values representable in a byte */ - -# define charSetSize 256 - -/* charset stack size */ - -# define maxCSStack 10 +/* Parser stack size */ +# define maxStack 32 struct _RTF_Info; typedef struct _RTF_Info RTF_Info; typedef void (*RTFFuncPtr) (RTF_Info *); /* generic function pointer */ + +/* RTF parser stack element */ +struct tagRTFState { + CHARFORMAT2W fmt; + int codePage; + int unicodeLength; +}; +typedef struct tagRTFState RTFState; + + struct _RTF_Info { /* * Public variables (listed in rtf.h) @@ -1434,55 +1065,26 @@ struct _RTF_Info { int prevChar; int bumpLine; + /* Document-wide attributes */ RTFFont *fontList; /* these lists MUST be */ RTFColor *colorList; /* initialized to NULL */ RTFStyle *styleList; + int ansiCodePage; /* ANSI codepage used in conversion to Unicode */ + + /* Character attributes */ + int unicodeLength; /* The length of ANSI representation of Unicode characters */ + int codePage; /* Current codepage for text conversion */ char *inputName; char *outputName; - EDITSTREAM editstream; - char InputBuffer[0x1000]; - DWORD dwInputSize; - DWORD dwInputUsed; + ME_InStream *stream; /* edit window to output to */ HWND hwndEdit; - - /* - * These arrays are used to map RTF input character values onto the standard - * character names represented by the values. Input character values are - * used as indices into the arrays to produce standard character codes. - */ - - - char *genCharSetFile ; - int genCharCode[charSetSize]; /* general */ - int haveGenCharSet; - - char *symCharSetFile; - int symCharCode[charSetSize]; /* symbol */ - int haveSymCharSet; - - int curCharSet; - int *curCharCode; - - /* - * By default, the reader is configured to handle charset mapping invisibly, - * including reading the charset files and switching charset maps as necessary - * for Symbol font. - */ - - int autoCharSetFlags; - - /* - * Stack for keeping track of charset map on group begin/end. This is - * necessary because group termination reverts the font to the previous - * value, which may implicitly change it. - */ - - int csStack[maxCSStack]; - int csTop; + + ME_TextEditor *editor; + ME_Style *style; RTFFuncPtr ccb[rtfMaxClass]; /* class callbacks */ @@ -1492,12 +1094,15 @@ struct _RTF_Info { RTFFuncPtr panicProc; - FILE *(*libFileOpen) (); - - char *outMap[rtfSC_MaxChar]; - DWORD dwOutputCount; - char OutputBuffer[0x1000]; + WCHAR OutputBuffer[0x1000]; + + DWORD dwCPOutputCount; + DWORD dwMaxCPOutputCount; + char *cpOutputBuffer; + + RTFState stack[maxStack]; + int stackTop; }; @@ -1506,6 +1111,7 @@ struct _RTF_Info { */ void RTFInit (RTF_Info *); +void RTFDestroy(RTF_Info *info); void RTFSetInputName (RTF_Info *, char *); char *RTFGetInputName (RTF_Info *); void RTFSetOutputName (RTF_Info *, char *); @@ -1530,10 +1136,6 @@ int RTFCheckMM (RTF_Info *, int, int); RTFFont *RTFGetFont (RTF_Info *, int); RTFColor *RTFGetColor (RTF_Info *, int); RTFStyle *RTFGetStyle (RTF_Info *, int); -# define RTFAlloc(size) _RTFAlloc ((int) size) -char *_RTFAlloc (int); -char *RTFStrSave (char *); -void RTFFree (char *); int RTFCharToHex ( char); int RTFHexToChar ( int ); void RTFSetMsgProc ( RTFFuncPtr ); @@ -1549,22 +1151,12 @@ void RTFSetPanicProc ( RTF_Info *, RTFFuncPtr); void RTFMsg (RTF_Info *, const char *fmt, ...); void RTFPanic (RTF_Info *, const char *fmt, ...); -int RTFReadOutputMap ( RTF_Info *, char *[], int); -int RTFReadCharSetMap ( RTF_Info *, int); -void RTFSetCharSetMap ( RTF_Info *, char *, int); -int RTFStdCharCode ( RTF_Info *, const char *); -const char *RTFStdCharName ( RTF_Info *, int); -int RTFMapChar ( RTF_Info *, int); -int RTFGetCharSet( RTF_Info * ); -void RTFSetCharSet( RTF_Info *, int); - -void RTFSetOpenLibFileProc ( RTF_Info *, FILE *(*)()); -FILE *RTFOpenLibFile ( RTF_Info *, char *, char *); - void RTFFlushOutputBuffer( RTF_Info *info ); -void RTFSetEditStream(RTF_Info *, EDITSTREAM *es); +void RTFSetEditStream(RTF_Info *info, ME_InStream *stream); void WriterInit (RTF_Info *); int BeginFile (RTF_Info *); +int RTFCharSetToCodePage(RTF_Info *info, int charset); + #endif diff --git a/reactos/lib/riched20/run.c b/reactos/lib/riched20/run.c index 9e0ef76cca3..533aae2a642 100644 --- a/reactos/lib/riched20/run.c +++ b/reactos/lib/riched20/run.c @@ -26,7 +26,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(richedit); int ME_CanJoinRuns(ME_Run *run1, ME_Run *run2) { - if ((run1->nFlags | run2->nFlags) & (MERF_ENDPARA | MERF_GRAPHICS)) + if ((run1->nFlags | run2->nFlags) & MERF_NOJOIN) return 0; if (run1->style != run2->style) return 0; @@ -91,8 +91,8 @@ void ME_CheckCharOffsets(ME_TextEditor *editor) ofs = 0; break; case diRun: - TRACE("run, real ofs = %d (+ofsp = %d), counted = %d, len = %d, txt = \"%s\", flags=%08x, fx&mask = %08lx\n", - p->member.run.nCharOfs, p->member.run.nCharOfs+ofsp, ofsp+ofs, + TRACE("run, real ofs = %d (+ofsp = %d), counted = %d, len = %d, txt = \"%s\", flags=%08x, fx&mask = %08lx\n", + p->member.run.nCharOfs, p->member.run.nCharOfs+ofsp, ofsp+ofs, p->member.run.strText->nLen, debugstr_w(p->member.run.strText->szData), p->member.run.nFlags, p->member.run.style->fmt.dwMask & p->member.run.style->fmt.dwEffects); @@ -108,14 +108,14 @@ void ME_CheckCharOffsets(ME_TextEditor *editor) int ME_CharOfsFromRunOfs(ME_TextEditor *editor, ME_DisplayItem *pRun, int nOfs) { ME_DisplayItem *pPara; - + assert(pRun->type == diRun); assert(pRun->member.run.nCharOfs != -1); pPara = ME_FindItemBack(pRun, diParagraph); assert(pPara); assert(pPara->type==diParagraph); - return pPara->member.para.nCharOfs + pRun->member.run.nCharOfs + return pPara->member.para.nCharOfs + pRun->member.run.nCharOfs + ME_VPosToPos(pRun->member.run.strText, nOfs); } @@ -128,7 +128,7 @@ void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem ** { ME_DisplayItem *pPara; int nParaOfs; - + pPara = editor->pBuffer->pFirst->member.para.next_para; assert(pPara); assert(ppRun); @@ -137,18 +137,18 @@ void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem ** { nParaOfs = pPara->member.para.nCharOfs; assert(nCharOfs >= nParaOfs); - + if (nCharOfs < pPara->member.para.next_para->member.para.nCharOfs) { *ppRun = ME_FindItemFwd(pPara, diRun); - assert(*ppRun); + assert(*ppRun); while (!((*ppRun)->member.run.nFlags & MERF_ENDPARA)) { ME_DisplayItem *pNext = ME_FindItemFwd(*ppRun, diRun); assert(pNext); assert(pNext->type == diRun); if (nCharOfs < nParaOfs + pNext->member.run.nCharOfs) { - *pOfs = ME_PosToVPos((*ppRun)->member.run.strText, + *pOfs = ME_PosToVPos((*ppRun)->member.run.strText, nCharOfs - nParaOfs - (*ppRun)->member.run.nCharOfs); return; } @@ -157,12 +157,12 @@ void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem ** if (nCharOfs == nParaOfs + (*ppRun)->member.run.nCharOfs) { *pOfs = 0; return; - } + } } pPara = pPara->member.para.next_para; } *ppRun = ME_FindItemBack(editor->pBuffer->pLast, diRun); - *pOfs = 0; + *pOfs = 0; assert((*ppRun)->member.run.nFlags & MERF_ENDPARA); } @@ -174,13 +174,15 @@ void ME_JoinRuns(ME_TextEditor *editor, ME_DisplayItem *p) assert(p->member.run.nCharOfs != -1); ME_GetParagraph(p)->member.para.nFlags |= MEPF_REWRAP; + if (editor->bCaretAtEnd && editor->pCursors[0].pRun == pNext) + editor->bCaretAtEnd = FALSE; for (i=0; inCursors; i++) { if (editor->pCursors[i].pRun == pNext) { editor->pCursors[i].pRun = p; editor->pCursors[i].nOffset += ME_StrVLen(p->member.run.strText); } } - + ME_AppendString(p->member.run.strText, pNext->member.run.strText); ME_Remove(pNext); ME_DestroyDisplayItem(pNext); @@ -198,7 +200,8 @@ ME_DisplayItem *ME_SplitRun(ME_Context *c, ME_DisplayItem *item, int nVChar) ME_TextEditor *editor = c->editor; ME_DisplayItem *item2 = NULL; ME_Run *run, *run2; - + ME_Paragraph *para = &ME_GetParagraph(item)->member.para; + assert(item->member.run.nCharOfs != -1); if(TRACE_ON(richedit)) { @@ -213,28 +216,28 @@ ME_DisplayItem *ME_SplitRun(ME_Context *c, ME_DisplayItem *item, int nVChar) run->pt.x, run->pt.y); item2 = ME_SplitRunSimple(editor, item, nVChar); - + run2 = &item2->member.run; - - ME_CalcRunExtent(c, run); - ME_CalcRunExtent(c, run2); - + + ME_CalcRunExtent(c, para, run); + ME_CalcRunExtent(c, para, run2); + run2->pt.x = run->pt.x+run->nWidth; run2->pt.y = run->pt.y; - + if(TRACE_ON(richedit)) { TRACE("Before check after split\n"); ME_CheckCharOffsets(editor); TRACE("After check after split\n"); - TRACE("After split: %s(%ld, %ld), %s(%ld, %ld)\n", + TRACE("After split: %s(%ld, %ld), %s(%ld, %ld)\n", debugstr_w(run->strText->szData), run->pt.x, run->pt.y, debugstr_w(run2->strText->szData), run2->pt.x, run2->pt.y); } return item2; } - + /* split a run starting from voffset */ ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, int nVChar) { @@ -244,22 +247,22 @@ ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, i int i; assert(nVChar > 0 && nVChar < ME_StrVLen(run->strText)); assert(item->type == diRun); - assert(!(item->member.run.nFlags & MERF_GRAPHICS)); + assert(!(item->member.run.nFlags & (MERF_GRAPHICS | MERF_TAB))); assert(item->member.run.nCharOfs != -1); - item2 = ME_MakeRun(run->style, + item2 = ME_MakeRun(run->style, ME_VSplitString(run->strText, nVChar), run->nFlags&MERF_SPLITMASK); - + item2->member.run.nCharOfs = item->member.run.nCharOfs+ ME_VPosToPos(item->member.run.strText, nVChar); run2 = &item2->member.run; ME_InsertBefore(item->next, item2); - + ME_UpdateRunFlags(editor, run); ME_UpdateRunFlags(editor, run2); for (i=0; inCursors; i++) { - if (editor->pCursors[i].pRun == item && + if (editor->pCursors[i].pRun == item && editor->pCursors[i].nOffset >= nVChar) { assert(item2->type == diRun); editor->pCursors[i].pRun = item2; @@ -270,18 +273,6 @@ ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, i return item2; } -/* split the start and final whitespace into separate runs */ -/* returns the last run added */ -/* -ME_DisplayItem *ME_SplitFurther(ME_TextEditor *editor, ME_DisplayItem *item) -{ - int i, nVLen, nChanged; - assert(item->type == diRun); - assert(!(item->member.run.nFlags & MERF_GRAPHICS)); - return item; -} -*/ - ME_DisplayItem *ME_MakeRun(ME_Style *s, ME_String *strData, int nFlags) { ME_DisplayItem *item = ME_MakeDI(diRun); @@ -298,12 +289,14 @@ ME_DisplayItem *ME_InsertRun(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem ME_Cursor tmp; ME_DisplayItem *pDI; ME_UndoItem *pUI; - + assert(pItem->type == diRun || pItem->type == diUndoInsertRun); - + pUI = ME_AddUndoItem(editor, diUndoDeleteRun, NULL); - pUI->nStart = nCharOfs; - pUI->nLen = pItem->member.run.strText->nLen; + if (pUI) { + pUI->nStart = nCharOfs; + pUI->nLen = pItem->member.run.strText->nLen; + } ME_CursorFromCharOfs(editor, nCharOfs, &tmp); if (tmp.nOffset) { tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset); @@ -315,13 +308,8 @@ ME_DisplayItem *ME_InsertRun(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem TRACE("Shift length:%d\n", pDI->member.run.strText->nLen); ME_PropagateCharOffset(tmp.pRun, pDI->member.run.strText->nLen); ME_GetParagraph(tmp.pRun)->member.para.nFlags |= MEPF_REWRAP; - - return pDI; -} -static inline int ME_IsWSpace(WCHAR ch) -{ - return ch <= ' '; + return pDI; } void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run) @@ -331,19 +319,19 @@ void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run) run->nFlags |= MERF_SPLITTABLE; else run->nFlags &= ~MERF_SPLITTABLE; - - if (!(run->nFlags & MERF_GRAPHICS)) { + + if (!(run->nFlags & MERF_NOTEXT)) { if (ME_IsWhitespaces(run->strText)) run->nFlags |= MERF_WHITESPACE | MERF_STARTWHITE | MERF_ENDWHITE; else { run->nFlags &= ~MERF_WHITESPACE; - + if (ME_IsWSpace(ME_GetCharFwd(run->strText,0))) run->nFlags |= MERF_STARTWHITE; else run->nFlags &= ~MERF_STARTWHITE; - + if (ME_IsWSpace(ME_GetCharBack(run->strText,0))) run->nFlags |= MERF_ENDWHITE; else @@ -361,7 +349,7 @@ void ME_GetGraphicsSize(ME_TextEditor *editor, ME_Run *run, SIZE *pSize) pSize->cy = 64; } -int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run) +int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Paragraph *para, ME_Run *run) { int fit = 0; HGDIOBJ hOldFont; @@ -370,6 +358,12 @@ int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run) if (!run->strText->nLen) return 0; + if (run->nFlags & MERF_TAB) + { + if (cx < run->nWidth/2) + return 0; + return 1; + } if (run->nFlags & MERF_GRAPHICS) { SIZE sz; @@ -380,9 +374,9 @@ int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run) } hDC = GetDC(editor->hWnd); hOldFont = ME_SelectStyleFont(editor, hDC, run->style); - GetTextExtentExPointW(hDC, run->strText->szData, run->strText->nLen, + GetTextExtentExPointW(hDC, run->strText->szData, run->strText->nLen, cx, &fit, NULL, &sz); - ME_UnselectStyleFont(editor, hDC, run->style, hOldFont); + ME_UnselectStyleFont(editor, hDC, run->style, hOldFont); ReleaseDC(editor->hWnd, hDC); return fit; } @@ -396,6 +390,12 @@ int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run) if (!run->strText->nLen) return 0; + if (run->nFlags & MERF_TAB) + { + if (cx < run->nWidth/2) + return 0; + return 1; + } if (run->nFlags & MERF_GRAPHICS) { SIZE sz; @@ -407,19 +407,19 @@ int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run) hDC = GetDC(editor->hWnd); hOldFont = ME_SelectStyleFont(editor, hDC, run->style); - GetTextExtentExPointW(hDC, run->strText->szData, run->strText->nLen, + GetTextExtentExPointW(hDC, run->strText->szData, run->strText->nLen, cx, &fit, NULL, &sz); if (fit != run->strText->nLen) { int chars = 1; - + GetTextExtentPoint32W(hDC, run->strText->szData, fit, &sz2); fit1 = ME_StrRelPos(run->strText, fit, &chars); GetTextExtentPoint32W(hDC, run->strText->szData, fit1, &sz3); if (cx >= (sz2.cx+sz3.cx)/2) fit = fit1; } - ME_UnselectStyleFont(editor, hDC, run->style, hOldFont); + ME_UnselectStyleFont(editor, hDC, run->style, hOldFont); ReleaseDC(editor->hWnd, hDC); return fit; } @@ -429,7 +429,7 @@ int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset) SIZE size; HDC hDC = GetDC(editor->hWnd); HGDIOBJ hOldFont; - + if (pRun->nFlags & MERF_GRAPHICS) { if (!nOffset) return 0; @@ -438,56 +438,88 @@ int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset) } hOldFont = ME_SelectStyleFont(editor, hDC, pRun->style); GetTextExtentPoint32W(hDC, pRun->strText->szData, nOffset, &size); - ME_UnselectStyleFont(editor, hDC, pRun->style, hOldFont); + ME_UnselectStyleFont(editor, hDC, pRun->style, hOldFont); ReleaseDC(editor->hWnd, hDC); return size.cx; } -void ME_GetTextExtent(ME_Context *c, LPCWSTR szText, int nChars, ME_Style *s, +void ME_GetTextExtent(ME_Context *c, LPCWSTR szText, int nChars, ME_Style *s, SIZE *size) { HDC hDC = c->hDC; HGDIOBJ hOldFont; hOldFont = ME_SelectStyleFont(c->editor, hDC, s); GetTextExtentPoint32W(hDC, szText, nChars, size); - ME_UnselectStyleFont(c->editor, hDC, s, hOldFont); + ME_UnselectStyleFont(c->editor, hDC, s, hOldFont); } -SIZE ME_GetRunSize(ME_Context *c, ME_Run *run, int nLen) +SIZE ME_GetRunSizeCommon(ME_Context *c, ME_Paragraph *para, ME_Run *run, int nLen, int *pAscent, int *pDescent) { SIZE size; int nMaxLen = ME_StrVLen(run->strText); if (nLen>nMaxLen) nLen = nMaxLen; - + + /* FIXME the following call also ensures that TEXTMETRIC structure is filled + * this is wasteful for graphics and TAB runs, but that shouldn't matter + * in practice + */ + ME_GetTextExtent(c, run->strText->szData, nLen, run->style, &size); + assert(run->style->tm.tmAscent>0); + assert(run->style->tm.tmDescent>0); + *pAscent = run->style->tm.tmAscent; + *pDescent = run->style->tm.tmDescent; + size.cy = *pAscent + *pDescent; + + if (run->nFlags & MERF_TAB) + { + int pos = 0, i = 0, ppos; + int lpsx = GetDeviceCaps(c->hDC, LOGPIXELSX); + PARAFORMAT2 *pFmt = para->pFmt; + do { + if (i < pFmt->cTabCount) + { + pos = pFmt->rgxTabs[i]&0x00FFFFFF; + i++; + } + else + { + pos += 720-(pos%720); + } + ppos = pos*lpsx/1440; + if (ppos>run->pt.x) { + size.cx = ppos - run->pt.x; + break; + } + } while(1); + size.cy = *pAscent + *pDescent; + return size; + } if (run->nFlags & MERF_GRAPHICS) { ME_GetGraphicsSize(c->editor, run, &size); + if (size.cy > *pAscent) + *pAscent = size.cy; + /* descent is unchanged */ return size; } - ME_GetTextExtent(c, run->strText->szData, nLen, run->style, &size); - return size; } -void ME_CalcRunExtent(ME_Context *c, ME_Run *run) +SIZE ME_GetRunSize(ME_Context *c, ME_Paragraph *para, ME_Run *run, int nLen) +{ + int asc, desc; + return ME_GetRunSizeCommon(c, para, run, nLen, &asc, &desc); +} + +void ME_CalcRunExtent(ME_Context *c, ME_Paragraph *para, ME_Run *run) { - SIZE size; int nEnd = ME_StrVLen(run->strText); - - if (run->nFlags & MERF_GRAPHICS) { - ME_GetGraphicsSize(c->editor, run, &size); - run->nWidth = size.cx; - run->nAscent = size.cy; - run->nDescent = 0; - return; - } - ME_GetTextExtent(c, run->strText->szData, nEnd, run->style, &size); + SIZE size = ME_GetRunSizeCommon(c, para, run, nEnd, &run->nAscent, &run->nDescent); run->nWidth = size.cx; - run->nAscent = run->style->tm.tmAscent; - run->nDescent = run->style->tm.tmDescent; + assert(size.cx); } void ME_MustBeWrapped(ME_Context *c, ME_DisplayItem *para) @@ -517,7 +549,7 @@ void ME_SetCharFormat(ME_TextEditor *editor, int nOfs, int nChars, CHARFORMAT2W { ME_Cursor tmp, tmp2; ME_DisplayItem *para; - + ME_CursorFromCharOfs(editor, nOfs, &tmp); if (tmp.nOffset) tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset); @@ -528,7 +560,7 @@ void ME_SetCharFormat(ME_TextEditor *editor, int nOfs, int nChars, CHARFORMAT2W para = ME_GetParagraph(tmp.pRun); para->member.para.nFlags |= MEPF_REWRAP; - + while(tmp.pRun != tmp2.pRun) { ME_UndoItem *undo = NULL; @@ -559,9 +591,9 @@ void ME_SetCharFormat(ME_TextEditor *editor, int nOfs, int nChars, CHARFORMAT2W void ME_SetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *mod) { - ME_Style *style; + ME_Style *style; ME_UndoItem *undo; - + assert(mod->cbSize == sizeof(CHARFORMAT2W)); undo = ME_AddUndoItem(editor, diUndoSetDefaultCharFormat, NULL); if (undo) { @@ -607,10 +639,10 @@ void ME_GetCharFormat(ME_TextEditor *editor, int nFrom, int nTo, CHARFORMAT2W *p ME_DisplayItem *run, *run_end; int nOffset, nOffset2; CHARFORMAT2W tmp; - + if (nTo>nFrom) /* selection consists of chars from nFrom up to nTo-1 */ nTo--; - + ME_RunOfsFromCharOfs(editor, nFrom, &run, &nOffset); if (nFrom == nTo) /* special case - if selection is empty, take previous char's formatting */ { @@ -626,22 +658,22 @@ void ME_GetCharFormat(ME_TextEditor *editor, int nFrom, int nTo, CHARFORMAT2W *p return; } ME_RunOfsFromCharOfs(editor, nTo, &run_end, &nOffset2); - + ME_GetRunCharFormat(editor, run, pFmt); - + if (run == run_end) return; - + do { /* FIXME add more style feature comparisons */ int nAttribs = CFM_SIZE | CFM_FACE | CFM_COLOR; int nEffects = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE; run = ME_FindItemFwd(run, diRun); - + ZeroMemory(&tmp, sizeof(tmp)); tmp.cbSize = sizeof(tmp); ME_GetRunCharFormat(editor, run, &tmp); - + assert((tmp.dwMask & nAttribs) == nAttribs); assert((tmp.dwMask & nEffects) == nEffects); /* reset flags that differ */ @@ -665,8 +697,8 @@ void ME_GetCharFormat(ME_TextEditor *editor, int nFrom, int nTo, CHARFORMAT2W *p pFmt->dwMask &= ~CFM_COLOR; } } - + pFmt->dwMask &= ~((pFmt->dwEffects ^ tmp.dwEffects) & nEffects); - + } while(run != run_end); } diff --git a/reactos/lib/riched20/string.c b/reactos/lib/riched20/string.c index c18fa1d5501..6abd22a5ff8 100644 --- a/reactos/lib/riched20/string.c +++ b/reactos/lib/riched20/string.c @@ -112,7 +112,7 @@ int ME_IsWhitespaces(ME_String *s) { /* FIXME multibyte */ WCHAR *pos = s->szData; - while(*pos++ == ' ') + while(ME_IsWSpace(*pos++)) ; pos--; if (*pos) @@ -123,15 +123,14 @@ int ME_IsWhitespaces(ME_String *s) int ME_IsSplitable(ME_String *s) { - /* FIXME multibyte */ WCHAR *pos = s->szData; WCHAR ch; - while(*pos++ == L' ') + while(ME_IsWSpace(*pos++)) ; pos--; while((ch = *pos++) != 0) { - if (ch == L' ') + if (ME_IsWSpace(ch)) return 1; } return 0; @@ -255,7 +254,7 @@ int ME_GetCharBack(ME_String *s, int nPos) int ME_FindNonWhitespaceV(ME_String *s, int nVChar) { int i; - for (i = nVChar; isspace(s->szData[i]) && inLen; i++) + for (i = nVChar; inLen && ME_IsWSpace(s->szData[i]); i++) ; return i; @@ -264,7 +263,7 @@ int ME_FindNonWhitespaceV(ME_String *s, int nVChar) { /* note: returns offset of the first trailing whitespace */ int ME_ReverseFindNonWhitespaceV(ME_String *s, int nVChar) { int i; - for (i = nVChar; i>0 && isspace(s->szData[i-1]); i--) + for (i = nVChar; i>0 && ME_IsWSpace(s->szData[i-1]); i--) ; return i; @@ -273,7 +272,7 @@ int ME_ReverseFindNonWhitespaceV(ME_String *s, int nVChar) { /* note: returns offset of the first trailing nonwhitespace */ int ME_ReverseFindWhitespaceV(ME_String *s, int nVChar) { int i; - for (i = nVChar; i>0 && !isspace(s->szData[i-1]); i--) + for (i = nVChar; i>0 && !ME_IsWSpace(s->szData[i-1]); i--) ; return i; diff --git a/reactos/lib/riched20/style.c b/reactos/lib/riched20/style.c index b2be737f7ab..cbdd9327168 100644 --- a/reactos/lib/riched20/style.c +++ b/reactos/lib/riched20/style.c @@ -54,7 +54,7 @@ CHARFORMAT2W *ME_ToCF2W(CHARFORMAT2W *to, CHARFORMAT2W *from) if (f->dwMask & CFM_FACE) MultiByteToWideChar(0, 0, f->szFaceName, -1, to->szFaceName, sizeof(to->szFaceName)); /* copy the rest of the 2A structure to 2W */ - CopyMemory(1+((CHARFORMATW *)from), f+1, sizeof(CHARFORMAT2A)-sizeof(CHARFORMATA)); + CopyMemory(1+((CHARFORMATW *)to), f+1, sizeof(CHARFORMAT2A)-sizeof(CHARFORMATA)); to->cbSize = sizeof(CHARFORMAT2W); return to; } @@ -124,6 +124,7 @@ ME_Style *ME_MakeStyle(CHARFORMAT2W *style) { s->nSequence = -2; s->nRefs = 1; s->hFont = NULL; + s->tm.tmAscent = -1; all_refs++; return s; } diff --git a/reactos/lib/riched20/undo.c b/reactos/lib/riched20/undo.c index e95edc15d7e..916dcb37628 100644 --- a/reactos/lib/riched20/undo.c +++ b/reactos/lib/riched20/undo.c @@ -26,6 +26,9 @@ void ME_EmptyUndoStack(ME_TextEditor *editor) { ME_DisplayItem *p, *pNext; + if (editor->nUndoMode == umIgnore) + return; + TRACE("Emptying undo stack\n"); p = editor->pUndoStack; @@ -121,6 +124,10 @@ ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, ME_DisplayIte } void ME_CommitUndo(ME_TextEditor *editor) { + + if (editor->nUndoMode == umIgnore) + return; + assert(editor->nUndoMode == umAddToUndo); /* no transactions, no need to commit */ @@ -140,6 +147,8 @@ void ME_PlayUndoItem(ME_TextEditor *editor, ME_DisplayItem *pItem) { ME_UndoItem *pUItem = (ME_UndoItem *)pItem; + if (editor->nUndoMode == umIgnore) + return; TRACE("Playing undo/redo item, id=%s\n", ME_GetDITypeName(pItem->type)); switch(pItem->type) @@ -202,6 +211,8 @@ void ME_Undo(ME_TextEditor *editor) { ME_DisplayItem *p; ME_UndoMode nMode = editor->nUndoMode; + if (editor->nUndoMode == umIgnore) + return; assert(nMode == umAddToUndo || nMode == umIgnore); /* no undo items ? */ @@ -235,6 +246,8 @@ void ME_Redo(ME_TextEditor *editor) { assert(nMode == umAddToUndo || nMode == umIgnore); + if (editor->nUndoMode == umIgnore) + return; /* no redo items ? */ if (!editor->pRedoStack) return; diff --git a/reactos/lib/riched20/wrap.c b/reactos/lib/riched20/wrap.c index 683b659130f..d48da585942 100644 --- a/reactos/lib/riched20/wrap.c +++ b/reactos/lib/riched20/wrap.c @@ -26,16 +26,16 @@ WINE_DEFAULT_DEBUG_CHANNEL(richedit); /* * Unsolved problems: - * + * * - center and right align in WordPad omits all spaces at the start, we don't * - objects/images are not handled yet - * - no tabs - */ - + * - no tabs + */ + ME_DisplayItem *ME_MakeRow(int height, int baseline, int width) { ME_DisplayItem *item = ME_MakeDI(diStartRow); - + item->member.row.nHeight = height; item->member.row.nBaseline = baseline; item->member.row.nWidth = width; @@ -49,7 +49,7 @@ void ME_BeginRow(ME_WrapContext *wc) wc->pLastSplittableRun = NULL; wc->nAvailWidth = wc->nTotalWidth - (wc->nRow ? wc->nLeftMargin : wc->nFirstMargin) - wc->nRightMargin; wc->pt.x = 0; -} +} void ME_InsertRowStart(ME_WrapContext *wc, ME_DisplayItem *pEnd) { @@ -95,7 +95,7 @@ void ME_WrapEndParagraph(ME_WrapContext *wc, ME_DisplayItem *p) { if (wc->pRowStart) ME_InsertRowStart(wc, p->next); - + /* p = p->member.para.prev_para->next; while(p) { @@ -109,15 +109,15 @@ void ME_WrapEndParagraph(ME_WrapContext *wc, ME_DisplayItem *p) p = p->next; } */ -} +} void ME_WrapSizeRun(ME_WrapContext *wc, ME_DisplayItem *p) { /* FIXME compose style (out of character and paragraph styles) here */ - + ME_UpdateRunFlags(wc->context->editor, &p->member.run); - - ME_CalcRunExtent(wc->context, &p->member.run); + + ME_CalcRunExtent(wc->context, &ME_GetParagraph(p)->member.para, &p->member.run); } ME_DisplayItem *ME_MaximizeSplit(ME_WrapContext *wc, ME_DisplayItem *p, int i) @@ -139,7 +139,7 @@ ME_DisplayItem *ME_MaximizeSplit(ME_WrapContext *wc, ME_DisplayItem *p, int i) while(piter != wc->pRowStart) { piter = ME_FindItemBack(piter, diRun); - if (piter->member.run.nFlags & MERF_WHITESPACE) + if (piter->member.run.nFlags & MERF_WHITESPACE) { pp = piter; continue; @@ -167,8 +167,8 @@ ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem *p, in ME_DisplayItem *piter = p, *pp; int i, idesp, len; ME_Run *run = &p->member.run; - - idesp = i = ME_CharFromPoint(wc->context->editor, loc, run); + + idesp = i = ME_CharFromPoint(wc->context->editor, loc, &ME_GetParagraph(p)->member.para, run); len = ME_StrVLen(run->strText); assert(len>0); assert(imember.run.strText->szData)); if (wc->pLastSplittableRun) { - if (wc->pLastSplittableRun->member.run.nFlags & MERF_GRAPHICS) + if (wc->pLastSplittableRun->member.run.nFlags & (MERF_GRAPHICS|MERF_TAB)) { wc->pt = wc->ptLastSplittableRun; return wc->pLastSplittableRun; @@ -193,7 +193,7 @@ ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem *p, in they serve no other purpose */ ME_UpdateRunFlags(wc->context->editor, run); assert((wc->pLastSplittableRun->member.run.nFlags & MERF_SPLITTABLE)); - + piter = wc->pLastSplittableRun; run = &piter->member.run; len = ME_StrVLen(run->strText); @@ -201,7 +201,7 @@ ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem *p, in i = ME_ReverseFindWhitespaceV(run->strText, len); if (i == len) i = ME_ReverseFindNonWhitespaceV(run->strText, len); - if (i) { + if (i) { ME_DisplayItem *piter2 = ME_SplitRun(wc->context, piter, i); wc->pt = piter2->member.run.pt; return piter2; @@ -239,7 +239,7 @@ ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem *p, in } /* the run is one char, can't split it */ return piter; - } + } } ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p) @@ -248,24 +248,24 @@ ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p) ME_Run *run; int len; - assert(p->type == diRun); + assert(p->type == diRun); if (!wc->pRowStart) wc->pRowStart = p; - ME_WrapSizeRun(wc, p); run = &p->member.run; run->pt.x = wc->pt.x; run->pt.y = wc->pt.y; - len = ME_StrVLen(run->strText); - + ME_WrapSizeRun(wc, p); + len = ME_StrVLen(run->strText); + if (wc->bOverflown) /* just skipping final whitespaces */ - { - if (run->nFlags & MERF_WHITESPACE) { + { + if (run->nFlags & (MERF_WHITESPACE|MERF_TAB)) { p->member.run.nFlags |= MERF_SKIPPED; /* wc->pt.x += run->nWidth; */ /* skip runs consisting of only whitespaces */ return p->next; } - + if (run->nFlags & MERF_STARTWHITE) { /* try to split the run at the first non-white char */ int black; @@ -274,10 +274,6 @@ ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p) wc->bOverflown = FALSE; pp = ME_SplitRun(wc->context, p, black); p->member.run.nFlags |= MERF_SKIPPED; -/* - run->pt = wc->pt; - wc->pt.x += run->nWidth; - */ ME_InsertRowStart(wc, pp); return pp; } @@ -290,15 +286,15 @@ ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p) /* will current run fit? */ if (wc->pt.x + run->nWidth > wc->nAvailWidth) { - int loc = wc->nAvailWidth - wc->pt.x; + int loc = wc->nAvailWidth - wc->pt.x; /* total white run ? */ if (run->nFlags & MERF_WHITESPACE) { /* let the overflow logic handle it */ wc->bOverflown = TRUE; return p; } - /* graphics - we can split before */ - if (run->nFlags & MERF_GRAPHICS) { + /* graphics or TAB - we can split before */ + if (run->nFlags & (MERF_GRAPHICS|MERF_TAB)) { wc->bOverflown = TRUE; return p; } @@ -330,8 +326,8 @@ ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p) ERR("failure!\n"); /* not found anything - writing over margins is the only option left */ } - if ((run->nFlags & (MERF_SPLITTABLE | MERF_STARTWHITE)) - || ((run->nFlags & MERF_GRAPHICS) && (p != wc->pRowStart))) + if ((run->nFlags & (MERF_SPLITTABLE | MERF_STARTWHITE)) + || ((run->nFlags & (MERF_GRAPHICS|MERF_TAB)) && (p != wc->pRowStart))) { wc->pLastSplittableRun = p; wc->ptLastSplittableRun = wc->pt; @@ -339,20 +335,24 @@ ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p) wc->pt.x += run->nWidth; return p->next; } - + void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) { ME_DisplayItem *p; ME_WrapContext wc; + int dpi = GetDeviceCaps(c->hDC, LOGPIXELSX); - assert(tp->type == diParagraph); + assert(tp->type == diParagraph); if (!(tp->member.para.nFlags & MEPF_REWRAP)) { return; } ME_PrepareParagraphForWrapping(c, tp); - + wc.context = c; /* wc.para_style = tp->member.para.style; */ wc.style = NULL; + tp->member.para.nRightMargin = tp->member.para.pFmt->dxRightIndent*dpi/1440; + tp->member.para.nFirstMargin = tp->member.para.pFmt->dxStartIndent*dpi/1440; + tp->member.para.nLeftMargin = (tp->member.para.pFmt->dxStartIndent+tp->member.para.pFmt->dxOffset)*dpi/1440; wc.nFirstMargin = tp->member.para.nFirstMargin; wc.nLeftMargin = tp->member.para.nLeftMargin; wc.nRightMargin = tp->member.para.nRightMargin; @@ -362,7 +362,7 @@ void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) { wc.nTotalWidth = c->rcView.right - c->rcView.left; wc.nAvailWidth = wc.nTotalWidth - wc.nFirstMargin - wc.nRightMargin; wc.pRowStart = NULL; - + ME_BeginRow(&wc); for (p = tp->next; p!=tp->member.para.next_para; ) { assert(p->type != diStartRow); @@ -413,37 +413,41 @@ void ME_PrepareParagraphForWrapping(ME_Context *c, ME_DisplayItem *tp) { } } -void ME_WrapMarkedParagraphs(ME_TextEditor *editor) { +BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) { HWND hWnd = editor->hWnd; HDC hDC = GetDC(hWnd); ME_DisplayItem *item; ME_Context c; - + BOOL bModified = FALSE; + ME_InitContext(&c, editor, hDC); c.pt.x = 0; c.pt.y = 0; item = editor->pBuffer->pFirst->next; while(item != editor->pBuffer->pLast) { BOOL bRedraw = FALSE; - + assert(item->type == diParagraph); if ((item->member.para.nFlags & MEPF_REWRAP) || (item->member.para.nYPos != c.pt.y)) bRedraw = TRUE; item->member.para.nYPos = c.pt.y; - + ME_WrapTextParagraph(&c, item); if (bRedraw) item->member.para.nFlags |= MEPF_REPAINT; + bModified = bModified | bRedraw; + c.pt.y += item->member.para.nHeight; item = item->member.para.next_para; } editor->sizeWindow.cx = c.rcView.right-c.rcView.left; editor->sizeWindow.cy = c.rcView.bottom-c.rcView.top; editor->nTotalLength = c.pt.y; - + ME_DestroyContext(&c); ReleaseDC(hWnd, hDC); + return bModified; } diff --git a/reactos/lib/riched20/writer.c b/reactos/lib/riched20/writer.c new file mode 100644 index 00000000000..a86c9fb6ca9 --- /dev/null +++ b/reactos/lib/riched20/writer.c @@ -0,0 +1,787 @@ +/* + * RichEdit - RTF writer module + * + * Copyright 2005 by Phil Krylov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "editor.h" +#include "rtf.h" + +WINE_DEFAULT_DEBUG_CHANNEL(richedit); + + +static BOOL +ME_StreamOutRTFText(ME_TextEditor *editor, WCHAR *text, LONG nChars); + + +static void +ME_StreamOutInit(ME_TextEditor *editor, EDITSTREAM *stream) +{ + editor->pStream = ALLOC_OBJ(ME_OutStream); + editor->pStream->stream = stream; + editor->pStream->pos = 0; + editor->pStream->written = 0; + editor->pStream->nFontTblLen = 0; + editor->pStream->nColorTblLen = 1; +} + + +static BOOL +ME_StreamOutFlush(ME_TextEditor *editor) +{ + LONG nStart = 0; + LONG nWritten = 0; + EDITSTREAM *stream = editor->pStream->stream; + + do { + stream->dwError = stream->pfnCallback(stream->dwCookie, editor->pStream->buffer + nStart, + editor->pStream->pos - nStart, &nWritten); + if (nWritten == 0 || stream->dwError) + return FALSE; + editor->pStream->written += nWritten; + nStart += nWritten; + } while (nStart < editor->pStream->pos); + editor->pStream->pos = 0; + return TRUE; +} + + +static LONG +ME_StreamOutFree(ME_TextEditor *editor) +{ + LONG written = editor->pStream->written; + + FREE_OBJ(editor->pStream); + editor->pStream = NULL; + return written; +} + + +static BOOL +ME_StreamOutMove(ME_TextEditor *editor, BYTE *buffer, int len) +{ + ME_OutStream *pStream = editor->pStream; + + while (len) { + int space = STREAMOUT_BUFFER_SIZE - pStream->pos; + int fit = min(space, len); + + TRACE("%u:%u:%.*s\n", pStream->pos, fit, fit, buffer); + memmove(pStream->buffer + pStream->pos, buffer, fit); + len -= fit; + buffer += fit; + pStream->pos += fit; + if (pStream->pos == STREAMOUT_BUFFER_SIZE) { + if (!ME_StreamOutFlush(editor)) + return FALSE; + } + } + return TRUE; +} + + +static BOOL +ME_StreamOutPrint(ME_TextEditor *editor, char *format, ...) +{ + char string[STREAMOUT_BUFFER_SIZE]; /* This is going to be enough */ + int len; + va_list valist; + + va_start(valist, format); + len = vsnprintf(string, sizeof(string), format, valist); + va_end(valist); + + return ME_StreamOutMove(editor, string, len); +} + + +static BOOL +ME_StreamOutRTFHeader(ME_TextEditor *editor, int dwFormat) +{ + char *cCharSet = NULL; + UINT nCodePage; + LANGID language; + BOOL success; + + if (dwFormat & SF_USECODEPAGE) { + CPINFOEXW info; + + switch (HIWORD(dwFormat)) { + case CP_ACP: + cCharSet = "ansi"; + nCodePage = GetACP(); + break; + case CP_OEMCP: + nCodePage = GetOEMCP(); + if (nCodePage == 437) + cCharSet = "pc"; + else if (nCodePage == 850) + cCharSet = "pca"; + else + cCharSet = "ansi"; + break; + case CP_UTF8: + nCodePage = CP_UTF8; + break; + default: + if (HIWORD(dwFormat) == CP_MACCP) { + cCharSet = "mac"; + nCodePage = 10000; /* MacRoman */ + } else { + cCharSet = "ansi"; + nCodePage = 1252; /* Latin-1 */ + } + if (GetCPInfoExW(HIWORD(dwFormat), 0, &info)) + nCodePage = info.CodePage; + } + } else { + cCharSet = "ansi"; + /* TODO: If the original document contained an \ansicpg value, retain it. + * Otherwise, M$ richedit emits a codepage number determined from the + * charset of the default font here. Anyway, this value is not used by + * the reader... */ + nCodePage = GetACP(); + } + if (nCodePage == CP_UTF8) + success = ME_StreamOutPrint(editor, "{\\urtf"); + else + success = ME_StreamOutPrint(editor, "{\\rtf1\\%s\\ansicpg%u\\uc1", cCharSet, nCodePage); + + if (!success) + return FALSE; + + editor->pStream->nDefaultCodePage = nCodePage; + + /* FIXME: This should be a document property */ + /* TODO: handle SFF_PLAINRTF */ + language = GetUserDefaultLangID(); + if (!ME_StreamOutPrint(editor, "\\deff0\\deflang%u\\deflangfe%u", language, language)) + return FALSE; + + /* FIXME: This should be a document property */ + editor->pStream->nDefaultFont = 0; + + return TRUE; +} + + +static BOOL +ME_StreamOutRTFFontAndColorTbl(ME_TextEditor *editor, ME_DisplayItem *pFirstRun, ME_DisplayItem *pLastRun) +{ + ME_DisplayItem *item = pFirstRun; + ME_FontTableItem *table = editor->pStream->fonttbl; + int i; + + do { + CHARFORMAT2W *fmt = &item->member.run.style->fmt; + COLORREF crColor; + + if (fmt->dwMask & CFM_FACE) { + WCHAR *face = fmt->szFaceName; + BYTE bCharSet = (fmt->dwMask & CFM_CHARSET) ? fmt->bCharSet : DEFAULT_CHARSET; + + for (i = 0; i < editor->pStream->nFontTblLen; i++) + if (table[i].bCharSet == bCharSet + && (table[i].szFaceName == face || !lstrcmpW(table[i].szFaceName, face))) + break; + if (i == editor->pStream->nFontTblLen) { + table[i].bCharSet = bCharSet; + table[i].szFaceName = face; + editor->pStream->nFontTblLen++; + } + } + + if (fmt->dwMask & CFM_COLOR && !(fmt->dwEffects & CFE_AUTOCOLOR)) { + crColor = fmt->crTextColor; + for (i = 1; i < editor->pStream->nColorTblLen; i++) + if (editor->pStream->colortbl[i] == crColor) + break; + if (i == editor->pStream->nColorTblLen) { + editor->pStream->colortbl[i] = crColor; + editor->pStream->nColorTblLen++; + } + } + if (fmt->dwMask & CFM_BACKCOLOR && !(fmt->dwEffects & CFE_AUTOBACKCOLOR)) { + crColor = fmt->crBackColor; + for (i = 1; i < editor->pStream->nColorTblLen; i++) + if (editor->pStream->colortbl[i] == crColor) + break; + if (i == editor->pStream->nColorTblLen) { + editor->pStream->colortbl[i] = crColor; + editor->pStream->nColorTblLen++; + } + } + + if (item == pLastRun) + break; + item = ME_FindItemFwd(item, diRun); + } while (item); + + if (!ME_StreamOutPrint(editor, "{\\fonttbl")) + return FALSE; + + for (i = 0; i < editor->pStream->nFontTblLen; i++) { + if (table[i].bCharSet != DEFAULT_CHARSET) { + if (!ME_StreamOutPrint(editor, "{\\f%u\\fcharset%u ", i, table[i].bCharSet)) + return FALSE; + } else { + if (!ME_StreamOutPrint(editor, "{\\f%u ", i)) + return FALSE; + } + if (!ME_StreamOutRTFText(editor, table[i].szFaceName, -1)) + return FALSE; + if (!ME_StreamOutPrint(editor, ";}\r\n")) + return FALSE; + } + if (!ME_StreamOutPrint(editor, "}")) + return FALSE; + + /* Output colors table if not empty */ + if (editor->pStream->nColorTblLen > 1) { + if (!ME_StreamOutPrint(editor, "{\\colortbl;")) + return FALSE; + for (i = 1; i < editor->pStream->nColorTblLen; i++) { + if (!ME_StreamOutPrint(editor, "\\red%u\\green%u\\blue%u;", + editor->pStream->colortbl[i] & 0xFF, + (editor->pStream->colortbl[i] >> 8) & 0xFF, + (editor->pStream->colortbl[i] >> 16) & 0xFF)) + return FALSE; + } + if (!ME_StreamOutPrint(editor, "}")) + return FALSE; + } + + return TRUE; +} + + +static BOOL +ME_StreamOutRTFParaProps(ME_TextEditor *editor, ME_DisplayItem *para) +{ + PARAFORMAT2 *fmt = para->member.para.pFmt; + char props[STREAMOUT_BUFFER_SIZE] = ""; + int i; + + /* TODO: Don't emit anything if the last PARAFORMAT2 is inherited */ + if (!ME_StreamOutPrint(editor, "\\pard")) + return FALSE; + + /* TODO: PFM_BORDER. M$ does not emit any keywords for these properties, and + * when streaming border keywords in, PFM_BORDER is set, but wBorder field is + * set very different from the documentation. + * (Tested with RichEdit 5.50.25.0601) */ + + if (fmt->dwMask & PFM_ALIGNMENT) { + switch (fmt->wAlignment) { + case PFA_LEFT: + /* Default alignment: not emitted */ + break; + case PFA_RIGHT: + strcat(props, "\\qr"); + break; + case PFA_CENTER: + strcat(props, "\\qc"); + break; + case PFA_JUSTIFY: + strcat(props, "\\qj"); + break; + } + } + + if (fmt->dwMask & PFM_LINESPACING) { + /* FIXME: MSDN says that the bLineSpacingRule field is controlled by the + * PFM_SPACEAFTER flag. Is that true? I don't believe so. */ + switch (fmt->bLineSpacingRule) { + case 0: /* Single spacing */ + strcat(props, "\\sl-240\\slmult1"); + break; + case 1: /* 1.5 spacing */ + strcat(props, "\\sl-360\\slmult1"); + break; + case 2: /* Double spacing */ + strcat(props, "\\sl-480\\slmult1"); + break; + case 3: + sprintf(props + strlen(props), "\\sl%ld\\slmult0", fmt->dyLineSpacing); + break; + case 4: + sprintf(props + strlen(props), "\\sl-%ld\\slmult0", fmt->dyLineSpacing); + break; + case 5: + sprintf(props + strlen(props), "\\sl-%ld\\slmult1", fmt->dyLineSpacing * 240 / 20); + break; + } + } + + if (fmt->dwMask & PFM_DONOTHYPHEN && fmt->wEffects & PFE_DONOTHYPHEN) + strcat(props, "\\hyph0"); + if (fmt->dwMask & PFM_KEEP && fmt->wEffects & PFE_KEEP) + strcat(props, "\\keep"); + if (fmt->dwMask & PFM_KEEPNEXT && fmt->wEffects & PFE_KEEPNEXT) + strcat(props, "\\keepn"); + if (fmt->dwMask & PFM_NOLINENUMBER && fmt->wEffects & PFE_NOLINENUMBER) + strcat(props, "\\noline"); + if (fmt->dwMask & PFM_NOWIDOWCONTROL && fmt->wEffects & PFE_NOWIDOWCONTROL) + strcat(props, "\\nowidctlpar"); + if (fmt->dwMask & PFM_PAGEBREAKBEFORE && fmt->wEffects & PFE_PAGEBREAKBEFORE) + strcat(props, "\\pagebb"); + if (fmt->dwMask & PFM_RTLPARA && fmt->wEffects & PFE_RTLPARA) + strcat(props, "\\rtlpar"); + if (fmt->dwMask & PFM_SIDEBYSIDE && fmt->wEffects & PFE_SIDEBYSIDE) + strcat(props, "\\sbys"); + if (fmt->dwMask & PFM_TABLE && fmt->dwMask & PFE_TABLE) + strcat(props, "\\intbl"); + + if (fmt->dwMask & PFM_OFFSET) + sprintf(props + strlen(props), "\\li%ld", fmt->dxOffset); + if (fmt->dwMask & PFM_OFFSETINDENT || fmt->dwMask & PFM_STARTINDENT) + sprintf(props + strlen(props), "\\fi%ld", fmt->dxStartIndent); + if (fmt->dwMask & PFM_RIGHTINDENT) + sprintf(props + strlen(props), "\\ri%ld", fmt->dxRightIndent); + if (fmt->dwMask & PFM_SPACEAFTER) + sprintf(props + strlen(props), "\\sa%ld", fmt->dySpaceAfter); + if (fmt->dwMask & PFM_SPACEBEFORE) + sprintf(props + strlen(props), "\\sb%ld", fmt->dySpaceBefore); + if (fmt->dwMask & PFM_STYLE) + sprintf(props + strlen(props), "\\s%d", fmt->sStyle); + + if (fmt->dwMask & PFM_TABSTOPS) { + static const char *leader[6] = { "", "\\tldot", "\\tlhyph", "\\tlul", "\\tlth", "\\tleq" }; + + for (i = 0; i < fmt->cTabCount; i++) { + switch ((fmt->rgxTabs[i] >> 24) & 0xF) { + case 1: + strcat(props, "\\tqc"); + break; + case 2: + strcat(props, "\\tqr"); + break; + case 3: + strcat(props, "\\tqdec"); + break; + case 4: + /* Word bar tab (vertical bar). Handled below */ + break; + } + if (fmt->rgxTabs[i] >> 28 <= 5) + strcat(props, leader[fmt->rgxTabs[i] >> 28]); + } + } + + + if (fmt->dwMask & PFM_SHADING) { + static const char *style[16] = { "", "\\bgdkhoriz", "\\bgdkvert", "\\bgdkfdiag", + "\\bgdkbdiag", "\\bgdkcross", "\\bgdkdcross", + "\\bghoriz", "\\bgvert", "\\bgfdiag", + "\\bgbdiag", "\\bgcross", "\\bgdcross", + "", "", "" }; + if (fmt->wShadingWeight) + sprintf(props + strlen(props), "\\shading%d", fmt->wShadingWeight); + if (fmt->wShadingStyle & 0xF) + strcat(props, style[fmt->wShadingStyle & 0xF]); + sprintf(props + strlen(props), "\\cfpat%d\\cbpat%d", + (fmt->wShadingStyle >> 4) & 0xF, (fmt->wShadingStyle >> 8) & 0xF); + } + + if (*props && !ME_StreamOutPrint(editor, props)) + return FALSE; + + return TRUE; +} + + +static BOOL +ME_StreamOutRTFCharProps(ME_TextEditor *editor, CHARFORMAT2W *fmt) +{ + char props[STREAMOUT_BUFFER_SIZE] = ""; + int i; + + if (fmt->dwMask & CFM_ALLCAPS && fmt->dwEffects & CFE_ALLCAPS) + strcat(props, "\\caps"); + if (fmt->dwMask & CFM_ANIMATION) + sprintf(props + strlen(props), "\\animtext%u", fmt->bAnimation); + if (fmt->dwMask & CFM_BACKCOLOR) { + if (!(fmt->dwEffects & CFE_AUTOBACKCOLOR)) { + for (i = 1; i < editor->pStream->nColorTblLen; i++) + if (editor->pStream->colortbl[i] == fmt->crBackColor) { + sprintf(props + strlen(props), "\\cb%u", i); + break; + } + } + } + if (fmt->dwMask & CFM_BOLD && fmt->dwEffects & CFE_BOLD) + strcat(props, "\\b"); + if (fmt->dwMask & CFM_COLOR) { + if (!(fmt->dwEffects & CFE_AUTOCOLOR)) { + for (i = 1; i < editor->pStream->nColorTblLen; i++) + if (editor->pStream->colortbl[i] == fmt->crTextColor) { + sprintf(props + strlen(props), "\\cf%u", i); + break; + } + } + } + /* TODO: CFM_DISABLED */ + if (fmt->dwMask & CFM_EMBOSS && fmt->dwEffects & CFE_EMBOSS) + strcat(props, "\\embo"); + if (fmt->dwMask & CFM_HIDDEN && fmt->dwEffects & CFE_HIDDEN) + strcat(props, "\\v"); + if (fmt->dwMask & CFM_IMPRINT && fmt->dwEffects & CFE_IMPRINT) + strcat(props, "\\impr"); + if (fmt->dwMask & CFM_ITALIC && fmt->dwEffects & CFE_ITALIC) + strcat(props, "\\i"); + if (fmt->dwMask & CFM_KERNING) + sprintf(props + strlen(props), "\\kerning%u", fmt->wKerning); + if (fmt->dwMask & CFM_LCID) { + /* TODO: handle SFF_PLAINRTF */ + if (LOWORD(fmt->lcid) == 1024) + strcat(props, "\\noproof\\lang1024\\langnp1024\\langfe1024\\langfenp1024"); + else + sprintf(props + strlen(props), "\\lang%u", LOWORD(fmt->lcid)); + } + /* CFM_LINK is not streamed out by M$ */ + if (fmt->dwMask & CFM_OFFSET) { + if (fmt->yOffset >= 0) + sprintf(props + strlen(props), "\\up%ld", fmt->yOffset); + else + sprintf(props + strlen(props), "\\dn%ld", -fmt->yOffset); + } + if (fmt->dwMask & CFM_OUTLINE && fmt->dwEffects & CFE_OUTLINE) + strcat(props, "\\outl"); + if (fmt->dwMask & CFM_PROTECTED && fmt->dwEffects & CFE_PROTECTED) + strcat(props, "\\protect"); + /* TODO: CFM_REVISED CFM_REVAUTHOR - probably using rsidtbl? */ + if (fmt->dwMask & CFM_SHADOW && fmt->dwEffects & CFE_SHADOW) + strcat(props, "\\shad"); + if (fmt->dwMask & CFM_SIZE) + sprintf(props + strlen(props), "\\fs%ld", fmt->yHeight / 10); + if (fmt->dwMask & CFM_SMALLCAPS && fmt->dwEffects & CFE_SMALLCAPS) + strcat(props, "\\scaps"); + if (fmt->dwMask & CFM_SPACING) + sprintf(props + strlen(props), "\\expnd%u\\expndtw%u", fmt->sSpacing / 5, fmt->sSpacing); + if (fmt->dwMask & CFM_STRIKEOUT && fmt->dwEffects & CFE_STRIKEOUT) + strcat(props, "\\strike"); + if (fmt->dwMask & CFM_STYLE) { + sprintf(props + strlen(props), "\\cs%u", fmt->sStyle); + /* TODO: emit style contents here */ + } + if (fmt->dwMask & (CFM_SUBSCRIPT | CFM_SUPERSCRIPT)) { + if (fmt->dwEffects & CFE_SUBSCRIPT) + strcat(props, "\\sub"); + else if (fmt->dwEffects & CFE_SUPERSCRIPT) + strcat(props, "\\super"); + } + if (fmt->dwMask & CFM_UNDERLINE || fmt->dwMask & CFM_UNDERLINETYPE) { + if (fmt->dwMask & CFM_UNDERLINETYPE) + switch (fmt->bUnderlineType) { + case CFU_CF1UNDERLINE: + case CFU_UNDERLINE: + strcat(props, "\\ul"); + break; + case CFU_UNDERLINEDOTTED: + strcat(props, "\\uld"); + break; + case CFU_UNDERLINEDOUBLE: + strcat(props, "\\uldb"); + break; + case CFU_UNDERLINEWORD: + strcat(props, "\\ulw"); + break; + case CFU_UNDERLINENONE: + default: + strcat(props, "\\ul0"); + break; + } + else if (fmt->dwEffects & CFE_UNDERLINE) + strcat(props, "\\ul"); + } + /* FIXME: How to emit CFM_WEIGHT? */ + + if (fmt->dwMask & CFM_FACE || fmt->dwMask & CFM_CHARSET) { + WCHAR *szFaceName; + + if (fmt->dwMask & CFM_FACE) + szFaceName = fmt->szFaceName; + else + szFaceName = editor->pStream->fonttbl[0].szFaceName; + for (i = 0; i < editor->pStream->nFontTblLen; i++) { + if (szFaceName == editor->pStream->fonttbl[i].szFaceName + || !lstrcmpW(szFaceName, editor->pStream->fonttbl[i].szFaceName)) + if (!(fmt->dwMask & CFM_CHARSET) + || fmt->bCharSet == editor->pStream->fonttbl[i].bCharSet) + break; + } + if (i < editor->pStream->nFontTblLen) + { + if (i != editor->pStream->nDefaultFont) + sprintf(props + strlen(props), "\\f%u", i); + + /* In UTF-8 mode, charsets/codepages are not used */ + if (editor->pStream->nDefaultCodePage != CP_UTF8) + { + if (editor->pStream->fonttbl[i].bCharSet == DEFAULT_CHARSET) + editor->pStream->nCodePage = editor->pStream->nDefaultCodePage; + else + editor->pStream->nCodePage = RTFCharSetToCodePage(NULL, + editor->pStream->fonttbl[i].bCharSet); + } + } + } + if (*props) + strcat(props, " "); + if (!ME_StreamOutPrint(editor, props)) + return FALSE; + return TRUE; +} + + +static BOOL +ME_StreamOutRTFText(ME_TextEditor *editor, WCHAR *text, LONG nChars) +{ + char buffer[STREAMOUT_BUFFER_SIZE]; + int pos = 0; + int fit, i; + + if (nChars == -1) + nChars = lstrlenW(text); + + while (nChars) { + /* In UTF-8 mode, font charsets are not used. */ + if (editor->pStream->nDefaultCodePage == CP_UTF8) { + /* 6 is the maximum character length in UTF-8 */ + fit = min(nChars, STREAMOUT_BUFFER_SIZE / 6); + WideCharToMultiByte(CP_UTF8, 0, text, fit, buffer, STREAMOUT_BUFFER_SIZE, + NULL, NULL); + nChars -= fit; + text += fit; + for (i = 0; buffer[i]; i++) + if (buffer[i] == '{' || buffer[i] == '}' || buffer[i] == '\\') { + if (!ME_StreamOutPrint(editor, "%.*s\\", i - pos, buffer + pos)) + return FALSE; + pos = i; + } + if (!pos) + if (!ME_StreamOutPrint(editor, "%s", buffer + pos)) + return FALSE; + pos = 0; + } else if (*text < 128) { + if (*text == '{' || *text == '}' || *text == '\\') + buffer[pos++] = '\\'; + buffer[pos++] = (char)(*text++); + nChars--; + } else { + BOOL unknown = FALSE; + BYTE letter[3]; + int nBytes, i; + + /* FIXME: In the MS docs for WideCharToMultiByte there is a big list of + * codepages including CP_SYMBOL for which the last parameter must be set + * to NULL for the function to succeed. But in Wine we need to care only + * about CP_SYMBOL */ + nBytes = WideCharToMultiByte(editor->pStream->nCodePage, 0, text, 1, + letter, 3, NULL, + (editor->pStream->nCodePage == CP_SYMBOL) ? NULL : &unknown); + if (unknown) + pos += sprintf(buffer + pos, "\\u%d?", (short)*text); + else if (*letter < 128) { + if (*letter == '{' || *letter == '}' || *letter == '\\') + buffer[pos++] = '\\'; + buffer[pos++] = *letter; + } else { + for (i = 0; i < nBytes; i++) + pos += sprintf(buffer + pos, "\\'%02x", letter[i]); + } + text++; + nChars--; + } + if (pos >= STREAMOUT_BUFFER_SIZE - 11) { + if (!ME_StreamOutMove(editor, buffer, pos)) + return FALSE; + pos = 0; + } + } + return ME_StreamOutMove(editor, buffer, pos); +} + + +static BOOL +ME_StreamOutRTF(ME_TextEditor *editor, int nStart, int nChars, int dwFormat) +{ + ME_DisplayItem *p, *pEnd; + int nOffset, nEndLen; + ME_RunOfsFromCharOfs(editor, nStart, &p, &nOffset); + ME_RunOfsFromCharOfs(editor, nStart+nChars, &pEnd, &nEndLen); + + if (!ME_StreamOutRTFHeader(editor, dwFormat)) + return FALSE; + + if (!ME_StreamOutRTFFontAndColorTbl(editor, p, pEnd)) + return FALSE; + + /* TODO: stylesheet table */ + + /* FIXME: maybe emit something smarter for the generator? */ + if (!ME_StreamOutPrint(editor, "{\\*\\generator Wine Riched20 2.0.????;}")) + return FALSE; + + /* TODO: information group */ + + /* TODO: document formatting properties */ + + /* FIXME: We have only one document section */ + + /* TODO: section formatting properties */ + + if (!ME_StreamOutRTFParaProps(editor, ME_GetParagraph(p))) + return FALSE; + + while(1) + { + switch(p->type) + { + case diParagraph: + if (!ME_StreamOutRTFParaProps(editor, p)) + return FALSE; + break; + case diRun: + if (p == pEnd && !nEndLen) + break; + TRACE("flags %xh\n", p->member.run.nFlags); + /* TODO: emit embedded objects */ + if (p->member.run.nFlags & MERF_GRAPHICS) + FIXME("embedded objects are not handled\n"); + if (p->member.run.nFlags & MERF_ENDPARA) { + if (!ME_StreamOutPrint(editor, "\r\n\\par")) + return FALSE; + nChars--; + } else { + int nEnd; + + if (!ME_StreamOutPrint(editor, "{")) + return FALSE; + TRACE("style %p\n", p->member.run.style); + if (!ME_StreamOutRTFCharProps(editor, &p->member.run.style->fmt)) + return FALSE; + + nEnd = (p == pEnd) ? nEndLen : ME_StrLen(p->member.run.strText); + if (!ME_StreamOutRTFText(editor, p->member.run.strText->szData + nOffset, nEnd - nOffset)) + return FALSE; + nOffset = 0; + if (!ME_StreamOutPrint(editor, "}")) + return FALSE; + } + break; + default: /* we missed the last item */ + assert(0); + } + if (p == pEnd) + break; + p = ME_FindItemFwd(p, diRunOrParagraphOrEnd); + } + if (!ME_StreamOutPrint(editor, "}")) + return FALSE; + return TRUE; +} + + +static BOOL +ME_StreamOutText(ME_TextEditor *editor, int nStart, int nChars, DWORD dwFormat) +{ + /* FIXME: use ME_RunOfsFromCharOfs */ + ME_DisplayItem *item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart); + int nLen; + UINT nCodePage = CP_ACP; + BYTE *buffer = NULL; + int nBufLen = 0; + BOOL success = TRUE; + + if (!item) + return FALSE; + + if (dwFormat & SF_USECODEPAGE) + nCodePage = HIWORD(dwFormat); + + /* TODO: Handle SF_TEXTIZED */ + + while (success && nChars && item) { + nLen = ME_StrLen(item->member.run.strText) - nStart; + if (nLen > nChars) + nLen = nChars; + + if (item->member.run.nFlags & MERF_ENDPARA) { + WCHAR szEOL[] = { '\r', '\n' }; + + if (dwFormat & SF_UNICODE) + success = ME_StreamOutMove(editor, (BYTE *)szEOL, 4); + else + success = ME_StreamOutMove(editor, "\r\n", 2); + } else { + if (dwFormat & SF_UNICODE) + success = ME_StreamOutMove(editor, (BYTE *)(item->member.run.strText->szData + nStart), + sizeof(WCHAR) * nLen); + else { + int nSize; + + nSize = WideCharToMultiByte(nCodePage, 0, item->member.run.strText->szData + nStart, + nLen, NULL, 0, NULL, NULL); + if (nSize > nBufLen) { + if (buffer) + FREE_OBJ(buffer); + buffer = ALLOC_N_OBJ(BYTE, nSize); + nBufLen = nSize; + } + WideCharToMultiByte(nCodePage, 0, item->member.run.strText->szData + nStart, + nLen, buffer, nSize, NULL, NULL); + success = ME_StreamOutMove(editor, buffer, nSize - 1); + } + } + + nChars -= nLen; + nStart = 0; + item = ME_FindItemFwd(item, diRun); + } + + if (buffer) + FREE_OBJ(buffer); + return success; +} + + +LRESULT +ME_StreamOut(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM *stream) +{ + int nStart, nTo; + + ME_StreamOutInit(editor, stream); + + if (dwFormat & SFF_SELECTION) + ME_GetSelection(editor, &nStart, &nTo); + else { + nStart = 0; + nTo = -1; + } + if (nTo == -1) + nTo = ME_GetTextLength(editor); + TRACE("from %d to %d\n", nStart, nTo); + + if (dwFormat & SF_RTF || dwFormat & SF_RTFNOOBJS) + ME_StreamOutRTF(editor, nStart, nTo - nStart, dwFormat); + else if (dwFormat & SF_TEXT || dwFormat & SF_TEXTIZED) + ME_StreamOutText(editor, nStart, nTo - nStart, dwFormat); + + ME_StreamOutFlush(editor); + return ME_StreamOutFree(editor); +} diff --git a/reactos/w32api/include/richedit.h b/reactos/w32api/include/richedit.h index b1c2ab43fd1..42744bae02d 100644 --- a/reactos/w32api/include/richedit.h +++ b/reactos/w32api/include/richedit.h @@ -59,6 +59,19 @@ extern "C" { #define CFE_AUTOBACKCOLOR 0x04000000 #define CFE_SUBSCRIPT 0x00010000 #define CFE_SUPERSCRIPT 0x00020000 +#define CFE_ALLCAPS CFM_ALLCAPS +#define CFE_EMBOSS CFM_EMBOSS +#define CFE_HIDDEN CFM_HIDDEN +#define CFE_IMPRINT CFM_IMPRINT +#define CFE_OUTLINE CFM_OUTLINE +#define CFE_SHADOW CFM_SHADOW +#define CFE_SMALLCAPS CFM_SMALLCAPS +#define CFU_CF1UNDERLINE 0xff +#define CFU_UNDERLINENONE 0 +#define CFU_UNDERLINE 1 +#define CFU_UNDERLINEWORD 2 +#define CFU_UNDERLINEDOUBLE 3 +#define CFU_UNDERLINEDOTTED 4 #define IMF_FORCENONE 1 #define IMF_FORCEENABLE 2 #define IMF_FORCEDISABLE 4 @@ -453,7 +466,7 @@ typedef struct _paraformat2 { LONG dySpaceBefore; LONG dySpaceAfter; LONG dyLineSpacing; - SHORT sStype; + SHORT sStyle; BYTE bLineSpacingRule; BYTE bOutlineLevel; WORD wShadingWeight;