Autosyncing with Wine HEAD

svn path=/trunk/; revision=26433
This commit is contained in:
The Wine Synchronizer 2007-04-20 11:26:32 +00:00
parent ac9fa62a28
commit c1a0a2b00c
23 changed files with 3864 additions and 1342 deletions

View file

@ -1,29 +0,0 @@
TOPSRCDIR = @top_srcdir@
TOPOBJDIR = ../..
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = riched20.dll
IMPORTLIB = libriched20.$(IMPLIBEXT)
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 \
writer.c
@MAKE_DLL_RULES@
### Dependencies:

View file

@ -2,6 +2,7 @@
* RichEdit - Caret and selection functions.
*
* Copyright 2004 by Krzysztof Foltman
* Copyright 2005 by Phil Krylov
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -15,7 +16,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
@ -23,6 +24,10 @@
WINE_DEFAULT_DEBUG_CHANNEL(richedit);
static BOOL
ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs);
void ME_GetSelection(ME_TextEditor *editor, int *from, int *to)
{
*from = ME_GetCursorOfs(editor, 0);
@ -73,93 +78,165 @@ int ME_GetTextLengthEx(ME_TextEditor *editor, GETTEXTLENGTHEX *how)
}
void ME_SetSelection(ME_TextEditor *editor, int from, int to)
int ME_SetSelection(ME_TextEditor *editor, int from, int to)
{
int selectionEnd = 0;
const int len = ME_GetTextLength(editor);
/* all negative values are effectively the same */
if (from < 0)
from = -1;
if (to < 0)
to = -1;
/* select all */
if (from == 0 && to == -1)
{
editor->pCursors[1].pRun = ME_FindItemFwd(editor->pBuffer->pFirst, diRun);
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);
editor->pCursors[0].nOffset = 0;
ME_InvalidateSelection(editor);
ME_ClearTempStyle(editor);
return;
return len + 1;
}
if (from == -1)
/* if both values are equal and also out of bound, that means to */
/* put the selection at the end of the text */
if ((from == to) && (to < 0 || to > len))
{
editor->pCursors[1] = editor->pCursors[0];
ME_Repaint(editor);
selectionEnd = 1;
}
else
{
/* if from is negative and to is positive then selection is */
/* deselected and caret moved to end of the current selection */
if (from < 0)
{
int start, end;
ME_GetSelection(editor, &start, &end);
editor->pCursors[1] = editor->pCursors[0];
ME_Repaint(editor);
ME_ClearTempStyle(editor);
return end;
}
/* adjust to if it's a negative value */
if (to < 0)
to = len + 1;
/* flip from and to if they are reversed */
if (from>to)
{
int tmp = from;
from = to;
to = tmp;
}
/* after fiddling with the values, we find from > len && to > len */
if (from > len)
selectionEnd = 1;
/* special case with to too big */
else if (to > len)
to = len + 1;
}
if (selectionEnd)
{
editor->pCursors[1].pRun = editor->pCursors[0].pRun = ME_FindItemBack(editor->pBuffer->pLast, diRun);
editor->pCursors[1].nOffset = editor->pCursors[0].nOffset = 0;
ME_InvalidateSelection(editor);
ME_ClearTempStyle(editor);
return;
}
if (from>to)
{
int tmp = from;
from = to;
to = tmp;
return len;
}
ME_RunOfsFromCharOfs(editor, from, &editor->pCursors[1].pRun, &editor->pCursors[1].nOffset);
ME_RunOfsFromCharOfs(editor, to, &editor->pCursors[0].pRun, &editor->pCursors[0].nOffset);
ME_RunOfsFromCharOfs(editor, to, &editor->pCursors[0].pRun, &editor->pCursors[0].nOffset);
return to;
}
void ME_MoveCaret(ME_TextEditor *editor)
{
HDC hDC = GetDC(editor->hWnd);
ME_Context c;
ME_Cursor *pCursor = &editor->pCursors[0];
void
ME_GetCursorCoordinates(ME_TextEditor *editor, ME_Cursor *pCursor,
int *x, int *y, int *height)
{
ME_DisplayItem *pCursorRun = pCursor->pRun;
ME_DisplayItem *pSizeRun = pCursor->pRun;
ME_InitContext(&c, editor, hDC);
assert(!pCursor->nOffset || !editor->bCaretAtEnd);
assert(height && x && y);
assert(!(ME_GetParagraph(pCursorRun)->member.para.nFlags & MEPF_REWRAP));
assert(pCursor->pRun);
assert(pCursor->pRun->type == diRun);
if (pCursorRun->type == diRun) {
ME_DisplayItem *row = ME_FindItemBack(pCursorRun, diStartRowOrParagraph);
if (row) {
HDC hDC = GetDC(editor->hWnd);
ME_Context c;
ME_DisplayItem *run = pCursorRun;
ME_DisplayItem *para;
ME_DisplayItem *para = NULL;
SIZE sz = {0, 0};
ME_InitContext(&c, editor, hDC);
if (!pCursor->nOffset && !editor->bCaretAtEnd)
{
ME_DisplayItem *prev = ME_FindItemBack(pCursorRun, diRunOrStartRow);
assert(prev);
if (prev->type == diRun)
pSizeRun = prev;
}
assert(row->type == diStartRow); /* paragraph -> run without start row ?*/
para = ME_FindItemBack(row, diParagraph);
assert(para);
assert(para->type == diParagraph);
if (editor->bCaretAtEnd && !pCursor->nOffset &&
run == ME_FindItemFwd(row, diRun))
{
ME_DisplayItem *tmp = ME_FindItemBack(row, diRunOrParagraph);
assert(tmp);
if (tmp->type == diRun)
{
row = ME_FindItemBack(tmp, diStartRow);
pSizeRun = run = tmp;
assert(run);
assert(run->type == diRun);
sz = ME_GetRunSize(&c, &para->member.para, &run->member.run, ME_StrLen(run->member.run.strText));
}
}
if (pCursor->nOffset && !(run->member.run.nFlags & MERF_SKIPPED)) {
sz = ME_GetRunSize(&c, &para->member.para, &run->member.run, pCursor->nOffset);
}
CreateCaret(editor->hWnd, NULL, 0, pSizeRun->member.run.nAscent+pSizeRun->member.run.nDescent);
SetCaretPos(run->member.run.pt.x+sz.cx,
para->member.para.nYPos+row->member.row.nBaseline+pSizeRun->member.run.pt.y-pSizeRun->member.run.nAscent-ME_GetYScrollPos(editor));
} else {
assert(0 == "Wrapped paragraph run without a row?");
CreateCaret(editor->hWnd, NULL, 0, 10);
SetCaretPos(0,0);
*height = pSizeRun->member.run.nAscent + pSizeRun->member.run.nDescent;
*x = run->member.run.pt.x + sz.cx;
*y = para->member.para.nYPos + row->member.row.nBaseline + pSizeRun->member.run.pt.y - pSizeRun->member.run.nAscent - ME_GetYScrollPos(editor);
ME_DestroyContext(&c);
ReleaseDC(editor->hWnd, hDC);
return;
}
}
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);
*height = 10; /* FIXME use global font */
*x = 0;
*y = 0;
}
void
ME_MoveCaret(ME_TextEditor *editor)
{
int x, y, height;
ME_WrapMarkedParagraphs(editor);
ME_GetCursorCoordinates(editor, &editor->pCursors[0], &x, &y, &height);
CreateCaret(editor->hWnd, NULL, 0, height);
SetCaretPos(x, y);
}
void ME_ShowCaret(ME_TextEditor *ed)
{
ME_MoveCaret(ed);
@ -292,58 +369,60 @@ void ME_DeleteTextAtCursor(ME_TextEditor *editor, int nCursor,
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);
}
static void
static ME_DisplayItem *
ME_InternalInsertTextFromCursor(ME_TextEditor *editor, int nCursor,
const WCHAR *str, int len, ME_Style *style,
int flags)
{
ME_DisplayItem *pNewRun = NULL;
ME_Cursor *p = &editor->pCursors[nCursor];
editor->bCaretAtEnd = FALSE;
assert(p->pRun->type == diRun);
ME_AddRefStyle(style);
return ME_InsertRunAtCursor(editor, p, style, str, len, flags);
}
/* FIXME this is temporary, just to have something to test how bad graphics handler is */
void ME_InsertGraphicsFromCursor(ME_TextEditor *editor, int nCursor)
{
ME_Style *pStyle = ME_GetInsertStyle(editor, nCursor);
WCHAR space = ' ';
pNewRun = ME_MakeRun(style, ME_MakeStringN(str, len), flags); /* addrefs style */
ME_InsertRun(editor, ME_CharOfsFromRunOfs(editor, p->pRun, p->nOffset), pNewRun);
ME_DestroyDisplayItem(pNewRun);
ME_ReleaseStyle(style);
/* FIXME no no no */
if (ME_IsSelection(editor))
ME_DeleteSelection(editor);
ME_InternalInsertTextFromCursor(editor, nCursor, &space, 1, pStyle,
MERF_GRAPHICS);
ME_SendSelChange(editor);
}
void
ME_InsertTableCellFromCursor(ME_TextEditor *editor, int nCursor)
{
WCHAR tab = '\t';
ME_DisplayItem *p, *run;
ME_Style *pStyle = ME_GetInsertStyle(editor, nCursor);
p = ME_InternalInsertTextFromCursor(editor, nCursor, &tab, 1, pStyle,
MERF_CELL);
run = p;
while ((run = ME_FindItemBack(run, diRunOrParagraph))->type == diRun)
{
if (run->member.run.nFlags & MERF_CELL)
{
assert(run->member.run.pCell->next);
p->member.run.pCell = run->member.run.pCell->next;
return;
}
}
assert(run->type == diParagraph);
assert(run->member.para.bTable);
assert(run->member.para.pCells);
p->member.run.pCell = run->member.para.pCells;
}
@ -352,16 +431,25 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
{
const WCHAR *pos;
ME_Cursor *p = NULL;
assert(style);
int freeSpace;
/* FIXME really HERE ? */
if (ME_IsSelection(editor))
ME_DeleteSelection(editor);
/* FIXME: is this too slow? */
/* Didn't affect performance for WM_SETTEXT (around 50sec/30K) */
freeSpace = editor->nTextLimit - ME_GetTextLength(editor);
/* text operations set modified state */
editor->nModifyStep = 1;
assert(style);
assert(nCursor>=0 && nCursor<editor->nCursors);
if (len == -1)
len = lstrlenW(str);
len = min(len, freeSpace);
while (len)
{
pos = str;
@ -385,14 +473,10 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
}
if (pos-str < len) { /* handle EOLs */
ME_DisplayItem *tp, *end_run;
ME_Paragraph *para;
ME_Style *tmp_style;
if (pos!=str)
ME_InternalInsertTextFromCursor(editor, nCursor, str, pos-str, style, 0);
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];
@ -420,69 +504,170 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
}
}
static BOOL ME_ArrowLeft(ME_TextEditor *editor, ME_Cursor *p)
static BOOL
ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs)
{
if (p->nOffset) {
p->nOffset = ME_StrRelPos2(p->pRun->member.run.strText, p->nOffset, -1);
ME_DisplayItem *pRun = pCursor->pRun;
if (nRelOfs == -1)
{
if (!pCursor->nOffset)
{
do {
pRun = ME_FindItemBack(pRun, diRunOrParagraph);
assert(pRun);
switch (pRun->type)
{
case diRun:
break;
case diParagraph:
if (pRun->member.para.prev_para->type == diTextStart)
return FALSE;
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);
break;
default:
assert(pRun->type != diRun && pRun->type != diParagraph);
return FALSE;
}
} while (RUN_IS_HIDDEN(&pRun->member.run));
pCursor->pRun = pRun;
if (pRun->member.run.nFlags & MERF_ENDPARA)
pCursor->nOffset = 0;
else
pCursor->nOffset = pRun->member.run.strText->nLen;
}
if (pCursor->nOffset)
pCursor->nOffset = ME_StrRelPos2(pCursor->pRun->member.run.strText, pCursor->nOffset, nRelOfs);
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);
if (!(pRun->member.run.nFlags & MERF_ENDPARA))
{
int new_ofs = ME_StrRelPos2(pRun->member.run.strText, pCursor->nOffset, nRelOfs);
if (new_ofs < pRun->member.run.strText->nLen)
{
pCursor->nOffset = new_ofs;
return TRUE;
}
else
assert(0);
}
if (pRun->type == diParagraph)
do {
pRun = ME_FindItemFwd(pRun, diRun);
} while (pRun && RUN_IS_HIDDEN(&pRun->member.run));
if (pRun)
{
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;
pCursor->pRun = pRun;
pCursor->nOffset = 0;
return TRUE;
}
assert(0);
}
return FALSE;
}
static BOOL ME_ArrowRight(ME_TextEditor *editor, ME_Cursor *p)
static BOOL
ME_MoveCursorWords(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs)
{
ME_DisplayItem *pRun;
ME_DisplayItem *pRun = cursor->pRun, *pOtherRun;
int nOffset = cursor->nOffset;
if (!(p->pRun->member.run.nFlags & MERF_ENDPARA))
if (nRelOfs == -1)
{
int new_ofs = ME_StrRelPos2(p->pRun->member.run.strText, p->nOffset, 1);
if (new_ofs<p->pRun->member.run.strText->nLen)
/* Backward movement */
while (TRUE)
{
p->nOffset = new_ofs;
return TRUE;
nOffset = ME_CallWordBreakProc(editor, pRun->member.run.strText,
nOffset, WB_MOVEWORDLEFT);
if (nOffset)
break;
pOtherRun = ME_FindItemBack(pRun, diRunOrParagraph);
if (pOtherRun->type == diRun)
{
if (ME_CallWordBreakProc(editor, pOtherRun->member.run.strText,
pOtherRun->member.run.strText->nLen - 1,
WB_ISDELIMITER)
&& !(pRun->member.run.nFlags & MERF_ENDPARA)
&& !(cursor->pRun == pRun && cursor->nOffset == 0)
&& !ME_CallWordBreakProc(editor, pRun->member.run.strText, 0,
WB_ISDELIMITER))
break;
pRun = pOtherRun;
nOffset = pOtherRun->member.run.strText->nLen;
}
else if (pOtherRun->type == diParagraph)
{
if (cursor->pRun == pRun && cursor->nOffset == 0)
{
/* Paragraph breaks are treated as separate words */
if (pOtherRun->member.para.prev_para->type == diTextStart)
return FALSE;
pRun = ME_FindItemBack(pOtherRun, diRunOrParagraph);
}
break;
}
}
}
pRun = ME_FindItemFwd(p->pRun, diRun);
if (pRun) {
p->pRun = pRun;
assert(p->pRun->type == diRun);
p->nOffset = 0;
else
{
/* Forward movement */
BOOL last_delim = FALSE;
while (TRUE)
{
if (last_delim && !ME_CallWordBreakProc(editor, pRun->member.run.strText,
nOffset, WB_ISDELIMITER))
break;
nOffset = ME_CallWordBreakProc(editor, pRun->member.run.strText,
nOffset, WB_MOVEWORDRIGHT);
if (nOffset < pRun->member.run.strText->nLen)
break;
pOtherRun = ME_FindItemFwd(pRun, diRunOrParagraphOrEnd);
if (pOtherRun->type == diRun)
{
last_delim = ME_CallWordBreakProc(editor, pRun->member.run.strText,
nOffset - 1, WB_ISDELIMITER);
pRun = pOtherRun;
nOffset = 0;
}
else if (pOtherRun->type == diParagraph)
{
if (cursor->pRun == pRun)
pRun = ME_FindItemFwd(pOtherRun, diRun);
nOffset = 0;
break;
}
else /* diTextEnd */
{
if (cursor->pRun == pRun)
return FALSE;
nOffset = 0;
break;
}
}
}
cursor->pRun = pRun;
cursor->nOffset = nOffset;
return TRUE;
}
void
ME_SelectWord(ME_TextEditor *editor)
{
if (!(editor->pCursors[0].pRun->member.run.nFlags & MERF_ENDPARA))
ME_MoveCursorWords(editor, &editor->pCursors[0], -1);
ME_MoveCursorWords(editor, &editor->pCursors[1], +1);
ME_InvalidateSelection(editor);
ME_SendSelChange(editor);
}
int ME_GetCursorOfs(ME_TextEditor *editor, int nCursor)
{
ME_Cursor *pCursor = &editor->pCursors[nCursor];
@ -599,6 +784,7 @@ ME_CharFromPos(ME_TextEditor *editor, int x, int y)
GetClientRect(editor->hWnd, &rc);
if (x < 0 || y < 0 || x >= rc.right || y >= rc.bottom)
return -1;
y += ME_GetYScrollPos(editor);
ME_FindPixelPos(editor, x, y, &cursor, NULL);
return (ME_GetParagraph(cursor.pRun)->member.para.nCharOfs
+ cursor.pRun->member.run.nCharOfs + cursor.nOffset);
@ -630,10 +816,9 @@ void ME_LButtonDown(ME_TextEditor *editor, int x, int y)
is_selection = 1;
}
}
ME_InvalidateSelection(editor);
HideCaret(editor->hWnd);
ME_MoveCaret(editor);
if (is_selection)
ME_Repaint(editor);
ShowCaret(editor->hWnd);
ME_ClearTempStyle(editor);
ME_SendSelChange(editor);
@ -646,16 +831,18 @@ void ME_MouseMove(ME_TextEditor *editor, int x, int y)
y += ME_GetYScrollPos(editor);
tmp_cursor = editor->pCursors[0];
if (!ME_FindPixelPos(editor, x, y, &editor->pCursors[0], &editor->bCaretAtEnd))
/* return */;
/* FIXME: do something with the return value of ME_FindPixelPos */
ME_FindPixelPos(editor, x, y, &tmp_cursor, &editor->bCaretAtEnd);
if (tmp_cursor.pRun == editor->pCursors[0].pRun &&
tmp_cursor.nOffset == editor->pCursors[0].nOffset)
return;
ME_InvalidateSelection(editor);
editor->pCursors[0] = tmp_cursor;
HideCaret(editor->hWnd);
ME_MoveCaret(editor);
ME_Repaint(editor);
ME_InvalidateSelection(editor);
ShowCaret(editor->hWnd);
ME_SendSelChange(editor);
}
@ -726,50 +913,36 @@ static int ME_GetXForArrow(ME_TextEditor *editor, ME_Cursor *pCursor)
return x;
}
static 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);
}
static void ME_ArrowDown(ME_TextEditor *editor, ME_Cursor *pCursor)
static void
ME_MoveCursorLines(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs)
{
ME_DisplayItem *pRun = pCursor->pRun;
ME_DisplayItem *pItem;
int x = ME_GetXForArrow(editor, pCursor);
if (!pCursor->nOffset && editor->bCaretAtEnd)
{
if (editor->bCaretAtEnd && !pCursor->nOffset)
pRun = ME_FindItemBack(pRun, diRun);
/* x = pRun->member.run.pt.x + pRun->member.run.nWidth; */
if (!pRun)
return;
if (nRelOfs == -1)
{
/* start of this row */
pItem = ME_FindItemBack(pRun, diStartRow);
assert(pItem);
/* start of the previous row */
pItem = ME_FindItemBack(pItem, diStartRow);
}
else
{
/* start of the next row */
pItem = ME_FindItemFwd(pRun, diStartRow);
/* FIXME If diParagraph is before diStartRow, wrap the next paragraph?
*/
}
/* 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 */
/* row not found - ignore */
return;
}
pCursor->pRun = ME_FindRunInRow(editor, pItem, x, &pCursor->nOffset, &editor->bCaretAtEnd);
@ -777,6 +950,7 @@ static void ME_ArrowDown(ME_TextEditor *editor, ME_Cursor *pCursor)
assert(pCursor->pRun->type == diRun);
}
static void ME_ArrowPageUp(ME_TextEditor *editor, ME_Cursor *pCursor)
{
ME_DisplayItem *pRun = pCursor->pRun;
@ -819,9 +993,9 @@ static void ME_ArrowPageUp(ME_TextEditor *editor, ME_Cursor *pCursor)
ME_EnsureVisible(editor, ME_FindItemFwd(editor->pBuffer->pFirst, diRun));
ME_Repaint(editor);
}
else {
ME_Scroll(editor, 0, ys-yprev);
ME_Repaint(editor);
else
{
ME_ScrollUp(editor, ys-yprev);
}
assert(pCursor->pRun);
assert(pCursor->pRun->type == diRun);
@ -872,9 +1046,9 @@ static void ME_ArrowPageDown(ME_TextEditor *editor, ME_Cursor *pCursor)
ME_EnsureVisible(editor, ME_FindItemBack(editor->pBuffer->pLast, diRun));
ME_Repaint(editor);
}
else {
ME_Scroll(editor, 0, ys-yprev);
ME_Repaint(editor);
else
{
ME_ScrollUp(editor,ys-yprev);
}
assert(pCursor->pRun);
assert(pCursor->pRun->type == diRun);
@ -883,6 +1057,10 @@ static void ME_ArrowPageDown(ME_TextEditor *editor, ME_Cursor *pCursor)
static void ME_ArrowHome(ME_TextEditor *editor, ME_Cursor *pCursor)
{
ME_DisplayItem *pRow = ME_FindItemBack(pCursor->pRun, diStartRow);
/* bCaretAtEnd doesn't make sense if the cursor isn't set at the
first character of the next row */
assert(!editor->bCaretAtEnd || !pCursor->nOffset);
ME_WrapMarkedParagraphs(editor);
if (pRow) {
ME_DisplayItem *pRun;
if (editor->bCaretAtEnd && !pCursor->nOffset) {
@ -962,25 +1140,6 @@ static int ME_GetSelCursor(ME_TextEditor *editor, int dir)
return 1;
}
static 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];
ME_Repaint(editor);
return TRUE;
}
BOOL ME_UpdateSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor)
{
ME_Cursor old_anchor = editor->pCursors[1];
@ -1007,14 +1166,6 @@ BOOL ME_UpdateSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor)
return TRUE;
}
static void ME_RepaintSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor)
{
if (ME_UpdateSelection(editor, pTempCursor)) {
ME_EnsureVisible(editor, editor->pCursors[0].pRun);
ME_Repaint(editor);
}
}
void ME_DeleteSelection(ME_TextEditor *editor)
{
int from, to;
@ -1042,8 +1193,12 @@ ME_Style *ME_GetSelectionInsertStyle(ME_TextEditor *editor)
void ME_SendSelChange(ME_TextEditor *editor)
{
SELCHANGE sc;
ME_ClearTempStyle(editor);
if (!(editor->nEventMask & ENM_SELCHANGE))
return;
sc.nmhdr.hwndFrom = editor->hWnd;
sc.nmhdr.idFrom = GetWindowLongW(editor->hWnd, GWLP_ID);
sc.nmhdr.code = EN_SELCHANGE;
@ -1056,116 +1211,69 @@ void ME_SendSelChange(ME_TextEditor *editor)
SendMessageW(GetParent(editor->hWnd), WM_NOTIFY, sc.nmhdr.idFrom, (LPARAM)&sc);
}
BOOL ME_ArrowKey(ME_TextEditor *editor, int nVKey, int nCtrl)
BOOL
ME_ArrowKey(ME_TextEditor *editor, int nVKey, BOOL extend, BOOL ctrl)
{
int nCursor = 0;
ME_Cursor *p = &editor->pCursors[nCursor];
ME_Cursor tmp_curs = *p;
BOOL success = FALSE;
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;
case VK_PRIOR:
ME_ArrowPageUp(editor, p);
ME_ClearTempStyle(editor);
ME_SendSelChange(editor);
return TRUE;
case VK_NEXT:
ME_ArrowPageDown(editor, p);
ME_ClearTempStyle(editor);
ME_SendSelChange(editor);
return TRUE;
}
ME_CheckCharOffsets(editor);
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);
ME_SendRequestResize(editor, FALSE);
return TRUE;
}
if (ME_ArrowLeft(editor, p)) {
editor->bCaretAtEnd = FALSE; /* FIXME or maybe not */
ME_ClearTempStyle(editor);
ME_MoveCaret(editor);
ME_DeleteTextAtCursor(editor, nCursor, 1);
ME_UpdateRepaint(editor);
ME_SendRequestResize(editor, FALSE);
}
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_ClearTempStyle(editor);
ME_UpdateRepaint(editor);
ME_SendRequestResize(editor, FALSE);
return TRUE;
}
ME_DeleteTextAtCursor(editor, nCursor, 1);
ME_ClearTempStyle(editor);
ME_UpdateRepaint(editor);
ME_SendRequestResize(editor, FALSE);
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;
if (ctrl)
success = ME_MoveCursorWords(editor, &tmp_curs, -1);
else
success = ME_MoveCursorChars(editor, &tmp_curs, -1);
break;
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;
if (ctrl)
success = ME_MoveCursorWords(editor, &tmp_curs, +1);
else
success = ME_MoveCursorChars(editor, &tmp_curs, +1);
break;
case VK_UP:
ME_MoveCursorLines(editor, &tmp_curs, -1);
break;
case VK_DOWN:
ME_MoveCursorLines(editor, &tmp_curs, +1);
break;
case VK_PRIOR:
ME_ArrowPageUp(editor, &tmp_curs);
break;
case VK_NEXT:
ME_ArrowPageDown(editor, &tmp_curs);
break;
case VK_HOME: {
if (ctrl)
ME_ArrowCtrlHome(editor, &tmp_curs);
else
ME_ArrowHome(editor, &tmp_curs);
editor->bCaretAtEnd = 0;
break;
}
case VK_END:
if (ctrl)
ME_ArrowCtrlEnd(editor, &tmp_curs);
else
ME_ArrowEnd(editor, &tmp_curs);
break;
}
return FALSE;
if (!extend)
editor->pCursors[1] = tmp_curs;
*p = tmp_curs;
ME_InvalidateSelection(editor);
ME_Repaint(editor);
HideCaret(editor->hWnd);
ME_EnsureVisible(editor, tmp_curs.pRun);
ME_ShowCaret(editor);
ME_SendSelChange(editor);
return success;
}

