[RICHED20]

* Sync with Wine 1.7.1.
CORE-7469

svn path=/trunk/; revision=60369
This commit is contained in:
Amine Khaldi 2013-09-26 16:32:14 +00:00
parent 16a2e9e6ce
commit bda34393bb
17 changed files with 1209 additions and 1204 deletions

View file

@ -1,7 +1,6 @@
add_definitions(-D__WINESRC__)
include_directories(${REACTOS_SOURCE_DIR}/include/reactos/wine)
spec2def(riched20.dll riched20.spec ADD_IMPORTLIB)
list(APPEND SOURCE
@ -24,7 +23,6 @@ list(APPEND SOURCE
undo.c
wrap.c
writer.c
version.rc
${CMAKE_CURRENT_BINARY_DIR}/riched20.def)
if(MSVC)
@ -34,19 +32,9 @@ if(MSVC)
set_source_files_properties(txthost.c txtsrv.c PROPERTIES COMPILE_FLAGS "/FImsvc.h")
endif()
add_library(riched20 SHARED ${SOURCE})
add_library(riched20 SHARED ${SOURCE} version.rc)
set_module_type(riched20 win32dll)
target_link_libraries(riched20 wine uuid)
add_importlibs(riched20
msvcrt
ole32
oleaut32
imm32
user32
gdi32
kernel32
ntdll)
add_importlibs(riched20 ole32 oleaut32 imm32 user32 gdi32 msvcrt kernel32 ntdll)
add_pch(riched20 editor.h)
add_cd_file(TARGET riched20 DESTINATION reactos/system32 FOR all)

View file

@ -205,7 +205,7 @@ ME_GetCursorCoordinates(ME_TextEditor *editor, ME_Cursor *pCursor,
ME_DisplayItem *para = pCursor->pPara;
ME_DisplayItem *pSizeRun = run;
ME_Context c;
SIZE sz = {0, 0};
int run_x;
assert(height && x && y);
assert(~para->member.para.nFlags & MEPF_REWRAP);
@ -235,18 +235,12 @@ ME_GetCursorCoordinates(ME_TextEditor *editor, ME_Cursor *pCursor,
pSizeRun = run = tmp;
assert(run);
assert(run->type == diRun);
sz = ME_GetRunSize(&c, &para->member.para,
&run->member.run, run->member.run.strText->nLen,
row->member.row.nLMargin);
}
}
if (pCursor->nOffset) {
sz = ME_GetRunSize(&c, &para->member.para, &run->member.run,
pCursor->nOffset, row->member.row.nLMargin);
}
run_x = ME_PointFromCharContext( &c, &run->member.run, pCursor->nOffset, TRUE );
*height = pSizeRun->member.run.nAscent + pSizeRun->member.run.nDescent;
*x = c.rcView.left + run->member.run.pt.x + sz.cx - editor->horz_si.nPos;
*x = c.rcView.left + run->member.run.pt.x + run_x - editor->horz_si.nPos;
*y = c.rcView.top + para->member.para.pt.y + row->member.row.nBaseline
+ run->member.run.pt.y - pSizeRun->member.run.nAscent
- editor->vert_si.nPos;
@ -317,11 +311,11 @@ BOOL ME_InternalDeleteText(ME_TextEditor *editor, ME_Cursor *start,
/* We aren't deleting anything in this run, so we will go back to the
* last run we are deleting text in. */
ME_PrevRun(&c.pPara, &c.pRun);
c.nOffset = c.pRun->member.run.strText->nLen;
c.nOffset = c.pRun->member.run.len;
}
run = &c.pRun->member.run;
if (run->nFlags & MERF_ENDPARA) {
int eollen = c.pRun->member.run.strText->nLen;
int eollen = c.pRun->member.run.len;
BOOL keepFirstParaFormat;
if (!ME_FindItemFwd(c.pRun, diParagraph))
@ -374,32 +368,18 @@ BOOL ME_InternalDeleteText(ME_TextEditor *editor, ME_Cursor *start,
nCharsToDelete is a number of chars to delete from THIS run */
nChars -= nCharsToDelete;
shift -= nCharsToDelete;
TRACE("Deleting %d (remaning %d) chars at %d in '%s' (%d)\n",
TRACE("Deleting %d (remaning %d) chars at %d in %s (%d)\n",
nCharsToDelete, nChars, c.nOffset,
debugstr_w(run->strText->szData), run->strText->nLen);
debugstr_run( run ), run->len);
if (!c.nOffset && run->strText->nLen == nCharsToDelete)
{
/* undo = reinsert whole run */
/* nOfs is a character offset (from the start of the document
to the current (deleted) run */
ME_UndoItem *pUndo = ME_AddUndoItem(editor, diUndoInsertRun, c.pRun);
if (pUndo)
pUndo->di.member.run.nCharOfs = nOfs+nChars;
}
else
{
/* undo = reinsert partial run */
ME_UndoItem *pUndo = ME_AddUndoItem(editor, diUndoInsertRun, c.pRun);
if (pUndo) {
ME_DestroyString(pUndo->di.member.run.strText);
pUndo->di.member.run.nCharOfs = nOfs+nChars;
pUndo->di.member.run.strText = ME_MakeStringN(run->strText->szData+c.nOffset, nCharsToDelete);
}
}
TRACE("Post deletion string: %s (%d)\n", debugstr_w(run->strText->szData), run->strText->nLen);
/* nOfs is a character offset (from the start of the document
to the current (deleted) run */
add_undo_insert_run( editor, nOfs + nChars, get_text( run, c.nOffset ), nCharsToDelete, run->nFlags, run->style );
ME_StrDeleteV(run->para->text, run->nCharOfs + c.nOffset, nCharsToDelete);
run->len -= nCharsToDelete;
TRACE("Post deletion string: %s (%d)\n", debugstr_run( run ), run->len);
TRACE("Shift value: %d\n", shift);
ME_StrDeleteV(run->strText, c.nOffset, nCharsToDelete);
/* update cursors (including c) */
for (i=-1; i<editor->nCursors; i++) {
@ -412,9 +392,9 @@ BOOL ME_InternalDeleteText(ME_TextEditor *editor, ME_Cursor *start,
else
pThisCur->nOffset -= nCharsToDelete;
assert(pThisCur->nOffset >= 0);
assert(pThisCur->nOffset <= run->strText->nLen);
assert(pThisCur->nOffset <= run->len);
}
if (pThisCur->nOffset == run->strText->nLen)
if (pThisCur->nOffset == run->len)
{
pThisCur->pRun = ME_FindItemFwd(pThisCur->pRun, diRunOrParagraphOrEnd);
assert(pThisCur->pRun->type == diRun);
@ -430,9 +410,9 @@ BOOL ME_InternalDeleteText(ME_TextEditor *editor, ME_Cursor *start,
else
ME_PropagateCharOffset(c.pRun, shift);
if (!cursor.pRun->member.run.strText->nLen)
if (!cursor.pRun->member.run.len)
{
TRACE("Removing useless run\n");
TRACE("Removing empty run\n");
ME_Remove(cursor.pRun);
ME_DestroyDisplayItem(cursor.pRun);
}
@ -572,13 +552,12 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
WCHAR space = ' ';
ME_InternalInsertTextFromCursor(editor, nCursor, &space, 1, style, 0);
} else {
ME_String *eol_str;
const WCHAR cr = '\r', *eol_str = str;
if (!editor->bEmulateVersion10) {
WCHAR cr = '\r';
eol_str = ME_MakeStringN(&cr, 1);
} else {
eol_str = ME_MakeStringN(str, eol_len);
if (!editor->bEmulateVersion10)
{
eol_str = &cr;
eol_len = 1;
}
p = &editor->pCursors[nCursor];
@ -586,7 +565,7 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
ME_SplitRunSimple(editor, p);
tmp_style = ME_GetInsertStyle(editor, nCursor);
/* ME_SplitParagraph increases style refcount */
tp = ME_SplitParagraph(editor, p->pRun, p->pRun->member.run.style, eol_str, 0);
tp = ME_SplitParagraph(editor, p->pRun, p->pRun->member.run.style, eol_str, eol_len, 0);
p->pRun = ME_FindItemFwd(tp, diRun);
p->pPara = tp;
end_run = ME_FindItemBack(tp, diRun);
@ -640,7 +619,7 @@ int ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs)
cursor->pRun = ME_FindItemBack(cursor->pRun, diRun);
}
cursor->nOffset -= cursor->pRun->member.run.nCharOfs;
} else if (cursor->nOffset >= cursor->pRun->member.run.strText->nLen) {
} else if (cursor->nOffset >= cursor->pRun->member.run.len) {
ME_DisplayItem *next_para;
int new_offset;
@ -650,9 +629,9 @@ int ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs)
{
/* new offset in the same paragraph */
do {
cursor->nOffset -= cursor->pRun->member.run.strText->nLen;
cursor->nOffset -= cursor->pRun->member.run.len;
cursor->pRun = ME_FindItemFwd(cursor->pRun, diRun);
} while (cursor->nOffset >= cursor->pRun->member.run.strText->nLen);
} while (cursor->nOffset >= cursor->pRun->member.run.len);
return nRelOfs;
}
@ -672,9 +651,9 @@ int ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs)
cursor->nOffset = new_offset - cursor->pPara->member.para.nCharOfs;
cursor->pRun = ME_FindItemFwd(cursor->pPara, diRun);
while (cursor->nOffset >= cursor->pRun->member.run.strText->nLen)
while (cursor->nOffset >= cursor->pRun->member.run.len)
{
cursor->nOffset -= cursor->pRun->member.run.strText->nLen;
cursor->nOffset -= cursor->pRun->member.run.len;
cursor->pRun = ME_FindItemFwd(cursor->pRun, diRun);
}
} /* else new offset is in the same run */
@ -694,23 +673,25 @@ ME_MoveCursorWords(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs)
/* Backward movement */
while (TRUE)
{
nOffset = ME_CallWordBreakProc(editor, pRun->member.run.strText,
nOffset, WB_MOVEWORDLEFT);
nOffset = ME_CallWordBreakProc(editor, get_text( &pRun->member.run, 0 ),
pRun->member.run.len, 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,
if (ME_CallWordBreakProc(editor, get_text( &pOtherRun->member.run, 0 ),
pOtherRun->member.run.len,
pOtherRun->member.run.len - 1,
WB_ISDELIMITER)
&& !(pRun->member.run.nFlags & MERF_ENDPARA)
&& !(cursor->pRun == pRun && cursor->nOffset == 0)
&& !ME_CallWordBreakProc(editor, pRun->member.run.strText, 0,
&& !ME_CallWordBreakProc(editor, get_text( &pRun->member.run, 0 ),
pRun->member.run.len, 0,
WB_ISDELIMITER))
break;
pRun = pOtherRun;
nOffset = pOtherRun->member.run.strText->nLen;
nOffset = pOtherRun->member.run.len;
}
else if (pOtherRun->type == diParagraph)
{
@ -738,18 +719,18 @@ ME_MoveCursorWords(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs)
while (TRUE)
{
if (last_delim && !ME_CallWordBreakProc(editor, pRun->member.run.strText,
nOffset, WB_ISDELIMITER))
if (last_delim && !ME_CallWordBreakProc(editor, get_text( &pRun->member.run, 0 ),
pRun->member.run.len, nOffset, WB_ISDELIMITER))
break;
nOffset = ME_CallWordBreakProc(editor, pRun->member.run.strText,
nOffset, WB_MOVEWORDRIGHT);
if (nOffset < pRun->member.run.strText->nLen)
nOffset = ME_CallWordBreakProc(editor, get_text( &pRun->member.run, 0 ),
pRun->member.run.len, nOffset, WB_MOVEWORDRIGHT);
if (nOffset < pRun->member.run.len)
break;
pOtherRun = ME_FindItemFwd(pRun, diRunOrParagraphOrEnd);
if (pOtherRun->type == diRun)
{
last_delim = ME_CallWordBreakProc(editor, pRun->member.run.strText,
nOffset - 1, WB_ISDELIMITER);
last_delim = ME_CallWordBreakProc(editor, get_text( &pRun->member.run, 0 ),
pRun->member.run.len, nOffset - 1, WB_ISDELIMITER);
pRun = pOtherRun;
nOffset = 0;
}
@ -884,22 +865,47 @@ static ME_DisplayItem* ME_FindPixelPosInTableRow(int x, int y,
return para;
}
static BOOL ME_ReturnFoundPos(ME_TextEditor *editor, ME_DisplayItem *found,
ME_Cursor *result, int rx, BOOL isExact)
static BOOL ME_FindRunInRow(ME_TextEditor *editor, ME_DisplayItem *pRow,
int x, ME_Cursor *cursor, int *pbCaretAtEnd)
{
assert(found);
assert(found->type == diRun);
if ((found->member.run.nFlags & MERF_ENDPARA) || rx < 0)
rx = 0;
result->pRun = found;
result->nOffset = ME_CharFromPointCursor(editor, rx, &found->member.run);
if (result->nOffset == found->member.run.strText->nLen && rx)
ME_DisplayItem *pNext, *pLastRun;
ME_Row *row = &pRow->member.row;
BOOL exact = TRUE;
if (x < row->pt.x)
{
result->pRun = ME_FindItemFwd(result->pRun, diRun);
result->nOffset = 0;
x = row->pt.x;
exact = FALSE;
}
result->pPara = ME_GetParagraph(result->pRun);
return isExact;
pNext = ME_FindItemFwd(pRow, diRunOrStartRow);
assert(pNext->type == diRun);
if (pbCaretAtEnd) *pbCaretAtEnd = FALSE;
cursor->nOffset = 0;
do {
int run_x = pNext->member.run.pt.x;
int width = pNext->member.run.nWidth;
if (x >= run_x && x < run_x+width)
{
cursor->nOffset = ME_CharFromPoint(editor, x-run_x, &pNext->member.run, TRUE, TRUE);
cursor->pRun = pNext;
cursor->pPara = ME_GetParagraph( cursor->pRun );
return exact;
}
pLastRun = pNext;
pNext = ME_FindItemFwd(pNext, diRunOrStartRow);
} while(pNext && pNext->type == diRun);
if ((pLastRun->member.run.nFlags & MERF_ENDPARA) == 0)
{
cursor->pRun = ME_FindItemFwd(pNext, diRun);
if (pbCaretAtEnd) *pbCaretAtEnd = TRUE;
}
else
cursor->pRun = pLastRun;
cursor->pPara = ME_GetParagraph( cursor->pRun );
return FALSE;
}
/* Finds the run and offset from the pixel position.
@ -914,8 +920,6 @@ static BOOL ME_FindPixelPos(ME_TextEditor *editor, int x, int y,
ME_Cursor *result, BOOL *is_eol)
{
ME_DisplayItem *p = editor->pBuffer->pFirst->member.para.next_para;
ME_DisplayItem *last = NULL;
int rx = 0;
BOOL isExact = TRUE;
x -= editor->rcFormat.left;
@ -944,17 +948,9 @@ static BOOL ME_FindPixelPos(ME_TextEditor *editor, int x, int y,
{
ME_DisplayItem *pp;
assert(p->type == diStartRow);
if (y < p->member.row.pt.y + p->member.row.nHeight)
{
p = ME_FindItemFwd(p, diRun);
break;
}
pp = ME_FindItemFwd(p, diStartRowOrParagraphOrEnd);
if (pp->type != diStartRow)
{
p = ME_FindItemFwd(p, diRun);
break;
}
if (y < p->member.row.pt.y + p->member.row.nHeight) break;
pp = ME_FindItemFwd(p, diStartRow);
if (!pp) break;
p = pp;
}
if (p == editor->pBuffer->pLast)
@ -964,40 +960,14 @@ static BOOL ME_FindPixelPos(ME_TextEditor *editor, int x, int y,
* determine the offset closest to the pixel position. */
isExact = FALSE;
p = ME_FindItemBack(p, diStartRow);
if (p != NULL){
p = ME_FindItemFwd(p, diRun);
}
else
{
p = editor->pBuffer->pLast;
}
}
for (; p != editor->pBuffer->pLast; p = p->next)
{
switch (p->type)
{
case diRun:
rx = x - p->member.run.pt.x;
if (rx < p->member.run.nWidth)
return ME_ReturnFoundPos(editor, p, result, rx, isExact);
break;
case diStartRow:
isExact = FALSE;
p = ME_FindItemFwd(p, diRun);
if (is_eol) *is_eol = 1;
rx = 0; /* FIXME not sure */
return ME_ReturnFoundPos(editor, p, result, rx, isExact);
case diCell:
case diParagraph:
case diTextEnd:
isExact = FALSE;
rx = 0; /* FIXME not sure */
p = last;
return ME_ReturnFoundPos(editor, p, result, rx, isExact);
default: assert(0);
}
last = p;
if (!p) p = editor->pBuffer->pLast;
}
assert( p->type == diStartRow || p == editor->pBuffer->pLast );
if( p->type == diStartRow )
return ME_FindRunInRow( editor, p, x, result, is_eol ) && isExact;
result->pRun = ME_FindItemBack(p, diRun);
result->pPara = ME_GetParagraph(result->pRun);
result->nOffset = 0;
@ -1196,45 +1166,6 @@ void ME_MouseMove(ME_TextEditor *editor, int x, int y)
ME_SendSelChange(editor);
}
static ME_DisplayItem *ME_FindRunInRow(ME_TextEditor *editor, ME_DisplayItem *pRow,
int x, int *pOffset, int *pbCaretAtEnd)
{
ME_DisplayItem *pNext, *pLastRun;
pNext = ME_FindItemFwd(pRow, diRunOrStartRow);
assert(pNext->type == diRun);
if (pbCaretAtEnd) *pbCaretAtEnd = FALSE;
if (pOffset) *pOffset = 0;
do {
int run_x = pNext->member.run.pt.x;
int width = pNext->member.run.nWidth;
if (x < run_x)
{
return pNext;
}
if (x >= run_x && x < run_x+width)
{
int ch = ME_CharFromPointCursor(editor, x-run_x, &pNext->member.run);
ME_String *s = pNext->member.run.strText;
if (ch < s->nLen) {
if (pOffset)
*pOffset = ch;
return pNext;
}
}
pLastRun = pNext;
pNext = ME_FindItemFwd(pNext, diRunOrStartRow);
} while(pNext && pNext->type == diRun);
if ((pLastRun->member.run.nFlags & MERF_ENDPARA) == 0)
{
pNext = ME_FindItemFwd(pNext, diRun);
if (pbCaretAtEnd) *pbCaretAtEnd = TRUE;
return pNext;
} else {
return pLastRun;
}
}
static int ME_GetXForArrow(ME_TextEditor *editor, ME_Cursor *pCursor)
{
ME_DisplayItem *pRun = pCursor->pRun;
@ -1251,7 +1182,7 @@ static int ME_GetXForArrow(ME_TextEditor *editor, ME_Cursor *pCursor)
}
else {
x = pRun->member.run.pt.x;
x += ME_PointFromChar(editor, &pRun->member.run, pCursor->nOffset);
x += ME_PointFromChar(editor, &pRun->member.run, pCursor->nOffset, TRUE);
}
editor->nUDArrowX = x;
}
@ -1333,8 +1264,7 @@ ME_MoveCursorLines(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs)
/* row not found - ignore */
return;
}
pCursor->pRun = ME_FindRunInRow(editor, pItem, x, &pCursor->nOffset, &editor->bCaretAtEnd);
pCursor->pPara = ME_GetParagraph(pCursor->pRun);
ME_FindRunInRow(editor, pItem, x, pCursor, &editor->bCaretAtEnd);
assert(pCursor->pRun);
assert(pCursor->pRun->type == diRun);
}
@ -1387,9 +1317,7 @@ static void ME_ArrowPageUp(ME_TextEditor *editor, ME_Cursor *pCursor)
pLast = p;
} while(1);
pCursor->pRun = ME_FindRunInRow(editor, pLast, x, &pCursor->nOffset,
&editor->bCaretAtEnd);
pCursor->pPara = ME_GetParagraph(pCursor->pRun);
ME_FindRunInRow(editor, pLast, x, pCursor, &editor->bCaretAtEnd);
}
assert(pCursor->pRun);
assert(pCursor->pRun->type == diRun);
@ -1447,9 +1375,7 @@ static void ME_ArrowPageDown(ME_TextEditor *editor, ME_Cursor *pCursor)
pLast = p;
} while(1);
pCursor->pRun = ME_FindRunInRow(editor, pLast, x, &pCursor->nOffset,
&editor->bCaretAtEnd);
pCursor->pPara = ME_GetParagraph(pCursor->pRun);
ME_FindRunInRow(editor, pLast, x, pCursor, &editor->bCaretAtEnd);
}
assert(pCursor->pRun);
assert(pCursor->pRun->type == diRun);

