diff --git a/reactos/lib/riched20/Makefile.in b/reactos/lib/riched20/Makefile.in new file mode 100644 index 00000000000..03602d91916 --- /dev/null +++ b/reactos/lib/riched20/Makefile.in @@ -0,0 +1,27 @@ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = riched20.dll +IMPORTS = user32 gdi32 kernel32 +EXTRALIBS = -luuid + +C_SRCS = \ + caret.c \ + context.c \ + editor.c \ + list.c \ + paint.c \ + para.c \ + reader.c \ + richole.c \ + row.c \ + run.c \ + string.c \ + style.c \ + undo.c \ + wrap.c + +@MAKE_DLL_RULES@ + +### Dependencies: diff --git a/reactos/lib/riched20/Makefile.ros-template b/reactos/lib/riched20/Makefile.ros-template new file mode 100644 index 00000000000..0f7733648ac --- /dev/null +++ b/reactos/lib/riched20/Makefile.ros-template @@ -0,0 +1,19 @@ +# $Id$ + +TARGET_NAME = riched20 + +TARGET_OBJECTS = @C_SRCS@ + +TARGET_CFLAGS = @EXTRADEFS@ -D__REACTOS__ -D__WINESRC__ + +TARGET_SDKLIBS = @IMPORTS@ wine.a wine_uuid.a ntdll.a + +TARGET_BASE = $(TARGET_BASE_LIB_SETUPAPI) + +TARGET_NORC = yes + +default: all + +DEP_OBJECTS = $(TARGET_OBJECTS) + +include $(TOOLS_PATH)/depend.mk diff --git a/reactos/lib/riched20/caret.c b/reactos/lib/riched20/caret.c new file mode 100644 index 00000000000..e3ba8b101f0 --- /dev/null +++ b/reactos/lib/riched20/caret.c @@ -0,0 +1,977 @@ +/* + * RichEdit - Caret and selection functions. + * + * Copyright 2004 by Krzysztof Foltman + * + * 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" + +WINE_DEFAULT_DEBUG_CHANNEL(richedit); + +void ME_GetSelection(ME_TextEditor *editor, int *from, int *to) +{ + *from = ME_GetCursorOfs(editor, 0); + *to = ME_GetCursorOfs(editor, 1); + + if (*from > *to) + { + int tmp = *from; + *from = *to; + *to = tmp; + } +} + +int ME_GetTextLength(ME_TextEditor *editor) +{ + return ME_CharOfsFromRunOfs(editor, ME_FindItemBack(editor->pBuffer->pLast, diRun), 0); +} + +void ME_SetSelection(ME_TextEditor *editor, int from, int to) +{ + if (from == 0 && to == -1) + { + editor->pCursors[1].pRun = ME_FindItemFwd(editor->pBuffer->pFirst, diRun); + editor->pCursors[1].nOffset = 0; + editor->pCursors[0].pRun = ME_FindItemBack(editor->pBuffer->pLast, diRun); + editor->pCursors[0].nOffset = 0; + ME_Repaint(editor); + ME_ClearTempStyle(editor); + return; + } + if (from == -1) + { + editor->pCursors[1] = editor->pCursors[0]; + ME_Repaint(editor); + ME_ClearTempStyle(editor); + return; + } + if (from>to) + { + int tmp = from; + from = to; + to = tmp; + } + ME_RunOfsFromCharOfs(editor, from, &editor->pCursors[1].pRun, &editor->pCursors[1].nOffset); + ME_RunOfsFromCharOfs(editor, to, &editor->pCursors[0].pRun, &editor->pCursors[0].nOffset); +} + +void ME_MoveCaret(ME_TextEditor *editor) +{ + HDC hDC = GetDC(editor->hWnd); + ME_Context c; + + ME_Cursor *pCursor = &editor->pCursors[0]; + ME_DisplayItem *pCursorRun = pCursor->pRun; + ME_DisplayItem *pSizeRun = pCursor->pRun; + + ME_InitContext(&c, editor, hDC); + assert(!pCursor->nOffset || !editor->bCaretAtEnd); + + if (pCursorRun->type == diRun) { + ME_DisplayItem *row = ME_FindItemBack(pCursorRun, diStartRowOrParagraph); + if (row) { + ME_DisplayItem *run = pCursorRun; + ME_DisplayItem *para; + SIZE sz = {0, 0}; + if (!pCursor->nOffset && !editor->bCaretAtEnd) + { + ME_DisplayItem *prev = ME_FindItemBack(pCursorRun, diRunOrStartRow); + if (prev->type == diRun) + pSizeRun = prev; + } + assert(row->type == diStartRow); /* paragraph -> run without start row ?*/ + para = ME_FindItemBack(row, diParagraph); + if (editor->bCaretAtEnd && !pCursor->nOffset && + run == ME_FindItemFwd(row, diRun)) + { + ME_DisplayItem *tmp = ME_FindItemBack(row, diRunOrParagraph); + if (tmp->type == diRun) + { + row = ME_FindItemBack(tmp, diStartRow); + pSizeRun = run = tmp; + sz = ME_GetRunSize(&c, &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); + } + 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)); + } else { + assert(0 == "Wrapped paragraph run without a row?"); + CreateCaret(editor->hWnd, NULL, 0, 10); + SetCaretPos(0,0); + } + } + else { + assert(0 == "Cursor not on a run"); + CreateCaret(editor->hWnd, NULL, 0, 10); /* FIXME use global font */ + SetCaretPos(0,0); + } + ME_DestroyContext(&c); + ReleaseDC(editor->hWnd, hDC); +} + +void ME_ShowCaret(ME_TextEditor *ed) +{ + ME_MoveCaret(ed); + ShowCaret(ed->hWnd); +} + +void ME_HideCaret(ME_TextEditor *ed) +{ + HideCaret(ed->hWnd); + DestroyCaret(); +} + +void ME_InternalDeleteText(ME_TextEditor *editor, int nOfs, + int nChars) +{ + ME_Cursor c; + int shift = 0; + + while(nChars > 0) + { + ME_Run *run; + ME_CursorFromCharOfs(editor, nOfs, &c); + run = &c.pRun->member.run; + if (run->nFlags & MERF_ENDPARA) { + if (!ME_FindItemFwd(c.pRun, diParagraph)) + { + return; + } + ME_JoinParagraphs(editor, ME_GetParagraph(c.pRun)); + /* ME_SkipAndPropagateCharOffset(p->pRun, shift); */ + ME_CheckCharOffsets(editor); + nChars--; + continue; + } + else + { + ME_Cursor cursor; + int nIntendedChars = nChars; + int nCharsToDelete = nChars; + int i; + int loc = c.nOffset; + + ME_FindItemBack(c.pRun, diParagraph)->member.para.nFlags |= MEPF_REWRAP; + + cursor = c; + ME_StrRelPos(run->strText, loc, &nChars); + /* nChars is the number of characters that should be deleted from the + FOLLOWING runs (these AFTER cursor.pRun) + nCharsToDelete is a number of chars to delete from THIS run */ + nCharsToDelete -= nChars; + shift -= nCharsToDelete; + TRACE("Deleting %d (intended %d-remaning %d) chars at %d in '%s' (%d)\n", + nCharsToDelete, nIntendedChars, nChars, c.nOffset, + debugstr_w(run->strText->szData), run->strText->nLen); + + if (!c.nOffset && ME_StrVLen(run->strText) == nCharsToDelete) + { + /* undo = reinsert whole run */ + /* nOfs is a character offset (from the start of the document + to the current (deleted) run */ + ME_UndoItem *pUndo = ME_AddUndoItem(editor, diUndoInsertRun, c.pRun); + if (pUndo) + pUndo->di.member.run.nCharOfs = nOfs; + } + else + { + /* undo = reinsert partial run */ + ME_UndoItem *pUndo = ME_AddUndoItem(editor, diUndoInsertRun, c.pRun); + if (pUndo) { + ME_DestroyString(pUndo->di.member.run.strText); + pUndo->di.member.run.nCharOfs = nOfs; + pUndo->di.member.run.strText = ME_MakeStringN(run->strText->szData+c.nOffset, nCharsToDelete); + } + } + TRACE("Post deletion string: %s (%d)\n", debugstr_w(run->strText->szData), run->strText->nLen); + TRACE("Shift value: %d\n", shift); + ME_StrDeleteV(run->strText, c.nOffset, nCharsToDelete); + + /* update cursors (including c) */ + for (i=-1; inCursors; i++) { + ME_Cursor *pThisCur = editor->pCursors + i; + if (i == -1) pThisCur = &c; + if (pThisCur->pRun == cursor.pRun) { + if (pThisCur->nOffset > cursor.nOffset) { + if (pThisCur->nOffset-cursor.nOffset < nCharsToDelete) + pThisCur->nOffset = cursor.nOffset; + else + pThisCur->nOffset -= nCharsToDelete; + assert(pThisCur->nOffset >= 0); + assert(pThisCur->nOffset <= ME_StrVLen(run->strText)); + } + if (pThisCur->nOffset == ME_StrVLen(run->strText)) + { + pThisCur->pRun = ME_FindItemFwd(pThisCur->pRun, diRunOrParagraphOrEnd); + assert(pThisCur->pRun->type == diRun); + pThisCur->nOffset = 0; + } + } + } + + /* c = updated data now */ + + if (c.pRun == cursor.pRun) + ME_SkipAndPropagateCharOffset(c.pRun, shift); + else + ME_PropagateCharOffset(c.pRun, shift); + + if (!ME_StrVLen(cursor.pRun->member.run.strText)) + { + TRACE("Removing useless run\n"); + ME_Remove(cursor.pRun); + ME_DestroyDisplayItem(cursor.pRun); + } + + shift = 0; + /* + ME_CheckCharOffsets(editor); + */ + continue; + } + } +} + +void ME_DeleteTextAtCursor(ME_TextEditor *editor, int nCursor, + int nChars) +{ + assert(nCursor>=0 && nCursornCursors); + ME_InternalDeleteText(editor, ME_GetCursorOfs(editor, nCursor), nChars); +} + +static WCHAR wszSpace[] = {' ', 0}; + +/* FIXME this is temporary, just to have something to test how bad graphics handler is */ +void ME_InsertGraphicsFromCursor(ME_TextEditor *editor, int nCursor) +{ + ME_Cursor *pCursor = &editor->pCursors[nCursor]; + ME_DisplayItem *pItem = NULL; + ME_DisplayItem *pNewRun = NULL; + ME_Style *pStyle = ME_GetInsertStyle(editor, nCursor); + ME_UndoItem *pUndo; + + /* FIXME no no no */ + if (ME_IsSelection(editor)) + ME_DeleteSelection(editor); + + pUndo = ME_AddUndoItem(editor, diUndoDeleteRun, NULL); + if (pUndo) { + pUndo->nStart = pCursor->nOffset + pCursor->pRun->member.run.nCharOfs + ME_GetParagraph(pCursor->pRun)->member.para.nCharOfs; + pUndo->nLen = 1; + } + if (pCursor->nOffset) + { + ME_SplitRunSimple(editor, pCursor->pRun, pCursor->nOffset); + } + pItem = pCursor->pRun; + pNewRun = ME_MakeRun(pStyle, ME_MakeStringN(wszSpace, 1), MERF_GRAPHICS); + pNewRun->member.run.nCharOfs = pCursor->pRun->member.run.nCharOfs; + ME_InsertBefore(pCursor->pRun, pNewRun); + ME_PropagateCharOffset(pItem, 1); + ME_CheckCharOffsets(editor); + ME_SendSelChange(editor); +} + +void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, + const WCHAR *str, int len, ME_Style *style) +{ + const WCHAR *pos; + ME_Cursor *p = NULL; + + assert(style); + editor->bCaretAtEnd = FALSE; + + /* + if (!style) + style = ME_GetInsertStyle(editor, nCursor); + else + ME_AddRefStyle(style); + */ + ME_AddRefStyle(style); + + /* FIXME really HERE ? */ + if (ME_IsSelection(editor)) + ME_DeleteSelection(editor); + + assert(nCursor>=0 && nCursornCursors); + if (len == -1) + 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') + pos++; + /* handle EOLs */ + if (pos-str < len) { + ME_DisplayItem *tp, *end_run; + ME_Paragraph *para; + ME_Style *tmp_style; + if (pos!=str) + ME_InsertTextFromCursor(editor, nCursor, str, pos-str, style); + p = &editor->pCursors[nCursor]; + tp = ME_FindItemBack(p->pRun, diParagraph); + para = &tp->member.para; + assert(tp); + if (p->nOffset) { + ME_SplitRunSimple(editor, p->pRun, p->nOffset); + p = &editor->pCursors[nCursor]; + } + tmp_style = ME_GetInsertStyle(editor, nCursor); + /* ME_SplitParagraph increases style refcount */ + tp = ME_SplitParagraph(editor, p->pRun, p->pRun->member.run.style); + p->pRun = ME_FindItemFwd(tp, diRun); + end_run = ME_FindItemBack(tp, diRun); + ME_ReleaseStyle(end_run->member.run.style); + end_run->member.run.style = tmp_style; + p->nOffset = 0; + if(pos-str < len && *pos =='\r') + pos++; + if(pos-str < len && *pos =='\n') + pos++; + if(pos-str < len) { + ME_InsertTextFromCursor(editor, nCursor, pos, len-(pos-str), style); + } + ME_ReleaseStyle(style); + return; + } + p = &editor->pCursors[nCursor]; + if (style) { + ME_DisplayItem *pNewRun = NULL; + + assert(p->pRun->type == diRun); + pNewRun = ME_MakeRun(style, ME_MakeStringN(str, len), 0); /* addrefs style */ + ME_InsertRun(editor, ME_CharOfsFromRunOfs(editor, p->pRun, p->nOffset), pNewRun); + ME_DestroyDisplayItem(pNewRun); + ME_ReleaseStyle(style); + return; + } else { + assert(0); + } +} + +BOOL ME_ArrowLeft(ME_TextEditor *editor, ME_Cursor *p) +{ + if (p->nOffset) { + p->nOffset = ME_StrRelPos2(p->pRun->member.run.strText, p->nOffset, -1); + return TRUE; + } + else + { + ME_DisplayItem *pRun = ME_FindItemBack(p->pRun, diRunOrParagraph); + assert(pRun); + if (pRun->type == diRun) { + p->pRun = pRun; + assert(p->pRun->type == diRun); + assert(pRun->member.run.strText->nLen); + p->nOffset = pRun->member.run.strText->nLen; + if (p->nOffset) { + p->nOffset = ME_StrRelPos2(pRun->member.run.strText, p->nOffset, -1); + return TRUE; + } + else + assert(0); + } + if (pRun->type == diParagraph) + { + if (pRun->member.para.prev_para->type == diTextStart) + return FALSE; + assert(pRun->member.para.prev_para->type == diParagraph); + pRun = ME_FindItemBack(pRun, diRunOrParagraph); + /* every paragraph ought to have at least one run */ + assert(pRun && pRun->type == diRun); + assert(pRun->member.run.nFlags & MERF_ENDPARA); + p->pRun = pRun; + p->nOffset = 0; + return TRUE; + } + assert(0); + } +} + +BOOL ME_ArrowRight(ME_TextEditor *editor, ME_Cursor *p) +{ + int new_ofs = ME_StrRelPos2(p->pRun->member.run.strText, p->nOffset, 1); + if (new_ofspRun->member.run.strText->nLen) { + p->nOffset = new_ofs; + } + else + { + ME_DisplayItem *pRun = ME_FindItemFwd(p->pRun, diRun); + if (pRun) { + p->pRun = pRun; + assert(p->pRun->type == diRun); + p->nOffset = 0; + } + } + return TRUE; +} + +int ME_GetCursorOfs(ME_TextEditor *editor, int nCursor) +{ + ME_Cursor *pCursor = &editor->pCursors[nCursor]; + + return ME_GetParagraph(pCursor->pRun)->member.para.nCharOfs + + pCursor->pRun->member.run.nCharOfs + pCursor->nOffset; +} + +int ME_FindPixelPos(ME_TextEditor *editor, int x, int y, ME_Cursor *result, BOOL *is_eol) +{ + ME_DisplayItem *p = editor->pBuffer->pFirst->member.para.next_para; + int rx = 0; + + if (is_eol) + *is_eol = 0; + + while(p != editor->pBuffer->pLast) + { + if (p->type == diParagraph) + { + int ry = y - p->member.para.nYPos; + if (ry < 0) + { + result->pRun = ME_FindItemFwd(p, diRun); + result->nOffset = 0; + return 0; + } + if (ry >= p->member.para.nHeight) + { + p = p->member.para.next_para; + continue; + } + p = ME_FindItemFwd(p, diStartRow); + y = ry; + continue; + } + if (p->type == diStartRow) + { + int ry = y - p->member.row.nYPos; + if (ry < 0) + return 0; + if (ry >= p->member.row.nHeight) + { + p = ME_FindItemFwd(p, diStartRowOrParagraphOrEnd); + if (p->type != diStartRow) + return 0; + continue; + } + p = ME_FindItemFwd(p, diRun); + continue; + } + if (p->type == diRun) + { + ME_DisplayItem *pp; + rx = x - p->member.run.pt.x; + if (rx < 0) + rx = 0; + if (rx >= p->member.run.nWidth) /* not this run yet... find next item */ + { + pp = p; + do { + p = p->next; + if (p->type == diRun) + { + rx = x - p->member.run.pt.x; + goto continue_search; + } + if (p->type == diStartRow) + { + p = ME_FindItemFwd(p, diRun); + if (is_eol) + *is_eol = 1; + rx = 0; /* FIXME not sure */ + goto found_here; + } + if (p->type == diParagraph || p->type == diTextEnd) + { + rx = 0; /* FIXME not sure */ + p = pp; + goto found_here; + } + } while(1); + continue; + } + found_here: + if (p->member.run.nFlags & MERF_ENDPARA) + rx = 0; + result->pRun = p; + result->nOffset = ME_CharFromPointCursor(editor, rx, &p->member.run); + if (editor->pCursors[0].nOffset == p->member.run.strText->nLen && rx) + { + result->pRun = ME_FindItemFwd(editor->pCursors[0].pRun, diRun); + result->nOffset = 0; + } + return 1; + } + assert(0); + continue_search: + ; + } + result->pRun = ME_FindItemBack(p, diRun); + result->nOffset = 0; + assert(result->pRun->member.run.nFlags & MERF_ENDPARA); + return 0; +} + +void ME_LButtonDown(ME_TextEditor *editor, int x, int y) +{ + ME_Cursor tmp_cursor; + int is_selection = 0; + + editor->nUDArrowX = -1; + + y += GetScrollPos(editor->hWnd, SB_VERT); + + tmp_cursor = editor->pCursors[0]; + is_selection = ME_IsSelection(editor); + + ME_FindPixelPos(editor, x, y, &editor->pCursors[0], &editor->bCaretAtEnd); + + if (GetKeyState(VK_SHIFT)>=0) + { + editor->pCursors[1] = editor->pCursors[0]; + } + else + { + if (!is_selection) { + editor->pCursors[1] = tmp_cursor; + is_selection = 1; + } + } + HideCaret(editor->hWnd); + ME_MoveCaret(editor); + if (is_selection) + ME_Repaint(editor); + ShowCaret(editor->hWnd); + ME_ClearTempStyle(editor); + ME_SendSelChange(editor); +} + +void ME_MouseMove(ME_TextEditor *editor, int x, int y) +{ + ME_Cursor tmp_cursor; + + y += GetScrollPos(editor->hWnd, SB_VERT); + + tmp_cursor = editor->pCursors[0]; + if (!ME_FindPixelPos(editor, x, y, &editor->pCursors[0], &editor->bCaretAtEnd)) + /* return */; + + if (tmp_cursor.pRun == editor->pCursors[0].pRun && + tmp_cursor.nOffset == editor->pCursors[0].nOffset) + return; + + HideCaret(editor->hWnd); + ME_MoveCaret(editor); + ME_Repaint(editor); + ShowCaret(editor->hWnd); + ME_SendSelChange(editor); +} + +static ME_DisplayItem *ME_FindRunInRow(ME_TextEditor *editor, ME_DisplayItem *pRow, + int x, int *pOffset, int *pbCaretAtEnd) +{ + ME_DisplayItem *pNext, *pLastRun; + pNext = ME_FindItemFwd(pRow, diRunOrStartRow); + assert(pNext->type == diRun); + pLastRun = pNext; + *pbCaretAtEnd = FALSE; + do { + int run_x = pNext->member.run.pt.x; + int width = pNext->member.run.nWidth; + if (x < run_x) + { + if (pOffset) *pOffset = 0; + return pNext; + } + if (x >= run_x && x < run_x+width) + { + int ch = ME_CharFromPointCursor(editor, x-run_x, &pNext->member.run); + ME_String *s = pNext->member.run.strText; + if (ch < s->nLen) { + if (pOffset) + *pOffset = ch; + return pNext; + } + } + pLastRun = pNext; + pNext = ME_FindItemFwd(pNext, diRunOrStartRow); + } while(pNext && pNext->type == diRun); + + if ((pLastRun->member.run.nFlags & MERF_ENDPARA) == 0) + { + pNext = ME_FindItemFwd(pNext, diRun); + if (pbCaretAtEnd) *pbCaretAtEnd = 1; + if (pOffset) *pOffset = 0; + return pNext; + } else { + if (pbCaretAtEnd) *pbCaretAtEnd = 0; + if (pOffset) *pOffset = 0; + return pLastRun; + } +} + +static int ME_GetXForArrow(ME_TextEditor *editor, ME_Cursor *pCursor) +{ + ME_DisplayItem *pRun = pCursor->pRun; + int x; + + if (editor->nUDArrowX != -1) + x = editor->nUDArrowX; + else { + if (editor->bCaretAtEnd) + { + pRun = ME_FindItemBack(pRun, diRun); + assert(pRun); + x = pRun->member.run.pt.x + pRun->member.run.nWidth; + } + else { + x = pRun->member.run.pt.x; + x += ME_PointFromChar(editor, &pRun->member.run, pCursor->nOffset); + } + editor->nUDArrowX = x; + } + return x; +} + +void ME_ArrowUp(ME_TextEditor *editor, ME_Cursor *pCursor) +{ + ME_DisplayItem *pRun = pCursor->pRun; + ME_DisplayItem *pItem, *pItem2; + int x = ME_GetXForArrow(editor, pCursor); + + if (editor->bCaretAtEnd && !pCursor->nOffset) + { + pRun = ME_FindItemBack(pRun, diRun); + if (!pRun) + return; + } + + /* start of this row */ + pItem = ME_FindItemBack(pRun, diStartRow); + assert(pItem); + /* start of the previous row */ + pItem2 = ME_FindItemBack(pItem, diStartRow); + /* no previous row = the first line of the first paragraph */ + if (!pItem2) /* can't go up - don't go BOL (as in MS richedit) */ + return; + /* FIXME + ME_WrapTextParagraph(editor, ME_FindItemBack(pItem2, diParagraph)); + */ + pCursor->pRun = ME_FindRunInRow(editor, pItem2, x, &pCursor->nOffset, &editor->bCaretAtEnd); +} + +void ME_ArrowDown(ME_TextEditor *editor, ME_Cursor *pCursor) +{ + ME_DisplayItem *pRun = pCursor->pRun; + ME_DisplayItem *pItem; + int x = ME_GetXForArrow(editor, pCursor); + if (!pCursor->nOffset && editor->bCaretAtEnd) + { + pRun = ME_FindItemBack(pRun, diRun); +/* x = pRun->member.run.pt.x + pRun->member.run.nWidth; */ + } + /* start of the next row */ + pItem = ME_FindItemFwd(pRun, diStartRow); + /* FIXME If diParagraph is before diStartRow, wrap the next paragraph? + */ + if (!pItem) + { + /* next row not found - ignore */ + return; + } + pCursor->pRun = ME_FindRunInRow(editor, pItem, x, &pCursor->nOffset, &editor->bCaretAtEnd); + 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); + if (pRow) { + ME_DisplayItem *pRun; + if (editor->bCaretAtEnd && !pCursor->nOffset) { + pRow = ME_FindItemBack(pRow, diStartRow); + if (!pRow) + return; + } + pRun = ME_FindItemFwd(pRow, diRun); + if (pRun) { + pCursor->pRun = pRun; + pCursor->nOffset = 0; + } + } + editor->bCaretAtEnd = FALSE; +} + +void ME_ArrowCtrlHome(ME_TextEditor *editor, ME_Cursor *pCursor) +{ + ME_DisplayItem *pRow = ME_FindItemBack(pCursor->pRun, diTextStart); + if (pRow) { + ME_DisplayItem *pRun = ME_FindItemFwd(pRow, diRun); + if (pRun) { + pCursor->pRun = pRun; + pCursor->nOffset = 0; + } + } +} + +void ME_ArrowEnd(ME_TextEditor *editor, ME_Cursor *pCursor) +{ + ME_DisplayItem *pRow; + + if (editor->bCaretAtEnd && !pCursor->nOffset) + return; + + pRow = ME_FindItemFwd(pCursor->pRun, diStartRowOrParagraphOrEnd); + assert(pRow); + if (pRow->type == diStartRow) { + /* FIXME WTF was I thinking about here ? */ + ME_DisplayItem *pRun = ME_FindItemFwd(pRow, diRun); + assert(pRun); + pCursor->pRun = pRun; + pCursor->nOffset = 0; + editor->bCaretAtEnd = 1; + return; + } + pCursor->pRun = ME_FindItemBack(pRow, diRun); + assert(pCursor->pRun && pCursor->pRun->member.run.nFlags & MERF_ENDPARA); + pCursor->nOffset = 0; + editor->bCaretAtEnd = FALSE; +} + +void ME_ArrowCtrlEnd(ME_TextEditor *editor, ME_Cursor *pCursor) +{ + ME_DisplayItem *p = ME_FindItemFwd(pCursor->pRun, diTextEnd); + assert(p); + p = ME_FindItemBack(p, diRun); + assert(p); + assert(p->member.run.nFlags & MERF_ENDPARA); + pCursor->pRun = p; + pCursor->nOffset = 0; + editor->bCaretAtEnd = FALSE; +} + +BOOL ME_IsSelection(ME_TextEditor *editor) +{ + return memcmp(&editor->pCursors[0], &editor->pCursors[1], sizeof(ME_Cursor))!=0; +} + +int ME_GetSelCursor(ME_TextEditor *editor, int dir) +{ + int cdir = ME_GetCursorOfs(editor, 0) - ME_GetCursorOfs(editor, 1); + + if (cdir*dir>0) + return 0; + else + return 1; +} + +BOOL ME_CancelSelection(ME_TextEditor *editor, int dir) +{ + int cdir; + + if (GetKeyState(VK_SHIFT)<0) + return FALSE; + if (!memcmp(&editor->pCursors[0], &editor->pCursors[1], sizeof(ME_Cursor))) + return FALSE; + + cdir = ME_GetCursorOfs(editor, 0) - ME_GetCursorOfs(editor, 1); + + if (cdir*dir>0) + 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) +{ + 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; + } + else + { + if (!memcmp(pTempCursor, &editor->pCursors[1], sizeof(ME_Cursor))) /* starting selection */ + { + editor->pCursors[1] = *pTempCursor; + } + } + + ME_Repaint(editor); +} + +void ME_DeleteSelection(ME_TextEditor *editor) +{ + int from, to; + ME_GetSelection(editor, &from, &to); + ME_DeleteTextAtCursor(editor, ME_GetSelCursor(editor,-1), to-from); +} + +ME_Style *ME_GetSelectionInsertStyle(ME_TextEditor *editor) +{ + ME_Style *style; + int from, to; + ME_Cursor c; + + ME_GetSelection(editor, &from, &to); + ME_CursorFromCharOfs(editor, from, &c); + if (from != to) { + style = c.pRun->member.run.style; + ME_AddRefStyle(style); /* ME_GetInsertStyle has already done that */ + } + else + style = ME_GetInsertStyle(editor, 0); + return style; +} + +void ME_SendSelChange(ME_TextEditor *editor) +{ + SELCHANGE sc; + if (!(editor->nEventMask & ENM_SELCHANGE)) + return; + sc.nmhdr.hwndFrom = editor->hWnd; + sc.nmhdr.idFrom = GetWindowLongW(editor->hWnd, GWLP_ID); + sc.nmhdr.code = EN_SELCHANGE; + SendMessageW(editor->hWnd, EM_EXGETSEL, 0, (LPARAM)&sc.chrg); + sc.seltyp = SEL_EMPTY; + if (sc.chrg.cpMin != sc.chrg.cpMax) + sc.seltyp |= SEL_TEXT; + if (sc.chrg.cpMin < sc.chrg.cpMax+1) /* wth were RICHEDIT authors thinking ? */ + sc.seltyp |= SEL_MULTICHAR; + SendMessageW(GetParent(editor->hWnd), WM_NOTIFY, sc.nmhdr.idFrom, (LPARAM)&sc); +} + +BOOL ME_ArrowKey(ME_TextEditor *editor, int nVKey, int nCtrl) +{ + int nCursor = 0; + ME_Cursor *p = &editor->pCursors[nCursor]; + ME_Cursor tmp_curs = *p; + + switch(nVKey) { + case VK_UP: + ME_ArrowUp(editor, p); + ME_ClearTempStyle(editor); + ME_RepaintSelection(editor, &tmp_curs); + ME_SendSelChange(editor); + return TRUE; + case VK_DOWN: + ME_ArrowDown(editor, p); + ME_ClearTempStyle(editor); + ME_RepaintSelection(editor, &tmp_curs); + ME_SendSelChange(editor); + return TRUE; + } + + editor->nUDArrowX = -1; + switch(nVKey) { + case VK_BACK: { /* FIXME backspace and delete aren't the same, they act different wrt paragraph style of the merged paragraph */ + if (GetWindowLongW(editor->hWnd, GWL_STYLE) & ES_READONLY) + return FALSE; + if (ME_IsSelection(editor)) + { + editor->bCaretAtEnd = FALSE; /* FIXME or maybe not */ + ME_DeleteSelection(editor); + ME_UpdateRepaint(editor); + return TRUE; + } + if (ME_ArrowLeft(editor, p)) { + editor->bCaretAtEnd = FALSE; /* FIXME or maybe not */ + ME_MoveCaret(editor); + ME_DeleteTextAtCursor(editor, nCursor, 1); + ME_UpdateRepaint(editor); + } + return TRUE; + } + case VK_DELETE: { + if (GetWindowLongW(editor->hWnd, GWL_STYLE) & ES_READONLY) + return FALSE; + /* editor->bCaretAtEnd = 0; FIXME or maybe not */ + if (ME_IsSelection(editor)) + { + ME_DeleteSelection(editor); + ME_UpdateRepaint(editor); + return TRUE; + } + ME_DeleteTextAtCursor(editor, nCursor, 1); + ME_UpdateRepaint(editor); + return TRUE; + } + case VK_HOME: { + if (GetKeyState(VK_CONTROL)<0) + ME_ArrowCtrlHome(editor, p); + else + ME_ArrowHome(editor, p); + editor->bCaretAtEnd = 0; + ME_ClearTempStyle(editor); + ME_RepaintSelection(editor, &tmp_curs); + ME_SendSelChange(editor); + return TRUE; + } + case VK_END: + if (GetKeyState(VK_CONTROL)<0) + ME_ArrowCtrlEnd(editor, p); + else + ME_ArrowEnd(editor, p); + ME_ClearTempStyle(editor); + ME_RepaintSelection(editor, &tmp_curs); + ME_SendSelChange(editor); + return TRUE; + case VK_LEFT: + editor->bCaretAtEnd = 0; + if (ME_CancelSelection(editor, -1)) + return TRUE; + ME_ArrowLeft(editor, p); + ME_RepaintSelection(editor, &tmp_curs); + ME_ClearTempStyle(editor); + ME_SendSelChange(editor); + return TRUE; + case VK_RIGHT: + editor->bCaretAtEnd = 0; + if (ME_CancelSelection(editor, +1)) + return TRUE; + ME_ArrowRight(editor, p); + ME_RepaintSelection(editor, &tmp_curs); + ME_ClearTempStyle(editor); + ME_SendSelChange(editor); + return TRUE; + } + return FALSE; +} diff --git a/reactos/lib/riched20/context.c b/reactos/lib/riched20/context.c new file mode 100644 index 00000000000..62b02590608 --- /dev/null +++ b/reactos/lib/riched20/context.c @@ -0,0 +1,37 @@ +/* + * RichEdit - Operation context functions + * + * Copyright 2004 by Krzysztof Foltman + * + * 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" + +void ME_InitContext(ME_Context *c, ME_TextEditor *editor, HDC hDC) +{ + c->nSequence = editor->nSequence++; + c->hDC = hDC; + c->editor = editor; + c->pt.x = 0; + c->pt.y = 0; + c->hbrMargin = CreateSolidBrush(RGB(224,224,224)); + GetClientRect(editor->hWnd, &c->rcView); +} + +void ME_DestroyContext(ME_Context *c) +{ + DeleteObject(c->hbrMargin); +} diff --git a/reactos/lib/riched20/editor.c b/reactos/lib/riched20/editor.c new file mode 100644 index 00000000000..eec98474719 --- /dev/null +++ b/reactos/lib/riched20/editor.c @@ -0,0 +1,1020 @@ +/* + * RichEdit - functions dealing with editor object + * + * Copyright 2004 by Krzysztof Foltman + * + * 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 + */ + +/* + API implementation status: + + Messages (ANSI versions not done yet) + - EM_AUTOURLDETECT 2.0 + - EM_CANPASTE + + EM_CANREDO 2.0 + + EM_CANUNDO + - EM_CHARFROMPOS + - EM_DISPLAYBAND + + EM_EMPTYUNDOBUFFER + + EM_EXGETSEL + - EM_EXLIMITTEXT + - EM_EXLINEFROMCHAR + + EM_EXSETSEL + - EM_FINDTEXT + - EM_FINDTEXTEX + - EM_FINDWORDBREAK + - EM_FMTLINES + - EM_FORMATRANGE + - EM_GETCHARFORMAT (partly done) + + EM_GETEVENTMASK + - EM_GETFIRSTVISIBLELINE + - EM_GETIMECOLOR 1.0asian + - EM_GETIMECOMPMODE 2.0 + - EM_GETIMEOPTIONS 1.0asian + - EM_GETIMESTATUS + - EM_GETLANGOPTIONS 2.0 + - EM_GETLIMITTEXT + - EM_GETLINE + - EM_GETLINECOUNT returns number of rows, not of paragraphs + + EM_GETMODIFY + - EM_GETOLEINTERFACE + - EM_GETOPTIONS + + EM_GETPARAFORMAT + - EM_GETPUNCTUATION 1.0asian + - EM_GETRECT + - EM_GETREDONAME 2.0 + + EM_GETSEL + + EM_GETSELTEXT (ANSI&Unicode) +! - EM_GETTHUMB + - EM_GETTEXTMODE 2.0 +? + EM_GETTEXTRANGE (ANSI&Unicode) + - EM_GETUNDONAME + - EM_GETWORDBREAKPROC + - EM_GETWORDBREAKPROCEX + - EM_GETWORDWRAPMODE 1.0asian + - EM_HIDESELECTION + - EM_LIMITTEXT + - EM_LINEFROMCHAR + - EM_LINEINDEX + - EM_LINELENGTH + - EM_LINESCROLL + - EM_PASTESPECIAL + - EM_POSFROMCHARS + - EM_REDO 2.0 + - EM_REQUESTRESIZE + + EM_REPLACESEL (proper style?) ANSI&Unicode + - EM_SCROLL + - EM_SCROLLCARET + - EM_SELECTIONTYPE + + EM_SETBKGNDCOLOR + - EM_SETCHARFORMAT (partly done, no ANSI) + + EM_SETEVENTMASK (few notifications supported) + - EM_SETIMECOLOR 1.0asian + - EM_SETIMEOPTIONS 1.0asian + - EM_SETLANGOPTIONS 2.0 + - EM_SETLIMITTEXT + + EM_SETMODIFY (not sure if implementation is correct) + - EM_SETOLECALLBACK + - EM_SETOPTIONS + + EM_SETPARAFORMAT + - EM_SETPUNCTUATION 1.0asian + + EM_SETREADONLY no beep on modification attempt + - EM_SETRECT + - EM_SETRECTNP (EM_SETRECT without repainting) - not supported in RICHEDIT + + EM_SETSEL + - EM_SETTARGETDEVICE + - EM_SETTEXTMODE 2.0 + - EM_SETUNDOLIMIT 2.0 + - EM_SETWORDBREAKPROC + - EM_SETWORDBREAKPROCEX + - EM_SETWORDWRAPMODE 1.0asian + - EM_STOPGROUPTYPING 2.0 + - EM_STREAMIN + - EM_STREAMOUT + - EM_UNDO + + WM_CHAR + + WM_CLEAR + - WM_COPY (lame implementation, no RTF support) + - WM_CUT (lame implementation, no RTF support) + + WM_GETDLGCODE (the current implementation is incomplete) + + WM_GETTEXT (ANSI&Unicode) + + WM_GETTEXTLENGTH (ANSI version sucks) + - WM_PASTE + - WM_SETFONT + + WM_SETTEXT (resets undo stack !) (proper style?) ANSI&Unicode + - WM_STYLECHANGING + - WM_STYLECHANGED (things like read-only flag) + - WM_UNICHAR + + Notifications + + * EN_CHANGE (sent from the wrong place) + - EN_CORRECTTEXT + - EN_DROPFILES + - EN_ERRSPACE + - EN_HSCROLL + - EN_IMECHANGE + + EN_KILLFOCUS + - EN_LINK + - EN_MAXTEXT + - EN_MSGFILTER + - EN_OLEOPFAILED + - EN_PROTECTED + - EN_REQUESTRESIZE + - EN_SAVECLIPBOARD + + EN_SELCHANGE + + EN_SETFOCUS + - EN_STOPNOUNDO + * EN_UPDATE (sent from the wrong place) + - EN_VSCROLL + + Styles + + - ES_AUTOHSCROLL + - ES_AUTOVSCROLL + - ES_CENTER + - ES_DISABLENOSCROLL (scrollbar is always visible) + - ES_EX_NOCALLOLEINIT + - ES_LEFT + - ES_MULTILINE (currently single line controls aren't supported) + - ES_NOIME + - ES_READONLY (I'm not sure if beeping is the proper behaviour) + - ES_RIGHT + - ES_SAVESEL + - ES_SELFIME + - ES_SUNKEN + - ES_VERTICAL + - ES_WANTRETURN (don't know how to do WM_GETDLGCODE part) + - WS_SETFONT + - WS_HSCROLL + - WS_VSCROLL +*/ + +/* + * RICHED20 TODO (incomplete): + * + * - font caching + * - add remaining CHARFORMAT/PARAFORMAT fields + * - right/center align should strip spaces from the beginning + * - more advanced navigation (Ctrl-arrows, PageUp/PageDn) + * - tabs + * - pictures (not just smiling faces that lack API support ;-) ) + * - OLE objects + * - 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 + * - 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) + * - undo for ME_JoinParagraphs doesn't store paragraph format ? (it does) + * - check/fix artificial EOL logic (bCursorAtEnd, hardly logical) + * - caret shouldn't be displayed when selection isn't empty + * - check refcounting in style management functions (looks perfect now, but no bugs is suspicious) + * - undo for setting default format (done, might be buggy) + * - styles might be not released properly (looks like they work like charm, but who knows? + * + */ + +#include "editor.h" +#include +#include +#include +#define NO_SHLWAPI_STREAM +#include + +#include "rtf.h" + +WINE_DEFAULT_DEBUG_CHANNEL(richedit); + +int me_debug = 0; +HANDLE me_heap = NULL; + +ME_TextBuffer *ME_MakeText() { + + ME_TextBuffer *buf = ALLOC_OBJ(ME_TextBuffer); + + ME_DisplayItem *p1 = ME_MakeDI(diTextStart); + ME_DisplayItem *p2 = ME_MakeDI(diTextEnd); + + p1->prev = NULL; + p1->next = p2; + p2->prev = p1; + p2->next = NULL; + p1->member.para.next_para = p2; + p2->member.para.prev_para = p1; + p2->member.para.nCharOfs = 0; + + buf->pFirst = p1; + buf->pLast = p2; + buf->pCharStyle = NULL; + + return buf; +} + +#define STREAMIN_BUFFER_SIZE 4096 /* M$ compatibility */ + +static LRESULT ME_StreamInText(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM *stream, ME_Style *style) +{ + BYTE buffer[STREAMIN_BUFFER_SIZE+1]; + WCHAR wszText[STREAMIN_BUFFER_SIZE+1]; + + 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; + + 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); + } + else + nWideChars = nDataSize>>1; + ME_InsertTextFromCursor(editor, 0, wszText, nWideChars, style); + if (nDataSizehWnd); + + if (format & SFF_SELECTION) { + style = ME_GetSelectionInsertStyle(editor); + SendMessageW(editor->hWnd, WM_CLEAR, 0, 0); + } + else { + style = editor->pBuffer->pDefaultStyle; + ME_AddRefStyle(style); + SendMessageA(editor->hWnd, EM_SETSEL, 0, 0); + SetWindowTextA(editor->hWnd, ""); + ME_ClearTempStyle(editor); + } + + 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 + { + /* FIXME where to put cursor now ? */ + } + ME_ReleaseStyle(style); + + return 0; +} + +ME_TextEditor *ME_MakeEditor(HWND hWnd) { + ME_TextEditor *ed = ALLOC_OBJ(ME_TextEditor); + HDC hDC; + int i; + ed->hWnd = hWnd; + ed->pBuffer = ME_MakeText(); + hDC = GetDC(hWnd); + ME_MakeFirstParagraph(hDC, ed->pBuffer); + ReleaseDC(hWnd, hDC); + ed->bCaretShown = FALSE; + ed->nCursors = 3; + ed->pCursors = ALLOC_N_OBJ(ME_Cursor, ed->nCursors); + ed->pCursors[0].pRun = ME_FindItemFwd(ed->pBuffer->pFirst, diRun); + ed->pCursors[0].nOffset = 0; + 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; + ed->bCaretAtEnd = FALSE; + ed->nEventMask = 0; + ed->nModifyStep = 0; + ed->pUndoStack = ed->pRedoStack = NULL; + ed->nUndoMode = umAddToUndo; + ed->nParagraphs = 1; + ed->nLastSelStart = ed->nLastSelEnd = 0; + for (i=0; ipFontCache[i].nRefs = 0; + ed->pFontCache[i].nAge = 0; + ed->pFontCache[i].hFont = NULL; + } + ME_CheckCharOffsets(ed); + return ed; +} + +void ME_DestroyEditor(ME_TextEditor *editor) +{ + ME_DisplayItem *pFirst = editor->pBuffer->pFirst; + ME_DisplayItem *p = pFirst, *pNext = NULL; + int i; + + ME_ClearTempStyle(editor); + ME_EmptyUndoStack(editor); + while(p) { + pNext = p->next; + ME_DestroyDisplayItem(p); + p = pNext; + } + ME_ReleaseStyle(editor->pBuffer->pDefaultStyle); + for (i=0; ipFontCache[i].hFont) + DeleteObject(editor->pFontCache[i].hFont); + } + + FREE_OBJ(editor); +} + +#define UNSUPPORTED_MSG(e) \ + case e: \ + FIXME(#e ": stub\n"); \ + return DefWindowProcW(hWnd, msg, wParam, lParam); + +/****************************************************************** + * RichEditANSIWndProc (RICHED20.10) + */ +LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { + HDC hDC; + PAINTSTRUCT ps; + SCROLLINFO si; + ME_TextEditor *editor = (ME_TextEditor *)GetWindowLongW(hWnd, 0); + TRACE("msg %d %08x %08lx\n", msg, wParam, lParam); + switch(msg) { + + UNSUPPORTED_MSG(EM_AUTOURLDETECT) + UNSUPPORTED_MSG(EM_CANPASTE) + UNSUPPORTED_MSG(EM_CHARFROMPOS) + UNSUPPORTED_MSG(EM_DISPLAYBAND) + UNSUPPORTED_MSG(EM_EXLIMITTEXT) + UNSUPPORTED_MSG(EM_EXLINEFROMCHAR) + UNSUPPORTED_MSG(EM_FINDTEXT) + UNSUPPORTED_MSG(EM_FINDTEXTEX) + UNSUPPORTED_MSG(EM_FINDWORDBREAK) + UNSUPPORTED_MSG(EM_FMTLINES) + UNSUPPORTED_MSG(EM_FORMATRANGE) + UNSUPPORTED_MSG(EM_GETFIRSTVISIBLELINE) + UNSUPPORTED_MSG(EM_GETIMECOMPMODE) + /* UNSUPPORTED_MSG(EM_GETIMESTATUS) missing in Wine headers */ + UNSUPPORTED_MSG(EM_GETLANGOPTIONS) + UNSUPPORTED_MSG(EM_GETLIMITTEXT) + UNSUPPORTED_MSG(EM_GETLINE) + UNSUPPORTED_MSG(EM_GETLINECOUNT) + /* UNSUPPORTED_MSG(EM_GETOLEINTERFACE) separate stub */ + UNSUPPORTED_MSG(EM_GETOPTIONS) + UNSUPPORTED_MSG(EM_GETRECT) + UNSUPPORTED_MSG(EM_GETREDONAME) + UNSUPPORTED_MSG(EM_GETTEXTMODE) + UNSUPPORTED_MSG(EM_GETUNDONAME) + UNSUPPORTED_MSG(EM_GETWORDBREAKPROC) + UNSUPPORTED_MSG(EM_GETWORDBREAKPROCEX) + UNSUPPORTED_MSG(EM_HIDESELECTION) + UNSUPPORTED_MSG(EM_LIMITTEXT) /* also known as EM_SETLIMITTEXT */ + UNSUPPORTED_MSG(EM_LINEFROMCHAR) + UNSUPPORTED_MSG(EM_LINEINDEX) + UNSUPPORTED_MSG(EM_LINELENGTH) + UNSUPPORTED_MSG(EM_LINESCROLL) + UNSUPPORTED_MSG(EM_PASTESPECIAL) +/* UNSUPPORTED_MSG(EM_POSFROMCHARS) missing in Wine headers */ + UNSUPPORTED_MSG(EM_REQUESTRESIZE) + UNSUPPORTED_MSG(EM_SCROLL) + UNSUPPORTED_MSG(EM_SCROLLCARET) + UNSUPPORTED_MSG(EM_SELECTIONTYPE) + UNSUPPORTED_MSG(EM_SETLANGOPTIONS) + UNSUPPORTED_MSG(EM_SETOLECALLBACK) + UNSUPPORTED_MSG(EM_SETOPTIONS) + UNSUPPORTED_MSG(EM_SETRECT) + UNSUPPORTED_MSG(EM_SETRECTNP) + UNSUPPORTED_MSG(EM_SETTARGETDEVICE) + UNSUPPORTED_MSG(EM_SETTEXTMODE) + 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 */ + +/* Messages specific to Richedit controls */ + + case EM_STREAMIN: + return ME_StreamIn(editor, wParam, (EDITSTREAM*)lParam); + case WM_GETDLGCODE: + { + UINT code = DLGC_WANTCHARS|DLGC_WANTARROWS; + if (GetWindowLongW(hWnd, GWL_STYLE)&ES_WANTRETURN) + code |= 0; /* FIXME what can we do here ? ask for messages and censor them ? */ + return code; + } + case WM_NCCREATE: + { + CREATESTRUCTW *pcs = (CREATESTRUCTW *)lParam; + editor = ME_MakeEditor(hWnd); + SetWindowLongW(hWnd, 0, (long)editor); + pcs = 0; /* ignore */ + return TRUE; + } + case EM_EMPTYUNDOBUFFER: + ME_EmptyUndoStack(editor); + return 0; + case EM_GETSEL: + { + ME_GetSelection(editor, (int *)wParam, (int *)lParam); + if (!((wParam|lParam) & 0xFFFF0000)) + return (lParam<<16)|wParam; + return -1; + } + case EM_EXGETSEL: + { + CHARRANGE *pRange = (CHARRANGE *)lParam; + ME_GetSelection(editor, (int *)&pRange->cpMin, (int *)&pRange->cpMax); + return 0; + } + case EM_CANUNDO: + return editor->pUndoStack != NULL; + case EM_CANREDO: + return editor->pRedoStack != NULL; + case EM_UNDO: + ME_Undo(editor); + return 0; + case EM_REDO: + ME_Redo(editor); + return 0; + case EM_SETSEL: + { + ME_SetSelection(editor, wParam, lParam); + ME_Repaint(editor); + ME_SendSelChange(editor); + return 0; + } + case EM_EXSETSEL: + { + CHARRANGE *pRange = (CHARRANGE *)lParam; + ME_SetSelection(editor, pRange->cpMin, pRange->cpMax); + /* FIXME optimize */ + ME_Repaint(editor); + ME_SendSelChange(editor); + return 0; + } + case EM_SETBKGNDCOLOR: + { + LRESULT lColor = ME_GetBackColor(editor); + if (wParam) + editor->rgbBackColor = -1; + else + editor->rgbBackColor = lParam; + InvalidateRect(hWnd, NULL, TRUE); + UpdateWindow(hWnd); + return lColor; + } + case EM_GETMODIFY: + return editor->nModifyStep == 0 ? 0 : 1; + case EM_SETMODIFY: + { + if (wParam) + editor->nModifyStep = 0x80000000; + else + editor->nModifyStep = 0; + + return 0; + } + case EM_SETREADONLY: + { + long nStyle = GetWindowLongW(hWnd, GWL_STYLE); + if (wParam) + nStyle |= ES_READONLY; + else + nStyle &= ~ES_READONLY; + SetWindowLongW(hWnd, GWL_STYLE, nStyle); + ME_Repaint(editor); + return 0; + } + case EM_SETEVENTMASK: + editor->nEventMask = lParam; + return 0; + case EM_GETEVENTMASK: + return editor->nEventMask; + case EM_SETCHARFORMAT: + { + CHARFORMAT2W buf, *p; + p = ME_ToCF2W(&buf, (CHARFORMAT2W *)lParam); + if (!wParam) + ME_SetDefaultCharFormat(editor, p); + else if (wParam == (SCF_WORD | SCF_SELECTION)) + FIXME("word selection not supported\n"); + else if (wParam == SCF_ALL) + ME_SetCharFormat(editor, 0, ME_GetTextLength(editor), p); + else + ME_SetSelectionCharFormat(editor, p); + ME_CommitUndo(editor); + ME_UpdateRepaint(editor); + return 0; + } + case EM_GETCHARFORMAT: + { + CHARFORMAT2W tmp; + tmp.cbSize = sizeof(tmp); + if (!wParam) + ME_GetDefaultCharFormat(editor, &tmp); + else + ME_GetSelectionCharFormat(editor, &tmp); + ME_CopyToCFAny((CHARFORMAT2W *)lParam, &tmp); + return 0; + } + case EM_SETPARAFORMAT: + ME_SetSelectionParaFormat(editor, (PARAFORMAT2 *)lParam); + ME_CommitUndo(editor); + return 0; + case EM_GETPARAFORMAT: + ME_GetSelectionParaFormat(editor, (PARAFORMAT2 *)lParam); + return 0; + case WM_CLEAR: + { + int from, to; + ME_GetSelection(editor, &from, &to); + ME_InternalDeleteText(editor, from, to-from); + ME_CommitUndo(editor); + ME_UpdateRepaint(editor); + return 0; + } + case EM_REPLACESEL: + { + int from, to; + ME_Style *style; + LPWSTR wszText = ME_ToUnicode(hWnd, (void *)lParam); + size_t len = lstrlenW(wszText); + TRACE("EM_REPLACESEL - %s\n", debugstr_w(wszText)); + + ME_GetSelection(editor, &from, &to); + style = ME_GetSelectionInsertStyle(editor); + ME_InternalDeleteText(editor, from, to-from); + ME_InsertTextFromCursor(editor, 0, wszText, len, style); + ME_ReleaseStyle(style); + ME_EndToUnicode(hWnd, wszText); + /* drop temporary style if line end */ + /* FIXME question: does abc\n mean: put abc, clear temp style, put \n? (would require a change) */ + if (len>0 && wszText[len-1] == '\n') + ME_ClearTempStyle(editor); + + ME_CommitUndo(editor); + if (!wParam) + ME_EmptyUndoStack(editor); + ME_UpdateRepaint(editor); + return 0; + } + case WM_SETTEXT: + { + LPWSTR wszText = ME_ToUnicode(hWnd, (void *)lParam); + TRACE("WM_SETTEXT - %s\n", (char *)(wszText)); /* debugstr_w() */ + ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor)); + /* uses default style! */ + ME_InsertTextFromCursor(editor, 0, wszText, -1, editor->pBuffer->pDefaultStyle); + ME_EndToUnicode(hWnd, wszText); + ME_CommitUndo(editor); + ME_EmptyUndoStack(editor); + ME_UpdateRepaint(editor); + return 0; + } + case WM_CUT: + case WM_COPY: + { + int from, to, pars; + WCHAR *data; + HANDLE hData; + + if (!OpenClipboard(hWnd)) + return 0; + + EmptyClipboard(); + ME_GetSelection(editor, &from, &to); + pars = ME_CountParagraphsBetween(editor, from, to); + hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(WCHAR)*(to-from+pars+1)); + data = (WCHAR *)GlobalLock(hData); + ME_GetTextW(editor, data, from, to-from, TRUE); + GlobalUnlock(hData); + SetClipboardData(CF_UNICODETEXT, hData); + CloseClipboard(); + if (msg == WM_CUT) + { + ME_InternalDeleteText(editor, from, to-from); + ME_CommitUndo(editor); + ME_UpdateRepaint(editor); + } + return 0; + } + case WM_GETTEXTLENGTH: + return ME_GetTextLength(editor); + case WM_GETTEXT: + { + TEXTRANGEW tr; /* W and A differ only by rng->lpstrText */ + tr.chrg.cpMin = 0; + tr.chrg.cpMax = wParam-1; + tr.lpstrText = (WCHAR *)lParam; + return RichEditANSIWndProc(hWnd, EM_GETTEXTRANGE, 0, (LPARAM)&tr); + } + case EM_GETSELTEXT: + { + int from, to; + TEXTRANGEW tr; /* W and A differ only by rng->lpstrText */ + ME_GetSelection(editor, &from, &to); + tr.chrg.cpMin = from; + tr.chrg.cpMax = to; + tr.lpstrText = (WCHAR *)lParam; + return RichEditANSIWndProc(hWnd, EM_GETTEXTRANGE, 0, (LPARAM)&tr); + } + case EM_GETTEXTRANGE: + { + TEXTRANGEW *rng = (TEXTRANGEW *)lParam; + if (IsWindowUnicode(hWnd)) + return ME_GetTextW(editor, rng->lpstrText, rng->chrg.cpMin, rng->chrg.cpMax-rng->chrg.cpMin, FALSE); + else + { + int nLen = rng->chrg.cpMax-rng->chrg.cpMin; + WCHAR *p = ALLOC_N_OBJ(WCHAR, nLen+1); + int nChars = ME_GetTextW(editor, p, rng->chrg.cpMin, nLen, FALSE); + /* FIXME this is a potential security hole (buffer overrun) + if you know more about wchar->mbyte conversion please explain + */ + WideCharToMultiByte(CP_ACP, 0, p, nChars+1, (char *)rng->lpstrText, nLen+1, NULL, NULL); + FREE_OBJ(p); + return nChars; + } + return ME_GetTextW(editor, rng->lpstrText, rng->chrg.cpMin, rng->chrg.cpMax-rng->chrg.cpMin, FALSE); + } + case WM_CREATE: + ME_CommitUndo(editor); + ME_WrapMarkedParagraphs(editor); + ME_MoveCaret(editor); + return 0; + case WM_DESTROY: + ME_DestroyEditor(editor); + SetWindowLongW(hWnd, 0, 0); + return 0; + case WM_LBUTTONDOWN: + SetFocus(hWnd); + ME_LButtonDown(editor, (short)LOWORD(lParam), (short)HIWORD(lParam)); + SetCapture(hWnd); + break; + case WM_MOUSEMOVE: + if (GetCapture() == hWnd) + ME_MouseMove(editor, (short)LOWORD(lParam), (short)HIWORD(lParam)); + break; + case WM_LBUTTONUP: + if (GetCapture() == hWnd) + ReleaseCapture(); + break; + case WM_PAINT: + hDC = BeginPaint(hWnd, &ps); + ME_PaintContent(editor, hDC, FALSE, &ps.rcPaint); + EndPaint(hWnd, &ps); + break; + case WM_SETFOCUS: + ME_ShowCaret(editor); + ME_SendOldNotify(editor, EN_SETFOCUS); + return 0; + case WM_KILLFOCUS: + ME_HideCaret(editor); + ME_SendOldNotify(editor, EN_KILLFOCUS); + return 0; + case WM_ERASEBKGND: + { + HDC hDC = (HDC)wParam; + RECT rc; + COLORREF rgbBG = ME_GetBackColor(editor); + if (GetUpdateRect(hWnd,&rc,TRUE)) + { + HBRUSH hbr = CreateSolidBrush(rgbBG); + FillRect(hDC, &rc, hbr); + DeleteObject(hbr); + } + return 1; + } + case WM_COMMAND: + TRACE("editor wnd command = %d\n", LOWORD(wParam)); + return 0; + case WM_KEYDOWN: + if (ME_ArrowKey(editor, LOWORD(wParam), GetKeyState(VK_CONTROL)<0)) { + ME_CommitUndo(editor); + ME_EnsureVisible(editor, editor->pCursors[0].pRun); + HideCaret(hWnd); + ME_MoveCaret(editor); + ShowCaret(hWnd); + return 0; + } + if (GetKeyState(VK_CONTROL)<0) + { + if (LOWORD(wParam)=='W') + { + CHARFORMAT2W chf; + char buf[2048]; + ME_GetSelectionCharFormat(editor, &chf); + ME_DumpStyleToBuf(&chf, buf); + MessageBoxA(NULL, buf, "Style dump", MB_OK); + } + if (LOWORD(wParam)=='Q') + { + ME_CheckCharOffsets(editor); + } + } + goto do_default; + case WM_CHAR: + { + WCHAR wstr; + if (GetWindowLongW(editor->hWnd, GWL_STYLE) & ES_READONLY) { + MessageBeep(MB_ICONERROR); + return 0; /* FIXME really 0 ? */ + } + wstr = LOWORD(wParam); + if (((unsigned)wstr)>=' ' || wstr=='\r') { + /* FIXME maybe it would make sense to call EM_REPLACESEL instead ? */ + ME_Style *style = ME_GetInsertStyle(editor, 0); + ME_SaveTempStyle(editor); + ME_InsertTextFromCursor(editor, 0, &wstr, 1, style); + ME_ReleaseStyle(style); + ME_CommitUndo(editor); + ME_UpdateRepaint(editor); + } + return 0; + } + case WM_VSCROLL: + { + 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); + break; + } + break; + } + case WM_SIZE: + { + ME_MarkAllForWrapping(editor); + ME_Repaint(editor); + return DefWindowProcW(hWnd, msg, wParam, lParam); + } + case EM_GETOLEINTERFACE: + { + LPVOID *ppvObj = (LPVOID*) lParam; + FIXME("EM_GETOLEINTERFACE %p: stub\n", ppvObj); + return CreateIRichEditOle(ppvObj); + } + default: + do_default: + return DefWindowProcW(hWnd, msg, wParam, lParam); + } + return 0L; +} + +/****************************************************************** + * RichEdit10ANSIWndProc (RICHED20.9) + */ +LRESULT WINAPI RichEdit10ANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + /* FIXME: this is NOT the same as 2.0 version */ + return RichEditANSIWndProc(hWnd, msg, wParam, lParam); +} + +void ME_SendOldNotify(ME_TextEditor *editor, int nCode) +{ + HWND hWnd = editor->hWnd; + SendMessageA(GetParent(hWnd), WM_COMMAND, (nCode<<16)|GetWindowLongW(hWnd, GWLP_ID), (LPARAM)hWnd); +} + +int ME_CountParagraphsBetween(ME_TextEditor *editor, int from, int to) +{ + ME_DisplayItem *item = ME_FindItemFwd(editor->pBuffer->pFirst, diParagraph); + int i = 0; + + while(item && item->member.para.next_para->member.para.nCharOfs <= from) + item = item->member.para.next_para; + if (!item) + return 0; + while(item && item->member.para.next_para->member.para.nCharOfs <= to) { + item = item->member.para.next_para; + i++; + } + 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); + 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; + if (nLen > nChars) + nLen = nChars; + CopyMemory(buffer, item->member.run.strText->szData + nStart, sizeof(WCHAR)*nLen); + nChars -= nLen; + nWritten += nLen; + if (!nChars) + return nWritten; + buffer += nLen; + nStart = 0; + item = ME_FindItemFwd(item, diRun); + } + + while(nChars && item) + { + int nLen = ME_StrLen(item->member.run.strText); + if (nLen > nChars) + nLen = nChars; + + if (item->member.run.nFlags & MERF_ENDPARA) + { + if (bCRLF) { + *buffer++ = '\r'; + nWritten++; + } + *buffer = '\n'; + assert(nLen == 1); + } + else + CopyMemory(buffer, item->member.run.strText->szData, sizeof(WCHAR)*nLen); + nChars -= nLen; + nWritten += nLen; + buffer += nLen; + + if (!nChars) + { + *buffer = L'\0'; + return nWritten; + } + item = ME_FindItemFwd(item, diRun); + } + *buffer = L'\0'; + return nWritten; +} + +static WCHAR wszClassName[] = {'R', 'i', 'c', 'h', 'E', 'd', 'i', 't', '2', '0', 'W', 0}; +static WCHAR wszClassName50[] = {'R', 'i', 'c', 'h', 'E', 'd', 'i', 't', '5', '0', 'W', 0}; + +void ME_RegisterEditorClass(HINSTANCE hInstance) +{ + BOOL bResult; + WNDCLASSW wcW; + WNDCLASSA wcA; + + wcW.style = CS_HREDRAW | CS_VREDRAW; + wcW.lpfnWndProc = RichEditANSIWndProc; + wcW.cbClsExtra = 0; + wcW.cbWndExtra = 4; + wcW.hInstance = NULL; /* hInstance would register DLL-local class */ + wcW.hIcon = NULL; + wcW.hCursor = LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_IBEAM)); + wcW.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH); + wcW.lpszMenuName = NULL; + wcW.lpszClassName = wszClassName; + bResult = RegisterClassW(&wcW); + assert(bResult); + wcW.lpszClassName = wszClassName50; + bResult = RegisterClassW(&wcW); + assert(bResult); + + wcA.style = CS_HREDRAW | CS_VREDRAW; + wcA.lpfnWndProc = RichEditANSIWndProc; + wcA.cbClsExtra = 0; + wcA.cbWndExtra = 4; + wcA.hInstance = NULL; /* hInstance would register DLL-local class */ + wcA.hIcon = NULL; + wcA.hCursor = LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_IBEAM)); + wcA.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH); + wcA.lpszMenuName = NULL; + wcA.lpszClassName = "RichEdit20A"; + bResult = RegisterClassA(&wcA); + assert(bResult); + wcA.lpszClassName = "RichEdit50A"; + bResult = RegisterClassA(&wcA); + assert(bResult); +} + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + TRACE("\n"); + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDLL); + me_heap = HeapCreate (0, 0x10000, 0); + ME_RegisterEditorClass(hinstDLL); + break; + + case DLL_PROCESS_DETACH: + UnregisterClassW(wszClassName, 0); + UnregisterClassW(wszClassName50, 0); + UnregisterClassA("RichEdit20A", 0); + UnregisterClassA("RichEdit50A", 0); + HeapDestroy (me_heap); + me_heap = NULL; + break; + } + return TRUE; +} + +/****************************************************************** + * CreateTextServices (RICHED20.4) + * + * FIXME should be ITextHost instead of void* + */ +HRESULT WINAPI CreateTextServices(IUnknown *punkOuter, void *pITextHost, + IUnknown **ppUnk) +{ + FIXME("stub\n"); + /* FIXME should support aggregation */ + if (punkOuter) + return CLASS_E_NOAGGREGATION; + + return E_FAIL; /* E_NOTIMPL isn't allowed by MSDN */ +} + +/****************************************************************** + * REExtendedRegisterClass (RICHED20.8) + * + * FIXME undocumented + */ +void WINAPI REExtendedRegisterClass(void) +{ + FIXME("stub\n"); +} diff --git a/reactos/lib/riched20/editor.h b/reactos/lib/riched20/editor.h new file mode 100644 index 00000000000..8749fd2a04f --- /dev/null +++ b/reactos/lib/riched20/editor.h @@ -0,0 +1,212 @@ +/* + * RichEdit - prototypes for functions and macro definitions + * + * Copyright 2004 by Krzysztof Foltman + * + * 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 "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 FREE_OBJ(ptr) HeapFree(me_heap, 0, ptr) + +/* style.c */ +ME_Style *ME_MakeStyle(CHARFORMAT2W *style); +void ME_AddRefStyle(ME_Style *item); +void ME_ReleaseStyle(ME_Style *item); +ME_Style *ME_GetInsertStyle(ME_TextEditor *editor, int nCursor); +ME_Style *ME_ApplyStyle(ME_Style *sSrc, CHARFORMAT2W *style); +HFONT ME_SelectStyleFont(ME_TextEditor *editor, HDC hDC, ME_Style *s); +void ME_UnselectStyleFont(ME_TextEditor *editor, HDC hDC, ME_Style *s, HFONT hOldFont); +void ME_InitCharFormat2W(CHARFORMAT2W *pFmt); +void ME_SaveTempStyle(ME_TextEditor *editor); +void ME_ClearTempStyle(ME_TextEditor *editor); +void ME_DumpStyleToBuf(CHARFORMAT2W *pFmt, char buf[2048]); +void ME_DumpStyle(ME_Style *s); +CHARFORMAT2W *ME_ToCF2W(CHARFORMAT2W *to, CHARFORMAT2W *from); +void ME_CopyToCF2W(CHARFORMAT2W *to, CHARFORMAT2W *from); +CHARFORMAT2W *ME_ToCFAny(CHARFORMAT2W *to, CHARFORMAT2W *from); +void ME_CopyToCFAny(CHARFORMAT2W *to, CHARFORMAT2W *from); +void ME_CopyCharFormat(CHARFORMAT2W *pDest, CHARFORMAT2W *pSrc); /* only works with 2W structs */ + +/* list.c */ +void ME_InsertBefore(ME_DisplayItem *diWhere, ME_DisplayItem *diWhat); +void ME_Remove(ME_DisplayItem *diWhere); +ME_DisplayItem *ME_FindItemBack(ME_DisplayItem *di, ME_DIType nTypeOrClass); +ME_DisplayItem *ME_FindItemFwd(ME_DisplayItem *di, ME_DIType nTypeOrClass); +ME_DisplayItem *ME_FindItemBackOrHere(ME_DisplayItem *di, ME_DIType nTypeOrClass); +ME_DisplayItem *ME_FindItemFwdOrHere(ME_DisplayItem *di, ME_DIType nTypeOrClass); +BOOL ME_DITypesEqual(ME_DIType type, ME_DIType nTypeOrClass); +ME_DisplayItem *ME_MakeDI(ME_DIType type); +void ME_DestroyDisplayItem(ME_DisplayItem *item); +void ME_DumpDocument(ME_TextBuffer *buffer); +const char *ME_GetDITypeName(ME_DIType type); + +/* string.c */ +int ME_GetOptimalBuffer(int nLen); +ME_String *ME_MakeString(LPCWSTR szText); +ME_String *ME_MakeStringN(LPCWSTR szText, int nMaxChars); +ME_String *ME_StrDup(ME_String *s); +void ME_DestroyString(ME_String *s); +void ME_AppendString(ME_String *s1, ME_String *s2); +ME_String *ME_ConcatString(ME_String *s1, ME_String *s2); +ME_String *ME_VSplitString(ME_String *orig, int nVPos); +int ME_IsWhitespaces(ME_String *s); +int ME_IsSplitable(ME_String *s); +/* int ME_CalcSkipChars(ME_String *s); */ +int ME_StrLen(ME_String *s); +int ME_StrVLen(ME_String *s); +int ME_FindNonWhitespaceV(ME_String *s, int nVChar); +int ME_FindWhitespaceV(ME_String *s, int nVChar); +int ME_GetCharFwd(ME_String *s, int nPos); /* get char starting from start */ +int ME_GetCharBack(ME_String *s, int nPos); /* get char starting from \0 */ +int ME_StrRelPos(ME_String *s, int nVChar, int *pRelChars); +int ME_StrRelPos2(ME_String *s, int nVChar, int nRelChars); +int ME_VPosToPos(ME_String *s, int nVPos); +int ME_PosToVPos(ME_String *s, int nPos); +void ME_StrDeleteV(ME_String *s, int nVChar, int nChars); +/* smart helpers for A<->W conversions, they reserve/free memory and call MultiByte<->WideChar functions */ +LPWSTR ME_ToUnicode(HWND hWnd, LPVOID psz); +void ME_EndToUnicode(HWND hWnd, LPVOID psz); +LPSTR ME_ToAnsi(HWND hWnd, LPVOID psz); +void ME_EndToAnsi(HWND hWnd, LPVOID psz); + + +/* note: those two really return the first matching offset (starting from EOS)+1 + * in other words, an offset of the first trailing white/black */ +int ME_ReverseFindNonWhitespaceV(ME_String *s, int nVChar); +int ME_ReverseFindWhitespaceV(ME_String *s, int nVChar); + +/* row.c */ +ME_DisplayItem *ME_FindRowStart(ME_Context *c, ME_DisplayItem *run, int nRelPos); +ME_DisplayItem *ME_RowStart(ME_DisplayItem *item); +ME_DisplayItem *ME_RowEnd(ME_DisplayItem *item); +void ME_RenumberParagraphs(ME_DisplayItem *item); /* TODO */ + +/* run.c */ +ME_DisplayItem *ME_MakeRun(ME_Style *s, ME_String *strData, int nFlags); +/* note: ME_InsertRun inserts a copy of the specified run - so you need to destroy the original */ +ME_DisplayItem *ME_InsertRun(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem *pItem); +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); +/* 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); +int ME_GetLastSplittablePlace(ME_Context *c, ME_Run *run); +int ME_CanJoinRuns(ME_Run *run1, ME_Run *run2); +void ME_JoinRuns(ME_TextEditor *editor, ME_DisplayItem *p); +ME_DisplayItem *ME_SplitRun(ME_Context *c, ME_DisplayItem *item, int nChar); +ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, int nChar); +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_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); +void ME_SkipAndPropagateCharOffset(ME_DisplayItem *p, int shift); +void ME_SetCharFormat(ME_TextEditor *editor, int nFrom, int nLen, CHARFORMAT2W *pFmt); +void ME_SetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt); +void ME_GetCharFormat(ME_TextEditor *editor, int nFrom, int nLen, CHARFORMAT2W *pFmt); +void ME_GetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt); +void ME_GetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt); +void ME_SetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *mod); + +/* caret.c */ +void ME_SetSelection(ME_TextEditor *editor, int from, int to); +void ME_HideCaret(ME_TextEditor *ed); +void ME_ShowCaret(ME_TextEditor *ed); +void ME_MoveCaret(ME_TextEditor *ed); +int ME_FindPixelPos(ME_TextEditor *editor, int x, int y, ME_Cursor *result, BOOL *is_eol); +void ME_LButtonDown(ME_TextEditor *editor, int x, int y); +void ME_MouseMove(ME_TextEditor *editor, int x, int y); +void ME_DeleteTextAtCursor(ME_TextEditor *editor, int nCursor, int nChars); +void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, + const WCHAR *str, int len, ME_Style *style); +void ME_SetCharFormat(ME_TextEditor *editor, int nOfs, int nChars, CHARFORMAT2W *pFmt); +BOOL ME_ArrowKey(ME_TextEditor *ed, int nVKey, int nCtrl); + +void ME_InitContext(ME_Context *c, ME_TextEditor *editor, HDC hDC); +void ME_DestroyContext(ME_Context *c); +ME_Style *GetInsertStyle(ME_TextEditor *editor, int nCursor); +void ME_MustBeWrapped(ME_Context *c, ME_DisplayItem *para); +int ME_GetCursorOfs(ME_TextEditor *editor, int nCursor); +void ME_GetSelection(ME_TextEditor *editor, int *from, int *to); +int ME_CountParagraphsBetween(ME_TextEditor *editor, int from, int to); +BOOL ME_IsSelection(ME_TextEditor *editor); +void ME_DeleteSelection(ME_TextEditor *editor); +void ME_SendSelChange(ME_TextEditor *editor); +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); + +/* 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); + +/* para.c */ +ME_DisplayItem *ME_GetParagraph(ME_DisplayItem *run); +void ME_MakeFirstParagraph(HDC hDC, ME_TextBuffer *editor); +ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *rp, ME_Style *style); +ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp); +void ME_DumpParaStyle(ME_Paragraph *s); +void ME_DumpParaStyleToBuf(PARAFORMAT2 *pFmt, char buf[2048]); +void ME_SetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, PARAFORMAT2 *pFmt); +void ME_SetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt); +void ME_GetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, PARAFORMAT2 *pFmt); +void ME_GetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt); +/* marks from first up to (but not including) last */ +void ME_MarkForWrapping(ME_TextEditor *editor, ME_DisplayItem *first, ME_DisplayItem *last); +void ME_MarkAllForWrapping(ME_TextEditor *editor); + +/* paint.c */ +void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, RECT *rcUpdate); +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_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun); +COLORREF ME_GetBackColor(ME_TextEditor *editor); + +/* richole.c */ +extern LRESULT CreateIRichEditOle(LPVOID *); + +/* wintest.c */ + +/* editor.c */ +void ME_RegisterEditorClass(); +ME_TextEditor *ME_MakeEditor(HWND hWnd); +void ME_DestroyEditor(ME_TextEditor *editor); +void ME_SendOldNotify(ME_TextEditor *editor, int nCode); +ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, ME_DisplayItem *di); +void ME_CommitUndo(ME_TextEditor *editor); +void ME_Undo(ME_TextEditor *editor); +void ME_Redo(ME_TextEditor *editor); +void ME_EmptyUndoStack(ME_TextEditor *editor); +int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, BOOL bCRLF); + +extern int me_debug; +extern HANDLE me_heap; +extern void DoWrap(ME_TextEditor *editor); diff --git a/reactos/lib/riched20/editstr.h b/reactos/lib/riched20/editstr.h new file mode 100644 index 00000000000..d1f48198303 --- /dev/null +++ b/reactos/lib/riched20/editstr.h @@ -0,0 +1,258 @@ +/* + * RichEdit - structures and constant + * + * Copyright 2004 by Krzysztof Foltman + * + * 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 + */ + +#ifndef __EDITSTR_H +#define __EDITSTR_H + +#ifndef _WIN32_IE +#define _WIN32_IE 0x0400 +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wine/debug.h" + +typedef struct tagME_String +{ + WCHAR *szData; + int nLen, nBuffer; +} ME_String; + +typedef struct tagME_Style +{ + CHARFORMAT2W fmt; + + HFONT hFont; /* cached font for the style */ + TEXTMETRICW tm; /* cached font metrics for the style */ + int nRefs; /* reference count */ + int nSequence; /* incremented when cache needs to be rebuilt, ie. every screen redraw */ +} ME_Style; + +typedef enum { + diTextStart, /* start of the text buffer */ + diParagraph, /* paragraph start */ + diRun, /* run (sequence of chars with the same character format) */ + diStartRow, /* start of the row (line of text on the screen) */ + diTextEnd, /* end of the text buffer */ + + /********************* these below are meant for finding only *********************/ + diStartRowOrParagraph, /* 5 */ + diStartRowOrParagraphOrEnd, + diRunOrParagraph, + diRunOrStartRow, + diParagraphOrEnd, + diRunOrParagraphOrEnd, /* 10 */ + + diUndoInsertRun, /* 11 */ + diUndoDeleteRun, /* 12 */ + diUndoJoinParagraphs, /* 13 */ + diUndoSplitParagraph, /* 14 */ + diUndoSetParagraphFormat, /* 15 */ + diUndoSetCharFormat, /* 16 */ + diUndoEndTransaction, /* 17 */ + diUndoSetDefaultCharFormat, /* 18 */ +} ME_DIType; + +/******************************** run flags *************************/ +#define MERF_STYLEFLAGS 0x0FFF +/* run contains non-text content, which has its own rules for wrapping, sizing etc */ +#define MERF_GRAPHICS 1 + +/* run is splittable (contains white spaces in the middle or end) */ +#define MERF_SPLITTABLE 0x001000 +/* run starts with whitespaces */ +#define MERF_STARTWHITE 0x002000 +/* run ends with whitespaces */ +#define MERF_ENDWHITE 0x004000 +/* run is completely made of whitespaces */ +#define MERF_WHITESPACE 0x008000 +/* run is a last (dummy) run in the paragraph */ +#define MERF_SKIPPED 0x010000 +/* flags that are calculated during text wrapping */ +#define MERF_CALCBYWRAP 0x0F0000 +/* the "end of paragraph" run, contains 1 character */ +#define MERF_ENDPARA 0x100000 + +/* those flags are kept when the row is split */ +#define MERF_SPLITMASK (~(0)) + +/******************************** para flags *************************/ + +/* this paragraph was already wrapped and hasn't changed, every change resets that flag */ +#define MEPF_REWRAP 1 +#define MEPF_REPAINT 2 + +/******************************** structures *************************/ + +struct tagME_DisplayItem; + +typedef struct tagME_Run +{ + ME_String *strText; + ME_Style *style; + int nCharOfs; /* relative to para's offset */ + int nWidth; /* width of full run, width of leading&trailing ws */ + int nFlags; + int nAscent, nDescent; /* pixels above/below baseline */ + POINT pt; /* relative to para's position */ +} ME_Run; + +typedef struct tagME_Document { + struct tagME_DisplayItem *def_char_style; + struct tagME_DisplayItem *def_para_style; + int last_wrapped_line; +} ME_Document; + +typedef struct tagME_Paragraph +{ + PARAFORMAT2 *pFmt; + int nLeftMargin, nRightMargin, nFirstMargin; + int nCharOfs; + int nFlags; + int nYPos, nHeight; + int nLastPaintYPos, nLastPaintHeight; + struct tagME_DisplayItem *prev_para, *next_para, *document; +} ME_Paragraph; + +typedef struct tagME_Row +{ + int nHeight; + int nBaseline; + int nWidth; + int nLMargin; + int nRMargin; + int nYPos; +} ME_Row; + +typedef struct tagME_DisplayItem +{ + ME_DIType type; + struct tagME_DisplayItem *prev, *next; + union { + ME_Run run; + ME_Row row; + ME_Paragraph para; + ME_Document doc; /* not used */ + ME_Style *ustyle; /* used by diUndoSetCharFormat */ + } member; +} ME_DisplayItem; + +typedef struct tagME_UndoItem +{ + ME_DisplayItem di; + int nStart, nLen; +} ME_UndoItem; + +typedef struct tagME_TextBuffer +{ + ME_DisplayItem *pFirst, *pLast; + ME_Style *pCharStyle; + ME_Style *pDefaultStyle; +} ME_TextBuffer; + +typedef struct tagME_Cursor +{ + ME_DisplayItem *pRun; + int nOffset; +} ME_Cursor; + +typedef enum { + umAddToUndo, + umAddToRedo, + umIgnore, + umAddBackToUndo +} ME_UndoMode; + +typedef struct tagME_FontCacheItem +{ + LOGFONTW lfSpecs; + HFONT hFont; + int nRefs; + int nAge; +} ME_FontCacheItem; + +#define HFONT_CACHE_SIZE 10 + +typedef struct tagME_TextEditor +{ + HWND hWnd; + BOOL bCaretShown; + ME_TextBuffer *pBuffer; + ME_Cursor *pCursors; + int nCursors; + SIZE sizeWindow; + int nScrollPos; + int nTotalLength, nLastTotalLength; + int nUDArrowX; + int nSequence; + int nOldSelFrom, nOldSelTo; + COLORREF rgbBackColor; + BOOL bCaretAtEnd; + int nEventMask; + int nModifyStep; + ME_DisplayItem *pUndoStack, *pRedoStack; + ME_UndoMode nUndoMode; + int nParagraphs; + int nLastSelStart, nLastSelEnd; + ME_FontCacheItem pFontCache[HFONT_CACHE_SIZE]; +} ME_TextEditor; + +typedef struct tagME_Context +{ + HDC hDC; + POINT pt; + POINT ptRowOffset; + RECT rcView; + HBRUSH hbrMargin; + + /* those are valid inside ME_WrapTextParagraph and related */ + POINT ptFirstRun; + ME_TextEditor *editor; + int nSequence; +} ME_Context; + +typedef struct tagME_WrapContext +{ + ME_Style *style; + ME_Context *context; + int nLeftMargin, nRightMargin, nFirstMargin; + int nTotalWidth, nAvailWidth; + int nRow; + POINT pt; + BOOL bOverflown; + ME_DisplayItem *pRowStart; + + ME_DisplayItem *pLastSplittableRun; + POINT ptLastSplittableRun; +} ME_WrapContext; + +#endif diff --git a/reactos/lib/riched20/list.c b/reactos/lib/riched20/list.c new file mode 100644 index 00000000000..e4e1f403862 --- /dev/null +++ b/reactos/lib/riched20/list.c @@ -0,0 +1,192 @@ +/* + * RichEdit - Basic operations on double linked lists. + * + * Copyright 2004 by Krzysztof Foltman + * + * 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" + +WINE_DEFAULT_DEBUG_CHANNEL(riched20); + +void ME_InsertBefore(ME_DisplayItem *diWhere, ME_DisplayItem *diWhat) +{ + diWhat->next = diWhere; + diWhat->prev = diWhere->prev; + + diWhere->prev->next = diWhat; + diWhat->next->prev = diWhat; +} + +void ME_Remove(ME_DisplayItem *diWhere) +{ + ME_DisplayItem *diNext = diWhere->next; + ME_DisplayItem *diPrev = diWhere->prev; + assert(diNext); + assert(diPrev); + diPrev->next = diNext; + diNext->prev = diPrev; +} + +ME_DisplayItem *ME_FindItemBack(ME_DisplayItem *di, ME_DIType nTypeOrClass) +{ + if (!di) + return NULL; + di = di->prev; + while(di!=NULL) { + if (ME_DITypesEqual(di->type, nTypeOrClass)) + return di; + di = di->prev; + } + return NULL; +} + +ME_DisplayItem *ME_FindItemBackOrHere(ME_DisplayItem *di, ME_DIType nTypeOrClass) +{ + while(di!=NULL) { + if (ME_DITypesEqual(di->type, nTypeOrClass)) + return di; + di = di->prev; + } + return NULL; +} + +ME_DisplayItem *ME_FindItemFwd(ME_DisplayItem *di, ME_DIType nTypeOrClass) +{ + if (!di) return NULL; + di = di->next; + while(di!=NULL) { + if (ME_DITypesEqual(di->type, nTypeOrClass)) + return di; + di = di->next; + } + return NULL; +} + +ME_DisplayItem *ME_FindItemFwdOrHere(ME_DisplayItem *di, ME_DIType nTypeOrClass) +{ + while(di!=NULL) { + if (ME_DITypesEqual(di->type, nTypeOrClass)) + return di; + di = di->next; + } + return NULL; +} + +BOOL ME_DITypesEqual(ME_DIType type, ME_DIType nTypeOrClass) +{ + if (type==nTypeOrClass) + return TRUE; + if (nTypeOrClass==diRunOrParagraph && (type==diRun || type==diParagraph)) + return TRUE; + if (nTypeOrClass==diRunOrStartRow && (type==diRun || type==diStartRow)) + return TRUE; + if (nTypeOrClass==diParagraphOrEnd && (type==diTextEnd || type==diParagraph)) + return TRUE; + if (nTypeOrClass==diStartRowOrParagraph && (type==diStartRow || type==diParagraph)) + return TRUE; + if (nTypeOrClass==diStartRowOrParagraphOrEnd + && (type==diStartRow || type==diParagraph || type==diTextEnd)) + return TRUE; + if (nTypeOrClass==diRunOrParagraphOrEnd + && (type==diRun || type==diParagraph || type==diTextEnd)) + return TRUE; + return FALSE; +} + +void ME_DestroyDisplayItem(ME_DisplayItem *item) { +/* TRACE("type=%s\n", ME_GetDITypeName(item->type)); */ + if (item->type==diParagraph || item->type == diUndoSetParagraphFormat) { + FREE_OBJ(item->member.para.pFmt); + } + if (item->type==diRun || item->type == diUndoInsertRun) { + ME_ReleaseStyle(item->member.run.style); + ME_DestroyString(item->member.run.strText); + } + if (item->type==diUndoSetCharFormat || item->type==diUndoSetDefaultCharFormat) { + ME_ReleaseStyle(item->member.ustyle); + } + FREE_OBJ(item); +} + +ME_DisplayItem *ME_MakeDI(ME_DIType type) { + ME_DisplayItem *item = ALLOC_OBJ(ME_DisplayItem); + ZeroMemory(item, sizeof(ME_DisplayItem)); + item->type = type; + item->prev = item->next = NULL; + if (type == diParagraph || type == diUndoSplitParagraph) { + item->member.para.pFmt = ALLOC_OBJ(PARAFORMAT2); + item->member.para.pFmt->cbSize = sizeof(PARAFORMAT2); + item->member.para.pFmt->dwMask = 0; + item->member.para.nFlags = MEPF_REWRAP; + } + + return item; +} + +const char *ME_GetDITypeName(ME_DIType type) +{ + switch(type) + { + case diParagraph: return "diParagraph"; + case diRun: return "diRun"; + case diTextStart: return "diTextStart"; + case diTextEnd: return "diTextEnd"; + case diStartRow: return "diStartRow"; + case diUndoEndTransaction: return "diUndoEndTransaction"; + case diUndoSetParagraphFormat: return "diUndoSetParagraphFormat"; + case diUndoSetCharFormat: return "diUndoSetCharFormat"; + case diUndoInsertRun: return "diUndoInsertRun"; + case diUndoDeleteRun: return "diUndoDeleteRun"; + case diUndoJoinParagraphs: return "diJoinParagraphs"; + case diUndoSplitParagraph: return "diSplitParagraph"; + case diUndoSetDefaultCharFormat: return "diUndoSetDefaultCharFormat"; + default: return "?"; + } +} + +void ME_DumpDocument(ME_TextBuffer *buffer) +{ + /* FIXME this is useless, */ + ME_DisplayItem *pItem = buffer->pFirst; + TRACE("DOCUMENT DUMP START\n"); + while(pItem) { + switch(pItem->type) + { + case diTextStart: + TRACE("Start"); + break; + case diParagraph: + TRACE("\nParagraph(ofs=%d)", pItem->member.para.nCharOfs); + break; + case diStartRow: + TRACE(" - StartRow"); + break; + case diRun: + TRACE(" - Run(\"%s\", %d)", debugstr_w(pItem->member.run.strText->szData), + pItem->member.run.nCharOfs); + break; + case diTextEnd: + TRACE("\nEnd\n"); + break; + default: + break; + } + pItem = pItem->next; + } + TRACE("DOCUMENT DUMP END\n"); +} diff --git a/reactos/lib/riched20/makefile b/reactos/lib/riched20/makefile new file mode 100644 index 00000000000..faf2fc04220 --- /dev/null +++ b/reactos/lib/riched20/makefile @@ -0,0 +1,9 @@ +# $Id: makefile 12852 2005-01-06 13:58:04Z mf $ + +PATH_TO_TOP = ../.. + +TARGET_TYPE = winedll + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk diff --git a/reactos/lib/riched20/paint.c b/reactos/lib/riched20/paint.c new file mode 100644 index 00000000000..90b8d9d36c6 --- /dev/null +++ b/reactos/lib/riched20/paint.c @@ -0,0 +1,430 @@ +/* + * RichEdit - painting functions + * + * Copyright 2004 by Krzysztof Foltman + * + * 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" + +WINE_DEFAULT_DEBUG_CHANNEL(richedit); + +void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, RECT *rcUpdate) { + ME_DisplayItem *item; + ME_Context c; + int yoffset; + + editor->nSequence++; + yoffset = GetScrollPos(editor->hWnd, SB_VERT); + 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) { + assert(item->type == diParagraph); + if (!bOnlyNew || (item->member.para.nFlags & MEPF_REPAINT)) + { + BOOL bPaint = (rcUpdate == NULL); + if (rcUpdate) + bPaint = c.pt.ybottom && + c.pt.y+item->member.para.nHeight>rcUpdate->top; + if (bPaint) + { + ME_DrawParagraph(&c, item); + item->member.para.nFlags &= ~MEPF_REPAINT; + } + } + c.pt.y += item->member.para.nHeight; + item = item->member.para.next_para; + } + if (c.pt.ynTotalLength-yoffset, y2 = editor->nLastTotalLength-yoffset; + if (y1left, xe = rcUpdate->right; + if (rcUpdate->top > ys) + ys = rcUpdate->top; + if (rcUpdate->bottom < ye) + ye = rcUpdate->bottom; + } + + rc.left = xs; /* FIXME remove if it's not necessary anymore */ + rc.top = c.pt.y; + rc.right = xe; + rc.bottom = c.pt.y+1; + FillRect(hDC, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH)); + + if (ys == c.pt.y) /* don't overwrite the top bar */ + ys++; + if (ye>ys) { + rc.left = xs; + rc.top = ys; + rc.right = xe; + rc.bottom = ye; + /* this is not supposed to be gray, I know, but lets keep it gray for now for debugging purposes */ + FillRect(hDC, &rc, (HBRUSH)GetStockObject(LTGRAY_BRUSH)); + } + } + editor->nLastTotalLength = editor->nTotalLength; + ME_DestroyContext(&c); +} + +void ME_MarkParagraphRange(ME_TextEditor *editor, ME_DisplayItem *p1, + ME_DisplayItem *p2, int nFlags) +{ + ME_DisplayItem *p3; + if (p1 == p2) + { + p1->member.para.nFlags |= nFlags; + return; + } + if (p1->member.para.nCharOfs > p2->member.para.nCharOfs) + p3 = p1, p1 = p2, p2 = p3; + + p1->member.para.nFlags |= nFlags; + do { + p1 = p1->member.para.next_para; + p1->member.para.nFlags |= nFlags; + } while (p1 != p2); +} + +void ME_MarkOffsetRange(ME_TextEditor *editor, int from, int to, int nFlags) +{ + ME_Cursor c1, c2; + ME_CursorFromCharOfs(editor, from, &c1); + ME_CursorFromCharOfs(editor, to, &c2); + + ME_MarkParagraphRange(editor, ME_GetParagraph(c1.pRun), ME_GetParagraph(c2.pRun), nFlags); +} + +void ME_MarkSelectionForRepaint(ME_TextEditor *editor) +{ + int from, to, from2, to2, end; + + end = ME_GetTextLength(editor); + ME_GetSelection(editor, &from, &to); + from2 = editor->nLastSelStart; + to2 = editor->nLastSelEnd; + if (fromfrom2) ME_MarkOffsetRange(editor, from2, from, MEPF_REPAINT); + if (toto2) ME_MarkOffsetRange(editor, to2, to, MEPF_REPAINT); + + editor->nLastSelStart = from; + editor->nLastSelEnd = to; +} + +void ME_Repaint(ME_TextEditor *editor) +{ + ME_Cursor *pCursor = &editor->pCursors[0]; + ME_DisplayItem *pRun = NULL; + int nOffset = -1; + HDC hDC; + + int nCharOfs = ME_CharOfsFromRunOfs(editor, pCursor->pRun, pCursor->nOffset); + ME_RunOfsFromCharOfs(editor, nCharOfs, &pRun, &nOffset); + assert(pRun == pCursor->pRun); + assert(nOffset == pCursor->nOffset); + ME_MarkSelectionForRepaint(editor); + ME_WrapMarkedParagraphs(editor); + hDC = GetDC(editor->hWnd); + ME_HideCaret(editor); + ME_PaintContent(editor, hDC, TRUE, NULL); + ReleaseDC(editor->hWnd, hDC); + ME_ShowCaret(editor); +} + +void ME_UpdateRepaint(ME_TextEditor *editor) +{ +/* + InvalidateRect(editor->hWnd, NULL, TRUE); + */ + ME_SendOldNotify(editor, EN_CHANGE); + ME_Repaint(editor); + ME_SendOldNotify(editor, EN_UPDATE); + ME_SendSelChange(editor); +} + +void ME_DrawTextWithStyle(ME_Context *c, int x, int y, LPCWSTR szText, int nChars, + ME_Style *s, int *width, int nSelFrom, int nSelTo, int ymin, int cy) { + HDC hDC = c->hDC; + HGDIOBJ hOldFont; + COLORREF rgbOld, rgbBack; + hOldFont = ME_SelectStyleFont(c->editor, hDC, s); + rgbBack = ME_GetBackColor(c->editor); + if ((s->fmt.dwMask & CFM_COLOR) && (s->fmt.dwEffects & CFE_AUTOCOLOR)) + rgbOld = SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT)); + else + rgbOld = SetTextColor(hDC, s->fmt.crTextColor); + ExtTextOutW(hDC, x, y, 0, NULL, szText, nChars, NULL); + if (width) { + SIZE sz; + GetTextExtentPoint32W(hDC, szText, nChars, &sz); + *width = sz.cx; + } + if (nSelFrom < nChars && nSelTo >= 0 && nSelFrom nChars) nSelTo = nChars; + GetTextExtentPoint32W(hDC, szText, nSelFrom, &sz); + x += sz.cx; + GetTextExtentPoint32W(hDC, szText+nSelFrom, nSelTo-nSelFrom, &sz); + PatBlt(hDC, x, ymin, sz.cx, cy, DSTINVERT); + } + SetTextColor(hDC, rgbOld); + ME_UnselectStyleFont(c->editor, hDC, s, hOldFont); +} + +void ME_DebugWrite(HDC hDC, POINT *pt, WCHAR *szText) { + int align = SetTextAlign(hDC, TA_LEFT|TA_TOP); + HGDIOBJ hFont = SelectObject(hDC, GetStockObject(DEFAULT_GUI_FONT)); + COLORREF color = SetTextColor(hDC, RGB(128,128,128)); + TextOutW(hDC, pt->x, pt->y, szText, lstrlenW(szText)); + SelectObject(hDC, hFont); + SetTextAlign(hDC, align); + SetTextColor(hDC, color); +} + +void ME_DrawGraphics(ME_Context *c, int x, int y, ME_Run *run, + ME_Paragraph *para, BOOL selected) { + SIZE sz; + int xs, ys, xe, ye, h, ym, width, eyes; + ME_GetGraphicsSize(c->editor, run, &sz); + xs = run->pt.x; + ys = y-sz.cy; + xe = xs+sz.cx; + ye = y; + h = ye-ys; + ym = ys+h/4; + width = sz.cx; + eyes = width/8; + /* draw a smiling face :) */ + Ellipse(c->hDC, xs, ys, xe, ye); + Ellipse(c->hDC, xs+width/8, ym, x+width/8+eyes, ym+eyes); + Ellipse(c->hDC, xs+7*width/8-eyes, ym, xs+7*width/8, ym+eyes); + MoveToEx(c->hDC, xs+width/8, ys+3*h/4-eyes, NULL); + LineTo(c->hDC, xs+width/8, ys+3*h/4); + LineTo(c->hDC, xs+7*width/8, ys+3*h/4); + LineTo(c->hDC, xs+7*width/8, ys+3*h/4-eyes); + if (selected) + { + /* descent is usually (always?) 0 for graphics */ + PatBlt(c->hDC, x, y-run->nAscent, sz.cx, run->nAscent+run->nDescent, DSTINVERT); + } +} + +void ME_DrawRun(ME_Context *c, int x, int y, ME_DisplayItem *rundi, ME_Paragraph *para) { + ME_Run *run = &rundi->member.run; + int runofs = run->nCharOfs+para->nCharOfs; + + if (run->nFlags & MERF_GRAPHICS) { + int blfrom, blto; + ME_GetSelection(c->editor, &blfrom, &blto); + ME_DrawGraphics(c, x, y, run, para, (runofs >= blfrom) && (runofs < blto)); + } else + { + int blfrom, blto; + ME_DisplayItem *start = ME_FindItemBack(rundi, diStartRow); + ME_GetSelection(c->editor, &blfrom, &blto); + + ME_DrawTextWithStyle(c, x, y, + run->strText->szData, ME_StrVLen(run->strText), run->style, NULL, + blfrom-runofs, blto-runofs, c->pt.y+start->member.row.nYPos, start->member.row.nHeight); + } +} + +COLORREF ME_GetBackColor(ME_TextEditor *editor) +{ +/* Looks like I was seriously confused + return GetSysColor((GetWindowLong(editor->hWnd, GWL_STYLE) & ES_READONLY) ? COLOR_3DFACE: COLOR_WINDOW); +*/ + if (editor->rgbBackColor == -1) + return GetSysColor(COLOR_WINDOW); + else + return editor->rgbBackColor; +} + +void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) { + int align = SetTextAlign(c->hDC, TA_BASELINE); + ME_DisplayItem *p; + ME_Run *run; + ME_Paragraph *para = NULL; + RECT rc, rcPara; + int y = c->pt.y; + int height = 0, baseline = 0, no=0, pno = 0; + int xs, xe; + int visible = 0; + int nMargWidth = 0; + + c->pt.x = c->rcView.left; + rcPara.left = c->rcView.left; + rcPara.right = c->rcView.right; + for (p = paragraph; p!=paragraph->member.para.next_para; p = p->next) { + switch(p->type) { + case diParagraph: + para = &p->member.para; + break; + case diStartRow: + assert(para); + nMargWidth = (pno==0?para->nFirstMargin:para->nLeftMargin); + xs = c->rcView.left+nMargWidth; + xe = c->rcView.right-para->nRightMargin; + y += height; + rcPara.top = y; + rcPara.bottom = y+p->member.row.nHeight; + visible = RectVisible(c->hDC, &rcPara); + if (visible) { + HBRUSH hbr; + /* 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); + /* right margin */ + rc.left = xe; + rc.right = c->rcView.right; + FillRect(c->hDC, &rc, c->hbrMargin); + rc.left = c->rcView.left+para->nLeftMargin; + rc.right = xe; + hbr = CreateSolidBrush(ME_GetBackColor(c->editor)); + FillRect(c->hDC, &rc, hbr); + DeleteObject(hbr); + } + if (me_debug) + { + const WCHAR wszRowDebug[] = {'r','o','w','[','%','d',']',0}; + WCHAR buf[128]; + POINT pt = c->pt; + wsprintfW(buf, wszRowDebug, no); + pt.y = 12+y; + ME_DebugWrite(c->hDC, &pt, buf); + } + + height = p->member.row.nHeight; + baseline = p->member.row.nBaseline; + pno++; + break; + case diRun: + assert(para); + run = &p->member.run; + if (visible && me_debug) { + rc.left = c->rcView.left+run->pt.x; + rc.right = c->rcView.left+run->pt.x+run->nWidth; + rc.top = c->pt.y+run->pt.y; + rc.bottom = c->pt.y+run->pt.y+height; + TRACE("rc = (%ld, %ld, %ld, %ld)\n", rc.left, rc.top, rc.right, rc.bottom); + if (run->nFlags & MERF_SKIPPED) + DrawFocusRect(c->hDC, &rc); + else + FrameRect(c->hDC, &rc, GetSysColorBrush(COLOR_GRAYTEXT)); + } + if (visible) + ME_DrawRun(c, run->pt.x, c->pt.y+run->pt.y+baseline, p, ¶graph->member.para); + if (me_debug) + { + /* I'm using %ls, hope wsprintfW is not going to use wrong (4-byte) WCHAR version */ + const WCHAR wszRunDebug[] = {'[','%','d',':','%','x',']',' ','%','l','s',0}; + WCHAR buf[2560]; + POINT pt; + pt.x = run->pt.x; + pt.y = c->pt.y + run->pt.y; + wsprintfW(buf, wszRunDebug, no, p->member.run.nFlags, p->member.run.strText->szData); + ME_DebugWrite(c->hDC, &pt, buf); + } + /* c->pt.x += p->member.run.nWidth; */ + break; + default: + break; + } + no++; + } + SetTextAlign(c->hDC, align); +} + +void ME_UpdateScrollBar(ME_TextEditor *editor, int ypos) +{ + 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) + { + TRACE("ScrollWindow(%d, %d, %d, %0.4f)\n", si.nPos, si.nMax, ypos, perc); + ScrollWindow(hWnd, 0, si.nPos - ypos, NULL, NULL); + UpdateWindow(hWnd); + } +} + +int ME_GetScrollPos(ME_TextEditor *editor) +{ + return GetScrollPos(editor->hWnd, SB_VERT); +} + +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; + + 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); + } +} diff --git a/reactos/lib/riched20/para.c b/reactos/lib/riched20/para.c new file mode 100644 index 00000000000..ecd8e49e58b --- /dev/null +++ b/reactos/lib/riched20/para.c @@ -0,0 +1,358 @@ +/* + * RichEdit - functions working on paragraphs of text (diParagraph). + * + * Copyright 2004 by Krzysztof Foltman + * + * 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" + +WINE_DEFAULT_DEBUG_CHANNEL(richedit); + +static WCHAR wszParagraphSign[] = {0xB6, 0}; + +void ME_MakeFirstParagraph(HDC hDC, ME_TextBuffer *text) +{ + PARAFORMAT2 fmt; + CHARFORMAT2W cf; + LOGFONTW lf; + HFONT hf; + ME_DisplayItem *para = ME_MakeDI(diParagraph); + ME_DisplayItem *run; + ME_Style *style; + + hf = (HFONT)GetStockObject(SYSTEM_FONT); + assert(hf); + GetObjectW(hf, sizeof(LOGFONTW), &lf); + ZeroMemory(&cf, sizeof(cf)); + cf.cbSize = sizeof(cf); + cf.dwMask = CFM_BACKCOLOR|CFM_COLOR|CFM_FACE|CFM_SIZE|CFM_CHARSET; + cf.dwMask |= CFM_ALLCAPS|CFM_BOLD|CFM_DISABLED|CFM_EMBOSS|CFM_HIDDEN; + cf.dwMask |= CFM_IMPRINT|CFM_ITALIC|CFM_LINK|CFM_OUTLINE|CFM_PROTECTED; + cf.dwMask |= CFM_REVISED|CFM_SHADOW|CFM_SMALLCAPS|CFM_STRIKEOUT; + cf.dwMask |= CFM_SUBSCRIPT|CFM_UNDERLINE; + + cf.dwEffects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR; + lstrcpyW(cf.szFaceName, lf.lfFaceName); + cf.yHeight=lf.lfHeight*1440/GetDeviceCaps(hDC, LOGPIXELSY); + if (lf.lfWeight>=700) /* FIXME correct weight ? */ + cf.dwEffects |= CFE_BOLD; + cf.wWeight = lf.lfWeight; + if (lf.lfItalic) cf.dwEffects |= CFE_ITALIC; + if (lf.lfUnderline) cf.dwEffects |= CFE_UNDERLINE; + if (lf.lfStrikeOut) cf.dwEffects |= CFE_STRIKEOUT; + + ZeroMemory(&fmt, sizeof(fmt)); + fmt.cbSize = sizeof(fmt); + fmt.dwMask = PFM_ALIGNMENT | PFM_OFFSET | PFM_STARTINDENT | PFM_RIGHTINDENT; + + CopyMemory(para->member.para.pFmt, &fmt, sizeof(PARAFORMAT2)); + + style = ME_MakeStyle(&cf); + text->pDefaultStyle = style; + + run = ME_MakeRun(style, ME_MakeString(wszParagraphSign), MERF_ENDPARA); + run->member.run.nCharOfs = 0; + + ME_InsertBefore(text->pLast, para); + ME_InsertBefore(text->pLast, run); + para->member.para.prev_para = text->pFirst; + para->member.para.next_para = text->pLast; + text->pFirst->member.para.next_para = para; + text->pLast->member.para.prev_para = para; + + text->pLast->member.para.nCharOfs = 1; +} + +void ME_MarkAllForWrapping(ME_TextEditor *editor) +{ + ME_MarkForWrapping(editor, editor->pBuffer->pFirst->member.para.next_para, editor->pBuffer->pLast); +} + +void ME_MarkForWrapping(ME_TextEditor *editor, ME_DisplayItem *first, ME_DisplayItem *last) +{ + while(first != last) + { + first->member.para.nFlags |= MEPF_REWRAP; + first = first->member.para.next_para; + } +} + +/* split paragraph at the beginning of the run */ +ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, ME_Style *style) +{ + ME_DisplayItem *next_para = NULL; + ME_DisplayItem *run_para = NULL; + ME_DisplayItem *new_para = ME_MakeDI(diParagraph); + ME_DisplayItem *end_run = ME_MakeRun(style,ME_MakeString(wszParagraphSign), MERF_ENDPARA); + ME_UndoItem *undo = NULL; + int ofs; + ME_DisplayItem *pp; + + assert(run->type == diRun); + + run_para = ME_GetParagraph(run); + assert(run_para->member.para.pFmt->cbSize == sizeof(PARAFORMAT2)); + + ofs = end_run->member.run.nCharOfs = run->member.run.nCharOfs; + next_para = run_para->member.para.next_para; + assert(next_para == ME_FindItemFwd(run_para, diParagraphOrEnd)); + + undo = ME_AddUndoItem(editor, diUndoJoinParagraphs, NULL); + if (undo) + undo->nStart = run_para->member.para.nCharOfs + ofs; + + /* the new paragraph will have a different starting offset, so let's update its runs */ + pp = run; + while(pp->type == diRun) { + pp->member.run.nCharOfs -= ofs; + pp = ME_FindItemFwd(pp, diRunOrParagraphOrEnd); + } + new_para->member.para.nCharOfs = ME_GetParagraph(run)->member.para.nCharOfs+ofs; + new_para->member.para.nCharOfs += 1; + + new_para->member.para.nFlags = MEPF_REWRAP; /* FIXME copy flags (if applicable) */ + /* FIXME initialize format style and call ME_SetParaFormat blah blah */ + CopyMemory(new_para->member.para.pFmt, run_para->member.para.pFmt, sizeof(PARAFORMAT2)); + + /* FIXME remove this as soon as nLeftMargin etc are replaced with proper fields of PARAFORMAT2 */ + new_para->member.para.nLeftMargin = run_para->member.para.nLeftMargin; + new_para->member.para.nRightMargin = run_para->member.para.nRightMargin; + new_para->member.para.nFirstMargin = run_para->member.para.nFirstMargin; + + /* insert paragraph into paragraph double linked list */ + new_para->member.para.prev_para = run_para; + new_para->member.para.next_para = next_para; + run_para->member.para.next_para = new_para; + next_para->member.para.prev_para = new_para; + + /* insert end run of the old paragraph, and new paragraph, into DI double linked list */ + ME_InsertBefore(run, new_para); + ME_InsertBefore(new_para, end_run); + + /* force rewrap of the */ + run_para->member.para.prev_para->member.para.nFlags |= MEPF_REWRAP; + new_para->member.para.prev_para->member.para.nFlags |= MEPF_REWRAP; + + /* we've added the end run, so we need to modify nCharOfs in the next paragraphs */ + ME_PropagateCharOffset(next_para, 1); + editor->nParagraphs++; + + return new_para; +} + +/* join tp with tp->member.para.next_para, keeping tp's style; this + * is consistent with the original */ +ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp) +{ + ME_DisplayItem *pNext, *pFirstRunInNext, *pRun, *pTmp; + int i, shift; + ME_UndoItem *undo = NULL; + + assert(tp->type == diParagraph); + assert(tp->member.para.next_para); + assert(tp->member.para.next_para->type == diParagraph); + + pNext = tp->member.para.next_para; + + { + /* null char format operation to store the original char format for the ENDPARA run */ + CHARFORMAT2W fmt; + ME_InitCharFormat2W(&fmt); + ME_SetCharFormat(editor, pNext->member.para.nCharOfs-1, 1, &fmt); + } + undo = ME_AddUndoItem(editor, diUndoSplitParagraph, NULL); + if (undo) + { + undo->nStart = pNext->member.para.nCharOfs-1; + assert(pNext->member.para.pFmt->cbSize == sizeof(PARAFORMAT2)); + CopyMemory(undo->di.member.para.pFmt, pNext->member.para.pFmt, sizeof(PARAFORMAT2)); + } + + shift = pNext->member.para.nCharOfs - tp->member.para.nCharOfs - 1; + + pRun = ME_FindItemBack(pNext, diRunOrParagraph); + pFirstRunInNext = ME_FindItemFwd(pNext, diRunOrParagraph); + + assert(pRun); + assert(pRun->type == diRun); + assert(pRun->member.run.nFlags & MERF_ENDPARA); + assert(pFirstRunInNext->type == diRun); + + /* if some cursor points at end of paragraph, make it point to the first + run of the next joined paragraph */ + for (i=0; inCursors; i++) { + if (editor->pCursors[i].pRun == pRun) { + editor->pCursors[i].pRun = pFirstRunInNext; + editor->pCursors[i].nOffset = 0; + } + } + + pTmp = pNext; + do { + pTmp = ME_FindItemFwd(pTmp, diRunOrParagraphOrEnd); + if (pTmp->type != diRun) + break; + TRACE("shifting \"%s\" by %d (previous %d)\n", debugstr_w(pTmp->member.run.strText->szData), shift, pTmp->member.run.nCharOfs); + pTmp->member.run.nCharOfs += shift; + } while(1); + + ME_Remove(pRun); + ME_DestroyDisplayItem(pRun); + + tp->member.para.next_para = pNext->member.para.next_para; + pNext->member.para.next_para->member.para.prev_para = tp; + ME_Remove(pNext); + ME_DestroyDisplayItem(pNext); + + ME_PropagateCharOffset(tp->member.para.next_para, -1); + + ME_CheckCharOffsets(editor); + + editor->nParagraphs--; + tp->member.para.nFlags |= MEPF_REWRAP; + return tp; +} + +ME_DisplayItem *ME_GetParagraph(ME_DisplayItem *item) { + return ME_FindItemBackOrHere(item, diParagraph); +} + +static void ME_DumpStyleEffect(char **p, const char *name, PARAFORMAT2 *fmt, int mask) +{ + *p += sprintf(*p, "%-22s%s\n", name, (fmt->dwMask & mask) ? ((fmt->wEffects & mask) ? "yes" : "no") : "N/A"); +} + +void ME_DumpParaStyleToBuf(PARAFORMAT2 *pFmt, char buf[2048]) +{ + /* FIXME only PARAFORMAT styles implemented */ + char *p; + p = buf; + p += sprintf(p, "Alignment: %s\n", + !(pFmt->dwMask & PFM_ALIGNMENT) ? "N/A" : + ((pFmt->wAlignment == PFA_LEFT) ? "left" : + ((pFmt->wAlignment == PFA_RIGHT) ? "right" : + ((pFmt->wAlignment == PFA_CENTER) ? "center" : + /*((pFmt->wAlignment == PFA_JUSTIFY) ? "justify" : "incorrect")*/ + "incorrect")))); + + if (pFmt->dwMask & PFM_OFFSET) + p += sprintf(p, "Offset: %d\n", (int)pFmt->dxOffset); + else + p += sprintf(p, "Offset: N/A\n"); + + if (pFmt->dwMask & PFM_OFFSETINDENT) + p += sprintf(p, "Offset indent: %d\n", (int)pFmt->dxStartIndent); + else + p += sprintf(p, "Offset indent: N/A\n"); + + if (pFmt->dwMask & PFM_STARTINDENT) + p += sprintf(p, "Start indent: %d\n", (int)pFmt->dxStartIndent); + else + p += sprintf(p, "Start indent: N/A\n"); + + if (pFmt->dwMask & PFM_RIGHTINDENT) + p += sprintf(p, "Right indent: %d\n", (int)pFmt->dxRightIndent); + else + p += sprintf(p, "Right indent: N/A\n"); + + ME_DumpStyleEffect(&p, "Page break before:", pFmt, PFM_PAGEBREAKBEFORE); +} + +void ME_SetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, PARAFORMAT2 *pFmt) +{ + PARAFORMAT2 copy; + assert(sizeof(*para->member.para.pFmt) == sizeof(PARAFORMAT2)); + ME_AddUndoItem(editor, diUndoSetParagraphFormat, para); + + CopyMemory(©, para->member.para.pFmt, sizeof(PARAFORMAT2)); + + if (pFmt->dwMask & PFM_ALIGNMENT) + para->member.para.pFmt->wAlignment = pFmt->wAlignment; + + /* FIXME to be continued (indents, bulleting and such) */ + + if (memcmp(©, para->member.para.pFmt, sizeof(PARAFORMAT2))) + para->member.para.nFlags |= MEPF_REWRAP; +} + +void ME_SetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt) +{ + int nFrom, nTo; + ME_DisplayItem *para, *para_end, *run; + int nOffset; + + ME_GetSelection(editor, &nFrom, &nTo); + if (nTo>nFrom) /* selection consists of chars from nFrom up to nTo-1 */ + nTo--; + + ME_RunOfsFromCharOfs(editor, nFrom, &run, &nOffset); + para = ME_GetParagraph(run); + ME_RunOfsFromCharOfs(editor, nTo, &run, &nOffset); + para_end = ME_GetParagraph(run); + + do { + ME_SetParaFormat(editor, para, pFmt); + if (para == para_end) + break; + para = para->member.para.next_para; + } while(1); + ME_Repaint(editor); +} + +void ME_GetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, PARAFORMAT2 *pFmt) +{ + if (pFmt->cbSize >= sizeof(PARAFORMAT2)) + { + CopyMemory(pFmt, para->member.para.pFmt, sizeof(PARAFORMAT2)); + return; + } + CopyMemory(pFmt, para->member.para.pFmt, pFmt->cbSize); +} + +void ME_GetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt) +{ + int nFrom, nTo; + ME_DisplayItem *para, *para_end, *run; + int nOffset; + PARAFORMAT2 tmp; + + ME_GetSelection(editor, &nFrom, &nTo); + if (nTo>nFrom) /* selection consists of chars from nFrom up to nTo-1 */ + nTo--; + + ME_RunOfsFromCharOfs(editor, nFrom, &run, &nOffset); + para = ME_GetParagraph(run); + ME_RunOfsFromCharOfs(editor, nTo, &run, &nOffset); + para_end = ME_GetParagraph(run); + + ME_GetParaFormat(editor, para, pFmt); + if (para == para_end) return; + + do { + ZeroMemory(&tmp, sizeof(tmp)); + tmp.cbSize = sizeof(tmp); + ME_GetParaFormat(editor, para, &tmp); + assert(tmp.dwMask & PFM_ALIGNMENT); + + if (pFmt->wAlignment != tmp.wAlignment) + pFmt->dwMask &= ~PFM_ALIGNMENT; + + if (para == para_end) + return; + para = para->member.para.next_para; + } while(1); +} diff --git a/reactos/lib/riched20/reader.c b/reactos/lib/riched20/reader.c new file mode 100644 index 00000000000..3f800b658de --- /dev/null +++ b/reactos/lib/riched20/reader.c @@ -0,0 +1,3786 @@ +/* + * WINE RTF file reader + * + * Portions Copyright 2004 Mike McCormack for CodeWeavers + * + * 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 + */ + +/* + * Derived from RTF Tools by Paul DuBois (dubois@primate.wisc.edu) + * Homepage: http://www.snake.net/software/RTF/ + * Original license follows: + */ + +/* + * reader.c - RTF file reader. Release 1.10. + * + * .... + * + * Author: Paul DuBois dubois@primate.wisc.edu + * + * This software may be redistributed without restriction and used for + * any purpose whatsoever. + */ + +#include +#include +#include +#include +#include + +#include "rtf.h" + +#include "windef.h" +#include "winbase.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(richedit); + +extern HANDLE me_heap; + +static int _RTFGetChar(RTF_Info *); +static void _RTFGetToken (RTF_Info *); +static void _RTFGetToken2 (RTF_Info *); +static int GetChar (RTF_Info *); +static void ReadFontTbl (RTF_Info *); +static void ReadColorTbl (RTF_Info *); +static void ReadStyleSheet (RTF_Info *); +static void ReadInfoGroup (RTF_Info *); +static void ReadPictGroup (RTF_Info *); +static void ReadObjGroup (RTF_Info *); +static void LookupInit (void); +static void Lookup (RTF_Info *, char *); +static int Hash (char*); + +static void CharSetInit (RTF_Info *); +static void ReadCharSetMaps (RTF_Info *); + + +/* + 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. + * + */ + +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 + */ + +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. + */ + +const char *stdCharName[] = +{ + "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 +}; + +int _RTFGetChar(RTF_Info *info) +{ + int ch; + + 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) + { + 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) + return EOF; + info->dwInputSize = count; + info->dwInputUsed = 0; + } + ch = info->InputBuffer[info->dwInputUsed++]; + if (!ch) + return EOF; + return ch; +} + +void RTFSetEditStream(RTF_Info *info, EDITSTREAM *es) +{ + TRACE("\n"); + + info->editstream.dwCookie = es->dwCookie; + info->editstream.dwError = es->dwError; + info->editstream.pfnCallback = es->pfnCallback; +} + +/* + * Initialize the reader. This may be called multiple times, + * to read multiple files. The only thing not reset is the input + * stream; that must be done with RTFSetStream(). + */ + +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 */ + { + info->rtfTextBuf = RTFAlloc (rtfBufSiz); + info->pushedTextBuf = RTFAlloc (rtfBufSiz); + if (info->rtfTextBuf == (char *) NULL + || info->pushedTextBuf == (char *) 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; + + /* initialize lookup table */ + LookupInit (); + + for (i = 0; i < rtfMaxClass; i++) + RTFSetClassCallback (info, i, (RTFFuncPtr) NULL); + for (i = 0; i < rtfMaxDestination; i++) + RTFSetDestinationCallback (info, i, (RTFFuncPtr) NULL); + + /* install built-in destination readers */ + RTFSetDestinationCallback (info, rtfFontTbl, ReadFontTbl); + RTFSetDestinationCallback (info, rtfColorTbl, ReadColorTbl); + RTFSetDestinationCallback (info, rtfStyleSheet, ReadStyleSheet); + RTFSetDestinationCallback (info, rtfInfo, ReadInfoGroup); + RTFSetDestinationCallback (info, rtfPict, ReadPictGroup); + RTFSetDestinationCallback (info, rtfObject, ReadObjGroup); + + + RTFSetReadHook (info, (RTFFuncPtr) 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; + } + + info->rtfClass = -1; + info->pushedClass = -1; + info->pushedChar = EOF; + + info->rtfLineNum = 0; + info->rtfLinePos = 0; + info->prevChar = EOF; + info->bumpLine = 0; + + CharSetInit (info); + info->csTop = 0; +} + +/* + * Set or get the input or output file name. These are never guaranteed + * to be accurate, only insofar as the calling program makes them so. + */ + +void RTFSetInputName(RTF_Info *info, char *name) +{ + TRACE("\n"); + + if ((info->inputName = RTFStrSave (name)) == (char *) NULL) + RTFPanic (info,"RTFSetInputName: out of memory"); +} + + +char *RTFGetInputName(RTF_Info *info) +{ + return (info->inputName); +} + + +void RTFSetOutputName(RTF_Info *info, char *name) +{ + TRACE("\n"); + + if ((info->outputName = RTFStrSave (name)) == (char *) NULL) + RTFPanic (info, "RTFSetOutputName: out of memory"); +} + + +char *RTFGetOutputName(RTF_Info *info) +{ + return (info->outputName); +} + + + +/* ---------------------------------------------------------------------- */ + +/* + * Callback table manipulation routines + */ + + +/* + * Install or return a writer callback for a token class + */ + +void RTFSetClassCallback(RTF_Info *info, int class, RTFFuncPtr callback) +{ + if (class >= 0 && class < rtfMaxClass) + info->ccb[class] = callback; +} + + +RTFFuncPtr RTFGetClassCallback(RTF_Info *info, int class) +{ + if (class >= 0 && class < rtfMaxClass) + return (info->ccb[class]); + return ((RTFFuncPtr) NULL); +} + + +/* + * Install or return a writer callback for a destination type + */ + +void RTFSetDestinationCallback(RTF_Info *info, int dest, RTFFuncPtr callback) +{ + if (dest >= 0 && dest < rtfMaxDestination) + info->dcb[dest] = callback; +} + + +RTFFuncPtr RTFGetDestinationCallback(RTF_Info *info, int dest) +{ + if (dest >= 0 && dest < rtfMaxDestination) + return (info->dcb[dest]); + return ((RTFFuncPtr) NULL); +} + + +/* ---------------------------------------------------------------------- */ + +/* + * Token reading routines + */ + + +/* + * Read the input stream, invoking the writer's callbacks + * where appropriate. + */ + +void RTFRead(RTF_Info *info) +{ + while (RTFGetToken (info) != rtfEOF) + RTFRouteToken (info); +} + + +/* + * Route a token. If it's a destination for which a reader is + * installed, process the destination internally, otherwise + * pass the token to the writer's class callback. + */ + +void RTFRouteToken(RTF_Info *info) +{ + RTFFuncPtr p; + + TRACE("\n"); + + if (info->rtfClass < 0 || info->rtfClass >= rtfMaxClass) /* watchdog */ + { + RTFPanic (info,"Unknown class %d: %s (reader malfunction)", + info->rtfClass, info->rtfTextBuf); + } + if (RTFCheckCM (info, rtfControl, rtfDestination)) + { + /* invoke destination-specific callback if there is one */ + if ((p = RTFGetDestinationCallback (info, info->rtfMinor)) + != (RTFFuncPtr) NULL) + { + (*p) (info); + return; + } + } + /* invoke class callback if there is one */ + if ((p = RTFGetClassCallback (info, info->rtfClass)) != (RTFFuncPtr) NULL) + (*p) (info); +} + + +/* + * Skip to the end of the current group. When this returns, + * writers that maintain a state stack may want to call their + * state unstacker; global vars will still be set to the group's + * closing brace. + */ + +void RTFSkipGroup(RTF_Info *info) +{ + int level = 1; + + TRACE("\n"); + + while (RTFGetToken (info) != rtfEOF) + { + if (info->rtfClass == rtfGroup) + { + if (info->rtfMajor == rtfBeginGroup) + ++level; + else if (info->rtfMajor == rtfEndGroup) + { + if (--level < 1) + break; /* end of initial group */ + } + } + } +} + + +/* + * Read one token. Call the read hook if there is one. The + * token class is the return value. Returns rtfEOF when there + * are no more tokens. + */ + +int RTFGetToken(RTF_Info *info) +{ + RTFFuncPtr p; + + TRACE("\n"); + + for (;;) + { + _RTFGetToken (info); + if ((p = RTFGetReadHook (info)) != (RTFFuncPtr) NULL) + (*p) (info); /* give read hook a look at token */ + + /* Silently discard newlines, carriage returns, nulls. */ + if (!(info->rtfClass == rtfText && info->rtfFormat != SF_TEXT + && (info->rtfMajor == '\r' || info->rtfMajor == '\n' || info->rtfMajor == '\0'))) + break; + } + return (info->rtfClass); +} + + +/* + * Install or return a token reader hook. + */ + +void RTFSetReadHook(RTF_Info *info, RTFFuncPtr f) +{ + info->readHook = f; +} + + +RTFFuncPtr RTFGetReadHook(RTF_Info *info) +{ + return (info->readHook); +} + + +void RTFUngetToken(RTF_Info *info) +{ + TRACE("\n"); + + if (info->pushedClass >= 0) /* there's already an ungotten token */ + RTFPanic (info,"cannot unget two tokens"); + if (info->rtfClass < 0) + RTFPanic (info,"no token to unget"); + info->pushedClass = info->rtfClass; + info->pushedMajor = info->rtfMajor; + info->pushedMinor = info->rtfMinor; + info->pushedParam = info->rtfParam; + (void) strcpy (info->pushedTextBuf, info->rtfTextBuf); +} + + +int RTFPeekToken(RTF_Info *info) +{ + _RTFGetToken (info); + RTFUngetToken (info); + return (info->rtfClass); +} + + +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; + } + + /* first check for pushed token from RTFUngetToken() */ + + if (info->pushedClass >= 0) + { + info->rtfClass = info->pushedClass; + info->rtfMajor = info->pushedMajor; + info->rtfMinor = info->pushedMinor; + info->rtfParam = info->pushedParam; + (void) strcpy (info->rtfTextBuf, info->pushedTextBuf); + info->rtfTextLen = strlen (info->rtfTextBuf); + info->pushedClass = -1; + return; + } + + /* + * Beyond this point, no token is ever seen twice, which is + * important, e.g., for making sure no "}" pops the font stack twice. + */ + + _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) + { + if (strncmp (fp->rtfFName, "Symbol", 6) == 0) + info->curCharSet = rtfCSSymbol; + 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; + } + } +} + + +/* this shouldn't be called anywhere but from _RTFGetToken() */ + +static void _RTFGetToken2(RTF_Info *info) +{ + int sign; + int c; + + TRACE("\n"); + + /* initialize token vars */ + + info->rtfClass = rtfUnknown; + info->rtfParam = rtfNoParam; + info->rtfTextBuf[info->rtfTextLen = 0] = '\0'; + + /* get first character, which may be a pushback from previous token */ + + if (info->pushedChar != EOF) + { + c = info->pushedChar; + info->rtfTextBuf[info->rtfTextLen++] = c; + info->rtfTextBuf[info->rtfTextLen] = '\0'; + info->pushedChar = EOF; + } + else if ((c = GetChar (info)) == EOF) + { + info->rtfClass = rtfEOF; + return; + } + + if (c == '{') + { + info->rtfClass = rtfGroup; + info->rtfMajor = rtfBeginGroup; + return; + } + if (c == '}') + { + info->rtfClass = rtfGroup; + info->rtfMajor = rtfEndGroup; + return; + } + if (c != '\\') + { + /* + * Two possibilities here: + * 1) ASCII 9, effectively like \tab control symbol + * 2) literal text char + */ + if (c == '\t') /* ASCII 9 */ + { + info->rtfClass = rtfControl; + info->rtfMajor = rtfSpecialChar; + info->rtfMinor = rtfTab; + } + else + { + info->rtfClass = rtfText; + info->rtfMajor = c; + } + return; + } + if ((c = GetChar (info)) == EOF) + { + /* early eof, whoops (class is rtfUnknown) */ + return; + } + if (!isalpha (c)) + { + /* + * Three possibilities here: + * 1) hex encoded text char, e.g., \'d5, \'d3 + * 2) special escaped text char, e.g., \{, \} + * 3) control symbol, e.g., \_, \-, \|, \<10> + */ + if (c == '\'') /* hex char */ + { + int c2; + + if ((c = GetChar (info)) != EOF && (c2 = GetChar (info)) != EOF) + { + /* should do isxdigit check! */ + info->rtfClass = rtfText; + info->rtfMajor = RTFCharToHex (c) * 16 + + RTFCharToHex (c2); + return; + } + /* early eof, whoops (class is rtfUnknown) */ + return; + } + + /* escaped char */ + /*if (index (":{}\\", c) != (char *) NULL)*/ /* escaped char */ + if (c == ':' || c == '{' || c == '}' || c == '\\') + { + info->rtfClass = rtfText; + info->rtfMajor = c; + return; + } + + /* control symbol */ + Lookup (info, info->rtfTextBuf); /* sets class, major, minor */ + return; + } + /* control word */ + while (isalpha (c)) + { + if ((c = GetChar (info)) == EOF) + break; + } + + /* + * At this point, the control word is all collected, so the + * major/minor numbers are determined before the parameter + * (if any) is scanned. There will be one too many characters + * in the buffer, though, so fix up before and restore after + * looking up. + */ + + if (c != EOF) + info->rtfTextBuf[info->rtfTextLen-1] = '\0'; + Lookup (info, info->rtfTextBuf); /* sets class, major, minor */ + if (c != EOF) + info->rtfTextBuf[info->rtfTextLen-1] = c; + + /* + * Should be looking at first digit of parameter if there + * is one, unless it's negative. In that case, next char + * is '-', so need to gobble next char, and remember sign. + */ + + sign = 1; + if (c == '-') + { + sign = -1; + c = GetChar (info); + } + if (c != EOF && isdigit (c)) + { + info->rtfParam = 0; + while (isdigit (c)) /* gobble parameter */ + { + info->rtfParam = info->rtfParam * 10 + c - '0'; + if ((c = GetChar (info)) == EOF) + break; + } + info->rtfParam *= sign; + } + /* + * If control symbol delimiter was a blank, gobble it. + * Otherwise the character is first char of next token, so + * push it back for next call. In either case, delete the + * delimiter from the token buffer. + */ + if (c != EOF) + { + if (c != ' ') + info->pushedChar = c; + info->rtfTextBuf[--info->rtfTextLen] = '\0'; + } +} + + +/* + * Read the next character from the input. This handles setting the + * current line and position-within-line variables. Those variable are + * set correctly whether lines end with CR, LF, or CRLF (the last being + * the tricky case). + * + * bumpLine indicates whether the line number should be incremented on + * the *next* input character. + */ + + +static int GetChar(RTF_Info *info) +{ + int c; + int oldBumpLine; + + TRACE("\n"); + + if ((c = _RTFGetChar(info)) != EOF) + { + info->rtfTextBuf[info->rtfTextLen++] = c; + info->rtfTextBuf[info->rtfTextLen] = '\0'; + } + if (info->prevChar == EOF) + info->bumpLine = 1; + oldBumpLine = info->bumpLine; /* non-zero if prev char was line ending */ + info->bumpLine = 0; + if (c == '\r') + info->bumpLine = 1; + else if (c == '\n') + { + info->bumpLine = 1; + if (info->prevChar == '\r') /* oops, previous \r wasn't */ + oldBumpLine = 0; /* really a line ending */ + } + ++info->rtfLinePos; + if (oldBumpLine) /* were we supposed to increment the */ + { /* line count on this char? */ + ++info->rtfLineNum; + info->rtfLinePos = 1; + } + info->prevChar = c; + return (c); +} + + +/* + * Synthesize a token by setting the global variables to the + * values supplied. Typically this is followed with a call + * to RTFRouteToken(). + * + * If a param value other than rtfNoParam is passed, it becomes + * part of the token text. + */ + +void RTFSetToken(RTF_Info *info, int class, int major, int minor, int param, const char *text) +{ + TRACE("\n"); + + info->rtfClass = class; + info->rtfMajor = major; + info->rtfMinor = minor; + info->rtfParam = param; + if (param == rtfNoParam) + (void) strcpy (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); +} + + +/* ---------------------------------------------------------------------- */ + +/* + * Special destination readers. They gobble the destination so the + * writer doesn't have to deal with them. That's wrong for any + * translator that wants to process any of these itself. In that + * case, these readers should be overridden by installing a different + * destination callback. + * + * NOTE: The last token read by each of these reader will be the + * destination's terminating '}', which will then be the current token. + * That '}' token is passed to RTFRouteToken() - the writer has already + * seen the '{' that began the destination group, and may have pushed a + * state; it also needs to know at the end of the group that a state + * should be popped. + * + * It's important that rtf.h and the control token lookup table list + * as many symbols as possible, because these destination readers + * unfortunately make strict assumptions about the input they expect, + * and a token of class rtfUnknown will throw them off easily. + */ + + +/* + * Read { \fonttbl ... } destination. Old font tables don't have + * braces around each table entry; try to adjust for that. + */ + +static void ReadFontTbl(RTF_Info *info) +{ + RTFFont *fp = NULL; + char buf[rtfBufSiz], *bp; + int old = -1; + const char *fn = "ReadFontTbl"; + + TRACE("\n"); + + for (;;) + { + (void) RTFGetToken (info); + if (RTFCheckCM (info, rtfGroup, rtfEndGroup)) + break; + if (old < 0) /* first entry - determine tbl type */ + { + if (RTFCheckCMM (info, rtfControl, rtfCharAttr, rtfFontNum)) + old = 1; /* no brace */ + else if (RTFCheckCM (info, rtfGroup, rtfBeginGroup)) + old = 0; /* brace */ + else /* can't tell! */ + RTFPanic (info, "%s: Cannot determine format", fn); + } + if (old == 0) /* need to find "{" here */ + { + if (!RTFCheckCM (info, rtfGroup, rtfBeginGroup)) + RTFPanic (info, "%s: missing \"{\"", fn); + (void) RTFGetToken (info); /* yes, skip to next token */ + } + if ((fp = New (RTFFont)) == (RTFFont *) 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->rtfFNum = -1; + fp->rtfFFamily = 0; + fp->rtfFCharSet = 0; + fp->rtfFPitch = 0; + fp->rtfFType = 0; + fp->rtfFCodePage = 0; + + while (info->rtfClass != rtfEOF + && !RTFCheckCM (info, rtfText, ';') + && !RTFCheckCM (info, rtfGroup, rtfEndGroup)) + { + if (info->rtfClass == rtfControl) + { + switch (info->rtfMajor) + { + default: + /* ignore token but announce it */ + RTFMsg (info,"%s: unknown token \"%s\"\n", + fn, info->rtfTextBuf); + break; + case rtfFontFamily: + fp->rtfFFamily = info->rtfMinor; + break; + case rtfCharAttr: + switch (info->rtfMinor) + { + default: + break; /* ignore unknown? */ + case rtfFontNum: + fp->rtfFNum = info->rtfParam; + break; + } + break; + case rtfFontAttr: + switch (info->rtfMinor) + { + default: + break; /* ignore unknown? */ + case rtfFontCharSet: + fp->rtfFCharSet = info->rtfParam; + break; + case rtfFontPitch: + fp->rtfFPitch = info->rtfParam; + break; + case rtfFontCodePage: + fp->rtfFCodePage = info->rtfParam; + break; + case rtfFTypeNil: + case rtfFTypeTrueType: + fp->rtfFType = info->rtfParam; + break; + } + break; + } + } + else if (RTFCheckCM (info, rtfGroup, rtfBeginGroup)) /* dest */ + { + RTFSkipGroup (info); /* ignore for now */ + } + else if (info->rtfClass == rtfText) /* font name */ + { + bp = buf; + while (info->rtfClass == rtfText + && !RTFCheckCM (info, rtfText, ';')) + { + *bp++ = info->rtfMajor; + (void) RTFGetToken (info); + } + + /* FIX: in some cases the isn't finished with a semi-column */ + if(RTFCheckCM (info, rtfGroup, rtfEndGroup)) + { + RTFUngetToken (info); + } + *bp = '\0'; + fp->rtfFName = RTFStrSave (buf); + if (fp->rtfFName == (char *) NULL) + RTFPanic (info, "%s: cannot allocate font name", fn); + /* already have next token; don't read one */ + /* at bottom of loop */ + continue; + } + else + { + /* ignore token but announce it */ + RTFMsg (info, "%s: unknown token \"%s\"\n", + fn,info->rtfTextBuf); + } + (void) RTFGetToken (info); + } + if (old == 0) /* need to see "}" here */ + { + (void) RTFGetToken (info); + if (!RTFCheckCM (info, rtfGroup, rtfEndGroup)) + RTFPanic (info, "%s: missing \"}\"", fn); + } + } + if (fp->rtfFNum == -1) + RTFPanic (info,"%s: missing font number", fn); +/* + * Could check other pieces of structure here, too, I suppose. + */ + RTFRouteToken (info); /* feed "}" back to router */ +} + + +/* + * The color table entries have color values of -1 if + * the default color should be used for the entry (only + * a semi-colon is given in the definition, no color values). + * There will be a problem if a partial entry (1 or 2 but + * not 3 color values) is given. The possibility is ignored + * here. + */ + +static void ReadColorTbl(RTF_Info *info) +{ + RTFColor *cp; + int cnum = 0; + const char *fn = "ReadColorTbl"; + + TRACE("\n"); + + for (;;) + { + (void) RTFGetToken (info); + if (RTFCheckCM (info, rtfGroup, rtfEndGroup)) + break; + if ((cp = New (RTFColor)) == (RTFColor *) NULL) + RTFPanic (info,"%s: cannot allocate color entry", fn); + cp->rtfCNum = cnum++; + cp->rtfCRed = cp->rtfCGreen = cp->rtfCBlue = -1; + cp->rtfNextColor = info->colorList; + info->colorList = cp; + while (RTFCheckCM (info, rtfControl, rtfColorName)) + { + switch (info->rtfMinor) + { + case rtfRed: cp->rtfCRed = info->rtfParam; break; + case rtfGreen: cp->rtfCGreen = info->rtfParam; break; + case rtfBlue: cp->rtfCBlue = info->rtfParam; break; + } + RTFGetToken (info); + } + if (!RTFCheckCM (info, rtfText, (int) ';')) + RTFPanic (info,"%s: malformed entry", fn); + } + RTFRouteToken (info); /* feed "}" back to router */ +} + + +/* + * The "Normal" style definition doesn't contain any style number, + * all others do. Normal style is given style rtfNormalStyleNum. + */ + +static void ReadStyleSheet(RTF_Info *info) +{ + RTFStyle *sp; + RTFStyleElt *sep, *sepLast; + char buf[rtfBufSiz], *bp; + const char *fn = "ReadStyleSheet"; + + TRACE("\n"); + + for (;;) + { + (void) RTFGetToken (info); + if (RTFCheckCM (info, rtfGroup, rtfEndGroup)) + break; + if ((sp = New (RTFStyle)) == (RTFStyle *) NULL) + RTFPanic (info,"%s: cannot allocate stylesheet entry", fn); + sp->rtfSName = (char *) NULL; + sp->rtfSNum = -1; + sp->rtfSType = rtfParStyle; + sp->rtfSAdditive = 0; + sp->rtfSBasedOn = rtfNoStyleNum; + sp->rtfSNextPar = -1; + sp->rtfSSEList = sepLast = (RTFStyleElt *) NULL; + sp->rtfNextStyle = info->styleList; + sp->rtfExpanding = 0; + info->styleList = sp; + if (!RTFCheckCM (info, rtfGroup, rtfBeginGroup)) + RTFPanic (info,"%s: missing \"{\"", fn); + for (;;) + { + (void) RTFGetToken (info); + if (info->rtfClass == rtfEOF + || RTFCheckCM (info, rtfText, ';')) + break; + if (info->rtfClass == rtfControl) + { + if (RTFCheckMM (info, rtfSpecialChar, rtfOptDest)) + continue; /* ignore "\*" */ + if (RTFCheckMM (info, rtfParAttr, rtfStyleNum)) + { + sp->rtfSNum = info->rtfParam; + sp->rtfSType = rtfParStyle; + continue; + } + if (RTFCheckMM (info, rtfCharAttr, rtfCharStyleNum)) + { + sp->rtfSNum = info->rtfParam; + sp->rtfSType = rtfCharStyle; + continue; + } + if (RTFCheckMM (info, rtfSectAttr, rtfSectStyleNum)) + { + sp->rtfSNum = info->rtfParam; + sp->rtfSType = rtfSectStyle; + continue; + } + if (RTFCheckMM (info, rtfStyleAttr, rtfBasedOn)) + { + sp->rtfSBasedOn = info->rtfParam; + continue; + } + if (RTFCheckMM (info, rtfStyleAttr, rtfAdditive)) + { + sp->rtfSAdditive = 1; + continue; + } + if (RTFCheckMM (info, rtfStyleAttr, rtfNext)) + { + sp->rtfSNextPar = info->rtfParam; + continue; + } + if ((sep = New (RTFStyleElt)) == (RTFStyleElt *) 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) + RTFPanic (info,"%s: cannot allocate style element text", fn); + if (sepLast == (RTFStyleElt *) NULL) + sp->rtfSSEList = sep; /* first element */ + else /* add to end */ + sepLast->rtfNextSE = sep; + sep->rtfNextSE = (RTFStyleElt *) NULL; + sepLast = sep; + } + else if (RTFCheckCM (info, rtfGroup, rtfBeginGroup)) + { + /* + * This passes over "{\*\keycode ... }, among + * other things. A temporary (perhaps) hack. + */ + RTFSkipGroup (info); + continue; + } + else if (info->rtfClass == rtfText) /* style name */ + { + bp = buf; + while (info->rtfClass == rtfText) + { + if (info->rtfMajor == ';') + { + /* put back for "for" loop */ + (void) RTFUngetToken (info); + break; + } + *bp++ = info->rtfMajor; + (void) RTFGetToken (info); + } + *bp = '\0'; + if ((sp->rtfSName = RTFStrSave (buf)) == (char *) NULL) + RTFPanic (info, "%s: cannot allocate style name", fn); + } + else /* unrecognized */ + { + /* ignore token but announce it */ + RTFMsg (info, "%s: unknown token \"%s\"\n", + fn, info->rtfTextBuf); + } + } + (void) RTFGetToken (info); + if (!RTFCheckCM (info, rtfGroup, rtfEndGroup)) + RTFPanic (info, "%s: missing \"}\"", fn); + + /* + * Check over the style structure. A name is a must. + * If no style number was specified, check whether it's the + * Normal style (in which case it's given style number + * rtfNormalStyleNum). Note that some "normal" style names + * just begin with "Normal" and can have other stuff following, + * e.g., "Normal,Times 10 point". Ugh. + * + * Some German RTF writers use "Standard" instead of "Normal". + */ + if (sp->rtfSName == (char *) NULL) + RTFPanic (info,"%s: missing style name", fn); + if (sp->rtfSNum < 0) + { + if (strncmp (buf, "Normal", 6) != 0 + && strncmp (buf, "Standard", 8) != 0) + RTFPanic (info,"%s: missing style number", fn); + sp->rtfSNum = rtfNormalStyleNum; + } + if (sp->rtfSNextPar == -1) /* if \snext not given, */ + sp->rtfSNextPar = sp->rtfSNum; /* next is itself */ + } + RTFRouteToken (info); /* feed "}" back to router */ +} + + +static void ReadInfoGroup(RTF_Info *info) +{ + RTFSkipGroup (info); + RTFRouteToken (info); /* feed "}" back to router */ +} + + +static void ReadPictGroup(RTF_Info *info) +{ + RTFSkipGroup (info); + RTFRouteToken (info); /* feed "}" back to router */ +} + + +static void ReadObjGroup(RTF_Info *info) +{ + RTFSkipGroup (info); + RTFRouteToken (info); /* feed "}" back to router */ +} + + +/* ---------------------------------------------------------------------- */ + +/* + * Routines to return pieces of stylesheet, or font or color tables. + * References to style 0 are mapped onto the Normal style. + */ + + +RTFStyle *RTFGetStyle(RTF_Info *info, int num) +{ + RTFStyle *s; + + if (num == -1) + return (info->styleList); + for (s = info->styleList; s != (RTFStyle *) NULL; s = s->rtfNextStyle) + { + if (s->rtfSNum == num) + break; + } + return (s); /* NULL if not found */ +} + + +RTFFont *RTFGetFont(RTF_Info *info, int num) +{ + RTFFont *f; + + if (num == -1) + return (info->fontList); + for (f = info->fontList; f != (RTFFont *) NULL; f = f->rtfNextFont) + { + if (f->rtfFNum == num) + break; + } + return (f); /* NULL if not found */ +} + + +RTFColor *RTFGetColor(RTF_Info *info, int num) +{ + RTFColor *c; + + if (num == -1) + return (info->colorList); + for (c = info->colorList; c != (RTFColor *) NULL; c = c->rtfNextColor) + { + if (c->rtfCNum == num) + break; + } + return (c); /* NULL if not found */ +} + + +/* ---------------------------------------------------------------------- */ + + +/* + * Expand style n, if there is such a style. + */ + +void RTFExpandStyle(RTF_Info *info, int n) +{ + RTFStyle *s; + RTFStyleElt *se; + + TRACE("\n"); + + if (n == -1 || (s = RTFGetStyle (info, n)) == (RTFStyle *) NULL) + return; + if (s->rtfExpanding != 0) + RTFPanic (info,"Style expansion loop, style %d", n); + s->rtfExpanding = 1; /* set expansion flag for loop detection */ + /* + * Expand "based-on" style (unless it's the same as the current + * style -- Normal style usually gives itself as its own based-on + * style). Based-on style expansion is done by synthesizing + * the token that the writer needs to see in order to trigger + * another style expansion, and feeding to token back through + * the router so the writer sees it. + */ + if (n != s->rtfSBasedOn) + { + RTFSetToken (info, rtfControl, rtfParAttr, rtfStyleNum, + s->rtfSBasedOn, "\\s"); + RTFRouteToken (info); + } + /* + * Now route the tokens unique to this style. RTFSetToken() + * 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) + { + 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); + RTFRouteToken (info); + } + s->rtfExpanding = 0; /* done - clear expansion flag */ +} + + +/* ---------------------------------------------------------------------- */ + +/* + * Control symbol lookup routines + */ + + +typedef struct RTFKey RTFKey; + +struct RTFKey +{ + int rtfKMajor; /* major number */ + int rtfKMinor; /* minor number */ + const char *rtfKStr; /* symbol name */ + int rtfKHash; /* symbol name hash value */ +}; + +/* + * A minor number of -1 means the token has no minor number + * (all valid minor numbers are >= 0). + */ + +static RTFKey rtfKey[] = +{ + /* + * Special characters + */ + + { rtfSpecialChar, rtfIIntVersion, "vern", 0 }, + { rtfSpecialChar, rtfICreateTime, "creatim", 0 }, + { rtfSpecialChar, rtfIRevisionTime, "revtim", 0 }, + { rtfSpecialChar, rtfIPrintTime, "printim", 0 }, + { rtfSpecialChar, rtfIBackupTime, "buptim", 0 }, + { rtfSpecialChar, rtfIEditTime, "edmins", 0 }, + { rtfSpecialChar, rtfIYear, "yr", 0 }, + { rtfSpecialChar, rtfIMonth, "mo", 0 }, + { rtfSpecialChar, rtfIDay, "dy", 0 }, + { rtfSpecialChar, rtfIHour, "hr", 0 }, + { rtfSpecialChar, rtfIMinute, "min", 0 }, + { rtfSpecialChar, rtfISecond, "sec", 0 }, + { rtfSpecialChar, rtfINPages, "nofpages", 0 }, + { rtfSpecialChar, rtfINWords, "nofwords", 0 }, + { rtfSpecialChar, rtfINChars, "nofchars", 0 }, + { rtfSpecialChar, rtfIIntID, "id", 0 }, + + { rtfSpecialChar, rtfCurHeadDate, "chdate", 0 }, + { rtfSpecialChar, rtfCurHeadDateLong, "chdpl", 0 }, + { rtfSpecialChar, rtfCurHeadDateAbbrev, "chdpa", 0 }, + { rtfSpecialChar, rtfCurHeadTime, "chtime", 0 }, + { rtfSpecialChar, rtfCurHeadPage, "chpgn", 0 }, + { rtfSpecialChar, rtfSectNum, "sectnum", 0 }, + { rtfSpecialChar, rtfCurFNote, "chftn", 0 }, + { rtfSpecialChar, rtfCurAnnotRef, "chatn", 0 }, + { rtfSpecialChar, rtfFNoteSep, "chftnsep", 0 }, + { rtfSpecialChar, rtfFNoteCont, "chftnsepc", 0 }, + { rtfSpecialChar, rtfCell, "cell", 0 }, + { rtfSpecialChar, rtfRow, "row", 0 }, + { rtfSpecialChar, rtfPar, "par", 0 }, + /* newline and carriage return are synonyms for */ + /* \par when they are preceded by a \ character */ + { rtfSpecialChar, rtfPar, "\n", 0 }, + { rtfSpecialChar, rtfPar, "\r", 0 }, + { rtfSpecialChar, rtfSect, "sect", 0 }, + { rtfSpecialChar, rtfPage, "page", 0 }, + { rtfSpecialChar, rtfColumn, "column", 0 }, + { rtfSpecialChar, rtfLine, "line", 0 }, + { rtfSpecialChar, rtfSoftPage, "softpage", 0 }, + { rtfSpecialChar, rtfSoftColumn, "softcol", 0 }, + { rtfSpecialChar, rtfSoftLine, "softline", 0 }, + { rtfSpecialChar, rtfSoftLineHt, "softlheight", 0 }, + { rtfSpecialChar, rtfTab, "tab", 0 }, + { rtfSpecialChar, rtfEmDash, "emdash", 0 }, + { rtfSpecialChar, rtfEnDash, "endash", 0 }, + { rtfSpecialChar, rtfEmSpace, "emspace", 0 }, + { rtfSpecialChar, rtfEnSpace, "enspace", 0 }, + { rtfSpecialChar, rtfBullet, "bullet", 0 }, + { rtfSpecialChar, rtfLQuote, "lquote", 0 }, + { rtfSpecialChar, rtfRQuote, "rquote", 0 }, + { rtfSpecialChar, rtfLDblQuote, "ldblquote", 0 }, + { rtfSpecialChar, rtfRDblQuote, "rdblquote", 0 }, + { rtfSpecialChar, rtfFormula, "|", 0 }, + { rtfSpecialChar, rtfNoBrkSpace, "~", 0 }, + { rtfSpecialChar, rtfNoReqHyphen, "-", 0 }, + { rtfSpecialChar, rtfNoBrkHyphen, "_", 0 }, + { rtfSpecialChar, rtfOptDest, "*", 0 }, + { rtfSpecialChar, rtfLTRMark, "ltrmark", 0 }, + { rtfSpecialChar, rtfRTLMark, "rtlmark", 0 }, + { rtfSpecialChar, rtfNoWidthJoiner, "zwj", 0 }, + { rtfSpecialChar, rtfNoWidthNonJoiner, "zwnj", 0 }, + /* is this valid? */ + { rtfSpecialChar, rtfCurHeadPict, "chpict", 0 }, + + /* + * Character formatting attributes + */ + + { rtfCharAttr, rtfPlain, "plain", 0 }, + { rtfCharAttr, rtfBold, "b", 0 }, + { rtfCharAttr, rtfAllCaps, "caps", 0 }, + { rtfCharAttr, rtfDeleted, "deleted", 0 }, + { rtfCharAttr, rtfSubScript, "dn", 0 }, + { rtfCharAttr, rtfSubScrShrink, "sub", 0 }, + { rtfCharAttr, rtfNoSuperSub, "nosupersub", 0 }, + { rtfCharAttr, rtfExpand, "expnd", 0 }, + { rtfCharAttr, rtfExpandTwips, "expndtw", 0 }, + { rtfCharAttr, rtfKerning, "kerning", 0 }, + { rtfCharAttr, rtfFontNum, "f", 0 }, + { rtfCharAttr, rtfFontSize, "fs", 0 }, + { rtfCharAttr, rtfItalic, "i", 0 }, + { rtfCharAttr, rtfOutline, "outl", 0 }, + { rtfCharAttr, rtfRevised, "revised", 0 }, + { rtfCharAttr, rtfRevAuthor, "revauth", 0 }, + { rtfCharAttr, rtfRevDTTM, "revdttm", 0 }, + { rtfCharAttr, rtfSmallCaps, "scaps", 0 }, + { rtfCharAttr, rtfShadow, "shad", 0 }, + { rtfCharAttr, rtfStrikeThru, "strike", 0 }, + { rtfCharAttr, rtfUnderline, "ul", 0 }, + { rtfCharAttr, rtfDotUnderline, "uld", 0 }, + { rtfCharAttr, rtfDbUnderline, "uldb", 0 }, + { rtfCharAttr, rtfNoUnderline, "ulnone", 0 }, + { rtfCharAttr, rtfWordUnderline, "ulw", 0 }, + { rtfCharAttr, rtfSuperScript, "up", 0 }, + { rtfCharAttr, rtfSuperScrShrink, "super", 0 }, + { rtfCharAttr, rtfInvisible, "v", 0 }, + { rtfCharAttr, rtfForeColor, "cf", 0 }, + { rtfCharAttr, rtfBackColor, "cb", 0 }, + { rtfCharAttr, rtfRTLChar, "rtlch", 0 }, + { rtfCharAttr, rtfLTRChar, "ltrch", 0 }, + { rtfCharAttr, rtfCharStyleNum, "cs", 0 }, + { rtfCharAttr, rtfCharCharSet, "cchs", 0 }, + { rtfCharAttr, rtfLanguage, "lang", 0 }, + /* this has disappeared from spec 1.2 */ + { rtfCharAttr, rtfGray, "gray", 0 }, + + /* + * Paragraph formatting attributes + */ + + { rtfParAttr, rtfParDef, "pard", 0 }, + { rtfParAttr, rtfStyleNum, "s", 0 }, + { rtfParAttr, rtfHyphenate, "hyphpar", 0 }, + { rtfParAttr, rtfInTable, "intbl", 0 }, + { rtfParAttr, rtfKeep, "keep", 0 }, + { rtfParAttr, rtfNoWidowControl, "nowidctlpar", 0 }, + { rtfParAttr, rtfKeepNext, "keepn", 0 }, + { rtfParAttr, rtfOutlineLevel, "level", 0 }, + { rtfParAttr, rtfNoLineNum, "noline", 0 }, + { rtfParAttr, rtfPBBefore, "pagebb", 0 }, + { rtfParAttr, rtfSideBySide, "sbys", 0 }, + { rtfParAttr, rtfQuadLeft, "ql", 0 }, + { rtfParAttr, rtfQuadRight, "qr", 0 }, + { rtfParAttr, rtfQuadJust, "qj", 0 }, + { rtfParAttr, rtfQuadCenter, "qc", 0 }, + { rtfParAttr, rtfFirstIndent, "fi", 0 }, + { rtfParAttr, rtfLeftIndent, "li", 0 }, + { rtfParAttr, rtfRightIndent, "ri", 0 }, + { rtfParAttr, rtfSpaceBefore, "sb", 0 }, + { rtfParAttr, rtfSpaceAfter, "sa", 0 }, + { rtfParAttr, rtfSpaceBetween, "sl", 0 }, + { rtfParAttr, rtfSpaceMultiply, "slmult", 0 }, + + { rtfParAttr, rtfSubDocument, "subdocument", 0 }, + + { rtfParAttr, rtfRTLPar, "rtlpar", 0 }, + { rtfParAttr, rtfLTRPar, "ltrpar", 0 }, + + { rtfParAttr, rtfTabPos, "tx", 0 }, + /* + * FrameMaker writes \tql (to mean left-justified tab, apparently) + * although it's not in the spec. It's also redundant, since lj + * tabs are the default. + */ + { rtfParAttr, rtfTabLeft, "tql", 0 }, + { rtfParAttr, rtfTabRight, "tqr", 0 }, + { rtfParAttr, rtfTabCenter, "tqc", 0 }, + { rtfParAttr, rtfTabDecimal, "tqdec", 0 }, + { rtfParAttr, rtfTabBar, "tb", 0 }, + { rtfParAttr, rtfLeaderDot, "tldot", 0 }, + { rtfParAttr, rtfLeaderHyphen, "tlhyph", 0 }, + { rtfParAttr, rtfLeaderUnder, "tlul", 0 }, + { rtfParAttr, rtfLeaderThick, "tlth", 0 }, + { rtfParAttr, rtfLeaderEqual, "tleq", 0 }, + + { rtfParAttr, rtfParLevel, "pnlvl", 0 }, + { rtfParAttr, rtfParBullet, "pnlvlblt", 0 }, + { rtfParAttr, rtfParSimple, "pnlvlbody", 0 }, + { rtfParAttr, rtfParNumCont, "pnlvlcont", 0 }, + { rtfParAttr, rtfParNumOnce, "pnnumonce", 0 }, + { rtfParAttr, rtfParNumAcross, "pnacross", 0 }, + { rtfParAttr, rtfParHangIndent, "pnhang", 0 }, + { rtfParAttr, rtfParNumRestart, "pnrestart", 0 }, + { rtfParAttr, rtfParNumCardinal, "pncard", 0 }, + { rtfParAttr, rtfParNumDecimal, "pndec", 0 }, + { rtfParAttr, rtfParNumULetter, "pnucltr", 0 }, + { rtfParAttr, rtfParNumURoman, "pnucrm", 0 }, + { rtfParAttr, rtfParNumLLetter, "pnlcltr", 0 }, + { rtfParAttr, rtfParNumLRoman, "pnlcrm", 0 }, + { rtfParAttr, rtfParNumOrdinal, "pnord", 0 }, + { rtfParAttr, rtfParNumOrdinalText, "pnordt", 0 }, + { rtfParAttr, rtfParNumBold, "pnb", 0 }, + { rtfParAttr, rtfParNumItalic, "pni", 0 }, + { rtfParAttr, rtfParNumAllCaps, "pncaps", 0 }, + { rtfParAttr, rtfParNumSmallCaps, "pnscaps", 0 }, + { rtfParAttr, rtfParNumUnder, "pnul", 0 }, + { rtfParAttr, rtfParNumDotUnder, "pnuld", 0 }, + { rtfParAttr, rtfParNumDbUnder, "pnuldb", 0 }, + { rtfParAttr, rtfParNumNoUnder, "pnulnone", 0 }, + { rtfParAttr, rtfParNumWordUnder, "pnulw", 0 }, + { rtfParAttr, rtfParNumStrikethru, "pnstrike", 0 }, + { rtfParAttr, rtfParNumForeColor, "pncf", 0 }, + { rtfParAttr, rtfParNumFont, "pnf", 0 }, + { rtfParAttr, rtfParNumFontSize, "pnfs", 0 }, + { rtfParAttr, rtfParNumIndent, "pnindent", 0 }, + { rtfParAttr, rtfParNumSpacing, "pnsp", 0 }, + { rtfParAttr, rtfParNumInclPrev, "pnprev", 0 }, + { rtfParAttr, rtfParNumCenter, "pnqc", 0 }, + { rtfParAttr, rtfParNumLeft, "pnql", 0 }, + { rtfParAttr, rtfParNumRight, "pnqr", 0 }, + { rtfParAttr, rtfParNumStartAt, "pnstart", 0 }, + + { rtfParAttr, rtfBorderTop, "brdrt", 0 }, + { rtfParAttr, rtfBorderBottom, "brdrb", 0 }, + { rtfParAttr, rtfBorderLeft, "brdrl", 0 }, + { rtfParAttr, rtfBorderRight, "brdrr", 0 }, + { rtfParAttr, rtfBorderBetween, "brdrbtw", 0 }, + { rtfParAttr, rtfBorderBar, "brdrbar", 0 }, + { rtfParAttr, rtfBorderBox, "box", 0 }, + { rtfParAttr, rtfBorderSingle, "brdrs", 0 }, + { rtfParAttr, rtfBorderThick, "brdrth", 0 }, + { rtfParAttr, rtfBorderShadow, "brdrsh", 0 }, + { rtfParAttr, rtfBorderDouble, "brdrdb", 0 }, + { rtfParAttr, rtfBorderDot, "brdrdot", 0 }, + { rtfParAttr, rtfBorderDot, "brdrdash", 0 }, + { rtfParAttr, rtfBorderHair, "brdrhair", 0 }, + { rtfParAttr, rtfBorderWidth, "brdrw", 0 }, + { rtfParAttr, rtfBorderColor, "brdrcf", 0 }, + { rtfParAttr, rtfBorderSpace, "brsp", 0 }, + + { rtfParAttr, rtfShading, "shading", 0 }, + { rtfParAttr, rtfBgPatH, "bghoriz", 0 }, + { rtfParAttr, rtfBgPatV, "bgvert", 0 }, + { rtfParAttr, rtfFwdDiagBgPat, "bgfdiag", 0 }, + { rtfParAttr, rtfBwdDiagBgPat, "bgbdiag", 0 }, + { rtfParAttr, rtfHatchBgPat, "bgcross", 0 }, + { rtfParAttr, rtfDiagHatchBgPat, "bgdcross", 0 }, + { rtfParAttr, rtfDarkBgPatH, "bgdkhoriz", 0 }, + { rtfParAttr, rtfDarkBgPatV, "bgdkvert", 0 }, + { rtfParAttr, rtfFwdDarkBgPat, "bgdkfdiag", 0 }, + { rtfParAttr, rtfBwdDarkBgPat, "bgdkbdiag", 0 }, + { rtfParAttr, rtfDarkHatchBgPat, "bgdkcross", 0 }, + { rtfParAttr, rtfDarkDiagHatchBgPat, "bgdkdcross", 0 }, + { rtfParAttr, rtfBgPatLineColor, "cfpat", 0 }, + { rtfParAttr, rtfBgPatColor, "cbpat", 0 }, + + /* + * Section formatting attributes + */ + + { rtfSectAttr, rtfSectDef, "sectd", 0 }, + { rtfSectAttr, rtfENoteHere, "endnhere", 0 }, + { rtfSectAttr, rtfPrtBinFirst, "binfsxn", 0 }, + { rtfSectAttr, rtfPrtBin, "binsxn", 0 }, + { rtfSectAttr, rtfSectStyleNum, "ds", 0 }, + + { rtfSectAttr, rtfNoBreak, "sbknone", 0 }, + { rtfSectAttr, rtfColBreak, "sbkcol", 0 }, + { rtfSectAttr, rtfPageBreak, "sbkpage", 0 }, + { rtfSectAttr, rtfEvenBreak, "sbkeven", 0 }, + { rtfSectAttr, rtfOddBreak, "sbkodd", 0 }, + + { rtfSectAttr, rtfColumns, "cols", 0 }, + { rtfSectAttr, rtfColumnSpace, "colsx", 0 }, + { rtfSectAttr, rtfColumnNumber, "colno", 0 }, + { rtfSectAttr, rtfColumnSpRight, "colsr", 0 }, + { rtfSectAttr, rtfColumnWidth, "colw", 0 }, + { rtfSectAttr, rtfColumnLine, "linebetcol", 0 }, + + { rtfSectAttr, rtfLineModulus, "linemod", 0 }, + { rtfSectAttr, rtfLineDist, "linex", 0 }, + { rtfSectAttr, rtfLineStarts, "linestarts", 0 }, + { rtfSectAttr, rtfLineRestart, "linerestart", 0 }, + { rtfSectAttr, rtfLineRestartPg, "lineppage", 0 }, + { rtfSectAttr, rtfLineCont, "linecont", 0 }, + + { rtfSectAttr, rtfSectPageWid, "pgwsxn", 0 }, + { rtfSectAttr, rtfSectPageHt, "pghsxn", 0 }, + { rtfSectAttr, rtfSectMarginLeft, "marglsxn", 0 }, + { rtfSectAttr, rtfSectMarginRight, "margrsxn", 0 }, + { rtfSectAttr, rtfSectMarginTop, "margtsxn", 0 }, + { rtfSectAttr, rtfSectMarginBottom, "margbsxn", 0 }, + { rtfSectAttr, rtfSectMarginGutter, "guttersxn", 0 }, + { rtfSectAttr, rtfSectLandscape, "lndscpsxn", 0 }, + { rtfSectAttr, rtfTitleSpecial, "titlepg", 0 }, + { rtfSectAttr, rtfHeaderY, "headery", 0 }, + { rtfSectAttr, rtfFooterY, "footery", 0 }, + + { rtfSectAttr, rtfPageStarts, "pgnstarts", 0 }, + { rtfSectAttr, rtfPageCont, "pgncont", 0 }, + { rtfSectAttr, rtfPageRestart, "pgnrestart", 0 }, + { rtfSectAttr, rtfPageNumRight, "pgnx", 0 }, + { rtfSectAttr, rtfPageNumTop, "pgny", 0 }, + { rtfSectAttr, rtfPageDecimal, "pgndec", 0 }, + { rtfSectAttr, rtfPageURoman, "pgnucrm", 0 }, + { rtfSectAttr, rtfPageLRoman, "pgnlcrm", 0 }, + { rtfSectAttr, rtfPageULetter, "pgnucltr", 0 }, + { rtfSectAttr, rtfPageLLetter, "pgnlcltr", 0 }, + { rtfSectAttr, rtfPageNumHyphSep, "pgnhnsh", 0 }, + { rtfSectAttr, rtfPageNumSpaceSep, "pgnhnsp", 0 }, + { rtfSectAttr, rtfPageNumColonSep, "pgnhnsc", 0 }, + { rtfSectAttr, rtfPageNumEmdashSep, "pgnhnsm", 0 }, + { rtfSectAttr, rtfPageNumEndashSep, "pgnhnsn", 0 }, + + { rtfSectAttr, rtfTopVAlign, "vertalt", 0 }, + /* misspelled as "vertal" in specification 1.0 */ + { rtfSectAttr, rtfBottomVAlign, "vertalb", 0 }, + { rtfSectAttr, rtfCenterVAlign, "vertalc", 0 }, + { rtfSectAttr, rtfJustVAlign, "vertalj", 0 }, + + { rtfSectAttr, rtfRTLSect, "rtlsect", 0 }, + { rtfSectAttr, rtfLTRSect, "ltrsect", 0 }, + + /* I've seen these in an old spec, but not in real files... */ + /*rtfSectAttr, rtfNoBreak, "nobreak", 0,*/ + /*rtfSectAttr, rtfColBreak, "colbreak", 0,*/ + /*rtfSectAttr, rtfPageBreak, "pagebreak", 0,*/ + /*rtfSectAttr, rtfEvenBreak, "evenbreak", 0,*/ + /*rtfSectAttr, rtfOddBreak, "oddbreak", 0,*/ + + /* + * Document formatting attributes + */ + + { rtfDocAttr, rtfDefTab, "deftab", 0 }, + { rtfDocAttr, rtfHyphHotZone, "hyphhotz", 0 }, + { rtfDocAttr, rtfHyphConsecLines, "hyphconsec", 0 }, + { rtfDocAttr, rtfHyphCaps, "hyphcaps", 0 }, + { rtfDocAttr, rtfHyphAuto, "hyphauto", 0 }, + { rtfDocAttr, rtfLineStart, "linestart", 0 }, + { rtfDocAttr, rtfFracWidth, "fracwidth", 0 }, + /* \makeback was given in old version of spec, it's now */ + /* listed as \makebackup */ + { rtfDocAttr, rtfMakeBackup, "makeback", 0 }, + { rtfDocAttr, rtfMakeBackup, "makebackup", 0 }, + { rtfDocAttr, rtfRTFDefault, "defformat", 0 }, + { rtfDocAttr, rtfPSOverlay, "psover", 0 }, + { rtfDocAttr, rtfDocTemplate, "doctemp", 0 }, + { rtfDocAttr, rtfDefLanguage, "deflang", 0 }, + + { rtfDocAttr, rtfFENoteType, "fet", 0 }, + { rtfDocAttr, rtfFNoteEndSect, "endnotes", 0 }, + { rtfDocAttr, rtfFNoteEndDoc, "enddoc", 0 }, + { rtfDocAttr, rtfFNoteText, "ftntj", 0 }, + { rtfDocAttr, rtfFNoteBottom, "ftnbj", 0 }, + { rtfDocAttr, rtfENoteEndSect, "aendnotes", 0 }, + { rtfDocAttr, rtfENoteEndDoc, "aenddoc", 0 }, + { rtfDocAttr, rtfENoteText, "aftntj", 0 }, + { rtfDocAttr, rtfENoteBottom, "aftnbj", 0 }, + { rtfDocAttr, rtfFNoteStart, "ftnstart", 0 }, + { rtfDocAttr, rtfENoteStart, "aftnstart", 0 }, + { rtfDocAttr, rtfFNoteRestartPage, "ftnrstpg", 0 }, + { rtfDocAttr, rtfFNoteRestart, "ftnrestart", 0 }, + { rtfDocAttr, rtfFNoteRestartCont, "ftnrstcont", 0 }, + { rtfDocAttr, rtfENoteRestart, "aftnrestart", 0 }, + { rtfDocAttr, rtfENoteRestartCont, "aftnrstcont", 0 }, + { rtfDocAttr, rtfFNoteNumArabic, "ftnnar", 0 }, + { rtfDocAttr, rtfFNoteNumLLetter, "ftnnalc", 0 }, + { rtfDocAttr, rtfFNoteNumULetter, "ftnnauc", 0 }, + { rtfDocAttr, rtfFNoteNumLRoman, "ftnnrlc", 0 }, + { rtfDocAttr, rtfFNoteNumURoman, "ftnnruc", 0 }, + { rtfDocAttr, rtfFNoteNumChicago, "ftnnchi", 0 }, + { rtfDocAttr, rtfENoteNumArabic, "aftnnar", 0 }, + { rtfDocAttr, rtfENoteNumLLetter, "aftnnalc", 0 }, + { rtfDocAttr, rtfENoteNumULetter, "aftnnauc", 0 }, + { rtfDocAttr, rtfENoteNumLRoman, "aftnnrlc", 0 }, + { rtfDocAttr, rtfENoteNumURoman, "aftnnruc", 0 }, + { rtfDocAttr, rtfENoteNumChicago, "aftnnchi", 0 }, + + { rtfDocAttr, rtfPaperWidth, "paperw", 0 }, + { rtfDocAttr, rtfPaperHeight, "paperh", 0 }, + { rtfDocAttr, rtfPaperSize, "psz", 0 }, + { rtfDocAttr, rtfLeftMargin, "margl", 0 }, + { rtfDocAttr, rtfRightMargin, "margr", 0 }, + { rtfDocAttr, rtfTopMargin, "margt", 0 }, + { rtfDocAttr, rtfBottomMargin, "margb", 0 }, + { rtfDocAttr, rtfFacingPage, "facingp", 0 }, + { rtfDocAttr, rtfGutterWid, "gutter", 0 }, + { rtfDocAttr, rtfMirrorMargin, "margmirror", 0 }, + { rtfDocAttr, rtfLandscape, "landscape", 0 }, + { rtfDocAttr, rtfPageStart, "pgnstart", 0 }, + { rtfDocAttr, rtfWidowCtrl, "widowctrl", 0 }, + + { rtfDocAttr, rtfLinkStyles, "linkstyles", 0 }, + + { rtfDocAttr, rtfNoAutoTabIndent, "notabind", 0 }, + { rtfDocAttr, rtfWrapSpaces, "wraptrsp", 0 }, + { rtfDocAttr, rtfPrintColorsBlack, "prcolbl", 0 }, + { rtfDocAttr, rtfNoExtraSpaceRL, "noextrasprl", 0 }, + { rtfDocAttr, rtfNoColumnBalance, "nocolbal", 0 }, + { rtfDocAttr, rtfCvtMailMergeQuote, "cvmme", 0 }, + { rtfDocAttr, rtfSuppressTopSpace, "sprstsp", 0 }, + { rtfDocAttr, rtfSuppressPreParSpace, "sprsspbf", 0 }, + { rtfDocAttr, rtfCombineTblBorders, "otblrul", 0 }, + { rtfDocAttr, rtfTranspMetafiles, "transmf", 0 }, + { rtfDocAttr, rtfSwapBorders, "swpbdr", 0 }, + { rtfDocAttr, rtfShowHardBreaks, "brkfrm", 0 }, + + { rtfDocAttr, rtfFormProtected, "formprot", 0 }, + { rtfDocAttr, rtfAllProtected, "allprot", 0 }, + { rtfDocAttr, rtfFormShading, "formshade", 0 }, + { rtfDocAttr, rtfFormDisplay, "formdisp", 0 }, + { rtfDocAttr, rtfPrintData, "printdata", 0 }, + + { rtfDocAttr, rtfRevProtected, "revprot", 0 }, + { rtfDocAttr, rtfRevisions, "revisions", 0 }, + { rtfDocAttr, rtfRevDisplay, "revprop", 0 }, + { rtfDocAttr, rtfRevBar, "revbar", 0 }, + + { rtfDocAttr, rtfAnnotProtected, "annotprot", 0 }, + + { rtfDocAttr, rtfRTLDoc, "rtldoc", 0 }, + { rtfDocAttr, rtfLTRDoc, "ltrdoc", 0 }, + + /* + * Style attributes + */ + + { rtfStyleAttr, rtfAdditive, "additive", 0 }, + { rtfStyleAttr, rtfBasedOn, "sbasedon", 0 }, + { rtfStyleAttr, rtfNext, "snext", 0 }, + + /* + * Picture attributes + */ + + { rtfPictAttr, rtfMacQD, "macpict", 0 }, + { rtfPictAttr, rtfPMMetafile, "pmmetafile", 0 }, + { rtfPictAttr, rtfWinMetafile, "wmetafile", 0 }, + { rtfPictAttr, rtfDevIndBitmap, "dibitmap", 0 }, + { rtfPictAttr, rtfWinBitmap, "wbitmap", 0 }, + { rtfPictAttr, rtfPixelBits, "wbmbitspixel", 0 }, + { rtfPictAttr, rtfBitmapPlanes, "wbmplanes", 0 }, + { rtfPictAttr, rtfBitmapWid, "wbmwidthbytes", 0 }, + + { rtfPictAttr, rtfPicWid, "picw", 0 }, + { rtfPictAttr, rtfPicHt, "pich", 0 }, + { rtfPictAttr, rtfPicGoalWid, "picwgoal", 0 }, + { rtfPictAttr, rtfPicGoalHt, "pichgoal", 0 }, + /* these two aren't in the spec, but some writers emit them */ + { rtfPictAttr, rtfPicGoalWid, "picwGoal", 0 }, + { rtfPictAttr, rtfPicGoalHt, "pichGoal", 0 }, + { rtfPictAttr, rtfPicScaleX, "picscalex", 0 }, + { rtfPictAttr, rtfPicScaleY, "picscaley", 0 }, + { rtfPictAttr, rtfPicScaled, "picscaled", 0 }, + { rtfPictAttr, rtfPicCropTop, "piccropt", 0 }, + { rtfPictAttr, rtfPicCropBottom, "piccropb", 0 }, + { rtfPictAttr, rtfPicCropLeft, "piccropl", 0 }, + { rtfPictAttr, rtfPicCropRight, "piccropr", 0 }, + + { rtfPictAttr, rtfPicMFHasBitmap, "picbmp", 0 }, + { rtfPictAttr, rtfPicMFBitsPerPixel, "picbpp", 0 }, + + { rtfPictAttr, rtfPicBinary, "bin", 0 }, + + /* + * NeXT graphic attributes + */ + + { rtfNeXTGrAttr, rtfNeXTGWidth, "width", 0 }, + { rtfNeXTGrAttr, rtfNeXTGHeight, "height", 0 }, + + /* + * Destinations + */ + + { rtfDestination, rtfFontTbl, "fonttbl", 0 }, + { rtfDestination, rtfFontAltName, "falt", 0 }, + { rtfDestination, rtfEmbeddedFont, "fonteb", 0 }, + { rtfDestination, rtfFontFile, "fontfile", 0 }, + { rtfDestination, rtfFileTbl, "filetbl", 0 }, + { rtfDestination, rtfFileInfo, "file", 0 }, + { rtfDestination, rtfColorTbl, "colortbl", 0 }, + { rtfDestination, rtfStyleSheet, "stylesheet", 0 }, + { rtfDestination, rtfKeyCode, "keycode", 0 }, + { rtfDestination, rtfRevisionTbl, "revtbl", 0 }, + { rtfDestination, rtfInfo, "info", 0 }, + { rtfDestination, rtfITitle, "title", 0 }, + { rtfDestination, rtfISubject, "subject", 0 }, + { rtfDestination, rtfIAuthor, "author", 0 }, + { rtfDestination, rtfIOperator, "operator", 0 }, + { rtfDestination, rtfIKeywords, "keywords", 0 }, + { rtfDestination, rtfIComment, "comment", 0 }, + { rtfDestination, rtfIVersion, "version", 0 }, + { rtfDestination, rtfIDoccomm, "doccomm", 0 }, + /* \verscomm may not exist -- was seen in earlier spec version */ + { rtfDestination, rtfIVerscomm, "verscomm", 0 }, + { rtfDestination, rtfNextFile, "nextfile", 0 }, + { rtfDestination, rtfTemplate, "template", 0 }, + { rtfDestination, rtfFNSep, "ftnsep", 0 }, + { rtfDestination, rtfFNContSep, "ftnsepc", 0 }, + { rtfDestination, rtfFNContNotice, "ftncn", 0 }, + { rtfDestination, rtfENSep, "aftnsep", 0 }, + { rtfDestination, rtfENContSep, "aftnsepc", 0 }, + { rtfDestination, rtfENContNotice, "aftncn", 0 }, + { rtfDestination, rtfPageNumLevel, "pgnhn", 0 }, + { rtfDestination, rtfParNumLevelStyle, "pnseclvl", 0 }, + { rtfDestination, rtfHeader, "header", 0 }, + { rtfDestination, rtfFooter, "footer", 0 }, + { rtfDestination, rtfHeaderLeft, "headerl", 0 }, + { rtfDestination, rtfHeaderRight, "headerr", 0 }, + { rtfDestination, rtfHeaderFirst, "headerf", 0 }, + { rtfDestination, rtfFooterLeft, "footerl", 0 }, + { rtfDestination, rtfFooterRight, "footerr", 0 }, + { rtfDestination, rtfFooterFirst, "footerf", 0 }, + { rtfDestination, rtfParNumText, "pntext", 0 }, + { rtfDestination, rtfParNumbering, "pn", 0 }, + { rtfDestination, rtfParNumTextAfter, "pntexta", 0 }, + { rtfDestination, rtfParNumTextBefore, "pntextb", 0 }, + { rtfDestination, rtfBookmarkStart, "bkmkstart", 0 }, + { rtfDestination, rtfBookmarkEnd, "bkmkend", 0 }, + { rtfDestination, rtfPict, "pict", 0 }, + { rtfDestination, rtfObject, "object", 0 }, + { rtfDestination, rtfObjClass, "objclass", 0 }, + { rtfDestination, rtfObjName, "objname", 0 }, + { rtfObjAttr, rtfObjTime, "objtime", 0 }, + { rtfDestination, rtfObjData, "objdata", 0 }, + { rtfDestination, rtfObjAlias, "objalias", 0 }, + { rtfDestination, rtfObjSection, "objsect", 0 }, + /* objitem and objtopic aren't documented in the spec! */ + { rtfDestination, rtfObjItem, "objitem", 0 }, + { rtfDestination, rtfObjTopic, "objtopic", 0 }, + { rtfDestination, rtfObjResult, "result", 0 }, + { rtfDestination, rtfDrawObject, "do", 0 }, + { rtfDestination, rtfFootnote, "footnote", 0 }, + { rtfDestination, rtfAnnotRefStart, "atrfstart", 0 }, + { rtfDestination, rtfAnnotRefEnd, "atrfend", 0 }, + { rtfDestination, rtfAnnotID, "atnid", 0 }, + { rtfDestination, rtfAnnotAuthor, "atnauthor", 0 }, + { rtfDestination, rtfAnnotation, "annotation", 0 }, + { rtfDestination, rtfAnnotRef, "atnref", 0 }, + { rtfDestination, rtfAnnotTime, "atntime", 0 }, + { rtfDestination, rtfAnnotIcon, "atnicn", 0 }, + { rtfDestination, rtfField, "field", 0 }, + { rtfDestination, rtfFieldInst, "fldinst", 0 }, + { rtfDestination, rtfFieldResult, "fldrslt", 0 }, + { rtfDestination, rtfDataField, "datafield", 0 }, + { rtfDestination, rtfIndex, "xe", 0 }, + { rtfDestination, rtfIndexText, "txe", 0 }, + { rtfDestination, rtfIndexRange, "rxe", 0 }, + { rtfDestination, rtfTOC, "tc", 0 }, + { rtfDestination, rtfNeXTGraphic, "NeXTGraphic", 0 }, + + /* + * Font families + */ + + { rtfFontFamily, rtfFFNil, "fnil", 0 }, + { rtfFontFamily, rtfFFRoman, "froman", 0 }, + { rtfFontFamily, rtfFFSwiss, "fswiss", 0 }, + { rtfFontFamily, rtfFFModern, "fmodern", 0 }, + { rtfFontFamily, rtfFFScript, "fscript", 0 }, + { rtfFontFamily, rtfFFDecor, "fdecor", 0 }, + { rtfFontFamily, rtfFFTech, "ftech", 0 }, + { rtfFontFamily, rtfFFBidirectional, "fbidi", 0 }, + + /* + * Font attributes + */ + + { rtfFontAttr, rtfFontCharSet, "fcharset", 0 }, + { rtfFontAttr, rtfFontPitch, "fprq", 0 }, + { rtfFontAttr, rtfFontCodePage, "cpg", 0 }, + { rtfFontAttr, rtfFTypeNil, "ftnil", 0 }, + { rtfFontAttr, rtfFTypeTrueType, "fttruetype", 0 }, + + /* + * File table attributes + */ + + { rtfFileAttr, rtfFileNum, "fid", 0 }, + { rtfFileAttr, rtfFileRelPath, "frelative", 0 }, + { rtfFileAttr, rtfFileOSNum, "fosnum", 0 }, + + /* + * File sources + */ + + { rtfFileSource, rtfSrcMacintosh, "fvalidmac", 0 }, + { rtfFileSource, rtfSrcDOS, "fvaliddos", 0 }, + { rtfFileSource, rtfSrcNTFS, "fvalidntfs", 0 }, + { rtfFileSource, rtfSrcHPFS, "fvalidhpfs", 0 }, + { rtfFileSource, rtfSrcNetwork, "fnetwork", 0 }, + + /* + * Color names + */ + + { rtfColorName, rtfRed, "red", 0 }, + { rtfColorName, rtfGreen, "green", 0 }, + { rtfColorName, rtfBlue, "blue", 0 }, + + /* + * Charset names + */ + + { rtfCharSet, rtfMacCharSet, "mac", 0 }, + { rtfCharSet, rtfAnsiCharSet, "ansi", 0 }, + { rtfCharSet, rtfPcCharSet, "pc", 0 }, + { rtfCharSet, rtfPcaCharSet, "pca", 0 }, + + /* + * Table attributes + */ + + { rtfTblAttr, rtfRowDef, "trowd", 0 }, + { rtfTblAttr, rtfRowGapH, "trgaph", 0 }, + { rtfTblAttr, rtfCellPos, "cellx", 0 }, + { rtfTblAttr, rtfMergeRngFirst, "clmgf", 0 }, + { rtfTblAttr, rtfMergePrevious, "clmrg", 0 }, + + { rtfTblAttr, rtfRowLeft, "trql", 0 }, + { rtfTblAttr, rtfRowRight, "trqr", 0 }, + { rtfTblAttr, rtfRowCenter, "trqc", 0 }, + { rtfTblAttr, rtfRowLeftEdge, "trleft", 0 }, + { rtfTblAttr, rtfRowHt, "trrh", 0 }, + { rtfTblAttr, rtfRowHeader, "trhdr", 0 }, + { rtfTblAttr, rtfRowKeep, "trkeep", 0 }, + + { rtfTblAttr, rtfRTLRow, "rtlrow", 0 }, + { rtfTblAttr, rtfLTRRow, "ltrrow", 0 }, + + { rtfTblAttr, rtfRowBordTop, "trbrdrt", 0 }, + { rtfTblAttr, rtfRowBordLeft, "trbrdrl", 0 }, + { rtfTblAttr, rtfRowBordBottom, "trbrdrb", 0 }, + { rtfTblAttr, rtfRowBordRight, "trbrdrr", 0 }, + { rtfTblAttr, rtfRowBordHoriz, "trbrdrh", 0 }, + { rtfTblAttr, rtfRowBordVert, "trbrdrv", 0 }, + + { rtfTblAttr, rtfCellBordBottom, "clbrdrb", 0 }, + { rtfTblAttr, rtfCellBordTop, "clbrdrt", 0 }, + { rtfTblAttr, rtfCellBordLeft, "clbrdrl", 0 }, + { rtfTblAttr, rtfCellBordRight, "clbrdrr", 0 }, + + { rtfTblAttr, rtfCellShading, "clshdng", 0 }, + { rtfTblAttr, rtfCellBgPatH, "clbghoriz", 0 }, + { rtfTblAttr, rtfCellBgPatV, "clbgvert", 0 }, + { rtfTblAttr, rtfCellFwdDiagBgPat, "clbgfdiag", 0 }, + { rtfTblAttr, rtfCellBwdDiagBgPat, "clbgbdiag", 0 }, + { rtfTblAttr, rtfCellHatchBgPat, "clbgcross", 0 }, + { rtfTblAttr, rtfCellDiagHatchBgPat, "clbgdcross", 0 }, + /* + * The spec lists "clbgdkhor", but the corresponding non-cell + * control is "bgdkhoriz". At any rate Macintosh Word seems + * to accept both "clbgdkhor" and "clbgdkhoriz". + */ + { rtfTblAttr, rtfCellDarkBgPatH, "clbgdkhoriz", 0 }, + { rtfTblAttr, rtfCellDarkBgPatH, "clbgdkhor", 0 }, + { rtfTblAttr, rtfCellDarkBgPatV, "clbgdkvert", 0 }, + { rtfTblAttr, rtfCellFwdDarkBgPat, "clbgdkfdiag", 0 }, + { rtfTblAttr, rtfCellBwdDarkBgPat, "clbgdkbdiag", 0 }, + { rtfTblAttr, rtfCellDarkHatchBgPat, "clbgdkcross", 0 }, + { rtfTblAttr, rtfCellDarkDiagHatchBgPat, "clbgdkdcross", 0 }, + { rtfTblAttr, rtfCellBgPatLineColor, "clcfpat", 0 }, + { rtfTblAttr, rtfCellBgPatColor, "clcbpat", 0 }, + + /* + * Field attributes + */ + + { rtfFieldAttr, rtfFieldDirty, "flddirty", 0 }, + { rtfFieldAttr, rtfFieldEdited, "fldedit", 0 }, + { rtfFieldAttr, rtfFieldLocked, "fldlock", 0 }, + { rtfFieldAttr, rtfFieldPrivate, "fldpriv", 0 }, + { rtfFieldAttr, rtfFieldAlt, "fldalt", 0 }, + + /* + * Positioning attributes + */ + + { rtfPosAttr, rtfAbsWid, "absw", 0 }, + { rtfPosAttr, rtfAbsHt, "absh", 0 }, + + { rtfPosAttr, rtfRPosMargH, "phmrg", 0 }, + { rtfPosAttr, rtfRPosPageH, "phpg", 0 }, + { rtfPosAttr, rtfRPosColH, "phcol", 0 }, + { rtfPosAttr, rtfPosX, "posx", 0 }, + { rtfPosAttr, rtfPosNegX, "posnegx", 0 }, + { rtfPosAttr, rtfPosXCenter, "posxc", 0 }, + { rtfPosAttr, rtfPosXInside, "posxi", 0 }, + { rtfPosAttr, rtfPosXOutSide, "posxo", 0 }, + { rtfPosAttr, rtfPosXRight, "posxr", 0 }, + { rtfPosAttr, rtfPosXLeft, "posxl", 0 }, + + { rtfPosAttr, rtfRPosMargV, "pvmrg", 0 }, + { rtfPosAttr, rtfRPosPageV, "pvpg", 0 }, + { rtfPosAttr, rtfRPosParaV, "pvpara", 0 }, + { rtfPosAttr, rtfPosY, "posy", 0 }, + { rtfPosAttr, rtfPosNegY, "posnegy", 0 }, + { rtfPosAttr, rtfPosYInline, "posyil", 0 }, + { rtfPosAttr, rtfPosYTop, "posyt", 0 }, + { rtfPosAttr, rtfPosYCenter, "posyc", 0 }, + { rtfPosAttr, rtfPosYBottom, "posyb", 0 }, + + { rtfPosAttr, rtfNoWrap, "nowrap", 0 }, + { rtfPosAttr, rtfDistFromTextAll, "dxfrtext", 0 }, + { rtfPosAttr, rtfDistFromTextX, "dfrmtxtx", 0 }, + { rtfPosAttr, rtfDistFromTextY, "dfrmtxty", 0 }, + /* \dyfrtext no longer exists in spec 1.2, apparently */ + /* replaced by \dfrmtextx and \dfrmtexty. */ + { rtfPosAttr, rtfTextDistY, "dyfrtext", 0 }, + + { rtfPosAttr, rtfDropCapLines, "dropcapli", 0 }, + { rtfPosAttr, rtfDropCapType, "dropcapt", 0 }, + + /* + * Object controls + */ + + { rtfObjAttr, rtfObjEmb, "objemb", 0 }, + { rtfObjAttr, rtfObjLink, "objlink", 0 }, + { rtfObjAttr, rtfObjAutoLink, "objautlink", 0 }, + { rtfObjAttr, rtfObjSubscriber, "objsub", 0 }, + { rtfObjAttr, rtfObjPublisher, "objpub", 0 }, + { rtfObjAttr, rtfObjICEmb, "objicemb", 0 }, + + { rtfObjAttr, rtfObjLinkSelf, "linkself", 0 }, + { rtfObjAttr, rtfObjLock, "objupdate", 0 }, + { rtfObjAttr, rtfObjUpdate, "objlock", 0 }, + + { rtfObjAttr, rtfObjHt, "objh", 0 }, + { rtfObjAttr, rtfObjWid, "objw", 0 }, + { rtfObjAttr, rtfObjSetSize, "objsetsize", 0 }, + { rtfObjAttr, rtfObjAlign, "objalign", 0 }, + { rtfObjAttr, rtfObjTransposeY, "objtransy", 0 }, + { rtfObjAttr, rtfObjCropTop, "objcropt", 0 }, + { rtfObjAttr, rtfObjCropBottom, "objcropb", 0 }, + { rtfObjAttr, rtfObjCropLeft, "objcropl", 0 }, + { rtfObjAttr, rtfObjCropRight, "objcropr", 0 }, + { rtfObjAttr, rtfObjScaleX, "objscalex", 0 }, + { rtfObjAttr, rtfObjScaleY, "objscaley", 0 }, + + { rtfObjAttr, rtfObjResRTF, "rsltrtf", 0 }, + { rtfObjAttr, rtfObjResPict, "rsltpict", 0 }, + { rtfObjAttr, rtfObjResBitmap, "rsltbmp", 0 }, + { rtfObjAttr, rtfObjResText, "rslttxt", 0 }, + { rtfObjAttr, rtfObjResMerge, "rsltmerge", 0 }, + + { rtfObjAttr, rtfObjBookmarkPubObj, "bkmkpub", 0 }, + { rtfObjAttr, rtfObjPubAutoUpdate, "pubauto", 0 }, + + /* + * Associated character formatting attributes + */ + + { rtfACharAttr, rtfACBold, "ab", 0 }, + { rtfACharAttr, rtfACAllCaps, "caps", 0 }, + { rtfACharAttr, rtfACForeColor, "acf", 0 }, + { rtfACharAttr, rtfACSubScript, "adn", 0 }, + { rtfACharAttr, rtfACExpand, "aexpnd", 0 }, + { rtfACharAttr, rtfACFontNum, "af", 0 }, + { rtfACharAttr, rtfACFontSize, "afs", 0 }, + { rtfACharAttr, rtfACItalic, "ai", 0 }, + { rtfACharAttr, rtfACLanguage, "alang", 0 }, + { rtfACharAttr, rtfACOutline, "aoutl", 0 }, + { rtfACharAttr, rtfACSmallCaps, "ascaps", 0 }, + { rtfACharAttr, rtfACShadow, "ashad", 0 }, + { rtfACharAttr, rtfACStrikeThru, "astrike", 0 }, + { rtfACharAttr, rtfACUnderline, "aul", 0 }, + { rtfACharAttr, rtfACDotUnderline, "auld", 0 }, + { rtfACharAttr, rtfACDbUnderline, "auldb", 0 }, + { rtfACharAttr, rtfACNoUnderline, "aulnone", 0 }, + { rtfACharAttr, rtfACWordUnderline, "aulw", 0 }, + { rtfACharAttr, rtfACSuperScript, "aup", 0 }, + + /* + * Footnote attributes + */ + + { rtfFNoteAttr, rtfFNAlt, "ftnalt", 0 }, + + /* + * Key code attributes + */ + + { rtfKeyCodeAttr, rtfAltKey, "alt", 0 }, + { rtfKeyCodeAttr, rtfShiftKey, "shift", 0 }, + { rtfKeyCodeAttr, rtfControlKey, "ctrl", 0 }, + { rtfKeyCodeAttr, rtfFunctionKey, "fn", 0 }, + + /* + * Bookmark attributes + */ + + { rtfBookmarkAttr, rtfBookmarkFirstCol, "bkmkcolf", 0 }, + { rtfBookmarkAttr, rtfBookmarkLastCol, "bkmkcoll", 0 }, + + /* + * Index entry attributes + */ + + { rtfIndexAttr, rtfIndexNumber, "xef", 0 }, + { rtfIndexAttr, rtfIndexBold, "bxe", 0 }, + { rtfIndexAttr, rtfIndexItalic, "ixe", 0 }, + + /* + * Table of contents attributes + */ + + { rtfTOCAttr, rtfTOCType, "tcf", 0 }, + { rtfTOCAttr, rtfTOCLevel, "tcl", 0 }, + + /* + * Drawing object attributes + */ + + { rtfDrawAttr, rtfDrawLock, "dolock", 0 }, + { rtfDrawAttr, rtfDrawPageRelX, "doxpage", 0 }, + { rtfDrawAttr, rtfDrawColumnRelX, "dobxcolumn", 0 }, + { rtfDrawAttr, rtfDrawMarginRelX, "dobxmargin", 0 }, + { rtfDrawAttr, rtfDrawPageRelY, "dobypage", 0 }, + { rtfDrawAttr, rtfDrawColumnRelY, "dobycolumn", 0 }, + { rtfDrawAttr, rtfDrawMarginRelY, "dobymargin", 0 }, + { rtfDrawAttr, rtfDrawHeight, "dobhgt", 0 }, + + { rtfDrawAttr, rtfDrawBeginGroup, "dpgroup", 0 }, + { rtfDrawAttr, rtfDrawGroupCount, "dpcount", 0 }, + { rtfDrawAttr, rtfDrawEndGroup, "dpendgroup", 0 }, + { rtfDrawAttr, rtfDrawArc, "dparc", 0 }, + { rtfDrawAttr, rtfDrawCallout, "dpcallout", 0 }, + { rtfDrawAttr, rtfDrawEllipse, "dpellipse", 0 }, + { rtfDrawAttr, rtfDrawLine, "dpline", 0 }, + { rtfDrawAttr, rtfDrawPolygon, "dppolygon", 0 }, + { rtfDrawAttr, rtfDrawPolyLine, "dppolyline", 0 }, + { rtfDrawAttr, rtfDrawRect, "dprect", 0 }, + { rtfDrawAttr, rtfDrawTextBox, "dptxbx", 0 }, + + { rtfDrawAttr, rtfDrawOffsetX, "dpx", 0 }, + { rtfDrawAttr, rtfDrawSizeX, "dpxsize", 0 }, + { rtfDrawAttr, rtfDrawOffsetY, "dpy", 0 }, + { rtfDrawAttr, rtfDrawSizeY, "dpysize", 0 }, + + { rtfDrawAttr, rtfCOAngle, "dpcoa", 0 }, + { rtfDrawAttr, rtfCOAccentBar, "dpcoaccent", 0 }, + { rtfDrawAttr, rtfCOBestFit, "dpcobestfit", 0 }, + { rtfDrawAttr, rtfCOBorder, "dpcoborder", 0 }, + { rtfDrawAttr, rtfCOAttachAbsDist, "dpcodabs", 0 }, + { rtfDrawAttr, rtfCOAttachBottom, "dpcodbottom", 0 }, + { rtfDrawAttr, rtfCOAttachCenter, "dpcodcenter", 0 }, + { rtfDrawAttr, rtfCOAttachTop, "dpcodtop", 0 }, + { rtfDrawAttr, rtfCOLength, "dpcolength", 0 }, + { rtfDrawAttr, rtfCONegXQuadrant, "dpcominusx", 0 }, + { rtfDrawAttr, rtfCONegYQuadrant, "dpcominusy", 0 }, + { rtfDrawAttr, rtfCOOffset, "dpcooffset", 0 }, + { rtfDrawAttr, rtfCOAttachSmart, "dpcosmarta", 0 }, + { rtfDrawAttr, rtfCODoubleLine, "dpcotdouble", 0 }, + { rtfDrawAttr, rtfCORightAngle, "dpcotright", 0 }, + { rtfDrawAttr, rtfCOSingleLine, "dpcotsingle", 0 }, + { rtfDrawAttr, rtfCOTripleLine, "dpcottriple", 0 }, + + { rtfDrawAttr, rtfDrawTextBoxMargin, "dptxbxmar", 0 }, + { rtfDrawAttr, rtfDrawTextBoxText, "dptxbxtext", 0 }, + { rtfDrawAttr, rtfDrawRoundRect, "dproundr", 0 }, + + { rtfDrawAttr, rtfDrawPointX, "dpptx", 0 }, + { rtfDrawAttr, rtfDrawPointY, "dppty", 0 }, + { rtfDrawAttr, rtfDrawPolyCount, "dppolycount", 0 }, + + { rtfDrawAttr, rtfDrawArcFlipX, "dparcflipx", 0 }, + { rtfDrawAttr, rtfDrawArcFlipY, "dparcflipy", 0 }, + + { rtfDrawAttr, rtfDrawLineBlue, "dplinecob", 0 }, + { rtfDrawAttr, rtfDrawLineGreen, "dplinecog", 0 }, + { rtfDrawAttr, rtfDrawLineRed, "dplinecor", 0 }, + { rtfDrawAttr, rtfDrawLinePalette, "dplinepal", 0 }, + { rtfDrawAttr, rtfDrawLineDashDot, "dplinedado", 0 }, + { rtfDrawAttr, rtfDrawLineDashDotDot, "dplinedadodo", 0 }, + { rtfDrawAttr, rtfDrawLineDash, "dplinedash", 0 }, + { rtfDrawAttr, rtfDrawLineDot, "dplinedot", 0 }, + { rtfDrawAttr, rtfDrawLineGray, "dplinegray", 0 }, + { rtfDrawAttr, rtfDrawLineHollow, "dplinehollow", 0 }, + { rtfDrawAttr, rtfDrawLineSolid, "dplinesolid", 0 }, + { rtfDrawAttr, rtfDrawLineWidth, "dplinew", 0 }, + + { rtfDrawAttr, rtfDrawHollowEndArrow, "dpaendhol", 0 }, + { rtfDrawAttr, rtfDrawEndArrowLength, "dpaendl", 0 }, + { rtfDrawAttr, rtfDrawSolidEndArrow, "dpaendsol", 0 }, + { rtfDrawAttr, rtfDrawEndArrowWidth, "dpaendw", 0 }, + { rtfDrawAttr, rtfDrawHollowStartArrow,"dpastarthol", 0 }, + { rtfDrawAttr, rtfDrawStartArrowLength,"dpastartl", 0 }, + { rtfDrawAttr, rtfDrawSolidStartArrow, "dpastartsol", 0 }, + { rtfDrawAttr, rtfDrawStartArrowWidth, "dpastartw", 0 }, + + { rtfDrawAttr, rtfDrawBgFillBlue, "dpfillbgcb", 0 }, + { rtfDrawAttr, rtfDrawBgFillGreen, "dpfillbgcg", 0 }, + { rtfDrawAttr, rtfDrawBgFillRed, "dpfillbgcr", 0 }, + { rtfDrawAttr, rtfDrawBgFillPalette, "dpfillbgpal", 0 }, + { rtfDrawAttr, rtfDrawBgFillGray, "dpfillbggray", 0 }, + { rtfDrawAttr, rtfDrawFgFillBlue, "dpfillfgcb", 0 }, + { rtfDrawAttr, rtfDrawFgFillGreen, "dpfillfgcg", 0 }, + { rtfDrawAttr, rtfDrawFgFillRed, "dpfillfgcr", 0 }, + { rtfDrawAttr, rtfDrawFgFillPalette, "dpfillfgpal", 0 }, + { rtfDrawAttr, rtfDrawFgFillGray, "dpfillfggray", 0 }, + { rtfDrawAttr, rtfDrawFillPatIndex, "dpfillpat", 0 }, + + { rtfDrawAttr, rtfDrawShadow, "dpshadow", 0 }, + { rtfDrawAttr, rtfDrawShadowXOffset, "dpshadx", 0 }, + { rtfDrawAttr, rtfDrawShadowYOffset, "dpshady", 0 }, + + { rtfVersion, -1, "rtf", 0 }, + { rtfDefFont, -1, "deff", 0 }, + + { 0, -1, (char *) NULL, 0 } +}; + + +/* + * Initialize lookup table hash values. Only need to do this once. + */ + +static void LookupInit(void) +{ + static int inited = 0; + RTFKey *rp; + + if (inited == 0) + { + for (rp = rtfKey; rp->rtfKStr != (char *) NULL; rp++) + rp->rtfKHash = Hash ((char*)rp->rtfKStr); + ++inited; + } +} + + +/* + * Determine major and minor number of control token. If it's + * not found, the class turns into rtfUnknown. + */ + +static void Lookup(RTF_Info *info, char *s) +{ + RTFKey *rp; + int hash; + + TRACE("\n"); + ++s; /* skip over the leading \ character */ + hash = Hash (s); + for (rp = rtfKey; rp->rtfKStr != (char *) NULL; rp++) + { + if (hash == rp->rtfKHash && strcmp (s, rp->rtfKStr) == 0) + { + info->rtfClass = rtfControl; + info->rtfMajor = rp->rtfKMajor; + info->rtfMinor = rp->rtfKMinor; + return; + } + } + info->rtfClass = rtfUnknown; +} + + +/* + * Compute hash value of symbol + */ + +static int Hash(char *s) +{ + char c; + int val = 0; + + while ((c = *s++) != '\0') + val += (int) 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); +} + + +/* ---------------------------------------------------------------------- */ + + +/* + * Token comparison routines + */ + +int RTFCheckCM(RTF_Info *info, int class, int major) +{ + return (info->rtfClass == class && info->rtfMajor == major); +} + + +int RTFCheckCMM(RTF_Info *info, int class, int major, int minor) +{ + return (info->rtfClass == class && info->rtfMajor == major && info->rtfMinor == minor); +} + + +int RTFCheckMM(RTF_Info *info, int major, int minor) +{ + return (info->rtfMajor == major && info->rtfMinor == minor); +} + + +/* ---------------------------------------------------------------------- */ + + +int RTFCharToHex(char c) +{ + if (isupper (c)) + c = tolower (c); + if (isdigit (c)) + return (c - '0'); /* '0'..'9' */ + return (c - 'a' + 10); /* 'a'..'f' */ +} + + +int RTFHexToChar(int i) +{ + if (i < 10) + return (i + '0'); + return (i - 10 + 'a'); +} + + +/* ---------------------------------------------------------------------- */ + +/* + * 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. + * + * 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. + */ + + +void RTFMsg (RTF_Info *info, const char *fmt, ...) +{ + char buf[rtfBufSiz]; + + va_list args; + va_start (args,fmt); + vsprintf (buf, fmt, args); + va_end (args); + MESSAGE( "%s", buf); +} + + +/* ---------------------------------------------------------------------- */ + + +/* + * Process termination. Print error message and exit. Also prints + * current token, and current input line number and position within + * line if any input has been read from the current file. (No input + * has been read if prevChar is EOF). + */ + +static void DefaultPanicProc(RTF_Info *info, char *s) +{ + MESSAGE( "%s", s); + /*exit (1);*/ +} + + + +void RTFPanic(RTF_Info *info, const char *fmt, ...) +{ + char buf[rtfBufSiz]; + + va_list args; + va_start (args,fmt); + vsprintf (buf, fmt, args); + va_end (args); + (void) strcat (buf, "\n"); + if (info->prevChar != EOF && info->rtfTextBuf != (char *) NULL) + { + sprintf (buf + strlen (buf), + "Last token read was \"%s\" near line %ld, position %d.\n", + info->rtfTextBuf, info->rtfLineNum, info->rtfLinePos); + } + DefaultPanicProc(info, buf); +} + +/* ---------------------------------------------------------------------- */ + +/* + * originally from RTF tools' text-writer.c + * + * text-writer -- RTF-to-text translation writer code. + * + * Read RTF input, write text of document (text extraction). + */ + +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); + +/* + * Initialize the writer. + */ + +void +WriterInit (RTF_Info *info ) +{ + RTFReadOutputMap (info, info->outMap,1); +} + + +int +BeginFile (RTF_Info *info ) +{ + /* install class callbacks */ + + RTFSetClassCallback (info, rtfText, TextClass); + RTFSetClassCallback (info, rtfControl, ControlClass); + + 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. + */ + +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); + } +} + + +static void +ControlClass (RTF_Info *info) +{ + TRACE("\n"); + + switch (info->rtfMajor) + { + case rtfDestination: + Destination (info); + break; + case rtfSpecialChar: + SpecialChar (info); + break; + } +} + + +/* + * This function notices destinations that should be ignored + * and skips to their ends. This keeps, for instance, picture + * data from being considered as plain text. + */ + +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; + } +} + + +/* + * 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. + */ + +void SpecialChar (RTF_Info *info) +{ + + TRACE("\n"); + + switch (info->rtfMinor) + { + case rtfPage: + case rtfSect: + case rtfRow: + case rtfLine: + case rtfPar: + PutLitChar (info, '\n'); + break; + case rtfCell: + PutStdChar (info, rtfSC_space); /* make sure cells are separated */ + break; + case rtfNoBrkSpace: + PutStdChar (info, rtfSC_nobrkspace); + break; + case rtfTab: + PutLitChar (info, '\t'); + break; + case rtfNoBrkHyphen: + PutStdChar (info, rtfSC_nobrkhyphen); + break; + case rtfBullet: + PutStdChar (info, rtfSC_bullet); + break; + case rtfEmDash: + PutStdChar (info, rtfSC_emdash); + break; + case rtfEnDash: + PutStdChar (info, rtfSC_endash); + break; + case rtfLQuote: + PutStdChar (info, rtfSC_quoteleft); + break; + case rtfRQuote: + PutStdChar (info, rtfSC_quoteright); + break; + case rtfLDblQuote: + PutStdChar (info, rtfSC_quotedblleft); + break; + case rtfRDblQuote: + PutStdChar (info, rtfSC_quotedblright); + 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) +{ + + 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); +} + +void PutLitChar (RTF_Info *info, int c) +{ + if( info->dwOutputCount >= ( sizeof info->OutputBuffer - 1 ) ) + RTFFlushOutputBuffer( info ); + info->OutputBuffer[info->dwOutputCount++] = c; +} + +void RTFFlushOutputBuffer( RTF_Info *info ) +{ + 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; +} diff --git a/reactos/lib/riched20/riched20.spec b/reactos/lib/riched20/riched20.spec new file mode 100644 index 00000000000..aa71eec8f77 --- /dev/null +++ b/reactos/lib/riched20/riched20.spec @@ -0,0 +1,9 @@ +2 extern IID_IRichEditOle +3 extern IID_IRichEditOleCallback +4 stdcall CreateTextServices(ptr ptr ptr) +5 extern IID_ITextServices +6 extern IID_ITextHost +7 extern IID_ITextHost2 +8 stdcall REExtendedRegisterClass() +9 stdcall RichEdit10ANSIWndProc(ptr long long long) +10 stdcall RichEditANSIWndProc(ptr long long long) diff --git a/reactos/lib/riched20/richole.c b/reactos/lib/riched20/richole.c new file mode 100644 index 00000000000..1c9e4509a75 --- /dev/null +++ b/reactos/lib/riched20/richole.c @@ -0,0 +1,266 @@ +/* + * RichEdit GUIDs and OLE interface + * + * Copyright 2004 by Krzysztof Foltman + * Copyright 2004 Aric Stewart + * + * 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 + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "ole2.h" +#include "richole.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(richedit); + +typedef struct IRichEditOleImpl { + IRichEditOleVtbl *lpVtbl; + DWORD ref; +} IRichEditOleImpl; + +/* there is no way to be consistent across different sets of headers - mingw, Wine, Win32 SDK*/ + +/* FIXME: the next 6 lines should be in textserv.h */ +#define TEXTSERV_GUID(name, l, w1, w2, b1, b2) \ + GUID name = { l, w1, w2, {b1, b2, 0x00, 0xaa, 0x00, 0x6c, 0xad, 0xc5}} + +TEXTSERV_GUID(IID_ITextServices, 0x8d33f740, 0xcf58, 0x11ce, 0xa8, 0x9d); +TEXTSERV_GUID(IID_ITextHost, 0xc5bdd8d0, 0xd26e, 0x11ce, 0xa8, 0x9e); +TEXTSERV_GUID(IID_ITextHost2, 0xc5bdd8d0, 0xd26e, 0x11ce, 0xa8, 0x9e); + +static HRESULT WINAPI +IRichEditOle_fnQueryInterface(IRichEditOle *me, REFIID riid, LPVOID *ppvObj) +{ + IRichEditOleImpl *This = (IRichEditOleImpl *)me; + + TRACE("%p %s\n", This, debugstr_guid(riid) ); + + if (IsEqualGUID(riid, &IID_IUnknown) || + IsEqualGUID(riid, &IID_IRichEditOle)) + { + IRichEditOle_AddRef(me); + *ppvObj = (LPVOID) This; + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG WINAPI +IRichEditOle_fnAddRef(IRichEditOle *me) +{ + IRichEditOleImpl *This = (IRichEditOleImpl *)me; + ULONG ref = InterlockedIncrement( &This->ref ); + + TRACE("%p ref = %lu\n", This, ref); + + return ref; +} + +static ULONG WINAPI +IRichEditOle_fnRelease(IRichEditOle *me) +{ + IRichEditOleImpl *This = (IRichEditOleImpl *)me; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE ("%p ref=%lu\n", This, ref); + + if (!ref) + { + TRACE ("Destroying %p\n", This); + HeapFree(GetProcessHeap(),0,This); + } + return ref; +} + +static HRESULT WINAPI +IRichEditOle_fnActivateAs(IRichEditOle *me, REFCLSID rclsid, REFCLSID rclsidAs) +{ + IRichEditOleImpl *This = (IRichEditOleImpl *)me; + FIXME("stub %p\n",This); + return E_NOTIMPL; +} + +static HRESULT WINAPI +IRichEditOle_fnContextSensitiveHelp(IRichEditOle *me, BOOL fEnterMode) +{ + IRichEditOleImpl *This = (IRichEditOleImpl *)me; + FIXME("stub %p\n",This); + return E_NOTIMPL; +} + +static HRESULT WINAPI +IRichEditOle_fnConvertObject(IRichEditOle *me, LONG iob, + REFCLSID rclsidNew, LPCSTR lpstrUserTypeNew) +{ + IRichEditOleImpl *This = (IRichEditOleImpl *)me; + FIXME("stub %p\n",This); + return E_NOTIMPL; +} + +static HRESULT WINAPI +IRichEditOle_fnGetClientSite(IRichEditOle *me, + LPOLECLIENTSITE *lplpolesite) +{ + IRichEditOleImpl *This = (IRichEditOleImpl *)me; + FIXME("stub %p\n",This); + return E_NOTIMPL; +} + +static HRESULT WINAPI +IRichEditOle_fnGetClipboardData(IRichEditOle *me, CHARRANGE *lpchrg, + DWORD reco, LPDATAOBJECT *lplpdataobj) +{ + IRichEditOleImpl *This = (IRichEditOleImpl *)me; + FIXME("stub %p\n",This); + return E_NOTIMPL; +} + +static LONG WINAPI IRichEditOle_fnGetLinkCount(IRichEditOle *me) +{ + IRichEditOleImpl *This = (IRichEditOleImpl *)me; + FIXME("stub %p\n",This); + return E_NOTIMPL; +} + +static HRESULT WINAPI +IRichEditOle_fnGetObject(IRichEditOle *me, LONG iob, + REOBJECT *lpreobject, DWORD dwFlags) +{ + IRichEditOleImpl *This = (IRichEditOleImpl *)me; + FIXME("stub %p\n",This); + return E_NOTIMPL; +} + +static LONG WINAPI +IRichEditOle_fnGetObjectCount(IRichEditOle *me) +{ + IRichEditOleImpl *This = (IRichEditOleImpl *)me; + FIXME("stub %p\n",This); + return E_NOTIMPL; +} + +static HRESULT WINAPI +IRichEditOle_fnHandsOffStorage(IRichEditOle *me, LONG iob) +{ + IRichEditOleImpl *This = (IRichEditOleImpl *)me; + FIXME("stub %p\n",This); + return E_NOTIMPL; +} + +static HRESULT WINAPI +IRichEditOle_fnImportDataObject(IRichEditOle *me, LPDATAOBJECT lpdataobj, + CLIPFORMAT cf, HGLOBAL hMetaPict) +{ + IRichEditOleImpl *This = (IRichEditOleImpl *)me; + FIXME("stub %p\n",This); + return E_NOTIMPL; +} + +static HRESULT WINAPI +IRichEditOle_fnInPlaceDeactivate(IRichEditOle *me) +{ + IRichEditOleImpl *This = (IRichEditOleImpl *)me; + FIXME("stub %p\n",This); + return E_NOTIMPL; +} + +static HRESULT WINAPI +IRichEditOle_fnInsertObject(IRichEditOle *me, REOBJECT *lpreobject) +{ + IRichEditOleImpl *This = (IRichEditOleImpl *)me; + FIXME("stub %p\n",This); + return E_NOTIMPL; +} + +static HRESULT WINAPI IRichEditOle_fnSaveCompleted(IRichEditOle *me, LONG iob, + LPSTORAGE lpstg) +{ + IRichEditOleImpl *This = (IRichEditOleImpl *)me; + FIXME("stub %p\n",This); + return E_NOTIMPL; +} + +static HRESULT WINAPI +IRichEditOle_fnSetDvaspect(IRichEditOle *me, LONG iob, DWORD dvaspect) +{ + IRichEditOleImpl *This = (IRichEditOleImpl *)me; + FIXME("stub %p\n",This); + return E_NOTIMPL; +} + +static HRESULT WINAPI IRichEditOle_fnSetHostNames(IRichEditOle *me, + LPCSTR lpstrContainerApp, LPCSTR lpstrContainerObj) +{ + IRichEditOleImpl *This = (IRichEditOleImpl *)me; + FIXME("stub %p\n",This); + return E_NOTIMPL; +} + +static HRESULT WINAPI +IRichEditOle_fnSetLinkAvailable(IRichEditOle *me, LONG iob, BOOL fAvailable) +{ + IRichEditOleImpl *This = (IRichEditOleImpl *)me; + FIXME("stub %p\n",This); + return E_NOTIMPL; +} + +static IRichEditOleVtbl revt = { + IRichEditOle_fnQueryInterface, + IRichEditOle_fnAddRef, + IRichEditOle_fnRelease, + IRichEditOle_fnGetClientSite, + IRichEditOle_fnGetObjectCount, + IRichEditOle_fnGetLinkCount, + IRichEditOle_fnGetObject, + IRichEditOle_fnInsertObject, + IRichEditOle_fnConvertObject, + IRichEditOle_fnActivateAs, + IRichEditOle_fnSetHostNames, + IRichEditOle_fnSetLinkAvailable, + IRichEditOle_fnSetDvaspect, + IRichEditOle_fnHandsOffStorage, + IRichEditOle_fnSaveCompleted, + IRichEditOle_fnInPlaceDeactivate, + IRichEditOle_fnContextSensitiveHelp, + IRichEditOle_fnGetClipboardData, + IRichEditOle_fnImportDataObject +}; + +LRESULT CreateIRichEditOle(LPVOID *ppObj) +{ + IRichEditOleImpl *reo; + + reo = HeapAlloc(GetProcessHeap(), 0, sizeof(IRichEditOleImpl)); + if (!reo) + return 0; + + reo->lpVtbl = &revt; + reo->ref = 1; + TRACE("Created %p\n",reo); + *ppObj = (LPVOID) reo; + + return 1; +} diff --git a/reactos/lib/riched20/row.c b/reactos/lib/riched20/row.c new file mode 100644 index 00000000000..1e4e208a97a --- /dev/null +++ b/reactos/lib/riched20/row.c @@ -0,0 +1,84 @@ +/* + * RichEdit - Operations on rows of text (rows are recreated during + * wrapping and are used for displaying the document, they don't keep any + * true document content; delete all rows, rewrap all paragraphs and + * you get them back). + * + * Copyright 2004 by Krzysztof Foltman + * + * 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" + +ME_DisplayItem *ME_FindRowStart(ME_Context *c, ME_DisplayItem *item, + int nRelPos) { + ME_DisplayItem *para = ME_GetParagraph(item); + ME_MustBeWrapped(c, para); + if(nRelPos>=0) { /* if this or preceding row */ + while(nRelPos<=0) { + ME_DisplayItem *item2 = ME_FindItemBack(item, diStartRowOrParagraph); + if (item2->type == diParagraph) + { + if (item2->member.para.prev_para == NULL) + return item; + /* if skipping to the preceding paragraph, ensure it's wrapped */ + ME_MustBeWrapped(c, item2->member.para.prev_para); + item = item2; + continue; + } + else if (item2->type == diStartRow) + { + nRelPos++; + if (nRelPos>0) + return item; + item = item2; + continue; + } + assert(0 == "bug in FindItemBack(item, diStartRowOrParagraph)"); + item = item2; + } + return item; + } + while(nRelPos>0) { /* if one of the next rows */ + ME_DisplayItem *item2 = ME_FindItemFwd(item, diStartRowOrParagraph); + if (!item2) + return item; + if (item2->type == diParagraph) + { + if (item2->member.para.next_para == NULL) + return item; + continue; + } + item = item2; + nRelPos--; + } + return item; +} + +/* I'm sure these functions would simplify some code in caret ops etc, + * I just didn't remember them when I wrote that code + */ + +ME_DisplayItem *ME_RowStart(ME_DisplayItem *item) { + return ME_FindItemBackOrHere(item, diStartRow); +} + +ME_DisplayItem *ME_RowEnd(ME_DisplayItem *item) { + ME_DisplayItem *item2 = ME_FindItemFwd(item, diStartRowOrParagraphOrEnd); + if (!item2) return NULL; + return ME_FindItemBack(item, diRun); +} diff --git a/reactos/lib/riched20/rtf.h b/reactos/lib/riched20/rtf.h new file mode 100644 index 00000000000..2704ae0504d --- /dev/null +++ b/reactos/lib/riched20/rtf.h @@ -0,0 +1,1570 @@ +#ifndef _RTF +#define _RTF + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#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. + */ + + +/* + * Twentieths of a point (twips) per inch (Many RTF measurements + * are in twips per inch (tpi) units). Assumes 72 points/inch. + */ + +# define rtfTpi 1440 + +/* + * RTF buffer size (avoids BUFSIZ, which differs across systems) + */ + +# define rtfBufSiz 1024 + +/* + * Tokens are associated with up to three classification numbers: + * + * Class number: Broadest (least detailed) breakdown. For programs + * that only care about gross token distinctions. + * Major/minor numbers: Within their class, tokens have a major + * number, and may also have a minor number to further + * distinquish tokens with the same major number. + * + * *** Class, major and minor token numbers are all >= 0 *** + * + * Tokens that can't be classified are put in the "unknown" class. + * For such, the major and minor numbers are meaningless, although + * rtfTextBuf may be of interest then. + * + * Text tokens are a single character, and the major number indicates + * the character value (note: can be non-ascii, i.e., greater than 127). + * There is no minor number. + * + * Control symbols may have a parameter value, which will be found in + * rtfParam. If no parameter was given, rtfParam = rtfNoParam. + * + * RTFGetToken() return value is the class number, but it sets all the + * global token vars. + * + * rtfEOF is a fake token used by the reader; the writer never sees + * it (except in the token reader hook, if it installs one). + */ + + +# ifdef THINK_C +# define rtfNoParam (-32768) /* 16-bit max. neg. value */ +# endif +# ifndef rtfNoParam +# define rtfNoParam (-1000000) +# endif + + + + +/* + * For some reason, the no-style number is 222 + */ + +# define rtfNoStyleNum 222 +# define rtfNormalStyleNum 0 + + +/* + * Token classes (must be zero-based and sequential) + */ + +# define rtfUnknown 0 +# define rtfGroup 1 +# define rtfText 2 +# define rtfControl 3 +# define rtfEOF 4 +# define rtfMaxClass 5 /* highest class + 1 */ + +/* + * Group class major numbers + */ + +# define rtfBeginGroup 0 +# define rtfEndGroup 1 + +/* + * Control class major and minor numbers. + */ + +# define rtfVersion 0 + +# define rtfDefFont 1 + +# define rtfCharSet 2 +# define rtfAnsiCharSet 0 +# define rtfMacCharSet 1 +# define rtfPcCharSet 2 +# define rtfPcaCharSet 3 + + +/* destination minor numbers should be zero-based and sequential */ + +# define rtfDestination 3 +# define rtfFontTbl 0 +# define rtfFontAltName 1 /* new in 1.10 */ +# define rtfEmbeddedFont 2 /* new in 1.10 */ +# define rtfFontFile 3 /* new in 1.10 */ +# define rtfFileTbl 4 /* new in 1.10 */ +# define rtfFileInfo 5 /* new in 1.10 */ +# define rtfColorTbl 6 +# define rtfStyleSheet 7 +# define rtfKeyCode 8 +# define rtfRevisionTbl 9 /* new in 1.10 */ +# define rtfInfo 10 +# define rtfITitle 11 +# define rtfISubject 12 +# define rtfIAuthor 13 +# define rtfIOperator 14 +# define rtfIKeywords 15 +# define rtfIComment 16 +# define rtfIVersion 17 +# define rtfIDoccomm 18 +# define rtfIVerscomm 19 +# define rtfNextFile 20 /* reclassified in 1.10 */ +# define rtfTemplate 21 /* reclassified in 1.10 */ +# define rtfFNSep 22 +# define rtfFNContSep 23 +# define rtfFNContNotice 24 +# define rtfENSep 25 /* new in 1.10 */ +# define rtfENContSep 26 /* new in 1.10 */ +# define rtfENContNotice 27 /* new in 1.10 */ +# define rtfPageNumLevel 28 /* new in 1.10 */ +# define rtfParNumLevelStyle 29 /* new in 1.10 */ +# define rtfHeader 30 +# define rtfFooter 31 +# define rtfHeaderLeft 32 +# define rtfHeaderRight 33 +# define rtfHeaderFirst 34 +# define rtfFooterLeft 35 +# define rtfFooterRight 36 +# define rtfFooterFirst 37 +# define rtfParNumText 38 /* new in 1.10 */ +# define rtfParNumbering 39 /* new in 1.10 */ +# define rtfParNumTextAfter 40 /* new in 1.10 */ +# define rtfParNumTextBefore 41 /* new in 1.10 */ +# define rtfBookmarkStart 42 +# define rtfBookmarkEnd 43 +# define rtfPict 44 +# define rtfObject 45 +# define rtfObjClass 46 +# define rtfObjName 47 +# define rtfObjTime 48 /* new in 1.10 */ +# define rtfObjData 49 +# define rtfObjAlias 50 +# define rtfObjSection 51 +# define rtfObjResult 52 +# define rtfObjItem 53 /* new in 1.10 */ +# define rtfObjTopic 54 /* new in 1.10 */ +# define rtfDrawObject 55 /* new in 1.10 */ +# define rtfFootnote 56 +# define rtfAnnotRefStart 57 /* new in 1.10 */ +# define rtfAnnotRefEnd 58 /* new in 1.10 */ +# define rtfAnnotID 59 /* reclassified in 1.10 */ +# define rtfAnnotAuthor 60 /* new in 1.10 */ +# define rtfAnnotation 61 /* reclassified in 1.10 */ +# define rtfAnnotRef 62 /* new in 1.10 */ +# define rtfAnnotTime 63 /* new in 1.10 */ +# define rtfAnnotIcon 64 /* new in 1.10 */ +# define rtfField 65 +# define rtfFieldInst 66 +# define rtfFieldResult 67 +# define rtfDataField 68 /* new in 1.10 */ +# define rtfIndex 69 +# define rtfIndexText 70 +# define rtfIndexRange 71 +# define rtfTOC 72 +# define rtfNeXTGraphic 73 +# define rtfMaxDestination 74 /* highest dest + 1 */ + +# define rtfFontFamily 4 +# define rtfFFNil 0 +# define rtfFFRoman 1 +# define rtfFFSwiss 2 +# define rtfFFModern 3 +# define rtfFFScript 4 +# define rtfFFDecor 5 +# define rtfFFTech 6 +# define rtfFFBidirectional 7 /* new in 1.10 */ + +# define rtfColorName 5 +# define rtfRed 0 +# define rtfGreen 1 +# define rtfBlue 2 + +# define rtfSpecialChar 6 + /* special chars seen in \info destination */ +# define rtfIIntVersion 0 +# define rtfICreateTime 1 +# define rtfIRevisionTime 2 +# define rtfIPrintTime 3 +# define rtfIBackupTime 4 +# define rtfIEditTime 5 +# define rtfIYear 6 +# define rtfIMonth 7 +# define rtfIDay 8 +# define rtfIHour 9 +# define rtfIMinute 10 +# define rtfISecond 11 /* new in 1.10 */ +# define rtfINPages 12 +# define rtfINWords 13 +# define rtfINChars 14 +# define rtfIIntID 15 + /* other special chars */ +# define rtfCurHeadDate 16 +# define rtfCurHeadDateLong 17 +# define rtfCurHeadDateAbbrev 18 +# define rtfCurHeadTime 19 +# define rtfCurHeadPage 20 +# define rtfSectNum 21 /* new in 1.10 */ +# define rtfCurFNote 22 +# define rtfCurAnnotRef 23 +# define rtfFNoteSep 24 +# define rtfFNoteCont 25 +# define rtfCell 26 +# define rtfRow 27 +# define rtfPar 28 +# define rtfSect 29 +# define rtfPage 30 +# define rtfColumn 31 +# define rtfLine 32 +# define rtfSoftPage 33 /* new in 1.10 */ +# define rtfSoftColumn 34 /* new in 1.10 */ +# define rtfSoftLine 35 /* new in 1.10 */ +# define rtfSoftLineHt 36 /* new in 1.10 */ +# define rtfTab 37 +# define rtfEmDash 38 +# define rtfEnDash 39 +# define rtfEmSpace 40 /* new in 1.10 */ +# define rtfEnSpace 41 /* new in 1.10 */ +# define rtfBullet 42 +# define rtfLQuote 43 +# define rtfRQuote 44 +# define rtfLDblQuote 45 +# define rtfRDblQuote 46 +# define rtfFormula 47 +# define rtfNoBrkSpace 49 +# define rtfNoReqHyphen 50 +# define rtfNoBrkHyphen 51 +# define rtfOptDest 52 +# define rtfLTRMark 53 /* new in 1.10 */ +# define rtfRTLMark 54 /* new in 1.10 */ +# define rtfNoWidthJoiner 55 /* new in 1.10 */ +# define rtfNoWidthNonJoiner 56 /* new in 1.10 */ +# define rtfCurHeadPict 57 /* valid? */ +/*# define rtfCurAnnot 58*/ /* apparently not used */ + +# define rtfStyleAttr 7 +# define rtfAdditive 0 /* new in 1.10 */ +# define rtfBasedOn 1 +# define rtfNext 2 + +# define rtfDocAttr 8 +# define rtfDefTab 0 +# define rtfHyphHotZone 1 +# define rtfHyphConsecLines 2 /* new in 1.10 */ +# define rtfHyphCaps 3 /* new in 1.10 */ +# define rtfHyphAuto 4 /* new in 1.10 */ +# define rtfLineStart 5 +# define rtfFracWidth 6 +# define rtfMakeBackup 7 +# define rtfRTFDefault 8 +# define rtfPSOverlay 9 +# define rtfDocTemplate 10 /* new in 1.10 */ +# define rtfDefLanguage 11 +# define rtfFENoteType 12 /* new in 1.10 */ +# define rtfFNoteEndSect 13 +# define rtfFNoteEndDoc 14 +# define rtfFNoteText 15 +# define rtfFNoteBottom 16 +# define rtfENoteEndSect 17 /* new in 1.10 */ +# define rtfENoteEndDoc 18 /* new in 1.10 */ +# define rtfENoteText 19 /* new in 1.10 */ +# define rtfENoteBottom 20 /* new in 1.10 */ +# define rtfFNoteStart 21 +# define rtfENoteStart 22 /* new in 1.10 */ +# define rtfFNoteRestartPage 23 /* new in 1.10 */ +# define rtfFNoteRestart 24 +# define rtfFNoteRestartCont 25 /* new in 1.10 */ +# define rtfENoteRestart 26 /* new in 1.10 */ +# define rtfENoteRestartCont 27 /* new in 1.10 */ +# define rtfFNoteNumArabic 28 /* new in 1.10 */ +# define rtfFNoteNumLLetter 29 /* new in 1.10 */ +# define rtfFNoteNumULetter 30 /* new in 1.10 */ +# define rtfFNoteNumLRoman 31 /* new in 1.10 */ +# define rtfFNoteNumURoman 32 /* new in 1.10 */ +# define rtfFNoteNumChicago 33 /* new in 1.10 */ +# define rtfENoteNumArabic 34 /* new in 1.10 */ +# define rtfENoteNumLLetter 35 /* new in 1.10 */ +# define rtfENoteNumULetter 36 /* new in 1.10 */ +# define rtfENoteNumLRoman 37 /* new in 1.10 */ +# define rtfENoteNumURoman 38 /* new in 1.10 */ +# define rtfENoteNumChicago 39 /* new in 1.10 */ +# define rtfPaperWidth 40 +# define rtfPaperHeight 41 +# define rtfPaperSize 42 /* new in 1.10 */ +# define rtfLeftMargin 43 +# define rtfRightMargin 44 +# define rtfTopMargin 45 +# define rtfBottomMargin 46 +# define rtfFacingPage 47 +# define rtfGutterWid 48 +# define rtfMirrorMargin 49 +# define rtfLandscape 50 +# define rtfPageStart 51 +# define rtfWidowCtrl 52 +# define rtfLinkStyles 53 /* new in 1.10 */ +# define rtfNoAutoTabIndent 54 /* new in 1.10 */ +# define rtfWrapSpaces 55 /* new in 1.10 */ +# define rtfPrintColorsBlack 56 /* new in 1.10 */ +# define rtfNoExtraSpaceRL 57 /* new in 1.10 */ +# define rtfNoColumnBalance 58 /* new in 1.10 */ +# define rtfCvtMailMergeQuote 59 /* new in 1.10 */ +# define rtfSuppressTopSpace 60 /* new in 1.10 */ +# define rtfSuppressPreParSpace 61 /* new in 1.10 */ +# define rtfCombineTblBorders 62 /* new in 1.10 */ +# define rtfTranspMetafiles 63 /* new in 1.10 */ +# define rtfSwapBorders 64 /* new in 1.10 */ +# define rtfShowHardBreaks 65 /* new in 1.10 */ +# define rtfFormProtected 66 /* new in 1.10 */ +# define rtfAllProtected 67 /* new in 1.10 */ +# define rtfFormShading 68 /* new in 1.10 */ +# define rtfFormDisplay 69 /* new in 1.10 */ +# define rtfPrintData 70 /* new in 1.10 */ +# define rtfRevProtected 71 /* new in 1.10 */ +# define rtfRevisions 72 +# define rtfRevDisplay 73 +# define rtfRevBar 74 +# define rtfAnnotProtected 75 /* new in 1.10 */ +# define rtfRTLDoc 76 /* new in 1.10 */ +# define rtfLTRDoc 77 /* new in 1.10 */ + +# define rtfSectAttr 9 +# define rtfSectDef 0 +# define rtfENoteHere 1 +# define rtfPrtBinFirst 2 +# define rtfPrtBin 3 +# define rtfSectStyleNum 4 /* new in 1.10 */ +# define rtfNoBreak 5 +# define rtfColBreak 6 +# define rtfPageBreak 7 +# define rtfEvenBreak 8 +# define rtfOddBreak 9 +# define rtfColumns 10 +# define rtfColumnSpace 11 +# define rtfColumnNumber 12 /* new in 1.10 */ +# define rtfColumnSpRight 13 /* new in 1.10 */ +# define rtfColumnWidth 14 /* new in 1.10 */ +# define rtfColumnLine 15 +# define rtfLineModulus 16 +# define rtfLineDist 17 +# define rtfLineStarts 18 +# define rtfLineRestart 19 +# define rtfLineRestartPg 20 +# define rtfLineCont 21 +# define rtfSectPageWid 22 +# define rtfSectPageHt 23 +# define rtfSectMarginLeft 24 +# define rtfSectMarginRight 25 +# define rtfSectMarginTop 26 +# define rtfSectMarginBottom 27 +# define rtfSectMarginGutter 28 +# define rtfSectLandscape 29 +# define rtfTitleSpecial 30 +# define rtfHeaderY 31 +# define rtfFooterY 32 +# define rtfPageStarts 33 +# define rtfPageCont 34 +# define rtfPageRestart 35 +# define rtfPageNumRight 36 /* renamed in 1.10 */ +# define rtfPageNumTop 37 +# define rtfPageDecimal 38 +# define rtfPageURoman 39 +# define rtfPageLRoman 40 +# define rtfPageULetter 41 +# define rtfPageLLetter 42 +# define rtfPageNumHyphSep 43 /* new in 1.10 */ +# define rtfPageNumSpaceSep 44 /* new in 1.10 */ +# define rtfPageNumColonSep 45 /* new in 1.10 */ +# define rtfPageNumEmdashSep 46 /* new in 1.10 */ +# define rtfPageNumEndashSep 47 /* new in 1.10 */ +# define rtfTopVAlign 48 +# define rtfBottomVAlign 49 +# define rtfCenterVAlign 50 +# define rtfJustVAlign 51 +# define rtfRTLSect 52 /* new in 1.10 */ +# define rtfLTRSect 53 /* new in 1.10 */ + +# define rtfTblAttr 10 +# define rtfRowDef 0 +# define rtfRowGapH 1 +# define rtfCellPos 2 +# define rtfMergeRngFirst 3 +# define rtfMergePrevious 4 +# define rtfRowLeft 5 +# define rtfRowRight 6 +# define rtfRowCenter 7 +# define rtfRowLeftEdge 8 +# define rtfRowHt 9 +# define rtfRowHeader 10 /* new in 1.10 */ +# define rtfRowKeep 11 /* new in 1.10 */ +# define rtfRTLRow 12 /* new in 1.10 */ +# define rtfLTRRow 13 /* new in 1.10 */ +# define rtfRowBordTop 14 /* new in 1.10 */ +# define rtfRowBordLeft 15 /* new in 1.10 */ +# define rtfRowBordBottom 16 /* new in 1.10 */ +# define rtfRowBordRight 17 /* new in 1.10 */ +# define rtfRowBordHoriz 18 /* new in 1.10 */ +# define rtfRowBordVert 19 /* new in 1.10 */ +# define rtfCellBordBottom 20 +# define rtfCellBordTop 21 +# define rtfCellBordLeft 22 +# define rtfCellBordRight 23 +# define rtfCellShading 24 +# define rtfCellBgPatH 25 +# define rtfCellBgPatV 26 +# define rtfCellFwdDiagBgPat 27 +# define rtfCellBwdDiagBgPat 28 +# define rtfCellHatchBgPat 29 +# define rtfCellDiagHatchBgPat 30 +# define rtfCellDarkBgPatH 31 +# define rtfCellDarkBgPatV 32 +# define rtfCellFwdDarkBgPat 33 +# define rtfCellBwdDarkBgPat 34 +# define rtfCellDarkHatchBgPat 35 +# define rtfCellDarkDiagHatchBgPat 36 +# define rtfCellBgPatLineColor 37 +# define rtfCellBgPatColor 38 + +# define rtfParAttr 11 +# define rtfParDef 0 +# define rtfStyleNum 1 +# define rtfHyphenate 2 /* new in 1.10 */ +# define rtfInTable 3 +# define rtfKeep 4 +# define rtfNoWidowControl 5 /* new in 1.10 */ +# define rtfKeepNext 6 +# define rtfOutlineLevel 7 /* new in 1.10 */ +# define rtfNoLineNum 8 +# define rtfPBBefore 9 +# define rtfSideBySide 10 +# define rtfQuadLeft 11 +# define rtfQuadRight 12 +# define rtfQuadJust 13 +# define rtfQuadCenter 14 +# define rtfFirstIndent 15 +# define rtfLeftIndent 16 +# define rtfRightIndent 17 +# define rtfSpaceBefore 18 +# define rtfSpaceAfter 19 +# define rtfSpaceBetween 20 +# define rtfSpaceMultiply 21 /* new in 1.10 */ +# define rtfSubDocument 22 /* new in 1.10 */ +# define rtfRTLPar 23 /* new in 1.10 */ +# define rtfLTRPar 24 /* new in 1.10 */ +# define rtfTabPos 25 +# define rtfTabLeft 26 /* new in 1.10 */ +# define rtfTabRight 27 +# define rtfTabCenter 28 +# define rtfTabDecimal 29 +# define rtfTabBar 30 +# define rtfLeaderDot 31 +# define rtfLeaderHyphen 32 +# define rtfLeaderUnder 33 +# define rtfLeaderThick 34 +# define rtfLeaderEqual 35 +# define rtfParLevel 36 /* new in 1.10 */ +# define rtfParBullet 37 /* new in 1.10 */ +# define rtfParSimple 38 /* new in 1.10 */ +# define rtfParNumCont 39 /* new in 1.10 */ +# define rtfParNumOnce 40 /* new in 1.10 */ +# define rtfParNumAcross 41 /* new in 1.10 */ +# define rtfParHangIndent 42 /* new in 1.10 */ +# define rtfParNumRestart 43 /* new in 1.10 */ +# define rtfParNumCardinal 44 /* new in 1.10 */ +# define rtfParNumDecimal 45 /* new in 1.10 */ +# define rtfParNumULetter 46 /* new in 1.10 */ +# define rtfParNumURoman 47 /* new in 1.10 */ +# define rtfParNumLLetter 48 /* new in 1.10 */ +# define rtfParNumLRoman 49 /* new in 1.10 */ +# define rtfParNumOrdinal 50 /* new in 1.10 */ +# define rtfParNumOrdinalText 51 /* new in 1.10 */ +# define rtfParNumBold 52 /* new in 1.10 */ +# define rtfParNumItalic 53 /* new in 1.10 */ +# define rtfParNumAllCaps 54 /* new in 1.10 */ +# define rtfParNumSmallCaps 55 /* new in 1.10 */ +# define rtfParNumUnder 56 /* new in 1.10 */ +# define rtfParNumDotUnder 57 /* new in 1.10 */ +# define rtfParNumDbUnder 58 /* new in 1.10 */ +# define rtfParNumNoUnder 59 /* new in 1.10 */ +# define rtfParNumWordUnder 60 /* new in 1.10 */ +# define rtfParNumStrikethru 61 /* new in 1.10 */ +# define rtfParNumForeColor 62 /* new in 1.10 */ +# define rtfParNumFont 63 /* new in 1.10 */ +# define rtfParNumFontSize 64 /* new in 1.10 */ +# define rtfParNumIndent 65 /* new in 1.10 */ +# define rtfParNumSpacing 66 /* new in 1.10 */ +# define rtfParNumInclPrev 67 /* new in 1.10 */ +# define rtfParNumCenter 68 /* new in 1.10 */ +# define rtfParNumLeft 69 /* new in 1.10 */ +# define rtfParNumRight 70 /* new in 1.10 */ +# define rtfParNumStartAt 71 /* new in 1.10 */ +# define rtfBorderTop 72 +# define rtfBorderBottom 73 +# define rtfBorderLeft 74 +# define rtfBorderRight 75 +# define rtfBorderBetween 76 +# define rtfBorderBar 77 +# define rtfBorderBox 78 +# define rtfBorderSingle 79 +# define rtfBorderThick 80 +# define rtfBorderShadow 81 +# define rtfBorderDouble 82 +# define rtfBorderDot 83 +# define rtfBorderDash 84 /* new in 1.10 */ +# define rtfBorderHair 85 +# define rtfBorderWidth 86 +# define rtfBorderColor 87 +# define rtfBorderSpace 88 +# define rtfShading 89 +# define rtfBgPatH 90 +# define rtfBgPatV 91 +# define rtfFwdDiagBgPat 92 +# define rtfBwdDiagBgPat 93 +# define rtfHatchBgPat 94 +# define rtfDiagHatchBgPat 95 +# define rtfDarkBgPatH 96 +# define rtfDarkBgPatV 97 +# define rtfFwdDarkBgPat 98 +# define rtfBwdDarkBgPat 99 +# define rtfDarkHatchBgPat 100 +# define rtfDarkDiagHatchBgPat 101 +# define rtfBgPatLineColor 102 +# define rtfBgPatColor 103 + +# define rtfCharAttr 12 +# define rtfPlain 0 +# define rtfBold 1 +# define rtfAllCaps 2 +# define rtfDeleted 3 +# define rtfSubScript 4 +# define rtfSubScrShrink 5 /* new in 1.10 */ +# define rtfNoSuperSub 6 /* new in 1.10 */ +# define rtfExpand 7 +# define rtfExpandTwips 8 /* new in 1.10 */ +# define rtfKerning 9 /* new in 1.10 */ +# define rtfFontNum 10 +# define rtfFontSize 11 +# define rtfItalic 12 +# define rtfOutline 13 +# define rtfRevised 14 +# define rtfRevAuthor 15 /* new in 1.10 */ +# define rtfRevDTTM 16 /* new in 1.10 */ +# define rtfSmallCaps 17 +# define rtfShadow 18 +# define rtfStrikeThru 19 +# define rtfUnderline 20 +# define rtfDotUnderline 21 /* renamed in 1.10 */ +# define rtfDbUnderline 22 +# define rtfNoUnderline 23 +# define rtfWordUnderline 24 /* renamed in 1.10 */ +# define rtfSuperScript 25 +# define rtfSuperScrShrink 26 /* new in 1.10 */ +# define rtfInvisible 27 +# define rtfForeColor 28 +# define rtfBackColor 29 +# define rtfRTLChar 30 /* new in 1.10 */ +# define rtfLTRChar 31 /* new in 1.10 */ +# define rtfCharStyleNum 32 /* new in 1.10 */ +# define rtfCharCharSet 33 /* new in 1.10 */ +# define rtfLanguage 34 +# define rtfGray 35 + +# define rtfPictAttr 13 +# define rtfMacQD 0 +# define rtfPMMetafile 1 +# define rtfWinMetafile 2 +# define rtfDevIndBitmap 3 +# define rtfWinBitmap 4 +# define rtfPixelBits 5 +# define rtfBitmapPlanes 6 +# define rtfBitmapWid 7 +# define rtfPicWid 8 +# define rtfPicHt 9 +# define rtfPicGoalWid 10 +# define rtfPicGoalHt 11 +# define rtfPicScaleX 12 +# define rtfPicScaleY 13 +# define rtfPicScaled 14 +# define rtfPicCropTop 15 +# define rtfPicCropBottom 16 +# define rtfPicCropLeft 17 +# define rtfPicCropRight 18 +# define rtfPicMFHasBitmap 19 /* new in 1.10 */ +# define rtfPicMFBitsPerPixel 20 /* new in 1.10 */ +# define rtfPicBinary 21 + +# define rtfBookmarkAttr 14 +# define rtfBookmarkFirstCol 0 +# define rtfBookmarkLastCol 1 + +# define rtfNeXTGrAttr 15 +# define rtfNeXTGWidth 0 +# define rtfNeXTGHeight 1 + +# define rtfFieldAttr 16 +# define rtfFieldDirty 0 +# define rtfFieldEdited 1 +# define rtfFieldLocked 2 +# define rtfFieldPrivate 3 +# define rtfFieldAlt 4 /* new in 1.10 */ + +# define rtfTOCAttr 17 +# define rtfTOCType 0 +# define rtfTOCLevel 1 + +# define rtfPosAttr 18 +# define rtfAbsWid 0 +# define rtfAbsHt 1 +# define rtfRPosMargH 2 +# define rtfRPosPageH 3 +# define rtfRPosColH 4 +# define rtfPosX 5 +# define rtfPosNegX 6 /* new in 1.10 */ +# define rtfPosXCenter 7 +# define rtfPosXInside 8 +# define rtfPosXOutSide 9 +# define rtfPosXRight 10 +# define rtfPosXLeft 11 +# define rtfRPosMargV 12 +# define rtfRPosPageV 13 +# define rtfRPosParaV 14 +# define rtfPosY 15 +# define rtfPosNegY 16 /* new in 1.10 */ +# define rtfPosYInline 17 +# define rtfPosYTop 18 +# define rtfPosYCenter 19 +# define rtfPosYBottom 20 +# define rtfNoWrap 21 +# define rtfDistFromTextAll 22 /* renamed in 1.10 */ +# define rtfDistFromTextX 23 /* new in 1.10 */ +# define rtfDistFromTextY 24 /* new in 1.10 */ +# define rtfTextDistY 25 +# define rtfDropCapLines 26 /* new in 1.10 */ +# define rtfDropCapType 27 /* new in 1.10 */ + +# define rtfObjAttr 19 +# define rtfObjEmb 0 +# define rtfObjLink 1 +# define rtfObjAutoLink 2 +# define rtfObjSubscriber 3 +# define rtfObjPublisher 4 /* new in 1.10 */ +# define rtfObjICEmb 5 +# define rtfObjLinkSelf 6 +# define rtfObjLock 7 +# define rtfObjUpdate 8 /* new in 1.10 */ +# define rtfObjHt 9 +# define rtfObjWid 10 +# define rtfObjSetSize 11 +# define rtfObjAlign 12 /* new in 1.10 */ +# define rtfObjTransposeY 13 +# define rtfObjCropTop 14 +# define rtfObjCropBottom 15 +# define rtfObjCropLeft 16 +# define rtfObjCropRight 17 +# define rtfObjScaleX 18 +# define rtfObjScaleY 19 +# define rtfObjResRTF 20 +# define rtfObjResPict 21 +# define rtfObjResBitmap 22 +# define rtfObjResText 23 +# define rtfObjResMerge 24 +# define rtfObjBookmarkPubObj 25 +# define rtfObjPubAutoUpdate 26 + +# define rtfFNoteAttr 20 /* new in 1.10 */ +# define rtfFNAlt 0 /* new in 1.10 */ + +# define rtfKeyCodeAttr 21 /* new in 1.10 */ +# define rtfAltKey 0 /* new in 1.10 */ +# define rtfShiftKey 1 /* new in 1.10 */ +# define rtfControlKey 2 /* new in 1.10 */ +# define rtfFunctionKey 3 /* new in 1.10 */ + +# define rtfACharAttr 22 /* new in 1.10 */ +# define rtfACBold 0 /* new in 1.10 */ +# define rtfACAllCaps 1 /* new in 1.10 */ +# define rtfACForeColor 2 /* new in 1.10 */ +# define rtfACSubScript 3 /* new in 1.10 */ +# define rtfACExpand 4 /* new in 1.10 */ +# define rtfACFontNum 5 /* new in 1.10 */ +# define rtfACFontSize 6 /* new in 1.10 */ +# define rtfACItalic 7 /* new in 1.10 */ +# define rtfACLanguage 8 /* new in 1.10 */ +# define rtfACOutline 9 /* new in 1.10 */ +# define rtfACSmallCaps 10 /* new in 1.10 */ +# define rtfACShadow 11 /* new in 1.10 */ +# define rtfACStrikeThru 12 /* new in 1.10 */ +# define rtfACUnderline 13 /* new in 1.10 */ +# define rtfACDotUnderline 14 /* new in 1.10 */ +# define rtfACDbUnderline 15 /* new in 1.10 */ +# define rtfACNoUnderline 16 /* new in 1.10 */ +# define rtfACWordUnderline 17 /* new in 1.10 */ +# define rtfACSuperScript 18 /* new in 1.10 */ + +# define rtfFontAttr 23 /* new in 1.10 */ +# define rtfFontCharSet 0 /* new in 1.10 */ +# define rtfFontPitch 1 /* new in 1.10 */ +# define rtfFontCodePage 2 /* new in 1.10 */ +# define rtfFTypeNil 3 /* new in 1.10 */ +# define rtfFTypeTrueType 4 /* new in 1.10 */ + +# define rtfFileAttr 24 /* new in 1.10 */ +# define rtfFileNum 0 /* new in 1.10 */ +# define rtfFileRelPath 1 /* new in 1.10 */ +# define rtfFileOSNum 2 /* new in 1.10 */ + +# define rtfFileSource 25 /* new in 1.10 */ +# define rtfSrcMacintosh 0 /* new in 1.10 */ +# define rtfSrcDOS 1 /* new in 1.10 */ +# define rtfSrcNTFS 2 /* new in 1.10 */ +# define rtfSrcHPFS 3 /* new in 1.10 */ +# define rtfSrcNetwork 4 /* new in 1.10 */ + +/* + * Drawing attributes + */ + +# define rtfDrawAttr 26 /* new in 1.10 */ +# define rtfDrawLock 0 /* new in 1.10 */ +# define rtfDrawPageRelX 1 /* new in 1.10 */ +# define rtfDrawColumnRelX 2 /* new in 1.10 */ +# define rtfDrawMarginRelX 3 /* new in 1.10 */ +# define rtfDrawPageRelY 4 /* new in 1.10 */ +# define rtfDrawColumnRelY 5 /* new in 1.10 */ +# define rtfDrawMarginRelY 6 /* new in 1.10 */ +# define rtfDrawHeight 7 /* new in 1.10 */ + +# define rtfDrawBeginGroup 8 /* new in 1.10 */ +# define rtfDrawGroupCount 9 /* new in 1.10 */ +# define rtfDrawEndGroup 10 /* new in 1.10 */ +# define rtfDrawArc 11 /* new in 1.10 */ +# define rtfDrawCallout 12 /* new in 1.10 */ +# define rtfDrawEllipse 13 /* new in 1.10 */ +# define rtfDrawLine 14 /* new in 1.10 */ +# define rtfDrawPolygon 15 /* new in 1.10 */ +# define rtfDrawPolyLine 16 /* new in 1.10 */ +# define rtfDrawRect 17 /* new in 1.10 */ +# define rtfDrawTextBox 18 /* new in 1.10 */ + +# define rtfDrawOffsetX 19 /* new in 1.10 */ +# define rtfDrawSizeX 20 /* new in 1.10 */ +# define rtfDrawOffsetY 21 /* new in 1.10 */ +# define rtfDrawSizeY 22 /* new in 1.10 */ + +# define rtfCOAngle 23 /* new in 1.10 */ +# define rtfCOAccentBar 24 /* new in 1.10 */ +# define rtfCOBestFit 25 /* new in 1.10 */ +# define rtfCOBorder 26 /* new in 1.10 */ +# define rtfCOAttachAbsDist 27 /* new in 1.10 */ +# define rtfCOAttachBottom 28 /* new in 1.10 */ +# define rtfCOAttachCenter 29 /* new in 1.10 */ +# define rtfCOAttachTop 30 /* new in 1.10 */ +# define rtfCOLength 31 /* new in 1.10 */ +# define rtfCONegXQuadrant 32 /* new in 1.10 */ +# define rtfCONegYQuadrant 33 /* new in 1.10 */ +# define rtfCOOffset 34 /* new in 1.10 */ +# define rtfCOAttachSmart 35 /* new in 1.10 */ +# define rtfCODoubleLine 36 /* new in 1.10 */ +# define rtfCORightAngle 37 /* new in 1.10 */ +# define rtfCOSingleLine 38 /* new in 1.10 */ +# define rtfCOTripleLine 39 /* new in 1.10 */ + +# define rtfDrawTextBoxMargin 40 /* new in 1.10 */ +# define rtfDrawTextBoxText 41 /* new in 1.10 */ +# define rtfDrawRoundRect 42 /* new in 1.10 */ + +# define rtfDrawPointX 43 /* new in 1.10 */ +# define rtfDrawPointY 44 /* new in 1.10 */ +# define rtfDrawPolyCount 45 /* new in 1.10 */ + +# define rtfDrawArcFlipX 46 /* new in 1.10 */ +# define rtfDrawArcFlipY 47 /* new in 1.10 */ + +# define rtfDrawLineBlue 48 /* new in 1.10 */ +# define rtfDrawLineGreen 49 /* new in 1.10 */ +# define rtfDrawLineRed 50 /* new in 1.10 */ +# define rtfDrawLinePalette 51 /* new in 1.10 */ +# define rtfDrawLineDashDot 52 /* new in 1.10 */ +# define rtfDrawLineDashDotDot 53 /* new in 1.10 */ +# define rtfDrawLineDash 54 /* new in 1.10 */ +# define rtfDrawLineDot 55 /* new in 1.10 */ +# define rtfDrawLineGray 56 /* new in 1.10 */ +# define rtfDrawLineHollow 57 /* new in 1.10 */ +# define rtfDrawLineSolid 58 /* new in 1.10 */ +# define rtfDrawLineWidth 59 /* new in 1.10 */ + +# define rtfDrawHollowEndArrow 60 /* new in 1.10 */ +# define rtfDrawEndArrowLength 61 /* new in 1.10 */ +# define rtfDrawSolidEndArrow 62 /* new in 1.10 */ +# define rtfDrawEndArrowWidth 63 /* new in 1.10 */ +# define rtfDrawHollowStartArrow 64 /* new in 1.10 */ +# define rtfDrawStartArrowLength 65 /* new in 1.10 */ +# define rtfDrawSolidStartArrow 66 /* new in 1.10 */ +# define rtfDrawStartArrowWidth 67 /* new in 1.10 */ + +# define rtfDrawBgFillBlue 68 /* new in 1.10 */ +# define rtfDrawBgFillGreen 69 /* new in 1.10 */ +# define rtfDrawBgFillRed 70 /* new in 1.10 */ +# define rtfDrawBgFillPalette 71 /* new in 1.10 */ +# define rtfDrawBgFillGray 72 /* new in 1.10 */ +# define rtfDrawFgFillBlue 73 /* new in 1.10 */ +# define rtfDrawFgFillGreen 74 /* new in 1.10 */ +# define rtfDrawFgFillRed 75 /* new in 1.10 */ +# define rtfDrawFgFillPalette 76 /* new in 1.10 */ +# define rtfDrawFgFillGray 77 /* new in 1.10 */ +# define rtfDrawFillPatIndex 78 /* new in 1.10 */ + +# define rtfDrawShadow 79 /* new in 1.10 */ +# define rtfDrawShadowXOffset 80 /* new in 1.10 */ +# define rtfDrawShadowYOffset 81 /* new in 1.10 */ + +/* + * index entry attributes + */ + +# define rtfIndexAttr 27 /* new in 1.10 */ +# define rtfIndexNumber 0 /* new in 1.10 */ +# define rtfIndexBold 1 /* reclassified in 1.10 */ +# define rtfIndexItalic 2 /* reclassified in 1.10 */ + + +/* + * \wmetafile argument values + */ + +# define rtfWmMmText 1 +# define rtfWmMmLometric 2 +# define rtfWmMmHimetric 3 +# define rtfWmMmLoenglish 4 +# define rtfWmMmHienglish 5 +# define rtfWmMmTwips 6 +# define rtfWmMmIsotropic 7 +# define rtfWmMmAnisotropic 8 + +/* + * \pmmetafile argument values + */ + +# define rtfPmPuArbitrary 4 +# define rtfPmPuPels 8 +# define rtfPmPuLometric 12 +# define rtfPmPuHimetric 16 +# define rtfPmPuLoenglish 20 +# define rtfPmPuHienglish 24 +# define rtfPmPuTwips 28 + +/* + * \lang argument values + */ + +# define rtfLangNoLang 0x0400 +# define rtfLangAlbanian 0x041c +# define rtfLangArabic 0x0401 +# define rtfLangBahasa 0x0421 +# define rtfLangBelgianDutch 0x0813 +# define rtfLangBelgianFrench 0x080c +# define rtfLangBrazilianPortuguese 0x0416 +# define rtfLangBulgarian 0x0402 +# define rtfLangCatalan 0x0403 +# define rtfLangLatinCroatoSerbian 0x041a +# define rtfLangCzech 0x0405 +# define rtfLangDanish 0x0406 +# define rtfLangDutch 0x0413 +# define rtfLangAustralianEnglish 0x0c09 +# define rtfLangUKEnglish 0x0809 +# define rtfLangUSEnglish 0x0409 +# define rtfLangFinnish 0x040b +# define rtfLangFrench 0x040c +# define rtfLangCanadianFrench 0x0c0c +# define rtfLangGerman 0x0407 +# define rtfLangGreek 0x0408 +# define rtfLangHebrew 0x040d +# define rtfLangHungarian 0x040e +# define rtfLangIcelandic 0x040f +# define rtfLangItalian 0x0410 +# define rtfLangJapanese 0x0411 +# define rtfLangKorean 0x0412 +# define rtfLangBokmalNorwegian 0x0414 +# define rtfLangNynorskNorwegian 0x0814 +# define rtfLangPolish 0x0415 +# define rtfLangPortuguese 0x0816 +# define rtfLangRhaetoRomanic 0x0417 +# define rtfLangRomanian 0x0418 +# define rtfLangRussian 0x0419 +# define rtfLangCyrillicSerboCroatian 0x081a +# define rtfLangSimplifiedChinese 0x0804 +# define rtfLangSlovak 0x041b +# define rtfLangCastilianSpanish 0x040a +# define rtfLangMexicanSpanish 0x080a +# define rtfLangSwedish 0x041d +# define rtfLangSwissFrench 0x100c +# define rtfLangSwissGerman 0x0807 +# define rtfLangSwissItalian 0x0810 +# define rtfLangThai 0x041e +# define rtfLangTraditionalChinese 0x0404 +# 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 + */ + +# define rtfParStyle 0 /* the default */ +# define rtfCharStyle 1 +# define rtfSectStyle 2 + +/* + * RTF font, color and style structures. Used for font table, + * color table, and stylesheet processing. + */ + +typedef struct RTFFont RTFFont; +typedef struct RTFColor RTFColor; +typedef struct RTFStyle RTFStyle; +typedef struct RTFStyleElt RTFStyleElt; + + +struct RTFFont +{ + char *rtfFName; /* font name */ + char *rtfFAltName; /* font alternate name */ + int rtfFNum; /* font number */ + int rtfFFamily; /* font family */ + int rtfFCharSet; /* font charset */ + int rtfFPitch; /* font pitch */ + int rtfFType; /* font type */ + int rtfFCodePage; /* font code page */ + RTFFont *rtfNextFont; /* next font in list */ +}; + + +/* + * Color values are -1 if the default color for the the color + * number should be used. The default color is writer-dependent. + */ + +struct RTFColor +{ + int rtfCNum; /* color number */ + int rtfCRed; /* red value */ + int rtfCGreen; /* green value */ + int rtfCBlue; /* blue value */ + RTFColor *rtfNextColor; /* next color in list */ +}; + + +struct RTFStyle +{ + char *rtfSName; /* style name */ + int rtfSType; /* style type */ + int rtfSAdditive; /* whether or not style is additive */ + int rtfSNum; /* style number */ + int rtfSBasedOn; /* style this one's based on */ + int rtfSNextPar; /* style next paragraph style */ + RTFStyleElt *rtfSSEList; /* list of style words */ + int rtfExpanding; /* non-zero = being expanded */ + RTFStyle *rtfNextStyle; /* next style in style list */ +}; + + +struct RTFStyleElt +{ + int rtfSEClass; /* token class */ + int rtfSEMajor; /* token major number */ + int rtfSEMinor; /* token minor number */ + int rtfSEParam; /* control symbol parameter */ + char *rtfSEText; /* text of symbol */ + RTFStyleElt *rtfNextSE; /* next element in style */ +}; + + +/* + * Return pointer to new element of type t, or NULL + * if no memory available. + */ + +# 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 + + +struct _RTF_Info; +typedef struct _RTF_Info RTF_Info; + +typedef void (*RTFFuncPtr) (RTF_Info *); /* generic function pointer */ + +struct _RTF_Info { + /* + * Public variables (listed in rtf.h) + */ + + /* + * Information pertaining to last token read by RTFToken. The + * text is exactly as it occurs in the input file, e.g., "\{" + * will be found in rtfTextBuf as "\{", even though it means "{". + * These variables are also set when styles are reprocessed. + */ + + int rtfClass; + int rtfMajor; + int rtfMinor; + int rtfParam; + int rtfFormat; + char *rtfTextBuf; + int rtfTextLen; + + long rtfLineNum; + int rtfLinePos; + + + /* + * Private stuff + */ + + int pushedChar; /* pushback char if read too far */ + + int pushedClass; /* pushed token info for RTFUngetToken() */ + int pushedMajor; + int pushedMinor; + int pushedParam; + char *pushedTextBuf; + + int prevChar; + int bumpLine; + + RTFFont *fontList; /* these lists MUST be */ + RTFColor *colorList; /* initialized to NULL */ + RTFStyle *styleList; + + char *inputName; + char *outputName; + + EDITSTREAM editstream; + char InputBuffer[0x1000]; + DWORD dwInputSize; + DWORD dwInputUsed; + + /* 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; + + RTFFuncPtr ccb[rtfMaxClass]; /* class callbacks */ + + RTFFuncPtr dcb[rtfMaxDestination]; /* destination callbacks */ + + RTFFuncPtr readHook; + + RTFFuncPtr panicProc; + + FILE *(*libFileOpen) (); + + char *outMap[rtfSC_MaxChar]; + + DWORD dwOutputCount; + char OutputBuffer[0x1000]; +}; + + +/* + * Public RTF reader routines + */ + +void RTFInit (RTF_Info *); +void RTFSetInputName (RTF_Info *, char *); +char *RTFGetInputName (RTF_Info *); +void RTFSetOutputName (RTF_Info *, char *); +char *RTFGetOutputName (RTF_Info *); +void RTFSetClassCallback (RTF_Info *, int, RTFFuncPtr); +RTFFuncPtr RTFGetClassCallback (RTF_Info *, int); +void RTFSetDestinationCallback (RTF_Info *, int, RTFFuncPtr); +RTFFuncPtr RTFGetDestinationCallback (RTF_Info *, int); +void RTFRead (RTF_Info *); +int RTFGetToken (RTF_Info *); /* writer should rarely need this */ +void RTFUngetToken (RTF_Info *); +int RTFPeekToken (RTF_Info *); +void RTFSetToken (RTF_Info *, int, int, int, int, const char *); +void RTFSetReadHook (RTF_Info *, RTFFuncPtr); +RTFFuncPtr RTFGetReadHook (RTF_Info *); +void RTFRouteToken (RTF_Info *); +void RTFSkipGroup (RTF_Info *); +void RTFExpandStyle (RTF_Info *, int); +int RTFCheckCM (RTF_Info *, int, int); +int RTFCheckCMM (RTF_Info *, int, int, int); +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 ); +void RTFSetPanicProc ( RTF_Info *, RTFFuncPtr); + +/* + * The following messing around is used to allow RTFMsg() and RTFPanic() + * to be variable-argument functions that are declared publicly but + * without generating prototype-mismatch errors on systems that have + * stdarg.h. + */ + +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 WriterInit (RTF_Info *); +int BeginFile (RTF_Info *); + +#endif diff --git a/reactos/lib/riched20/run.c b/reactos/lib/riched20/run.c new file mode 100644 index 00000000000..9e0ef76cca3 --- /dev/null +++ b/reactos/lib/riched20/run.c @@ -0,0 +1,672 @@ +/* + * RichEdit - operations on runs (diRun, rectangular pieces of paragraphs). + * Splitting/joining runs. Adjusting offsets after deleting/adding content. + * Character/pixel conversions. + * + * Copyright 2004 by Krzysztof Foltman + * + * 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" + +WINE_DEFAULT_DEBUG_CHANNEL(richedit); + +int ME_CanJoinRuns(ME_Run *run1, ME_Run *run2) +{ + if ((run1->nFlags | run2->nFlags) & (MERF_ENDPARA | MERF_GRAPHICS)) + return 0; + if (run1->style != run2->style) + return 0; + if ((run1->nFlags & MERF_STYLEFLAGS) != (run2->nFlags & MERF_STYLEFLAGS)) + return 0; + return 1; +} + +void ME_SkipAndPropagateCharOffset(ME_DisplayItem *p, int shift) +{ + p = ME_FindItemFwd(p, diRunOrParagraphOrEnd); + assert(p); + ME_PropagateCharOffset(p, shift); +} + +void ME_PropagateCharOffset(ME_DisplayItem *p, int shift) +{ + if (p->type == diRun) /* propagate in all runs in this para */ + { + TRACE("PropagateCharOffset(%s, %d)\n", debugstr_w(p->member.run.strText->szData), shift); + do { + p->member.run.nCharOfs += shift; + assert(p->member.run.nCharOfs >= 0); + p = ME_FindItemFwd(p, diRunOrParagraphOrEnd); + } while(p->type == diRun); + } + if (p->type == diParagraph) /* propagate in all next paras */ + { + do { + p->member.para.nCharOfs += shift; + assert(p->member.para.nCharOfs >= 0); + p = p->member.para.next_para; + } while(p->type == diParagraph); + } + if (p->type == diTextEnd) + { + p->member.para.nCharOfs += shift; + assert(p->member.para.nCharOfs >= 0); + } +} + +void ME_CheckCharOffsets(ME_TextEditor *editor) +{ + ME_DisplayItem *p = editor->pBuffer->pFirst; + int ofs = 0, ofsp = 0; + if(TRACE_ON(richedit)) + { + TRACE("---\n"); + ME_DumpDocument(editor->pBuffer); + } + do { + p = ME_FindItemFwd(p, diRunOrParagraphOrEnd); + switch(p->type) { + case diTextEnd: + TRACE("tend, real ofsp = %d, counted = %d\n", p->member.para.nCharOfs, ofsp+ofs); + assert(ofsp+ofs == p->member.para.nCharOfs); + return; + case diParagraph: + TRACE("para, real ofsp = %d, counted = %d\n", p->member.para.nCharOfs, ofsp+ofs); + assert(ofsp+ofs == p->member.para.nCharOfs); + ofsp = p->member.para.nCharOfs; + 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, + 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); + assert(ofs == p->member.run.nCharOfs); + ofs += ME_StrLen(p->member.run.strText); + break; + default: + assert(0); + } + } while(1); +} + +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 + + ME_VPosToPos(pRun->member.run.strText, nOfs); +} + +void ME_CursorFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_Cursor *pCursor) +{ + ME_RunOfsFromCharOfs(editor, nCharOfs, &pCursor->pRun, &pCursor->nOffset); +} + +void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **ppRun, int *pOfs) +{ + ME_DisplayItem *pPara; + int nParaOfs; + + pPara = editor->pBuffer->pFirst->member.para.next_para; + assert(pPara); + assert(ppRun); + assert(pOfs); + while (pPara->type == diParagraph) + { + 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); + 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, + nCharOfs - nParaOfs - (*ppRun)->member.run.nCharOfs); + return; + } + *ppRun = pNext; + } + 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; + assert((*ppRun)->member.run.nFlags & MERF_ENDPARA); +} + +void ME_JoinRuns(ME_TextEditor *editor, ME_DisplayItem *p) +{ + ME_DisplayItem *pNext = p->next; + int i; + assert(p->type == diRun && pNext->type == diRun); + assert(p->member.run.nCharOfs != -1); + ME_GetParagraph(p)->member.para.nFlags |= MEPF_REWRAP; + + 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); + ME_UpdateRunFlags(editor, &p->member.run); + if(TRACE_ON(richedit)) + { + TRACE("Before check after join\n"); + ME_CheckCharOffsets(editor); + TRACE("After check after join\n"); + } +} + +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; + + assert(item->member.run.nCharOfs != -1); + if(TRACE_ON(richedit)) + { + TRACE("Before check before split\n"); + ME_CheckCharOffsets(editor); + TRACE("After check before split\n"); + } + + run = &item->member.run; + + TRACE("Before split: %s(%ld, %ld)\n", debugstr_w(run->strText->szData), + run->pt.x, run->pt.y); + + item2 = ME_SplitRunSimple(editor, item, nVChar); + + run2 = &item2->member.run; + + ME_CalcRunExtent(c, run); + ME_CalcRunExtent(c, 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", + 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) +{ + ME_Run *run = &item->member.run; + ME_DisplayItem *item2; + ME_Run *run2; + 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.nCharOfs != -1); + + 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 && + editor->pCursors[i].nOffset >= nVChar) { + assert(item2->type == diRun); + editor->pCursors[i].pRun = item2; + editor->pCursors[i].nOffset -= nVChar; + } + } + ME_GetParagraph(item)->member.para.nFlags |= MEPF_REWRAP; + 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); + item->member.run.style = s; + item->member.run.strText = strData; + item->member.run.nFlags = nFlags; + item->member.run.nCharOfs = -1; + ME_AddRefStyle(s); + return item; +} + +ME_DisplayItem *ME_InsertRun(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem *pItem) +{ + 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; + ME_CursorFromCharOfs(editor, nCharOfs, &tmp); + if (tmp.nOffset) { + tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset); + tmp.nOffset = 0; + } + pDI = ME_MakeRun(pItem->member.run.style, ME_StrDup(pItem->member.run.strText), pItem->member.run.nFlags); + pDI->member.run.nCharOfs = tmp.pRun->member.run.nCharOfs; + ME_InsertBefore(tmp.pRun, pDI); + 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 <= ' '; +} + +void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run) +{ + assert(run->nCharOfs != -1); + if (ME_IsSplitable(run->strText)) + run->nFlags |= MERF_SPLITTABLE; + else + run->nFlags &= ~MERF_SPLITTABLE; + + if (!(run->nFlags & MERF_GRAPHICS)) { + 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 + run->nFlags &= ~MERF_ENDWHITE; + } + } + else + run->nFlags &= ~(MERF_WHITESPACE | MERF_STARTWHITE | MERF_ENDWHITE); +} + +void ME_GetGraphicsSize(ME_TextEditor *editor, ME_Run *run, SIZE *pSize) +{ + assert(run->nFlags & MERF_GRAPHICS); + pSize->cx = 64; + pSize->cy = 64; +} + +int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run) +{ + int fit = 0; + HGDIOBJ hOldFont; + HDC hDC; + SIZE sz; + if (!run->strText->nLen) + return 0; + + if (run->nFlags & MERF_GRAPHICS) + { + SIZE sz; + ME_GetGraphicsSize(editor, run, &sz); + if (cx < sz.cx) + return 0; + return 1; + } + hDC = GetDC(editor->hWnd); + hOldFont = ME_SelectStyleFont(editor, hDC, run->style); + GetTextExtentExPointW(hDC, run->strText->szData, run->strText->nLen, + cx, &fit, NULL, &sz); + ME_UnselectStyleFont(editor, hDC, run->style, hOldFont); + ReleaseDC(editor->hWnd, hDC); + return fit; +} + +int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run) +{ + int fit = 0, fit1 = 0; + HGDIOBJ hOldFont; + HDC hDC; + SIZE sz, sz2, sz3; + if (!run->strText->nLen) + return 0; + + if (run->nFlags & MERF_GRAPHICS) + { + SIZE sz; + ME_GetGraphicsSize(editor, run, &sz); + if (cx < sz.cx/2) + return 0; + return 1; + } + + hDC = GetDC(editor->hWnd); + hOldFont = ME_SelectStyleFont(editor, hDC, run->style); + 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); + ReleaseDC(editor->hWnd, hDC); + return fit; +} + +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; + ME_GetGraphicsSize(editor, pRun, &size); + return 1; + } + hOldFont = ME_SelectStyleFont(editor, hDC, pRun->style); + GetTextExtentPoint32W(hDC, pRun->strText->szData, nOffset, &size); + 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, + 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); +} + +SIZE ME_GetRunSize(ME_Context *c, ME_Run *run, int nLen) +{ + SIZE size; + int nMaxLen = ME_StrVLen(run->strText); + + if (nLen>nMaxLen) + nLen = nMaxLen; + + if (run->nFlags & MERF_GRAPHICS) + { + ME_GetGraphicsSize(c->editor, run, &size); + return size; + } + + ME_GetTextExtent(c, run->strText->szData, nLen, run->style, &size); + + return size; +} + +void ME_CalcRunExtent(ME_Context *c, 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); + run->nWidth = size.cx; + run->nAscent = run->style->tm.tmAscent; + run->nDescent = run->style->tm.tmDescent; +} + +void ME_MustBeWrapped(ME_Context *c, ME_DisplayItem *para) +{ + assert(para->type == diParagraph); + /* FIXME */ +} + +void ME_SetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt) +{ + int nFrom, nTo; + ME_GetSelection(editor, &nFrom, &nTo); + if (nFrom == nTo) + { + ME_Style *s; + if (!editor->pBuffer->pCharStyle) + editor->pBuffer->pCharStyle = ME_GetInsertStyle(editor, 0); + s = ME_ApplyStyle(editor->pBuffer->pCharStyle, pFmt); + ME_ReleaseStyle(editor->pBuffer->pCharStyle); + editor->pBuffer->pCharStyle = s; + } + else + ME_SetCharFormat(editor, nFrom, nTo-nFrom, pFmt); +} + +void ME_SetCharFormat(ME_TextEditor *editor, int nOfs, int nChars, CHARFORMAT2W *pFmt) +{ + ME_Cursor tmp, tmp2; + ME_DisplayItem *para; + + ME_CursorFromCharOfs(editor, nOfs, &tmp); + if (tmp.nOffset) + tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset); + + ME_CursorFromCharOfs(editor, nOfs+nChars, &tmp2); + if (tmp2.nOffset) + tmp2.pRun = ME_SplitRunSimple(editor, tmp2.pRun, tmp2.nOffset); + + para = ME_GetParagraph(tmp.pRun); + para->member.para.nFlags |= MEPF_REWRAP; + + while(tmp.pRun != tmp2.pRun) + { + ME_UndoItem *undo = NULL; + ME_Style *new_style = ME_ApplyStyle(tmp.pRun->member.run.style, pFmt); + /* ME_DumpStyle(new_style); */ + undo = ME_AddUndoItem(editor, diUndoSetCharFormat, NULL); + if (undo) { + undo->nStart = tmp.pRun->member.run.nCharOfs+para->member.para.nCharOfs; + undo->nLen = tmp.pRun->member.run.strText->nLen; + undo->di.member.ustyle = tmp.pRun->member.run.style; + /* we'd have to addref undo..ustyle and release tmp...style + but they'd cancel each other out so we can do nothing instead */ + } + else + ME_ReleaseStyle(tmp.pRun->member.run.style); + tmp.pRun->member.run.style = new_style; + tmp.pRun = ME_FindItemFwd(tmp.pRun, diRunOrParagraph); + if (tmp.pRun->type == diParagraph) + { + para = tmp.pRun; + tmp.pRun = ME_FindItemFwd(tmp.pRun, diRun); + if (tmp.pRun != tmp2.pRun) + para->member.para.nFlags |= MEPF_REWRAP; + } + assert(tmp.pRun); + } +} + +void ME_SetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *mod) +{ + ME_Style *style; + ME_UndoItem *undo; + + assert(mod->cbSize == sizeof(CHARFORMAT2W)); + undo = ME_AddUndoItem(editor, diUndoSetDefaultCharFormat, NULL); + if (undo) { + undo->nStart = -1; + undo->nLen = -1; + undo->di.member.ustyle = editor->pBuffer->pDefaultStyle; + ME_AddRefStyle(undo->di.member.ustyle); + } + style = ME_ApplyStyle(editor->pBuffer->pDefaultStyle, mod); + editor->pBuffer->pDefaultStyle->fmt = style->fmt; + editor->pBuffer->pDefaultStyle->tm = style->tm; + ME_ReleaseStyle(style); + ME_MarkAllForWrapping(editor); + /* pcf = editor->pBuffer->pDefaultStyle->fmt; */ +} + +void ME_GetRunCharFormat(ME_TextEditor *editor, ME_DisplayItem *run, CHARFORMAT2W *pFmt) +{ + ME_CopyCharFormat(pFmt, &run->member.run.style->fmt); +} + +void ME_GetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt) +{ + int nFrom, nTo; + ME_GetSelection(editor, &nFrom, &nTo); + ME_CopyCharFormat(pFmt, &editor->pBuffer->pDefaultStyle->fmt); +} + +void ME_GetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt) +{ + int nFrom, nTo; + ME_GetSelection(editor, &nFrom, &nTo); + if (nFrom == nTo && editor->pBuffer->pCharStyle) + { + ME_CopyCharFormat(pFmt, &editor->pBuffer->pCharStyle->fmt); + return; + } + ME_GetCharFormat(editor, nFrom, nTo, pFmt); +} + +void ME_GetCharFormat(ME_TextEditor *editor, int nFrom, int nTo, CHARFORMAT2W *pFmt) +{ + 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 */ + { + if (!nOffset) + { + ME_DisplayItem *tmp_run = ME_FindItemBack(run, diRunOrParagraph); + if (tmp_run->type == diRun) { + ME_GetRunCharFormat(editor, tmp_run, pFmt); + return; + } + } + ME_GetRunCharFormat(editor, run, pFmt); + 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 */ + + if (pFmt->yHeight != tmp.yHeight) + pFmt->dwMask &= ~CFM_SIZE; + if (pFmt->dwMask & CFM_FACE) + { + if (!(tmp.dwMask & CFM_FACE)) + pFmt->dwMask &= ~CFM_FACE; + else if (lstrcmpW(pFmt->szFaceName, tmp.szFaceName)) + pFmt->dwMask &= ~CFM_FACE; + } + if (pFmt->yHeight != tmp.yHeight) + pFmt->dwMask &= ~CFM_SIZE; + if (pFmt->dwMask & CFM_COLOR) + { + if (!((pFmt->dwEffects&CFE_AUTOCOLOR) & (tmp.dwEffects&CFE_AUTOCOLOR))) + { + if (pFmt->crTextColor != tmp.crTextColor) + 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 new file mode 100644 index 00000000000..c18fa1d5501 --- /dev/null +++ b/reactos/lib/riched20/string.c @@ -0,0 +1,318 @@ +/* + * RichEdit - string operations + * + * Copyright 2004 by Krzysztof Foltman + * + * 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" + +WINE_DEFAULT_DEBUG_CHANNEL(richedit); + +int ME_GetOptimalBuffer(int nLen) +{ + return ((2*nLen+1)+128)&~63; +} + +ME_String *ME_MakeString(LPCWSTR szText) +{ + ME_String *s = ALLOC_OBJ(ME_String); + s->nLen = lstrlenW(szText); + s->nBuffer = ME_GetOptimalBuffer(s->nLen+1); + s->szData = ALLOC_N_OBJ(WCHAR, s->nBuffer); + lstrcpyW(s->szData, szText); + return s; +} + +ME_String *ME_MakeStringN(LPCWSTR szText, int nMaxChars) +{ + ME_String *s = ALLOC_OBJ(ME_String); + int i; + for (i=0; inLen = i; + s->nBuffer = ME_GetOptimalBuffer(s->nLen+1); + s->szData = ALLOC_N_OBJ(WCHAR, s->nBuffer); + lstrcpynW(s->szData, szText, s->nLen+1); + return s; +} + +ME_String *ME_StrDup(ME_String *s) +{ + return ME_MakeStringN(s->szData, s->nLen); +} + +void ME_DestroyString(ME_String *s) +{ + FREE_OBJ(s->szData); + FREE_OBJ(s); +} + +void ME_AppendString(ME_String *s1, ME_String *s2) +{ + if (s1->nLen+s2->nLen+1 <= s1->nBuffer) { + lstrcpyW(s1->szData+s1->nLen, s2->szData); + s1->nLen += s2->nLen; + } + else + { + WCHAR *buf; + s1->nBuffer = ME_GetOptimalBuffer(s1->nLen+s2->nLen+1); + + buf = ALLOC_N_OBJ(WCHAR, s1->nBuffer); + lstrcpyW(buf, s1->szData); + lstrcpyW(buf+s1->nLen, s2->szData); + FREE_OBJ(s1->szData); + s1->szData = buf; + s1->nLen += s2->nLen; + } +} + +ME_String *ME_ConcatString(ME_String *s1, ME_String *s2) +{ + ME_String *s = ALLOC_OBJ(ME_String); + s->nLen = s1->nLen+s2->nLen; + s->nBuffer = ME_GetOptimalBuffer(s1->nLen+s2->nLen+1); + s->szData = ALLOC_N_OBJ(WCHAR, s->nBuffer); + lstrcpyW(s->szData, s1->szData); + lstrcpyW(s->szData+s1->nLen, s2->szData); + return s; +} + +ME_String *ME_VSplitString(ME_String *orig, int charidx) +{ + ME_String *s; + + /*if (charidx<0) charidx = 0; + if (charidx>orig->nLen) charidx = orig->nLen; + */ + assert(charidx>=0); + assert(charidx<=orig->nLen); + + s = ME_MakeString(orig->szData+charidx); + orig->nLen = charidx; + orig->szData[charidx] = L'\0'; + return s; +} + +int ME_IsWhitespaces(ME_String *s) +{ + /* FIXME multibyte */ + WCHAR *pos = s->szData; + while(*pos++ == ' ') + ; + pos--; + if (*pos) + return 0; + else + return 1; +} + +int ME_IsSplitable(ME_String *s) +{ + /* FIXME multibyte */ + WCHAR *pos = s->szData; + WCHAR ch; + while(*pos++ == L' ') + ; + pos--; + while((ch = *pos++) != 0) + { + if (ch == L' ') + return 1; + } + return 0; +} + +/* FIXME multibyte */ +/* +int ME_CalcSkipChars(ME_String *s) +{ + int cnt = 0; + while(cnt < s->nLen && s->szData[s->nLen-1-cnt]==' ') + cnt++; + return cnt; +} +*/ + +int ME_StrLen(ME_String *s) { + return s->nLen; +} + +int ME_StrVLen(ME_String *s) { + return s->nLen; +} + +/* FIXME we use widechars, not multibytes, inside, no need for complex logic anymore */ +int ME_StrRelPos(ME_String *s, int nVChar, int *pRelChars) +{ + TRACE("%s,%d,&%d\n", debugstr_w(s->szData), nVChar, *pRelChars); + + assert(*pRelChars); + if (!*pRelChars) return nVChar; + + if (*pRelChars>0) + { + while(nVCharnLen && *pRelChars>0) + { + nVChar++; + (*pRelChars)--; + } + return nVChar; + } + + while(nVChar>0 && *pRelChars<0) + { + nVChar--; + (*pRelChars)++; + } + return nVChar; +} + +int ME_StrRelPos2(ME_String *s, int nVChar, int nRelChars) +{ + return ME_StrRelPos(s, nVChar, &nRelChars); +} + +int ME_VPosToPos(ME_String *s, int nVPos) +{ + return nVPos; + /* + int i = 0, len = 0; + if (!nVPos) + return 0; + while (i < s->nLen) + { + if (i == nVPos) + return len; + if (s->szData[i]=='\\') i++; + i++; + len++; + } + return len; + */ +} + +int ME_PosToVPos(ME_String *s, int nPos) +{ + if (!nPos) + return 0; + return ME_StrRelPos2(s, 0, nPos); +} + +void ME_StrDeleteV(ME_String *s, int nVChar, int nChars) +{ + int end_ofs; + + assert(nVChar >=0 && nVChar <= s->nLen); + assert(nChars >= 0); + assert(nVChar+nChars <= s->nLen); + + end_ofs = ME_StrRelPos2(s, nVChar, nChars); + assert(end_ofs <= s->nLen); + memmove(s->szData+nVChar, s->szData+end_ofs, 2*(s->nLen+1-end_ofs)); + s->nLen -= (end_ofs - nVChar); +} + +int ME_GetCharFwd(ME_String *s, int nPos) +{ + int nVPos = 0; + + assert(nPos < ME_StrLen(s)); + if (nPos) + nVPos = ME_StrRelPos2(s, nVPos, nPos); + + if (nVPos < s->nLen) + return s->szData[nVPos]; + return -1; +} + +int ME_GetCharBack(ME_String *s, int nPos) +{ + int nVPos = ME_StrVLen(s); + + assert(nPos < ME_StrLen(s)); + if (nPos) + nVPos = ME_StrRelPos2(s, nVPos, -nPos); + + if (nVPos < s->nLen) + return s->szData[nVPos]; + return -1; +} + +int ME_FindNonWhitespaceV(ME_String *s, int nVChar) { + int i; + for (i = nVChar; isspace(s->szData[i]) && inLen; i++) + ; + + return i; +} + +/* 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--) + ; + + return i; +} + +/* 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--) + ; + + return i; +} + +LPWSTR ME_ToUnicode(HWND hWnd, LPVOID psz) +{ + if (IsWindowUnicode(hWnd)) + return (LPWSTR)psz; + else { + WCHAR *tmp; + int nChars = MultiByteToWideChar(CP_ACP, 0, (char *)psz, -1, NULL, 0); + if((tmp = ALLOC_N_OBJ(WCHAR, nChars)) != NULL) + MultiByteToWideChar(CP_ACP, 0, (char *)psz, -1, tmp, nChars); + return tmp; + } +} + +void ME_EndToUnicode(HWND hWnd, LPVOID psz) +{ + if (IsWindowUnicode(hWnd)) + FREE_OBJ(psz); +} + +LPSTR ME_ToAnsi(HWND hWnd, LPVOID psz) +{ + if (!IsWindowUnicode(hWnd)) + return (LPSTR)psz; + else { + char *tmp; + int nChars = WideCharToMultiByte(CP_ACP, 0, (WCHAR *)psz, -1, NULL, 0, NULL, NULL); + if((tmp = ALLOC_N_OBJ(char, nChars)) != NULL) + WideCharToMultiByte(CP_ACP, 0, (WCHAR *)psz, -1, tmp, nChars, NULL, NULL); + return tmp; + } +} + +void ME_EndToAnsi(HWND hWnd, LPVOID psz) +{ + if (!IsWindowUnicode(hWnd)) + FREE_OBJ(psz); +} diff --git a/reactos/lib/riched20/style.c b/reactos/lib/riched20/style.c new file mode 100644 index 00000000000..b2be737f7ab --- /dev/null +++ b/reactos/lib/riched20/style.c @@ -0,0 +1,443 @@ +/* + * RichEdit style management functions + * + * Copyright 2004 by Krzysztof Foltman + * + * 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" + +WINE_DEFAULT_DEBUG_CHANNEL(richedit); + +static int all_refs = 0; + +CHARFORMAT2W *ME_ToCF2W(CHARFORMAT2W *to, CHARFORMAT2W *from) +{ + if (from->cbSize == sizeof(CHARFORMATA)) + { + CHARFORMATA *f = (CHARFORMATA *)from; + CopyMemory(to, f, sizeof(*f)-sizeof(f->szFaceName)); + to->cbSize = sizeof(CHARFORMAT2W); + if (f->dwMask & CFM_FACE) { + MultiByteToWideChar(0, 0, f->szFaceName, -1, to->szFaceName, sizeof(to->szFaceName)/sizeof(WCHAR)); + } + return to; + } + if (from->cbSize == sizeof(CHARFORMATW)) + { + CHARFORMATW *f = (CHARFORMATW *)from; + CopyMemory(to, f, sizeof(*f)); + /* theoretically, we don't need to zero the remaining memory */ + ZeroMemory(((CHARFORMATW *)to)+1, sizeof(CHARFORMAT2W)-sizeof(CHARFORMATW)); + to->cbSize = sizeof(CHARFORMAT2W); + return to; + } + if (from->cbSize == sizeof(CHARFORMAT2A)) + { + CHARFORMATA *f = (CHARFORMATA *)from; + /* copy the A structure without face name */ + CopyMemory(to, f, sizeof(CHARFORMATA)-sizeof(f->szFaceName)); + /* convert face name */ + 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)); + to->cbSize = sizeof(CHARFORMAT2W); + return to; + } + + assert(from->cbSize >= sizeof(CHARFORMAT2W)); + return from; +} + +void ME_CopyToCF2W(CHARFORMAT2W *to, CHARFORMAT2W *from) +{ + if (ME_ToCF2W(to, from) == from) + CopyMemory(to, from, sizeof(*from)); +} + +CHARFORMAT2W *ME_ToCFAny(CHARFORMAT2W *to, CHARFORMAT2W *from) +{ + assert(from->cbSize == sizeof(CHARFORMAT2W)); + if (to->cbSize == sizeof(CHARFORMATA)) + { + CHARFORMATA *t = (CHARFORMATA *)to; + CopyMemory(t, from, sizeof(*t)-sizeof(t->szFaceName)); + WideCharToMultiByte(0, 0, from->szFaceName, -1, t->szFaceName, sizeof(t->szFaceName), 0, 0); + t->cbSize = sizeof(*t); /* it was overwritten by CopyMemory */ + return to; + } + if (to->cbSize == sizeof(CHARFORMATW)) + { + CHARFORMATW *t = (CHARFORMATW *)to; + CopyMemory(t, from, sizeof(*t)); + t->cbSize = sizeof(*t); /* it was overwritten by CopyMemory */ + return to; + } + if (to->cbSize == sizeof(CHARFORMAT2A)) + { + CHARFORMAT2A *t = (CHARFORMAT2A *)to; + /* copy the A structure without face name */ + CopyMemory(t, from, sizeof(CHARFORMATA)-sizeof(t->szFaceName)); + /* convert face name */ + WideCharToMultiByte(0, 0, from->szFaceName, -1, t->szFaceName, sizeof(t->szFaceName), 0, 0); + /* copy the rest of the 2A structure to 2W */ + CopyMemory(&t->wWeight, &from->wWeight, sizeof(CHARFORMAT2A)-sizeof(CHARFORMATA)); + t->cbSize = sizeof(*t); /* it was overwritten by CopyMemory */ + return to; + } + assert(to->cbSize >= sizeof(CHARFORMAT2W)); + return from; +} + +void ME_CopyToCFAny(CHARFORMAT2W *to, CHARFORMAT2W *from) +{ + if (ME_ToCFAny(to, from) == from) + CopyMemory(to, from, to->cbSize); +} + +ME_Style *ME_MakeStyle(CHARFORMAT2W *style) { + CHARFORMAT2W styledata; + ME_Style *s = ALLOC_OBJ(ME_Style); + + style = ME_ToCF2W(&styledata, style); + memset(s, 0, sizeof(ME_Style)); + if (style->cbSize <= sizeof(CHARFORMAT2W)) + CopyMemory(&s->fmt, style, style->cbSize); + else + CopyMemory(&s->fmt, style, sizeof(CHARFORMAT2W)); + s->fmt.cbSize = sizeof(CHARFORMAT2W); + + s->nSequence = -2; + s->nRefs = 1; + s->hFont = NULL; + all_refs++; + return s; +} + +#define COPY_STYLE_ITEM(mask, member) \ + if (style->dwMask & mask) { \ + s->fmt.dwMask |= mask;\ + s->fmt.member = style->member;\ + } + +#define COPY_STYLE_ITEM_MEMCPY(mask, member) \ + if (style->dwMask & mask) { \ + s->fmt.dwMask |= mask;\ + CopyMemory(s->fmt.member, style->member, sizeof(style->member));\ + } + +void ME_InitCharFormat2W(CHARFORMAT2W *pFmt) +{ + ZeroMemory(pFmt, sizeof(CHARFORMAT2W)); + pFmt->cbSize = sizeof(CHARFORMAT2W); +} + +ME_Style *ME_ApplyStyle(ME_Style *sSrc, CHARFORMAT2W *style) +{ + CHARFORMAT2W styledata; + ME_Style *s = ME_MakeStyle(&sSrc->fmt); + style = ME_ToCF2W(&styledata, style); + COPY_STYLE_ITEM(CFM_ANIMATION, bAnimation); + COPY_STYLE_ITEM(CFM_BACKCOLOR, crBackColor); + COPY_STYLE_ITEM(CFM_CHARSET, bCharSet); + COPY_STYLE_ITEM(CFM_COLOR, crTextColor); + COPY_STYLE_ITEM_MEMCPY(CFM_FACE, szFaceName); + COPY_STYLE_ITEM(CFM_KERNING, wKerning); + COPY_STYLE_ITEM(CFM_LCID, lcid); + COPY_STYLE_ITEM(CFM_OFFSET, yOffset); + COPY_STYLE_ITEM(CFM_REVAUTHOR, bRevAuthor); + COPY_STYLE_ITEM(CFM_SIZE, yHeight); + COPY_STYLE_ITEM(CFM_SPACING, sSpacing); + COPY_STYLE_ITEM(CFM_STYLE, sStyle); + COPY_STYLE_ITEM(CFM_UNDERLINETYPE, bUnderlineType); + COPY_STYLE_ITEM(CFM_WEIGHT, wWeight); + + s->fmt.dwEffects &= ~(style->dwMask); + s->fmt.dwEffects |= style->dwEffects & style->dwMask; + s->fmt.dwMask |= style->dwMask; + if (style->dwMask & CFM_COLOR) + { + if (style->dwEffects & CFE_AUTOCOLOR) + s->fmt.dwEffects |= CFE_AUTOCOLOR; + else + s->fmt.dwEffects &= ~CFE_AUTOCOLOR; + } + return s; +} + +void ME_CopyCharFormat(CHARFORMAT2W *pDest, CHARFORMAT2W *pSrc) +{ + /* using this with non-2W structs is forbidden */ + assert(pSrc->cbSize == sizeof(CHARFORMAT2W)); + assert(pDest->cbSize == sizeof(CHARFORMAT2W)); + CopyMemory(pDest, pSrc, sizeof(CHARFORMAT2W)); +} + +static void ME_DumpStyleEffect(char **p, const char *name, CHARFORMAT2W *fmt, int mask) +{ + *p += sprintf(*p, "%-22s%s\n", name, (fmt->dwMask & mask) ? ((fmt->dwEffects & mask) ? "YES" : "no") : "N/A"); +} + +void ME_DumpStyle(ME_Style *s) +{ + char buf[2048]; + ME_DumpStyleToBuf(&s->fmt, buf); + TRACE("%s\n", buf); +} + +void ME_DumpStyleToBuf(CHARFORMAT2W *pFmt, char buf[2048]) +{ + /* FIXME only CHARFORMAT styles implemented */ + /* this function sucks, doesn't check for buffer overruns but it's "good enough" as for debug code */ + char *p; + p = buf; + p += sprintf(p, "Font face: "); + if (pFmt->dwMask & CFM_FACE) { + WCHAR *q = pFmt->szFaceName; + while(*q) { + *p++ = (*q > 255) ? '?' : *q; + q++; + } + } else + p += sprintf(p, "N/A"); + + if (pFmt->dwMask & CFM_SIZE) + p += sprintf(p, "\nFont size: %d\n", (int)pFmt->yHeight); + else + p += sprintf(p, "\nFont size: N/A\n"); + + if (pFmt->dwMask & CFM_OFFSET) + p += sprintf(p, "Char offset: %d\n", (int)pFmt->yOffset); + else + p += sprintf(p, "Char offset: N/A\n"); + + if (pFmt->dwMask & CFM_CHARSET) + p += sprintf(p, "Font charset: %d\n", (int)pFmt->bCharSet); + else + p += sprintf(p, "Font charset: N/A\n"); + + /* I'm assuming CFM_xxx and CFE_xxx are the same values, fortunately it IS true wrt used flags*/ + ME_DumpStyleEffect(&p, "Font bold:", pFmt, CFM_BOLD); + ME_DumpStyleEffect(&p, "Font italic:", pFmt, CFM_ITALIC); + ME_DumpStyleEffect(&p, "Font underline:", pFmt, CFM_UNDERLINE); + ME_DumpStyleEffect(&p, "Font strikeout:", pFmt, CFM_STRIKEOUT); + p += sprintf(p, "Text color: "); + if (pFmt->dwMask & CFM_COLOR) + { + if (pFmt->dwEffects & CFE_AUTOCOLOR) + p += sprintf(p, "auto\n"); + else + p += sprintf(p, "%06x\n", (int)pFmt->crTextColor); + } + else + p += sprintf(p, "N/A\n"); + ME_DumpStyleEffect(&p, "Text protected:", pFmt, CFM_PROTECTED); +} + +void ME_LogFontFromStyle(HDC hDC, LOGFONTW *lf, ME_Style *s) +{ + int rx, ry; + rx = GetDeviceCaps(hDC, LOGPIXELSX); + ry = GetDeviceCaps(hDC, LOGPIXELSY); + ZeroMemory(lf, sizeof(LOGFONTW)); + lstrcpyW(lf->lfFaceName, s->fmt.szFaceName); + lf->lfHeight = -s->fmt.yHeight*ry/1440; + lf->lfWeight = 400; + if (s->fmt.dwEffects & s->fmt.dwMask & CFM_BOLD) + lf->lfWeight = 700; + if (s->fmt.dwEffects & s->fmt.dwMask & CFM_WEIGHT) + lf->lfWeight = s->fmt.wWeight; + if (s->fmt.dwEffects & s->fmt.dwMask & CFM_ITALIC) + lf->lfItalic = 1; + if (s->fmt.dwEffects & s->fmt.dwMask & CFM_UNDERLINE) + lf->lfUnderline = 1; + if (s->fmt.dwEffects & s->fmt.dwMask & CFM_STRIKEOUT) + lf->lfStrikeOut = 1; +/*lf.lfQuality = PROOF_QUALITY; */ + lf->lfPitchAndFamily = s->fmt.bPitchAndFamily; + lf->lfCharSet = s->fmt.bCharSet; +} + + +BOOL ME_IsFontEqual(LOGFONTW *p1, LOGFONTW *p2) +{ + if (memcmp(p1, p2, sizeof(LOGFONTW)-sizeof(p1->lfFaceName))) + return FALSE; + if (lstrcmpW(p1->lfFaceName, p2->lfFaceName)) + return FALSE; + return TRUE; +} + +HFONT ME_SelectStyleFont(ME_TextEditor *editor, HDC hDC, ME_Style *s) +{ + HFONT hOldFont; + LOGFONTW lf; + int i, nEmpty, nAge = 0x7FFFFFFF; + ME_FontCacheItem *item; + assert(hDC); + assert(s); + + ME_LogFontFromStyle(hDC, &lf, s); + + for (i=0; ipFontCache[i].nAge++; + for (i=0, nEmpty=-1, nAge=0; ipFontCache[i]; + if (!item->nRefs) + { + if (item->nAge > nAge) + nEmpty = i, nAge = item->nAge; + } + if (ME_IsFontEqual(&item->lfSpecs, &lf)) + break; + } + if (i < HFONT_CACHE_SIZE) /* found */ + { + item = &editor->pFontCache[i]; + TRACE("font reused %d\n", i); + + s->hFont = item->hFont; + item->nRefs++; + } + else + { + item = &editor->pFontCache[nEmpty]; /* this legal even when nEmpty == -1, as we don't dereference it */ + + assert(nEmpty != -1); /* otherwise we leak cache entries or get too many fonts at once*/ + if (item->hFont) { + TRACE("font deleted %d\n", nEmpty); + DeleteObject(item->hFont); + item->hFont = NULL; + } + s->hFont = CreateFontIndirectW(&lf); + assert(s->hFont); + TRACE("font created %d\n", nEmpty); + item->hFont = s->hFont; + item->nRefs = 1; + memcpy(&item->lfSpecs, &lf, sizeof(LOGFONTW)); + } + hOldFont = SelectObject(hDC, s->hFont); + /* should be cached too, maybe ? */ + GetTextMetricsW(hDC, &s->tm); + return hOldFont; +} + +void ME_UnselectStyleFont(ME_TextEditor *editor, HDC hDC, ME_Style *s, HFONT hOldFont) +{ + int i; + + assert(hDC); + assert(s); + SelectObject(hDC, hOldFont); + for (i=0; ipFontCache[i]; + if (pItem->hFont == s->hFont && pItem->nRefs > 0) + { + pItem->nRefs--; + pItem->nAge = 0; + s->hFont = NULL; + return; + } + } + assert(0 == "UnselectStyleFont without SelectStyleFont"); +} + +void ME_DestroyStyle(ME_Style *s) { + if (s->hFont) + { + DeleteObject(s->hFont); + s->hFont = NULL; + } + FREE_OBJ(s); +} + +void ME_AddRefStyle(ME_Style *s) +{ + assert(s->nRefs>0); /* style with 0 references isn't supposed to exist */ + s->nRefs++; + all_refs++; +} + +void ME_ReleaseStyle(ME_Style *s) +{ + s->nRefs--; + all_refs--; + if (s->nRefs==0) + TRACE("destroy style %p, total refs=%d\n", s, all_refs); + else + TRACE("release style %p, new refs=%d, total refs=%d\n", s, s->nRefs, all_refs); + if (!all_refs) FIXME("all style references freed (good!)\n"); + assert(s->nRefs>=0); + if (!s->nRefs) + ME_DestroyStyle(s); +} + +ME_Style *ME_GetInsertStyle(ME_TextEditor *editor, int nCursor) { + if (ME_IsSelection(editor)) + { + ME_Cursor c; + int from, to; + + ME_GetSelection(editor, &from, &to); + ME_CursorFromCharOfs(editor, from, &c); + ME_AddRefStyle(c.pRun->member.run.style); + return c.pRun->member.run.style; + } + if (editor->pBuffer->pCharStyle) { + ME_AddRefStyle(editor->pBuffer->pCharStyle); + return editor->pBuffer->pCharStyle; + } + else + { + ME_Cursor *pCursor = &editor->pCursors[nCursor]; + ME_DisplayItem *pRunItem = pCursor->pRun; + ME_DisplayItem *pPrevItem = NULL; + if (pCursor->nOffset) { + ME_Run *pRun = &pRunItem->member.run; + ME_AddRefStyle(pRun->style); + return pRun->style; + } + pPrevItem = ME_FindItemBack(pRunItem, diRunOrParagraph); + if (pPrevItem->type == diRun) + { + ME_AddRefStyle(pPrevItem->member.run.style); + return pPrevItem->member.run.style; + } + else + { + ME_AddRefStyle(pRunItem->member.run.style); + return pRunItem->member.run.style; + } + } +} + +void ME_SaveTempStyle(ME_TextEditor *editor) +{ + ME_Style *old_style = editor->pBuffer->pCharStyle; + editor->pBuffer->pCharStyle = ME_GetInsertStyle(editor, 0); + if (old_style) + ME_ReleaseStyle(old_style); +} + +void ME_ClearTempStyle(ME_TextEditor *editor) +{ + if (!editor->pBuffer->pCharStyle) return; + ME_ReleaseStyle(editor->pBuffer->pCharStyle); + editor->pBuffer->pCharStyle = NULL; +} diff --git a/reactos/lib/riched20/undo.c b/reactos/lib/riched20/undo.c new file mode 100644 index 00000000000..e95edc15d7e --- /dev/null +++ b/reactos/lib/riched20/undo.c @@ -0,0 +1,261 @@ +/* + * RichEdit - functions dealing with editor object + * + * Copyright 2004 by Krzysztof Foltman + * + * 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" + +WINE_DEFAULT_DEBUG_CHANNEL(richedit); + +void ME_EmptyUndoStack(ME_TextEditor *editor) +{ + ME_DisplayItem *p, *pNext; + + TRACE("Emptying undo stack\n"); + + p = editor->pUndoStack; + editor->pUndoStack = NULL; + while(p) { + pNext = p->next; + ME_DestroyDisplayItem(p); + p = pNext; + } + p = editor->pRedoStack; + editor->pRedoStack = NULL; + while(p) { + pNext = p->next; + ME_DestroyDisplayItem(p); + p = pNext; + } +} + +ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, ME_DisplayItem *pdi) { + if (editor->nUndoMode == umIgnore) + return NULL; + else + { + ME_DisplayItem *pItem = (ME_DisplayItem *)ALLOC_OBJ(ME_UndoItem); + switch(type) + { + case diUndoEndTransaction: + break; + case diUndoSetParagraphFormat: + assert(pdi); + CopyMemory(&pItem->member.para, &pdi->member.para, sizeof(ME_Paragraph)); + pItem->member.para.pFmt = ALLOC_OBJ(PARAFORMAT2); + CopyMemory(pItem->member.para.pFmt, pdi->member.para.pFmt, sizeof(PARAFORMAT2)); + break; + case diUndoInsertRun: + assert(pdi); + CopyMemory(&pItem->member.run, &pdi->member.run, sizeof(ME_Run)); + pItem->member.run.strText = ME_StrDup(pItem->member.run.strText); + ME_AddRefStyle(pItem->member.run.style); + break; + case diUndoSetCharFormat: + case diUndoSetDefaultCharFormat: + break; + case diUndoDeleteRun: + case diUndoJoinParagraphs: + break; + case diUndoSplitParagraph: + pItem->member.para.pFmt = ALLOC_OBJ(PARAFORMAT2); + pItem->member.para.pFmt->cbSize = sizeof(PARAFORMAT2); + pItem->member.para.pFmt->dwMask = 0; + + break; + default: + assert(0 == "AddUndoItem, unsupported item type"); + return NULL; + } + pItem->type = type; + pItem->prev = NULL; + if (editor->nUndoMode == umAddToUndo || editor->nUndoMode == umAddBackToUndo) + { + if (editor->nUndoMode == umAddToUndo) + TRACE("Pushing id=%s to undo stack, deleting redo stack\n", ME_GetDITypeName(type)); + else + TRACE("Pushing id=%s to undo stack\n", ME_GetDITypeName(type)); + pItem->next = editor->pUndoStack; + if (editor->pUndoStack) + editor->pUndoStack->prev = pItem; + editor->pUndoStack = pItem; + /* any new operation (not redo) clears the redo stack */ + if (editor->nUndoMode == umAddToUndo) { + ME_DisplayItem *p = editor->pRedoStack; + while(p) + { + ME_DisplayItem *pp = p->next; + ME_DestroyDisplayItem(p); + p = pp; + } + editor->pRedoStack = NULL; + } + } + else if (editor->nUndoMode == umAddToRedo) + { + TRACE("Pushing id=%s to redo stack\n", ME_GetDITypeName(type)); + pItem->next = editor->pRedoStack; + if (editor->pRedoStack) + editor->pRedoStack->prev = pItem; + editor->pRedoStack = pItem; + } + else + assert(0); + return (ME_UndoItem *)pItem; + } +} + +void ME_CommitUndo(ME_TextEditor *editor) { + assert(editor->nUndoMode == umAddToUndo); + + /* no transactions, no need to commit */ + if (!editor->pUndoStack) + return; + + /* no need to commit empty transactions */ + if (editor->pUndoStack->type == diUndoEndTransaction) + return; + + ME_AddUndoItem(editor, diUndoEndTransaction, NULL); + ME_SendSelChange(editor); + editor->nModifyStep++; +} + +void ME_PlayUndoItem(ME_TextEditor *editor, ME_DisplayItem *pItem) +{ + ME_UndoItem *pUItem = (ME_UndoItem *)pItem; + + TRACE("Playing undo/redo item, id=%s\n", ME_GetDITypeName(pItem->type)); + + switch(pItem->type) + { + case diUndoEndTransaction: + assert(0); + case diUndoSetParagraphFormat: + { + ME_Cursor tmp; + ME_CursorFromCharOfs(editor, pItem->member.para.nCharOfs, &tmp); + ME_SetParaFormat(editor, ME_FindItemBack(tmp.pRun, diParagraph), pItem->member.para.pFmt); + break; + } + case diUndoSetCharFormat: + { + ME_SetCharFormat(editor, pUItem->nStart, pUItem->nLen, &pItem->member.ustyle->fmt); + break; + } + case diUndoSetDefaultCharFormat: + { + ME_SetDefaultCharFormat(editor, &pItem->member.ustyle->fmt); + break; + } + case diUndoInsertRun: + { + ME_InsertRun(editor, pItem->member.run.nCharOfs, pItem); + break; + } + case diUndoDeleteRun: + { + ME_InternalDeleteText(editor, pUItem->nStart, pUItem->nLen); + break; + } + case diUndoJoinParagraphs: + { + ME_Cursor tmp; + ME_CursorFromCharOfs(editor, pUItem->nStart, &tmp); + /* the only thing that's needed is paragraph offset, so no need to split runs */ + ME_JoinParagraphs(editor, ME_GetParagraph(tmp.pRun)); + break; + } + case diUndoSplitParagraph: + { + ME_Cursor tmp; + ME_DisplayItem *new_para; + ME_CursorFromCharOfs(editor, pUItem->nStart, &tmp); + if (tmp.nOffset) + tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset); + new_para = ME_SplitParagraph(editor, tmp.pRun, tmp.pRun->member.run.style); + assert(pItem->member.para.pFmt->cbSize == sizeof(PARAFORMAT2)); + CopyMemory(new_para->member.para.pFmt, pItem->member.para.pFmt, sizeof(PARAFORMAT2)); + break; + } + default: + assert(0 == "PlayUndoItem, unexpected type"); + } +} + +void ME_Undo(ME_TextEditor *editor) { + ME_DisplayItem *p; + ME_UndoMode nMode = editor->nUndoMode; + + assert(nMode == umAddToUndo || nMode == umIgnore); + + /* no undo items ? */ + if (!editor->pUndoStack) + return; + + /* watch out for uncommited transactions ! */ + assert(editor->pUndoStack->type == diUndoEndTransaction); + + editor->nUndoMode = umAddToRedo; + p = editor->pUndoStack->next; + ME_DestroyDisplayItem(editor->pUndoStack); + do { + ME_DisplayItem *pp = p; + ME_PlayUndoItem(editor, p); + p = p->next; + ME_DestroyDisplayItem(pp); + } while(p && p->type != diUndoEndTransaction); + ME_AddUndoItem(editor, diUndoEndTransaction, NULL); + editor->pUndoStack = p; + if (p) + p->prev = NULL; + editor->nUndoMode = nMode; + editor->nModifyStep--; + ME_UpdateRepaint(editor); +} + +void ME_Redo(ME_TextEditor *editor) { + ME_DisplayItem *p; + ME_UndoMode nMode = editor->nUndoMode; + + assert(nMode == umAddToUndo || nMode == umIgnore); + + /* no redo items ? */ + if (!editor->pRedoStack) + return; + + /* watch out for uncommited transactions ! */ + assert(editor->pRedoStack->type == diUndoEndTransaction); + + editor->nUndoMode = umAddBackToUndo; + p = editor->pRedoStack->next; + ME_DestroyDisplayItem(editor->pRedoStack); + do { + ME_DisplayItem *pp = p; + ME_PlayUndoItem(editor, p); + p = p->next; + ME_DestroyDisplayItem(pp); + } while(p && p->type != diUndoEndTransaction); + ME_AddUndoItem(editor, diUndoEndTransaction, NULL); + editor->pRedoStack = p; + if (p) + p->prev = NULL; + editor->nUndoMode = nMode; + editor->nModifyStep++; + ME_UpdateRepaint(editor); +} diff --git a/reactos/lib/riched20/wrap.c b/reactos/lib/riched20/wrap.c new file mode 100644 index 00000000000..683b659130f --- /dev/null +++ b/reactos/lib/riched20/wrap.c @@ -0,0 +1,449 @@ +/* + * RichEdit - Paragraph wrapping. Don't try to understand it. You've been + * warned ! + * + * Copyright 2004 by Krzysztof Foltman + * + * 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" + +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 + */ + +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; + return item; +} + +void ME_BeginRow(ME_WrapContext *wc) +{ + wc->pRowStart = NULL; + wc->bOverflown = FALSE; + 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) +{ + ME_DisplayItem *p, *row, *para; + int ascent = 0, descent = 0, width=0, shift = 0, align = 0; + /* wrap text */ + para = ME_GetParagraph(wc->pRowStart); + for (p = wc->pRowStart; p!=pEnd; p = p->next) + { + /* ENDPARA run shouldn't affect row height, except if it's the only run in the paragraph */ + if (p->type==diRun && ((p==wc->pRowStart) || !(p->member.run.nFlags & MERF_ENDPARA))) { /* FIXME add more run types */ + if (p->member.run.nAscent>ascent) + ascent = p->member.run.nAscent; + if (p->member.run.nDescent>descent) + descent = p->member.run.nDescent; + if (!(p->member.run.nFlags & (MERF_ENDPARA|MERF_SKIPPED))) + width += p->member.run.nWidth; + } + } + row = ME_MakeRow(ascent+descent, ascent, width); + row->member.row.nYPos = wc->pt.y; + row->member.row.nLMargin = (!wc->nRow ? wc->nFirstMargin : wc->nLeftMargin); + row->member.row.nRMargin = wc->nRightMargin; + assert(para->member.para.pFmt->dwMask & PFM_ALIGNMENT); + align = para->member.para.pFmt->wAlignment; + if (align == PFA_CENTER) + shift = (wc->nAvailWidth-width)/2; + if (align == PFA_RIGHT) + shift = wc->nAvailWidth-width; + for (p = wc->pRowStart; p!=pEnd; p = p->next) + { + if (p->type==diRun) { /* FIXME add more run types */ + p->member.run.pt.x += row->member.row.nLMargin+shift; + } + } + ME_InsertBefore(wc->pRowStart, row); + wc->nRow++; + wc->pt.y += ascent+descent; + ME_BeginRow(wc); +} + +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) { + if (p->type == diParagraph || p->type == diTextEnd) + return; + if (p->type == diRun) + { + ME_Run *run = &p->member.run; + TRACE("%s - (%d, %d)\n", debugstr_w(run->strText->szData), run->pt.x, run->pt.y); + } + 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_DisplayItem *ME_MaximizeSplit(ME_WrapContext *wc, ME_DisplayItem *p, int i) +{ + ME_DisplayItem *pp, *piter = p; + int j; + if (!i) + return NULL; + j = ME_ReverseFindNonWhitespaceV(p->member.run.strText, i); + if (j>0) { + pp = ME_SplitRun(wc->context, piter, j); + wc->pt.x += piter->member.run.nWidth; + return pp; + } + else + { + pp = piter; + /* omit all spaces before split point */ + while(piter != wc->pRowStart) + { + piter = ME_FindItemBack(piter, diRun); + if (piter->member.run.nFlags & MERF_WHITESPACE) + { + pp = piter; + continue; + } + if (piter->member.run.nFlags & MERF_ENDWHITE) + { + j = ME_ReverseFindNonWhitespaceV(piter->member.run.strText, i); + pp = ME_SplitRun(wc->context, piter, i); + wc->pt = pp->member.run.pt; + return pp; + } + /* this run is the end of spaces, so the run edge is a good point to split */ + wc->pt = pp->member.run.pt; + wc->bOverflown = TRUE; + TRACE("Split point is: %s|%s\n", debugstr_w(piter->member.run.strText->szData), debugstr_w(pp->member.run.strText->szData)); + return pp; + } + wc->pt = piter->member.run.pt; + return piter; + } +} + +ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem *p, int loc) +{ + ME_DisplayItem *piter = p, *pp; + int i, idesp, len; + ME_Run *run = &p->member.run; + + idesp = i = ME_CharFromPoint(wc->context->editor, loc, run); + len = ME_StrVLen(run->strText); + assert(len>0); + assert(istrText, i); + pp = ME_MaximizeSplit(wc, p, i); + if (pp) + return pp; + } + TRACE("Must backtrack to split at: %s\n", debugstr_w(p->member.run.strText->szData)); + if (wc->pLastSplittableRun) + { + if (wc->pLastSplittableRun->member.run.nFlags & MERF_GRAPHICS) + { + wc->pt = wc->ptLastSplittableRun; + return wc->pLastSplittableRun; + } + else if (wc->pLastSplittableRun->member.run.nFlags & MERF_SPLITTABLE) + { + /* the following two lines are just to check if we forgot to call UpdateRunFlags earlier, + 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); + /* don't split words */ + i = ME_ReverseFindWhitespaceV(run->strText, len); + if (i == len) + i = ME_ReverseFindNonWhitespaceV(run->strText, len); + if (i) { + ME_DisplayItem *piter2 = ME_SplitRun(wc->context, piter, i); + wc->pt = piter2->member.run.pt; + return piter2; + } + /* splittable = must have whitespaces */ + assert(0 == "Splittable, but no whitespaces"); + } + else + { + /* restart from the first run beginning with spaces */ + wc->pt = wc->ptLastSplittableRun; + return wc->pLastSplittableRun; + } + } + TRACE("Backtracking failed, trying desperate: %s\n", debugstr_w(p->member.run.strText->szData)); + /* OK, no better idea, so assume we MAY split words if we can split at all*/ + if (idesp) + return ME_SplitRun(wc->context, piter, idesp); + else + if (wc->pRowStart && piter != wc->pRowStart) + { + /* don't need to break current run, because it's possible to split + before this run */ + wc->bOverflown = TRUE; + return piter; + } + else + { + /* split point inside first character - no choice but split after that char */ + int chars = 1; + int pos2 = ME_StrRelPos(run->strText, 0, &chars); + if (pos2 != len) { + /* the run is more than 1 char, so we may split */ + return ME_SplitRun(wc->context, piter, pos2); + } + /* the run is one char, can't split it */ + return piter; + } +} + +ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p) +{ + ME_DisplayItem *pp; + ME_Run *run; + int len; + + 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); + + if (wc->bOverflown) /* just skipping final whitespaces */ + { + if (run->nFlags & MERF_WHITESPACE) { + 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; + black = ME_FindNonWhitespaceV(run->strText, 0); + if (black) { + 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; + } + } + /* black run: the row goes from pRowStart to the previous run */ + ME_InsertRowStart(wc, p); + return p; + } + /* we're not at the end of the row */ + /* will current run fit? */ + if (wc->pt.x + run->nWidth > wc->nAvailWidth) + { + 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) { + wc->bOverflown = TRUE; + return p; + } + /* can we separate out the last spaces ? (to use overflow logic later) */ + if (run->nFlags & MERF_ENDWHITE) + { + /* we aren't sure if it's *really* necessary, it's a good start however */ + int black = ME_ReverseFindNonWhitespaceV(run->strText, len); + ME_SplitRun(wc->context, p, black); + /* handle both parts again */ + return p; + } + /* determine the split point by backtracking */ + pp = ME_SplitByBacktracking(wc, p, loc); + if (pp == wc->pRowStart) + { + /* we had only spaces so far, entire content can be omitted */ + wc->pt.x = 0; + return p->next; + } + if (p != pp) /* found a suitable split point */ + { + wc->bOverflown = TRUE; + return pp; + } + /* we detected that it's best to split on start of this run */ + if (wc->bOverflown) + return pp; + 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))) + { + wc->pLastSplittableRun = p; + wc->ptLastSplittableRun = wc->pt; + } + wc->pt.x += run->nWidth; + return p->next; +} + +void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) { + ME_DisplayItem *p; + ME_WrapContext wc; + + 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; + wc.nFirstMargin = tp->member.para.nFirstMargin; + wc.nLeftMargin = tp->member.para.nLeftMargin; + wc.nRightMargin = tp->member.para.nRightMargin; + wc.nRow = 0; + wc.pt.x = 0; + wc.pt.y = 0; + 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); + if (p->type == diRun) { + p = ME_WrapHandleRun(&wc, p); + continue; + } + p = p->next; + } + ME_WrapEndParagraph(&wc, p); + tp->member.para.nFlags &= ~MEPF_REWRAP; + tp->member.para.nHeight = wc.pt.y; +} + + +void ME_PrepareParagraphForWrapping(ME_Context *c, ME_DisplayItem *tp) { + ME_DisplayItem *p; + /* remove all items that will be reinserted by paragraph wrapper anyway */ + for (p = tp->next; p!=tp->member.para.next_para; p = p->next) { + switch(p->type) { + case diStartRow: + p = p->prev; + ME_Remove(p->next); + break; + default: + break; + } + } + /* join runs that can be joined, set up flags */ + for (p = tp->next; p!=tp->member.para.next_para; p = p->next) { + int changed = 0; + switch(p->type) { + case diStartRow: assert(0); break; /* should have deleted it */ + case diRun: + while (p->next->type == diRun) { /* FIXME */ + if (ME_CanJoinRuns(&p->member.run, &p->next->member.run)) { + ME_JoinRuns(c->editor, p); + changed = 1; + } + else + break; + } + p->member.run.nFlags &= ~MERF_CALCBYWRAP; + break; + default: + break; + } + } +} + +void ME_WrapMarkedParagraphs(ME_TextEditor *editor) { + HWND hWnd = editor->hWnd; + HDC hDC = GetDC(hWnd); + ME_DisplayItem *item; + ME_Context c; + + 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; + + 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); +}