View file

@ -0,0 +1,412 @@
/*
* Richedit clipboard handling
*
* Copyright (C) 2006 Kevin Koltzau
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "editor.h"
WINE_DEFAULT_DEBUG_CHANNEL(richedit);
static UINT cfRTF = 0;
typedef struct DataObjectImpl {
const IDataObjectVtbl *lpVtbl;
LONG ref;
FORMATETC *fmtetc;
UINT fmtetc_cnt;
HANDLE unicode;
HANDLE rtf;
} DataObjectImpl;
typedef struct EnumFormatImpl {
const IEnumFORMATETCVtbl *lpVtbl;
LONG ref;
FORMATETC *fmtetc;
UINT fmtetc_cnt;
UINT cur;
} EnumFormatImpl;
static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT size, LPENUMFORMATETC *lplpformatetc);
static HRESULT WINAPI EnumFormatImpl_QueryInterface(IEnumFORMATETC *iface, REFIID riid, LPVOID *ppvObj)
{
EnumFormatImpl *This = (EnumFormatImpl*)iface;
TRACE("%p %s\n", This, debugstr_guid(riid));
if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumFORMATETC)) {
IEnumFORMATETC_AddRef(iface);
*ppvObj = (LPVOID)This;
return S_OK;
}
*ppvObj = NULL;
return E_NOINTERFACE;
}
static ULONG WINAPI EnumFormatImpl_AddRef(IEnumFORMATETC *iface)
{
EnumFormatImpl *This = (EnumFormatImpl*)iface;
LONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p) ref=%d\n", This, ref);
return ref;
}
static ULONG WINAPI EnumFormatImpl_Release(IEnumFORMATETC *iface)
{
EnumFormatImpl *This = (EnumFormatImpl*)iface;
ULONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p) ref=%d\n", This, ref);
if(!ref) {
GlobalFree(This->fmtetc);
richedit_free(This);
}
return ref;
}
static HRESULT WINAPI EnumFormatImpl_Next(IEnumFORMATETC *iface, ULONG celt,
FORMATETC *rgelt, ULONG *pceltFetched)
{
EnumFormatImpl *This = (EnumFormatImpl*)iface;
ULONG count = 0;
TRACE("(%p)->(%d %p %p)\n", This, celt, rgelt, pceltFetched);
if(!rgelt)
return E_INVALIDARG;
count = min(celt, This->fmtetc_cnt-This->cur);
if(count > 0) {
memcpy(rgelt, This->fmtetc+This->cur, count*sizeof(FORMATETC));
This->cur += count;
}
if(pceltFetched)
*pceltFetched = count;
return count == celt ? S_OK : S_FALSE;
}
static HRESULT WINAPI EnumFormatImpl_Skip(IEnumFORMATETC *iface, ULONG celt)
{
EnumFormatImpl *This = (EnumFormatImpl*)iface;
ULONG count = 0;
TRACE("(%p)->(%d)\n", This, celt);
count = min(celt, This->fmtetc_cnt-This->cur);
This->cur += count;
return count == celt ? S_OK : S_FALSE;
}
static HRESULT WINAPI EnumFormatImpl_Reset(IEnumFORMATETC *iface)
{
EnumFormatImpl *This = (EnumFormatImpl*)iface;
TRACE("(%p)\n", This);
This->cur = 0;
return S_OK;
}
static HRESULT WINAPI EnumFormatImpl_Clone(IEnumFORMATETC *iface, IEnumFORMATETC **ppenum)
{
EnumFormatImpl *This = (EnumFormatImpl*)iface;
HRESULT hr;
TRACE("(%p)->(%p)\n", This, ppenum);
if(!ppenum)
return E_INVALIDARG;
hr = EnumFormatImpl_Create(This->fmtetc, This->fmtetc_cnt, ppenum);
if(SUCCEEDED(hr))
hr = IEnumFORMATETC_Skip(*ppenum, This->cur);
return hr;
}
static const IEnumFORMATETCVtbl VT_EnumFormatImpl = {
EnumFormatImpl_QueryInterface,
EnumFormatImpl_AddRef,
EnumFormatImpl_Release,
EnumFormatImpl_Next,
EnumFormatImpl_Skip,
EnumFormatImpl_Reset,
EnumFormatImpl_Clone
};
static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT fmtetc_cnt, IEnumFORMATETC **lplpformatetc)
{
EnumFormatImpl *ret;
TRACE("\n");
ret = richedit_alloc(sizeof(EnumFormatImpl));
ret->lpVtbl = &VT_EnumFormatImpl;
ret->ref = 1;
ret->cur = 0;
ret->fmtetc_cnt = fmtetc_cnt;
ret->fmtetc = GlobalAlloc(GMEM_ZEROINIT, fmtetc_cnt*sizeof(FORMATETC));
memcpy(ret->fmtetc, fmtetc, fmtetc_cnt*sizeof(FORMATETC));
*lplpformatetc = (LPENUMFORMATETC)ret;
return S_OK;
}
static HRESULT WINAPI DataObjectImpl_QueryInterface(IDataObject *iface, REFIID riid, LPVOID *ppvObj)
{
DataObjectImpl *This = (DataObjectImpl*)iface;
TRACE("(%p)->(%s)\n", This, debugstr_guid(riid));
if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDataObject)) {
IDataObject_AddRef(iface);
*ppvObj = (LPVOID)This;
return S_OK;
}
*ppvObj = NULL;
return E_NOINTERFACE;
}
static ULONG WINAPI DataObjectImpl_AddRef(IDataObject* iface)
{
DataObjectImpl *This = (DataObjectImpl*)iface;
ULONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p) ref=%d\n", This, ref);
return ref;
}
static ULONG WINAPI DataObjectImpl_Release(IDataObject* iface)
{
DataObjectImpl *This = (DataObjectImpl*)iface;
ULONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p) ref=%d\n",This, ref);
if(!ref) {
if(This->unicode) GlobalFree(This->unicode);
if(This->rtf) GlobalFree(This->rtf);
if(This->fmtetc) GlobalFree(This->fmtetc);
richedit_free(This);
}
return ref;
}
static HRESULT WINAPI DataObjectImpl_GetData(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
{
DataObjectImpl *This = (DataObjectImpl*)iface;
TRACE("(%p)->(fmt=0x%08x tym=0x%08x)\n", This, pformatetc->cfFormat, pformatetc->tymed);
if(pformatetc->lindex != -1)
return DV_E_LINDEX;
if(!(pformatetc->tymed & TYMED_HGLOBAL))
return DV_E_TYMED;
if(This->unicode && pformatetc->cfFormat == CF_UNICODETEXT)
pmedium->u.hGlobal = This->unicode;
else if(This->rtf && pformatetc->cfFormat == cfRTF)
pmedium->u.hGlobal = This->rtf;
else
return DV_E_FORMATETC;
pmedium->tymed = TYMED_HGLOBAL;
pmedium->pUnkForRelease = (LPUNKNOWN)iface;
IUnknown_AddRef(pmedium->pUnkForRelease);
return S_OK;
}
static HRESULT WINAPI DataObjectImpl_GetDataHere(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
{
DataObjectImpl *This = (DataObjectImpl*)iface;
FIXME("(%p): stub\n", This);
return E_NOTIMPL;
}
static HRESULT WINAPI DataObjectImpl_QueryGetData(IDataObject* iface, FORMATETC *pformatetc)
{
DataObjectImpl *This = (DataObjectImpl*)iface;
UINT i;
BOOL foundFormat = FALSE;
TRACE("(%p)->(fmt=0x%08x tym=0x%08x)\n", This, pformatetc->cfFormat, pformatetc->tymed);
if(pformatetc->lindex != -1)
return DV_E_LINDEX;
for(i=0; i<This->fmtetc_cnt; i++) {
if(This->fmtetc[i].cfFormat == pformatetc->cfFormat) {
foundFormat = TRUE;
if(This->fmtetc[i].tymed == pformatetc->tymed)
return S_OK;
}
}
return foundFormat?DV_E_FORMATETC:DV_E_TYMED;
}
static HRESULT WINAPI DataObjectImpl_GetCanonicalFormatEtc(IDataObject* iface, FORMATETC *pformatectIn,
FORMATETC *pformatetcOut)
{
DataObjectImpl *This = (DataObjectImpl*)iface;
TRACE("(%p)->(%p,%p)\n", This, pformatectIn, pformatetcOut);
if(pformatetcOut) {
memcpy(pformatetcOut, pformatectIn, sizeof(FORMATETC));
pformatetcOut->ptd = NULL;
}
return DATA_S_SAMEFORMATETC;
}
static HRESULT WINAPI DataObjectImpl_SetData(IDataObject* iface, FORMATETC *pformatetc,
STGMEDIUM *pmedium, BOOL fRelease)
{
DataObjectImpl *This = (DataObjectImpl*)iface;
FIXME("(%p): stub\n", This);
return E_NOTIMPL;
}
static HRESULT WINAPI DataObjectImpl_EnumFormatEtc(IDataObject* iface, DWORD dwDirection,
IEnumFORMATETC **ppenumFormatEtc)
{
DataObjectImpl *This = (DataObjectImpl*)iface;
TRACE("(%p)->(%d)\n", This, dwDirection);
if(dwDirection != DATADIR_GET) {
FIXME("Unsupported direction: %d\n", dwDirection);
/* WinXP riched20 also returns E_NOTIMPL in this case */
return E_NOTIMPL;
}
return EnumFormatImpl_Create(This->fmtetc, This->fmtetc_cnt, ppenumFormatEtc);
}
static HRESULT WINAPI DataObjectImpl_DAdvise(IDataObject* iface, FORMATETC *pformatetc, DWORD advf,
IAdviseSink *pAdvSink, DWORD *pdwConnection)
{
DataObjectImpl *This = (DataObjectImpl*)iface;
FIXME("(%p): stub\n", This);
return E_NOTIMPL;
}
static HRESULT WINAPI DataObjectImpl_DUnadvise(IDataObject* iface, DWORD dwConnection)
{
DataObjectImpl *This = (DataObjectImpl*)iface;
FIXME("(%p): stub\n", This);
return E_NOTIMPL;
}
static HRESULT WINAPI DataObjectImpl_EnumDAdvise(IDataObject* iface, IEnumSTATDATA **ppenumAdvise)
{
DataObjectImpl *This = (DataObjectImpl*)iface;
FIXME("(%p): stub\n", This);
return E_NOTIMPL;
}
static const IDataObjectVtbl VT_DataObjectImpl =
{
DataObjectImpl_QueryInterface,
DataObjectImpl_AddRef,
DataObjectImpl_Release,
DataObjectImpl_GetData,
DataObjectImpl_GetDataHere,
DataObjectImpl_QueryGetData,
DataObjectImpl_GetCanonicalFormatEtc,
DataObjectImpl_SetData,
DataObjectImpl_EnumFormatEtc,
DataObjectImpl_DAdvise,
DataObjectImpl_DUnadvise,
DataObjectImpl_EnumDAdvise
};
static HGLOBAL get_unicode_text(ME_TextEditor *editor, CHARRANGE *lpchrg)
{
int pars, len;
WCHAR *data;
HANDLE ret;
pars = ME_CountParagraphsBetween(editor, lpchrg->cpMin, lpchrg->cpMax);
len = lpchrg->cpMax-lpchrg->cpMin;
ret = GlobalAlloc(GMEM_MOVEABLE, sizeof(WCHAR)*(len+pars+1));
data = (WCHAR *)GlobalLock(ret);
len = ME_GetTextW(editor, data, lpchrg->cpMin, len, TRUE);
data[len] = 0;
GlobalUnlock(ret);
return ret;
}
typedef struct tagME_GlobalDestStruct
{
HGLOBAL hData;
int nLength;
} ME_GlobalDestStruct;
static DWORD CALLBACK ME_AppendToHGLOBAL(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb)
{
ME_GlobalDestStruct *pData = (ME_GlobalDestStruct *)dwCookie;
int nMaxSize;
BYTE *pDest;
nMaxSize = GlobalSize(pData->hData);
if (pData->nLength+cb+1 >= cb) {
/* round up to 2^17 */
int nNewSize = (((nMaxSize+cb+1)|0x1FFFF)+1) & 0xFFFE0000;
pData->hData = GlobalReAlloc(pData->hData, nNewSize, 0);
}
pDest = (BYTE *)GlobalLock(pData->hData);
memcpy(pDest + pData->nLength, lpBuff, cb);
pData->nLength += cb;
pDest[pData->nLength] = '\0';
GlobalUnlock(pData->hData);
*pcb = cb;
return 0;
}
static HGLOBAL get_rtf_text(ME_TextEditor *editor, CHARRANGE *lpchrg)
{
EDITSTREAM es;
ME_GlobalDestStruct gds;
gds.hData = GlobalAlloc(GMEM_MOVEABLE, 0);
gds.nLength = 0;
es.dwCookie = (DWORD_PTR)&gds;
es.pfnCallback = ME_AppendToHGLOBAL;
ME_StreamOutRange(editor, SF_RTF, lpchrg->cpMin, lpchrg->cpMax, &es);
GlobalReAlloc(gds.hData, gds.nLength+1, 0);
return gds.hData;
}
HRESULT ME_GetDataObject(ME_TextEditor *editor, CHARRANGE *lpchrg, LPDATAOBJECT *lplpdataobj)
{
DataObjectImpl *obj;
TRACE("(%p,%d,%d)\n", editor, lpchrg->cpMin, lpchrg->cpMax);
obj = richedit_alloc(sizeof(DataObjectImpl));
if(cfRTF == 0)
cfRTF = RegisterClipboardFormatA("Rich Text Format");
obj->lpVtbl = &VT_DataObjectImpl;
obj->ref = 1;
obj->unicode = get_unicode_text(editor, lpchrg);
obj->rtf = NULL;
obj->fmtetc_cnt = 1;
if(editor->mode & TM_RICHTEXT)
obj->fmtetc_cnt++;
obj->fmtetc = GlobalAlloc(GMEM_ZEROINIT, obj->fmtetc_cnt*sizeof(FORMATETC));
InitFormatEtc(obj->fmtetc[0], CF_UNICODETEXT, TYMED_HGLOBAL);
if(editor->mode & TM_RICHTEXT) {
obj->rtf = get_rtf_text(editor, lpchrg);
InitFormatEtc(obj->fmtetc[1], cfRTF, TYMED_HGLOBAL);
}
*lplpdataobj = (LPDATAOBJECT)obj;
return S_OK;
}

View file

@ -15,7 +15,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "editor.h"

File diff suppressed because it is too large Load diff

View file

@ -15,14 +15,44 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "editstr.h"
#include "wine/unicode.h"
#define ALLOC_OBJ(type) HeapAlloc(me_heap, 0, sizeof(type))
#define ALLOC_N_OBJ(type, count) HeapAlloc(me_heap, 0, (count)*sizeof(type))
#define FREE_OBJ(ptr) HeapFree(me_heap, 0, ptr)
extern HANDLE me_heap;
static inline void *richedit_alloc( size_t len )
{
return HeapAlloc( me_heap, 0, len );
}
static inline BOOL richedit_free( void *ptr )
{
return HeapFree( me_heap, 0, ptr );
}
static inline void *richedit_realloc( void *ptr, size_t len )
{
return HeapReAlloc( me_heap, 0, ptr, len );
}
#define ALLOC_OBJ(type) richedit_alloc(sizeof(type))
#define ALLOC_N_OBJ(type, count) richedit_alloc((count)*sizeof(type))
#define FREE_OBJ(ptr) richedit_free(ptr)
#define RUN_IS_HIDDEN(run) ((run)->style->fmt.dwMask & CFM_HIDDEN \
&& (run)->style->fmt.dwEffects & CFE_HIDDEN)
#define InitFormatEtc(fe, cf, med) \
{\
(fe).cfFormat=cf;\
(fe).dwAspect=DVASPECT_CONTENT;\
(fe).ptd=NULL;\
(fe).tymed=med;\
(fe).lindex=-1;\
};
/* style.c */
ME_Style *ME_MakeStyle(CHARFORMAT2W *style);
@ -42,6 +72,7 @@ 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 */
void ME_CharFormatFromLogFont(HDC hDC, LOGFONTW *lf, CHARFORMAT2W *fmt); /* ditto */
/* list.c */
void ME_InsertBefore(ME_DisplayItem *diWhere, ME_DisplayItem *diWhat);
@ -53,6 +84,7 @@ 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_DestroyTableCellList(ME_DisplayItem *item);
void ME_DumpDocument(ME_TextBuffer *buffer);
const char *ME_GetDITypeName(ME_DIType type);
@ -60,6 +92,8 @@ const char *ME_GetDITypeName(ME_DIType type);
int ME_GetOptimalBuffer(int nLen);
ME_String *ME_MakeString(LPCWSTR szText);
ME_String *ME_MakeStringN(LPCWSTR szText, int nMaxChars);
ME_String *ME_MakeStringR(WCHAR cRepeat, int nMaxChars);
ME_String *ME_MakeStringB(int nMaxChars);
ME_String *ME_StrDup(ME_String *s);
void ME_DestroyString(ME_String *s);
void ME_AppendString(ME_String *s1, ME_String *s2);
@ -72,6 +106,7 @@ 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_CallWordBreakProc(ME_TextEditor *editor, ME_String *str, INT start, INT code);
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);
@ -80,16 +115,19 @@ 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);
LPWSTR ME_ToUnicode(BOOL unicode, LPVOID psz);
void ME_EndToUnicode(BOOL unicode, LPVOID psz);
static inline int ME_IsWSpace(WCHAR ch)
{
return ch > '\0' && ch <= ' ';
}
static inline int ME_CharCompare(WCHAR a, WCHAR b, int caseSensitive)
{
return caseSensitive ? (a == b) : (toupperW(a) == toupperW(b));
}
/* 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);
@ -107,10 +145,12 @@ int ME_RowNumberFromCharOfs(ME_TextEditor *editor, int nOfs);
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);
ME_DisplayItem *ME_InsertRunAtCursor(ME_TextEditor *editor, ME_Cursor *cursor,
ME_Style *style, const WCHAR *str, int len, int flags);
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_Paragraph *para, ME_Run *run);
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);
@ -136,7 +176,8 @@ 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);
int ME_SetSelection(ME_TextEditor *editor, int from, int to);
void ME_SelectWord(ME_TextEditor *editor);
void ME_HideCaret(ME_TextEditor *ed);
void ME_ShowCaret(ME_TextEditor *ed);
void ME_MoveCaret(ME_TextEditor *ed);
@ -147,13 +188,14 @@ 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);
BOOL ME_ArrowKey(ME_TextEditor *ed, int nVKey, BOOL extend, BOOL ctrl);
void ME_InitContext(ME_Context *c, ME_TextEditor *editor, HDC hDC);
void ME_DestroyContext(ME_Context *c);
ME_Style *GetInsertStyle(ME_TextEditor *editor, int nCursor);
void ME_MustBeWrapped(ME_Context *c, ME_DisplayItem *para);
void ME_GetCursorCoordinates(ME_TextEditor *editor, ME_Cursor *pCursor,
int *x, int *y, int *height);
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);
@ -161,6 +203,7 @@ 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_InsertTableCellFromCursor(ME_TextEditor *editor, int nCursor);
void ME_InternalDeleteText(ME_TextEditor *editor, int nOfs, int nChars);
int ME_GetTextLength(ME_TextEditor *editor);
int ME_GetTextLengthEx(ME_TextEditor *editor, GETTEXTLENGTHEX *how);
@ -173,10 +216,12 @@ 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);
BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor);
void ME_InvalidateMarkedParagraphs(ME_TextEditor *editor);
void ME_SendRequestResize(ME_TextEditor *editor, BOOL force);
/* para.c */
ME_DisplayItem *ME_GetParagraph(ME_DisplayItem *run);
void ME_GetSelectionParas(ME_TextEditor *editor, ME_DisplayItem **para, ME_DisplayItem **para_end);
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);
@ -188,6 +233,7 @@ void ME_GetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, PARAFORMAT2 *
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_MarkForPainting(ME_TextEditor *editor, ME_DisplayItem *first, ME_DisplayItem *last);
void ME_MarkAllForWrapping(ME_TextEditor *editor);
/* paint.c */
@ -196,23 +242,32 @@ void ME_Repaint(ME_TextEditor *editor);
void ME_RewrapRepaint(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 ME_GetYScrollPos(ME_TextEditor *editor);
void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun);
COLORREF ME_GetBackColor(ME_TextEditor *editor);
void ME_Scroll(ME_TextEditor *editor, int cx, int cy);
void ME_InvalidateSelection(ME_TextEditor *editor);
void ME_QueueInvalidateFromCursor(ME_TextEditor *editor, int nCursor);
BOOL ME_SetZoom(ME_TextEditor *editor, int numerator, int denominator);
/* scroll functions in paint.c */
void ME_ScrollAbs(ME_TextEditor *editor, int absY);
void ME_ScrollUp(ME_TextEditor *editor, int cy);
void ME_ScrollDown(ME_TextEditor *editor, int cy);
void ME_Scroll(ME_TextEditor *editor, int value, int type);
void ME_UpdateScrollBar(ME_TextEditor *editor);
int ME_GetYScrollPos(ME_TextEditor *editor);
BOOL ME_GetYScrollVisible(ME_TextEditor *editor);
/* richole.c */
extern LRESULT CreateIRichEditOle(LPVOID *);
extern LRESULT CreateIRichEditOle(ME_TextEditor *editor, LPVOID *);
/* wintest.c */
/* editor.c */
void ME_RegisterEditorClass(HINSTANCE hInstance);
ME_TextEditor *ME_MakeEditor(HWND hWnd);
void ME_DestroyEditor(ME_TextEditor *editor);
void ME_SendOldNotify(ME_TextEditor *editor, int nCode);
void ME_LinkNotify(ME_TextEditor *editor, UINT msg, WPARAM wParam, LPARAM lParam);
ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, ME_DisplayItem *di);
void ME_CommitUndo(ME_TextEditor *editor);
void ME_Undo(ME_TextEditor *editor);
@ -221,10 +276,13 @@ void ME_EmptyUndoStack(ME_TextEditor *editor);
int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, BOOL bCRLF);
ME_DisplayItem *ME_FindItemAtOffset(ME_TextEditor *editor, ME_DIType nItemType, int nOffset, int *nItemOffset);
void ME_StreamInFill(ME_InStream *stream);
int ME_AutoURLDetect(ME_TextEditor *editor, WCHAR curChar);
extern int me_debug;
extern HANDLE me_heap;
extern void DoWrap(ME_TextEditor *editor);
/* writer.c */
LRESULT ME_StreamOutRange(ME_TextEditor *editor, DWORD dwFormat, int nStart, int nTo, EDITSTREAM *stream);
LRESULT ME_StreamOut(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM *stream);
/* clipboard.c */
HRESULT ME_GetDataObject(ME_TextEditor *editor, CHARRANGE *lpchrg, LPDATAOBJECT *lplpdataobj);