View file

@ -840,6 +840,14 @@ void ME_RTFParAttrHook(RTF_Info *info)
}
break;
}
case rtfRTLPar:
fmt.dwMask = PFM_RTLPARA;
fmt.wEffects = PFE_RTLPARA;
break;
case rtfLTRPar:
fmt.dwMask = PFM_RTLPARA;
fmt.wEffects = 0;
break;
}
if (fmt.dwMask) {
RTFFlushOutputBuffer(info);
@ -1723,7 +1731,7 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH
if ((flags & FR_WHOLEWORD) && nMin)
{
ME_CursorFromCharOfs(editor, nMin - 1, &cursor);
wLastChar = cursor.pRun->member.run.strText->szData[cursor.nOffset];
wLastChar = *get_text( &cursor.pRun->member.run, cursor.nOffset );
ME_MoveCursorChars(editor, &cursor, 1);
} else {
ME_CursorFromCharOfs(editor, nMin, &cursor);
@ -1735,7 +1743,7 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH
int nCurStart = cursor.nOffset;
int nMatched = 0;
while (pCurItem && ME_CharCompare(pCurItem->member.run.strText->szData[nCurStart + nMatched], text[nMatched], (flags & FR_MATCHCASE)))
while (pCurItem && ME_CharCompare( *get_text( &pCurItem->member.run, nCurStart + nMatched ), text[nMatched], (flags & FR_MATCHCASE)))
{
if ((flags & FR_WHOLEWORD) && isalnumW(wLastChar))
break;
@ -1750,14 +1758,14 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH
/* Check to see if next character is a whitespace */
if (flags & FR_WHOLEWORD)
{
if (nCurStart + nMatched == pCurItem->member.run.strText->nLen)
if (nCurStart + nMatched == pCurItem->member.run.len)
{
pNextItem = ME_FindItemFwd(pCurItem, diRun);
nNextStart = -nMatched;
}
if (pNextItem)
wNextChar = pNextItem->member.run.strText->szData[nNextStart + nMatched];
wNextChar = *get_text( &pNextItem->member.run, nNextStart + nMatched );
else
wNextChar = ' ';
@ -1774,19 +1782,19 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH
TRACE("found at %d-%d\n", cursor.nOffset, cursor.nOffset + nLen);
return cursor.nOffset;
}
if (nCurStart + nMatched == pCurItem->member.run.strText->nLen)
if (nCurStart + nMatched == pCurItem->member.run.len)
{
pCurItem = ME_FindItemFwd(pCurItem, diRun);
nCurStart = -nMatched;
}
}
if (pCurItem)
wLastChar = pCurItem->member.run.strText->szData[nCurStart + nMatched];
wLastChar = *get_text( &pCurItem->member.run, nCurStart + nMatched );
else
wLastChar = ' ';
cursor.nOffset++;
if (cursor.nOffset == cursor.pRun->member.run.strText->nLen)
if (cursor.nOffset == cursor.pRun->member.run.len)
{
ME_NextRun(&cursor.pPara, &cursor.pRun);
cursor.nOffset = 0;
@ -1799,7 +1807,7 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH
if ((flags & FR_WHOLEWORD) && nMax < nTextLen - 1)
{
ME_CursorFromCharOfs(editor, nMax + 1, &cursor);
wLastChar = cursor.pRun->member.run.strText->szData[cursor.nOffset];
wLastChar = *get_text( &cursor.pRun->member.run, cursor.nOffset );
ME_MoveCursorChars(editor, &cursor, -1);
} else {
ME_CursorFromCharOfs(editor, nMax, &cursor);
@ -1815,10 +1823,11 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH
if (nCurEnd == 0)
{
ME_PrevRun(&pCurPara, &pCurItem);
nCurEnd = pCurItem->member.run.strText->nLen + nMatched;
nCurEnd = pCurItem->member.run.len + nMatched;
}
while (pCurItem && ME_CharCompare(pCurItem->member.run.strText->szData[nCurEnd - nMatched - 1], text[nLen - nMatched - 1], (flags & FR_MATCHCASE)))
while (pCurItem && ME_CharCompare( *get_text( &pCurItem->member.run, nCurEnd - nMatched - 1 ),
text[nLen - nMatched - 1], (flags & FR_MATCHCASE) ))
{
if ((flags & FR_WHOLEWORD) && isalnumW(wLastChar))
break;
@ -1838,11 +1847,11 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH
{
pPrevItem = ME_FindItemBack(pCurItem, diRun);
if (pPrevItem)
nPrevEnd = pPrevItem->member.run.strText->nLen + nMatched;
nPrevEnd = pPrevItem->member.run.len + nMatched;
}
if (pPrevItem)
wPrevChar = pPrevItem->member.run.strText->szData[nPrevEnd - nMatched - 1];
wPrevChar = *get_text( &pPrevItem->member.run, nPrevEnd - nMatched - 1 );
else
wPrevChar = ' ';
@ -1865,11 +1874,11 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH
ME_PrevRun(&pCurPara, &pCurItem);
/* Don't care about pCurItem becoming NULL here; it's already taken
* care of in the exterior loop condition */
nCurEnd = pCurItem->member.run.strText->nLen + nMatched;
nCurEnd = pCurItem->member.run.len + nMatched;
}
}
if (pCurItem)
wLastChar = pCurItem->member.run.strText->szData[nCurEnd - nMatched - 1];
wLastChar = *get_text( &pCurItem->member.run, nCurEnd - nMatched - 1 );
else
wLastChar = ' ';
@ -1877,7 +1886,7 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH
if (cursor.nOffset < 0)
{
ME_PrevRun(&cursor.pPara, &cursor.pRun);
cursor.nOffset = cursor.pRun->member.run.strText->nLen;
cursor.nOffset = cursor.pRun->member.run.len;
}
}
}
@ -2709,7 +2718,8 @@ ME_TextEditor *ME_MakeEditor(ITextHost *texthost, BOOL bEmulateVersion10)
ed->nEventMask = 0;
ed->nModifyStep = 0;
ed->nTextLimit = TEXT_LIMIT_DEFAULT;
ed->pUndoStack = ed->pRedoStack = ed->pUndoStackBottom = NULL;
list_init( &ed->undo_stack );
list_init( &ed->redo_stack );
ed->nUndoStackSize = 0;
ed->nUndoLimit = STACK_SIZE_DEFAULT;
ed->nUndoMode = umAddToUndo;
@ -2833,6 +2843,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
break;
case DLL_PROCESS_DETACH:
if (lpvReserved) break;
UnregisterClassW(RICHEDIT_CLASS20W, 0);
UnregisterClassW(MSFTEDIT_CLASS, 0);
UnregisterClassA(RICHEDIT_CLASS20A, 0);
@ -2843,7 +2854,6 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
UnregisterClassW(REComboBox20W, 0);
LookupCleanup();
HeapDestroy (me_heap);
me_heap = NULL;
break;
}
return TRUE;
@ -3009,7 +3019,7 @@ static void ME_LinkNotify(ME_TextEditor *editor, UINT msg, WPARAM wParam, LPARAM
info.lParam = lParam;
cursor.nOffset = 0;
info.chrg.cpMin = ME_GetCursorOfs(&cursor);
info.chrg.cpMax = info.chrg.cpMin + cursor.pRun->member.run.strText->nLen;
info.chrg.cpMax = info.chrg.cpMin + cursor.pRun->member.run.len;
ITextHost_TxNotify(editor->texthost, info.nmhdr.code, &info);
}
}
@ -3106,9 +3116,9 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
return editor->nUndoLimit;
}
case EM_CANUNDO:
return editor->pUndoStack != NULL;
return !list_empty( &editor->undo_stack );
case EM_CANREDO:
return editor->pRedoStack != NULL;
return !list_empty( &editor->redo_stack );
case WM_UNDO: /* FIXME: actually not the same */
case EM_UNDO:
return ME_Undo(editor);
@ -3703,16 +3713,15 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
while (nCharsLeft && (run = ME_FindItemFwd(run, diRunOrStartRow))
&& run->type == diRun)
{
WCHAR *str = get_text( &run->member.run, 0 );
unsigned int nCopy;
ME_String *strText;
strText = run->member.run.strText;
nCopy = min(nCharsLeft, strText->nLen);
nCopy = min(nCharsLeft, run->member.run.len);
if (unicode)
memcpy(dest, strText->szData, nCopy * sizeof(WCHAR));
memcpy(dest, str, nCopy * sizeof(WCHAR));
else
nCopy = WideCharToMultiByte(CP_ACP, 0, strText->szData, nCopy, dest,
nCopy = WideCharToMultiByte(CP_ACP, 0, str, nCopy, dest,
nCharsLeft, NULL, NULL);
dest += nCopy * (unicode ? sizeof(WCHAR) : 1);
nCharsLeft -= nCopy;
@ -3754,8 +3763,8 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
assert(last_para->member.run.nFlags & MERF_ENDPARA);
if (editor->bEmulateVersion10 && prev_para &&
last_para->member.run.nCharOfs == 0 &&
prev_para->member.run.strText->nLen == 1 &&
prev_para->member.run.strText->szData[0] == '\r')
prev_para->member.run.len == 1 &&
*get_text( &prev_para->member.run, 0 ) == '\r')
{
/* In 1.0 emulation, the last solitary \r at the very end of the text
(if one exists) is NOT a line break.
@ -3819,7 +3828,7 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
} else {
ME_DisplayItem *endRun = ME_FindItemBack(item_end, diRun);
assert(endRun && endRun->member.run.nFlags & MERF_ENDPARA);
nNextLineOfs = item_end->member.para.nCharOfs - endRun->member.run.strText->nLen;
nNextLineOfs = item_end->member.para.nCharOfs - endRun->member.run.len;
}
nChars = nNextLineOfs - nThisLineOfs;
TRACE("EM_LINELENGTH(%ld)==%d\n",wParam, nChars);
@ -3849,28 +3858,38 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
}
case EM_FINDTEXT:
{
FINDTEXTA *ft = (FINDTEXTA *)lParam;
int nChars = MultiByteToWideChar(CP_ACP, 0, ft->lpstrText, -1, NULL, 0);
WCHAR *tmp;
LRESULT r;
if(!unicode){
FINDTEXTA *ft = (FINDTEXTA *)lParam;
int nChars = MultiByteToWideChar(CP_ACP, 0, ft->lpstrText, -1, NULL, 0);
WCHAR *tmp;
if ((tmp = ALLOC_N_OBJ(WCHAR, nChars)) != NULL)
MultiByteToWideChar(CP_ACP, 0, ft->lpstrText, -1, tmp, nChars);
r = ME_FindText(editor, wParam, &ft->chrg, tmp, NULL);
FREE_OBJ( tmp );
if ((tmp = ALLOC_N_OBJ(WCHAR, nChars)) != NULL)
MultiByteToWideChar(CP_ACP, 0, ft->lpstrText, -1, tmp, nChars);
r = ME_FindText(editor, wParam, &ft->chrg, tmp, NULL);
FREE_OBJ( tmp );
}else{
FINDTEXTW *ft = (FINDTEXTW *)lParam;
r = ME_FindText(editor, wParam, &ft->chrg, ft->lpstrText, NULL);
}
return r;
}
case EM_FINDTEXTEX:
{
FINDTEXTEXA *ex = (FINDTEXTEXA *)lParam;
int nChars = MultiByteToWideChar(CP_ACP, 0, ex->lpstrText, -1, NULL, 0);
WCHAR *tmp;
LRESULT r;
if(!unicode){
FINDTEXTEXA *ex = (FINDTEXTEXA *)lParam;
int nChars = MultiByteToWideChar(CP_ACP, 0, ex->lpstrText, -1, NULL, 0);
WCHAR *tmp;
if ((tmp = ALLOC_N_OBJ(WCHAR, nChars)) != NULL)
MultiByteToWideChar(CP_ACP, 0, ex->lpstrText, -1, tmp, nChars);
r = ME_FindText(editor, wParam, &ex->chrg, tmp, &ex->chrgText);
FREE_OBJ( tmp );
if ((tmp = ALLOC_N_OBJ(WCHAR, nChars)) != NULL)
MultiByteToWideChar(CP_ACP, 0, ex->lpstrText, -1, tmp, nChars);
r = ME_FindText(editor, wParam, &ex->chrg, tmp, &ex->chrgText);
FREE_OBJ( tmp );
}else{
FINDTEXTEXW *ex = (FINDTEXTEXW *)lParam;
r = ME_FindText(editor, wParam, &ex->chrg, ex->lpstrText, &ex->chrgText);
}
return r;
}
case EM_FINDTEXTW:
@ -3917,7 +3936,7 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
ME_RunOfsFromCharOfs(editor, nCharOfs, &pPara, &pRun, &nOffset);
assert(pRun->type == diRun);
pt.y = pRun->member.run.pt.y;
pt.x = pRun->member.run.pt.x + ME_PointFromChar(editor, &pRun->member.run, nOffset);
pt.x = pRun->member.run.pt.x + ME_PointFromChar(editor, &pRun->member.run, nOffset, TRUE);
pt.y += pPara->member.para.pt.y + editor->rcFormat.top;
pt.x += editor->rcFormat.left;
@ -4049,6 +4068,9 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
return 0;
goto do_default;
case WM_CHAR:
if ((editor->nEventMask & ENM_KEYEVENTS) &&
!ME_FilterEvent(editor, msg, &wParam, &lParam))
return 0;
return ME_Char(editor, wParam, lParam, unicode);
case WM_UNICHAR:
if (unicode)
@ -4348,7 +4370,8 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
int mask = 0;
int changes = 0;
if (ME_GetTextLength(editor) || editor->pUndoStack || editor->pRedoStack)
if (ME_GetTextLength(editor) ||
!list_empty( &editor->undo_stack ) || !list_empty( &editor->redo_stack ))
return E_UNEXPECTED;
/* Check for mutually exclusive flags in adjacent bits of wParam */
@ -4602,8 +4625,8 @@ int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int buflen,
assert(pRun);
pNextRun = ME_FindItemFwd(pRun, diRun);
nLen = pRun->member.run.strText->nLen - start->nOffset;
str = pRun->member.run.strText->szData + start->nOffset;
nLen = pRun->member.run.len - start->nOffset;
str = get_text( &pRun->member.run, start->nOffset );
/* No '\r' is appended to the last paragraph. */
while (srcChars && buflen && pNextRun)
@ -4634,8 +4657,8 @@ int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int buflen,
pRun = pNextRun;
pNextRun = ME_FindItemFwd(pRun, diRun);
nLen = pRun->member.run.strText->nLen;
str = pRun->member.run.strText->szData;
nLen = pRun->member.run.len;
str = get_text( &pRun->member.run, 0 );
}
*buffer = 0;
return buffer - pStart;
@ -4775,9 +4798,9 @@ static BOOL ME_FindNextURLCandidate(ME_TextEditor *editor,
while (nChars > 0)
{
WCHAR *strStart = cursor.pRun->member.run.strText->szData;
WCHAR *strStart = get_text( &cursor.pRun->member.run, 0 );
WCHAR *str = strStart + cursor.nOffset;
int nLen = cursor.pRun->member.run.strText->nLen - cursor.nOffset;
int nLen = cursor.pRun->member.run.len - cursor.nOffset;
nChars -= nLen;
if (~cursor.pRun->member.run.nFlags & MERF_ENDPARA)
@ -4951,9 +4974,9 @@ static BOOL ME_UpdateLinkAttribute(ME_TextEditor *editor, ME_Cursor *start, int
/* Update candidateEnd since setting character formats may split
* runs, which can cause a cursor to be at an invalid offset within
* a split run. */
while (candidateEnd.nOffset >= candidateEnd.pRun->member.run.strText->nLen)
while (candidateEnd.nOffset >= candidateEnd.pRun->member.run.len)
{
candidateEnd.nOffset -= candidateEnd.pRun->member.run.strText->nLen;
candidateEnd.nOffset -= candidateEnd.pRun->member.run.len;
candidateEnd.pRun = ME_FindItemFwd(candidateEnd.pRun, diRun);
}
modified = TRUE;

View file

@ -56,6 +56,16 @@ static inline void * __WINE_ALLOC_SIZE(2) heap_realloc( void *ptr, size_t len )
(fe).lindex=-1;\
};
static inline WCHAR *get_text( const ME_Run *run, int offset )
{
return run->para->text->szData + run->nCharOfs + offset;
}
static inline const char *debugstr_run( const ME_Run *run )
{
return debugstr_wn( get_text( run, 0 ), run->len );
}
/* style.c */
ME_Style *ME_MakeStyle(CHARFORMAT2W *style) DECLSPEC_HIDDEN;
void ME_AddRefStyle(ME_Style *item) DECLSPEC_HIDDEN;
@ -90,15 +100,14 @@ const char *ME_GetDITypeName(ME_DIType type) DECLSPEC_HIDDEN;
/* string.c */
ME_String *ME_MakeStringN(LPCWSTR szText, int nMaxChars) DECLSPEC_HIDDEN;
ME_String *ME_MakeStringR(WCHAR cRepeat, int nMaxChars) DECLSPEC_HIDDEN;
ME_String *ME_StrDup(const ME_String *s) DECLSPEC_HIDDEN;
void ME_DestroyString(ME_String *s) DECLSPEC_HIDDEN;
void ME_AppendString(ME_String *s1, const ME_String *s2) DECLSPEC_HIDDEN;
BOOL ME_AppendString(ME_String *s, const WCHAR *append, int len) DECLSPEC_HIDDEN;
ME_String *ME_VSplitString(ME_String *orig, int nVPos) DECLSPEC_HIDDEN;
int ME_IsWhitespaces(const ME_String *s) DECLSPEC_HIDDEN;
int ME_IsSplitable(const ME_String *s) DECLSPEC_HIDDEN;
int ME_FindNonWhitespaceV(const ME_String *s, int nVChar) DECLSPEC_HIDDEN;
int ME_CallWordBreakProc(ME_TextEditor *editor, ME_String *str, INT start, INT code) DECLSPEC_HIDDEN;
int ME_CallWordBreakProc(ME_TextEditor *editor, WCHAR *str, INT len, INT start, INT code) DECLSPEC_HIDDEN;
void ME_StrDeleteV(ME_String *s, int nVChar, int nChars) DECLSPEC_HIDDEN;
BOOL ME_InsertString(ME_String *s, int ofs, const WCHAR *insert, int len) DECLSPEC_HIDDEN;
/* smart helpers for A<->W conversions, they reserve/free memory and call MultiByte<->WideChar functions */
LPWSTR ME_ToUnicode(BOOL unicode, LPVOID psz) DECLSPEC_HIDDEN;
void ME_EndToUnicode(BOOL unicode, LPVOID psz) DECLSPEC_HIDDEN;
@ -125,22 +134,22 @@ ME_DisplayItem *ME_FindRowWithNumber(ME_TextEditor *editor, int nRow) DECLSPEC_H
int ME_RowNumberFromCharOfs(ME_TextEditor *editor, int nOfs) DECLSPEC_HIDDEN;
/* run.c */
ME_DisplayItem *ME_MakeRun(ME_Style *s, ME_String *strData, int nFlags) DECLSPEC_HIDDEN;
ME_DisplayItem *ME_MakeRun(ME_Style *s, int nFlags) DECLSPEC_HIDDEN;
ME_DisplayItem *ME_InsertRunAtCursor(ME_TextEditor *editor, ME_Cursor *cursor,
ME_Style *style, const WCHAR *str, int len, int flags) DECLSPEC_HIDDEN;
void ME_CheckCharOffsets(ME_TextEditor *editor) DECLSPEC_HIDDEN;
void ME_PropagateCharOffset(ME_DisplayItem *p, int shift) DECLSPEC_HIDDEN;
int ME_CharFromPoint(ME_Context *c, int cx, ME_Run *run) DECLSPEC_HIDDEN;
/* this one accounts for 1/2 char tolerance */
int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run) DECLSPEC_HIDDEN;
int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset) DECLSPEC_HIDDEN;
int ME_CharFromPointContext(ME_Context *c, int cx, ME_Run *run, BOOL closest, BOOL visual_order) DECLSPEC_HIDDEN;
int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run, BOOL closest, BOOL visual_order) DECLSPEC_HIDDEN;
int ME_PointFromCharContext(ME_Context *c, ME_Run *pRun, int nOffset, BOOL visual_order) DECLSPEC_HIDDEN;
int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset, BOOL visual_order) DECLSPEC_HIDDEN;
int ME_CanJoinRuns(const ME_Run *run1, const ME_Run *run2) DECLSPEC_HIDDEN;
void ME_JoinRuns(ME_TextEditor *editor, ME_DisplayItem *p) DECLSPEC_HIDDEN;
ME_DisplayItem *ME_SplitRun(ME_WrapContext *wc, ME_DisplayItem *item, int nChar) DECLSPEC_HIDDEN;
ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_Cursor *cursor) DECLSPEC_HIDDEN;
void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run) DECLSPEC_HIDDEN;
void ME_CalcRunExtent(ME_Context *c, const ME_Paragraph *para, int startx, ME_Run *run) DECLSPEC_HIDDEN;
SIZE ME_GetRunSize(ME_Context *c, const ME_Paragraph *para, ME_Run *run, int nLen, int startx) DECLSPEC_HIDDEN;
SIZE ME_GetRunSizeCommon(ME_Context *c, const ME_Paragraph *para, ME_Run *run, int nLen,
int startx, int *pAscent, int *pDescent) DECLSPEC_HIDDEN;
void ME_CursorFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_Cursor *pCursor) DECLSPEC_HIDDEN;
void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **ppPara, ME_DisplayItem **ppRun, int *pOfs) DECLSPEC_HIDDEN;
int ME_CharOfsFromRunOfs(ME_TextEditor *editor, const ME_DisplayItem *pPara, const ME_DisplayItem *pRun, int nOfs) DECLSPEC_HIDDEN;
@ -194,7 +203,7 @@ void ME_SendRequestResize(ME_TextEditor *editor, BOOL force) DECLSPEC_HIDDEN;
ME_DisplayItem *ME_GetParagraph(ME_DisplayItem *run) DECLSPEC_HIDDEN;
void ME_GetSelectionParas(ME_TextEditor *editor, ME_DisplayItem **para, ME_DisplayItem **para_end) DECLSPEC_HIDDEN;
void ME_MakeFirstParagraph(ME_TextEditor *editor) DECLSPEC_HIDDEN;
ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *rp, ME_Style *style, ME_String *eol_str, int paraFlags) DECLSPEC_HIDDEN;
ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *rp, ME_Style *style, const WCHAR *eol_str, int eol_len, int paraFlags) DECLSPEC_HIDDEN;
ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp,
BOOL keepFirstParaFormat) DECLSPEC_HIDDEN;
void ME_DumpParaStyle(ME_Paragraph *s) DECLSPEC_HIDDEN;
@ -317,7 +326,12 @@ ITextHost *ME_CreateTextHost(HWND hwnd, CREATESTRUCTW *cs, BOOL bEmulateVersion1
#define ITextHost_TxGetSelectionBarWidth(This,a) TXTHOST_VTABLE(This)->TxGetSelectionBarWidth(This,a)
/* undo.c */
ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, const ME_DisplayItem *pdi) DECLSPEC_HIDDEN;
BOOL add_undo_insert_run( ME_TextEditor *, int pos, const WCHAR *str, int len, int flags, ME_Style *style ) DECLSPEC_HIDDEN;
BOOL add_undo_delete_run( ME_TextEditor *, int pos, int len ) DECLSPEC_HIDDEN;
BOOL add_undo_set_para_fmt( ME_TextEditor *, const ME_Paragraph *para ) DECLSPEC_HIDDEN;
BOOL add_undo_set_char_fmt( ME_TextEditor *, int pos, int len, const CHARFORMAT2W *fmt ) DECLSPEC_HIDDEN;
BOOL add_undo_join_paras( ME_TextEditor *, int pos ) DECLSPEC_HIDDEN;
BOOL add_undo_split_para( ME_TextEditor *, const ME_Paragraph *para, ME_String *eol_str, const ME_Cell *cell) DECLSPEC_HIDDEN;
void ME_CommitUndo(ME_TextEditor *editor) DECLSPEC_HIDDEN;
void ME_ContinueCoalescingTransaction(ME_TextEditor *editor) DECLSPEC_HIDDEN;
void ME_CommitCoalescingUndo(ME_TextEditor *editor) DECLSPEC_HIDDEN;

