From bda34393bb64200ed2d7c1d0955289c68cf236db Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Thu, 26 Sep 2013 16:32:14 +0000 Subject: [PATCH] [RICHED20] * Sync with Wine 1.7.1. CORE-7469 svn path=/trunk/; revision=60369 --- reactos/dll/win32/riched20/CMakeLists.txt | 16 +- reactos/dll/win32/riched20/caret.c | 266 ++++------- reactos/dll/win32/riched20/editor.c | 131 +++--- reactos/dll/win32/riched20/editor.h | 42 +- reactos/dll/win32/riched20/editstr.h | 94 +++- reactos/dll/win32/riched20/list.c | 35 +- reactos/dll/win32/riched20/paint.c | 417 ++++++++--------- reactos/dll/win32/riched20/para.c | 147 +++--- reactos/dll/win32/riched20/richole.c | 8 +- reactos/dll/win32/riched20/run.c | 350 ++++++-------- reactos/dll/win32/riched20/string.c | 111 ++--- reactos/dll/win32/riched20/table.c | 17 +- reactos/dll/win32/riched20/txtsrv.c | 2 +- reactos/dll/win32/riched20/undo.c | 531 ++++++++++++---------- reactos/dll/win32/riched20/wrap.c | 183 ++++++-- reactos/dll/win32/riched20/writer.c | 43 +- reactos/media/doc/README.WINE | 2 +- 17 files changed, 1200 insertions(+), 1195 deletions(-) diff --git a/reactos/dll/win32/riched20/CMakeLists.txt b/reactos/dll/win32/riched20/CMakeLists.txt index 9a2e48baa7b..06af6874560 100644 --- a/reactos/dll/win32/riched20/CMakeLists.txt +++ b/reactos/dll/win32/riched20/CMakeLists.txt @@ -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) diff --git a/reactos/dll/win32/riched20/caret.c b/reactos/dll/win32/riched20/caret.c index 7decff2025f..b39a8c7e10d 100644 --- a/reactos/dll/win32/riched20/caret.c +++ b/reactos/dll/win32/riched20/caret.c @@ -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, ¶->member.para, - &run->member.run, run->member.run.strText->nLen, - row->member.row.nLMargin); } } - if (pCursor->nOffset) { - sz = ME_GetRunSize(&c, ¶->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; inCursors; 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); diff --git a/reactos/dll/win32/riched20/editor.c b/reactos/dll/win32/riched20/editor.c index f7aed7f15cb..e2837adc2e3 100644 --- a/reactos/dll/win32/riched20/editor.c +++ b/reactos/dll/win32/riched20/editor.c @@ -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 ((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(!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 ); + }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 ((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(!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 ); + }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; diff --git a/reactos/dll/win32/riched20/editor.h b/reactos/dll/win32/riched20/editor.h index d96145f342e..43f7e7dc146 100644 --- a/reactos/dll/win32/riched20/editor.h +++ b/reactos/dll/win32/riched20/editor.h @@ -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; diff --git a/reactos/dll/win32/riched20/editstr.h b/reactos/dll/win32/riched20/editstr.h index 885d491678e..627d37e7a7e 100644 --- a/reactos/dll/win32/riched20/editstr.h +++ b/reactos/dll/win32/riched20/editstr.h @@ -53,6 +53,7 @@ #include #include +#include #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; diff --git a/reactos/dll/win32/riched20/list.c b/reactos/dll/win32/riched20/list.c index bb91bc4de65..7722fc94e09 100644 --- a/reactos/dll/win32/riched20/list.c +++ b/reactos/dll/win32/riched20/list.c @@ -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: diff --git a/reactos/dll/win32/riched20/paint.c b/reactos/dll/win32/riched20/paint.c index f82802ab661..e728b47432a 100644 --- a/reactos/dll/win32/riched20/paint.c +++ b/reactos/dll/win32/riched20/paint.c @@ -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 void ME_DrawTextWithStyle(ME_Context *c, int x, int y, LPCWSTR szText, - int nChars, ME_Style *s, int width, - int nSelFrom, int nSelTo, int ymin, int cy) +static int calc_y_offset( const ME_Context *c, ME_Style *style ) { - 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 */ - - 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); + int offs = 0, twips = 0; - 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 (nSelFrom <= 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)) { - nSelFrom = 0; + 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 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) { - GetTextExtentPoint32W(hDC, szText, nSelFrom, &sz); - xSelStart = x + sz.cx; + 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; + } } - if (nSelTo >= nChars) + 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) { - nSelTo = nChars; - xSelEnd = x + width; + 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 ); } - else + 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) { - GetTextExtentPoint32W(hDC, szText+nSelFrom, nSelTo-nSelFrom, &sz); - xSelEnd = xSelStart + sz.cx; + old_style_selected = selected; + selected = FALSE; } - } - /* Choose the pen type for underlining the text. */ - if (s->fmt.dwMask & CFM_UNDERLINETYPE) - { - switch (s->fmt.bUnderlineType) + if (selected) + back_color = ITextHost_TxGetSysColor( c->editor->texthost, COLOR_HIGHLIGHT ); + + if (actually_draw) { - 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; + 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 ); } - if (hPen) + else if (selected) { - hOldPen = SelectObject(hDC, hPen); + HBRUSH brush = CreateSolidBrush( back_color ); + FillRect( hdc, &rect, brush ); + DeleteObject( brush ); } - } - 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) + 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) { - SetTextColor(hDC, rgb); - ExtTextOutW(hDC, xSelEnd, y-yOffset, 0, NULL, szText+nSelTo, - nChars-nSelTo, NULL); - if (hPen) - LineTo(hDC, x + width, y - yOffset + 1); + masked = ME_MakeStringR( c->editor->cPasswordMask, run->len ); + text = masked->szData; } - } - else + + 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; + 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; + + yOffset = calc_y_offset( c, run->style ); + + if (selected) { - ExtTextOutW(hDC, x, y-yOffset, 0, NULL, szText, nChars, lpDx); + get_selection_rect( c, run, nSelFrom, nSelTo, cy, &sel_rect ); + OffsetRect( &sel_rect, x, ymin ); - /* FIXME: should use textmetrics info for Descent info */ - if (hPen) + if (c->editor->bEmulateVersion10) { - MoveToEx(hDC, x, y - yOffset + 1, NULL); - LineTo(hDC, x + width, y - yOffset + 1); + old_style_selected = TRUE; + selected = FALSE; } - - if (bHighlightedText) /* v1.0 inverts the selection */ + else { - PatBlt(hDC, xSelStart, ymin, xSelEnd-xSelStart, cy, DSTINVERT); + sel_rgn = CreateRectRgnIndirect( &sel_rect ); + clip = CreateRectRgn( 0, 0, 0, 0 ); + if (GetClipRgn( hDC, clip ) != 1) + { + DeleteObject( clip ); + clip = NULL; + } } } - if (hPen) + 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) { - SelectObject(hDC, hOldPen); - DeleteObject(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 ); } - SetTextColor(hDC, rgbOld); - ME_UnselectStyleFont(c, s, hOldFont); + + if (old_style_selected) + PatBlt( hDC, sel_rect.left, ymin, sel_rect.right - sel_rect.left, cy, DSTINVERT ); + + 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) diff --git a/reactos/dll/win32/riched20/para.c b/reactos/dll/win32/riched20/para.c index ffa816de543..8cf3d241594 100644 --- a/reactos/dll/win32/riched20/para.c +++ b/reactos/dll/win32/riched20/para.c @@ -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 = ¶->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, ¶->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); diff --git a/reactos/dll/win32/riched20/richole.c b/reactos/dll/win32/riched20/richole.c index 5ec1f37c84b..97289d525b9 100644 --- a/reactos/dll/win32/riched20/richole.c +++ b/reactos/dll/win32/riched20/richole.c @@ -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 diff --git a/reactos/dll/win32/riched20/run.c b/reactos/dll/win32/riched20/run.c index 8a1f91fa926..8929fc536cb 100644 --- a/reactos/dll/win32/riched20/run.c +++ b/reactos/dll/win32/riched20/run.c @@ -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; inCursors; 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); + if (c->editor->cPasswordMask) + { + mask_text = ME_MakeStringR( c->editor->cPasswordMask, run->len ); + str = mask_text->szData; + } else - strRunText = run->strText; + str = get_text( run, 0 ); - hOldFont = ME_SelectStyleFont(&c, run->style); - GetTextExtentExPointW(c.hDC, strRunText->szData, strRunText->nLen, + hOldFont = ME_SelectStyleFont(c, run->style); + GetTextExtentExPointW(c->hDC, str, run->len, cx, &fit, NULL, &sz); - if (fit != strRunText->nLen) + if (closest && fit != run->len) { - GetTextExtentPoint32W(c.hDC, strRunText->szData, fit, &sz2); - GetTextExtentPoint32W(c.hDC, strRunText->szData, fit + 1, &sz3); + 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) diff --git a/reactos/dll/win32/riched20/string.c b/reactos/dll/win32/riched20/string.c index db45d928d64..6d7d222bde8 100644 --- a/reactos/dll/win32/riched20/string.c +++ b/reactos/dll/win32/riched20/string.c @@ -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); - - 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; - } + DWORD new_len = s->nLen + len + 1; + assert( ofs <= s->nLen ); + + 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; inLen && 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; } diff --git a/reactos/dll/win32/riched20/table.c b/reactos/dll/win32/riched20/table.c index 1182550679f..d5fbfcbd450 100644 --- a/reactos/dll/win32/riched20/table.c +++ b/reactos/dll/win32/riched20/table.c @@ -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; diff --git a/reactos/dll/win32/riched20/txtsrv.c b/reactos/dll/win32/riched20/txtsrv.c index 4771a310060..32032f14c20 100644 --- a/reactos/dll/win32/riched20/txtsrv.c +++ b/reactos/dll/win32/riched20/txtsrv.c @@ -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; diff --git a/reactos/dll/win32/riched20/undo.c b/reactos/dll/win32/riched20/undo.c index a101cc178c6..9db690eec6b 100644 --- a/reactos/dll/win32/riched20/undo.c +++ b/reactos/dll/win32/riched20/undo.c @@ -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; - } -} -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 + LIST_FOR_EACH_ENTRY_SAFE( cursor, cursor2, &editor->undo_stack, struct undo_item, entry ) { - 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; + list_remove( &cursor->entry ); + destroy_undo_item( cursor ); + } + + empty_redo_stack( editor ); +} + +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) + item = LIST_ENTRY( head, struct undo_item, entry ); + if (item->type == undo_potential_end_transaction) + item->type = undo_end_transaction; + } + + 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) { - ME_DisplayItem *pp = p->next; - ME_DestroyDisplayItem(p); - p = pp; + 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--; } - editor->pRedoStack = NULL; - } + + /* 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, ¶->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); diff --git a/reactos/dll/win32/riched20/wrap.c b/reactos/dll/win32/riched20/wrap.c index 8ac14f93536..52722dbf403 100644 --- a/reactos/dll/win32/riched20/wrap.c +++ b/reactos/dll/win32/riched20/wrap.c @@ -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, ¶->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(istrText, 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; } diff --git a/reactos/dll/win32/riched20/writer.c b/reactos/dll/win32/riched20/writer.c index 8a69545950b..0ac2decd8e9 100644 --- a/reactos/dll/win32/riched20/writer.c +++ b/reactos/dll/win32/riched20/writer.c @@ -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); } diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE index 684819ab3fb..453ecd490ac 100644 --- a/reactos/media/doc/README.WINE +++ b/reactos/media/doc/README.WINE @@ -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 -- 2.17.1