View file

@ -15,7 +15,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef __EDITSTR_H
@ -30,6 +30,10 @@
#include <stdio.h>
#include <stdlib.h>
#define COBJMACROS
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include <windef.h>
#include <winbase.h>
#include <winnls.h>
@ -38,6 +42,8 @@
#include <winuser.h>
#include <richedit.h>
#include <commctrl.h>
#include <ole2.h>
#include <richole.h>
#include "wine/debug.h"
@ -58,6 +64,7 @@ typedef struct tagME_Style
} ME_Style;
typedef enum {
diInvalid,
diTextStart, /* start of the text buffer */
diParagraph, /* paragraph start */
diRun, /* run (sequence of chars with the same character format) */
@ -88,6 +95,10 @@ typedef enum {
#define MERF_GRAPHICS 1
/* run is a tab (or, in future, any kind of content whose size is dependent on run position) */
#define MERF_TAB 2
/* run is a cell boundary */
#define MERF_CELL 4
#define MERF_NONTEXT (MERF_GRAPHICS | MERF_TAB | MERF_CELL)
/* run is splittable (contains white spaces in the middle or end) */
#define MERF_SPLITTABLE 0x001000
@ -103,6 +114,8 @@ typedef enum {
#define MERF_CALCBYWRAP 0x0F0000
/* the "end of paragraph" run, contains 1 character */
#define MERF_ENDPARA 0x100000
/* run is hidden */
#define MERF_HIDDEN 0x200000
/* runs with any of these flags set cannot be joined */
#define MERF_NOJOIN (MERF_GRAPHICS|MERF_TAB|MERF_ENDPARA)
@ -131,6 +144,7 @@ typedef struct tagME_Run
int nFlags;
int nAscent, nDescent; /* pixels above/below baseline */
POINT pt; /* relative to para's position */
struct tagME_TableCell *pCell; /* for MERF_CELL: points to respective cell in ME_Paragraph */
} ME_Run;
typedef struct tagME_Document {
@ -139,9 +153,20 @@ typedef struct tagME_Document {
int last_wrapped_line;
} ME_Document;
typedef struct tagME_TableCell
{
int nRightBoundary;
struct tagME_TableCell *next;
} ME_TableCell;
typedef struct tagME_Paragraph
{
PARAFORMAT2 *pFmt;
BOOL bTable; /* this paragraph is a table row */
struct tagME_TableCell *pCells; /* list of cells and their properties */
struct tagME_TableCell *pLastCell; /* points to the last cell in the list */
int nLeftMargin, nRightMargin, nFirstMargin;
int nCharOfs;
int nFlags;
@ -268,23 +293,34 @@ typedef struct tagME_TextEditor
int nTotalLength, nLastTotalLength;
int nUDArrowX;
int nSequence;
int nOldSelFrom, nOldSelTo;
COLORREF rgbBackColor;
HBRUSH hbrBackground;
BOOL bCaretAtEnd;
int nEventMask;
int nModifyStep;
ME_DisplayItem *pUndoStack, *pRedoStack;
ME_DisplayItem *pUndoStack, *pRedoStack, *pUndoStackBottom;
int nUndoStackSize;
int nUndoLimit;
ME_UndoMode nUndoMode;
int nParagraphs;
int nLastSelStart, nLastSelEnd;
ME_DisplayItem *pLastSelStartPara, *pLastSelEndPara;
ME_FontCacheItem pFontCache[HFONT_CACHE_SIZE];
ME_OutStream *pStream;
BOOL bScrollX, bScrollY;
int nScrollPosY;
int nZoomNumerator, nZoomDenominator;
RECT rcFormat;
BOOL bRedraw;
int nInvalidOfs;
int nTextLimit;
EDITWORDBREAKPROCW pfnWordBreak;
LPRICHEDITOLECALLBACK lpOleCallback;
/*TEXTMODE variable; contains only one of each of the following options:
*TM_RICHTEXT or TM_PLAINTEXT
*TM_SINGLELEVELUNDO or TM_MULTILEVELUNDO
*TM_SINGLECODEPAGE or TM_MULTICODEPAGE*/
int mode;
BOOL bHideSelection;
BOOL AutoURLDetect_bEnable;
WCHAR cPasswordMask;
} ME_TextEditor;
typedef struct tagME_Context

View file

@ -15,7 +15,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
@ -112,6 +112,7 @@ 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);
ME_DestroyTableCellList(item);
}
if (item->type==diRun || item->type == diUndoInsertRun) {
ME_ReleaseStyle(item->member.run.style);
@ -120,9 +121,28 @@ void ME_DestroyDisplayItem(ME_DisplayItem *item) {
if (item->type==diUndoSetCharFormat || item->type==diUndoSetDefaultCharFormat) {
ME_ReleaseStyle(item->member.ustyle);
}
if (item->type==diUndoSplitParagraph)
FREE_OBJ(item->member.para.pFmt);
FREE_OBJ(item);
}
void
ME_DestroyTableCellList(ME_DisplayItem *item)
{
if (item->member.para.pCells)
{
ME_TableCell *pCell = item->member.para.pCells;
ME_TableCell *pNext;
while (pCell) {
pNext = pCell->next;
FREE_OBJ(pCell);
pCell = pNext;
}
item->member.para.pCells = NULL;
}
}
ME_DisplayItem *ME_MakeDI(ME_DIType type) {
ME_DisplayItem *item = ALLOC_OBJ(ME_DisplayItem);
ZeroMemory(item, sizeof(ME_DisplayItem));
@ -168,20 +188,20 @@ void ME_DumpDocument(ME_TextBuffer *buffer)
switch(pItem->type)
{
case diTextStart:
TRACE("Start");
TRACE("Start\n");
break;
case diParagraph:
TRACE("\nParagraph(ofs=%d)", pItem->member.para.nCharOfs);
TRACE("Paragraph(ofs=%d)\n", pItem->member.para.nCharOfs);
break;
case diStartRow:
TRACE(" - StartRow");
TRACE(" - StartRow\n");
break;
case diRun:
TRACE(" - Run(\"%s\", %d)", debugstr_w(pItem->member.run.strText->szData),
TRACE(" - Run(\"%s\", %d)\n", debugstr_w(pItem->member.run.strText->szData),
pItem->member.run.nCharOfs);
break;
case diTextEnd:
TRACE("\nEnd(ofs=%d)\n", pItem->member.para.nCharOfs);
TRACE("End(ofs=%d)\n", pItem->member.para.nCharOfs);
break;
default:
break;

View file

@ -2,6 +2,7 @@
* RichEdit - painting functions
*
* Copyright 2004 by Krzysztof Foltman
* Copyright 2005 by Phil Krylov
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -15,7 +16,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "editor.h"
@ -93,95 +94,48 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, RECT *rcUpda
ME_DestroyContext(&c);
}
static 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);
}
static 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);
}
static 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 (from<from2) ME_MarkOffsetRange(editor, from, from2, MEPF_REPAINT);
if (from>from2) ME_MarkOffsetRange(editor, from2, from, MEPF_REPAINT);
if (to<to2) ME_MarkOffsetRange(editor, to, to2, MEPF_REPAINT);
if (to>to2) 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);
if (ME_WrapMarkedParagraphs(editor)) {
ME_UpdateScrollBar(editor);
}
if (editor->bRedraw)
if (ME_WrapMarkedParagraphs(editor))
{
hDC = GetDC(editor->hWnd);
ME_HideCaret(editor);
ME_PaintContent(editor, hDC, TRUE, NULL);
ReleaseDC(editor->hWnd, hDC);
ME_ShowCaret(editor);
ME_EnsureVisible(editor, pCursor->pRun);
ME_UpdateScrollBar(editor);
FIXME("ME_Repaint had to call ME_WrapMarkedParagraphs\n");
}
ME_SendOldNotify(editor, EN_UPDATE);
UpdateWindow(editor->hWnd);
}
void ME_UpdateRepaint(ME_TextEditor *editor)
{
/*
InvalidateRect(editor->hWnd, NULL, TRUE);
*/
ME_SendOldNotify(editor, EN_CHANGE);
/* Should be called whenever the contents of the control have changed */
ME_Cursor *pCursor;
if (ME_WrapMarkedParagraphs(editor))
ME_UpdateScrollBar(editor);
/* Ensure that the cursor is visible */
pCursor = &editor->pCursors[0];
ME_EnsureVisible(editor, pCursor->pRun);
/* send EN_CHANGE if the event mask asks for it */
if(editor->nEventMask & ENM_CHANGE)
{
ME_SendOldNotify(editor, EN_CHANGE);
}
ME_Repaint(editor);
ME_SendOldNotify(editor, EN_UPDATE);
ME_SendSelChange(editor);
}
void
ME_RewrapRepaint(ME_TextEditor *editor)
{
{
/* RewrapRepaint should be called whenever the control has changed in
* looks, but not content. Like resizing. */
ME_MarkAllForWrapping(editor);
ME_WrapMarkedParagraphs(editor);
ME_UpdateScrollBar(editor);
ME_Repaint(editor);
}
@ -194,7 +148,9 @@ static void ME_DrawTextWithStyle(ME_Context *c, int x, int y, LPCWSTR szText, in
int yOffset = 0, yTwipsOffset = 0;
hOldFont = ME_SelectStyleFont(c->editor, hDC, s);
rgbBack = ME_GetBackColor(c->editor);
if ((s->fmt.dwMask & CFM_COLOR) && (s->fmt.dwEffects & CFE_AUTOCOLOR))
if ((s->fmt.dwMask & CFM_LINK) && (s->fmt.dwEffects & CFE_LINK))
rgbOld = SetTextColor(hDC, RGB(0,0,255));
else if ((s->fmt.dwMask & CFM_COLOR) && (s->fmt.dwEffects & CFE_AUTOCOLOR))
rgbOld = SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
else
rgbOld = SetTextColor(hDC, s->fmt.crTextColor);
@ -231,7 +187,10 @@ static void ME_DrawTextWithStyle(ME_Context *c, int x, int y, LPCWSTR szText, in
GetTextExtentPoint32W(hDC, szText, nSelFrom, &sz);
x += sz.cx;
GetTextExtentPoint32W(hDC, szText+nSelFrom, nSelTo-nSelFrom, &sz);
PatBlt(hDC, x, ymin, sz.cx, cy, DSTINVERT);
/* Invert selection if not hidden by EM_HIDESELECTION */
if (c->editor->bHideSelection == FALSE)
PatBlt(hDC, x, ymin, sz.cx, cy, DSTINVERT);
}
SetTextColor(hDC, rgbOld);
ME_UnselectStyleFont(c->editor, hDC, s, hOldFont);
@ -247,8 +206,8 @@ static void ME_DebugWrite(HDC hDC, POINT *pt, WCHAR *szText) {
SetTextColor(hDC, color);
}
void ME_DrawGraphics(ME_Context *c, int x, int y, ME_Run *run,
ME_Paragraph *para, BOOL selected) {
static 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);
@ -275,27 +234,46 @@ void ME_DrawGraphics(ME_Context *c, int x, int y, ME_Run *run,
}
}
static void ME_DrawRun(ME_Context *c, int x, int y, ME_DisplayItem *rundi, ME_Paragraph *para) {
static void ME_DrawRun(ME_Context *c, int x, int y, ME_DisplayItem *rundi, ME_Paragraph *para)
{
ME_Run *run = &rundi->member.run;
ME_DisplayItem *start = ME_FindItemBack(rundi, diStartRow);
int runofs = run->nCharOfs+para->nCharOfs;
int nSelFrom, nSelTo;
const WCHAR wszSpace[] = {' ', 0};
/* you can always comment it out if you need visible paragraph marks */
if (run->nFlags & (MERF_ENDPARA|MERF_TAB))
if (run->nFlags & MERF_HIDDEN)
return;
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
ME_GetSelection(c->editor, &nSelFrom, &nSelTo);
/* Draw selected end-of-paragraph mark */
if (run->nFlags & MERF_ENDPARA && runofs >= nSelFrom && runofs < nSelTo)
ME_DrawTextWithStyle(c, x, y, wszSpace, 1, run->style, NULL, 0, 1,
c->pt.y + start->member.row.nYPos,
start->member.row.nHeight);
/* you can always comment it out if you need visible paragraph marks */
if (run->nFlags & (MERF_ENDPARA | MERF_TAB | MERF_CELL))
return;
if (run->nFlags & MERF_GRAPHICS)
ME_DrawGraphics(c, x, y, run, para, (runofs >= nSelFrom) && (runofs < nSelTo));
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);
}
if (c->editor->cPasswordMask)
{
ME_String *szMasked = ME_MakeStringR(c->editor->cPasswordMask,ME_StrVLen(run->strText));
ME_DrawTextWithStyle(c, x, y,
szMasked->szData, ME_StrVLen(szMasked), run->style, NULL,
nSelFrom-runofs,nSelTo-runofs, c->pt.y+start->member.row.nYPos, start->member.row.nHeight);
ME_DestroyString(szMasked);
}
else
ME_DrawTextWithStyle(c, x, y,
run->strText->szData, ME_StrVLen(run->strText), run->style, NULL,
nSelFrom-runofs,nSelTo-runofs, c->pt.y+start->member.row.nYPos, start->member.row.nHeight);
}
}
COLORREF ME_GetBackColor(ME_TextEditor *editor)
@ -378,7 +356,7 @@ void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) {
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);
TRACE("rc = (%d, %d, %d, %d)\n", rc.left, rc.top, rc.right, rc.bottom);
if (run->nFlags & MERF_SKIPPED)
DrawFocusRect(c->hDC, &rc);
else
@ -407,80 +385,118 @@ void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) {
SetTextAlign(c->hDC, align);
}
void ME_Scroll(ME_TextEditor *editor, int cx, int cy)
void ME_ScrollAbs(ME_TextEditor *editor, int absY)
{
SCROLLINFO si;
HWND hWnd = editor->hWnd;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_POS;
GetScrollInfo(hWnd, SB_VERT, &si);
si.nPos = editor->nScrollPosY -= cy;
SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
if (editor->bRedraw)
{
if (abs(cy) > editor->sizeWindow.cy)
InvalidateRect(editor->hWnd, NULL, TRUE);
else
ScrollWindowEx(hWnd, cx, cy, NULL, NULL, NULL, NULL, SW_ERASE|SW_INVALIDATE);
}
ME_Scroll(editor, absY, 1);
}
void ME_UpdateScrollBar(ME_TextEditor *editor)
void ME_ScrollUp(ME_TextEditor *editor, int cy)
{
ME_Scroll(editor, cy, 2);
}
void ME_ScrollDown(ME_TextEditor *editor, int cy)
{
ME_Scroll(editor, cy, 3);
}
void ME_Scroll(ME_TextEditor *editor, int value, int type)
{
HWND hWnd = editor->hWnd;
SCROLLINFO si;
int nOldLen = editor->nTotalLength;
BOOL bScrollY = (editor->nTotalLength > editor->sizeWindow.cy);
BOOL bUpdateScrollBars;
si.cbSize = sizeof(si);
si.fMask = SIF_POS | SIF_RANGE;
GetScrollInfo(hWnd, SB_VERT, &si);
bUpdateScrollBars = (bScrollY || editor->bScrollY)&& ((si.nMax != nOldLen) || (si.nPage != editor->sizeWindow.cy));
int nOrigPos, nNewPos, nActualScroll;
nOrigPos = ME_GetYScrollPos(editor);
if (bScrollY != editor->bScrollY)
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_POS;
switch (type)
{
si.fMask = SIF_RANGE | SIF_PAGE;
si.nMin = 0;
si.nPage = editor->sizeWindow.cy;
if (bScrollY) {
si.nMax = editor->nTotalLength;
} else {
si.nMax = 0;
}
SetScrollInfo(hWnd, SB_VERT, &si, FALSE);
ME_MarkAllForWrapping(editor);
editor->bScrollY = bScrollY;
ME_WrapMarkedParagraphs(editor);
bUpdateScrollBars = TRUE;
}
if (bUpdateScrollBars) {
int nScroll = 0;
si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
if (editor->nTotalLength > editor->sizeWindow.cy) {
si.nMax = editor->nTotalLength;
si.nPage = editor->sizeWindow.cy;
if (si.nPos > si.nMax-si.nPage) {
nScroll = (si.nMax-si.nPage)-si.nPos;
si.nPos = si.nMax-si.nPage;
}
}
else {
si.nMax = 0;
si.nPage = 0;
case 1:
/*Scroll absolutly*/
si.nPos = value;
break;
case 2:
/* Scroll up - towards the beginning of the document */
si.nPos = nOrigPos - value;
break;
case 3:
/* Scroll down - towards the end of the document */
si.nPos = nOrigPos + value;
break;
default:
FIXME("ME_Scroll called incorrectly\n");
si.nPos = 0;
}
TRACE("min=%d max=%d page=%d pos=%d shift=%d\n", si.nMin, si.nMax, si.nPage, si.nPos, nScroll);
editor->nScrollPosY = si.nPos;
SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
if (nScroll)
ScrollWindow(hWnd, 0, -nScroll, NULL, NULL);
}
nNewPos = SetScrollInfo(editor->hWnd, SB_VERT, &si, editor->bRedraw);
nActualScroll = nOrigPos - nNewPos;
if (editor->bRedraw)
{
if (abs(nActualScroll) > editor->sizeWindow.cy)
InvalidateRect(editor->hWnd, NULL, TRUE);
else
ScrollWindowEx(editor->hWnd, 0, nActualScroll, NULL, NULL, NULL, NULL, SW_INVALIDATE);
ME_Repaint(editor);
}
ME_UpdateScrollBar(editor);
}
void ME_UpdateScrollBar(ME_TextEditor *editor)
{
/* Note that this is the only funciton that should ever call SetScrolLInfo
* with SIF_PAGE or SIF_RANGE. SetScrollPos and SetScrollRange should never
* be used at all. */
HWND hWnd;
SCROLLINFO si;
BOOL bScrollBarWasVisible,bScrollBarWillBeVisible;
if (ME_WrapMarkedParagraphs(editor))
FIXME("ME_UpdateScrollBar had to call ME_WrapMarkedParagraphs\n");
hWnd = editor->hWnd;
si.cbSize = sizeof(si);
bScrollBarWasVisible = ME_GetYScrollVisible(editor);
bScrollBarWillBeVisible = editor->nTotalLength > editor->sizeWindow.cy;
if (bScrollBarWasVisible != bScrollBarWillBeVisible)
{
ShowScrollBar(hWnd, SB_VERT, bScrollBarWillBeVisible);
ME_MarkAllForWrapping(editor);
ME_WrapMarkedParagraphs(editor);
}
si.fMask = SIF_PAGE | SIF_RANGE;
if (GetWindowLongW(hWnd, GWL_STYLE) & ES_DISABLENOSCROLL)
si.fMask |= SIF_DISABLENOSCROLL;
si.nMin = 0;
si.nMax = editor->nTotalLength;
si.nPage = editor->sizeWindow.cy;
TRACE("min=%d max=%d page=%d\n", si.nMin, si.nMax, si.nPage);
SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
}
int ME_GetYScrollPos(ME_TextEditor *editor)
{
return editor->nScrollPosY;
SCROLLINFO si;
si.cbSize = sizeof(si);
si.fMask = SIF_POS;
GetScrollInfo(editor->hWnd, SB_VERT, &si);
return si.nPos;
}
BOOL ME_GetYScrollVisible(ME_TextEditor *editor)
{ /* Returns true if the scrollbar is visible */
SCROLLBARINFO sbi;
sbi.cbSize = sizeof(sbi);
GetScrollBarInfo(editor->hWnd, OBJID_VSCROLL, &sbi);
return ((sbi.rgstate[0] & STATE_SYSTEM_INVISIBLE) == 0);
}
void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun)
@ -488,7 +504,6 @@ 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, yold;
HWND hWnd = editor->hWnd;
assert(pRow);
assert(pPara);
@ -497,26 +512,85 @@ void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun)
yheight = pRow->member.row.nHeight;
yold = ME_GetYScrollPos(editor);
yrel = y - yold;
if (yrel < 0) {
editor->nScrollPosY = y;
SetScrollPos(hWnd, SB_VERT, y, TRUE);
if (editor->bRedraw)
{
ScrollWindow(hWnd, 0, -yrel, NULL, NULL);
UpdateWindow(hWnd);
}
} else if (yrel + yheight > editor->sizeWindow.cy) {
int newy = y+yheight-editor->sizeWindow.cy;
editor->nScrollPosY = newy;
SetScrollPos(hWnd, SB_VERT, newy, TRUE);
if (editor->bRedraw)
{
ScrollWindow(hWnd, 0, -(newy-yold), NULL, NULL);
UpdateWindow(hWnd);
}
}
if (y < yold)
ME_ScrollAbs(editor,y);
else if (yrel + yheight > editor->sizeWindow.cy)
ME_ScrollAbs(editor,y+yheight-editor->sizeWindow.cy);
}
void
ME_InvalidateFromOfs(ME_TextEditor *editor, int nCharOfs)
{
RECT rc;
int x, y, height;
ME_Cursor tmp;
ME_RunOfsFromCharOfs(editor, nCharOfs, &tmp.pRun, &tmp.nOffset);
ME_GetCursorCoordinates(editor, &tmp, &x, &y, &height);
rc.left = 0;
rc.top = y;
rc.bottom = y + height;
rc.right = editor->rcFormat.right;
InvalidateRect(editor->hWnd, &rc, FALSE);
}
void
ME_InvalidateSelection(ME_TextEditor *editor)
{
ME_DisplayItem *para1, *para2;
int nStart, nEnd;
int len = ME_GetTextLength(editor);
ME_GetSelection(editor, &nStart, &nEnd);
/* if both old and new selection are 0-char (= caret only), then
there's no (inverted) area to be repainted, neither old nor new */
if (nStart == nEnd && editor->nLastSelStart == editor->nLastSelEnd)
return;
ME_WrapMarkedParagraphs(editor);
ME_GetSelectionParas(editor, &para1, &para2);
assert(para1->type == diParagraph);
assert(para2->type == diParagraph);
/* last selection markers aren't always updated, which means
they can point past the end of the document */
if (editor->nLastSelStart > len)
editor->nLastSelEnd = len;
if (editor->nLastSelEnd > len)
editor->nLastSelEnd = len;
/* if the start part of selection is being expanded or contracted... */
if (nStart < editor->nLastSelStart) {
ME_MarkForPainting(editor, para1, ME_FindItemFwd(editor->pLastSelStartPara, diParagraphOrEnd));
} else
if (nStart > editor->nLastSelStart) {
ME_MarkForPainting(editor, editor->pLastSelStartPara, ME_FindItemFwd(para1, diParagraphOrEnd));
}
/* if the end part of selection is being contracted or expanded... */
if (nEnd < editor->nLastSelEnd) {
ME_MarkForPainting(editor, para2, ME_FindItemFwd(editor->pLastSelEndPara, diParagraphOrEnd));
} else
if (nEnd > editor->nLastSelEnd) {
ME_MarkForPainting(editor, editor->pLastSelEndPara, ME_FindItemFwd(para2, diParagraphOrEnd));
}
ME_InvalidateMarkedParagraphs(editor);
/* remember the last invalidated position */
ME_GetSelection(editor, &editor->nLastSelStart, &editor->nLastSelEnd);
ME_GetSelectionParas(editor, &editor->pLastSelStartPara, &editor->pLastSelEndPara);
assert(editor->pLastSelStartPara->type == diParagraph);
assert(editor->pLastSelEndPara->type == diParagraph);
}
void
ME_QueueInvalidateFromCursor(ME_TextEditor *editor, int nCursor)
{
editor->nInvalidOfs = ME_GetCursorOfs(editor, nCursor);
}
BOOL
ME_SetZoom(ME_TextEditor *editor, int numerator, int denominator)