View file

@ -53,6 +53,7 @@
#include <textserv.h>
#include <wine/debug.h>
#include <wine/list.h>
#ifdef __i386__
extern const struct ITextHostVtbl itextHostStdcallVtbl;
@ -89,15 +90,6 @@ typedef enum {
diRunOrStartRow,
diParagraphOrEnd,
diRunOrParagraphOrEnd, /* 12 */
diUndoInsertRun, /* 13 */
diUndoDeleteRun, /* 14 */
diUndoJoinParagraphs, /* 15 */
diUndoSplitParagraph, /* 16 */
diUndoSetParagraphFormat, /* 17 */
diUndoSetCharFormat, /* 18 */
diUndoEndTransaction, /* 19 - marks the end of a group of changes for undo */
diUndoPotentialEndTransaction, /* 20 - allows grouping typed chars for undo */
} ME_DIType;
#define SELECTIONBAR_WIDTH 8
@ -153,9 +145,10 @@ struct tagME_DisplayItem;
typedef struct tagME_Run
{
ME_String *strText;
ME_Style *style;
struct tagME_Paragraph *para; /* ptr to the run's paragraph */
int nCharOfs; /* relative to para's offset */
int len; /* length of run's text */
int nWidth; /* width of full run, width of leading&trailing ws */
int nFlags;
int nAscent, nDescent; /* pixels above/below baseline */
@ -180,6 +173,7 @@ typedef struct tagME_BorderRect
typedef struct tagME_Paragraph
{
PARAFORMAT2 *pFmt;
ME_String *text;
struct tagME_DisplayItem *pCell; /* v4.1 */
ME_BorderRect border;
@ -234,17 +228,9 @@ typedef struct tagME_DisplayItem
ME_Row row;
ME_Cell cell;
ME_Paragraph para;
ME_Style *ustyle; /* used by diUndoSetCharFormat */
} member;
} ME_DisplayItem;
typedef struct tagME_UndoItem
{
ME_DisplayItem di;
int nStart, nLen;
ME_String *eol_str; /* used by diUndoSplitParagraph */
} ME_UndoItem;
typedef struct tagME_TextBuffer
{
ME_DisplayItem *pFirst, *pLast;
@ -266,6 +252,75 @@ typedef enum {
umAddBackToUndo
} ME_UndoMode;
enum undo_type
{
undo_insert_run,
undo_delete_run,
undo_join_paras,
undo_split_para,
undo_set_para_fmt,
undo_set_char_fmt,
undo_end_transaction, /* marks the end of a group of changes for undo */
undo_potential_end_transaction /* allows grouping typed chars for undo */
};
struct insert_run_item
{
int pos, len;
WCHAR *str;
ME_Style *style;
DWORD flags;
};
struct delete_run_item
{
int pos, len;
};
struct join_paras_item
{
int pos;
};
struct split_para_item
{
int pos;
PARAFORMAT2 fmt;
ME_BorderRect border;
ME_String *eol_str;
DWORD flags;
ME_BorderRect cell_border;
int cell_right_boundary;
};
struct set_para_fmt_item
{
int pos;
PARAFORMAT2 fmt;
ME_BorderRect border;
};
struct set_char_fmt_item
{
int pos, len;
CHARFORMAT2W fmt;
};
struct undo_item
{
struct list entry;
enum undo_type type;
union
{
struct insert_run_item insert_run;
struct delete_run_item delete_run;
struct join_paras_item join_paras;
struct split_para_item split_para;
struct set_para_fmt_item set_para_fmt;
struct set_char_fmt_item set_char_fmt;
} u;
};
typedef enum {
stPosition = 0,
stWord,
@ -341,7 +396,8 @@ typedef struct tagME_TextEditor
BOOL bCaretAtEnd;
int nEventMask;
int nModifyStep;
ME_DisplayItem *pUndoStack, *pRedoStack, *pUndoStackBottom;
struct list undo_stack;
struct list redo_stack;
int nUndoStackSize;
int nUndoLimit;
ME_UndoMode nUndoMode;

View file

@ -139,32 +139,31 @@ ME_DisplayItem *ME_FindItemFwd(ME_DisplayItem *di, ME_DIType nTypeOrClass)
return NULL;
}
void ME_DestroyDisplayItem(ME_DisplayItem *item) {
void ME_DestroyDisplayItem(ME_DisplayItem *item)
{
/* TRACE("type=%s\n", ME_GetDITypeName(item->type)); */
if (item->type==diParagraph || item->type == diUndoSetParagraphFormat) {
if (item->type==diParagraph)
{
FREE_OBJ(item->member.para.pFmt);
ME_DestroyString(item->member.para.text);
}
if (item->type==diRun || item->type == diUndoInsertRun) {
if (item->type==diRun)
{
if (item->member.run.ole_obj) ME_DeleteReObject(item->member.run.ole_obj);
ME_ReleaseStyle(item->member.run.style);
ME_DestroyString(item->member.run.strText);
}
if (item->type==diUndoSetCharFormat) {
ME_ReleaseStyle(item->member.ustyle);
}
if (item->type==diUndoSplitParagraph) {
FREE_OBJ(item->member.para.pFmt);
FREE_OBJ(item->member.para.pCell);
}
FREE_OBJ(item);
}
ME_DisplayItem *ME_MakeDI(ME_DIType type) {
ME_DisplayItem *ME_MakeDI(ME_DIType type)
{
ME_DisplayItem *item = ALLOC_OBJ(ME_DisplayItem);
ZeroMemory(item, sizeof(ME_DisplayItem));
item->type = type;
item->prev = item->next = NULL;
if (type == diParagraph || type == diUndoSplitParagraph) {
if (type == diParagraph)
{
item->member.para.pFmt = ALLOC_OBJ(PARAFORMAT2);
ME_SetDefaultParaFormat(item->member.para.pFmt);
item->member.para.nFlags = MEPF_REWRAP;
@ -183,14 +182,6 @@ const char *ME_GetDITypeName(ME_DIType type)
case diTextStart: return "diTextStart";
case diTextEnd: return "diTextEnd";
case diStartRow: return "diStartRow";
case diUndoEndTransaction: return "diUndoEndTransaction";
case diUndoPotentialEndTransaction: return "diUndoPotentialEndTransaction";
case diUndoSetParagraphFormat: return "diUndoSetParagraphFormat";
case diUndoSetCharFormat: return "diUndoSetCharFormat";
case diUndoInsertRun: return "diUndoInsertRun";
case diUndoDeleteRun: return "diUndoDeleteRun";
case diUndoJoinParagraphs: return "diJoinParagraphs";
case diUndoSplitParagraph: return "diSplitParagraph";
default: return "?";
}
}
@ -222,7 +213,7 @@ void ME_DumpDocument(ME_TextBuffer *buffer)
TRACE(" - StartRow\n");
break;
case diRun:
TRACE(" - Run(\"%s\", %d, flags=%x)\n", debugstr_w(pItem->member.run.strText->szData),
TRACE(" - Run(%s, %d, flags=%x)\n", debugstr_run( &pItem->member.run ),
pItem->member.run.nCharOfs, pItem->member.run.nFlags);
break;
case diTextEnd:

View file

@ -166,210 +166,237 @@ int ME_twips2pointsY(const ME_Context *c, int y)
return y * c->dpi.cy * c->editor->nZoomNumerator / 1440 / c->editor->nZoomDenominator;
}
static void ME_HighlightSpace(ME_Context *c, int x, int y, LPCWSTR szText,
int nChars, ME_Style *s, int width,
int nSelFrom, int nSelTo, int ymin, int cy)
{
HDC hDC = c->hDC;
HGDIOBJ hOldFont = NULL;
SIZE sz;
int selWidth;
/* Only highlight if there is a selection in the run and when
* EM_HIDESELECTION is not being used to hide the selection. */
if (nSelFrom >= nChars || nSelTo < 0 || nSelFrom >= nSelTo
|| c->editor->bHideSelection)
return;
hOldFont = ME_SelectStyleFont(c, s);
if (width <= 0)
{
GetTextExtentPoint32W(hDC, szText, nChars, &sz);
width = sz.cx;
}
if (nSelFrom < 0) nSelFrom = 0;
if (nSelTo > nChars) nSelTo = nChars;
GetTextExtentPoint32W(hDC, szText, nSelFrom, &sz);
x += sz.cx;
if (nSelTo != nChars)
{
GetTextExtentPoint32W(hDC, szText+nSelFrom, nSelTo-nSelFrom, &sz);
selWidth = sz.cx;
} else {
selWidth = width - sz.cx;
}
ME_UnselectStyleFont(c, s, hOldFont);
if (c->editor->bEmulateVersion10)
PatBlt(hDC, x, ymin, selWidth, cy, DSTINVERT);
else
{
RECT rect;
HBRUSH hBrush;
rect.left = x;
rect.top = ymin;
rect.right = x + selWidth;
rect.bottom = ymin + cy;
hBrush = CreateSolidBrush(ITextHost_TxGetSysColor(c->editor->texthost,
COLOR_HIGHLIGHT));
FillRect(hDC, &rect, hBrush);
DeleteObject(hBrush);
}
static int calc_y_offset( const ME_Context *c, ME_Style *style )
{
int offs = 0, twips = 0;
if ((style->fmt.dwMask & style->fmt.dwEffects) & CFM_OFFSET)
twips = style->fmt.yOffset;
if ((style->fmt.dwMask & style->fmt.dwEffects) & (CFM_SUPERSCRIPT | CFM_SUBSCRIPT))
{
if (style->fmt.dwEffects & CFE_SUPERSCRIPT) twips = style->fmt.yHeight/3;
if (style->fmt.dwEffects & CFE_SUBSCRIPT) twips = -style->fmt.yHeight/12;
}
if (twips) offs = ME_twips2pointsY( c, twips );
return offs;
}
static void ME_DrawTextWithStyle(ME_Context *c, int x, int y, LPCWSTR szText,
int nChars, ME_Style *s, int width,
static COLORREF get_text_color( ME_Context *c, ME_Style *style, BOOL highlight )
{
COLORREF color;
if (highlight)
color = ITextHost_TxGetSysColor( c->editor->texthost, COLOR_HIGHLIGHTTEXT );
else if ((style->fmt.dwMask & CFM_LINK) && (style->fmt.dwEffects & CFE_LINK))
color = RGB(0,0,255);
else if ((style->fmt.dwMask & CFM_COLOR) && (style->fmt.dwEffects & CFE_AUTOCOLOR))
color = ITextHost_TxGetSysColor( c->editor->texthost, COLOR_WINDOWTEXT );
else
color = style->fmt.crTextColor;
return color;
}
static void get_underline_pen( ME_Style *style, COLORREF color, HPEN *pen )
{
*pen = NULL;
/* Choose the pen type for underlining the text. */
if (style->fmt.dwMask & CFM_UNDERLINETYPE)
{
switch (style->fmt.bUnderlineType)
{
case CFU_UNDERLINE:
case CFU_UNDERLINEWORD: /* native seems to map it to simple underline (MSDN) */
case CFU_UNDERLINEDOUBLE: /* native seems to map it to simple underline (MSDN) */
*pen = CreatePen( PS_SOLID, 1, color );
break;
case CFU_UNDERLINEDOTTED:
*pen = CreatePen( PS_DOT, 1, color );
break;
default:
FIXME( "Unknown underline type (%u)\n", style->fmt.bUnderlineType );
/* fall through */
case CFU_CF1UNDERLINE: /* this type is supported in the font, do nothing */
case CFU_UNDERLINENONE:
break;
}
}
return;
}
static void draw_underline( ME_Context *c, ME_Run *run, int x, int y, COLORREF color )
{
HPEN pen;
get_underline_pen( run->style, color, &pen );
if (pen)
{
HPEN old_pen = SelectObject( c->hDC, pen );
MoveToEx( c->hDC, x, y + 1, NULL );
LineTo( c->hDC, x + run->nWidth, y + 1 );
SelectObject( c->hDC, old_pen );
DeleteObject( pen );
}
return;
}
/*********************************************************************
* draw_space
*
* Draw the end-of-paragraph or tab space.
*
* If actually_draw is TRUE then ensure any underline is drawn.
*/
static void draw_space( ME_Context *c, ME_Run *run, int x, int y,
BOOL selected, BOOL actually_draw, int ymin, int cy )
{
HDC hdc = c->hDC;
BOOL old_style_selected = FALSE;
RECT rect;
COLORREF back_color = 0;
SetRect( &rect, x, ymin, x + run->nWidth, ymin + cy );
if (c->editor->bHideSelection) selected = FALSE;
if (c->editor->bEmulateVersion10)
{
old_style_selected = selected;
selected = FALSE;
}
if (selected)
back_color = ITextHost_TxGetSysColor( c->editor->texthost, COLOR_HIGHLIGHT );
if (actually_draw)
{
COLORREF text_color = get_text_color( c, run->style, selected );
COLORREF old_text, old_back;
HFONT old_font = NULL;
int y_offset = calc_y_offset( c, run->style );
static const WCHAR space[1] = {' '};
old_font = ME_SelectStyleFont( c, run->style );
old_text = SetTextColor( hdc, text_color );
if (selected) old_back = SetBkColor( hdc, back_color );
ExtTextOutW( hdc, x, y - y_offset, selected ? ETO_OPAQUE : 0, &rect, space, 1, &run->nWidth );
if (selected) SetBkColor( hdc, old_back );
SetTextColor( hdc, old_text );
ME_UnselectStyleFont( c, run->style, old_font );
draw_underline( c, run, x, y - y_offset, text_color );
}
else if (selected)
{
HBRUSH brush = CreateSolidBrush( back_color );
FillRect( hdc, &rect, brush );
DeleteObject( brush );
}
if (old_style_selected)
PatBlt( hdc, x, ymin, run->nWidth, cy, DSTINVERT );
}
static void get_selection_rect( ME_Context *c, ME_Run *run, int from, int to, int cy, RECT *r )
{
from = max( 0, from );
to = min( run->len, to );
r->left = ME_PointFromCharContext( c, run, from, TRUE );
r->top = 0;
r->right = ME_PointFromCharContext( c, run, to, TRUE );
r->bottom = cy;
return;
}
static void draw_text( ME_Context *c, ME_Run *run, int x, int y, BOOL selected, RECT *sel_rect )
{
COLORREF text_color = get_text_color( c, run->style, selected );
COLORREF back_color = selected ? ITextHost_TxGetSysColor( c->editor->texthost, COLOR_HIGHLIGHT ) : 0;
COLORREF old_text, old_back = 0;
const WCHAR *text = get_text( run, 0 );
ME_String *masked = NULL;
if (c->editor->cPasswordMask)
{
masked = ME_MakeStringR( c->editor->cPasswordMask, run->len );
text = masked->szData;
}
old_text = SetTextColor( c->hDC, text_color );
if (selected) old_back = SetBkColor( c->hDC, back_color );
ExtTextOutW( c->hDC, x, y, selected ? ETO_OPAQUE : 0, sel_rect, text, run->len, NULL );
if (selected) SetBkColor( c->hDC, old_back );
SetTextColor( c->hDC, old_text );
draw_underline( c, run, x, y, text_color );
ME_DestroyString( masked );
return;
}
static void ME_DrawTextWithStyle(ME_Context *c, ME_Run *run, int x, int y,
int nSelFrom, int nSelTo, int ymin, int cy)
{
HDC hDC = c->hDC;
HGDIOBJ hOldFont;
COLORREF rgbOld;
int yOffset = 0, yTwipsOffset = 0;
SIZE sz;
COLORREF rgb;
HPEN hPen = NULL, hOldPen = NULL;
BOOL bHighlightedText = (nSelFrom < nChars && nSelTo >= 0
&& nSelFrom < nSelTo && !c->editor->bHideSelection);
int xSelStart = x, xSelEnd = x;
int *lpDx = NULL;
/* lpDx is only needed for tabs to make sure the underline done automatically
* by the font extends to the end of the tab. Tabs are always stored as
* a single character run, so we can handle this case separately, since
* otherwise lpDx would need to specify the lengths of each character. */
if (width && nChars == 1)
lpDx = &width; /* Make sure underline for tab extends across tab space */
int yOffset = 0;
BOOL selected = (nSelFrom < run->len && nSelTo >= 0
&& nSelFrom < nSelTo && !c->editor->bHideSelection);
BOOL old_style_selected = FALSE;
RECT sel_rect;
HRGN clip = NULL, sel_rgn = NULL;
hOldFont = ME_SelectStyleFont(c, s);
if ((s->fmt.dwMask & s->fmt.dwEffects) & CFM_OFFSET) {
yTwipsOffset = s->fmt.yOffset;
}
if ((s->fmt.dwMask & s->fmt.dwEffects) & (CFM_SUPERSCRIPT | CFM_SUBSCRIPT)) {
if (s->fmt.dwEffects & CFE_SUPERSCRIPT) yTwipsOffset = s->fmt.yHeight/3;
if (s->fmt.dwEffects & CFE_SUBSCRIPT) yTwipsOffset = -s->fmt.yHeight/12;
}
if (yTwipsOffset)
yOffset = ME_twips2pointsY(c, yTwipsOffset);
yOffset = calc_y_offset( c, run->style );
if ((s->fmt.dwMask & CFM_LINK) && (s->fmt.dwEffects & CFE_LINK))
rgb = RGB(0,0,255);
else if ((s->fmt.dwMask & CFM_COLOR) && (s->fmt.dwEffects & CFE_AUTOCOLOR))
rgb = ITextHost_TxGetSysColor(c->editor->texthost, COLOR_WINDOWTEXT);
else
rgb = s->fmt.crTextColor;
/* Determine the area that is selected in the run. */
GetTextExtentPoint32W(hDC, szText, nChars, &sz);
/* Treat width as an optional parameter. We can get the width from the
* text extent of the string if it isn't specified. */
if (!width) width = sz.cx;
if (bHighlightedText)
if (selected)
{
if (nSelFrom <= 0)
get_selection_rect( c, run, nSelFrom, nSelTo, cy, &sel_rect );
OffsetRect( &sel_rect, x, ymin );
if (c->editor->bEmulateVersion10)
{
nSelFrom = 0;
old_style_selected = TRUE;
selected = FALSE;
}
else
{
GetTextExtentPoint32W(hDC, szText, nSelFrom, &sz);
xSelStart = x + sz.cx;
}
if (nSelTo >= nChars)
{
nSelTo = nChars;
xSelEnd = x + width;
}
else
{
GetTextExtentPoint32W(hDC, szText+nSelFrom, nSelTo-nSelFrom, &sz);
xSelEnd = xSelStart + sz.cx;
sel_rgn = CreateRectRgnIndirect( &sel_rect );
clip = CreateRectRgn( 0, 0, 0, 0 );
if (GetClipRgn( hDC, clip ) != 1)
{
DeleteObject( clip );
clip = NULL;
}
}
}
/* Choose the pen type for underlining the text. */
if (s->fmt.dwMask & CFM_UNDERLINETYPE)
hOldFont = ME_SelectStyleFont( c, run->style );
if (sel_rgn) ExtSelectClipRgn( hDC, sel_rgn, RGN_DIFF );
draw_text( c, run, x, y - yOffset, FALSE, NULL );
if (sel_rgn)
{
switch (s->fmt.bUnderlineType)
{
case CFU_UNDERLINE:
case CFU_UNDERLINEWORD: /* native seems to map it to simple underline (MSDN) */
case CFU_UNDERLINEDOUBLE: /* native seems to map it to simple underline (MSDN) */
hPen = CreatePen(PS_SOLID, 1, rgb);
break;
case CFU_UNDERLINEDOTTED:
hPen = CreatePen(PS_DOT, 1, rgb);
break;
default:
FIXME("Unknown underline type (%u)\n", s->fmt.bUnderlineType);
/* fall through */
case CFU_CF1UNDERLINE: /* this type is supported in the font, do nothing */
case CFU_UNDERLINENONE:
hPen = NULL;
break;
}
if (hPen)
{
hOldPen = SelectObject(hDC, hPen);
}
ExtSelectClipRgn( hDC, clip, RGN_COPY );
ExtSelectClipRgn( hDC, sel_rgn, RGN_AND );
draw_text( c, run, x, y - yOffset, TRUE, &sel_rect );
ExtSelectClipRgn( hDC, clip, RGN_COPY );
if (clip) DeleteObject( clip );
DeleteObject( sel_rgn );
}
rgbOld = SetTextColor(hDC, rgb);
if (bHighlightedText && !c->editor->bEmulateVersion10)
{
COLORREF rgbBackOld;
RECT dim;
/* FIXME: should use textmetrics info for Descent info */
if (hPen)
MoveToEx(hDC, x, y - yOffset + 1, NULL);
if (xSelStart > x)
{
ExtTextOutW(hDC, x, y-yOffset, 0, NULL, szText, nSelFrom, NULL);
if (hPen)
LineTo(hDC, xSelStart, y - yOffset + 1);
}
dim.top = ymin;
dim.bottom = ymin + cy;
dim.left = xSelStart;
dim.right = xSelEnd;
SetTextColor(hDC, ITextHost_TxGetSysColor(c->editor->texthost,
COLOR_HIGHLIGHTTEXT));
rgbBackOld = SetBkColor(hDC, ITextHost_TxGetSysColor(c->editor->texthost,
COLOR_HIGHLIGHT));
ExtTextOutW(hDC, xSelStart, y-yOffset, ETO_OPAQUE, &dim,
szText+nSelFrom, nSelTo-nSelFrom, lpDx);
if (hPen)
LineTo(hDC, xSelEnd, y - yOffset + 1);
SetBkColor(hDC, rgbBackOld);
if (xSelEnd < x + width)
{
SetTextColor(hDC, rgb);
ExtTextOutW(hDC, xSelEnd, y-yOffset, 0, NULL, szText+nSelTo,
nChars-nSelTo, NULL);
if (hPen)
LineTo(hDC, x + width, y - yOffset + 1);
}
}
else
{
ExtTextOutW(hDC, x, y-yOffset, 0, NULL, szText, nChars, lpDx);
if (old_style_selected)
PatBlt( hDC, sel_rect.left, ymin, sel_rect.right - sel_rect.left, cy, DSTINVERT );
/* FIXME: should use textmetrics info for Descent info */
if (hPen)
{
MoveToEx(hDC, x, y - yOffset + 1, NULL);
LineTo(hDC, x + width, y - yOffset + 1);
}
if (bHighlightedText) /* v1.0 inverts the selection */
{
PatBlt(hDC, xSelStart, ymin, xSelEnd-xSelStart, cy, DSTINVERT);
}
}
if (hPen)
{
SelectObject(hDC, hOldPen);
DeleteObject(hPen);
}
SetTextColor(hDC, rgbOld);
ME_UnselectStyleFont(c, s, hOldFont);
ME_UnselectStyleFont(c, run->style, hOldFont);
}
static void ME_DebugWrite(HDC hDC, const POINT *pt, LPCWSTR szText) {
@ -388,7 +415,6 @@ static void ME_DrawRun(ME_Context *c, int x, int y, ME_DisplayItem *rundi, ME_Pa
ME_DisplayItem *start;
int runofs = run->nCharOfs+para->nCharOfs;
int nSelFrom, nSelTo;
const WCHAR wszSpace[] = {' ', 0};
if (run->nFlags & MERF_HIDDEN)
return;
@ -401,21 +427,20 @@ static void ME_DrawRun(ME_Context *c, int x, int y, ME_DisplayItem *rundi, ME_Pa
{
if (runofs >= nSelFrom && runofs < nSelTo)
{
ME_HighlightSpace(c, x, y, wszSpace, 1, run->style, 0, 0, 1,
c->pt.y + para->pt.y + start->member.row.pt.y,
start->member.row.nHeight);
draw_space( c, run, x, y, TRUE, FALSE,
c->pt.y + para->pt.y + start->member.row.pt.y,
start->member.row.nHeight );
}
return;
}
if (run->nFlags & (MERF_TAB | MERF_ENDCELL))
{
/* wszSpace is used instead of the tab character because otherwise
* an unwanted symbol can be inserted instead. */
ME_DrawTextWithStyle(c, x, y, wszSpace, 1, run->style, run->nWidth,
nSelFrom-runofs, nSelTo-runofs,
c->pt.y + para->pt.y + start->member.row.pt.y,
start->member.row.nHeight);
BOOL selected = runofs >= nSelFrom && runofs < nSelTo;
draw_space( c, run, x, y, selected, TRUE,
c->pt.y + para->pt.y + start->member.row.pt.y,
start->member.row.nHeight );
return;
}
@ -423,22 +448,9 @@ static void ME_DrawRun(ME_Context *c, int x, int y, ME_DisplayItem *rundi, ME_Pa
ME_DrawOLE(c, x, y, run, para, (runofs >= nSelFrom) && (runofs < nSelTo));
else
{
if (c->editor->cPasswordMask)
{
ME_String *szMasked = ME_MakeStringR(c->editor->cPasswordMask, run->strText->nLen);
ME_DrawTextWithStyle(c, x, y,
szMasked->szData, szMasked->nLen, run->style, run->nWidth,
nSelFrom-runofs,nSelTo-runofs,
c->pt.y + para->pt.y + start->member.row.pt.y,
start->member.row.nHeight);
ME_DestroyString(szMasked);
}
else
ME_DrawTextWithStyle(c, x, y,
run->strText->szData, run->strText->nLen, run->style, run->nWidth,
nSelFrom-runofs,nSelTo-runofs,
c->pt.y + para->pt.y + start->member.row.pt.y,
start->member.row.nHeight);
ME_DrawTextWithStyle(c, run, x, y, nSelFrom - runofs, nSelTo - runofs,
c->pt.y + para->pt.y + start->member.row.pt.y,
start->member.row.nHeight);
}
}
@ -947,13 +959,12 @@ static void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph)
c->pt.y + para->pt.y + run->pt.y + baseline, p, para);
if (me_debug)
{
/* I'm using %ls, hope wsprintfW is not going to use wrong (4-byte) WCHAR version */
const WCHAR wszRunDebug[] = {'[','%','d',':','%','x',']',' ','%','l','s',0};
WCHAR buf[2560];
POINT pt;
pt.x = c->pt.x + run->pt.x;
pt.y = c->pt.y + para->pt.y + run->pt.y;
wsprintfW(buf, wszRunDebug, no, p->member.run.nFlags, p->member.run.strText->szData);
wsprintfW(buf, wszRunDebug, no, p->member.run.nFlags, get_text( &p->member.run, 0 ));
ME_DebugWrite(c->hDC, &pt, buf);
}
break;
@ -1224,7 +1235,7 @@ void ME_EnsureVisible(ME_TextEditor *editor, ME_Cursor *pCursor)
if (editor->styleFlags & ES_AUTOHSCROLL)
{
x = pRun->pt.x + ME_PointFromChar(editor, pRun, pCursor->nOffset);
x = pRun->pt.x + ME_PointFromChar(editor, pRun, pCursor->nOffset, TRUE);
if (x > editor->horz_si.nPos + editor->sizeWindow.cx)
x = x + 1 - editor->sizeWindow.cx;
else if (x > editor->horz_si.nPos)

View file

@ -33,7 +33,7 @@ void ME_MakeFirstParagraph(ME_TextEditor *editor)
ME_DisplayItem *para = ME_MakeDI(diParagraph);
ME_DisplayItem *run;
ME_Style *style;
ME_String *eol_str;
int eol_len;
WCHAR cr_lf[] = {'\r','\n',0};
ME_InitContext(&c, editor, ITextHost_TxGetDC(editor->texthost));
@ -64,9 +64,13 @@ void ME_MakeFirstParagraph(ME_TextEditor *editor)
style = ME_MakeStyle(&cf);
text->pDefaultStyle = style;
eol_str = ME_MakeStringN(cr_lf, editor->bEmulateVersion10 ? 2 : 1);
run = ME_MakeRun(style, eol_str, MERF_ENDPARA);
eol_len = editor->bEmulateVersion10 ? 2 : 1;
para->member.para.text = ME_MakeStringN( cr_lf, eol_len );
run = ME_MakeRun(style, MERF_ENDPARA);
run->member.run.nCharOfs = 0;
run->member.run.len = eol_len;
run->member.run.para = &para->member.para;
ME_InsertBefore(text->pLast, para);
ME_InsertBefore(text->pLast, run);
@ -127,7 +131,7 @@ static BOOL ME_SetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, const
else
dwMask &= PFM_ALL2;
ME_AddUndoItem(editor, diUndoSetParagraphFormat, para);
add_undo_set_para_fmt( editor, &para->member.para );
copy = *para->member.para.pFmt;
@ -150,35 +154,31 @@ static BOOL ME_SetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, const
memcpy(para->member.para.pFmt->rgxTabs, pFmt->rgxTabs, pFmt->cTabCount*sizeof(LONG));
}
if (dwMask & (PFM_ALL2 & ~PFM_ALL))
{
/* PARAFORMAT2 fields */
#define EFFECTS_MASK (PFM_RTLPARA|PFM_KEEP|PFM_KEEPNEXT|PFM_PAGEBREAKBEFORE| \
PFM_NOLINENUMBER|PFM_NOWIDOWCONTROL|PFM_DONOTHYPHEN|PFM_SIDEBYSIDE| \
PFM_TABLE)
/* we take for granted that PFE_xxx is the hiword of the corresponding PFM_xxx */
if (dwMask & EFFECTS_MASK) {
para->member.para.pFmt->dwMask |= dwMask & EFFECTS_MASK;
para->member.para.pFmt->wEffects &= ~HIWORD(dwMask);
para->member.para.pFmt->wEffects |= pFmt->wEffects & HIWORD(dwMask);
}
/* we take for granted that PFE_xxx is the hiword of the corresponding PFM_xxx */
if (dwMask & EFFECTS_MASK)
{
para->member.para.pFmt->dwMask |= dwMask & EFFECTS_MASK;
para->member.para.pFmt->wEffects &= ~HIWORD(dwMask);
para->member.para.pFmt->wEffects |= pFmt->wEffects & HIWORD(dwMask);
}
#undef EFFECTS_MASK
COPY_FIELD(PFM_SPACEBEFORE, dySpaceBefore);
COPY_FIELD(PFM_SPACEAFTER, dySpaceAfter);
COPY_FIELD(PFM_LINESPACING, dyLineSpacing);
COPY_FIELD(PFM_STYLE, sStyle);
COPY_FIELD(PFM_LINESPACING, bLineSpacingRule);
COPY_FIELD(PFM_SHADING, wShadingWeight);
COPY_FIELD(PFM_SHADING, wShadingStyle);
COPY_FIELD(PFM_NUMBERINGSTART, wNumberingStart);
COPY_FIELD(PFM_NUMBERINGSTYLE, wNumberingStyle);
COPY_FIELD(PFM_NUMBERINGTAB, wNumberingTab);
COPY_FIELD(PFM_BORDER, wBorderSpace);
COPY_FIELD(PFM_BORDER, wBorderWidth);
COPY_FIELD(PFM_BORDER, wBorders);
}
COPY_FIELD(PFM_SPACEBEFORE, dySpaceBefore);
COPY_FIELD(PFM_SPACEAFTER, dySpaceAfter);
COPY_FIELD(PFM_LINESPACING, dyLineSpacing);
COPY_FIELD(PFM_STYLE, sStyle);
COPY_FIELD(PFM_LINESPACING, bLineSpacingRule);
COPY_FIELD(PFM_SHADING, wShadingWeight);
COPY_FIELD(PFM_SHADING, wShadingStyle);
COPY_FIELD(PFM_NUMBERINGSTART, wNumberingStart);
COPY_FIELD(PFM_NUMBERINGSTYLE, wNumberingStyle);
COPY_FIELD(PFM_NUMBERINGTAB, wNumberingTab);
COPY_FIELD(PFM_BORDER, wBorderSpace);
COPY_FIELD(PFM_BORDER, wBorderWidth);
COPY_FIELD(PFM_BORDER, wBorders);
para->member.para.pFmt->dwMask |= dwMask;
#undef COPY_FIELD
@ -191,14 +191,13 @@ static BOOL ME_SetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, const
/* split paragraph at the beginning of the run */
ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run,
ME_Style *style, ME_String *eol_str,
ME_Style *style, const WCHAR *eol_str, int eol_len,
int paraFlags)
{
ME_DisplayItem *next_para = NULL;
ME_DisplayItem *run_para = NULL;
ME_DisplayItem *new_para = ME_MakeDI(diParagraph);
ME_DisplayItem *end_run;
ME_UndoItem *undo = NULL;
int ofs, i;
ME_DisplayItem *pp;
int run_flags = MERF_ENDPARA;
@ -214,19 +213,21 @@ ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run,
} else { /* v1.0 - v3.0 */
assert(!(paraFlags & (MEPF_CELL|MEPF_ROWSTART|MEPF_ROWEND)));
}
end_run = ME_MakeRun(style, eol_str, run_flags);
assert(run->type == diRun);
run_para = ME_GetParagraph(run);
assert(run_para->member.para.pFmt->cbSize == sizeof(PARAFORMAT2));
new_para->member.para.text = ME_VSplitString( run_para->member.para.text, run->member.run.nCharOfs );
end_run = ME_MakeRun(style, run_flags);
ofs = end_run->member.run.nCharOfs = run->member.run.nCharOfs;
end_run->member.run.len = eol_len;
end_run->member.run.para = run->member.run.para;
ME_AppendString( run_para->member.para.text, eol_str, eol_len );
next_para = run_para->member.para.next_para;
assert(next_para == ME_FindItemFwd(run_para, diParagraphOrEnd));
undo = ME_AddUndoItem(editor, diUndoJoinParagraphs, NULL);
if (undo)
undo->nStart = run_para->member.para.nCharOfs + ofs;
add_undo_join_paras( editor, run_para->member.para.nCharOfs + ofs );
/* Update selection cursors to point to the correct paragraph. */
for (i = 0; i < editor->nCursors; i++) {
@ -241,10 +242,11 @@ ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run,
pp = run;
while(pp->type == diRun) {
pp->member.run.nCharOfs -= ofs;
pp->member.run.para = &new_para->member.para;
pp = ME_FindItemFwd(pp, diRunOrParagraphOrEnd);
}
new_para->member.para.nCharOfs = run_para->member.para.nCharOfs + ofs;
new_para->member.para.nCharOfs += eol_str->nLen;
new_para->member.para.nCharOfs += eol_len;
new_para->member.para.nFlags = MEPF_REWRAP;
/* FIXME initialize format style and call ME_SetParaFormat blah blah */
@ -311,7 +313,7 @@ ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run,
new_para->member.para.prev_para->member.para.nFlags |= MEPF_REWRAP;
/* we've added the end run, so we need to modify nCharOfs in the next paragraphs */
ME_PropagateCharOffset(next_para, eol_str->nLen);
ME_PropagateCharOffset(next_para, eol_len);
editor->nParagraphs++;
return new_para;
@ -322,12 +324,12 @@ ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run,
ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp,
BOOL keepFirstParaFormat)
{
ME_DisplayItem *pNext, *pFirstRunInNext, *pRun, *pTmp;
ME_DisplayItem *pNext, *pFirstRunInNext, *pRun, *pTmp, *pCell = NULL;
int i, shift;
ME_UndoItem *undo = NULL;
int end_len;
CHARFORMAT2W fmt;
ME_Cursor startCur, endCur;
ME_String *eol_str;
assert(tp->type == diParagraph);
assert(tp->member.para.next_para);
@ -342,7 +344,9 @@ ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp,
assert(pRun->type == diRun);
assert(pRun->member.run.nFlags & MERF_ENDPARA);
end_len = pRun->member.run.strText->nLen;
end_len = pRun->member.run.len;
eol_str = ME_VSplitString( tp->member.para.text, pRun->member.run.nCharOfs );
ME_AppendString( tp->member.para.text, pNext->member.para.text->szData, pNext->member.para.text->nLen );
/* null char format operation to store the original char format for the ENDPARA run */
ME_InitCharFormat2W(&fmt);
@ -353,20 +357,6 @@ ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp,
ME_PrevRun(&startCur.pPara, &startCur.pRun);
ME_SetCharFormat(editor, &startCur, &endCur, &fmt);
undo = ME_AddUndoItem(editor, diUndoSplitParagraph, pNext);
if (undo)
{
undo->nStart = pNext->member.para.nCharOfs - end_len;
undo->eol_str = pRun->member.run.strText;
pRun->member.run.strText = NULL; /* Avoid freeing the string */
}
if (!keepFirstParaFormat)
{
ME_AddUndoItem(editor, diUndoSetParagraphFormat, tp);
*tp->member.para.pFmt = *pNext->member.para.pFmt;
tp->member.para.border = pNext->member.para.border;
}
if (!editor->bEmulateVersion10) { /* v4.1 */
/* Table cell/row properties are always moved over from the removed para. */
tp->member.para.nFlags = pNext->member.para.nFlags;
@ -374,35 +364,35 @@ ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp,
/* Remove cell boundary if it is between the end paragraph run and the next
* paragraph display item. */
pTmp = pRun->next;
while (pTmp != pNext) {
for (pTmp = pRun->next; pTmp != pNext; pTmp = pTmp->next)
{
if (pTmp->type == diCell)
{
ME_Cell *pCell = &pTmp->member.cell;
if (undo)
{
assert(!(undo->di.member.para.nFlags & MEPF_ROWEND));
if (!(undo->di.member.para.nFlags & MEPF_ROWSTART))
undo->di.member.para.nFlags |= MEPF_CELL;
undo->di.member.para.pCell = ALLOC_OBJ(ME_DisplayItem);
*undo->di.member.para.pCell = *pTmp;
undo->di.member.para.pCell->next = NULL;
undo->di.member.para.pCell->prev = NULL;
undo->di.member.para.pCell->member.cell.next_cell = NULL;
undo->di.member.para.pCell->member.cell.prev_cell = NULL;
}
ME_Remove(pTmp);
if (pCell->prev_cell)
pCell->prev_cell->member.cell.next_cell = pCell->next_cell;
if (pCell->next_cell)
pCell->next_cell->member.cell.prev_cell = pCell->prev_cell;
ME_DestroyDisplayItem(pTmp);
pCell = pTmp;
break;
}
pTmp = pTmp->next;
}
}
add_undo_split_para( editor, &pNext->member.para, eol_str, pCell ? &pCell->member.cell : NULL );
if (pCell)
{
ME_Remove( pCell );
if (pCell->member.cell.prev_cell)
pCell->member.cell.prev_cell->member.cell.next_cell = pCell->member.cell.next_cell;
if (pCell->member.cell.next_cell)
pCell->member.cell.next_cell->member.cell.prev_cell = pCell->member.cell.prev_cell;
ME_DestroyDisplayItem( pCell );
}
if (!keepFirstParaFormat)
{
add_undo_set_para_fmt( editor, &tp->member.para );
*tp->member.para.pFmt = *pNext->member.para.pFmt;
tp->member.para.border = pNext->member.para.border;
}
shift = pNext->member.para.nCharOfs - tp->member.para.nCharOfs - end_len;
pFirstRunInNext = ME_FindItemFwd(pNext, diRunOrParagraph);
@ -425,8 +415,9 @@ ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp,
pTmp = ME_FindItemFwd(pTmp, diRunOrParagraphOrEnd);
if (pTmp->type != diRun)
break;
TRACE("shifting \"%s\" by %d (previous %d)\n", debugstr_w(pTmp->member.run.strText->szData), shift, pTmp->member.run.nCharOfs);
TRACE("shifting %s by %d (previous %d)\n", debugstr_run( &pTmp->member.run ), shift, pTmp->member.run.nCharOfs);
pTmp->member.run.nCharOfs += shift;
pTmp->member.run.para = &tp->member.para;
} while(1);
ME_Remove(pRun);

View file

@ -300,7 +300,7 @@ IRichEditOle_fnGetClientSite(IRichEditOle *me,
if(!lplpolesite)
return E_INVALIDARG;
*lplpolesite = &This->clientSite->IOleClientSite_iface;
IOleClientSite_fnAddRef(*lplpolesite);
IOleClientSite_AddRef(*lplpolesite);
return S_OK;
}
@ -448,21 +448,21 @@ ITextDocument_fnQueryInterface(ITextDocument* me, REFIID riid,
void** ppvObject)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
return IRichEditOle_fnQueryInterface(&This->IRichEditOle_iface, riid, ppvObject);
return IRichEditOle_QueryInterface(&This->IRichEditOle_iface, riid, ppvObject);
}
static ULONG WINAPI
ITextDocument_fnAddRef(ITextDocument* me)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
return IRichEditOle_fnAddRef(&This->IRichEditOle_iface);
return IRichEditOle_AddRef(&This->IRichEditOle_iface);
}
static ULONG WINAPI
ITextDocument_fnRelease(ITextDocument* me)
{
IRichEditOleImpl *This = impl_from_ITextDocument(me);
return IRichEditOle_fnRelease(&This->IRichEditOle_iface);
return IRichEditOle_Release(&This->IRichEditOle_iface);
}
static HRESULT WINAPI

View file

@ -64,7 +64,7 @@ void ME_PropagateCharOffset(ME_DisplayItem *p, int shift)
*/
if (p->type == diRun) /* propagate in all runs in this para */
{
TRACE("PropagateCharOffset(%s, %d)\n", debugstr_w(p->member.run.strText->szData), shift);
TRACE("PropagateCharOffset(%s, %d)\n", debugstr_run( &p->member.run ), shift);
do {
p->member.run.nCharOfs += shift;
assert(p->member.run.nCharOfs >= 0);
@ -121,14 +121,14 @@ 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 = %08x\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.len, debugstr_run( &p->member.run ),
p->member.run.nFlags,
p->member.run.style->fmt.dwMask & p->member.run.style->fmt.dwEffects);
assert(ofs == p->member.run.nCharOfs);
assert(p->member.run.strText->nLen);
ofs += p->member.run.strText->nLen;
assert(p->member.run.len);
ofs += p->member.run.len;
break;
case diCell:
TRACE_(richedit_check)("cell\n");
@ -226,11 +226,11 @@ void ME_JoinRuns(ME_TextEditor *editor, ME_DisplayItem *p)
for (i=0; i<editor->nCursors; i++) {
if (editor->pCursors[i].pRun == pNext) {
editor->pCursors[i].pRun = p;
editor->pCursors[i].nOffset += p->member.run.strText->nLen;
editor->pCursors[i].nOffset += p->member.run.len;
}
}
ME_AppendString(p->member.run.strText, pNext->member.run.strText);
p->member.run.len += pNext->member.run.len;
ME_Remove(pNext);
ME_DestroyDisplayItem(pNext);
ME_UpdateRunFlags(editor, &p->member.run);
@ -242,54 +242,6 @@ 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_WrapContext *wc, ME_DisplayItem *item, int nVChar)
{
ME_TextEditor *editor = wc->context->editor;
ME_Run *run, *run2;
ME_Paragraph *para = &wc->pPara->member.para;
ME_Cursor cursor = {wc->pPara, item, nVChar};
assert(item->member.run.nCharOfs != -1);
if(TRACE_ON(richedit))
{
TRACE("Before check before split\n");
ME_CheckCharOffsets(editor);
TRACE("After check before split\n");
}
run = &item->member.run;
TRACE("Before split: %s(%d, %d)\n", debugstr_w(run->strText->szData),
run->pt.x, run->pt.y);
ME_SplitRunSimple(editor, &cursor);
run2 = &cursor.pRun->member.run;
ME_CalcRunExtent(wc->context, para, wc->nRow ? wc->nLeftMargin : wc->nFirstMargin, run);
run2->pt.x = run->pt.x+run->nWidth;
run2->pt.y = run->pt.y;
if(TRACE_ON(richedit))
{
TRACE("Before check after split\n");
ME_CheckCharOffsets(editor);
TRACE("After check after split\n");
TRACE("After split: %s(%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);
}
return cursor.pRun;
}
/******************************************************************************
* ME_SplitRunSimple
*
@ -306,10 +258,11 @@ ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_Cursor *cursor)
assert(!(run->member.run.nFlags & MERF_NONTEXT));
new_run = ME_MakeRun(run->member.run.style,
ME_VSplitString(run->member.run.strText, nOffset),
run->member.run.nFlags & MERF_SPLITMASK);
new_run->member.run.nCharOfs = run->member.run.nCharOfs + nOffset;
new_run->member.run.len = run->member.run.len - nOffset;
new_run->member.run.para = run->member.run.para;
run->member.run.len = nOffset;
cursor->pRun = new_run;
cursor->nOffset = 0;
@ -333,14 +286,15 @@ ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_Cursor *cursor)
*
* A helper function to create run structures quickly.
*/
ME_DisplayItem *ME_MakeRun(ME_Style *s, ME_String *strData, int nFlags)
ME_DisplayItem *ME_MakeRun(ME_Style *s, int nFlags)
{
ME_DisplayItem *item = ME_MakeDI(diRun);
item->member.run.style = s;
item->member.run.ole_obj = NULL;
item->member.run.strText = strData;
item->member.run.nFlags = nFlags;
item->member.run.nCharOfs = -1;
item->member.run.len = 0;
item->member.run.para = NULL;
ME_AddRefStyle(s);
return item;
}
@ -357,20 +311,18 @@ 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)
ME_SplitRunSimple(editor, cursor);
pUI = ME_AddUndoItem(editor, diUndoDeleteRun, NULL);
if (pUI) {
pUI->nStart = cursor->pPara->member.para.nCharOfs
+ cursor->pRun->member.run.nCharOfs;
pUI->nLen = len;
}
add_undo_delete_run( editor, cursor->pPara->member.para.nCharOfs +
cursor->pRun->member.run.nCharOfs, len );
pDI = ME_MakeRun(style, ME_MakeStringN(str, len), flags);
pDI = ME_MakeRun(style, flags);
pDI->member.run.nCharOfs = cursor->pRun->member.run.nCharOfs;
pDI->member.run.len = len;
pDI->member.run.para = cursor->pRun->member.run.para;
ME_InsertString( pDI->member.run.para->text, pDI->member.run.nCharOfs, str, len );
ME_InsertBefore(cursor->pRun, pDI);
TRACE("Shift length:%d\n", len);
ME_PropagateCharOffset(cursor->pRun, len);
@ -378,6 +330,35 @@ ME_InsertRunAtCursor(ME_TextEditor *editor, ME_Cursor *cursor, ME_Style *style,
return pDI;
}
static BOOL run_is_splittable( const ME_Run *run )
{
WCHAR *str = get_text( run, 0 ), *p;
int i;
BOOL found_ink = FALSE;
for (i = 0, p = str; i < run->len; i++, p++)
{
if (ME_IsWSpace( *p ))
{
if (found_ink) return TRUE;
}
else
found_ink = TRUE;
}
return FALSE;
}
static BOOL run_is_entirely_ws( const ME_Run *run )
{
WCHAR *str = get_text( run, 0 ), *p;
int i;
for (i = 0, p = str; i < run->len; i++, p++)
if (!ME_IsWSpace( *p )) return FALSE;
return TRUE;
}
/******************************************************************************
* ME_UpdateRunFlags
*
@ -387,7 +368,6 @@ ME_InsertRunAtCursor(ME_TextEditor *editor, ME_Cursor *cursor, ME_Style *style,
*/
void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run)
{
ME_String *strText = run->strText;
assert(run->nCharOfs >= 0);
if (RUN_IS_HIDDEN(run) || run->nFlags & MERF_TABLESTART)
@ -395,24 +375,25 @@ void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run)
else
run->nFlags &= ~MERF_HIDDEN;
if (ME_IsSplitable(strText))
if (run_is_splittable( run ))
run->nFlags |= MERF_SPLITTABLE;
else
run->nFlags &= ~MERF_SPLITTABLE;
if (!(run->nFlags & MERF_NOTEXT)) {
if (ME_IsWhitespaces(strText))
if (!(run->nFlags & MERF_NOTEXT))
{
if (run_is_entirely_ws( run ))
run->nFlags |= MERF_WHITESPACE | MERF_STARTWHITE | MERF_ENDWHITE;
else
{
run->nFlags &= ~MERF_WHITESPACE;
if (ME_IsWSpace(strText->szData[0]))
if (ME_IsWSpace( *get_text( run, 0 ) ))
run->nFlags |= MERF_STARTWHITE;
else
run->nFlags &= ~MERF_STARTWHITE;
if (ME_IsWSpace(strText->szData[strText->nLen - 1]))
if (ME_IsWSpace( *get_text( run, run->len - 1 ) ))
run->nFlags |= MERF_ENDWHITE;
else
run->nFlags &= ~MERF_ENDWHITE;
@ -423,119 +404,77 @@ void ME_UpdateRunFlags(ME_TextEditor *editor, 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_Context *c, int cx, ME_Run *run)
{
int fit = 0;
HGDIOBJ hOldFont;
SIZE sz;
if (!run->strText->nLen || cx <= 0)
return 0;
if (run->nFlags & MERF_TAB ||
(run->nFlags & (MERF_ENDCELL|MERF_ENDPARA)) == MERF_ENDCELL)
{
if (cx < run->nWidth/2)
return 0;
return 1;
}
if (run->nFlags & MERF_GRAPHICS)
{
SIZE sz;
ME_GetOLEObjectSize(c, run, &sz);
if (cx < sz.cx)
return 0;
return 1;
}
hOldFont = ME_SelectStyleFont(c, run->style);
if (c->editor->cPasswordMask)
{
ME_String *strMasked = ME_MakeStringR(c->editor->cPasswordMask, run->strText->nLen);
GetTextExtentExPointW(c->hDC, strMasked->szData, run->strText->nLen,
cx, &fit, NULL, &sz);
ME_DestroyString(strMasked);
}
else
{
GetTextExtentExPointW(c->hDC, run->strText->szData, run->strText->nLen,
cx, &fit, NULL, &sz);
}
ME_UnselectStyleFont(c, run->style, hOldFont);
return fit;
}
/******************************************************************************
* ME_CharFromPointCursor
* ME_CharFromPointContext
*
* 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).
* pixel horizontal position.
*
* It is used for mouse click handling, for better usability (and compatibility
* with the native control).
* If closest is FALSE return the actual character
* If closest is TRUE will round to the closest leading edge.
* ie. if the second character is at pixel position 8 and third at 16 then for:
* closest = FALSE cx = 0..7 return 0, cx = 8..15 return 1
* closest = TRUE cx = 0..3 return 0, cx = 4..11 return 1.
*/
int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run)
int ME_CharFromPointContext(ME_Context *c, int cx, ME_Run *run, BOOL closest, BOOL visual_order)
{
ME_String *strRunText;
/* This could point to either the run's real text, or it's masked form in a password control */
ME_String *mask_text = NULL;
WCHAR *str;
int fit = 0;
ME_Context c;
HGDIOBJ hOldFont;
SIZE sz, sz2, sz3;
if (!run->strText->nLen || cx <= 0)
if (!run->len || cx <= 0)
return 0;
if (run->nFlags & (MERF_TAB | MERF_ENDCELL))
{
if (cx < run->nWidth/2)
return 0;
if (!closest || cx < run->nWidth / 2) return 0;
return 1;
}
ME_InitContext(&c, editor, ITextHost_TxGetDC(editor->texthost));
if (run->nFlags & MERF_GRAPHICS)
{
SIZE sz;
ME_GetOLEObjectSize(&c, run, &sz);
ME_DestroyContext(&c);
if (cx < sz.cx/2)
return 0;
ME_GetOLEObjectSize(c, run, &sz);
if (!closest || cx < sz.cx / 2) return 0;
return 1;
}
if (editor->cPasswordMask)
strRunText = ME_MakeStringR(editor->cPasswordMask, run->strText->nLen);
else
strRunText = run->strText;
hOldFont = ME_SelectStyleFont(&c, run->style);
GetTextExtentExPointW(c.hDC, strRunText->szData, strRunText->nLen,
cx, &fit, NULL, &sz);
if (fit != strRunText->nLen)
if (c->editor->cPasswordMask)
{
GetTextExtentPoint32W(c.hDC, strRunText->szData, fit, &sz2);
GetTextExtentPoint32W(c.hDC, strRunText->szData, fit + 1, &sz3);
mask_text = ME_MakeStringR( c->editor->cPasswordMask, run->len );
str = mask_text->szData;
}
else
str = get_text( run, 0 );
hOldFont = ME_SelectStyleFont(c, run->style);
GetTextExtentExPointW(c->hDC, str, run->len,
cx, &fit, NULL, &sz);
if (closest && fit != run->len)
{
GetTextExtentPoint32W(c->hDC, str, fit, &sz2);
GetTextExtentPoint32W(c->hDC, str, fit + 1, &sz3);
if (cx >= (sz2.cx+sz3.cx)/2)
fit = fit + 1;
}
if (editor->cPasswordMask)
ME_DestroyString(strRunText);
ME_DestroyString( mask_text );
ME_UnselectStyleFont(&c, run->style, hOldFont);
ME_DestroyContext(&c);
ME_UnselectStyleFont(c, run->style, hOldFont);
return fit;
}
int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run, BOOL closest, BOOL visual_order)
{
ME_Context c;
int ret;
ME_InitContext( &c, editor, ITextHost_TxGetDC( editor->texthost ) );
ret = ME_CharFromPointContext( &c, cx, run, closest, visual_order );
ME_DestroyContext(&c);
return ret;
}
/******************************************************************************
* ME_GetTextExtent
*
@ -555,52 +494,67 @@ static void ME_GetTextExtent(ME_Context *c, LPCWSTR szText, int nChars, ME_Style
}
/******************************************************************************
* ME_PointFromChar
* ME_PointFromCharContext
*
* 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)
int ME_PointFromCharContext(ME_Context *c, ME_Run *pRun, int nOffset, BOOL visual_order)
{
SIZE size;
ME_Context c;
ME_String *strRunText;
/* This could point to either the run's real text, or it's masked form in a password control */
ME_String *mask_text = NULL;
WCHAR *str;
ME_InitContext(&c, editor, ITextHost_TxGetDC(editor->texthost));
if (pRun->nFlags & MERF_GRAPHICS)
{
if (nOffset)
ME_GetOLEObjectSize(&c, pRun, &size);
ME_DestroyContext(&c);
ME_GetOLEObjectSize(c, pRun, &size);
return nOffset != 0;
} else if (pRun->nFlags & MERF_ENDPARA) {
nOffset = 0;
}
if (editor->cPasswordMask)
strRunText = ME_MakeStringR(editor->cPasswordMask, pRun->strText->nLen);
if (c->editor->cPasswordMask)
{
mask_text = ME_MakeStringR(c->editor->cPasswordMask, pRun->len);
str = mask_text->szData;
}
else
strRunText = pRun->strText;
str = get_text( pRun, 0 );
ME_GetTextExtent(&c, strRunText->szData, nOffset, pRun->style, &size);
ME_DestroyContext(&c);
if (editor->cPasswordMask)
ME_DestroyString(strRunText);
ME_GetTextExtent(c, str, nOffset, pRun->style, &size);
ME_DestroyString( mask_text );
return size.cx;
}
/******************************************************************************
* ME_PointFromChar
*
* Calls ME_PointFromCharContext after first creating a context.
*/
int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset, BOOL visual_order)
{
ME_Context c;
int ret;
ME_InitContext(&c, editor, ITextHost_TxGetDC(editor->texthost));
ret = ME_PointFromCharContext( &c, pRun, nOffset, visual_order );
ME_DestroyContext(&c);
return ret;
}
/******************************************************************************
* ME_GetRunSizeCommon
*
* Finds width, height, ascent and descent of a run, up to given character
* (nLen).
*/
static SIZE ME_GetRunSizeCommon(ME_Context *c, const ME_Paragraph *para, ME_Run *run, int nLen,
int startx, int *pAscent, int *pDescent)
SIZE ME_GetRunSizeCommon(ME_Context *c, const ME_Paragraph *para, ME_Run *run, int nLen,
int startx, int *pAscent, int *pDescent)
{
SIZE size;
int nMaxLen = run->strText->nLen;
int nMaxLen = run->len;
if (nLen>nMaxLen)
nLen = nMaxLen;
@ -618,7 +572,7 @@ static SIZE ME_GetRunSizeCommon(ME_Context *c, const ME_Paragraph *para, ME_Run
}
else
{
ME_GetTextExtent(c, run->strText->szData, nLen, run->style, &size);
ME_GetTextExtent(c, get_text( run, 0 ), nLen, run->style, &size);
}
*pAscent = run->style->tm.tmAscent;
*pDescent = run->style->tm.tmDescent;
@ -667,41 +621,6 @@ static SIZE ME_GetRunSizeCommon(ME_Context *c, const ME_Paragraph *para, ME_Run
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, const ME_Paragraph *para,
ME_Run *run, int nLen, int startx)
{
int asc, desc;
return ME_GetRunSizeCommon(c, para, run, nLen, startx, &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, const ME_Paragraph *para, int startx, ME_Run *run)
{
if (run->nFlags & MERF_HIDDEN)
run->nWidth = 0;
else
{
int nEnd = run->strText->nLen;
SIZE size = ME_GetRunSizeCommon(c, para, run, nEnd, startx,
&run->nAscent, &run->nDescent);
run->nWidth = size.cx;
if (!size.cx)
WARN("size.cx == 0\n");
}
}
/******************************************************************************
* ME_SetSelectionCharFormat
*
@ -769,19 +688,12 @@ void ME_SetCharFormat(ME_TextEditor *editor, ME_Cursor *start, ME_Cursor *end, C
while(run != end_run)
{
ME_UndoItem *undo = NULL;
ME_Style *new_style = ME_ApplyStyle(run->member.run.style, pFmt);
/* ME_DumpStyle(new_style); */
undo = ME_AddUndoItem(editor, diUndoSetCharFormat, NULL);
if (undo) {
undo->nStart = run->member.run.nCharOfs+para->member.para.nCharOfs;
undo->nLen = run->member.run.strText->nLen;
undo->di.member.ustyle = run->member.run.style;
/* we'd have to addref undo...ustyle and release tmp...style
but they'd cancel each other out so we can do nothing instead */
}
else
ME_ReleaseStyle(run->member.run.style);
add_undo_set_char_fmt( editor, para->member.para.nCharOfs + run->member.run.nCharOfs,
run->member.run.len, &run->member.run.style->fmt );
ME_ReleaseStyle(run->member.run.style);
run->member.run.style = new_style;
run = ME_FindItemFwd(run, diRunOrParagraph);
if (run && run->type == diParagraph)

View file

@ -59,11 +59,6 @@ ME_String *ME_MakeStringR(WCHAR cRepeat, int nMaxChars)
return s;
}
ME_String *ME_StrDup(const ME_String *s)
{
return ME_MakeStringN(s->szData, s->nLen);
}
void ME_DestroyString(ME_String *s)
{
if (!s) return;
@ -71,25 +66,28 @@ void ME_DestroyString(ME_String *s)
FREE_OBJ(s);
}
void ME_AppendString(ME_String *s1, const ME_String *s2)
BOOL ME_InsertString(ME_String *s, int ofs, const WCHAR *insert, int len)
{
if (s1->nLen+s2->nLen+1 <= s1->nBuffer)
{
memcpy(s1->szData + s1->nLen, s2->szData, s2->nLen * sizeof(WCHAR));
s1->nLen += s2->nLen;
s1->szData[s1->nLen] = 0;
} else {
WCHAR *buf;
s1->nBuffer = ME_GetOptimalBuffer(s1->nLen+s2->nLen+1);
DWORD new_len = s->nLen + len + 1;
assert( ofs <= s->nLen );
buf = ALLOC_N_OBJ(WCHAR, s1->nBuffer);
memcpy(buf, s1->szData, s1->nLen * sizeof(WCHAR));
memcpy(buf + s1->nLen, s2->szData, s2->nLen * sizeof(WCHAR));
FREE_OBJ(s1->szData);
s1->szData = buf;
s1->nLen += s2->nLen;
s1->szData[s1->nLen] = 0;
}
if( new_len > s->nBuffer )
{
s->nBuffer = ME_GetOptimalBuffer( new_len );
s->szData = heap_realloc( s->szData, s->nBuffer * sizeof(WCHAR) );
if (!s->szData) return FALSE;
}
memmove( s->szData + ofs + len, s->szData + ofs, (s->nLen - ofs + 1) * sizeof(WCHAR) );
memcpy( s->szData + ofs, insert, len * sizeof(WCHAR) );
s->nLen += len;
return TRUE;
}
BOOL ME_AppendString(ME_String *s, const WCHAR *append, int len)
{
return ME_InsertString( s, s->nLen, append, len );
}
ME_String *ME_VSplitString(ME_String *orig, int charidx)
@ -108,34 +106,6 @@ ME_String *ME_VSplitString(ME_String *orig, int charidx)
return s;
}
int ME_IsWhitespaces(const ME_String *s)
{
/* FIXME multibyte */
WCHAR *pos = s->szData;
while(ME_IsWSpace(*pos++))
;
pos--;
if (*pos)
return 0;
else
return 1;
}
int ME_IsSplitable(const ME_String *s)
{
WCHAR *pos = s->szData;
WCHAR ch;
while(ME_IsWSpace(*pos++))
;
pos--;
while((ch = *pos++) != 0)
{
if (ME_IsWSpace(ch))
return 1;
}
return 0;
}
void ME_StrDeleteV(ME_String *s, int nVChar, int nChars)
{
int end_ofs = nVChar + nChars;
@ -149,33 +119,6 @@ void ME_StrDeleteV(ME_String *s, int nVChar, int nChars)
s->nLen -= nChars;
}
int ME_FindNonWhitespaceV(const ME_String *s, int nVChar) {
int i;
for (i = nVChar; i<s->nLen && ME_IsWSpace(s->szData[i]); i++)
;
return i;
}
/* note: returns offset of the first trailing whitespace */
int ME_ReverseFindNonWhitespaceV(const ME_String *s, int nVChar) {
int i;
for (i = nVChar; i>0 && ME_IsWSpace(s->szData[i-1]); i--)
;
return i;
}
/* note: returns offset of the first trailing nonwhitespace */
int ME_ReverseFindWhitespaceV(const ME_String *s, int nVChar) {
int i;
for (i = nVChar; i>0 && !ME_IsWSpace(s->szData[i-1]); i--)
;
return i;
}
static int
ME_WordBreakProc(LPWSTR s, INT start, INT len, INT code)
{
@ -208,22 +151,22 @@ ME_WordBreakProc(LPWSTR s, INT start, INT len, INT code)
int
ME_CallWordBreakProc(ME_TextEditor *editor, ME_String *str, INT start, INT code)
ME_CallWordBreakProc(ME_TextEditor *editor, WCHAR *str, INT len, INT start, INT code)
{
if (!editor->pfnWordBreak) {
return ME_WordBreakProc(str->szData, start, str->nLen*sizeof(WCHAR), code);
return ME_WordBreakProc(str, start, len * sizeof(WCHAR), code);
} else if (!editor->bEmulateVersion10) {
/* MSDN lied about the third parameter for EditWordBreakProc being the number
* of characters, it is actually the number of bytes of the string. */
return editor->pfnWordBreak(str->szData, start, str->nLen*sizeof(WCHAR), code);
return editor->pfnWordBreak(str, start, len * sizeof(WCHAR), code);
} else {
int result;
int buffer_size = WideCharToMultiByte(CP_ACP, 0, str->szData, str->nLen,
int buffer_size = WideCharToMultiByte(CP_ACP, 0, str, len,
NULL, 0, NULL, NULL);
char *buffer = heap_alloc(buffer_size);
WideCharToMultiByte(CP_ACP, 0, str->szData, str->nLen,
WideCharToMultiByte(CP_ACP, 0, str, len,
buffer, buffer_size, NULL, NULL);
result = editor->pfnWordBreak(str->szData, start, str->nLen, code);
result = editor->pfnWordBreak((WCHAR*)buffer, start, buffer_size, code);
heap_free(buffer);
return result;
}

View file

@ -58,7 +58,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(richedit_lists);
static ME_DisplayItem* ME_InsertEndParaFromCursor(ME_TextEditor *editor,
int nCursor,
ME_String *eol_str,
const WCHAR *eol_str, int eol_len,
int paraFlags)
{
ME_Style *pStyle = ME_GetInsertStyle(editor, nCursor);
@ -67,7 +67,7 @@ static ME_DisplayItem* ME_InsertEndParaFromCursor(ME_TextEditor *editor,
if (cursor->nOffset)
ME_SplitRunSimple(editor, cursor);
tp = ME_SplitParagraph(editor, cursor->pRun, pStyle, eol_str, paraFlags);
tp = ME_SplitParagraph(editor, cursor->pRun, pStyle, eol_str, eol_len, paraFlags);
ME_ReleaseStyle(pStyle);
cursor->pPara = tp;
cursor->pRun = ME_FindItemFwd(tp, diRun);
@ -78,8 +78,7 @@ ME_DisplayItem* ME_InsertTableRowStartFromCursor(ME_TextEditor *editor)
{
ME_DisplayItem *para;
WCHAR cr_lf[] = {'\r', '\n', 0};
ME_String *eol_str = ME_MakeStringN(cr_lf, 2);
para = ME_InsertEndParaFromCursor(editor, 0, eol_str, MEPF_ROWSTART);
para = ME_InsertEndParaFromCursor(editor, 0, cr_lf, 2, MEPF_ROWSTART);
return para->member.para.prev_para;
}
@ -122,8 +121,7 @@ ME_DisplayItem* ME_InsertTableCellFromCursor(ME_TextEditor *editor)
{
ME_DisplayItem *para;
WCHAR tab = '\t';
ME_String *eol_str = ME_MakeStringN(&tab, 1);
para = ME_InsertEndParaFromCursor(editor, 0, eol_str, MEPF_CELL);
para = ME_InsertEndParaFromCursor(editor, 0, &tab, 1, MEPF_CELL);
return para;
}
@ -131,8 +129,7 @@ ME_DisplayItem* ME_InsertTableRowEndFromCursor(ME_TextEditor *editor)
{
ME_DisplayItem *para;
WCHAR cr_lf[] = {'\r', '\n', 0};
ME_String *eol_str = ME_MakeStringN(cr_lf, 2);
para = ME_InsertEndParaFromCursor(editor, 0, eol_str, MEPF_ROWEND);
para = ME_InsertEndParaFromCursor(editor, 0, cr_lf, 2, MEPF_ROWEND);
return para->member.para.prev_para;
}
@ -305,7 +302,7 @@ void ME_ProtectPartialTableDeletion(ME_TextEditor *editor, ME_Cursor *c, int *nC
- end_para->member.para.nCharOfs;
if (remaining)
{
assert(remaining < c2.pRun->member.run.strText->nLen);
assert(remaining < c2.pRun->member.run.len);
end_para = end_para->member.para.next_para;
}
}
@ -353,7 +350,7 @@ void ME_ProtectPartialTableDeletion(ME_TextEditor *editor, ME_Cursor *c, int *nC
{
ME_Run *end_run = &ME_FindItemBack(next_para, diRun)->member.run;
int nCharsNew = (next_para->member.para.nCharOfs - nOfs
- end_run->strText->nLen);
- end_run->len);
nCharsNew = max(nCharsNew, 0);
assert(nCharsNew <= *nChars);
*nChars = nCharsNew;

View file

@ -77,7 +77,7 @@ static HRESULT WINAPI ITextServicesImpl_QueryInterface(IUnknown *iface, REFIID r
if (IsEqualIID(riid, &IID_IUnknown))
*ppv = &This->IUnknown_inner;
else if IsEqualIID(riid, &IID_ITextServices)
else if (IsEqualIID(riid, &IID_ITextServices))
*ppv = &This->ITextServices_iface;
else {
*ppv = NULL;

View file

@ -22,150 +22,194 @@
WINE_DEFAULT_DEBUG_CHANNEL(richedit);
static void destroy_undo_item( struct undo_item *undo )
{
switch( undo->type )
{
case undo_insert_run:
heap_free( undo->u.insert_run.str );
ME_ReleaseStyle( undo->u.insert_run.style );
break;
case undo_split_para:
ME_DestroyString( undo->u.split_para.eol_str );
break;
default:
break;
}
heap_free( undo );
}
static void empty_redo_stack(ME_TextEditor *editor)
{
struct undo_item *cursor, *cursor2;
LIST_FOR_EACH_ENTRY_SAFE( cursor, cursor2, &editor->redo_stack, struct undo_item, entry )
{
list_remove( &cursor->entry );
destroy_undo_item( cursor );
}
}
void ME_EmptyUndoStack(ME_TextEditor *editor)
{
ME_DisplayItem *p, *pNext;
struct undo_item *cursor, *cursor2;
if (editor->nUndoMode == umIgnore)
return;
TRACE("Emptying undo stack\n");
p = editor->pUndoStack;
editor->pUndoStack = editor->pUndoStackBottom = NULL;
editor->nUndoStackSize = 0;
while(p) {
pNext = p->next;
ME_DestroyDisplayItem(p);
p = pNext;
}
p = editor->pRedoStack;
editor->pRedoStack = NULL;
while(p) {
pNext = p->next;
ME_DestroyDisplayItem(p);
p = pNext;
}
LIST_FOR_EACH_ENTRY_SAFE( cursor, cursor2, &editor->undo_stack, struct undo_item, entry )
{
list_remove( &cursor->entry );
destroy_undo_item( cursor );
}
empty_redo_stack( editor );
}
ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, const ME_DisplayItem *pdi) {
if (editor->nUndoMode == umIgnore)
return NULL;
else if (editor->nUndoLimit == 0)
return NULL;
else
{
ME_DisplayItem *pItem = ALLOC_OBJ(ME_UndoItem);
switch(type)
{
case diUndoPotentialEndTransaction:
/* only should be added for manually typed chars, not undos or redos */
assert(editor->nUndoMode == umAddToUndo);
/* intentional fall-through to next case */
case diUndoEndTransaction:
break;
case diUndoSetParagraphFormat:
assert(pdi);
pItem->member.para = pdi->member.para;
pItem->member.para.pFmt = ALLOC_OBJ(PARAFORMAT2);
*pItem->member.para.pFmt = *pdi->member.para.pFmt;
break;
case diUndoInsertRun:
assert(pdi);
pItem->member.run = pdi->member.run;
pItem->member.run.strText = ME_StrDup(pItem->member.run.strText);
ME_AddRefStyle(pItem->member.run.style);
if (pdi->member.run.ole_obj)
{
pItem->member.run.ole_obj = ALLOC_OBJ(*pItem->member.run.ole_obj);
ME_CopyReObject(pItem->member.run.ole_obj, pdi->member.run.ole_obj);
}
else pItem->member.run.ole_obj = NULL;
break;
case diUndoSetCharFormat:
break;
case diUndoDeleteRun:
case diUndoJoinParagraphs:
break;
case diUndoSplitParagraph:
{
ME_DisplayItem *prev_para = pdi->member.para.prev_para;
assert(pdi->member.para.pFmt->cbSize == sizeof(PARAFORMAT2));
pItem->member.para.pFmt = ALLOC_OBJ(PARAFORMAT2);
pItem->member.para.pFmt->cbSize = sizeof(PARAFORMAT2);
pItem->member.para.pFmt->dwMask = 0;
*pItem->member.para.pFmt = *pdi->member.para.pFmt;
pItem->member.para.border = pdi->member.para.border;
pItem->member.para.nFlags = prev_para->member.para.nFlags & ~MEPF_CELL;
pItem->member.para.pCell = NULL;
break;
}
default:
assert(0 == "AddUndoItem, unsupported item type");
return NULL;
}
pItem->type = type;
pItem->prev = NULL;
static struct undo_item *add_undo( ME_TextEditor *editor, enum undo_type type )
{
struct undo_item *undo, *item;
struct list *head;
if (editor->nUndoMode == umIgnore) return NULL;
if (editor->nUndoLimit == 0) return NULL;
undo = heap_alloc( sizeof(*undo) );
if (!undo) return NULL;
undo->type = type;
if (editor->nUndoMode == umAddToUndo || editor->nUndoMode == umAddBackToUndo)
{
if (editor->pUndoStack
&& editor->pUndoStack->type == diUndoPotentialEndTransaction)
{
editor->pUndoStack->type = diUndoEndTransaction;
}
if (editor->nUndoMode == umAddToUndo)
TRACE("Pushing id=%s to undo stack, deleting redo stack\n", ME_GetDITypeName(type));
else
TRACE("Pushing id=%s to undo stack\n", ME_GetDITypeName(type));
pItem->next = editor->pUndoStack;
if (type == diUndoEndTransaction || type == diUndoPotentialEndTransaction)
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
head = list_head( &editor->undo_stack );
if (head)
{
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;
while(p)
{
ME_DisplayItem *pp = p->next;
ME_DestroyDisplayItem(p);
p = pp;
item = LIST_ENTRY( head, struct undo_item, entry );
if (item->type == undo_potential_end_transaction)
item->type = undo_end_transaction;
}
editor->pRedoStack = NULL;
}
if (editor->nUndoMode == umAddToUndo)
TRACE("Pushing id=%d to undo stack, deleting redo stack\n", type);
else
TRACE("Pushing id=%d to undo stack\n", type);
list_add_head( &editor->undo_stack, &undo->entry );
if (type == undo_end_transaction || type == undo_potential_end_transaction)
editor->nUndoStackSize++;
if (editor->nUndoStackSize > editor->nUndoLimit)
{
struct undo_item *cursor2;
/* remove oldest undo from stack */
LIST_FOR_EACH_ENTRY_SAFE_REV( item, cursor2, &editor->undo_stack, struct undo_item, entry )
{
BOOL done = (item->type == undo_end_transaction);
list_remove( &item->entry );
destroy_undo_item( item );
if (done) break;
}
editor->nUndoStackSize--;
}
/* any new operation (not redo) clears the redo stack */
if (editor->nUndoMode == umAddToUndo) empty_redo_stack( editor );
}
else if (editor->nUndoMode == umAddToRedo)
{
TRACE("Pushing id=%s to redo stack\n", ME_GetDITypeName(type));
pItem->next = editor->pRedoStack;
if (editor->pRedoStack)
editor->pRedoStack->prev = pItem;
editor->pRedoStack = pItem;
TRACE("Pushing id=%d to redo stack\n", type);
list_add_head( &editor->redo_stack, &undo->entry );
}
else
assert(0);
return (ME_UndoItem *)pItem;
}
return undo;
}
BOOL add_undo_insert_run( ME_TextEditor *editor, int pos, const WCHAR *str, int len, int flags, ME_Style *style )
{
struct undo_item *undo = add_undo( editor, undo_insert_run );
if (!undo) return FALSE;
undo->u.insert_run.str = heap_alloc( (len + 1) * sizeof(WCHAR) );
if (!undo->u.insert_run.str)
{
ME_EmptyUndoStack( editor );
return FALSE;
}
memcpy( undo->u.insert_run.str, str, len * sizeof(WCHAR) );
undo->u.insert_run.str[len] = 0;
undo->u.insert_run.pos = pos;
undo->u.insert_run.len = len;
undo->u.insert_run.flags = flags;
undo->u.insert_run.style = style;
ME_AddRefStyle( style );
return TRUE;
}
BOOL add_undo_set_para_fmt( ME_TextEditor *editor, const ME_Paragraph *para )
{
struct undo_item *undo = add_undo( editor, undo_set_para_fmt );
if (!undo) return FALSE;
undo->u.set_para_fmt.pos = para->nCharOfs;
undo->u.set_para_fmt.fmt = *para->pFmt;
undo->u.set_para_fmt.border = para->border;
return TRUE;
}
BOOL add_undo_set_char_fmt( ME_TextEditor *editor, int pos, int len, const CHARFORMAT2W *fmt )
{
struct undo_item *undo = add_undo( editor, undo_set_char_fmt );
if (!undo) return FALSE;
undo->u.set_char_fmt.pos = pos;
undo->u.set_char_fmt.len = len;
undo->u.set_char_fmt.fmt = *fmt;
return TRUE;
}
BOOL add_undo_join_paras( ME_TextEditor *editor, int pos )
{
struct undo_item *undo = add_undo( editor, undo_join_paras );
if (!undo) return FALSE;
undo->u.join_paras.pos = pos;
return TRUE;
}
BOOL add_undo_split_para( ME_TextEditor *editor, const ME_Paragraph *para, ME_String *eol_str, const ME_Cell *cell )
{
struct undo_item *undo = add_undo( editor, undo_split_para );
if (!undo) return FALSE;
undo->u.split_para.pos = para->nCharOfs - eol_str->nLen;
undo->u.split_para.eol_str = eol_str;
undo->u.split_para.fmt = *para->pFmt;
undo->u.split_para.border = para->border;
undo->u.split_para.flags = para->prev_para->member.para.nFlags & ~MEPF_CELL;
if (cell)
{
undo->u.split_para.cell_border = cell->border;
undo->u.split_para.cell_right_boundary = cell->nRightBoundary;
}
return TRUE;
}
BOOL add_undo_delete_run( ME_TextEditor *editor, int pos, int len )
{
struct undo_item *undo = add_undo( editor, undo_delete_run );
if (!undo) return FALSE;
undo->u.delete_run.pos = pos;
undo->u.delete_run.len = len;
return TRUE;
}
/**
@ -180,29 +224,31 @@ ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, const ME_Disp
* This can also be used to conclude a coalescing transaction (used for grouping
* typed characters).
*/
void ME_CommitUndo(ME_TextEditor *editor) {
void ME_CommitUndo(ME_TextEditor *editor)
{
struct undo_item *item;
struct list *head;
if (editor->nUndoMode == umIgnore)
return;
assert(editor->nUndoMode == umAddToUndo);
/* no transactions, no need to commit */
if (!editor->pUndoStack)
return;
head = list_head( &editor->undo_stack );
if (!head) return;
/* no need to commit empty transactions */
if (editor->pUndoStack->type == diUndoEndTransaction)
return;
if (editor->pUndoStack->type == diUndoPotentialEndTransaction)
item = LIST_ENTRY( head, struct undo_item, entry );
if (item->type == undo_end_transaction) return;
if (item->type == undo_potential_end_transaction)
{
/* Previous transaction was as a result of characters typed,
* so the end of this transaction is confirmed. */
editor->pUndoStack->type = diUndoEndTransaction;
item->type = undo_end_transaction;
return;
}
ME_AddUndoItem(editor, diUndoEndTransaction, NULL);
add_undo( editor, undo_end_transaction );
}
/**
@ -218,21 +264,23 @@ void ME_CommitUndo(ME_TextEditor *editor) {
*/
void ME_ContinueCoalescingTransaction(ME_TextEditor *editor)
{
ME_DisplayItem* p;
struct undo_item *item;
struct list *head;
if (editor->nUndoMode == umIgnore)
return;
assert(editor->nUndoMode == umAddToUndo);
p = editor->pUndoStack;
head = list_head( &editor->undo_stack );
if (!head) return;
if (p && p->type == diUndoPotentialEndTransaction) {
assert(p->next); /* EndTransactions shouldn't be at bottom of undo stack */
editor->pUndoStack = p->next;
editor->pUndoStack->prev = NULL;
item = LIST_ENTRY( head, struct undo_item, entry );
if (item->type == undo_potential_end_transaction)
{
list_remove( &item->entry );
editor->nUndoStackSize--;
ME_DestroyDisplayItem(p);
destroy_undo_item( item );
}
}
@ -252,92 +300,91 @@ void ME_ContinueCoalescingTransaction(ME_TextEditor *editor)
*/
void ME_CommitCoalescingUndo(ME_TextEditor *editor)
{
struct undo_item *item;
struct list *head;
if (editor->nUndoMode == umIgnore)
return;
assert(editor->nUndoMode == umAddToUndo);
/* no transactions, no need to commit */
if (!editor->pUndoStack)
return;
head = list_head( &editor->undo_stack );
if (!head) return;
/* no need to commit empty transactions */
if (editor->pUndoStack->type == diUndoEndTransaction)
return;
if (editor->pUndoStack->type == diUndoPotentialEndTransaction)
return;
item = LIST_ENTRY( head, struct undo_item, entry );
if (item->type == undo_end_transaction ||
item->type == undo_potential_end_transaction)
return;
ME_AddUndoItem(editor, diUndoPotentialEndTransaction, NULL);
add_undo( editor, undo_potential_end_transaction );
}
static void ME_PlayUndoItem(ME_TextEditor *editor, ME_DisplayItem *pItem)
static void ME_PlayUndoItem(ME_TextEditor *editor, struct undo_item *undo)
{
ME_UndoItem *pUItem = (ME_UndoItem *)pItem;
if (editor->nUndoMode == umIgnore)
return;
TRACE("Playing undo/redo item, id=%s\n", ME_GetDITypeName(pItem->type));
TRACE("Playing undo/redo item, id=%d\n", undo->type);
switch(pItem->type)
switch(undo->type)
{
case diUndoPotentialEndTransaction:
case diUndoEndTransaction:
case undo_potential_end_transaction:
case undo_end_transaction:
assert(0);
case diUndoSetParagraphFormat:
case undo_set_para_fmt:
{
ME_Cursor tmp;
ME_DisplayItem *para;
ME_CursorFromCharOfs(editor, pItem->member.para.nCharOfs, &tmp);
ME_CursorFromCharOfs(editor, undo->u.set_para_fmt.pos, &tmp);
para = ME_FindItemBack(tmp.pRun, diParagraph);
ME_AddUndoItem(editor, diUndoSetParagraphFormat, para);
*para->member.para.pFmt = *pItem->member.para.pFmt;
para->member.para.border = pItem->member.para.border;
add_undo_set_para_fmt( editor, &para->member.para );
*para->member.para.pFmt = undo->u.set_para_fmt.fmt;
para->member.para.border = undo->u.set_para_fmt.border;
break;
}
case diUndoSetCharFormat:
case undo_set_char_fmt:
{
ME_Cursor start, end;
ME_CursorFromCharOfs(editor, pUItem->nStart, &start);
ME_CursorFromCharOfs(editor, undo->u.set_char_fmt.pos, &start);
end = start;
ME_MoveCursorChars(editor, &end, pUItem->nLen);
ME_SetCharFormat(editor, &start, &end, &pItem->member.ustyle->fmt);
ME_MoveCursorChars(editor, &end, undo->u.set_char_fmt.len);
ME_SetCharFormat(editor, &start, &end, &undo->u.set_char_fmt.fmt);
break;
}
case diUndoInsertRun:
case undo_insert_run:
{
ME_Cursor tmp;
ME_CursorFromCharOfs(editor, pItem->member.run.nCharOfs, &tmp);
ME_InsertRunAtCursor(editor, &tmp, pItem->member.run.style,
pItem->member.run.strText->szData,
pItem->member.run.strText->nLen,
pItem->member.run.nFlags);
ME_CursorFromCharOfs(editor, undo->u.insert_run.pos, &tmp);
ME_InsertRunAtCursor(editor, &tmp, undo->u.insert_run.style,
undo->u.insert_run.str,
undo->u.insert_run.len,
undo->u.insert_run.flags);
break;
}
case diUndoDeleteRun:
case undo_delete_run:
{
ME_Cursor tmp;
ME_CursorFromCharOfs(editor, pUItem->nStart, &tmp);
ME_InternalDeleteText(editor, &tmp, pUItem->nLen, TRUE);
ME_CursorFromCharOfs(editor, undo->u.delete_run.pos, &tmp);
ME_InternalDeleteText(editor, &tmp, undo->u.delete_run.len, TRUE);
break;
}
case diUndoJoinParagraphs:
case undo_join_paras:
{
ME_Cursor tmp;
ME_CursorFromCharOfs(editor, pUItem->nStart, &tmp);
/* the only thing that's needed is paragraph offset, so no need to split runs */
ME_CursorFromCharOfs(editor, undo->u.join_paras.pos, &tmp);
ME_JoinParagraphs(editor, tmp.pPara, TRUE);
break;
}
case diUndoSplitParagraph:
case undo_split_para:
{
ME_Cursor tmp;
ME_DisplayItem *this_para, *new_para;
BOOL bFixRowStart;
int paraFlags = pItem->member.para.nFlags & (MEPF_ROWSTART|MEPF_CELL|MEPF_ROWEND);
ME_CursorFromCharOfs(editor, pUItem->nStart, &tmp);
int paraFlags = undo->u.split_para.flags & (MEPF_ROWSTART|MEPF_CELL|MEPF_ROWEND);
ME_CursorFromCharOfs(editor, undo->u.split_para.pos, &tmp);
if (tmp.nOffset)
ME_SplitRunSimple(editor, &tmp);
assert(pUItem->eol_str);
this_para = tmp.pPara;
bFixRowStart = this_para->member.para.nFlags & MEPF_ROWSTART;
if (bFixRowStart)
@ -347,58 +394,54 @@ static void ME_PlayUndoItem(ME_TextEditor *editor, ME_DisplayItem *pItem)
this_para->member.para.nFlags &= ~MEPF_ROWSTART;
}
new_para = ME_SplitParagraph(editor, tmp.pRun, tmp.pRun->member.run.style,
pUItem->eol_str, paraFlags);
undo->u.split_para.eol_str->szData, undo->u.split_para.eol_str->nLen, paraFlags);
if (bFixRowStart)
new_para->member.para.nFlags |= MEPF_ROWSTART;
assert(pItem->member.para.pFmt->cbSize == sizeof(PARAFORMAT2));
*new_para->member.para.pFmt = *pItem->member.para.pFmt;
new_para->member.para.border = pItem->member.para.border;
if (pItem->member.para.pCell)
*new_para->member.para.pFmt = undo->u.split_para.fmt;
new_para->member.para.border = undo->u.split_para.border;
if (paraFlags)
{
ME_DisplayItem *pItemCell, *pCell;
pItemCell = pItem->member.para.pCell;
pCell = new_para->member.para.pCell;
pCell->member.cell.nRightBoundary = pItemCell->member.cell.nRightBoundary;
pCell->member.cell.border = pItemCell->member.cell.border;
ME_DisplayItem *pCell = new_para->member.para.pCell;
pCell->member.cell.nRightBoundary = undo->u.split_para.cell_right_boundary;
pCell->member.cell.border = undo->u.split_para.cell_border;
}
break;
}
default:
assert(0 == "PlayUndoItem, unexpected type");
}
}
BOOL ME_Undo(ME_TextEditor *editor) {
ME_DisplayItem *p;
BOOL ME_Undo(ME_TextEditor *editor)
{
ME_UndoMode nMode = editor->nUndoMode;
if (editor->nUndoMode == umIgnore)
return FALSE;
struct list *head;
struct undo_item *undo, *cursor2;
if (editor->nUndoMode == umIgnore) return FALSE;
assert(nMode == umAddToUndo || nMode == umIgnore);
/* no undo items ? */
if (!editor->pUndoStack)
return FALSE;
head = list_head( &editor->undo_stack );
if (!head) return FALSE;
/* watch out for uncommitted transactions ! */
assert(editor->pUndoStack->type == diUndoEndTransaction
|| editor->pUndoStack->type == diUndoPotentialEndTransaction);
undo = LIST_ENTRY( head, struct undo_item, entry );
assert(undo->type == undo_end_transaction
|| undo->type == undo_potential_end_transaction);
editor->nUndoMode = umAddToRedo;
p = editor->pUndoStack->next;
ME_DestroyDisplayItem(editor->pUndoStack);
editor->pUndoStack = p;
do {
p->prev = NULL;
ME_PlayUndoItem(editor, p);
editor->pUndoStack = p->next;
ME_DestroyDisplayItem(p);
p = editor->pUndoStack;
} while(p && p->type != diUndoEndTransaction);
if (p)
p->prev = NULL;
list_remove( &undo->entry );
destroy_undo_item( undo );
LIST_FOR_EACH_ENTRY_SAFE( undo, cursor2, &editor->undo_stack, struct undo_item, entry )
{
if (undo->type == undo_end_transaction) break;
ME_PlayUndoItem( editor, undo );
list_remove( &undo->entry );
destroy_undo_item( undo );
}
ME_MoveCursorFromTableRowStartParagraph(editor);
ME_AddUndoItem(editor, diUndoEndTransaction, NULL);
add_undo( editor, undo_end_transaction );
ME_CheckTablesForCorruption(editor);
editor->nUndoStackSize--;
editor->nUndoMode = nMode;
@ -406,36 +449,36 @@ BOOL ME_Undo(ME_TextEditor *editor) {
return TRUE;
}
BOOL ME_Redo(ME_TextEditor *editor) {
ME_DisplayItem *p;
BOOL ME_Redo(ME_TextEditor *editor)
{
ME_UndoMode nMode = editor->nUndoMode;
struct list *head;
struct undo_item *undo, *cursor2;
assert(nMode == umAddToUndo || nMode == umIgnore);
if (editor->nUndoMode == umIgnore)
return FALSE;
/* no redo items ? */
if (!editor->pRedoStack)
return FALSE;
if (editor->nUndoMode == umIgnore) return FALSE;
head = list_head( &editor->redo_stack );
if (!head) return FALSE;
/* watch out for uncommitted transactions ! */
assert(editor->pRedoStack->type == diUndoEndTransaction);
undo = LIST_ENTRY( head, struct undo_item, entry );
assert( undo->type == undo_end_transaction );
editor->nUndoMode = umAddBackToUndo;
p = editor->pRedoStack->next;
ME_DestroyDisplayItem(editor->pRedoStack);
editor->pRedoStack = p;
do {
p->prev = NULL;
ME_PlayUndoItem(editor, p);
editor->pRedoStack = p->next;
ME_DestroyDisplayItem(p);
p = editor->pRedoStack;
} while(p && p->type != diUndoEndTransaction);
if (p)
p->prev = NULL;
list_remove( &undo->entry );
destroy_undo_item( undo );
LIST_FOR_EACH_ENTRY_SAFE( undo, cursor2, &editor->redo_stack, struct undo_item, entry )
{
if (undo->type == undo_end_transaction) break;
ME_PlayUndoItem( editor, undo );
list_remove( &undo->entry );
destroy_undo_item( undo );
}
ME_MoveCursorFromTableRowStartParagraph(editor);
ME_AddUndoItem(editor, diUndoEndTransaction, NULL);
add_undo( editor, undo_end_transaction );
ME_CheckTablesForCorruption(editor);
editor->nUndoMode = nMode;
ME_UpdateRepaint(editor, FALSE);

View file

@ -32,6 +32,84 @@ WINE_DEFAULT_DEBUG_CHANNEL(richedit);
* - no tabs
*/
/******************************************************************************
* calc_run_extent
*
* 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.
*/
static void calc_run_extent(ME_Context *c, const ME_Paragraph *para, int startx, ME_Run *run)
{
if (run->nFlags & MERF_HIDDEN) run->nWidth = 0;
else
{
SIZE size = ME_GetRunSizeCommon( c, para, run, run->len, startx, &run->nAscent, &run->nDescent );
run->nWidth = size.cx;
}
}
/******************************************************************************
* split_run_extents
*
* Splits a run into two in a given place. It also updates the screen position
* and size (extent) of the newly generated runs.
*/
static ME_DisplayItem *split_run_extents(ME_WrapContext *wc, ME_DisplayItem *item, int nVChar)
{
ME_TextEditor *editor = wc->context->editor;
ME_Run *run, *run2;
ME_Paragraph *para = &wc->pPara->member.para;
ME_Cursor cursor = {wc->pPara, item, nVChar};
assert(item->member.run.nCharOfs != -1);
if(TRACE_ON(richedit))
{
TRACE("Before check before split\n");
ME_CheckCharOffsets(editor);
TRACE("After check before split\n");
}
run = &item->member.run;
TRACE("Before split: %s(%d, %d)\n", debugstr_run( run ),
run->pt.x, run->pt.y);
ME_SplitRunSimple(editor, &cursor);
run2 = &cursor.pRun->member.run;
calc_run_extent(wc->context, para, wc->nRow ? wc->nLeftMargin : wc->nFirstMargin, run);
run2->pt.x = run->pt.x+run->nWidth;
run2->pt.y = run->pt.y;
if(TRACE_ON(richedit))
{
TRACE("Before check after split\n");
ME_CheckCharOffsets(editor);
TRACE("After check after split\n");
TRACE("After split: %s(%d, %d), %s(%d, %d)\n",
debugstr_run( run ), run->pt.x, run->pt.y,
debugstr_run( run2 ), run2->pt.x, run2->pt.y);
}
return cursor.pRun;
}
/******************************************************************************
* find_split_point
*
* Returns a character position to split 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).
*/
static int find_split_point( ME_Context *c, int cx, ME_Run *run )
{
if (!run->len || cx <= 0) return 0;
return ME_CharFromPointContext( c, cx, run, FALSE, FALSE );
}
static ME_DisplayItem *ME_MakeRow(int height, int baseline, int width)
{
ME_DisplayItem *item = ME_MakeDI(diStartRow);
@ -110,9 +188,8 @@ static void ME_InsertRowStart(ME_WrapContext *wc, const ME_DisplayItem *pEnd)
{
/* Exclude space characters from run width.
* Other whitespace or delimiters are not treated this way. */
SIZE sz;
int len = p->member.run.strText->nLen;
WCHAR *text = p->member.run.strText->szData + len - 1;
int len = p->member.run.len;
WCHAR *text = get_text( &p->member.run, len - 1 );
assert (len);
if (~p->member.run.nFlags & MERF_GRAPHICS)
@ -120,14 +197,10 @@ static void ME_InsertRowStart(ME_WrapContext *wc, const ME_DisplayItem *pEnd)
len--;
if (len)
{
if (len == p->member.run.strText->nLen)
{
if (len == p->member.run.len)
width += p->member.run.nWidth;
} else {
sz = ME_GetRunSize(wc->context, &para->member.para,
&p->member.run, len, p->member.run.pt.x);
width += sz.cx;
}
else
width += ME_PointFromCharContext( wc->context, &p->member.run, len, FALSE );
}
bSkippingSpaces = !len;
} else if (!(p->member.run.nFlags & MERF_ENDPARA))
@ -155,6 +228,7 @@ static void ME_InsertRowStart(ME_WrapContext *wc, const ME_DisplayItem *pEnd)
shift = max((wc->nAvailWidth-width)/2, 0);
if (align == PFA_RIGHT)
shift = max(wc->nAvailWidth-width, 0);
row->member.row.pt.x = row->member.row.nLMargin + shift;
for (p = wc->pRowStart; p!=pEnd; p = p->next)
{
if (p->type==diRun) { /* FIXME add more run types */
@ -189,7 +263,7 @@ static void ME_WrapEndParagraph(ME_WrapContext *wc, ME_DisplayItem *p)
if (p->type == diRun)
{
ME_Run *run = &p->member.run;
TRACE("%s - (%d, %d)\n", debugstr_w(run->strText->szData), run->pt.x, run->pt.y);
TRACE("%s - (%d, %d)\n", debugstr_run(run), run->pt.x, run->pt.y);
}
p = p->next;
}
@ -202,8 +276,41 @@ static void ME_WrapSizeRun(ME_WrapContext *wc, ME_DisplayItem *p)
ME_UpdateRunFlags(wc->context->editor, &p->member.run);
ME_CalcRunExtent(wc->context, &wc->pPara->member.para,
wc->nRow ? wc->nLeftMargin : wc->nFirstMargin, &p->member.run);
calc_run_extent(wc->context, &wc->pPara->member.para,
wc->nRow ? wc->nLeftMargin : wc->nFirstMargin, &p->member.run);
}
static int find_non_whitespace(const WCHAR *s, int len, int start)
{
int i;
for (i = start; i < len && ME_IsWSpace( s[i] ); i++)
;
return i;
}
/* note: these two really return the first matching offset (starting from EOS)+1
* in other words, an offset of the first trailing white/black */
/* note: returns offset of the first trailing whitespace */
static int reverse_find_non_whitespace(const WCHAR *s, int start)
{
int i;
for (i = start; i > 0 && ME_IsWSpace( s[i - 1] ); i--)
;
return i;
}
/* note: returns offset of the first trailing nonwhitespace */
static int reverse_find_whitespace(const WCHAR *s, int start)
{
int i;
for (i = start; i > 0 && !ME_IsWSpace( s[i - 1] ); i--)
;
return i;
}
static ME_DisplayItem *ME_MaximizeSplit(ME_WrapContext *wc, ME_DisplayItem *p, int i)
@ -212,9 +319,9 @@ static ME_DisplayItem *ME_MaximizeSplit(ME_WrapContext *wc, ME_DisplayItem *p, i
int j;
if (!i)
return NULL;
j = ME_ReverseFindNonWhitespaceV(p->member.run.strText, i);
j = reverse_find_non_whitespace( get_text( &p->member.run, 0 ), i);
if (j>0) {
pp = ME_SplitRun(wc, piter, j);
pp = split_run_extents(wc, piter, j);
wc->pt.x += piter->member.run.nWidth;
return pp;
}
@ -232,16 +339,16 @@ static ME_DisplayItem *ME_MaximizeSplit(ME_WrapContext *wc, ME_DisplayItem *p, i
}
if (piter->member.run.nFlags & MERF_ENDWHITE)
{
i = ME_ReverseFindNonWhitespaceV(piter->member.run.strText,
piter->member.run.strText->nLen);
pp = ME_SplitRun(wc, piter, i);
i = reverse_find_non_whitespace( get_text( &piter->member.run, 0 ),
piter->member.run.len );
pp = split_run_extents(wc, piter, i);
wc->pt = pp->member.run.pt;
return pp;
}
/* this run is the end of spaces, so the run edge is a good point to split */
wc->pt = pp->member.run.pt;
wc->bOverflown = TRUE;
TRACE("Split point is: %s|%s\n", debugstr_w(piter->member.run.strText->szData), debugstr_w(pp->member.run.strText->szData));
TRACE("Split point is: %s|%s\n", debugstr_run( &piter->member.run ), debugstr_run( &pp->member.run ));
return pp;
}
wc->pt = piter->member.run.pt;
@ -255,18 +362,18 @@ 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, loc, run);
len = run->strText->nLen;
idesp = i = find_split_point( wc->context, loc, run );
len = run->len;
assert(len>0);
assert(i<len);
if (i) {
/* don't split words */
i = ME_ReverseFindWhitespaceV(run->strText, i);
i = reverse_find_whitespace( get_text( run, 0 ), i );
pp = ME_MaximizeSplit(wc, p, i);
if (pp)
return pp;
}
TRACE("Must backtrack to split at: %s\n", debugstr_w(p->member.run.strText->szData));
TRACE("Must backtrack to split at: %s\n", debugstr_run( &p->member.run ));
if (wc->pLastSplittableRun)
{
if (wc->pLastSplittableRun->member.run.nFlags & (MERF_GRAPHICS|MERF_TAB))
@ -283,13 +390,13 @@ static ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem
piter = wc->pLastSplittableRun;
run = &piter->member.run;
len = run->strText->nLen;
len = run->len;
/* don't split words */
i = ME_ReverseFindWhitespaceV(run->strText, len);
i = reverse_find_whitespace( get_text( run, 0 ), len );
if (i == len)
i = ME_ReverseFindNonWhitespaceV(run->strText, len);
i = reverse_find_non_whitespace( get_text( run, 0 ), len );
if (i) {
ME_DisplayItem *piter2 = ME_SplitRun(wc, piter, i);
ME_DisplayItem *piter2 = split_run_extents(wc, piter, i);
wc->pt = piter2->member.run.pt;
return piter2;
}
@ -303,10 +410,10 @@ static ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem
return wc->pLastSplittableRun;
}
}
TRACE("Backtracking failed, trying desperate: %s\n", debugstr_w(p->member.run.strText->szData));
TRACE("Backtracking failed, trying desperate: %s\n", debugstr_run( &p->member.run ));
/* OK, no better idea, so assume we MAY split words if we can split at all*/
if (idesp)
return ME_SplitRun(wc, piter, idesp);
return split_run_extents(wc, piter, idesp);
else
if (wc->pRowStart && piter != wc->pRowStart)
{
@ -320,7 +427,7 @@ static ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem
/* split point inside first character - no choice but split after that char */
if (len != 1) {
/* the run is more than 1 char, so we may split */
return ME_SplitRun(wc, piter, 1);
return split_run_extents(wc, piter, 1);
}
/* the run is one char, can't split it */
return piter;
@ -340,7 +447,7 @@ static ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
run->pt.x = wc->pt.x;
run->pt.y = wc->pt.y;
ME_WrapSizeRun(wc, p);
len = run->strText->nLen;
len = run->len;
if (wc->bOverflown) /* just skipping final whitespaces */
{
@ -357,13 +464,13 @@ static ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
if (run->nFlags & MERF_STARTWHITE) {
/* try to split the run at the first non-white char */
int black;
black = ME_FindNonWhitespaceV(run->strText, 0);
black = find_non_whitespace( get_text( run, 0 ), run->len, 0 );
if (black) {
wc->bOverflown = FALSE;
pp = ME_SplitRun(wc, p, black);
ME_CalcRunExtent(wc->context, &wc->pPara->member.para,
wc->nRow ? wc->nLeftMargin : wc->nFirstMargin,
&pp->member.run);
pp = split_run_extents(wc, p, black);
calc_run_extent(wc->context, &wc->pPara->member.para,
wc->nRow ? wc->nLeftMargin : wc->nFirstMargin,
&pp->member.run);
ME_InsertRowStart(wc, pp);
return pp;
}
@ -410,8 +517,8 @@ static ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
if (run->nFlags & MERF_ENDWHITE)
{
/* we aren't sure if it's *really* necessary, it's a good start however */
int black = ME_ReverseFindNonWhitespaceV(run->strText, len);
ME_SplitRun(wc, p, black);
int black = reverse_find_non_whitespace( get_text( run, 0 ), len );
split_run_extents(wc, p, black);
/* handle both parts again */
return p;
}

View file

@ -297,20 +297,23 @@ ME_StreamOutRTFFontAndColorTbl(ME_OutStream *pStream, ME_DisplayItem *pFirstRun,
if (!ME_StreamOutPrint(pStream, "}\r\n"))
return FALSE;
/* Output colors table if not empty */
if (pStream->nColorTblLen > 1) {
if (!ME_StreamOutPrint(pStream, "{\\colortbl;"))
return FALSE;
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(pStream, "}"))
/* It seems like Open Office ignores \deff0 tag at RTF-header.
As result it can't correctly parse text before first \fN tag,
so we can put \f0 immediately after font table. This forces
parser to use the same font, that \deff0 specifies.
It makes OOffice happy */
if (!ME_StreamOutPrint(pStream, "\\f0"))
return FALSE;
/* Output the color table */
if (!ME_StreamOutPrint(pStream, "{\\colortbl;")) return FALSE; /* first entry is auto-color */
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(pStream, "}")) return FALSE;
return TRUE;
}
@ -677,7 +680,7 @@ ME_StreamOutRTFCharProps(ME_OutStream *pStream, CHARFORMAT2W *fmt)
break;
case CFU_UNDERLINENONE:
default:
strcat(props, "\\ul0");
strcat(props, "\\ulnone");
break;
}
else if (fmt->dwEffects & CFE_UNDERLINE)
@ -870,7 +873,7 @@ static BOOL ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream,
return FALSE;
}
/* Skip as many characters as required by current line break */
nChars = max(0, nChars - cursor.pRun->member.run.strText->nLen);
nChars = max(0, nChars - cursor.pRun->member.run.len);
} else if (cursor.pRun->member.run.nFlags & MERF_ENDROW) {
if (!ME_StreamOutPrint(pStream, "\\line \r\n"))
return FALSE;
@ -884,8 +887,8 @@ static BOOL ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream,
if (!ME_StreamOutRTFCharProps(pStream, &cursor.pRun->member.run.style->fmt))
return FALSE;
nEnd = (cursor.pRun == endCur.pRun) ? endCur.nOffset : cursor.pRun->member.run.strText->nLen;
if (!ME_StreamOutRTFText(pStream, cursor.pRun->member.run.strText->szData + cursor.nOffset,
nEnd = (cursor.pRun == endCur.pRun) ? endCur.nOffset : cursor.pRun->member.run.len;
if (!ME_StreamOutRTFText(pStream, get_text( &cursor.pRun->member.run, cursor.nOffset ),
nEnd - cursor.nOffset))
return FALSE;
cursor.nOffset = 0;
@ -919,7 +922,7 @@ static BOOL ME_StreamOutText(ME_TextEditor *editor, ME_OutStream *pStream,
/* TODO: Handle SF_TEXTIZED */
while (success && nChars && cursor.pRun) {
nLen = min(nChars, cursor.pRun->member.run.strText->nLen - cursor.nOffset);
nLen = min(nChars, cursor.pRun->member.run.len - cursor.nOffset);
if (!editor->bEmulateVersion10 && cursor.pRun->member.run.nFlags & MERF_ENDPARA)
{
@ -932,19 +935,19 @@ static BOOL ME_StreamOutText(ME_TextEditor *editor, ME_OutStream *pStream,
success = ME_StreamOutMove(pStream, "\r\n", 2);
} else {
if (dwFormat & SF_UNICODE)
success = ME_StreamOutMove(pStream, (const char *)(cursor.pRun->member.run.strText->szData + cursor.nOffset),
success = ME_StreamOutMove(pStream, (const char *)(get_text( &cursor.pRun->member.run, cursor.nOffset )),
sizeof(WCHAR) * nLen);
else {
int nSize;
nSize = WideCharToMultiByte(nCodePage, 0, cursor.pRun->member.run.strText->szData + cursor.nOffset,
nSize = WideCharToMultiByte(nCodePage, 0, get_text( &cursor.pRun->member.run, cursor.nOffset ),
nLen, NULL, 0, NULL, NULL);
if (nSize > nBufLen) {
FREE_OBJ(buffer);
buffer = ALLOC_N_OBJ(char, nSize);
nBufLen = nSize;
}
WideCharToMultiByte(nCodePage, 0, cursor.pRun->member.run.strText->szData + cursor.nOffset,
WideCharToMultiByte(nCodePage, 0, get_text( &cursor.pRun->member.run, cursor.nOffset ),
nLen, buffer, nSize, NULL, NULL);
success = ME_StreamOutMove(pStream, buffer, nSize);
}

View file

@ -161,7 +161,7 @@ reactos/dll/win32/qmgrprxy # Synced to Wine-1.5.26
reactos/dll/win32/query # Synced to Wine-1.7.1
reactos/dll/win32/rasapi32 # Synced to Wine-1.5.4
reactos/dll/win32/resutils # Synced to Wine-1.5.19
reactos/dll/win32/riched20 # Synced to Wine-1.5.19
reactos/dll/win32/riched20 # Synced to Wine-1.7.1
reactos/dll/win32/riched32 # Synced to Wine-1.5.19
reactos/dll/win32/rpcrt4 # Synced to Wine-1.3.26
reactos/dll/win32/rsabase # Autosync