View file

@ -2,6 +2,7 @@
* RichEdit - functions working on paragraphs of text (diParagraph).
*
* Copyright 2004 by Krzysztof Foltman
* Copyright 2006 by Phil Krylov
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -15,14 +16,14 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "editor.h"
WINE_DEFAULT_DEBUG_CHANNEL(richedit);
static WCHAR wszParagraphSign[] = {0xB6, 0};
static const WCHAR wszParagraphSign[] = {0xB6, 0};
void ME_MakeFirstParagraph(HDC hDC, ME_TextBuffer *text)
{
@ -91,6 +92,15 @@ void ME_MarkForWrapping(ME_TextEditor *editor, ME_DisplayItem *first, ME_Display
}
}
void ME_MarkForPainting(ME_TextEditor *editor, ME_DisplayItem *first, ME_DisplayItem *last)
{
while(first != last)
{
first->member.para.nFlags |= MEPF_REPAINT;
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)
{
@ -133,6 +143,35 @@ ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, ME
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;
new_para->member.para.bTable = run_para->member.para.bTable;
/* Inherit previous cell definitions if any */
new_para->member.para.pCells = NULL;
if (run_para->member.para.pCells)
{
ME_TableCell *pCell, *pNewCell;
for (pCell = run_para->member.para.pCells; pCell; pCell = pCell->next)
{
pNewCell = ALLOC_OBJ(ME_TableCell);
pNewCell->nRightBoundary = pCell->nRightBoundary;
pNewCell->next = NULL;
if (new_para->member.para.pCells)
new_para->member.para.pLastCell->next = pNewCell;
else
new_para->member.para.pCells = pNewCell;
new_para->member.para.pLastCell = pNewCell;
}
}
/* fix paragraph properties. FIXME only needed when called from RTF reader */
if (run_para->member.para.pCells && !run_para->member.para.bTable)
{
/* Paragraph does not have an \intbl keyword, so any table definition
* stored is invalid */
ME_DestroyTableCellList(run_para);
}
/* insert paragraph into paragraph double linked list */
new_para->member.para.prev_para = run_para;
@ -215,6 +254,11 @@ ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp)
ME_Remove(pRun);
ME_DestroyDisplayItem(pRun);
if (editor->pLastSelStartPara == pNext)
editor->pLastSelStartPara = tp;
if (editor->pLastSelEndPara == pNext)
editor->pLastSelEndPara = tp;
tp->member.para.next_para = pNext->member.para.next_para;
pNext->member.para.next_para->member.para.prev_para = tp;
ME_Remove(pNext);
@ -303,21 +347,37 @@ void ME_SetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, PARAFORMAT2 *
para->member.para.nFlags |= MEPF_REWRAP;
}
void
ME_GetSelectionParas(ME_TextEditor *editor, ME_DisplayItem **para, ME_DisplayItem **para_end)
{
ME_Cursor *pEndCursor = &editor->pCursors[1];
*para = ME_GetParagraph(editor->pCursors[0].pRun);
*para_end = ME_GetParagraph(editor->pCursors[1].pRun);
if ((*para_end)->member.para.nCharOfs < (*para)->member.para.nCharOfs) {
ME_DisplayItem *tmp = *para;
*para = *para_end;
*para_end = tmp;
pEndCursor = &editor->pCursors[0];
}
/* selection consists of chars from nFrom up to nTo-1 */
if ((*para_end)->member.para.nCharOfs > (*para)->member.para.nCharOfs) {
if (!pEndCursor->nOffset) {
*para_end = ME_GetParagraph(ME_FindItemBack(pEndCursor->pRun, diRun));
}
}
}
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);
ME_DisplayItem *para, *para_end;
ME_GetSelectionParas(editor, &para, &para_end);
do {
ME_SetParaFormat(editor, para, pFmt);
if (para == para_end)
@ -338,19 +398,10 @@ void ME_GetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, PARAFORMAT2 *
void ME_GetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt)
{
int nFrom, nTo;
ME_DisplayItem *para, *para_end, *run;
int nOffset;
ME_DisplayItem *para, *para_end;
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_GetSelectionParas(editor, &para, &para_end);
ME_GetParaFormat(editor, para, pFmt);
if (para == para_end) return;

View file

@ -2,6 +2,7 @@
* WINE RTF file reader
*
* Portions Copyright 2004 Mike McCormack for CodeWeavers
* Portions Copyright 2006 by Phil Krylov
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -15,7 +16,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/*
@ -63,9 +64,8 @@ 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 int Hash (const char *);
static void CharAttr(RTF_Info *info);
static void CharSet(RTF_Info *info);
@ -85,17 +85,9 @@ static void RTFPutCodePageChar(RTF_Info *info, int c);
* Return pointer to block of size bytes, or NULL if there's
* not enough memory available.
*/
static inline void *RTFAlloc(int size)
{
return HeapAlloc(me_heap, 0, size);
}
static inline void * RTFReAlloc(void *ptr, int size)
{
return HeapReAlloc(me_heap, 0, ptr, size);
}
#define RTFAlloc(size) richedit_alloc(size)
#define RTFReAlloc(ptr, size) richedit_realloc(ptr, size)
#define RTFFree(ptr) richedit_free(ptr)
/*
* Saves a string on the heap and returns a pointer to it.
@ -111,12 +103,6 @@ static inline char *RTFStrSave(char *s)
}
static inline void RTFFree(void *p)
{
HeapFree(me_heap, 0, p);
}
/* ---------------------------------------------------------------------- */
@ -125,8 +111,6 @@ int _RTFGetChar(RTF_Info *info)
int ch;
ME_InStream *stream = info->stream;
TRACE("\n");
if (stream->dwSize <= stream->dwUsed)
{
ME_StreamInFill(stream);
@ -145,8 +129,6 @@ int _RTFGetChar(RTF_Info *info)
void RTFSetEditStream(RTF_Info *info, ME_InStream *stream)
{
TRACE("\n");
info->stream = stream;
}
@ -212,8 +194,6 @@ void RTFInit(RTF_Info *info)
{
int i;
TRACE("\n");
if (info->rtfTextBuf == NULL) /* initialize the text buffers */
{
info->rtfTextBuf = RTFAlloc (rtfBufSiz);
@ -227,9 +207,6 @@ void RTFInit(RTF_Info *info)
RTFFree (info->outputName);
info->inputName = info->outputName = NULL;
/* initialize lookup table */
LookupInit ();
for (i = 0; i < rtfMaxClass; i++)
RTFSetClassCallback (info, i, NULL);
for (i = 0; i < rtfMaxDestination; i++)
@ -279,8 +256,6 @@ void RTFInit(RTF_Info *info)
void RTFSetInputName(RTF_Info *info, char *name)
{
TRACE("\n");
info->inputName = RTFStrSave (name);
if (info->inputName == NULL)
ERR ("RTFSetInputName: out of memory\n");
@ -295,8 +270,6 @@ char *RTFGetInputName(RTF_Info *info)
void RTFSetOutputName(RTF_Info *info, char *name)
{
TRACE("\n");
info->outputName = RTFStrSave (name);
if (info->outputName == NULL)
ERR ("RTFSetOutputName: out of memory\n");
@ -384,8 +357,6 @@ void RTFRouteToken(RTF_Info *info)
{
RTFFuncPtr p;
TRACE("\n");
if (info->rtfClass < 0 || info->rtfClass >= rtfMaxClass) /* watchdog */
{
ERR( "Unknown class %d: %s (reader malfunction)\n",
@ -419,8 +390,6 @@ void RTFSkipGroup(RTF_Info *info)
{
int level = 1;
TRACE("\n");
while (RTFGetToken (info) != rtfEOF)
{
if (info->rtfClass == rtfGroup)
@ -447,7 +416,6 @@ int RTFGetToken(RTF_Info *info)
{
RTFFuncPtr p;
TRACE("\n");
/* don't try to return anything once EOF is reached */
if (info->rtfClass == rtfEOF) {
return rtfEOF;
@ -487,8 +455,6 @@ RTFFuncPtr RTFGetReadHook(RTF_Info *info)
void RTFUngetToken(RTF_Info *info)
{
TRACE("\n");
if (info->pushedClass >= 0) /* there's already an ungotten token */
ERR ("cannot unget two tokens\n");
if (info->rtfClass < 0)
@ -511,8 +477,6 @@ int RTFPeekToken(RTF_Info *info)
static void _RTFGetToken(RTF_Info *info)
{
TRACE("\n");
if (info->rtfFormat == SF_TEXT)
{
info->rtfMajor = GetChar (info);
@ -596,7 +560,7 @@ RTFCharSetToCodePage(RTF_Info *info, int charset)
{
CHARSETINFO csi;
DWORD n = charset;
/* FIXME: TranslateCharsetInfo does not work as good as it
* should, so let's use it only when all else fails */
if (!TranslateCharsetInfo(&n, &csi, TCI_SRCCHARSET))
@ -616,8 +580,6 @@ static void _RTFGetToken2(RTF_Info *info)
int sign;
int c;
TRACE("\n");
/* initialize token vars */
info->rtfClass = rtfUnknown;
@ -787,8 +749,6 @@ static int GetChar(RTF_Info *info)
int c;
int oldBumpLine;
TRACE("\n");
if ((c = _RTFGetChar(info)) != EOF)
{
info->rtfTextBuf[info->rtfTextLen++] = c;
@ -828,8 +788,6 @@ static int GetChar(RTF_Info *info)
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;
@ -877,8 +835,6 @@ static void ReadFontTbl(RTF_Info *info)
int old = -1;
const char *fn = "ReadFontTbl";
TRACE("\n");
for (;;)
{
RTFGetToken (info);
@ -929,7 +885,7 @@ static void ReadFontTbl(RTF_Info *info)
{
default:
/* ignore token but announce it */
ERR ("%s: unknown token \"%s\"\n",
WARN ("%s: unknown token \"%s\"\n",
fn, info->rtfTextBuf);
break;
case rtfFontFamily:
@ -999,7 +955,7 @@ static void ReadFontTbl(RTF_Info *info)
else
{
/* ignore token but announce it */
ERR ( "%s: unknown token \"%s\"\n",
WARN ( "%s: unknown token \"%s\"\n",
fn,info->rtfTextBuf);
}
RTFGetToken (info);
@ -1056,8 +1012,7 @@ static void ReadColorTbl(RTF_Info *info)
RTFColor *cp;
int cnum = 0;
const char *fn = "ReadColorTbl";
TRACE("\n");
int group_level = 1;
for (;;)
{
@ -1065,7 +1020,18 @@ static void ReadColorTbl(RTF_Info *info)
if (info->rtfClass == rtfEOF)
break;
if (RTFCheckCM (info, rtfGroup, rtfEndGroup))
break;
{
group_level--;
if (!group_level)
break;
continue;
}
else if (RTFCheckCM(info, rtfGroup, rtfBeginGroup))
{
group_level++;
continue;
}
cp = New (RTFColor);
if (cp == NULL)
ERR ( "%s: cannot allocate color entry\n", fn);
@ -1105,8 +1071,6 @@ static void ReadStyleSheet(RTF_Info *info)
const char *fn = "ReadStyleSheet";
int real_style;
TRACE("\n");
for (;;)
{
RTFGetToken (info);
@ -1229,7 +1193,7 @@ static void ReadStyleSheet(RTF_Info *info)
else /* unrecognized */
{
/* ignore token but announce it */
ERR ( "%s: unknown token \"%s\"\n",
WARN ( "%s: unknown token \"%s\"\n",
fn, info->rtfTextBuf);
}
}
@ -1351,8 +1315,6 @@ void RTFExpandStyle(RTF_Info *info, int n)
RTFStyle *s;
RTFStyleElt *se;
TRACE("\n");
if (n == -1)
return;
s = RTFGetStyle (info, n);
@ -1817,7 +1779,7 @@ static RTFKey rtfKey[] =
{ rtfDocAttr, rtfRTLDoc, "rtldoc", 0 },
{ rtfDocAttr, rtfLTRDoc, "ltrdoc", 0 },
{ rtfDocAttr, rtfAnsiCodePage, "ansicpg", 0 },
{ rtfDocAttr, rtfUTF8RTF, "urtf", 0 },
@ -2326,26 +2288,34 @@ static RTFHashTableEntry rtfHashTable[RTF_KEY_COUNT * 2];
* Initialize lookup table hash values. Only need to do this once.
*/
static void LookupInit(void)
void LookupInit(void)
{
static int inited = 0;
RTFKey *rp;
if (inited == 0)
memset(rtfHashTable, 0, sizeof rtfHashTable);
for (rp = rtfKey; rp->rtfKStr != NULL; rp++)
{
memset(rtfHashTable, 0, RTF_KEY_COUNT * 2 * sizeof(*rtfHashTable));
for (rp = rtfKey; rp->rtfKStr != NULL; rp++) {
int index;
rp->rtfKHash = Hash ((char*)rp->rtfKStr);
index = rp->rtfKHash % (RTF_KEY_COUNT * 2);
if (!rtfHashTable[index].count)
rtfHashTable[index].value = RTFAlloc(sizeof(RTFKey *));
else
rtfHashTable[index].value = RTFReAlloc(rtfHashTable[index].value, sizeof(RTFKey *) * (rtfHashTable[index].count + 1));
rtfHashTable[index].value[rtfHashTable[index].count++] = rp;
}
++inited;
int index;
rp->rtfKHash = Hash (rp->rtfKStr);
index = rp->rtfKHash % (RTF_KEY_COUNT * 2);
if (!rtfHashTable[index].count)
rtfHashTable[index].value = RTFAlloc(sizeof(RTFKey *));
else
rtfHashTable[index].value = RTFReAlloc(rtfHashTable[index].value, sizeof(RTFKey *) * (rtfHashTable[index].count + 1));
rtfHashTable[index].value[rtfHashTable[index].count++] = rp;
}
}
void LookupCleanup(void)
{
int i;
for (i=0; i<RTF_KEY_COUNT*2; i++)
{
RTFFree( rtfHashTable[i].value );
rtfHashTable[i].value = NULL;
rtfHashTable[i].count = 0;
}
}
@ -2362,7 +2332,6 @@ static void Lookup(RTF_Info *info, char *s)
RTFHashTableEntry *entry;
int i;
TRACE("\n");
++s; /* skip over the leading \ character */
hash = Hash (s);
entry = &rtfHashTable[hash % (RTF_KEY_COUNT * 2)];
@ -2385,7 +2354,7 @@ static void Lookup(RTF_Info *info, char *s)
* Compute hash value of symbol
*/
static int Hash(char *s)
static int Hash(const char *s)
{
char c;
int val = 0;
@ -2495,8 +2464,6 @@ TextClass (RTF_Info *info)
static void
ControlClass (RTF_Info *info)
{
TRACE("\n");
switch (info->rtfMajor)
{
case rtfCharAttr:
@ -2525,7 +2492,7 @@ static void
CharAttr(RTF_Info *info)
{
RTFFont *font;
switch (info->rtfMinor)
{
case rtfFontNum:
@ -2578,7 +2545,6 @@ CharSet(RTF_Info *info)
static void
Destination (RTF_Info *info)
{
TRACE("\n");
if (!RTFGetDestinationCallback(info, info->rtfMinor))
RTFSkipGroup (info);
}
@ -2611,9 +2577,6 @@ DocAttr(RTF_Info *info)
static void SpecialChar (RTF_Info *info)
{
TRACE("\n");
switch (info->rtfMinor)
{
case rtfOptDest:
@ -2628,9 +2591,9 @@ static void SpecialChar (RTF_Info *info)
case rtfUnicode:
{
int i;
RTFPutUnicodeChar(info, info->rtfParam);
/* After \u we must skip number of character tokens set by \ucN */
for (i = 0; i < info->unicodeLength; i++)
{
@ -2652,9 +2615,6 @@ static void SpecialChar (RTF_Info *info)
case rtfPar:
RTFPutUnicodeChar (info, '\n');
break;
case rtfCell:
RTFPutUnicodeChar (info, ' '); /* make sure cells are separated */
break;
case rtfNoBrkSpace:
RTFPutUnicodeChar (info, 0x00A0);
break;

View file

@ -3,17 +3,20 @@
<include base="riched20">.</include>
<include base="ReactOS">include/reactos/wine</include>
<define name="__REACTOS__" />
<define name="__WINESRC__" />
<define name="__USE_W32API" />
<define name="_WIN32_IE">0x600</define>
<define name="_WIN32_WINNT">0x501</define>
<define name="WINVER">0x501</define>
<library>uuid</library>
<library>wine</library>
<library>ntdll</library>
<library>kernel32</library>
<library>ole32</library>
<library>user32</library>
<library>gdi32</library>
<library>kernel32</library>
<library>uuid</library>
<library>ntdll</library>
<file>caret.c</file>
<file>clipboard.c</file>
<file>context.c</file>
<file>editor.c</file>
<file>list.c</file>
@ -25,8 +28,10 @@
<file>run.c</file>
<file>string.c</file>
<file>style.c</file>
<file>txtsrv.c</file>
<file>undo.c</file>
<file>wrap.c</file>
<file>writer.c</file>
<file>version.rc</file>
<file>riched20.spec</file>
</module>

View file

@ -16,7 +16,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
@ -31,37 +31,58 @@
#include "winuser.h"
#include "ole2.h"
#include "richole.h"
#include "editor.h"
#include "tom.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(richedit);
typedef struct IRichEditOleImpl {
const IRichEditOleVtbl *lpVtbl;
LONG 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 */
#include "initguid.h"
#define TEXTSERV_GUID(name, l, w1, w2, b1, b2) \
GUID name = { l, w1, w2, {b1, b2, 0x00, 0xaa, 0x00, 0x6c, 0xad, 0xc5}}
DEFINE_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);
DEFINE_GUID(IID_ITextDocument, 0x8cc497c0, 0xa1df, 0x11ce, 0x80, 0x98, 0x00, 0xaa, 0x00, 0x47, 0xbe, 0x5d);
typedef struct IRichEditOleImpl {
const IRichEditOleVtbl *lpRichEditOleVtbl;
const ITextDocumentVtbl *lpTextDocumentVtbl;
LONG ref;
ME_TextEditor *editor;
} IRichEditOleImpl;
static inline IRichEditOleImpl *impl_from_IRichEditOle(IRichEditOle *iface)
{
return (IRichEditOleImpl *)((BYTE*)iface - FIELD_OFFSET(IRichEditOleImpl, lpRichEditOleVtbl));
}
static inline IRichEditOleImpl *impl_from_ITextDocument(ITextDocument *iface)
{
return (IRichEditOleImpl *)((BYTE*)iface - FIELD_OFFSET(IRichEditOleImpl, lpTextDocumentVtbl));
}
static HRESULT WINAPI
IRichEditOle_fnQueryInterface(IRichEditOle *me, REFIID riid, LPVOID *ppvObj)
{
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
IRichEditOleImpl *This = impl_from_IRichEditOle(me);
TRACE("%p %s\n", This, debugstr_guid(riid) );
*ppvObj = NULL;
if (IsEqualGUID(riid, &IID_IUnknown) ||
IsEqualGUID(riid, &IID_IRichEditOle))
*ppvObj = &This->lpRichEditOleVtbl;
else if (IsEqualGUID(riid, &IID_ITextDocument))
*ppvObj = &This->lpTextDocumentVtbl;
if (*ppvObj)
{
IRichEditOle_AddRef(me);
*ppvObj = (LPVOID) This;
return S_OK;
}
FIXME("%p: unhandled interface %s\n", This, debugstr_guid(riid) );
@ -72,10 +93,10 @@ IRichEditOle_fnQueryInterface(IRichEditOle *me, REFIID riid, LPVOID *ppvObj)
static ULONG WINAPI
IRichEditOle_fnAddRef(IRichEditOle *me)
{
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
IRichEditOleImpl *This = impl_from_IRichEditOle(me);
ULONG ref = InterlockedIncrement( &This->ref );
TRACE("%p ref = %lu\n", This, ref);
TRACE("%p ref = %u\n", This, ref);
return ref;
}
@ -83,15 +104,15 @@ IRichEditOle_fnAddRef(IRichEditOle *me)
static ULONG WINAPI
IRichEditOle_fnRelease(IRichEditOle *me)
{
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
IRichEditOleImpl *This = impl_from_IRichEditOle(me);
ULONG ref = InterlockedDecrement(&This->ref);
TRACE ("%p ref=%lu\n", This, ref);
TRACE ("%p ref=%u\n", This, ref);
if (!ref)
{
TRACE ("Destroying %p\n", This);
HeapFree(GetProcessHeap(),0,This);
richedit_free(This);
}
return ref;
}
@ -99,7 +120,7 @@ IRichEditOle_fnRelease(IRichEditOle *me)
static HRESULT WINAPI
IRichEditOle_fnActivateAs(IRichEditOle *me, REFCLSID rclsid, REFCLSID rclsidAs)
{
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
IRichEditOleImpl *This = impl_from_IRichEditOle(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
@ -107,7 +128,7 @@ IRichEditOle_fnActivateAs(IRichEditOle *me, REFCLSID rclsid, REFCLSID rclsidAs)
static HRESULT WINAPI
IRichEditOle_fnContextSensitiveHelp(IRichEditOle *me, BOOL fEnterMode)
{
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
IRichEditOleImpl *This = impl_from_IRichEditOle(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
@ -116,7 +137,7 @@ static HRESULT WINAPI
IRichEditOle_fnConvertObject(IRichEditOle *me, LONG iob,
REFCLSID rclsidNew, LPCSTR lpstrUserTypeNew)
{
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
IRichEditOleImpl *This = impl_from_IRichEditOle(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
@ -125,7 +146,7 @@ static HRESULT WINAPI
IRichEditOle_fnGetClientSite(IRichEditOle *me,
LPOLECLIENTSITE *lplpolesite)
{
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
IRichEditOleImpl *This = impl_from_IRichEditOle(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
@ -134,14 +155,22 @@ 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;
IRichEditOleImpl *This = impl_from_IRichEditOle(me);
CHARRANGE tmpchrg;
TRACE("(%p,%p,%d)\n",This, lpchrg, reco);
if(!lplpdataobj)
return E_INVALIDARG;
if(!lpchrg) {
ME_GetSelection(This->editor, (int*)&tmpchrg.cpMin, (int*)&tmpchrg.cpMax);
lpchrg = &tmpchrg;
}
return ME_GetDataObject(This->editor, lpchrg, lplpdataobj);
}
static LONG WINAPI IRichEditOle_fnGetLinkCount(IRichEditOle *me)
{
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
IRichEditOleImpl *This = impl_from_IRichEditOle(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
@ -150,7 +179,7 @@ static HRESULT WINAPI
IRichEditOle_fnGetObject(IRichEditOle *me, LONG iob,
REOBJECT *lpreobject, DWORD dwFlags)
{
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
IRichEditOleImpl *This = impl_from_IRichEditOle(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
@ -158,7 +187,7 @@ IRichEditOle_fnGetObject(IRichEditOle *me, LONG iob,
static LONG WINAPI
IRichEditOle_fnGetObjectCount(IRichEditOle *me)
{
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
IRichEditOleImpl *This = impl_from_IRichEditOle(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
@ -166,7 +195,7 @@ IRichEditOle_fnGetObjectCount(IRichEditOle *me)
static HRESULT WINAPI
IRichEditOle_fnHandsOffStorage(IRichEditOle *me, LONG iob)
{
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
IRichEditOleImpl *This = impl_from_IRichEditOle(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
@ -175,7 +204,7 @@ static HRESULT WINAPI
IRichEditOle_fnImportDataObject(IRichEditOle *me, LPDATAOBJECT lpdataobj,
CLIPFORMAT cf, HGLOBAL hMetaPict)
{
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
IRichEditOleImpl *This = impl_from_IRichEditOle(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
@ -183,7 +212,7 @@ IRichEditOle_fnImportDataObject(IRichEditOle *me, LPDATAOBJECT lpdataobj,
static HRESULT WINAPI
IRichEditOle_fnInPlaceDeactivate(IRichEditOle *me)
{
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
IRichEditOleImpl *This = impl_from_IRichEditOle(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
@ -191,7 +220,7 @@ IRichEditOle_fnInPlaceDeactivate(IRichEditOle *me)
static HRESULT WINAPI
IRichEditOle_fnInsertObject(IRichEditOle *me, REOBJECT *lpreobject)
{
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
IRichEditOleImpl *This = impl_from_IRichEditOle(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
@ -199,7 +228,7 @@ IRichEditOle_fnInsertObject(IRichEditOle *me, REOBJECT *lpreobject)
static HRESULT WINAPI IRichEditOle_fnSaveCompleted(IRichEditOle *me, LONG iob,
LPSTORAGE lpstg)
{
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
IRichEditOleImpl *This = impl_from_IRichEditOle(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
@ -207,7 +236,7 @@ static HRESULT WINAPI IRichEditOle_fnSaveCompleted(IRichEditOle *me, LONG iob,
static HRESULT WINAPI
IRichEditOle_fnSetDvaspect(IRichEditOle *me, LONG iob, DWORD dvaspect)
{
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
IRichEditOleImpl *This = impl_from_IRichEditOle(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
@ -215,7 +244,7 @@ IRichEditOle_fnSetDvaspect(IRichEditOle *me, LONG iob, DWORD dvaspect)
static HRESULT WINAPI IRichEditOle_fnSetHostNames(IRichEditOle *me,
LPCSTR lpstrContainerApp, LPCSTR lpstrContainerObj)
{
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
IRichEditOleImpl *This = impl_from_IRichEditOle(me);
FIXME("stub %p %s %s\n",This, lpstrContainerApp, lpstrContainerObj);
return E_NOTIMPL;
}
@ -223,7 +252,7 @@ static HRESULT WINAPI IRichEditOle_fnSetHostNames(IRichEditOle *me,
static HRESULT WINAPI
IRichEditOle_fnSetLinkAvailable(IRichEditOle *me, LONG iob, BOOL fAvailable)
{
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
IRichEditOleImpl *This = impl_from_IRichEditOle(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
@ -250,16 +279,264 @@ static const IRichEditOleVtbl revt = {
IRichEditOle_fnImportDataObject
};
LRESULT CreateIRichEditOle(LPVOID *ppObj)
static HRESULT WINAPI
ITextDocument_fnQueryInterface(ITextDocument* me, REFIID riid,
void** ppvObject)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
return IRichEditOle_fnQueryInterface((IRichEditOle*)&This->lpRichEditOleVtbl,
riid, ppvObject);
}
static ULONG WINAPI
ITextDocument_fnAddRef(ITextDocument* me)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
return IRichEditOle_fnAddRef((IRichEditOle*)&This->lpRichEditOleVtbl);
}
static ULONG WINAPI
ITextDocument_fnRelease(ITextDocument* me)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
return IRichEditOle_fnRelease((IRichEditOle*)&This->lpRichEditOleVtbl);
}
static HRESULT WINAPI
ITextDocument_fnGetTypeInfoCount(ITextDocument* me,
UINT* pctinfo)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnGetTypeInfo(ITextDocument* me, UINT iTInfo, LCID lcid,
ITypeInfo** ppTInfo)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnGetIDsOfNames(ITextDocument* me, REFIID riid,
LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnInvoke(ITextDocument* me, DISPID dispIdMember,
REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams,
VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnGetName(ITextDocument* me, BSTR* pName)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnGetSelection(ITextDocument* me, ITextSelection** ppSel)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnGetStoryCount(ITextDocument* me, long* pCount)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnGetStoryRanges(ITextDocument* me,
ITextStoryRanges** ppStories)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnGetSaved(ITextDocument* me, long* pValue)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnSetSaved(ITextDocument* me, long Value)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnGetDefaultTabStop(ITextDocument* me, float* pValue)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnSetDefaultTabStop(ITextDocument* me, float Value)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnNew(ITextDocument* me)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnOpen(ITextDocument* me, VARIANT* pVar, long Flags,
long CodePage)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnSave(ITextDocument* me, VARIANT* pVar, long Flags,
long CodePage)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnFreeze(ITextDocument* me, long* pCount)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnUnfreeze(ITextDocument* me, long* pCount)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnBeginEditCollection(ITextDocument* me)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnEndEditCollection(ITextDocument* me)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnUndo(ITextDocument* me, long Count, long* prop)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnRedo(ITextDocument* me, long Count, long* prop)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnRange(ITextDocument* me, long cp1, long cp2,
ITextRange** ppRange)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
ITextDocument_fnRangeFromPoint(ITextDocument* me, long x, long y,
ITextRange** ppRange)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
FIXME("stub %p\n",This);
return E_NOTIMPL;
}
static const ITextDocumentVtbl tdvt = {
ITextDocument_fnQueryInterface,
ITextDocument_fnAddRef,
ITextDocument_fnRelease,
ITextDocument_fnGetTypeInfoCount,
ITextDocument_fnGetTypeInfo,
ITextDocument_fnGetIDsOfNames,
ITextDocument_fnInvoke,
ITextDocument_fnGetName,
ITextDocument_fnGetSelection,
ITextDocument_fnGetStoryCount,
ITextDocument_fnGetStoryRanges,
ITextDocument_fnGetSaved,
ITextDocument_fnSetSaved,
ITextDocument_fnGetDefaultTabStop,
ITextDocument_fnSetDefaultTabStop,
ITextDocument_fnNew,
ITextDocument_fnOpen,
ITextDocument_fnSave,
ITextDocument_fnFreeze,
ITextDocument_fnUnfreeze,
ITextDocument_fnBeginEditCollection,
ITextDocument_fnEndEditCollection,
ITextDocument_fnUndo,
ITextDocument_fnRedo,
ITextDocument_fnRange,
ITextDocument_fnRangeFromPoint
};
LRESULT CreateIRichEditOle(ME_TextEditor *editor, LPVOID *ppObj)
{
IRichEditOleImpl *reo;
reo = HeapAlloc(GetProcessHeap(), 0, sizeof(IRichEditOleImpl));
reo = richedit_alloc(sizeof(IRichEditOleImpl));
if (!reo)
return 0;
reo->lpVtbl = &revt;
reo->lpRichEditOleVtbl = &revt;
reo->lpTextDocumentVtbl = &tdvt;
reo->ref = 1;
reo->editor = editor;
TRACE("Created %p\n",reo);
*ppObj = (LPVOID) reo;

View file

@ -18,7 +18,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
@ -28,8 +28,8 @@ 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) {
if(nRelPos<=0) { /* if this or preceding row */
do {
ME_DisplayItem *item2 = ME_FindItemBack(item, diStartRowOrParagraph);
if (item2->type == diParagraph)
{
@ -50,8 +50,7 @@ ME_DisplayItem *ME_FindRowStart(ME_Context *c, ME_DisplayItem *item,
}
assert(0 == "bug in FindItemBack(item, diStartRowOrParagraph)");
item = item2;
}
return item;
} while(1);
}
while(nRelPos>0) { /* if one of the next rows */
ME_DisplayItem *item2 = ME_FindItemFwd(item, diStartRowOrParagraph);

View file

@ -1147,4 +1147,7 @@ int BeginFile (RTF_Info *);
int RTFCharSetToCodePage(RTF_Info *info, int charset);
void LookupInit (void);
void LookupCleanup (void);
#endif

View file

@ -4,6 +4,7 @@
* Character/pixel conversions.
*
* Copyright 2004 by Krzysztof Foltman
* Copyright 2006 by Phil Krylov
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -17,7 +18,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "editor.h"
@ -26,6 +27,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(richedit);
WINE_DECLARE_DEBUG_CHANNEL(richedit_check);
WINE_DECLARE_DEBUG_CHANNEL(richedit_lists);
/******************************************************************************
* ME_CanJoinRuns
*
* Returns 1 if two runs can be safely merged into one, 0 otherwise.
*/
int ME_CanJoinRuns(ME_Run *run1, ME_Run *run2)
{
if ((run1->nFlags | run2->nFlags) & MERF_NOJOIN)
@ -44,8 +50,18 @@ void ME_SkipAndPropagateCharOffset(ME_DisplayItem *p, int shift)
ME_PropagateCharOffset(p, shift);
}
/******************************************************************************
* ME_PropagateCharOffsets
*
* Shifts (increases or decreases) character offset (relative to beginning of
* the document) of the part of the text starting from given place.
*/
void ME_PropagateCharOffset(ME_DisplayItem *p, int shift)
{
/* Runs in one paragraph contain character offset relative to their owning
* paragraph. If we start the shifting from the run, we need to shift
* all the relative offsets until the end of the paragraph
*/
if (p->type == diRun) /* propagate in all runs in this para */
{
TRACE("PropagateCharOffset(%s, %d)\n", debugstr_w(p->member.run.strText->szData), shift);
@ -55,6 +71,10 @@ void ME_PropagateCharOffset(ME_DisplayItem *p, int shift)
p = ME_FindItemFwd(p, diRunOrParagraphOrEnd);
} while(p->type == diRun);
}
/* Runs in next paragraphs don't need their offsets updated, because they,
* again, those offsets are relative to their respective paragraphs.
* Instead of that, we're updating paragraphs' character offsets.
*/
if (p->type == diParagraph) /* propagate in all next paras */
{
do {
@ -63,6 +83,9 @@ void ME_PropagateCharOffset(ME_DisplayItem *p, int shift)
p = p->member.para.next_para;
} while(p->type == diParagraph);
}
/* diTextEnd also has character offset in it, which makes finding text length
* easier. But it needs to be up to date first.
*/
if (p->type == diTextEnd)
{
p->member.para.nCharOfs += shift;
@ -70,6 +93,11 @@ void ME_PropagateCharOffset(ME_DisplayItem *p, int shift)
}
}
/******************************************************************************
* ME_CheckCharOffsets
*
* Checks if editor lists' validity and optionally dumps the document structure
*/
void ME_CheckCharOffsets(ME_TextEditor *editor)
{
ME_DisplayItem *p = editor->pBuffer->pFirst;
@ -93,7 +121,7 @@ void ME_CheckCharOffsets(ME_TextEditor *editor)
ofs = 0;
break;
case diRun:
TRACE_(richedit_check)("run, real ofs = %d (+ofsp = %d), counted = %d, len = %d, txt = \"%s\", flags=%08x, fx&mask = %08lx\n",
TRACE_(richedit_check)("run, real ofs = %d (+ofsp = %d), counted = %d, len = %d, txt = \"%s\", flags=%08x, fx&mask = %08x\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,
@ -110,6 +138,13 @@ void ME_CheckCharOffsets(ME_TextEditor *editor)
} while(1);
}
/******************************************************************************
* ME_CharOfsFromRunOfs
*
* Converts a character position relative to the start of the run, to a
* character position relative to the start of the document.
* Kind of a "local to global" offset conversion.
*/
int ME_CharOfsFromRunOfs(ME_TextEditor *editor, ME_DisplayItem *pRun, int nOfs)
{
ME_DisplayItem *pPara;
@ -124,11 +159,25 @@ int ME_CharOfsFromRunOfs(ME_TextEditor *editor, ME_DisplayItem *pRun, int nOfs)
+ ME_VPosToPos(pRun->member.run.strText, nOfs);
}
/******************************************************************************
* ME_CursorFromCharOfs
*
* Converts a character offset (relative to the start of the document) to
* a cursor structure (which contains a run and a position relative to that
* run).
*/
void ME_CursorFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_Cursor *pCursor)
{
ME_RunOfsFromCharOfs(editor, nCharOfs, &pCursor->pRun, &pCursor->nOffset);
}
/******************************************************************************
* ME_RunOfsFromCharOfs
*
* Find a run and relative character offset given an absolute character offset
* (absolute offset being an offset relative to the start of the document).
* Kind of a "global to local" offset conversion.
*/
void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **ppRun, int *pOfs)
{
ME_DisplayItem *pPara;
@ -175,6 +224,11 @@ void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **
assert((*ppRun)->member.run.nFlags & MERF_ENDPARA);
}
/******************************************************************************
* ME_JoinRuns
*
* Merges two adjacent runs, the one given as a parameter and the next one.
*/
void ME_JoinRuns(ME_TextEditor *editor, ME_DisplayItem *p)
{
ME_DisplayItem *pNext = p->next;
@ -183,8 +237,11 @@ void ME_JoinRuns(ME_TextEditor *editor, ME_DisplayItem *p)
assert(p->member.run.nCharOfs != -1);
ME_GetParagraph(p)->member.para.nFlags |= MEPF_REWRAP;
if (editor->bCaretAtEnd && editor->pCursors[0].pRun == pNext)
/* if we were at the end of screen line, and the next run is in the new
* line, then it's not the end of the line anymore */
if (editor->bCaretAtEnd && editor->pCursors[0].pRun == pNext)
editor->bCaretAtEnd = FALSE;
/* Update all cursors so that they don't contain the soon deleted run */
for (i=0; i<editor->nCursors; i++) {
if (editor->pCursors[i].pRun == pNext) {
editor->pCursors[i].pRun = p;
@ -204,6 +261,12 @@ void ME_JoinRuns(ME_TextEditor *editor, ME_DisplayItem *p)
}
}
/******************************************************************************
* ME_SplitRun
*
* Splits a run into two in a given place. It also updates the screen position
* and size (extent) of the newly generated runs.
*/
ME_DisplayItem *ME_SplitRun(ME_Context *c, ME_DisplayItem *item, int nVChar)
{
ME_TextEditor *editor = c->editor;
@ -221,7 +284,7 @@ ME_DisplayItem *ME_SplitRun(ME_Context *c, ME_DisplayItem *item, int nVChar)
run = &item->member.run;
TRACE("Before split: %s(%ld, %ld)\n", debugstr_w(run->strText->szData),
TRACE("Before split: %s(%d, %d)\n", debugstr_w(run->strText->szData),
run->pt.x, run->pt.y);
item2 = ME_SplitRunSimple(editor, item, nVChar);
@ -239,7 +302,7 @@ ME_DisplayItem *ME_SplitRun(ME_Context *c, ME_DisplayItem *item, int nVChar)
TRACE("Before check after split\n");
ME_CheckCharOffsets(editor);
TRACE("After check after split\n");
TRACE("After split: %s(%ld, %ld), %s(%ld, %ld)\n",
TRACE("After split: %s(%d, %d), %s(%d, %d)\n",
debugstr_w(run->strText->szData), run->pt.x, run->pt.y,
debugstr_w(run2->strText->szData), run2->pt.x, run2->pt.y);
}
@ -247,7 +310,12 @@ ME_DisplayItem *ME_SplitRun(ME_Context *c, ME_DisplayItem *item, int nVChar)
return item2;
}
/* split a run starting from voffset */
/******************************************************************************
* ME_SplitRunSimple
*
* Does the most basic job of splitting a run into two - it does not
* update the positions and extents.
*/
ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, int nVChar)
{
ME_Run *run = &item->member.run;
@ -256,7 +324,7 @@ ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, i
int i;
assert(nVChar > 0 && nVChar < ME_StrVLen(run->strText));
assert(item->type == diRun);
assert(!(item->member.run.nFlags & (MERF_GRAPHICS | MERF_TAB)));
assert(!(item->member.run.nFlags & MERF_NONTEXT));
assert(item->member.run.nCharOfs != -1);
item2 = ME_MakeRun(run->style,
@ -282,6 +350,11 @@ ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, i
return item2;
}
/******************************************************************************
* ME_MakeRun
*
* A helper function to create run structures quickly.
*/
ME_DisplayItem *ME_MakeRun(ME_Style *s, ME_String *strData, int nFlags)
{
ME_DisplayItem *item = ME_MakeDI(diRun);
@ -293,37 +366,80 @@ ME_DisplayItem *ME_MakeRun(ME_Style *s, ME_String *strData, int nFlags)
return item;
}
/******************************************************************************
* ME_InsertRun
*
* Inserts a run at a given character position (offset).
*/
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);
if (pUI) {
pUI->nStart = nCharOfs;
pUI->nLen = pItem->member.run.strText->nLen;
}
ME_CursorFromCharOfs(editor, nCharOfs, &tmp);
if (tmp.nOffset) {
tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset);
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;
pDI = ME_InsertRunAtCursor(editor, &tmp, pItem->member.run.style,
pItem->member.run.strText->szData,
pItem->member.run.strText->nLen,
pItem->member.run.nFlags);
return pDI;
}
/******************************************************************************
* ME_InsertRunAtCursor
*
* Inserts a new run with given style, flags and content at a given position,
* which is passed as a cursor structure (which consists of a run and
* a run-relative character offset).
*/
ME_DisplayItem *
ME_InsertRunAtCursor(ME_TextEditor *editor, ME_Cursor *cursor, ME_Style *style,
const WCHAR *str, int len, int flags)
{
ME_DisplayItem *pDI;
ME_UndoItem *pUI;
if (cursor->nOffset) {
/* We're inserting at the middle of the existing run, which means that
* that run must be split. It isn't always necessary, but */
cursor->pRun = ME_SplitRunSimple(editor, cursor->pRun, cursor->nOffset);
cursor->nOffset = 0;
}
pUI = ME_AddUndoItem(editor, diUndoDeleteRun, NULL);
if (pUI) {
pUI->nStart = (ME_GetParagraph(cursor->pRun)->member.para.nCharOfs
+ cursor->pRun->member.run.nCharOfs);
pUI->nLen = len;
}
pDI = ME_MakeRun(style, ME_MakeStringN(str, len), flags);
pDI->member.run.nCharOfs = cursor->pRun->member.run.nCharOfs;
ME_InsertBefore(cursor->pRun, pDI);
TRACE("Shift length:%d\n", len);
ME_PropagateCharOffset(cursor->pRun, len);
ME_GetParagraph(cursor->pRun)->member.para.nFlags |= MEPF_REWRAP;
return pDI;
}
/******************************************************************************
* ME_UpdateRunFlags
*
* Determine some of run attributes given its content (style, text content).
* Some flags cannot be determined by this function (MERF_GRAPHICS,
* MERF_ENDPARA)
*/
void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run)
{
assert(run->nCharOfs != -1);
if (RUN_IS_HIDDEN(run))
run->nFlags |= MERF_HIDDEN;
else
run->nFlags &= ~MERF_HIDDEN;
if (ME_IsSplitable(run->strText))
run->nFlags |= MERF_SPLITTABLE;
else
@ -351,6 +467,12 @@ void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run)
run->nFlags &= ~(MERF_WHITESPACE | MERF_STARTWHITE | MERF_ENDWHITE);
}
/******************************************************************************
* ME_GetGraphicsSize
*
* Sets run extent for graphics runs. This functionality is just a placeholder
* for future OLE object support, and will be removed.
*/
void ME_GetGraphicsSize(ME_TextEditor *editor, ME_Run *run, SIZE *pSize)
{
assert(run->nFlags & MERF_GRAPHICS);
@ -358,7 +480,14 @@ void ME_GetGraphicsSize(ME_TextEditor *editor, ME_Run *run, SIZE *pSize)
pSize->cy = 64;
}
int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Paragraph *para, ME_Run *run)
/******************************************************************************
* ME_CharFromPoint
*
* Returns a character position inside the run given a run-relative
* pixel horizontal position. This version rounds left (ie. if the second
* character is at pixel position 8, then for cx=0..7 it returns 0).
*/
int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run)
{
int fit = 0;
HGDIOBJ hOldFont;
@ -367,9 +496,9 @@ int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Paragraph *para, ME_Run *
if (!run->strText->nLen)
return 0;
if (run->nFlags & MERF_TAB)
if (run->nFlags & (MERF_TAB | MERF_CELL))
{
if (cx < run->nWidth/2)
if (cx < run->nWidth/2)
return 0;
return 1;
}
@ -383,15 +512,41 @@ int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Paragraph *para, ME_Run *
}
hDC = GetDC(editor->hWnd);
hOldFont = ME_SelectStyleFont(editor, hDC, run->style);
GetTextExtentExPointW(hDC, run->strText->szData, run->strText->nLen,
cx, &fit, NULL, &sz);
if (editor->cPasswordMask)
{
ME_String *strMasked = ME_MakeStringR(editor->cPasswordMask,ME_StrVLen(run->strText));
GetTextExtentExPointW(hDC, strMasked->szData, run->strText->nLen,
cx, &fit, NULL, &sz);
ME_DestroyString(strMasked);
}
else
{
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;
}
/******************************************************************************
* ME_CharFromPointCursor
*
* Returns a character position inside the run given a run-relative
* pixel horizontal position. This version rounds to the nearest character edge
* (ie. if the second character is at pixel position 8, then for cx=0..3
* it returns 0, and for cx=4..7 it returns 1).
*
* It is used for mouse click handling, for better usability (and compatibility
* with the native control).
*/
int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run)
{
ME_String *strRunText;
/* This could point to either the run's real text, or it's masked form in a password control */
int fit = 0, fit1 = 0;
HGDIOBJ hOldFont;
HDC hDC;
@ -399,7 +554,7 @@ int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run)
if (!run->strText->nLen)
return 0;
if (run->nFlags & MERF_TAB)
if (run->nFlags & (MERF_TAB | MERF_CELL))
{
if (cx < run->nWidth/2)
return 0;
@ -413,31 +568,48 @@ int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run)
return 0;
return 1;
}
if (editor->cPasswordMask)
strRunText = ME_MakeStringR(editor->cPasswordMask,ME_StrVLen(run->strText));
else
strRunText = run->strText;
hDC = GetDC(editor->hWnd);
hOldFont = ME_SelectStyleFont(editor, hDC, run->style);
GetTextExtentExPointW(hDC, run->strText->szData, run->strText->nLen,
GetTextExtentExPointW(hDC, strRunText->szData, strRunText->nLen,
cx, &fit, NULL, &sz);
if (fit != run->strText->nLen)
if (fit != strRunText->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);
GetTextExtentPoint32W(hDC, strRunText->szData, fit, &sz2);
fit1 = ME_StrRelPos(strRunText, fit, &chars);
GetTextExtentPoint32W(hDC, strRunText->szData, fit1, &sz3);
if (cx >= (sz2.cx+sz3.cx)/2)
fit = fit1;
}
if (editor->cPasswordMask)
ME_DestroyString(strRunText);
ME_UnselectStyleFont(editor, hDC, run->style, hOldFont);
ReleaseDC(editor->hWnd, hDC);
return fit;
}
/******************************************************************************
* ME_PointFromChar
*
* Returns a run-relative pixel position given a run-relative character
* position (character offset)
*/
int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset)
{
SIZE size;
HDC hDC = GetDC(editor->hWnd);
HGDIOBJ hOldFont;
ME_String *strRunText;
/* This could point to either the run's real text, or it's masked form in a password control */
if (pRun->nFlags & MERF_GRAPHICS)
{
@ -445,15 +617,27 @@ int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset)
ME_GetGraphicsSize(editor, pRun, &size);
return 1;
}
if (editor->cPasswordMask)
strRunText = ME_MakeStringR(editor->cPasswordMask,ME_StrVLen(pRun->strText));
else
strRunText = pRun->strText;
hOldFont = ME_SelectStyleFont(editor, hDC, pRun->style);
GetTextExtentPoint32W(hDC, pRun->strText->szData, nOffset, &size);
GetTextExtentPoint32W(hDC, strRunText->szData, nOffset, &size);
ME_UnselectStyleFont(editor, hDC, pRun->style, hOldFont);
ReleaseDC(editor->hWnd, hDC);
if (editor->cPasswordMask)
ME_DestroyString(strRunText);
return size.cx;
}
void ME_GetTextExtent(ME_Context *c, LPCWSTR szText, int nChars, ME_Style *s,
SIZE *size)
/******************************************************************************
* ME_GetTextExtent
*
* Finds a width and a height of the text using a specified style
*/
static void ME_GetTextExtent(ME_Context *c, LPCWSTR szText, int nChars, ME_Style *s, SIZE *size)
{
HDC hDC = c->hDC;
HGDIOBJ hOldFont;
@ -462,7 +646,14 @@ void ME_GetTextExtent(ME_Context *c, LPCWSTR szText, int nChars, ME_Style *s,
ME_UnselectStyleFont(c->editor, hDC, s, hOldFont);
}
SIZE ME_GetRunSizeCommon(ME_Context *c, ME_Paragraph *para, ME_Run *run, int nLen, int *pAscent, int *pDescent)
/******************************************************************************
* ME_GetRunSizeCommon
*
* Finds width, height, ascent and descent of a run, up to given character
* (nLen).
*/
static SIZE ME_GetRunSizeCommon(ME_Context *c, ME_Paragraph *para, ME_Run *run, int nLen,
int *pAscent, int *pDescent)
{
SIZE size;
int nMaxLen = ME_StrVLen(run->strText);
@ -471,10 +662,20 @@ SIZE ME_GetRunSizeCommon(ME_Context *c, ME_Paragraph *para, ME_Run *run, int nLe
nLen = nMaxLen;
/* FIXME the following call also ensures that TEXTMETRIC structure is filled
* this is wasteful for graphics and TAB runs, but that shouldn't matter
* this is wasteful for MERF_NONTEXT runs, but that shouldn't matter
* in practice
*/
ME_GetTextExtent(c, run->strText->szData, nLen, run->style, &size);
if (c->editor->cPasswordMask)
{
ME_String *szMasked = ME_MakeStringR(c->editor->cPasswordMask,nLen);
ME_GetTextExtent(c, szMasked->szData, nLen,run->style, &size);
ME_DestroyString(szMasked);
}
else
{
ME_GetTextExtent(c, run->strText->szData, nLen, run->style, &size);
}
*pAscent = run->style->tm.tmAscent;
*pDescent = run->style->tm.tmDescent;
size.cy = *pAscent + *pDescent;
@ -511,31 +712,67 @@ SIZE ME_GetRunSizeCommon(ME_Context *c, ME_Paragraph *para, ME_Run *run, int nLe
/* descent is unchanged */
return size;
}
if (run->nFlags & MERF_CELL)
{
int lpsx = GetDeviceCaps(c->hDC, LOGPIXELSX);
size.cx = run->pCell->nRightBoundary * lpsx / 1440 - run->pt.x;
return size;
}
return size;
}
/******************************************************************************
* ME_GetRunSize
*
* Finds width and height (but not ascent and descent) of a part of the run
* up to given character.
*/
SIZE ME_GetRunSize(ME_Context *c, ME_Paragraph *para, ME_Run *run, int nLen)
{
int asc, desc;
return ME_GetRunSizeCommon(c, para, run, nLen, &asc, &desc);
}
/******************************************************************************
* ME_CalcRunExtent
*
* Updates the size of the run (fills width, ascent and descent). The height
* is calculated based on whole row's ascent and descent anyway, so no need
* to use it here.
*/
void ME_CalcRunExtent(ME_Context *c, ME_Paragraph *para, ME_Run *run)
{
int nEnd = ME_StrVLen(run->strText);
SIZE size = ME_GetRunSizeCommon(c, para, run, nEnd, &run->nAscent, &run->nDescent);
run->nWidth = size.cx;
if (!size.cx)
WARN("size.cx == 0\n");
if (run->nFlags & MERF_HIDDEN)
run->nWidth = 0;
else
{
int nEnd = ME_StrVLen(run->strText);
SIZE size = ME_GetRunSizeCommon(c, para, run, nEnd, &run->nAscent, &run->nDescent);
run->nWidth = size.cx;
if (!size.cx)
WARN("size.cx == 0\n");
}
}
/******************************************************************************
* ME_MustBeWrapped
*
* This should ensure that the given paragraph is wrapped so that its screen
* row structure may be used. But it doesn't, yet.
*/
void ME_MustBeWrapped(ME_Context *c, ME_DisplayItem *para)
{
assert(para->type == diParagraph);
/* FIXME */
}
/******************************************************************************
* ME_SetSelectionCharFormat
*
* Applies a style change, either to a current selection, or to insert cursor
* (ie. the style next typed characters will use).
*/
void ME_SetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt)
{
int nFrom, nTo;
@ -553,6 +790,11 @@ void ME_SetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt)
ME_SetCharFormat(editor, nFrom, nTo-nFrom, pFmt);
}
/******************************************************************************
* ME_SetCharFormat
*
* Applies a style change to the specified part of the text
*/
void ME_SetCharFormat(ME_TextEditor *editor, int nOfs, int nChars, CHARFORMAT2W *pFmt)
{
ME_Cursor tmp, tmp2;
@ -597,6 +839,11 @@ void ME_SetCharFormat(ME_TextEditor *editor, int nOfs, int nChars, CHARFORMAT2W
}
}
/******************************************************************************
* ME_SetDefaultCharFormat
*
* Applies a style change to the default character style.
*/
void ME_SetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *mod)
{
ME_Style *style;
@ -618,11 +865,17 @@ void ME_SetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *mod)
/* pcf = editor->pBuffer->pDefaultStyle->fmt; */
}
void ME_GetRunCharFormat(ME_TextEditor *editor, ME_DisplayItem *run, CHARFORMAT2W *pFmt)
static void ME_GetRunCharFormat(ME_TextEditor *editor, ME_DisplayItem *run, CHARFORMAT2W *pFmt)
{
ME_CopyCharFormat(pFmt, &run->member.run.style->fmt);
}
/******************************************************************************
* ME_GetDefaultCharFormat
*
* Retrieves the current default character style (the one applied where no
* other style was applied) .
*/
void ME_GetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt)
{
int nFrom, nTo;
@ -630,6 +883,12 @@ void ME_GetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt)
ME_CopyCharFormat(pFmt, &editor->pBuffer->pDefaultStyle->fmt);
}
/******************************************************************************
* ME_GetSelectionCharFormat
*
* If selection exists, it returns all style elements that are set consistently
* in the whole selection. If not, it just returns the current style.
*/
void ME_GetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt)
{
int nFrom, nTo;
@ -642,6 +901,12 @@ void ME_GetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt)
ME_GetCharFormat(editor, nFrom, nTo, pFmt);
}
/******************************************************************************
* ME_GetCharFormat
*
* Returns the style consisting of those attributes which are consistently set
* in the whole character range.
*/
void ME_GetCharFormat(ME_TextEditor *editor, int nFrom, int nTo, CHARFORMAT2W *pFmt)
{
ME_DisplayItem *run, *run_end;

View file

@ -15,7 +15,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "editor.h"
@ -40,13 +40,39 @@ ME_String *ME_MakeString(LPCWSTR szText)
ME_String *ME_MakeStringN(LPCWSTR szText, int nMaxChars)
{
ME_String *s = ALLOC_OBJ(ME_String);
int i;
for (i=0; i<nMaxChars && szText[i]; i++)
;
s->nLen = i;
s->nLen = nMaxChars;
s->nBuffer = ME_GetOptimalBuffer(s->nLen+1);
s->szData = ALLOC_N_OBJ(WCHAR, s->nBuffer);
lstrcpynW(s->szData, szText, s->nLen+1);
/* Native allows NUL chars */
memmove(s->szData, szText, s->nLen * sizeof(WCHAR));
s->szData[s->nLen] = 0;
return s;
}
ME_String *ME_MakeStringR(WCHAR cRepeat, int nMaxChars)
{ /* Make a string by repeating a char nMaxChars times */
int i;
ME_String *s = ALLOC_OBJ(ME_String);
s->nLen = nMaxChars;
s->nBuffer = ME_GetOptimalBuffer(s->nLen+1);
s->szData = ALLOC_N_OBJ(WCHAR, s->nBuffer);
for (i = 0;i<nMaxChars;i++)
s->szData[i] = cRepeat;
s->szData[s->nLen] = 0;
return s;
}
ME_String *ME_MakeStringB(int nMaxChars)
{ /* Create a buffer (uninitialized string) of size nMaxChars */
ME_String *s = ALLOC_OBJ(ME_String);
s->nLen = nMaxChars;
s->nBuffer = ME_GetOptimalBuffer(s->nLen+1);
s->szData = ALLOC_N_OBJ(WCHAR, s->nBuffer);
s->szData[s->nLen] = 0;
return s;
}
@ -155,29 +181,22 @@ 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)
{
int nRelChars = *pRelChars;
TRACE("%s,%d,&%d\n", debugstr_w(s->szData), nVChar, *pRelChars);
assert(*pRelChars);
if (!*pRelChars) return nVChar;
if (*pRelChars>0)
{
while(nVChar<s->nLen && *pRelChars>0)
{
nVChar++;
(*pRelChars)--;
}
if (!nRelChars)
return nVChar;
}
while(nVChar>0 && *pRelChars<0)
{
nVChar--;
(*pRelChars)++;
}
if (nRelChars>0)
nRelChars = min(*pRelChars, s->nLen - nVChar);
else
nRelChars = max(*pRelChars, -nVChar);
nVChar += nRelChars;
*pRelChars -= nRelChars;
return nVChar;
}
@ -278,9 +297,57 @@ int ME_ReverseFindWhitespaceV(ME_String *s, int nVChar) {
return i;
}
LPWSTR ME_ToUnicode(HWND hWnd, LPVOID psz)
static int
ME_WordBreakProc(LPWSTR s, INT start, INT len, INT code)
{
if (IsWindowUnicode(hWnd))
/* FIXME: Native also knows about punctuation */
TRACE("s==%s, start==%d, len==%d, code==%d\n",
debugstr_wn(s, len), start, len, code);
switch (code)
{
case WB_ISDELIMITER:
return ME_IsWSpace(s[start]);
case WB_LEFT:
case WB_MOVEWORDLEFT:
while (start && ME_IsWSpace(s[start - 1]))
start--;
while (start && !ME_IsWSpace(s[start - 1]))
start--;
return start;
case WB_RIGHT:
case WB_MOVEWORDRIGHT:
if (start && ME_IsWSpace(s[start - 1]))
{
while (start < len && ME_IsWSpace(s[start]))
start++;
}
else
{
while (start < len && !ME_IsWSpace(s[start]))
start++;
while (start < len && ME_IsWSpace(s[start]))
start++;
}
return start;
}
return 0;
}
int
ME_CallWordBreakProc(ME_TextEditor *editor, ME_String *str, INT start, INT code)
{
/* FIXME: ANSIfy the string when bEmulateVersion10 is TRUE */
if (!editor->pfnWordBreak)
return ME_WordBreakProc(str->szData, start, str->nLen, code);
else
return editor->pfnWordBreak(str->szData, start, str->nLen, code);
}
LPWSTR ME_ToUnicode(BOOL unicode, LPVOID psz)
{
if (unicode)
return (LPWSTR)psz;
else {
WCHAR *tmp;
@ -291,27 +358,8 @@ LPWSTR ME_ToUnicode(HWND hWnd, LPVOID psz)
}
}
void ME_EndToUnicode(HWND hWnd, LPVOID psz)
void ME_EndToUnicode(BOOL unicode, 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))
if (!unicode)
FREE_OBJ(psz);
}

View file

@ -15,7 +15,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "editor.h"
@ -237,6 +237,7 @@ void ME_DumpStyleToBuf(CHARFORMAT2W *pFmt, char buf[2048])
ME_DumpStyleEffect(&p, "Font italic:", pFmt, CFM_ITALIC);
ME_DumpStyleEffect(&p, "Font underline:", pFmt, CFM_UNDERLINE);
ME_DumpStyleEffect(&p, "Font strikeout:", pFmt, CFM_STRIKEOUT);
ME_DumpStyleEffect(&p, "Hidden text:", pFmt, CFM_HIDDEN);
p += sprintf(p, "Text color: ");
if (pFmt->dwMask & CFM_COLOR)
{
@ -274,7 +275,7 @@ ME_LogFontFromStyle(HDC hDC, LOGFONTW *lf, ME_Style *s, int nZoomNumerator, int
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)
if (s->fmt.dwEffects & s->fmt.dwMask & (CFM_UNDERLINE | CFE_LINK))
lf->lfUnderline = 1;
if (s->fmt.dwEffects & s->fmt.dwMask & CFM_STRIKEOUT)
lf->lfStrikeOut = 1;
@ -285,8 +286,29 @@ ME_LogFontFromStyle(HDC hDC, LOGFONTW *lf, ME_Style *s, int nZoomNumerator, int
lf->lfCharSet = s->fmt.bCharSet;
}
void ME_CharFormatFromLogFont(HDC hDC, LOGFONTW *lf, CHARFORMAT2W *fmt)
{
int rx, ry;
ME_InitCharFormat2W(fmt);
rx = GetDeviceCaps(hDC, LOGPIXELSX);
ry = GetDeviceCaps(hDC, LOGPIXELSY);
lstrcpyW(fmt->szFaceName, lf->lfFaceName);
fmt->dwEffects = 0;
fmt->dwMask = CFM_WEIGHT|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT|CFM_SIZE|CFM_FACE|CFM_CHARSET;
fmt->wWeight = lf->lfWeight;
fmt->yHeight = -lf->lfHeight*1440/ry;
if (lf->lfWeight>400) fmt->dwEffects |= CFM_BOLD;
if (lf->lfItalic) fmt->dwEffects |= CFM_ITALIC;
if (lf->lfUnderline) fmt->dwEffects |= CFM_UNDERLINE;
/* notice that if a logfont was created with underline due to CFM_LINK, this
would add an erronious CFM_UNDERLINE. This isn't currently ever a problem */
if (lf->lfStrikeOut) fmt->dwEffects |= CFM_STRIKEOUT;
fmt->bPitchAndFamily = lf->lfPitchAndFamily;
fmt->bCharSet = lf->lfCharSet;
}
BOOL ME_IsFontEqual(LOGFONTW *p1, LOGFONTW *p2)
static BOOL ME_IsFontEqual(LOGFONTW *p1, LOGFONTW *p2)
{
if (memcmp(p1, p2, sizeof(LOGFONTW)-sizeof(p1->lfFaceName)))
return FALSE;
@ -316,7 +338,7 @@ HFONT ME_SelectStyleFont(ME_TextEditor *editor, HDC hDC, ME_Style *s)
if (item->nAge > nAge)
nEmpty = i, nAge = item->nAge;
}
if (ME_IsFontEqual(&item->lfSpecs, &lf))
if (item->hFont && ME_IsFontEqual(&item->lfSpecs, &lf))
break;
}
if (i < HFONT_CACHE_SIZE) /* found */
@ -371,7 +393,7 @@ void ME_UnselectStyleFont(ME_TextEditor *editor, HDC hDC, ME_Style *s, HFONT hOl
assert(0 == "UnselectStyleFont without SelectStyleFont");
}
void ME_DestroyStyle(ME_Style *s) {
static void ME_DestroyStyle(ME_Style *s) {
if (s->hFont)
{
DeleteObject(s->hFont);

View file

@ -0,0 +1,393 @@
/*
* RichEdit - functions and interfaces around CreateTextServices
*
* Copyright 2005, 2006, Maarten Lankhorst
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#define NONAMELESSSTRUCT
#define NONAMELESSUNION
#define COBJMACROS
#include "editor.h"
#include "ole2.h"
#include "richole.h"
#include "winreg.h"
#include "imm.h"
#include "textserv.h"
#include "wine/debug.h"
#include "editstr.h"
#ifdef __i386__ /* thiscall functions are i386-specific */
#define THISCALL(func) __thiscall_ ## func
#define DEFINE_THISCALL_WRAPPER(func) \
extern typeof(func) THISCALL(func); \
__ASM_GLOBAL_FUNC(__thiscall_ ## func, \
"popl %eax\n\t" \
"pushl %ecx\n\t" \
"pushl %eax\n\t" \
"jmp " __ASM_NAME(#func) )
#else /* __i386__ */
#define THISCALL(func) func
#define DEFINE_THISCALL_WRAPPER(func) /* nothing */
#endif /* __i386__ */
WINE_DEFAULT_DEBUG_CHANNEL(richedit);
typedef struct ITextServicesImpl {
const ITextServicesVtbl *lpVtbl;
ITextHost *pMyHost;
LONG ref;
CRITICAL_SECTION csTxtSrv;
} ITextServicesImpl;
static const ITextServicesVtbl textservices_Vtbl;
/******************************************************************
* CreateTextServices (RICHED20.4)
*/
HRESULT WINAPI CreateTextServices(IUnknown * pUnkOuter,
ITextHost * pITextHost,
IUnknown **ppUnk)
{
ITextServicesImpl *ITextImpl;
TRACE("%p %p --> %p\n", pUnkOuter, pITextHost, ppUnk);
if (pITextHost == NULL)
return E_POINTER;
ITextImpl = CoTaskMemAlloc(sizeof(*ITextImpl));
if (ITextImpl == NULL)
return E_OUTOFMEMORY;
InitializeCriticalSection(&ITextImpl->csTxtSrv);
ITextImpl->csTxtSrv.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ITextServicesImpl.csTxtSrv");
ITextImpl->ref = 1;
ITextHost_AddRef(pITextHost);
ITextImpl->pMyHost = pITextHost;
ITextImpl->lpVtbl = &textservices_Vtbl;
if (pUnkOuter)
{
FIXME("Support aggregation\n");
return CLASS_E_NOAGGREGATION;
}
*ppUnk = (IUnknown *)ITextImpl;
return S_OK;
}
#define ICOM_THIS_MULTI(impl,field,iface) \
impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
static HRESULT WINAPI fnTextSrv_QueryInterface(ITextServices * iface,
REFIID riid,
LPVOID * ppv)
{
ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppv);
*ppv = NULL;
if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_ITextServices))
*ppv = (LPVOID)This;
if (*ppv)
{
IUnknown_AddRef((IUnknown *)(*ppv));
TRACE ("-- Interface = %p\n", *ppv);
return S_OK;
}
FIXME("Unknown interface: %s\n", debugstr_guid(riid));
return E_NOINTERFACE;
}
static ULONG WINAPI fnTextSrv_AddRef(ITextServices *iface)
{
ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
DWORD ref = InterlockedIncrement(&This->ref);
TRACE("(%p/%p)->() AddRef from %d\n", This, iface, ref - 1);
return ref;
}
static ULONG WINAPI fnTextSrv_Release(ITextServices *iface)
{
ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
DWORD ref = InterlockedDecrement(&This->ref);
TRACE("(%p/%p)->() Release from %d\n", This, iface, ref + 1);
if (!ref)
{
ITextHost_Release(This->pMyHost);
This->csTxtSrv.DebugInfo->Spare[0] = 0;
DeleteCriticalSection(&This->csTxtSrv);
CoTaskMemFree(This);
}
return ref;
}
HRESULT WINAPI fnTextSrv_TxSendMessage(ITextServices *iface,
UINT msg,
WPARAM wparam,
LPARAM lparam,
LRESULT* plresult)
{
ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
FIXME("%p: STUB\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI fnTextSrv_TxDraw(ITextServices *iface,
DWORD dwDrawAspect,
LONG lindex,
void* pvAspect,
DVTARGETDEVICE* ptd,
HDC hdcDraw,
HDC hdcTargetDev,
LPCRECTL lprcBounds,
LPCRECTL lprcWBounds,
LPRECT lprcUpdate,
BOOL (CALLBACK * pfnContinue)(DWORD),
DWORD dwContinue,
LONG lViewId)
{
ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
FIXME("%p: STUB\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI fnTextSrv_TxGetHScroll(ITextServices *iface,
LONG* plMin,
LONG* plMax,
LONG* plPos,
LONG* plPage,
BOOL* pfEnabled)
{
ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
FIXME("%p: STUB\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI fnTextSrv_TxGetVScroll(ITextServices *iface,
LONG* plMin,
LONG* plMax,
LONG* plPos,
LONG* plPage,
BOOL* pfEnabled)
{
ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
FIXME("%p: STUB\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI fnTextSrv_OnTxSetCursor(ITextServices *iface,
DWORD dwDrawAspect,
LONG lindex,
void* pvAspect,
DVTARGETDEVICE* ptd,
HDC hdcDraw,
HDC hicTargetDev,
LPCRECT lprcClient,
INT x, INT y)
{
ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
FIXME("%p: STUB\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI fnTextSrv_TxQueryHitPoint(ITextServices *iface,
DWORD dwDrawAspect,
LONG lindex,
void* pvAspect,
DVTARGETDEVICE* ptd,
HDC hdcDraw,
HDC hicTargetDev,
LPCRECT lprcClient,
INT x, INT y,
DWORD* pHitResult)
{
ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
FIXME("%p: STUB\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI fnTextSrv_OnTxInplaceActivate(ITextServices *iface,
LPCRECT prcClient)
{
ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
FIXME("%p: STUB\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI fnTextSrv_OnTxInplaceDeactivate(ITextServices *iface)
{
ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
FIXME("%p: STUB\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI fnTextSrv_OnTxUIActivate(ITextServices *iface)
{
ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
FIXME("%p: STUB\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI fnTextSrv_OnTxUIDeactivate(ITextServices *iface)
{
ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
FIXME("%p: STUB\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI fnTextSrv_TxGetText(ITextServices *iface,
BSTR* pbstrText)
{
ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
FIXME("%p: STUB\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI fnTextSrv_TxSetText(ITextServices *iface,
LPCWSTR pszText)
{
ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
FIXME("%p: STUB\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI fnTextSrv_TxGetCurrentTargetX(ITextServices *iface,
LONG* x)
{
ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
FIXME("%p: STUB\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI fnTextSrv_TxGetBaseLinePos(ITextServices *iface,
LONG* x)
{
ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
FIXME("%p: STUB\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI fnTextSrv_TxGetNaturalSize(ITextServices *iface,
DWORD dwAspect,
HDC hdcDraw,
HDC hicTargetDev,
DVTARGETDEVICE* ptd,
DWORD dwMode,
const SIZEL* psizelExtent,
LONG* pwidth,
LONG* pheight)
{
ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
FIXME("%p: STUB\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI fnTextSrv_TxGetDropTarget(ITextServices *iface,
IDropTarget** ppDropTarget)
{
ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
FIXME("%p: STUB\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI fnTextSrv_OnTxPropertyBitsChange(ITextServices *iface,
DWORD dwMask,
DWORD dwBits)
{
ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
FIXME("%p: STUB\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI fnTextSrv_TxGetCachedSize(ITextServices *iface,
DWORD* pdwWidth,
DWORD* pdwHeight)
{
ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
FIXME("%p: STUB\n", This);
return E_NOTIMPL;
}
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxSendMessage)
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxDraw)
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetHScroll)
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetVScroll)
DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxSetCursor)
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxQueryHitPoint)
DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxInplaceActivate)
DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxInplaceDeactivate)
DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxUIActivate)
DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxUIDeactivate)
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetText)
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxSetText)
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetCurrentTargetX)
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetBaseLinePos)
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetNaturalSize)
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetDropTarget)
DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxPropertyBitsChange)
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetCachedSize)
static const ITextServicesVtbl textservices_Vtbl =
{
fnTextSrv_QueryInterface,
fnTextSrv_AddRef,
fnTextSrv_Release,
THISCALL(fnTextSrv_TxSendMessage),
THISCALL(fnTextSrv_TxDraw),
THISCALL(fnTextSrv_TxGetHScroll),
THISCALL(fnTextSrv_TxGetVScroll),
THISCALL(fnTextSrv_OnTxSetCursor),
THISCALL(fnTextSrv_TxQueryHitPoint),
THISCALL(fnTextSrv_OnTxInplaceActivate),
THISCALL(fnTextSrv_OnTxInplaceDeactivate),
THISCALL(fnTextSrv_OnTxUIActivate),
THISCALL(fnTextSrv_OnTxUIDeactivate),
THISCALL(fnTextSrv_TxGetText),
THISCALL(fnTextSrv_TxSetText),
THISCALL(fnTextSrv_TxGetCurrentTargetX),
THISCALL(fnTextSrv_TxGetBaseLinePos),
THISCALL(fnTextSrv_TxGetNaturalSize),
THISCALL(fnTextSrv_TxGetDropTarget),
THISCALL(fnTextSrv_OnTxPropertyBitsChange),
THISCALL(fnTextSrv_TxGetCachedSize)
};

View file

@ -15,7 +15,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "editor.h"
@ -32,7 +32,8 @@ void ME_EmptyUndoStack(ME_TextEditor *editor)
TRACE("Emptying undo stack\n");
p = editor->pUndoStack;
editor->pUndoStack = NULL;
editor->pUndoStack = editor->pUndoStackBottom = NULL;
editor->nUndoStackSize = 0;
while(p) {
pNext = p->next;
ME_DestroyDisplayItem(p);
@ -50,6 +51,8 @@ void ME_EmptyUndoStack(ME_TextEditor *editor)
ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, ME_DisplayItem *pdi) {
if (editor->nUndoMode == umIgnore)
return NULL;
else if (editor->nUndoLimit == 0)
return NULL;
else
{
ME_DisplayItem *pItem = (ME_DisplayItem *)ALLOC_OBJ(ME_UndoItem);
@ -93,10 +96,31 @@ ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, ME_DisplayIte
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 (type == diUndoEndTransaction)
editor->nUndoStackSize++;
if (editor->pUndoStack)
editor->pUndoStack->prev = pItem;
else
editor->pUndoStackBottom = pItem;
editor->pUndoStack = pItem;
if (editor->nUndoStackSize > editor->nUndoLimit)
{ /* remove oldest undo from stack */
ME_DisplayItem *p = editor->pUndoStackBottom;
while (p->type !=diUndoEndTransaction)
p = p->prev; /*find new stack bottom */
editor->pUndoStackBottom = p->prev;
editor->pUndoStackBottom->next = NULL;
do
{
ME_DisplayItem *pp = p->next;
ME_DestroyDisplayItem(p);
p = pp;
} while (p);
editor->nUndoStackSize--;
}
/* any new operation (not redo) clears the redo stack */
if (editor->nUndoMode == umAddToUndo) {
ME_DisplayItem *p = editor->pRedoStack;
@ -124,7 +148,6 @@ ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, ME_DisplayIte
}
void ME_CommitUndo(ME_TextEditor *editor) {
if (editor->nUndoMode == umIgnore)
return;
@ -140,10 +163,9 @@ void ME_CommitUndo(ME_TextEditor *editor) {
ME_AddUndoItem(editor, diUndoEndTransaction, NULL);
ME_SendSelChange(editor);
editor->nModifyStep++;
}
void ME_PlayUndoItem(ME_TextEditor *editor, ME_DisplayItem *pItem)
static void ME_PlayUndoItem(ME_TextEditor *editor, ME_DisplayItem *pItem)
{
ME_UndoItem *pUItem = (ME_UndoItem *)pItem;
@ -233,10 +255,10 @@ void ME_Undo(ME_TextEditor *editor) {
} while(p && p->type != diUndoEndTransaction);
ME_AddUndoItem(editor, diUndoEndTransaction, NULL);
editor->pUndoStack = p;
editor->nUndoStackSize--;
if (p)
p->prev = NULL;
editor->nUndoMode = nMode;
editor->nModifyStep--;
ME_UpdateRepaint(editor);
}
@ -269,6 +291,5 @@ void ME_Redo(ME_TextEditor *editor) {
if (p)
p->prev = NULL;
editor->nUndoMode = nMode;
editor->nModifyStep++;
ME_UpdateRepaint(editor);
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2006 Mike McCormack
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define WINE_FILEDESCRIPTION_STR "Wine Richedit dll"
#define WINE_FILENAME_STR "riched20.dll"
#define WINE_FILEVERSION 5,30,23,1215
#define WINE_FILEVERSION_STR "5,30,23,1215"
#define WINE_PRODUCTVERSION 5,30,23,1215
#define WINE_PRODUCTVERSION_STR "5,30,23,1215"
#include "wine/wine_common_ver.rc"

View file

@ -16,7 +16,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
@ -168,7 +168,7 @@ static ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem
int i, idesp, len;
ME_Run *run = &p->member.run;
idesp = i = ME_CharFromPoint(wc->context->editor, loc, &ME_GetParagraph(p)->member.para, run);
idesp = i = ME_CharFromPoint(wc->context->editor, loc, run);
len = ME_StrVLen(run->strText);
assert(len>0);
assert(i<len);
@ -380,15 +380,17 @@ void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) {
void ME_PrepareParagraphForWrapping(ME_Context *c, ME_DisplayItem *tp) {
ME_DisplayItem *p;
ME_DisplayItem *p, *pRow;
/* remove all items that will be reinserted by paragraph wrapper anyway */
tp->member.para.nRows = 0;
for (p = tp->next; p!=tp->member.para.next_para; p = p->next) {
switch(p->type) {
case diStartRow:
pRow = p;
p = p->prev;
ME_Remove(p->next);
ME_Remove(pRow);
ME_DestroyDisplayItem(pRow);
break;
default:
break;
@ -422,6 +424,7 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
ME_DisplayItem *item;
ME_Context c;
BOOL bModified = FALSE;
int yStart = -1, yEnd = -1;
ME_InitContext(&c, editor, hDC);
c.pt.x = 0;
@ -439,11 +442,17 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
ME_WrapTextParagraph(&c, item);
if (bRedraw)
{
item->member.para.nFlags |= MEPF_REPAINT;
if (yStart == -1)
yStart = c.pt.y;
}
bModified = bModified | bRedraw;
c.pt.y += item->member.para.nHeight;
if (bRedraw)
yEnd = c.pt.y;
item = item->member.para.next_para;
}
editor->sizeWindow.cx = c.rcView.right-c.rcView.left;
@ -453,9 +462,42 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
ME_DestroyContext(&c);
ReleaseDC(hWnd, hDC);
if (bModified || editor->nTotalLength < editor->nLastTotalLength)
ME_InvalidateMarkedParagraphs(editor);
return bModified;
}
void ME_InvalidateMarkedParagraphs(ME_TextEditor *editor) {
ME_Context c;
HDC hDC = GetDC(editor->hWnd);
ME_InitContext(&c, editor, hDC);
if (editor->bRedraw)
{
RECT rc = c.rcView;
int ofs = ME_GetYScrollPos(editor);
ME_DisplayItem *item = editor->pBuffer->pFirst;
while(item != editor->pBuffer->pLast) {
if (item->member.para.nFlags & MEPF_REPAINT) {
rc.top = item->member.para.nYPos - ofs;
rc.bottom = item->member.para.nYPos + item->member.para.nHeight - ofs;
InvalidateRect(editor->hWnd, &rc, TRUE);
}
item = item->member.para.next_para;
}
if (editor->nTotalLength < editor->nLastTotalLength)
{
rc.top = editor->nTotalLength - ofs;
rc.bottom = editor->nLastTotalLength - ofs;
InvalidateRect(editor->hWnd, &rc, TRUE);
}
}
ME_DestroyContext(&c);
ReleaseDC(editor->hWnd, hDC);
}
void
ME_SendRequestResize(ME_TextEditor *editor, BOOL force)

View file

@ -15,7 +15,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "editor.h"
@ -25,71 +25,69 @@ WINE_DEFAULT_DEBUG_CHANNEL(richedit);
static BOOL
ME_StreamOutRTFText(ME_TextEditor *editor, WCHAR *text, LONG nChars);
ME_StreamOutRTFText(ME_OutStream *pStream, WCHAR *text, LONG nChars);
static void
static ME_OutStream*
ME_StreamOutInit(ME_TextEditor *editor, EDITSTREAM *stream)
{
editor->pStream = ALLOC_OBJ(ME_OutStream);
editor->pStream->stream = stream;
editor->pStream->stream->dwError = 0;
editor->pStream->pos = 0;
editor->pStream->written = 0;
editor->pStream->nFontTblLen = 0;
editor->pStream->nColorTblLen = 1;
ME_OutStream *pStream = ALLOC_OBJ(ME_OutStream);
pStream->stream = stream;
pStream->stream->dwError = 0;
pStream->pos = 0;
pStream->written = 0;
pStream->nFontTblLen = 0;
pStream->nColorTblLen = 1;
return pStream;
}
static BOOL
ME_StreamOutFlush(ME_TextEditor *editor)
ME_StreamOutFlush(ME_OutStream *pStream)
{
LONG nStart = 0;
LONG nWritten = 0;
LONG nRemaining = 0;
EDITSTREAM *stream = editor->pStream->stream;
EDITSTREAM *stream = pStream->stream;
do {
TRACE("sending %lu bytes\n", editor->pStream->pos - nStart);
TRACE("sending %u bytes\n", pStream->pos - nStart);
/* Some apps seem not to set *pcb unless a problem arises, relying
on initial random nWritten value, which is usually >STREAMOUT_BUFFER_SIZE */
nRemaining = editor->pStream->pos - nStart;
nRemaining = pStream->pos - nStart;
nWritten = 0xDEADBEEF;
stream->dwError = stream->pfnCallback(stream->dwCookie, (LPBYTE)editor->pStream->buffer + nStart,
editor->pStream->pos - nStart, &nWritten);
TRACE("error=%lu written=%lu\n", stream->dwError, nWritten);
if (nWritten > (editor->pStream->pos - nStart) || nWritten<0) {
FIXME("Invalid returned written size *pcb: 0x%x (%ld) instead of %ld\n",
stream->dwError = stream->pfnCallback(stream->dwCookie, (LPBYTE)pStream->buffer + nStart,
pStream->pos - nStart, &nWritten);
TRACE("error=%u written=%u\n", stream->dwError, nWritten);
if (nWritten > (pStream->pos - nStart) || nWritten<0) {
FIXME("Invalid returned written size *pcb: 0x%x (%d) instead of %d\n",
(unsigned)nWritten, nWritten, nRemaining);
nWritten = nRemaining;
}
if (nWritten == 0 || stream->dwError)
return FALSE;
editor->pStream->written += nWritten;
pStream->written += nWritten;
nStart += nWritten;
} while (nStart < editor->pStream->pos);
editor->pStream->pos = 0;
} while (nStart < pStream->pos);
pStream->pos = 0;
return TRUE;
}
static LONG
ME_StreamOutFree(ME_TextEditor *editor)
ME_StreamOutFree(ME_OutStream *pStream)
{
LONG written = editor->pStream->written;
TRACE("total length = %lu\n", written);
LONG written = pStream->written;
TRACE("total length = %u\n", written);
FREE_OBJ(editor->pStream);
editor->pStream = NULL;
FREE_OBJ(pStream);
return written;
}
static BOOL
ME_StreamOutMove(ME_TextEditor *editor, const char *buffer, int len)
ME_StreamOutMove(ME_OutStream *pStream, const char *buffer, int len)
{
ME_OutStream *pStream = editor->pStream;
while (len) {
int space = STREAMOUT_BUFFER_SIZE - pStream->pos;
int fit = min(space, len);
@ -100,7 +98,7 @@ ME_StreamOutMove(ME_TextEditor *editor, const char *buffer, int len)
buffer += fit;
pStream->pos += fit;
if (pStream->pos == STREAMOUT_BUFFER_SIZE) {
if (!ME_StreamOutFlush(editor))
if (!ME_StreamOutFlush(pStream))
return FALSE;
}
}
@ -109,22 +107,22 @@ ME_StreamOutMove(ME_TextEditor *editor, const char *buffer, int len)
static BOOL
ME_StreamOutPrint(ME_TextEditor *editor, const char *format, ...)
ME_StreamOutPrint(ME_OutStream *pStream, const char *format, ...)
{
char string[STREAMOUT_BUFFER_SIZE]; /* This is going to be enough */
int len;
va_list valist;
va_start(valist, format);
len = _vsnprintf(string, sizeof(string), format, valist);
len = vsnprintf(string, sizeof(string), format, valist);
va_end(valist);
return ME_StreamOutMove(editor, string, len);
return ME_StreamOutMove(pStream, string, len);
}
static BOOL
ME_StreamOutRTFHeader(ME_TextEditor *editor, int dwFormat)
ME_StreamOutRTFHeader(ME_OutStream *pStream, int dwFormat)
{
const char *cCharSet = NULL;
UINT nCodePage;
@ -171,33 +169,33 @@ ME_StreamOutRTFHeader(ME_TextEditor *editor, int dwFormat)
nCodePage = GetACP();
}
if (nCodePage == CP_UTF8)
success = ME_StreamOutPrint(editor, "{\\urtf");
success = ME_StreamOutPrint(pStream, "{\\urtf");
else
success = ME_StreamOutPrint(editor, "{\\rtf1\\%s\\ansicpg%u\\uc1", cCharSet, nCodePage);
success = ME_StreamOutPrint(pStream, "{\\rtf1\\%s\\ansicpg%u\\uc1", cCharSet, nCodePage);
if (!success)
return FALSE;
editor->pStream->nDefaultCodePage = nCodePage;
pStream->nDefaultCodePage = nCodePage;
/* FIXME: This should be a document property */
/* TODO: handle SFF_PLAINRTF */
language = GetUserDefaultLangID();
if (!ME_StreamOutPrint(editor, "\\deff0\\deflang%u\\deflangfe%u", language, language))
if (!ME_StreamOutPrint(pStream, "\\deff0\\deflang%u\\deflangfe%u", language, language))
return FALSE;
/* FIXME: This should be a document property */
editor->pStream->nDefaultFont = 0;
pStream->nDefaultFont = 0;
return TRUE;
}
static BOOL
ME_StreamOutRTFFontAndColorTbl(ME_TextEditor *editor, ME_DisplayItem *pFirstRun, ME_DisplayItem *pLastRun)
ME_StreamOutRTFFontAndColorTbl(ME_OutStream *pStream, ME_DisplayItem *pFirstRun, ME_DisplayItem *pLastRun)
{
ME_DisplayItem *item = pFirstRun;
ME_FontTableItem *table = editor->pStream->fonttbl;
ME_FontTableItem *table = pStream->fonttbl;
int i;
do {
@ -208,35 +206,35 @@ ME_StreamOutRTFFontAndColorTbl(ME_TextEditor *editor, ME_DisplayItem *pFirstRun,
WCHAR *face = fmt->szFaceName;
BYTE bCharSet = (fmt->dwMask & CFM_CHARSET) ? fmt->bCharSet : DEFAULT_CHARSET;
for (i = 0; i < editor->pStream->nFontTblLen; i++)
for (i = 0; i < pStream->nFontTblLen; i++)
if (table[i].bCharSet == bCharSet
&& (table[i].szFaceName == face || !lstrcmpW(table[i].szFaceName, face)))
break;
if (i == editor->pStream->nFontTblLen) {
if (i == pStream->nFontTblLen) {
table[i].bCharSet = bCharSet;
table[i].szFaceName = face;
editor->pStream->nFontTblLen++;
pStream->nFontTblLen++;
}
}
if (fmt->dwMask & CFM_COLOR && !(fmt->dwEffects & CFE_AUTOCOLOR)) {
crColor = fmt->crTextColor;
for (i = 1; i < editor->pStream->nColorTblLen; i++)
if (editor->pStream->colortbl[i] == crColor)
for (i = 1; i < pStream->nColorTblLen; i++)
if (pStream->colortbl[i] == crColor)
break;
if (i == editor->pStream->nColorTblLen) {
editor->pStream->colortbl[i] = crColor;
editor->pStream->nColorTblLen++;
if (i == pStream->nColorTblLen) {
pStream->colortbl[i] = crColor;
pStream->nColorTblLen++;
}
}
if (fmt->dwMask & CFM_BACKCOLOR && !(fmt->dwEffects & CFE_AUTOBACKCOLOR)) {
crColor = fmt->crBackColor;
for (i = 1; i < editor->pStream->nColorTblLen; i++)
if (editor->pStream->colortbl[i] == crColor)
for (i = 1; i < pStream->nColorTblLen; i++)
if (pStream->colortbl[i] == crColor)
break;
if (i == editor->pStream->nColorTblLen) {
editor->pStream->colortbl[i] = crColor;
editor->pStream->nColorTblLen++;
if (i == pStream->nColorTblLen) {
pStream->colortbl[i] = crColor;
pStream->nColorTblLen++;
}
}
@ -245,37 +243,37 @@ ME_StreamOutRTFFontAndColorTbl(ME_TextEditor *editor, ME_DisplayItem *pFirstRun,
item = ME_FindItemFwd(item, diRun);
} while (item);
if (!ME_StreamOutPrint(editor, "{\\fonttbl"))
if (!ME_StreamOutPrint(pStream, "{\\fonttbl"))
return FALSE;
for (i = 0; i < editor->pStream->nFontTblLen; i++) {
for (i = 0; i < pStream->nFontTblLen; i++) {
if (table[i].bCharSet != DEFAULT_CHARSET) {
if (!ME_StreamOutPrint(editor, "{\\f%u\\fcharset%u ", i, table[i].bCharSet))
if (!ME_StreamOutPrint(pStream, "{\\f%u\\fcharset%u ", i, table[i].bCharSet))
return FALSE;
} else {
if (!ME_StreamOutPrint(editor, "{\\f%u ", i))
if (!ME_StreamOutPrint(pStream, "{\\f%u ", i))
return FALSE;
}
if (!ME_StreamOutRTFText(editor, table[i].szFaceName, -1))
if (!ME_StreamOutRTFText(pStream, table[i].szFaceName, -1))
return FALSE;
if (!ME_StreamOutPrint(editor, ";}\r\n"))
if (!ME_StreamOutPrint(pStream, ";}\r\n"))
return FALSE;
}
if (!ME_StreamOutPrint(editor, "}"))
if (!ME_StreamOutPrint(pStream, "}"))
return FALSE;
/* Output colors table if not empty */
if (editor->pStream->nColorTblLen > 1) {
if (!ME_StreamOutPrint(editor, "{\\colortbl;"))
if (pStream->nColorTblLen > 1) {
if (!ME_StreamOutPrint(pStream, "{\\colortbl;"))
return FALSE;
for (i = 1; i < editor->pStream->nColorTblLen; i++) {
if (!ME_StreamOutPrint(editor, "\\red%u\\green%u\\blue%u;",
editor->pStream->colortbl[i] & 0xFF,
(editor->pStream->colortbl[i] >> 8) & 0xFF,
(editor->pStream->colortbl[i] >> 16) & 0xFF))
for (i = 1; i < pStream->nColorTblLen; i++) {
if (!ME_StreamOutPrint(pStream, "\\red%u\\green%u\\blue%u;",
pStream->colortbl[i] & 0xFF,
(pStream->colortbl[i] >> 8) & 0xFF,
(pStream->colortbl[i] >> 16) & 0xFF))
return FALSE;
}
if (!ME_StreamOutPrint(editor, "}"))
if (!ME_StreamOutPrint(pStream, "}"))
return FALSE;
}
@ -284,15 +282,33 @@ ME_StreamOutRTFFontAndColorTbl(ME_TextEditor *editor, ME_DisplayItem *pFirstRun,
static BOOL
ME_StreamOutRTFParaProps(ME_TextEditor *editor, ME_DisplayItem *para)
ME_StreamOutRTFParaProps(ME_OutStream *pStream, ME_DisplayItem *para)
{
PARAFORMAT2 *fmt = para->member.para.pFmt;
char props[STREAMOUT_BUFFER_SIZE] = "";
int i;
if (para->member.para.pCells)
{
ME_TableCell *cell = para->member.para.pCells;
if (!ME_StreamOutPrint(pStream, "\\trowd"))
return FALSE;
do {
sprintf(props, "\\cellx%d", cell->nRightBoundary);
if (!ME_StreamOutPrint(pStream, props))
return FALSE;
cell = cell->next;
} while (cell);
props[0] = '\0';
}
/* TODO: Don't emit anything if the last PARAFORMAT2 is inherited */
if (!ME_StreamOutPrint(editor, "\\pard"))
if (!ME_StreamOutPrint(pStream, "\\pard"))
return FALSE;
if (para->member.para.bTable)
strcat(props, "\\intbl");
/* TODO: PFM_BORDER. M$ does not emit any keywords for these properties, and
* when streaming border keywords in, PFM_BORDER is set, but wBorder field is
@ -330,13 +346,13 @@ ME_StreamOutRTFParaProps(ME_TextEditor *editor, ME_DisplayItem *para)
strcat(props, "\\sl-480\\slmult1");
break;
case 3:
sprintf(props + strlen(props), "\\sl%ld\\slmult0", fmt->dyLineSpacing);
sprintf(props + strlen(props), "\\sl%d\\slmult0", fmt->dyLineSpacing);
break;
case 4:
sprintf(props + strlen(props), "\\sl-%ld\\slmult0", fmt->dyLineSpacing);
sprintf(props + strlen(props), "\\sl-%d\\slmult0", fmt->dyLineSpacing);
break;
case 5:
sprintf(props + strlen(props), "\\sl-%ld\\slmult1", fmt->dyLineSpacing * 240 / 20);
sprintf(props + strlen(props), "\\sl-%d\\slmult1", fmt->dyLineSpacing * 240 / 20);
break;
}
}
@ -361,20 +377,20 @@ ME_StreamOutRTFParaProps(ME_TextEditor *editor, ME_DisplayItem *para)
strcat(props, "\\intbl");
if (fmt->dwMask & PFM_OFFSET)
sprintf(props + strlen(props), "\\li%ld", fmt->dxOffset);
sprintf(props + strlen(props), "\\li%d", fmt->dxOffset);
if (fmt->dwMask & PFM_OFFSETINDENT || fmt->dwMask & PFM_STARTINDENT)
sprintf(props + strlen(props), "\\fi%ld", fmt->dxStartIndent);
sprintf(props + strlen(props), "\\fi%d", fmt->dxStartIndent);
if (fmt->dwMask & PFM_RIGHTINDENT)
sprintf(props + strlen(props), "\\ri%ld", fmt->dxRightIndent);
sprintf(props + strlen(props), "\\ri%d", fmt->dxRightIndent);
if (fmt->dwMask & PFM_SPACEAFTER)
sprintf(props + strlen(props), "\\sa%ld", fmt->dySpaceAfter);
sprintf(props + strlen(props), "\\sa%d", fmt->dySpaceAfter);
if (fmt->dwMask & PFM_SPACEBEFORE)
sprintf(props + strlen(props), "\\sb%ld", fmt->dySpaceBefore);
sprintf(props + strlen(props), "\\sb%d", fmt->dySpaceBefore);
if (fmt->dwMask & PFM_STYLE)
sprintf(props + strlen(props), "\\s%d", fmt->sStyle);
if (fmt->dwMask & PFM_TABSTOPS) {
static const char *leader[6] = { "", "\\tldot", "\\tlhyph", "\\tlul", "\\tlth", "\\tleq" };
static const char * const leader[6] = { "", "\\tldot", "\\tlhyph", "\\tlul", "\\tlth", "\\tleq" };
for (i = 0; i < fmt->cTabCount; i++) {
switch ((fmt->rgxTabs[i] >> 24) & 0xF) {
@ -393,13 +409,13 @@ ME_StreamOutRTFParaProps(ME_TextEditor *editor, ME_DisplayItem *para)
}
if (fmt->rgxTabs[i] >> 28 <= 5)
strcat(props, leader[fmt->rgxTabs[i] >> 28]);
sprintf(props+strlen(props), "\\tx%ld", fmt->rgxTabs[i]&0x00FFFFFF);
sprintf(props+strlen(props), "\\tx%d", fmt->rgxTabs[i]&0x00FFFFFF);
}
}
if (fmt->dwMask & PFM_SHADING) {
static const char *style[16] = { "", "\\bgdkhoriz", "\\bgdkvert", "\\bgdkfdiag",
static const char * const style[16] = { "", "\\bgdkhoriz", "\\bgdkvert", "\\bgdkfdiag",
"\\bgdkbdiag", "\\bgdkcross", "\\bgdkdcross",
"\\bghoriz", "\\bgvert", "\\bgfdiag",
"\\bgbdiag", "\\bgcross", "\\bgdcross",
@ -412,7 +428,7 @@ ME_StreamOutRTFParaProps(ME_TextEditor *editor, ME_DisplayItem *para)
(fmt->wShadingStyle >> 4) & 0xF, (fmt->wShadingStyle >> 8) & 0xF);
}
if (*props && !ME_StreamOutPrint(editor, props))
if (*props && !ME_StreamOutPrint(pStream, props))
return FALSE;
return TRUE;
@ -420,7 +436,7 @@ ME_StreamOutRTFParaProps(ME_TextEditor *editor, ME_DisplayItem *para)
static BOOL
ME_StreamOutRTFCharProps(ME_TextEditor *editor, CHARFORMAT2W *fmt)
ME_StreamOutRTFCharProps(ME_OutStream *pStream, CHARFORMAT2W *fmt)
{
char props[STREAMOUT_BUFFER_SIZE] = "";
int i;
@ -431,8 +447,8 @@ ME_StreamOutRTFCharProps(ME_TextEditor *editor, CHARFORMAT2W *fmt)
sprintf(props + strlen(props), "\\animtext%u", fmt->bAnimation);
if (fmt->dwMask & CFM_BACKCOLOR) {
if (!(fmt->dwEffects & CFE_AUTOBACKCOLOR)) {
for (i = 1; i < editor->pStream->nColorTblLen; i++)
if (editor->pStream->colortbl[i] == fmt->crBackColor) {
for (i = 1; i < pStream->nColorTblLen; i++)
if (pStream->colortbl[i] == fmt->crBackColor) {
sprintf(props + strlen(props), "\\cb%u", i);
break;
}
@ -442,8 +458,8 @@ ME_StreamOutRTFCharProps(ME_TextEditor *editor, CHARFORMAT2W *fmt)
strcat(props, "\\b");
if (fmt->dwMask & CFM_COLOR) {
if (!(fmt->dwEffects & CFE_AUTOCOLOR)) {
for (i = 1; i < editor->pStream->nColorTblLen; i++)
if (editor->pStream->colortbl[i] == fmt->crTextColor) {
for (i = 1; i < pStream->nColorTblLen; i++)
if (pStream->colortbl[i] == fmt->crTextColor) {
sprintf(props + strlen(props), "\\cf%u", i);
break;
}
@ -470,9 +486,9 @@ ME_StreamOutRTFCharProps(ME_TextEditor *editor, CHARFORMAT2W *fmt)
/* CFM_LINK is not streamed out by M$ */
if (fmt->dwMask & CFM_OFFSET) {
if (fmt->yOffset >= 0)
sprintf(props + strlen(props), "\\up%ld", fmt->yOffset);
sprintf(props + strlen(props), "\\up%d", fmt->yOffset);
else
sprintf(props + strlen(props), "\\dn%ld", -fmt->yOffset);
sprintf(props + strlen(props), "\\dn%d", -fmt->yOffset);
}
if (fmt->dwMask & CFM_OUTLINE && fmt->dwEffects & CFE_OUTLINE)
strcat(props, "\\outl");
@ -482,7 +498,7 @@ ME_StreamOutRTFCharProps(ME_TextEditor *editor, CHARFORMAT2W *fmt)
if (fmt->dwMask & CFM_SHADOW && fmt->dwEffects & CFE_SHADOW)
strcat(props, "\\shad");
if (fmt->dwMask & CFM_SIZE)
sprintf(props + strlen(props), "\\fs%ld", fmt->yHeight / 10);
sprintf(props + strlen(props), "\\fs%d", fmt->yHeight / 10);
if (fmt->dwMask & CFM_SMALLCAPS && fmt->dwEffects & CFE_SMALLCAPS)
strcat(props, "\\scaps");
if (fmt->dwMask & CFM_SPACING)
@ -531,40 +547,39 @@ ME_StreamOutRTFCharProps(ME_TextEditor *editor, CHARFORMAT2W *fmt)
if (fmt->dwMask & CFM_FACE)
szFaceName = fmt->szFaceName;
else
szFaceName = editor->pStream->fonttbl[0].szFaceName;
for (i = 0; i < editor->pStream->nFontTblLen; i++) {
if (szFaceName == editor->pStream->fonttbl[i].szFaceName
|| !lstrcmpW(szFaceName, editor->pStream->fonttbl[i].szFaceName))
szFaceName = pStream->fonttbl[0].szFaceName;
for (i = 0; i < pStream->nFontTblLen; i++) {
if (szFaceName == pStream->fonttbl[i].szFaceName
|| !lstrcmpW(szFaceName, pStream->fonttbl[i].szFaceName))
if (!(fmt->dwMask & CFM_CHARSET)
|| fmt->bCharSet == editor->pStream->fonttbl[i].bCharSet)
|| fmt->bCharSet == pStream->fonttbl[i].bCharSet)
break;
}
if (i < editor->pStream->nFontTblLen)
if (i < pStream->nFontTblLen)
{
if (i != editor->pStream->nDefaultFont)
if (i != pStream->nDefaultFont)
sprintf(props + strlen(props), "\\f%u", i);
/* In UTF-8 mode, charsets/codepages are not used */
if (editor->pStream->nDefaultCodePage != CP_UTF8)
if (pStream->nDefaultCodePage != CP_UTF8)
{
if (editor->pStream->fonttbl[i].bCharSet == DEFAULT_CHARSET)
editor->pStream->nCodePage = editor->pStream->nDefaultCodePage;
if (pStream->fonttbl[i].bCharSet == DEFAULT_CHARSET)
pStream->nCodePage = pStream->nDefaultCodePage;
else
editor->pStream->nCodePage = RTFCharSetToCodePage(NULL,
editor->pStream->fonttbl[i].bCharSet);
pStream->nCodePage = RTFCharSetToCodePage(NULL, pStream->fonttbl[i].bCharSet);
}
}
}
if (*props)
strcat(props, " ");
if (!ME_StreamOutPrint(editor, props))
if (!ME_StreamOutPrint(pStream, props))
return FALSE;
return TRUE;
}
static BOOL
ME_StreamOutRTFText(ME_TextEditor *editor, WCHAR *text, LONG nChars)
ME_StreamOutRTFText(ME_OutStream *pStream, WCHAR *text, LONG nChars)
{
char buffer[STREAMOUT_BUFFER_SIZE];
int pos = 0;
@ -575,7 +590,7 @@ ME_StreamOutRTFText(ME_TextEditor *editor, WCHAR *text, LONG nChars)
while (nChars) {
/* In UTF-8 mode, font charsets are not used. */
if (editor->pStream->nDefaultCodePage == CP_UTF8) {
if (pStream->nDefaultCodePage == CP_UTF8) {
/* 6 is the maximum character length in UTF-8 */
fit = min(nChars, STREAMOUT_BUFFER_SIZE / 6);
nBytes = WideCharToMultiByte(CP_UTF8, 0, text, fit, buffer,
@ -584,12 +599,12 @@ ME_StreamOutRTFText(ME_TextEditor *editor, WCHAR *text, LONG nChars)
text += fit;
for (i = 0; i < nBytes; i++)
if (buffer[i] == '{' || buffer[i] == '}' || buffer[i] == '\\') {
if (!ME_StreamOutPrint(editor, "%.*s\\", i - pos, buffer + pos))
if (!ME_StreamOutPrint(pStream, "%.*s\\", i - pos, buffer + pos))
return FALSE;
pos = i;
}
if (pos < nBytes)
if (!ME_StreamOutMove(editor, buffer + pos, nBytes - pos))
if (!ME_StreamOutMove(pStream, buffer + pos, nBytes - pos))
return FALSE;
pos = 0;
} else if (*text < 128) {
@ -605,9 +620,9 @@ ME_StreamOutRTFText(ME_TextEditor *editor, WCHAR *text, LONG nChars)
* codepages including CP_SYMBOL for which the last parameter must be set
* to NULL for the function to succeed. But in Wine we need to care only
* about CP_SYMBOL */
nBytes = WideCharToMultiByte(editor->pStream->nCodePage, 0, text, 1,
nBytes = WideCharToMultiByte(pStream->nCodePage, 0, text, 1,
letter, 3, NULL,
(editor->pStream->nCodePage == CP_SYMBOL) ? NULL : &unknown);
(pStream->nCodePage == CP_SYMBOL) ? NULL : &unknown);
if (unknown)
pos += sprintf(buffer + pos, "\\u%d?", (short)*text);
else if ((BYTE)*letter < 128) {
@ -622,33 +637,36 @@ ME_StreamOutRTFText(ME_TextEditor *editor, WCHAR *text, LONG nChars)
nChars--;
}
if (pos >= STREAMOUT_BUFFER_SIZE - 11) {
if (!ME_StreamOutMove(editor, buffer, pos))
if (!ME_StreamOutMove(pStream, buffer, pos))
return FALSE;
pos = 0;
}
}
return ME_StreamOutMove(editor, buffer, pos);
return ME_StreamOutMove(pStream, buffer, pos);
}
static BOOL
ME_StreamOutRTF(ME_TextEditor *editor, int nStart, int nChars, int dwFormat)
ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream, int nStart, int nChars, int dwFormat)
{
ME_DisplayItem *p, *pEnd;
int nOffset, nEndLen;
ME_DisplayItem *p, *pEnd, *pPara;
int nOffset, nEndLen;
ME_RunOfsFromCharOfs(editor, nStart, &p, &nOffset);
ME_RunOfsFromCharOfs(editor, nStart+nChars, &pEnd, &nEndLen);
if (!ME_StreamOutRTFHeader(editor, dwFormat))
pPara = ME_GetParagraph(p);
if (!ME_StreamOutRTFHeader(pStream, dwFormat))
return FALSE;
if (!ME_StreamOutRTFFontAndColorTbl(editor, p, pEnd))
if (!ME_StreamOutRTFFontAndColorTbl(pStream, p, pEnd))
return FALSE;
/* TODO: stylesheet table */
/* FIXME: maybe emit something smarter for the generator? */
if (!ME_StreamOutPrint(editor, "{\\*\\generator Wine Riched20 2.0.????;}"))
if (!ME_StreamOutPrint(pStream, "{\\*\\generator Wine Riched20 2.0.????;}"))
return FALSE;
/* TODO: information group */
@ -659,7 +677,7 @@ ME_StreamOutRTF(ME_TextEditor *editor, int nStart, int nChars, int dwFormat)
/* TODO: section formatting properties */
if (!ME_StreamOutRTFParaProps(editor, ME_GetParagraph(p)))
if (!ME_StreamOutRTFParaProps(pStream, ME_GetParagraph(p)))
return FALSE;
while(1)
@ -667,8 +685,9 @@ ME_StreamOutRTF(ME_TextEditor *editor, int nStart, int nChars, int dwFormat)
switch(p->type)
{
case diParagraph:
if (!ME_StreamOutRTFParaProps(editor, p))
if (!ME_StreamOutRTFParaProps(pStream, p))
return FALSE;
pPara = p;
break;
case diRun:
if (p == pEnd && !nEndLen)
@ -677,26 +696,35 @@ ME_StreamOutRTF(ME_TextEditor *editor, int nStart, int nChars, int dwFormat)
/* TODO: emit embedded objects */
if (p->member.run.nFlags & MERF_GRAPHICS)
FIXME("embedded objects are not handled\n");
if (p->member.run.nFlags & MERF_ENDPARA) {
if (!ME_StreamOutPrint(editor, "\r\n\\par"))
if (p->member.run.nFlags & MERF_CELL) {
if (!ME_StreamOutPrint(pStream, "\\cell "))
return FALSE;
nChars--;
} else if (p->member.run.nFlags & MERF_ENDPARA) {
if (pPara->member.para.bTable) {
if (!ME_StreamOutPrint(pStream, "\\row \r\n"))
return FALSE;
} else {
if (!ME_StreamOutPrint(pStream, "\r\n\\par"))
return FALSE;
}
nChars--;
if (editor->bEmulateVersion10 && nChars)
nChars--;
} else {
int nEnd;
if (!ME_StreamOutPrint(editor, "{"))
if (!ME_StreamOutPrint(pStream, "{"))
return FALSE;
TRACE("style %p\n", p->member.run.style);
if (!ME_StreamOutRTFCharProps(editor, &p->member.run.style->fmt))
if (!ME_StreamOutRTFCharProps(pStream, &p->member.run.style->fmt))
return FALSE;
nEnd = (p == pEnd) ? nEndLen : ME_StrLen(p->member.run.strText);
if (!ME_StreamOutRTFText(editor, p->member.run.strText->szData + nOffset, nEnd - nOffset))
if (!ME_StreamOutRTFText(pStream, p->member.run.strText->szData + nOffset, nEnd - nOffset))
return FALSE;
nOffset = 0;
if (!ME_StreamOutPrint(editor, "}"))
if (!ME_StreamOutPrint(pStream, "}"))
return FALSE;
}
break;
@ -707,14 +735,14 @@ ME_StreamOutRTF(ME_TextEditor *editor, int nStart, int nChars, int dwFormat)
break;
p = ME_FindItemFwd(p, diRunOrParagraphOrEnd);
}
if (!ME_StreamOutPrint(editor, "}"))
if (!ME_StreamOutPrint(pStream, "}"))
return FALSE;
return TRUE;
}
static BOOL
ME_StreamOutText(ME_TextEditor *editor, int nStart, int nChars, DWORD dwFormat)
ME_StreamOutText(ME_TextEditor *editor, ME_OutStream *pStream, int nStart, int nChars, DWORD dwFormat)
{
/* FIXME: use ME_RunOfsFromCharOfs */
ME_DisplayItem *item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart);
@ -741,12 +769,12 @@ ME_StreamOutText(ME_TextEditor *editor, int nStart, int nChars, DWORD dwFormat)
static const WCHAR szEOL[2] = { '\r', '\n' };
if (dwFormat & SF_UNICODE)
success = ME_StreamOutMove(editor, (const char *)szEOL, sizeof(szEOL));
success = ME_StreamOutMove(pStream, (const char *)szEOL, sizeof(szEOL));
else
success = ME_StreamOutMove(editor, "\r\n", 2);
success = ME_StreamOutMove(pStream, "\r\n", 2);
} else {
if (dwFormat & SF_UNICODE)
success = ME_StreamOutMove(editor, (const char *)(item->member.run.strText->szData + nStart),
success = ME_StreamOutMove(pStream, (const char *)(item->member.run.strText->szData + nStart),
sizeof(WCHAR) * nLen);
else {
int nSize;
@ -754,14 +782,13 @@ ME_StreamOutText(ME_TextEditor *editor, int nStart, int nChars, DWORD dwFormat)
nSize = WideCharToMultiByte(nCodePage, 0, item->member.run.strText->szData + nStart,
nLen, NULL, 0, NULL, NULL);
if (nSize > nBufLen) {
if (buffer)
FREE_OBJ(buffer);
FREE_OBJ(buffer);
buffer = ALLOC_N_OBJ(char, nSize);
nBufLen = nSize;
}
WideCharToMultiByte(nCodePage, 0, item->member.run.strText->szData + nStart,
nLen, buffer, nSize, NULL, NULL);
success = ME_StreamOutMove(editor, buffer, nSize);
success = ME_StreamOutMove(pStream, buffer, nSize);
}
}
@ -772,25 +799,16 @@ ME_StreamOutText(ME_TextEditor *editor, int nStart, int nChars, DWORD dwFormat)
item = ME_FindItemFwd(item, diRun);
}
if (buffer)
FREE_OBJ(buffer);
FREE_OBJ(buffer);
return success;
}
LRESULT
ME_StreamOut(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM *stream)
ME_StreamOutRange(ME_TextEditor *editor, DWORD dwFormat, int nStart, int nTo, EDITSTREAM *stream)
{
int nStart, nTo;
ME_StreamOutInit(editor, stream);
ME_OutStream *pStream = ME_StreamOutInit(editor, stream);
if (dwFormat & SFF_SELECTION)
ME_GetSelection(editor, &nStart, &nTo);
else {
nStart = 0;
nTo = -1;
}
if (nTo == -1)
{
nTo = ME_GetTextLength(editor);
@ -799,12 +817,26 @@ ME_StreamOut(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM *stream)
nTo++;
}
TRACE("from %d to %d\n", nStart, nTo);
if (dwFormat & SF_RTF)
ME_StreamOutRTF(editor, nStart, nTo - nStart, dwFormat);
ME_StreamOutRTF(editor, pStream, nStart, nTo - nStart, dwFormat);
else if (dwFormat & SF_TEXT || dwFormat & SF_TEXTIZED)
ME_StreamOutText(editor, nStart, nTo - nStart, dwFormat);
if (!editor->pStream->stream->dwError)
ME_StreamOutFlush(editor);
return ME_StreamOutFree(editor);
ME_StreamOutText(editor, pStream, nStart, nTo - nStart, dwFormat);
if (!pStream->stream->dwError)
ME_StreamOutFlush(pStream);
return ME_StreamOutFree(pStream);
}
LRESULT
ME_StreamOut(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM *stream)
{
int nStart, nTo;
if (dwFormat & SFF_SELECTION)
ME_GetSelection(editor, &nStart, &nTo);
else {
nStart = 0;
nTo = -1;
}
return ME_StreamOutRange(editor, dwFormat, nStart, nTo, stream);
}