diff --git a/reactos/dll/win32/riched20/caret.c b/reactos/dll/win32/riched20/caret.c index 170363a48f1..26af743518f 100644 --- a/reactos/dll/win32/riched20/caret.c +++ b/reactos/dll/win32/riched20/caret.c @@ -31,11 +31,11 @@ void ME_SetCursorToStart(ME_TextEditor *editor, ME_Cursor *cursor) cursor->nOffset = 0; } -static void ME_SetCursorToEnd(ME_TextEditor *editor, ME_Cursor *cursor) +static void ME_SetCursorToEnd(ME_TextEditor *editor, ME_Cursor *cursor, BOOL final_eop) { cursor->pPara = editor->pBuffer->pLast->member.para.prev_para; cursor->pRun = ME_FindItemBack(editor->pBuffer->pLast, diRun); - cursor->nOffset = 0; + cursor->nOffset = final_eop ? cursor->pRun->member.run.len : 0; } @@ -83,7 +83,7 @@ int ME_GetSelection(ME_TextEditor *editor, ME_Cursor **from, ME_Cursor **to) int ME_GetTextLength(ME_TextEditor *editor) { ME_Cursor cursor; - ME_SetCursorToEnd(editor, &cursor); + ME_SetCursorToEnd(editor, &cursor, FALSE); return ME_GetCursorOfs(&cursor); } @@ -138,8 +138,7 @@ int ME_SetSelection(ME_TextEditor *editor, int from, int to) if (from == 0 && to == -1) { ME_SetCursorToStart(editor, &editor->pCursors[1]); - ME_SetCursorToEnd(editor, &editor->pCursors[0]); - editor->pCursors[0].nOffset = editor->pCursors[0].pRun->member.run.len; + ME_SetCursorToEnd(editor, &editor->pCursors[0], TRUE); ME_InvalidateSelection(editor); return len + 1; } @@ -193,7 +192,7 @@ int ME_SetSelection(ME_TextEditor *editor, int from, int to) if (selectionEnd) { - ME_SetCursorToEnd(editor, &editor->pCursors[0]); + ME_SetCursorToEnd(editor, &editor->pCursors[0], FALSE); editor->pCursors[1] = editor->pCursors[0]; ME_InvalidateSelection(editor); return len; @@ -201,7 +200,7 @@ int ME_SetSelection(ME_TextEditor *editor, int from, int to) ME_CursorFromCharOfs(editor, from, &editor->pCursors[1]); editor->pCursors[0] = editor->pCursors[1]; - ME_MoveCursorChars(editor, &editor->pCursors[0], to - from); + ME_MoveCursorChars(editor, &editor->pCursors[0], to - from, FALSE); /* Selection is not allowed in the middle of an end paragraph run. */ if (editor->pCursors[1].pRun->member.run.nFlags & MERF_ENDPARA) editor->pCursors[1].nOffset = 0; @@ -445,7 +444,7 @@ BOOL ME_InternalDeleteText(ME_TextEditor *editor, ME_Cursor *start, continue; } } - if (delete_all) ME_SetDefaultParaFormat( editor, start_para->member.para.pFmt ); + if (delete_all) ME_SetDefaultParaFormat( editor, &start_para->member.para.fmt ); return TRUE; } @@ -550,7 +549,6 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, pos++; } else { /* handle EOLs */ ME_DisplayItem *tp, *end_run, *run, *prev; - ME_Style *tmp_style; int eol_len = 0; /* Find number of CR and LF in end of paragraph run */ @@ -595,13 +593,9 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, run = p->pRun; } - tmp_style = ME_GetInsertStyle(editor, nCursor); - /* ME_SplitParagraph increases style refcount */ - tp = ME_SplitParagraph(editor, run, run->member.run.style, eol_str, eol_len, 0); + tp = ME_SplitParagraph(editor, run, style, eol_str, eol_len, 0); end_run = ME_FindItemBack(tp, diRun); - ME_ReleaseStyle(end_run->member.run.style); - end_run->member.run.style = tmp_style; /* Move any cursors that were at the end of the previous run to the beginning of the new para */ prev = ME_FindItemBack( end_run, diRun ); @@ -628,10 +622,11 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, } /* Move the cursor nRelOfs characters (either forwards or backwards) + * If final_eop is TRUE, allow moving the cursor to the end of the final eop. * * returns the actual number of characters moved. **/ -int ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs) +int ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs, BOOL final_eop) { cursor->nOffset += nRelOfs; if (cursor->nOffset < 0) @@ -683,11 +678,11 @@ int ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs) return nRelOfs; } - if (new_offset >= ME_GetTextLength(editor)) + if (new_offset >= ME_GetTextLength(editor) + (final_eop ? 1 : 0)) { /* new offset at the end of the text */ - ME_SetCursorToEnd(editor, cursor); - nRelOfs -= new_offset - ME_GetTextLength(editor); + ME_SetCursorToEnd(editor, cursor, final_eop); + nRelOfs -= new_offset - (ME_GetTextLength(editor) + (final_eop ? 1 : 0)); return nRelOfs; } @@ -859,7 +854,7 @@ ME_SelectByType(ME_TextEditor *editor, ME_SelectionType selectionType) /* Select everything with cursor anchored from the start of the text */ editor->nSelectionType = stDocument; ME_SetCursorToStart(editor, &editor->pCursors[1]); - ME_SetCursorToEnd(editor, &editor->pCursors[0]); + ME_SetCursorToEnd(editor, &editor->pCursors[0], FALSE); break; default: assert(0); } @@ -908,8 +903,8 @@ static ME_DisplayItem* ME_FindPixelPosInTableRow(int x, int y, /* Return table row delimiter */ para = ME_FindItemFwd(cell, diParagraph); assert(para->member.para.nFlags & MEPF_ROWEND); - assert(para->member.para.pFmt->dwMask & PFM_TABLEROWDELIMITER); - assert(para->member.para.pFmt->wEffects & PFE_TABLEROWDELIMITER); + assert(para->member.para.fmt.dwMask & PFM_TABLEROWDELIMITER); + assert(para->member.para.fmt.wEffects & PFE_TABLEROWDELIMITER); return para; } @@ -961,11 +956,13 @@ static BOOL ME_FindRunInRow(ME_TextEditor *editor, ME_DisplayItem *pRow, * x & y are pixel positions in virtual coordinates into the rich edit control, * so client coordinates must first be adjusted by the scroll position. * + * If final_eop is TRUE consider the final end-of-paragraph. + * * returns TRUE if the result was exactly under the cursor, otherwise returns * FALSE, and result is set to the closest position to the coordinates. */ static BOOL ME_FindPixelPos(ME_TextEditor *editor, int x, int y, - ME_Cursor *result, BOOL *is_eol) + ME_Cursor *result, BOOL *is_eol, BOOL final_eop) { ME_DisplayItem *p = editor->pBuffer->pFirst->member.para.next_para; BOOL isExact = TRUE; @@ -1001,7 +998,7 @@ static BOOL ME_FindPixelPos(ME_TextEditor *editor, int x, int y, if (!pp) break; p = pp; } - if (p == editor->pBuffer->pLast) + if (p == editor->pBuffer->pLast && !final_eop) { /* The position is below the last paragraph, so the last row will be used * rather than the end of the text, so the x position will be used to @@ -1016,10 +1013,7 @@ static BOOL ME_FindPixelPos(ME_TextEditor *editor, int x, int y, 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; - assert(result->pRun->member.run.nFlags & MERF_ENDPARA); + ME_SetCursorToEnd(editor, result, TRUE); return FALSE; } @@ -1047,7 +1041,7 @@ BOOL ME_CharFromPos(ME_TextEditor *editor, int x, int y, } x += editor->horz_si.nPos; y += editor->vert_si.nPos; - bResult = ME_FindPixelPos(editor, x, y, cursor, NULL); + bResult = ME_FindPixelPos(editor, x, y, cursor, NULL, FALSE); if (isExact) *isExact = bResult; return TRUE; } @@ -1130,7 +1124,7 @@ void ME_LButtonDown(ME_TextEditor *editor, int x, int y, int clickNum) is_selection = ME_IsSelection(editor); is_shift = GetKeyState(VK_SHIFT) < 0; - ME_FindPixelPos(editor, x, y, &editor->pCursors[0], &editor->bCaretAtEnd); + ME_FindPixelPos(editor, x, y, &editor->pCursors[0], &editor->bCaretAtEnd, FALSE); if (x >= editor->rcFormat.left || is_shift) { @@ -1190,7 +1184,7 @@ void ME_MouseMove(ME_TextEditor *editor, int x, int y) tmp_cursor = editor->pCursors[0]; /* FIXME: do something with the return value of ME_FindPixelPos */ - ME_FindPixelPos(editor, x, y, &tmp_cursor, &editor->bCaretAtEnd); + ME_FindPixelPos(editor, x, y, &tmp_cursor, &editor->bCaretAtEnd, TRUE); ME_InvalidateSelection(editor); editor->pCursors[0] = tmp_cursor; @@ -1237,7 +1231,7 @@ static int ME_GetXForArrow(ME_TextEditor *editor, ME_Cursor *pCursor) static void -ME_MoveCursorLines(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs) +ME_MoveCursorLines(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs, BOOL extend) { ME_DisplayItem *pRun = pCursor->pRun; ME_DisplayItem *pOldPara = pCursor->pPara; @@ -1255,8 +1249,12 @@ ME_MoveCursorLines(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs) assert(pItem); /* start of the previous row */ pItem = ME_FindItemBack(pItem, diStartRow); - if (!pItem) - return; /* row not found - ignore */ + if (!pItem) /* row not found */ + { + if (extend) + ME_SetCursorToStart(editor, pCursor); + return; + } pNewPara = ME_GetParagraph(pItem); if (pOldPara->member.para.nFlags & MEPF_ROWEND || (pOldPara->member.para.pCell && @@ -1282,8 +1280,12 @@ ME_MoveCursorLines(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs) { /* start of the next row */ pItem = ME_FindItemFwd(pRun, diStartRow); - if (!pItem) - return; /* row not found - ignore */ + if (!pItem) /* row not found */ + { + if (extend) + ME_SetCursorToEnd(editor, pCursor, TRUE); + return; + } pNewPara = ME_GetParagraph(pItem); if (pOldPara->member.para.nFlags & MEPF_ROWSTART || (pOldPara->member.para.pCell && @@ -1383,7 +1385,7 @@ static void ME_ArrowPageDown(ME_TextEditor *editor, ME_Cursor *pCursor) if (editor->vert_si.nPos >= y - editor->sizeWindow.cy) { - ME_SetCursorToEnd(editor, pCursor); + ME_SetCursorToEnd(editor, pCursor, FALSE); editor->bCaretAtEnd = FALSE; } else { ME_DisplayItem *pRun = pCursor->pRun; @@ -1480,7 +1482,7 @@ static void ME_ArrowEnd(ME_TextEditor *editor, ME_Cursor *pCursor) static void ME_ArrowCtrlEnd(ME_TextEditor *editor, ME_Cursor *pCursor) { - ME_SetCursorToEnd(editor, pCursor); + ME_SetCursorToEnd(editor, pCursor, FALSE); editor->bCaretAtEnd = FALSE; } @@ -1508,9 +1510,6 @@ void ME_SendSelChange(ME_TextEditor *editor) { SELCHANGE sc; - if (!(editor->nEventMask & ENM_SELCHANGE)) - return; - sc.nmhdr.hwndFrom = NULL; sc.nmhdr.idFrom = 0; sc.nmhdr.code = EN_SELCHANGE; @@ -1520,16 +1519,21 @@ void ME_SendSelChange(ME_TextEditor *editor) sc.seltyp |= SEL_TEXT; if (sc.chrg.cpMin < sc.chrg.cpMax+1) /* what were RICHEDIT authors thinking ? */ sc.seltyp |= SEL_MULTICHAR; - TRACE("cpMin=%d cpMax=%d seltyp=%d (%s %s)\n", - sc.chrg.cpMin, sc.chrg.cpMax, sc.seltyp, - (sc.seltyp & SEL_TEXT) ? "SEL_TEXT" : "", - (sc.seltyp & SEL_MULTICHAR) ? "SEL_MULTICHAR" : ""); + if (sc.chrg.cpMin != editor->notified_cr.cpMin || sc.chrg.cpMax != editor->notified_cr.cpMax) { ME_ClearTempStyle(editor); editor->notified_cr = sc.chrg; - ITextHost_TxNotify(editor->texthost, sc.nmhdr.code, &sc); + + if (editor->nEventMask & ENM_SELCHANGE) + { + TRACE("cpMin=%d cpMax=%d seltyp=%d (%s %s)\n", + sc.chrg.cpMin, sc.chrg.cpMax, sc.seltyp, + (sc.seltyp & SEL_TEXT) ? "SEL_TEXT" : "", + (sc.seltyp & SEL_MULTICHAR) ? "SEL_MULTICHAR" : ""); + ITextHost_TxNotify(editor->texthost, sc.nmhdr.code, &sc); + } } } @@ -1548,20 +1552,20 @@ ME_ArrowKey(ME_TextEditor *editor, int nVKey, BOOL extend, BOOL ctrl) if (ctrl) success = ME_MoveCursorWords(editor, &tmp_curs, -1); else - success = ME_MoveCursorChars(editor, &tmp_curs, -1); + success = ME_MoveCursorChars(editor, &tmp_curs, -1, extend); break; case VK_RIGHT: editor->bCaretAtEnd = FALSE; if (ctrl) success = ME_MoveCursorWords(editor, &tmp_curs, +1); else - success = ME_MoveCursorChars(editor, &tmp_curs, +1); + success = ME_MoveCursorChars(editor, &tmp_curs, +1, extend); break; case VK_UP: - ME_MoveCursorLines(editor, &tmp_curs, -1); + ME_MoveCursorLines(editor, &tmp_curs, -1, extend); break; case VK_DOWN: - ME_MoveCursorLines(editor, &tmp_curs, +1); + ME_MoveCursorLines(editor, &tmp_curs, +1, extend); break; case VK_PRIOR: ME_ArrowPageUp(editor, &tmp_curs); diff --git a/reactos/dll/win32/riched20/editor.c b/reactos/dll/win32/riched20/editor.c index e90dcb8c018..a43a0e0034e 100644 --- a/reactos/dll/win32/riched20/editor.c +++ b/reactos/dll/win32/riched20/editor.c @@ -424,11 +424,12 @@ void ME_RTFCharAttrHook(RTF_Info *info) { case rtfPlain: /* FIXME add more flags once they're implemented */ - fmt.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINETYPE | CFM_STRIKEOUT | CFM_COLOR | CFM_BACKCOLOR | CFM_SIZE | CFM_WEIGHT; + fmt.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_UNDERLINETYPE | CFM_STRIKEOUT | + CFM_COLOR | CFM_BACKCOLOR | CFM_SIZE | CFM_WEIGHT; fmt.dwEffects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR; fmt.yHeight = 12*20; /* 12pt */ fmt.wWeight = FW_NORMAL; - fmt.bUnderlineType = CFU_UNDERLINENONE; + fmt.bUnderlineType = CFU_UNDERLINE; break; case rtfBold: fmt.dwMask = CFM_BOLD | CFM_WEIGHT; @@ -440,24 +441,28 @@ void ME_RTFCharAttrHook(RTF_Info *info) fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0; break; case rtfUnderline: - fmt.dwMask = CFM_UNDERLINETYPE; - fmt.bUnderlineType = info->rtfParam ? CFU_CF1UNDERLINE : CFU_UNDERLINENONE; + fmt.dwMask = CFM_UNDERLINETYPE | CFM_UNDERLINE; + fmt.bUnderlineType = CFU_UNDERLINE; + fmt.dwEffects = info->rtfParam ? CFE_UNDERLINE : 0; break; case rtfDotUnderline: - fmt.dwMask = CFM_UNDERLINETYPE; - fmt.bUnderlineType = info->rtfParam ? CFU_UNDERLINEDOTTED : CFU_UNDERLINENONE; + fmt.dwMask = CFM_UNDERLINETYPE | CFM_UNDERLINE; + fmt.bUnderlineType = CFU_UNDERLINEDOTTED; + fmt.dwEffects = info->rtfParam ? CFE_UNDERLINE : 0; break; case rtfDbUnderline: - fmt.dwMask = CFM_UNDERLINETYPE; - fmt.bUnderlineType = info->rtfParam ? CFU_UNDERLINEDOUBLE : CFU_UNDERLINENONE; + fmt.dwMask = CFM_UNDERLINETYPE | CFM_UNDERLINE; + fmt.bUnderlineType = CFU_UNDERLINEDOUBLE; + fmt.dwEffects = info->rtfParam ? CFE_UNDERLINE : 0; break; case rtfWordUnderline: - fmt.dwMask = CFM_UNDERLINETYPE; - fmt.bUnderlineType = info->rtfParam ? CFU_UNDERLINEWORD : CFU_UNDERLINENONE; + fmt.dwMask = CFM_UNDERLINETYPE | CFM_UNDERLINE; + fmt.bUnderlineType = CFU_UNDERLINEWORD; + fmt.dwEffects = info->rtfParam ? CFE_UNDERLINE : 0; break; case rtfNoUnderline: - fmt.dwMask = CFM_UNDERLINETYPE; - fmt.bUnderlineType = CFU_UNDERLINENONE; + fmt.dwMask = CFM_UNDERLINE; + fmt.dwEffects = 0; break; case rtfStrikeThru: fmt.dwMask = CFM_STRIKEOUT; @@ -486,7 +491,7 @@ void ME_RTFCharAttrHook(RTF_Info *info) { RTFColor *c = RTFGetColor(info, info->rtfParam); if (c && c->rtfCBlue >= 0) - fmt.crTextColor = (c->rtfCBlue<<16)|(c->rtfCGreen<<8)|(c->rtfCRed); + fmt.crBackColor = (c->rtfCBlue<<16)|(c->rtfCGreen<<8)|(c->rtfCRed); else fmt.dwEffects = CFE_AUTOBACKCOLOR; } @@ -550,8 +555,9 @@ void ME_RTFParAttrHook(RTF_Info *info) info->borderType = RTFBorderParaTop; info->fmt.dwMask = PFM_ALIGNMENT | PFM_BORDER | PFM_LINESPACING | PFM_TABSTOPS | PFM_OFFSET | PFM_RIGHTINDENT | PFM_SPACEAFTER | PFM_SPACEBEFORE | - PFM_STARTINDENT | PFM_RTLPARA; - /* TODO: numbering, shading */ + PFM_STARTINDENT | PFM_RTLPARA | PFM_NUMBERING | PFM_NUMBERINGSTART | + PFM_NUMBERINGSTYLE | PFM_NUMBERINGTAB; + /* TODO: shading */ info->fmt.wAlignment = PFA_LEFT; info->fmt.cTabCount = 0; info->fmt.dxOffset = info->fmt.dxStartIndent = info->fmt.dxRightIndent = 0; @@ -561,6 +567,11 @@ void ME_RTFParAttrHook(RTF_Info *info) info->fmt.dySpaceBefore = info->fmt.dySpaceAfter = 0; info->fmt.dyLineSpacing = 0; info->fmt.wEffects &= ~PFE_RTLPARA; + info->fmt.wNumbering = 0; + info->fmt.wNumberingStart = 0; + info->fmt.wNumberingStyle = 0; + info->fmt.wNumberingTab = 0; + if (!info->editor->bEmulateVersion10) /* v4.1 */ { if (info->tableDef && info->tableDef->tableRowStart && @@ -754,18 +765,6 @@ void ME_RTFParAttrHook(RTF_Info *info) info->fmt.dwMask |= PFM_NUMBERING; info->fmt.wNumbering = 2; /* FIXME: MSDN says it's not used ?? */ break; - case rtfParNumDecimal: - info->fmt.dwMask |= PFM_NUMBERING; - info->fmt.wNumbering = 2; /* FIXME: MSDN says it's not used ?? */ - break; - case rtfParNumIndent: - info->fmt.dwMask |= PFM_NUMBERINGTAB; - info->fmt.wNumberingTab = info->rtfParam; - break; - case rtfParNumStartAt: - info->fmt.dwMask |= PFM_NUMBERINGSTART; - info->fmt.wNumberingStart = info->rtfParam; - break; case rtfBorderLeft: info->borderType = RTFBorderParaLeft; info->fmt.wBorders |= 1; @@ -861,7 +860,7 @@ void ME_RTFParAttrHook(RTF_Info *info) info->fmt.wEffects |= PFE_RTLPARA; break; case rtfLTRPar: - info->fmt.dwMask = PFM_RTLPARA; + info->fmt.dwMask |= PFM_RTLPARA; info->fmt.wEffects &= ~PFE_RTLPARA; break; } @@ -899,7 +898,7 @@ void ME_RTFTblAttrHook(RTF_Info *info) /* Tab stops were used to store cell positions before v4.1 but v4.1 * still seems to set the tabstops without using them. */ ME_DisplayItem *para = info->editor->pCursors[0].pPara; - PARAFORMAT2 *pFmt = para->member.para.pFmt; + PARAFORMAT2 *pFmt = ¶->member.para.fmt; pFmt->rgxTabs[cellNum] &= ~0x00FFFFFF; pFmt->rgxTabs[cellNum] |= 0x00FFFFFF & info->rtfParam; } @@ -970,7 +969,7 @@ void ME_RTFSpecialCharHook(RTF_Info *info) } } else { /* v1.0 - v3.0 */ ME_DisplayItem *para = info->editor->pCursors[0].pPara; - PARAFORMAT2 *pFmt = para->member.para.pFmt; + PARAFORMAT2 *pFmt = ¶->member.para.fmt; if (pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE && tableDef->numCellsInserted < tableDef->numCellsDefined) { @@ -1056,8 +1055,8 @@ void ME_RTFSpecialCharHook(RTF_Info *info) } para = ME_InsertTableRowEndFromCursor(info->editor); - para->member.para.pFmt->dxOffset = abs(info->tableDef->gapH); - para->member.para.pFmt->dxStartIndent = info->tableDef->leftEdge; + para->member.para.fmt.dxOffset = abs(info->tableDef->gapH); + para->member.para.fmt.dxStartIndent = info->tableDef->leftEdge; ME_ApplyBorderProperties(info, ¶->member.para.border, tableDef->border); info->nestingLevel--; @@ -1079,7 +1078,7 @@ void ME_RTFSpecialCharHook(RTF_Info *info) } else { /* v1.0 - v3.0 */ WCHAR endl = '\r'; ME_DisplayItem *para = info->editor->pCursors[0].pPara; - PARAFORMAT2 *pFmt = para->member.para.pFmt; + PARAFORMAT2 *pFmt = ¶->member.para.fmt; pFmt->dxOffset = info->tableDef->gapH; pFmt->dxStartIndent = info->tableDef->leftEdge; @@ -1106,7 +1105,7 @@ void ME_RTFSpecialCharHook(RTF_Info *info) PARAFORMAT2 *pFmt; RTFFlushOutputBuffer(info); para = info->editor->pCursors[0].pPara; - pFmt = para->member.para.pFmt; + pFmt = ¶->member.para.fmt; if (pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE) { /* rtfPar is treated like a space within a table. */ @@ -1423,6 +1422,110 @@ static void ME_RTFReadObjectGroup(RTF_Info *info) RTFRouteToken(info); /* feed "}" back to router */ } +static void ME_RTFReadParnumGroup( RTF_Info *info ) +{ + int level = 1, type = -1; + WORD indent = 0, start = 1; + WCHAR txt_before = 0, txt_after = 0; + + for (;;) + { + RTFGetToken( info ); + + if (RTFCheckCMM( info, rtfControl, rtfDestination, rtfParNumTextBefore ) || + RTFCheckCMM( info, rtfControl, rtfDestination, rtfParNumTextAfter )) + { + int loc = info->rtfMinor; + + RTFGetToken( info ); + if (info->rtfClass == rtfText) + { + if (loc == rtfParNumTextBefore) + txt_before = info->rtfMajor; + else + txt_after = info->rtfMajor; + continue; + } + /* falling through to catch EOFs and group level changes */ + } + + if (info->rtfClass == rtfEOF) + return; + + if (RTFCheckCM( info, rtfGroup, rtfEndGroup )) + { + if (--level == 0) break; + continue; + } + + if (RTFCheckCM( info, rtfGroup, rtfBeginGroup )) + { + level++; + continue; + } + + /* Ignore non para-attr */ + if (!RTFCheckCM( info, rtfControl, rtfParAttr )) + continue; + + switch (info->rtfMinor) + { + case rtfParLevel: /* Para level is ignored */ + case rtfParSimple: + break; + case rtfParBullet: + type = PFN_BULLET; + break; + + case rtfParNumDecimal: + type = PFN_ARABIC; + break; + case rtfParNumULetter: + type = PFN_UCLETTER; + break; + case rtfParNumURoman: + type = PFN_UCROMAN; + break; + case rtfParNumLLetter: + type = PFN_LCLETTER; + break; + case rtfParNumLRoman: + type = PFN_LCROMAN; + break; + + case rtfParNumIndent: + indent = info->rtfParam; + break; + case rtfParNumStartAt: + start = info->rtfParam; + break; + } + } + + if (type != -1) + { + info->fmt.dwMask |= (PFM_NUMBERING | PFM_NUMBERINGSTART | PFM_NUMBERINGSTYLE | PFM_NUMBERINGTAB); + info->fmt.wNumbering = type; + info->fmt.wNumberingStart = start; + info->fmt.wNumberingStyle = PFNS_PAREN; + if (type != PFN_BULLET) + { + if (txt_before == 0 && txt_after == 0) + info->fmt.wNumberingStyle = PFNS_PLAIN; + else if (txt_after == '.') + info->fmt.wNumberingStyle = PFNS_PERIOD; + else if (txt_before == '(' && txt_after == ')') + info->fmt.wNumberingStyle = PFNS_PARENS; + } + info->fmt.wNumberingTab = indent; + } + + TRACE("type %d indent %d start %d txt before %04x txt after %04x\n", + type, indent, start, txt_before, txt_after); + + RTFRouteToken( info ); /* feed "}" back to router */ +} + static void ME_RTFReadHook(RTF_Info *info) { switch(info->rtfClass) @@ -1523,7 +1626,7 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre ME_GetTextLength(editor), FALSE); from = to = 0; ME_ClearTempStyle(editor); - ME_SetDefaultParaFormat(editor, editor->pCursors[0].pPara->member.para.pFmt); + ME_SetDefaultParaFormat(editor, &editor->pCursors[0].pPara->member.para.fmt); } @@ -1556,8 +1659,9 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre if (!invalidRTF && !inStream.editstream->dwError) { + ME_Cursor start; + from = ME_GetCursorOfs(&editor->pCursors[0]); if (format & SF_RTF) { - from = ME_GetCursorOfs(&editor->pCursors[0]); /* setup the RTF parser */ memset(&parser, 0, sizeof parser); @@ -1571,6 +1675,7 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre RTFSetDestinationCallback(&parser, rtfShpPict, ME_RTFReadShpPictGroup); RTFSetDestinationCallback(&parser, rtfPict, ME_RTFReadPictGroup); RTFSetDestinationCallback(&parser, rtfObject, ME_RTFReadObjectGroup); + RTFSetDestinationCallback(&parser, rtfParNumbering, ME_RTFReadParnumGroup); if (!parser.editor->bEmulateVersion10) /* v4.1 */ { RTFSetDestinationCallback(&parser, rtfNoNestTables, RTFSkipGroup); @@ -1644,9 +1749,19 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre if (newto > to + (editor->bEmulateVersion10 ? 1 : 0)) { WCHAR lastchar[3] = {'\0', '\0'}; int linebreakSize = editor->bEmulateVersion10 ? 2 : 1; - ME_Cursor linebreakCursor = *selEnd; + ME_Cursor linebreakCursor = *selEnd, lastcharCursor = *selEnd; + CHARFORMAT2W cf; - ME_MoveCursorChars(editor, &linebreakCursor, -linebreakSize); + /* Set the final eop to the char fmt of the last char */ + cf.cbSize = sizeof(cf); + cf.dwMask = CFM_ALL2; + ME_MoveCursorChars(editor, &lastcharCursor, -1, FALSE); + ME_GetCharFormat(editor, &lastcharCursor, &linebreakCursor, &cf); + ME_SetSelection(editor, newto, -1); + ME_SetSelectionCharFormat(editor, &cf); + ME_SetSelection(editor, newto, newto); + + ME_MoveCursorChars(editor, &linebreakCursor, -linebreakSize, FALSE); ME_GetTextW(editor, lastchar, 2, &linebreakCursor, linebreakSize, FALSE, FALSE); if (lastchar[0] == '\r' && (lastchar[1] == '\n' || lastchar[1] == '\0')) { ME_InternalDeleteText(editor, &linebreakCursor, linebreakSize, FALSE); @@ -1659,12 +1774,17 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre style = parser.style; } else if (format & SF_TEXT) + { num_read = ME_StreamInText(editor, format, &inStream, style); + to = ME_GetCursorOfs(&editor->pCursors[0]); + } else ERR("EM_STREAMIN without SF_TEXT or SF_RTF\n"); /* put the cursor at the top */ if (!(format & SFF_SELECTION)) ME_SetSelection(editor, 0, 0); + ME_CursorFromCharOfs(editor, from, &start); + ME_UpdateLinkAttribute(editor, &start, to - from); } /* Restore saved undo mode */ @@ -1796,7 +1916,7 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH { ME_CursorFromCharOfs(editor, nMin - 1, &cursor); wLastChar = *get_text( &cursor.pRun->member.run, cursor.nOffset ); - ME_MoveCursorChars(editor, &cursor, 1); + ME_MoveCursorChars(editor, &cursor, 1, FALSE); } else { ME_CursorFromCharOfs(editor, nMin, &cursor); } @@ -1872,7 +1992,7 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH { ME_CursorFromCharOfs(editor, nMax + 1, &cursor); wLastChar = *get_text( &cursor.pRun->member.run, cursor.nOffset ); - ME_MoveCursorChars(editor, &cursor, -1); + ME_MoveCursorChars(editor, &cursor, -1, FALSE); } else { ME_CursorFromCharOfs(editor, nMax, &cursor); } @@ -2286,7 +2406,7 @@ ME_KeyDown(ME_TextEditor *editor, WORD nKey) int from, to; const WCHAR endl = '\r'; const WCHAR endlv10[] = {'\r','\n'}; - ME_Style *style; + ME_Style *style, *eop_style; if (editor->styleFlags & ES_READONLY) { MessageBeep(MB_ICONERROR); @@ -2324,7 +2444,7 @@ ME_KeyDown(ME_TextEditor *editor, WORD nKey) ME_InsertTextFromCursor(editor, 0, &endl, 1, editor->pCursors[0].pRun->member.run.style); para = editor->pBuffer->pFirst->member.para.next_para; - ME_SetDefaultParaFormat(editor, para->member.para.pFmt); + ME_SetDefaultParaFormat(editor, ¶->member.para.fmt); para->member.para.nFlags = MEPF_REWRAP; editor->pCursors[0].pPara = para; editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun); @@ -2383,21 +2503,29 @@ ME_KeyDown(ME_TextEditor *editor, WORD nKey) } style = ME_GetInsertStyle(editor, 0); - ME_SaveTempStyle(editor); + + /* Normally the new eop style is the insert style, however in a list it is copied from the existing + eop style (this prevents the list label style changing when the new eop is inserted). + No extra ref is taken here on eop_style. */ + if (para->member.para.fmt.wNumbering) + eop_style = para->member.para.eop_run->style; + else + eop_style = style; ME_ContinueCoalescingTransaction(editor); if (shift_is_down) ME_InsertEndRowFromCursor(editor, 0); else if (!editor->bEmulateVersion10) - ME_InsertTextFromCursor(editor, 0, &endl, 1, style); + ME_InsertTextFromCursor(editor, 0, &endl, 1, eop_style); else - ME_InsertTextFromCursor(editor, 0, endlv10, 2, style); - ME_ReleaseStyle(style); + ME_InsertTextFromCursor(editor, 0, endlv10, 2, eop_style); ME_CommitCoalescingUndo(editor); SetCursor(NULL); ME_UpdateSelectionLinkAttribute(editor); ME_UpdateRepaint(editor, FALSE); + ME_SaveTempStyle(editor, style); /* set the temp insert style for the new para */ + ME_ReleaseStyle(style); } return TRUE; } @@ -2557,7 +2685,6 @@ static LRESULT ME_Char(ME_TextEditor *editor, WPARAM charCode, if(editor->nTextLimit > ME_GetTextLength(editor) - (to-from)) { ME_Style *style = ME_GetInsertStyle(editor, 0); - ME_SaveTempStyle(editor); ME_ContinueCoalescingTransaction(editor); ME_InsertTextFromCursor(editor, 0, &wstr, 1, style); ME_ReleaseStyle(style); @@ -4529,7 +4656,7 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, ME_Style *style = ME_GetInsertStyle(editor, 0); hIMC = ITextHost_TxImmGetContext(editor->texthost); ME_DeleteSelection(editor); - ME_SaveTempStyle(editor); + ME_SaveTempStyle(editor, style); if (lParam & (GCS_RESULTSTR|GCS_COMPSTR)) { LPWSTR lpCompStr = NULL; diff --git a/reactos/dll/win32/riched20/editor.h b/reactos/dll/win32/riched20/editor.h index 1ea6ea6f427..505733f7e52 100644 --- a/reactos/dll/win32/riched20/editor.h +++ b/reactos/dll/win32/riched20/editor.h @@ -111,7 +111,7 @@ ME_Style *ME_ApplyStyle(ME_TextEditor *ed, ME_Style *sSrc, CHARFORMAT2W *style) HFONT ME_SelectStyleFont(ME_Context *c, ME_Style *s) DECLSPEC_HIDDEN; void ME_UnselectStyleFont(ME_Context *c, ME_Style *s, HFONT hOldFont) DECLSPEC_HIDDEN; void ME_InitCharFormat2W(CHARFORMAT2W *pFmt) DECLSPEC_HIDDEN; -void ME_SaveTempStyle(ME_TextEditor *editor) DECLSPEC_HIDDEN; +void ME_SaveTempStyle(ME_TextEditor *editor, ME_Style *style) DECLSPEC_HIDDEN; void ME_ClearTempStyle(ME_TextEditor *editor) DECLSPEC_HIDDEN; void ME_DumpStyleToBuf(CHARFORMAT2W *pFmt, char buf[2048]) DECLSPEC_HIDDEN; void ME_DumpStyle(ME_Style *s) DECLSPEC_HIDDEN; @@ -135,6 +135,8 @@ void ME_DumpDocument(ME_TextBuffer *buffer) 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_MakeStringConst(const WCHAR *str, int len) DECLSPEC_HIDDEN; +ME_String *ME_MakeStringEmpty(int len) DECLSPEC_HIDDEN; void ME_DestroyString(ME_String *s) 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; @@ -213,7 +215,7 @@ BOOL ME_DeleteTextAtCursor(ME_TextEditor *editor, int nCursor, int nChars) DECLS void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, const WCHAR *str, int len, ME_Style *style) DECLSPEC_HIDDEN; void ME_InsertEndRowFromCursor(ME_TextEditor *editor, int nCursor) DECLSPEC_HIDDEN; -int ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs) DECLSPEC_HIDDEN; +int ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs, BOOL final_eop) DECLSPEC_HIDDEN; BOOL ME_ArrowKey(ME_TextEditor *ed, int nVKey, BOOL extend, BOOL ctrl) DECLSPEC_HIDDEN; int ME_GetCursorOfs(const ME_Cursor *cursor) DECLSPEC_HIDDEN; @@ -251,6 +253,8 @@ BOOL ME_SetSelectionParaFormat(ME_TextEditor *editor, const PARAFORMAT2 *pFmt) D void ME_GetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt) DECLSPEC_HIDDEN; void ME_MarkAllForWrapping(ME_TextEditor *editor) DECLSPEC_HIDDEN; void ME_SetDefaultParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt) DECLSPEC_HIDDEN; +void para_num_init( ME_Context *c, ME_Paragraph *para ) DECLSPEC_HIDDEN; +void para_num_clear( struct para_num *pn ) DECLSPEC_HIDDEN; /* paint.c */ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, const RECT *rcUpdate) DECLSPEC_HIDDEN; diff --git a/reactos/dll/win32/riched20/editstr.h b/reactos/dll/win32/riched20/editstr.h index cf090109ce6..88a0a8dff14 100644 --- a/reactos/dll/win32/riched20/editstr.h +++ b/reactos/dll/win32/riched20/editstr.h @@ -29,6 +29,7 @@ typedef struct tagME_String { WCHAR *szData; int nLen, nBuffer; + void (*free)(struct tagME_String *); } ME_String; typedef struct tagME_FontCacheItem @@ -158,9 +159,17 @@ typedef struct tagME_BorderRect ME_Border right; } ME_BorderRect; +struct para_num +{ + ME_Style *style; + ME_String *text; + INT width; + POINT pt; +}; + typedef struct tagME_Paragraph { - PARAFORMAT2 *pFmt; + PARAFORMAT2 fmt; ME_String *text; struct tagME_DisplayItem *pCell; /* v4.1 */ @@ -171,6 +180,8 @@ typedef struct tagME_Paragraph POINT pt; int nHeight, nWidth; int nRows; + struct para_num para_num; + ME_Run *eop_run; /* ptr to the end-of-para run */ struct tagME_DisplayItem *prev_para, *next_para; } ME_Paragraph; @@ -333,27 +344,6 @@ struct tagME_InStream { }; typedef struct tagME_InStream ME_InStream; - -#define STREAMOUT_BUFFER_SIZE 4096 -#define STREAMOUT_FONTTBL_SIZE 8192 -#define STREAMOUT_COLORTBL_SIZE 1024 - -typedef struct tagME_OutStream { - EDITSTREAM *stream; - char buffer[STREAMOUT_BUFFER_SIZE]; - UINT pos, written; - UINT nCodePage; - UINT nFontTblLen; - ME_FontTableItem fonttbl[STREAMOUT_FONTTBL_SIZE]; - UINT nColorTblLen; - COLORREF colortbl[STREAMOUT_COLORTBL_SIZE]; - UINT nDefaultFont; - UINT nDefaultCodePage; - /* nNestingLevel = 0 means we aren't in a cell, 1 means we are in a cell, - * an greater numbers mean we are in a cell nested within a cell. */ - UINT nNestingLevel; -} ME_OutStream; - typedef struct tagME_TextEditor { HWND hWnd, hwndParent; @@ -431,19 +421,4 @@ typedef struct tagME_Context ME_TextEditor *editor; } ME_Context; -typedef struct tagME_WrapContext -{ - ME_Style *style; - ME_Context *context; - int nLeftMargin, nRightMargin, nFirstMargin; - int nAvailWidth; - int nRow; - POINT pt; - BOOL bOverflown, bWordWrap; - ME_DisplayItem *pPara; - ME_DisplayItem *pRowStart; - - ME_DisplayItem *pLastSplittableRun; -} ME_WrapContext; - #endif diff --git a/reactos/dll/win32/riched20/list.c b/reactos/dll/win32/riched20/list.c index ce21c59892e..d3214466845 100644 --- a/reactos/dll/win32/riched20/list.c +++ b/reactos/dll/win32/riched20/list.c @@ -163,8 +163,8 @@ void ME_DestroyDisplayItem(ME_DisplayItem *item) TRACE("type=%s\n", ME_GetDITypeName(item->type)); if (item->type==diParagraph) { - FREE_OBJ(item->member.para.pFmt); ME_DestroyString(item->member.para.text); + para_num_clear( &item->member.para.para_num ); } if (item->type==diRun) diff --git a/reactos/dll/win32/riched20/paint.c b/reactos/dll/win32/riched20/paint.c index 42434b9b470..41b38969c04 100644 --- a/reactos/dll/win32/riched20/paint.c +++ b/reactos/dll/win32/riched20/paint.c @@ -201,11 +201,26 @@ static COLORREF get_text_color( ME_Context *c, ME_Style *style, BOOL highlight ) return color; } +static COLORREF get_back_color( ME_Context *c, ME_Style *style, BOOL highlight ) +{ + COLORREF color; + + if (highlight) + color = ITextHost_TxGetSysColor( c->editor->texthost, COLOR_HIGHLIGHT ); + else if ( (style->fmt.dwMask & CFM_BACKCOLOR) + && !(style->fmt.dwEffects & CFE_AUTOBACKCOLOR) ) + color = style->fmt.crBackColor; + else + color = ITextHost_TxGetSysColor( c->editor->texthost, COLOR_WINDOW ); + + 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) + if (style->fmt.dwEffects & CFE_UNDERLINE) { switch (style->fmt.bUnderlineType) { @@ -314,14 +329,17 @@ static void get_selection_rect( ME_Context *c, ME_Run *run, int from, int to, in 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 back_color = get_back_color( c, run->style, selected ); COLORREF old_text, old_back = 0; const WCHAR *text = get_text( run, 0 ); ME_String *masked = NULL; + const BOOL paint_bg = ( selected + || ( ( run->style->fmt.dwMask & CFM_BACKCOLOR ) + && !(CFE_AUTOBACKCOLOR & run->style->fmt.dwEffects) ) + ); if (c->editor->cPasswordMask) { @@ -330,16 +348,16 @@ static void draw_text( ME_Context *c, ME_Run *run, int x, int y, BOOL selected, } old_text = SetTextColor( c->hDC, text_color ); - if (selected) old_back = SetBkColor( c->hDC, back_color ); + if (paint_bg) old_back = SetBkColor( c->hDC, back_color ); if (run->para->nFlags & MEPF_COMPLEX) - ScriptTextOut( c->hDC, &run->style->script_cache, x, y, selected ? ETO_OPAQUE : 0, sel_rect, + ScriptTextOut( c->hDC, &run->style->script_cache, x, y, paint_bg ? ETO_OPAQUE : 0, sel_rect, &run->script_analysis, NULL, 0, run->glyphs, run->num_glyphs, run->advances, NULL, run->offsets ); else - ExtTextOutW( c->hDC, x, y, selected ? ETO_OPAQUE : 0, sel_rect, text, run->len, NULL ); + ExtTextOutW( c->hDC, x, y, paint_bg ? ETO_OPAQUE : 0, sel_rect, text, run->len, NULL ); - if (selected) SetBkColor( c->hDC, old_back ); + if (paint_bg) SetBkColor( c->hDC, old_back ); SetTextColor( c->hDC, old_text ); draw_underline( c, run, x, y, text_color ); @@ -389,7 +407,18 @@ static void ME_DrawTextWithStyle(ME_Context *c, ME_Run *run, int x, int y, 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 (!(run->style->fmt.dwEffects & CFE_AUTOBACKCOLOR) + && (run->style->fmt.dwMask & CFM_BACKCOLOR) ) + { + RECT tmp_rect; + get_selection_rect( c, run, 0, run->len, cy, &tmp_rect ); + OffsetRect( &tmp_rect, x, ymin ); + draw_text( c, run, x, y - yOffset, FALSE, &tmp_rect ); + } + else + draw_text( c, run, x, y - yOffset, FALSE, NULL ); + if (sel_rgn) { ExtSelectClipRgn( hDC, clip, RGN_COPY ); @@ -524,16 +553,16 @@ static void ME_DrawParaDecoration(ME_Context* c, ME_Paragraph* para, int y, RECT BOOL hasParaBorder; SetRectEmpty(bounds); - if (!(para->pFmt->dwMask & (PFM_BORDER | PFM_SPACEBEFORE | PFM_SPACEAFTER))) return; + if (!(para->fmt.dwMask & (PFM_BORDER | PFM_SPACEBEFORE | PFM_SPACEAFTER))) return; border_width = top_border = bottom_border = 0; - idx = (para->pFmt->wBorders >> 8) & 0xF; + idx = (para->fmt.wBorders >> 8) & 0xF; hasParaBorder = (!(c->editor->bEmulateVersion10 && - para->pFmt->dwMask & PFM_TABLE && - para->pFmt->wEffects & PFE_TABLE) && - (para->pFmt->dwMask & PFM_BORDER) && + para->fmt.dwMask & PFM_TABLE && + para->fmt.wEffects & PFE_TABLE) && + (para->fmt.dwMask & PFM_BORDER) && idx != 0 && - (para->pFmt->wBorders & 0xF)); + (para->fmt.wBorders & 0xF)); if (hasParaBorder) { /* FIXME: wBorders is not stored as MSDN says in v1.0 - 4.1 of richedit @@ -560,29 +589,29 @@ static void ME_DrawParaDecoration(ME_Context* c, ME_Paragraph* para, int y, RECT * 0x0F00 bottom right * 0xF000 right bottom */ - if (para->pFmt->wBorders & 0x00B0) - FIXME("Unsupported border flags %x\n", para->pFmt->wBorders); - border_width = ME_GetParaBorderWidth(c, para->pFmt->wBorders); - if (para->pFmt->wBorders & 4) top_border = border_width; - if (para->pFmt->wBorders & 8) bottom_border = border_width; + if (para->fmt.wBorders & 0x00B0) + FIXME("Unsupported border flags %x\n", para->fmt.wBorders); + border_width = ME_GetParaBorderWidth(c, para->fmt.wBorders); + if (para->fmt.wBorders & 4) top_border = border_width; + if (para->fmt.wBorders & 8) bottom_border = border_width; } - if (para->pFmt->dwMask & PFM_SPACEBEFORE) + if (para->fmt.dwMask & PFM_SPACEBEFORE) { rc.left = c->rcView.left; rc.right = c->rcView.right; rc.top = y; - bounds->top = ME_twips2pointsY(c, para->pFmt->dySpaceBefore); + bounds->top = ME_twips2pointsY(c, para->fmt.dySpaceBefore); rc.bottom = y + bounds->top + top_border; FillRect(c->hDC, &rc, c->editor->hbrBackground); } - if (para->pFmt->dwMask & PFM_SPACEAFTER) + if (para->fmt.dwMask & PFM_SPACEAFTER) { rc.left = c->rcView.left; rc.right = c->rcView.right; rc.bottom = y + para->nHeight; - bounds->bottom = ME_twips2pointsY(c, para->pFmt->dySpaceAfter); + bounds->bottom = ME_twips2pointsY(c, para->fmt.dySpaceAfter); rc.top = rc.bottom - bounds->bottom - bottom_border; FillRect(c->hDC, &rc, c->editor->hbrBackground); } @@ -595,11 +624,11 @@ static void ME_DrawParaDecoration(ME_Context* c, ME_Paragraph* para, int y, RECT HPEN pen = NULL, oldpen = NULL; POINT pt; - if (para->pFmt->wBorders & 64) /* autocolor */ + if (para->fmt.wBorders & 64) /* autocolor */ pencr = ITextHost_TxGetSysColor(c->editor->texthost, COLOR_WINDOWTEXT); else - pencr = pen_colors[(para->pFmt->wBorders >> 12) & 0xF]; + pencr = pen_colors[(para->fmt.wBorders >> 12) & 0xF]; rightEdge = c->pt.x + max(c->editor->sizeWindow.cx, c->editor->nTotalWidth); @@ -612,9 +641,9 @@ static void ME_DrawParaDecoration(ME_Context* c, ME_Paragraph* para, int y, RECT /* before & after spaces are not included in border */ /* helper to draw the double lines in case of corner */ -#define DD(x) ((para->pFmt->wBorders & (x)) ? (pen_width + 1) : 0) +#define DD(x) ((para->fmt.wBorders & (x)) ? (pen_width + 1) : 0) - if (para->pFmt->wBorders & 1) + if (para->fmt.wBorders & 1) { MoveToEx(c->hDC, c->pt.x, y + bounds->top, NULL); LineTo(c->hDC, c->pt.x, y + para->nHeight - bounds->bottom); @@ -629,7 +658,7 @@ static void ME_DrawParaDecoration(ME_Context* c, ME_Paragraph* para, int y, RECT } bounds->left += border_width; } - if (para->pFmt->wBorders & 2) + if (para->fmt.wBorders & 2) { MoveToEx(c->hDC, rightEdge - 1, y + bounds->top, NULL); LineTo(c->hDC, rightEdge - 1, y + para->nHeight - bounds->bottom); @@ -644,7 +673,7 @@ static void ME_DrawParaDecoration(ME_Context* c, ME_Paragraph* para, int y, RECT } bounds->right += border_width; } - if (para->pFmt->wBorders & 4) + if (para->fmt.wBorders & 4) { MoveToEx(c->hDC, c->pt.x, y + bounds->top, NULL); LineTo(c->hDC, rightEdge, y + bounds->top); @@ -654,7 +683,7 @@ static void ME_DrawParaDecoration(ME_Context* c, ME_Paragraph* para, int y, RECT } bounds->top += border_width; } - if (para->pFmt->wBorders & 8) + if (para->fmt.wBorders & 8) { MoveToEx(c->hDC, c->pt.x, y + para->nHeight - bounds->bottom - 1, NULL); LineTo(c->hDC, rightEdge, y + para->nHeight - bounds->bottom - 1); @@ -812,7 +841,7 @@ static void ME_DrawTableBorders(ME_Context *c, ME_DisplayItem *paragraph) } } else { /* v1.0 - 3.0 */ /* Draw simple table border */ - if (para->pFmt->dwMask & PFM_TABLE && para->pFmt->wEffects & PFE_TABLE) { + if (para->fmt.dwMask & PFM_TABLE && para->fmt.wEffects & PFE_TABLE) { HPEN pen = NULL, oldpen = NULL; int i, firstX, startX, endX, rowY, rowBottom, nHeight; POINT oldPt; @@ -824,21 +853,21 @@ static void ME_DrawTableBorders(ME_Context *c, ME_DisplayItem *paragraph) /* Find the start relative to the text */ firstX = c->pt.x + ME_FindItemFwd(paragraph, diRun)->member.run.pt.x; /* Go back by the horizontal gap, which is stored in dxOffset */ - firstX -= ME_twips2pointsX(c, para->pFmt->dxOffset); + firstX -= ME_twips2pointsX(c, para->fmt.dxOffset); /* The left edge, stored in dxStartIndent affected just the first edge */ - startX = firstX - ME_twips2pointsX(c, para->pFmt->dxStartIndent); + startX = firstX - ME_twips2pointsX(c, para->fmt.dxStartIndent); rowY = c->pt.y + para->pt.y; - if (para->pFmt->dwMask & PFM_SPACEBEFORE) - rowY += ME_twips2pointsY(c, para->pFmt->dySpaceBefore); + if (para->fmt.dwMask & PFM_SPACEBEFORE) + rowY += ME_twips2pointsY(c, para->fmt.dySpaceBefore); nHeight = ME_FindItemFwd(paragraph, diStartRow)->member.row.nHeight; rowBottom = rowY + nHeight; /* Draw horizontal lines */ MoveToEx(c->hDC, firstX, rowY, &oldPt); - i = para->pFmt->cTabCount - 1; - endX = startX + ME_twips2pointsX(c, para->pFmt->rgxTabs[i] & 0x00ffffff) + 1; + i = para->fmt.cTabCount - 1; + endX = startX + ME_twips2pointsX(c, para->fmt.rgxTabs[i] & 0x00ffffff) + 1; LineTo(c->hDC, endX, rowY); - pNextFmt = para->next_para->member.para.pFmt; + pNextFmt = ¶->next_para->member.para.fmt; /* The bottom of the row only needs to be drawn if the next row is * not a table. */ if (!(pNextFmt && pNextFmt->dwMask & PFM_TABLE && pNextFmt->wEffects && @@ -854,9 +883,9 @@ static void ME_DrawTableBorders(ME_Context *c, ME_DisplayItem *paragraph) /* Draw vertical lines */ MoveToEx(c->hDC, firstX, rowY, NULL); LineTo(c->hDC, firstX, rowBottom); - for (i = 0; i < para->pFmt->cTabCount; i++) + for (i = 0; i < para->fmt.cTabCount; i++) { - int rightBoundary = para->pFmt->rgxTabs[i] & 0x00ffffff; + int rightBoundary = para->fmt.rgxTabs[i] & 0x00ffffff; endX = startX + ME_twips2pointsX(c, rightBoundary); MoveToEx(c->hDC, endX, rowY, NULL); LineTo(c->hDC, endX, rowBottom); @@ -869,6 +898,28 @@ static void ME_DrawTableBorders(ME_Context *c, ME_DisplayItem *paragraph) } } +static void draw_para_number( ME_Context *c, ME_DisplayItem *p ) +{ + ME_Paragraph *para = &p->member.para; + HFONT old_font; + int x, y; + COLORREF old_text; + + if (para->fmt.wNumbering) + { + old_font = ME_SelectStyleFont( c, para->para_num.style ); + old_text = SetTextColor( c->hDC, get_text_color( c, para->para_num.style, FALSE ) ); + + x = c->pt.x + para->para_num.pt.x; + y = c->pt.y + para->pt.y + para->para_num.pt.y; + + ExtTextOutW( c->hDC, x, y, 0, NULL, para->para_num.text->szData, para->para_num.text->nLen, NULL ); + + SetTextColor( c->hDC, old_text ); + ME_UnselectStyleFont( c, para->para_num.style, old_font ); + } +} + static void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) { int align = SetTextAlign(c->hDC, TA_BASELINE); @@ -994,6 +1045,7 @@ static void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) } ME_DrawTableBorders(c, paragraph); + draw_para_number(c, paragraph); SetTextAlign(c->hDC, align); } diff --git a/reactos/dll/win32/riched20/para.c b/reactos/dll/win32/riched20/para.c index c762cf0c0fe..6c023f2d96d 100644 --- a/reactos/dll/win32/riched20/para.c +++ b/reactos/dll/win32/riched20/para.c @@ -27,8 +27,7 @@ static ME_DisplayItem *make_para(ME_TextEditor *editor) { ME_DisplayItem *item = ME_MakeDI(diParagraph); - item->member.para.pFmt = ALLOC_OBJ(PARAFORMAT2); - ME_SetDefaultParaFormat(editor, item->member.para.pFmt); + ME_SetDefaultParaFormat(editor, &item->member.para.fmt); item->member.para.nFlags = MEPF_REWRAP; return item; } @@ -53,11 +52,12 @@ void ME_MakeFirstParagraph(ME_TextEditor *editor) GetObjectW(hf, sizeof(LOGFONTW), &lf); ZeroMemory(&cf, sizeof(cf)); cf.cbSize = sizeof(cf); - cf.dwMask = CFM_BACKCOLOR|CFM_COLOR|CFM_FACE|CFM_SIZE|CFM_CHARSET; + cf.dwMask = CFM_ANIMATION|CFM_BACKCOLOR|CFM_CHARSET|CFM_COLOR|CFM_FACE|CFM_KERNING|CFM_LCID|CFM_OFFSET; + cf.dwMask |= CFM_REVAUTHOR|CFM_SIZE|CFM_SPACING|CFM_STYLE|CFM_UNDERLINETYPE|CFM_WEIGHT; cf.dwMask |= CFM_ALLCAPS|CFM_BOLD|CFM_DISABLED|CFM_EMBOSS|CFM_HIDDEN; cf.dwMask |= CFM_IMPRINT|CFM_ITALIC|CFM_LINK|CFM_OUTLINE|CFM_PROTECTED; cf.dwMask |= CFM_REVISED|CFM_SHADOW|CFM_SMALLCAPS|CFM_STRIKEOUT; - cf.dwMask |= CFM_SUBSCRIPT|CFM_UNDERLINETYPE|CFM_WEIGHT; + cf.dwMask |= CFM_SUBSCRIPT|CFM_UNDERLINE; cf.dwEffects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR; lstrcpyW(cf.szFaceName, lf.lfFaceName); @@ -66,10 +66,12 @@ void ME_MakeFirstParagraph(ME_TextEditor *editor) if (lf.lfWeight > FW_NORMAL) cf.dwEffects |= CFE_BOLD; cf.wWeight = lf.lfWeight; if (lf.lfItalic) cf.dwEffects |= CFE_ITALIC; - cf.bUnderlineType = (lf.lfUnderline) ? CFU_CF1UNDERLINE : CFU_UNDERLINENONE; + if (lf.lfUnderline) cf.dwEffects |= CFE_UNDERLINE; + cf.bUnderlineType = CFU_UNDERLINE; if (lf.lfStrikeOut) cf.dwEffects |= CFE_STRIKEOUT; cf.bPitchAndFamily = lf.lfPitchAndFamily; cf.bCharSet = lf.lfCharSet; + cf.lcid = GetSystemDefaultLCID(); style = ME_MakeStyle(&cf); text->pDefaultStyle = style; @@ -82,6 +84,8 @@ void ME_MakeFirstParagraph(ME_TextEditor *editor) run->member.run.len = eol_len; run->member.run.para = ¶->member.para; + para->member.para.eop_run = &run->member.run; + ME_InsertBefore(text->pLast, para); ME_InsertBefore(text->pLast, run); para->member.para.prev_para = text->pFirst; @@ -110,29 +114,234 @@ void ME_MarkAllForWrapping(ME_TextEditor *editor) static void ME_UpdateTableFlags(ME_DisplayItem *para) { - para->member.para.pFmt->dwMask |= PFM_TABLE|PFM_TABLEROWDELIMITER; + para->member.para.fmt.dwMask |= PFM_TABLE|PFM_TABLEROWDELIMITER; if (para->member.para.pCell) { para->member.para.nFlags |= MEPF_CELL; } else { para->member.para.nFlags &= ~MEPF_CELL; } if (para->member.para.nFlags & MEPF_ROWEND) { - para->member.para.pFmt->wEffects |= PFE_TABLEROWDELIMITER; + para->member.para.fmt.wEffects |= PFE_TABLEROWDELIMITER; } else { - para->member.para.pFmt->wEffects &= ~PFE_TABLEROWDELIMITER; + para->member.para.fmt.wEffects &= ~PFE_TABLEROWDELIMITER; } if (para->member.para.nFlags & (MEPF_ROWSTART|MEPF_CELL|MEPF_ROWEND)) - para->member.para.pFmt->wEffects |= PFE_TABLE; + para->member.para.fmt.wEffects |= PFE_TABLE; else - para->member.para.pFmt->wEffects &= ~PFE_TABLE; + para->member.para.fmt.wEffects &= ~PFE_TABLE; } -static BOOL ME_SetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, const PARAFORMAT2 *pFmt) +static inline BOOL para_num_same_list( const PARAFORMAT2 *item, const PARAFORMAT2 *base ) +{ + return item->wNumbering == base->wNumbering && + item->wNumberingStart == base->wNumberingStart && + item->wNumberingStyle == base->wNumberingStyle && + !(item->wNumberingStyle & PFNS_NEWNUMBER); +} + +static int para_num_get_num( ME_Paragraph *para ) +{ + ME_DisplayItem *prev; + int num = para->fmt.wNumberingStart; + + for (prev = para->prev_para; prev->type == diParagraph; + para = &prev->member.para, prev = prev->member.para.prev_para, num++) + { + if (!para_num_same_list( &prev->member.para.fmt, ¶->fmt )) break; + } + return num; +} + +static ME_String *para_num_get_str( ME_Paragraph *para, WORD num ) +{ + /* max 4 Roman letters (representing '8') / decade + '(' + ')' */ + ME_String *str = ME_MakeStringEmpty( 20 + 2 ); + WCHAR *p; + static const WCHAR fmtW[] = {'%', 'd', 0}; + static const WORD letter_base[] = { 1, 26, 26 * 26, 26 * 26 * 26 }; + /* roman_base should start on a '5' not a '1', otherwise the 'total' code will need adjusting. + 'N' and 'O' are what MS uses for 5000 and 10000, their version doesn't work well above 30000, + but we'll use 'P' as the obvious extension, this gets us up to 2^16, which is all we care about. */ + static const struct + { + int base; + char letter; + } + roman_base[] = + { + {50000, 'P'}, {10000, 'O'}, {5000, 'N'}, {1000, 'M'}, + {500, 'D'}, {100, 'C'}, {50, 'L'}, {10, 'X'}, {5, 'V'}, {1, 'I'} + }; + int i, len; + WORD letter, total, char_offset = 0; + + if (!str) return NULL; + + p = str->szData; + + if ((para->fmt.wNumberingStyle & 0xf00) == PFNS_PARENS) + *p++ = '('; + + switch (para->fmt.wNumbering) + { + case PFN_ARABIC: + default: + p += sprintfW( p, fmtW, num ); + break; + + case PFN_LCLETTER: + char_offset = 'a' - 'A'; + /* fall through */ + case PFN_UCLETTER: + if (!num) num = 1; + + /* This is not base-26 (or 27) as zeros don't count unless they are leading zeros. + It's simplest to start with the least significant letter, so first calculate how many letters are needed. */ + for (i = 0, total = 0; i < sizeof(letter_base) / sizeof(letter_base[0]); i++) + { + total += letter_base[i]; + if (num < total) break; + } + len = i; + for (i = 0; i < len; i++) + { + num -= letter_base[i]; + letter = (num / letter_base[i]) % 26; + p[len - i - 1] = letter + 'A' + char_offset; + } + p += len; + *p = 0; + break; + + case PFN_LCROMAN: + char_offset = 'a' - 'A'; + /* fall through */ + case PFN_UCROMAN: + if (!num) num = 1; + + for (i = 0; i < sizeof(roman_base) / sizeof(roman_base[0]); i++) + { + if (i > 0) + { + if (i % 2 == 0) /* eg 5000, check for 9000 */ + total = roman_base[i].base + 4 * roman_base[i + 1].base; + else /* eg 1000, check for 4000 */ + total = 4 * roman_base[i].base; + + if (num / total) + { + *p++ = roman_base[(i & ~1) + 1].letter + char_offset; + *p++ = roman_base[i - 1].letter + char_offset; + num -= total; + continue; + } + } + + len = num / roman_base[i].base; + while (len--) + { + *p++ = roman_base[i].letter + char_offset; + num -= roman_base[i].base; + } + } + *p = 0; + break; + } + + switch (para->fmt.wNumberingStyle & 0xf00) + { + case PFNS_PARENS: + case PFNS_PAREN: + *p++ = ')'; + *p = 0; + break; + + case PFNS_PERIOD: + *p++ = '.'; + *p = 0; + break; + } + + str->nLen = p - str->szData; + return str; +} + +void para_num_init( ME_Context *c, ME_Paragraph *para ) +{ + ME_Style *style; + CHARFORMAT2W cf; + static const WCHAR bullet_font[] = {'S','y','m','b','o','l',0}; + static const WCHAR bullet_str[] = {0xb7, 0}; + static const WCHAR spaceW[] = {' ', 0}; + HFONT old_font; + SIZE sz; + + if (para->para_num.style && para->para_num.text) return; + + if (!para->para_num.style) + { + style = para->eop_run->style; + + if (para->fmt.wNumbering == PFN_BULLET) + { + cf.cbSize = sizeof(cf); + cf.dwMask = CFM_FACE | CFM_CHARSET; + memcpy( cf.szFaceName, bullet_font, sizeof(bullet_font) ); + cf.bCharSet = SYMBOL_CHARSET; + style = ME_ApplyStyle( c->editor, style, &cf ); + } + else + { + ME_AddRefStyle( style ); + } + + para->para_num.style = style; + } + + if (!para->para_num.text) + { + if (para->fmt.wNumbering != PFN_BULLET) + para->para_num.text = para_num_get_str( para, para_num_get_num( para ) ); + else + para->para_num.text = ME_MakeStringConst( bullet_str, 1 ); + } + + old_font = ME_SelectStyleFont( c, para->para_num.style ); + GetTextExtentPointW( c->hDC, para->para_num.text->szData, para->para_num.text->nLen, &sz ); + para->para_num.width = sz.cx; + GetTextExtentPointW( c->hDC, spaceW, 1, &sz ); + para->para_num.width += sz.cx; + ME_UnselectStyleFont( c, para->para_num.style, old_font ); +} + +void para_num_clear( struct para_num *pn ) +{ + if (pn->style) + { + ME_ReleaseStyle( pn->style ); + pn->style = NULL; + } + ME_DestroyString( pn->text ); + pn->text = NULL; +} + +static void para_num_clear_list( ME_Paragraph *para, const PARAFORMAT2 *orig_fmt ) +{ + do + { + para->nFlags |= MEPF_REWRAP; + para_num_clear( ¶->para_num ); + if (para->next_para->type != diParagraph) break; + para = ¶->next_para->member.para; + } while (para_num_same_list( ¶->fmt, orig_fmt )); +} + +static BOOL ME_SetParaFormat(ME_TextEditor *editor, ME_Paragraph *para, const PARAFORMAT2 *pFmt) { PARAFORMAT2 copy; DWORD dwMask; - assert(para->member.para.pFmt->cbSize == sizeof(PARAFORMAT2)); + assert(para->fmt.cbSize == sizeof(PARAFORMAT2)); dwMask = pFmt->dwMask; if (pFmt->cbSize < sizeof(PARAFORMAT)) return FALSE; @@ -141,27 +350,27 @@ static BOOL ME_SetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, const else dwMask &= PFM_ALL2; - add_undo_set_para_fmt( editor, ¶->member.para ); + add_undo_set_para_fmt( editor, para ); - copy = *para->member.para.pFmt; + copy = para->fmt; #define COPY_FIELD(m, f) \ if (dwMask & (m)) { \ - para->member.para.pFmt->dwMask |= m; \ - para->member.para.pFmt->f = pFmt->f; \ + para->fmt.dwMask |= m; \ + para->fmt.f = pFmt->f; \ } COPY_FIELD(PFM_NUMBERING, wNumbering); COPY_FIELD(PFM_STARTINDENT, dxStartIndent); if (dwMask & PFM_OFFSETINDENT) - para->member.para.pFmt->dxStartIndent += pFmt->dxStartIndent; + para->fmt.dxStartIndent += pFmt->dxStartIndent; COPY_FIELD(PFM_RIGHTINDENT, dxRightIndent); COPY_FIELD(PFM_OFFSET, dxOffset); COPY_FIELD(PFM_ALIGNMENT, wAlignment); if (dwMask & PFM_TABSTOPS) { - para->member.para.pFmt->cTabCount = pFmt->cTabCount; - memcpy(para->member.para.pFmt->rgxTabs, pFmt->rgxTabs, pFmt->cTabCount*sizeof(LONG)); + para->fmt.cTabCount = pFmt->cTabCount; + memcpy(para->fmt.rgxTabs, pFmt->rgxTabs, pFmt->cTabCount*sizeof(LONG)); } #define EFFECTS_MASK (PFM_RTLPARA|PFM_KEEP|PFM_KEEPNEXT|PFM_PAGEBREAKBEFORE| \ @@ -170,9 +379,9 @@ static BOOL ME_SetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, const /* 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); + para->fmt.dwMask |= dwMask & EFFECTS_MASK; + para->fmt.wEffects &= ~HIWORD(dwMask); + para->fmt.wEffects |= pFmt->wEffects & HIWORD(dwMask); } #undef EFFECTS_MASK @@ -190,11 +399,19 @@ static BOOL ME_SetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, const COPY_FIELD(PFM_BORDER, wBorderWidth); COPY_FIELD(PFM_BORDER, wBorders); - para->member.para.pFmt->dwMask |= dwMask; + para->fmt.dwMask |= dwMask; #undef COPY_FIELD - if (memcmp(©, para->member.para.pFmt, sizeof(PARAFORMAT2))) - para->member.para.nFlags |= MEPF_REWRAP; + if (memcmp(©, ¶->fmt, sizeof(PARAFORMAT2))) + { + para->nFlags |= MEPF_REWRAP; + if (((dwMask & PFM_NUMBERING) && (copy.wNumbering != para->fmt.wNumbering)) || + ((dwMask & PFM_NUMBERINGSTART) && (copy.wNumberingStart != para->fmt.wNumberingStart)) || + ((dwMask & PFM_NUMBERINGSTYLE) && (copy.wNumberingStyle != para->fmt.wNumberingStyle))) + { + para_num_clear_list( para, © ); + } + } return TRUE; } @@ -225,7 +442,11 @@ ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, } assert(run->type == diRun); run_para = ME_GetParagraph(run); - assert(run_para->member.para.pFmt->cbSize == sizeof(PARAFORMAT2)); + assert(run_para->member.para.fmt.cbSize == sizeof(PARAFORMAT2)); + + /* Clear any cached para numbering following this paragraph */ + if (run_para->member.para.fmt.wNumbering) + para_num_clear_list( &run_para->member.para, &run_para->member.para.fmt ); new_para->member.para.text = ME_VSplitString( run_para->member.para.text, run->member.run.nCharOfs ); @@ -260,7 +481,7 @@ ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, new_para->member.para.nFlags = MEPF_REWRAP; /* FIXME initialize format style and call ME_SetParaFormat blah blah */ - *new_para->member.para.pFmt = *run_para->member.para.pFmt; + new_para->member.para.fmt = run_para->member.para.fmt; new_para->member.para.border = run_para->member.para.border; /* insert paragraph into paragraph double linked list */ @@ -273,6 +494,10 @@ ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, ME_InsertBefore(run, new_para); ME_InsertBefore(new_para, end_run); + /* Fix up the paras' eop_run ptrs */ + new_para->member.para.eop_run = run_para->member.para.eop_run; + run_para->member.para.eop_run = &end_run->member.run; + if (!editor->bEmulateVersion10) { /* v4.1 */ if (paraFlags & (MEPF_ROWSTART|MEPF_CELL)) { @@ -345,6 +570,10 @@ ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp, assert(tp->member.para.next_para); assert(tp->member.para.next_para->type == diParagraph); + /* Clear any cached para numbering following this paragraph */ + if (tp->member.para.fmt.wNumbering) + para_num_clear_list( &tp->member.para, &tp->member.para.fmt ); + pNext = tp->member.para.next_para; /* Need to locate end-of-paragraph run here, in order to know end_len */ @@ -399,7 +628,7 @@ ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp, if (!keepFirstParaFormat) { add_undo_set_para_fmt( editor, &tp->member.para ); - *tp->member.para.pFmt = *pNext->member.para.pFmt; + tp->member.para.fmt = pNext->member.para.fmt; tp->member.para.border = pNext->member.para.border; } @@ -430,6 +659,9 @@ ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp, pTmp->member.run.para = &tp->member.para; } while(1); + /* Fix up the para's eop_run ptr */ + tp->member.para.eop_run = pNext->member.para.eop_run; + ME_Remove(pRun); ME_DestroyDisplayItem(pRun); @@ -551,7 +783,7 @@ BOOL ME_SetSelectionParaFormat(ME_TextEditor *editor, const PARAFORMAT2 *pFmt) ME_GetSelectionParas(editor, ¶, ¶_end); do { - ME_SetParaFormat(editor, para, pFmt); + ME_SetParaFormat(editor, ¶->member.para, pFmt); if (para == para_end) break; para = para->member.para.next_para; @@ -566,9 +798,9 @@ static void ME_GetParaFormat(ME_TextEditor *editor, { UINT cbSize = pFmt->cbSize; if (pFmt->cbSize >= sizeof(PARAFORMAT2)) { - *pFmt = *para->member.para.pFmt; + *pFmt = para->member.para.fmt; } else { - CopyMemory(pFmt, para->member.para.pFmt, pFmt->cbSize); + CopyMemory(pFmt, ¶->member.para.fmt, pFmt->cbSize); pFmt->dwMask &= PFM_ALL; } pFmt->cbSize = cbSize; @@ -592,7 +824,7 @@ void ME_GetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt) while (para != para_end) { para = para->member.para.next_para; - curFmt = para->member.para.pFmt; + curFmt = ¶->member.para.fmt; #define CHECK_FIELD(m, f) \ if (pFmt->f != curFmt->f) pFmt->dwMask &= ~(m); @@ -603,7 +835,7 @@ void ME_GetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt) CHECK_FIELD(PFM_OFFSET, dxOffset); CHECK_FIELD(PFM_ALIGNMENT, wAlignment); if (pFmt->dwMask & PFM_TABSTOPS) { - if (pFmt->cTabCount != para->member.para.pFmt->cTabCount || + if (pFmt->cTabCount != para->member.para.fmt.cTabCount || memcmp(pFmt->rgxTabs, curFmt->rgxTabs, curFmt->cTabCount*sizeof(int))) pFmt->dwMask &= ~PFM_TABSTOPS; } diff --git a/reactos/dll/win32/riched20/reader.c b/reactos/dll/win32/riched20/reader.c index d012305443f..db45c9e8677 100644 --- a/reactos/dll/win32/riched20/reader.c +++ b/reactos/dll/win32/riched20/reader.c @@ -1763,8 +1763,8 @@ static RTFKey rtfKey[] = { rtfDestination, rtfFooterFirst, "footerf", 0 }, { rtfDestination, rtfParNumText, "pntext", 0 }, { rtfDestination, rtfParNumbering, "pn", 0 }, - { rtfDestination, rtfParNumTextAfter, "pntexta", 0 }, - { rtfDestination, rtfParNumTextBefore, "pntextb", 0 }, + { rtfDestination, rtfParNumTextAfter, "pntxta", 0 }, + { rtfDestination, rtfParNumTextBefore, "pntxtb", 0 }, { rtfDestination, rtfBookmarkStart, "bkmkstart", 0 }, { rtfDestination, rtfBookmarkEnd, "bkmkend", 0 }, { rtfDestination, rtfPict, "pict", 0 }, diff --git a/reactos/dll/win32/riched20/richole.c b/reactos/dll/win32/riched20/richole.c index e38009dba8a..050b33cdc7d 100644 --- a/reactos/dll/win32/riched20/richole.c +++ b/reactos/dll/win32/riched20/richole.c @@ -437,7 +437,7 @@ static HRESULT get_textfont_prop_for_pos(const IRichEditOleImpl *reole, int pos, ME_CursorFromCharOfs(reole->editor, pos, &from); to = from; - ME_MoveCursorChars(reole->editor, &to, 1); + ME_MoveCursorChars(reole->editor, &to, 1, FALSE); ME_GetCharFormat(reole->editor, &from, &to, &fmt); switch (propid) diff --git a/reactos/dll/win32/riched20/run.c b/reactos/dll/win32/riched20/run.c index f79e81efed8..445bbc2f918 100644 --- a/reactos/dll/win32/riched20/run.c +++ b/reactos/dll/win32/riched20/run.c @@ -616,17 +616,16 @@ SIZE ME_GetRunSizeCommon(ME_Context *c, const ME_Paragraph *para, ME_Run *run, i int startx, int *pAscent, int *pDescent) { SIZE size; - int nMaxLen = run->len; + WCHAR spaceW[] = {' ',0}; - if (nLen>nMaxLen) - nLen = nMaxLen; + nLen = min( nLen, run->len ); - /* FIXME the following call also ensures that TEXTMETRIC structure is filled - * this is wasteful for MERF_NONTEXT runs, but that shouldn't matter - * in practice - */ - - if (para->nFlags & MEPF_COMPLEX) + if (run->nFlags & MERF_ENDPARA) + { + nLen = min( nLen, 1 ); + ME_GetTextExtent(c, spaceW, nLen, run->style, &size); + } + else if (para->nFlags & MEPF_COMPLEX) { size.cx = run->nWidth; } @@ -647,7 +646,7 @@ SIZE ME_GetRunSizeCommon(ME_Context *c, const ME_Paragraph *para, ME_Run *run, i if (run->nFlags & MERF_TAB) { int pos = 0, i = 0, ppos, shift = 0; - PARAFORMAT2 *pFmt = para->pFmt; + const PARAFORMAT2 *pFmt = ¶->fmt; if (c->editor->bEmulateVersion10 && /* v1.0 - 3.0 */ pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE) @@ -759,28 +758,26 @@ void ME_SetCharFormat(ME_TextEditor *editor, ME_Cursor *start, ME_Cursor *end, C for (run = start_run; run != end_run; run = ME_FindItemFwd( run, diRun )) { ME_Style *new_style = ME_ApplyStyle(editor, run->member.run.style, pFmt); + ME_Paragraph *para = run->member.run.para; add_undo_set_char_fmt( editor, run->member.run.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->member.run.para->nFlags |= MEPF_REWRAP; + + /* The para numbering style depends on the eop style */ + if ((run->member.run.nFlags & MERF_ENDPARA) && para->para_num.style) + { + ME_ReleaseStyle(para->para_num.style); + para->para_num.style = NULL; + } + para->nFlags |= MEPF_REWRAP; } } static void ME_GetRunCharFormat(ME_TextEditor *editor, ME_DisplayItem *run, CHARFORMAT2W *pFmt) { ME_CopyCharFormat(pFmt, &run->member.run.style->fmt); - if ((pFmt->dwMask & CFM_UNDERLINETYPE) && (pFmt->bUnderlineType == CFU_CF1UNDERLINE)) - { - pFmt->dwMask |= CFM_UNDERLINE; - pFmt->dwEffects |= CFE_UNDERLINE; - } - if ((pFmt->dwMask & CFM_UNDERLINETYPE) && (pFmt->bUnderlineType == CFU_UNDERLINENONE)) - { - pFmt->dwMask |= CFM_UNDERLINE; - pFmt->dwEffects &= ~CFE_UNDERLINE; - } } /****************************************************************************** diff --git a/reactos/dll/win32/riched20/string.c b/reactos/dll/win32/riched20/string.c index 44726b35941..cfb149a93e2 100644 --- a/reactos/dll/win32/riched20/string.c +++ b/reactos/dll/win32/riched20/string.c @@ -24,27 +24,59 @@ WINE_DEFAULT_DEBUG_CHANNEL(richedit); static int ME_GetOptimalBuffer(int nLen) { - /* FIXME: This seems wasteful for tabs and end of lines strings, - * since they have a small fixed length. */ return ((sizeof(WCHAR) * nLen) + 128) & ~63; } -/* Create a buffer (uninitialized string) of size nMaxChars */ -static ME_String *ME_MakeStringB(int nMaxChars) +static ME_String *make_string( void (*free)(ME_String *) ) { - ME_String *s = ALLOC_OBJ(ME_String); + ME_String *s = heap_alloc( sizeof(*s) ); + if (s) s->free = free; + return s; +} + +/* Create a ME_String using the const string provided. + * str must exist for the lifetime of the returned ME_String. + */ +ME_String *ME_MakeStringConst(const WCHAR *str, int len) +{ + ME_String *s = make_string( NULL ); + if (!s) return NULL; + + s->szData = (WCHAR *)str; + s->nLen = len; + s->nBuffer = 0; + return s; +} + +static void heap_string_free(ME_String *s) +{ + heap_free( s->szData ); +} + +/* Create a buffer (uninitialized string) of size nMaxChars */ +ME_String *ME_MakeStringEmpty(int nMaxChars) +{ + ME_String *s = make_string( heap_string_free ); + + if (!s) return NULL; s->nLen = nMaxChars; s->nBuffer = ME_GetOptimalBuffer(s->nLen + 1); - s->szData = ALLOC_N_OBJ(WCHAR, s->nBuffer); + s->szData = heap_alloc( s->nBuffer * sizeof(WCHAR) ); + if (!s->szData) + { + heap_free( s ); + return NULL; + } s->szData[s->nLen] = 0; return s; } ME_String *ME_MakeStringN(LPCWSTR szText, int nMaxChars) { - ME_String *s = ME_MakeStringB(nMaxChars); - /* Native allows NULL chars */ + ME_String *s = ME_MakeStringEmpty(nMaxChars); + + if (!s) return NULL; memcpy(s->szData, szText, s->nLen * sizeof(WCHAR)); return s; } @@ -53,7 +85,9 @@ ME_String *ME_MakeStringN(LPCWSTR szText, int nMaxChars) ME_String *ME_MakeStringR(WCHAR cRepeat, int nMaxChars) { int i; - ME_String *s = ME_MakeStringB(nMaxChars); + ME_String *s = ME_MakeStringEmpty(nMaxChars); + + if (!s) return NULL; for (i = 0; i < nMaxChars; i++) s->szData[i] = cRepeat; return s; @@ -62,20 +96,24 @@ ME_String *ME_MakeStringR(WCHAR cRepeat, int nMaxChars) void ME_DestroyString(ME_String *s) { if (!s) return; - FREE_OBJ(s->szData); - FREE_OBJ(s); + if (s->free) s->free( s ); + heap_free( s ); } BOOL ME_InsertString(ME_String *s, int ofs, const WCHAR *insert, int len) { DWORD new_len = s->nLen + len + 1; + WCHAR *new; + + assert( s->nBuffer ); /* Not a const string */ 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; + new = heap_realloc( s->szData, s->nBuffer * sizeof(WCHAR) ); + if (!new) return FALSE; + s->szData = new; } memmove( s->szData + ofs + len, s->szData + ofs, (s->nLen - ofs + 1) * sizeof(WCHAR) ); @@ -94,13 +132,13 @@ ME_String *ME_VSplitString(ME_String *orig, int charidx) { ME_String *s; - /*if (charidx<0) charidx = 0; - if (charidx>orig->nLen) charidx = orig->nLen; - */ + assert(orig->nBuffer); /* Not a const string */ assert(charidx>=0); assert(charidx<=orig->nLen); s = ME_MakeStringN(orig->szData+charidx, orig->nLen-charidx); + if (!s) return NULL; + orig->nLen = charidx; orig->szData[charidx] = '\0'; return s; @@ -110,6 +148,7 @@ void ME_StrDeleteV(ME_String *s, int nVChar, int nChars) { int end_ofs = nVChar + nChars; + assert(s->nBuffer); /* Not a const string */ assert(nChars >= 0); assert(nVChar >= 0); assert(end_ofs <= s->nLen); @@ -163,6 +202,7 @@ ME_CallWordBreakProc(ME_TextEditor *editor, WCHAR *str, INT len, INT start, INT int buffer_size = WideCharToMultiByte(CP_ACP, 0, str, len, NULL, 0, NULL, NULL); char *buffer = heap_alloc(buffer_size); + if (!buffer) return 0; WideCharToMultiByte(CP_ACP, 0, str, len, buffer, buffer_size, NULL, NULL); result = editor->pfnWordBreak((WCHAR*)buffer, start, buffer_size, code); @@ -187,7 +227,7 @@ LPWSTR ME_ToUnicode(LONG codepage, LPVOID psz, INT *len) if(!nChars) return NULL; - if((tmp = ALLOC_N_OBJ(WCHAR, nChars)) != NULL) + if((tmp = heap_alloc( nChars * sizeof(WCHAR) )) != NULL) *len = MultiByteToWideChar(codepage, 0, psz, -1, tmp, nChars) - 1; return tmp; } @@ -196,5 +236,5 @@ LPWSTR ME_ToUnicode(LONG codepage, LPVOID psz, INT *len) void ME_EndToUnicode(LONG codepage, LPVOID psz) { if (codepage != CP_UNICODE) - FREE_OBJ(psz); + heap_free( psz ); } diff --git a/reactos/dll/win32/riched20/style.c b/reactos/dll/win32/riched20/style.c index 06c0e6f65eb..1a944cbb798 100644 --- a/reactos/dll/win32/riched20/style.c +++ b/reactos/dll/win32/riched20/style.c @@ -79,20 +79,6 @@ static CHARFORMAT2W *ME_ToCFAny(CHARFORMAT2W *to, CHARFORMAT2W *from) CHARFORMATA *t = (CHARFORMATA *)to; CopyMemory(t, from, FIELD_OFFSET(CHARFORMATA, szFaceName)); WideCharToMultiByte(CP_ACP, 0, from->szFaceName, -1, t->szFaceName, sizeof(t->szFaceName), NULL, NULL); - if (from->dwMask & CFM_UNDERLINETYPE) - { - switch (from->bUnderlineType) - { - case CFU_CF1UNDERLINE: - to->dwMask |= CFM_UNDERLINE; - to->dwEffects |= CFE_UNDERLINE; - break; - case CFU_UNDERLINENONE: - to->dwMask |= CFM_UNDERLINE; - to->dwEffects &= ~CFE_UNDERLINE; - break; - } - } t->cbSize = sizeof(*t); /* it was overwritten by CopyMemory */ return to; } @@ -100,20 +86,6 @@ static CHARFORMAT2W *ME_ToCFAny(CHARFORMAT2W *to, CHARFORMAT2W *from) { CHARFORMATW *t = (CHARFORMATW *)to; CopyMemory(t, from, sizeof(*t)); - if (from->dwMask & CFM_UNDERLINETYPE) - { - switch (from->bUnderlineType) - { - case CFU_CF1UNDERLINE: - to->dwMask |= CFM_UNDERLINE; - to->dwEffects |= CFE_UNDERLINE; - break; - case CFU_UNDERLINENONE: - to->dwMask |= CFM_UNDERLINE; - to->dwEffects &= ~CFE_UNDERLINE; - break; - } - } t->cbSize = sizeof(*t); /* it was overwritten by CopyMemory */ return to; } @@ -195,7 +167,6 @@ ME_Style *ME_ApplyStyle(ME_TextEditor *editor, ME_Style *sSrc, CHARFORMAT2W *mod } COPY_STYLE_ITEM(CFM_SPACING, sSpacing); COPY_STYLE_ITEM(CFM_STYLE, sStyle); - COPY_STYLE_ITEM(CFM_UNDERLINETYPE, bUnderlineType); COPY_STYLE_ITEM(CFM_WEIGHT, wWeight); /* FIXME: this is not documented this way, but that's the more logical */ COPY_STYLE_ITEM(CFM_FACE, bPitchAndFamily); @@ -210,12 +181,18 @@ ME_Style *ME_ApplyStyle(ME_TextEditor *editor, ME_Style *sSrc, CHARFORMAT2W *mod else fmt.dwEffects &= ~CFE_AUTOCOLOR; } - if (mod->dwMask & CFM_UNDERLINE) + + COPY_STYLE_ITEM(CFM_UNDERLINETYPE, bUnderlineType); + /* If the CFM_UNDERLINE effect is not specified set it appropiately */ + if ((mod->dwMask & CFM_UNDERLINETYPE) && !(mod->dwMask & CFM_UNDERLINE)) { - fmt.dwMask |= CFM_UNDERLINETYPE; - fmt.bUnderlineType = (mod->dwEffects & CFM_UNDERLINE) ? - CFU_CF1UNDERLINE : CFU_UNDERLINENONE; + fmt.dwMask |= CFM_UNDERLINE; + if (mod->bUnderlineType == CFU_UNDERLINENONE) + fmt.dwEffects &= ~CFE_UNDERLINE; + else + fmt.dwEffects |= CFE_UNDERLINE; } + if (mod->dwMask & CFM_BOLD && !(mod->dwMask & CFM_WEIGHT)) { fmt.wWeight = (mod->dwEffects & CFE_BOLD) ? FW_BOLD : FW_NORMAL; @@ -329,9 +306,8 @@ ME_LogFontFromStyle(ME_Context* c, LOGFONTW *lf, const ME_Style *s) lf->lfWeight = s->fmt.wWeight; if (s->fmt.dwEffects & s->fmt.dwMask & CFM_ITALIC) lf->lfItalic = 1; - if (s->fmt.dwEffects & s->fmt.dwMask & (CFM_UNDERLINE | CFE_LINK)) - lf->lfUnderline = 1; - if (s->fmt.dwMask & CFM_UNDERLINETYPE && s->fmt.bUnderlineType == CFU_CF1UNDERLINE) + if ((s->fmt.dwEffects & s->fmt.dwMask & (CFM_UNDERLINE | CFE_LINK)) && + s->fmt.bUnderlineType == CFU_CF1UNDERLINE) lf->lfUnderline = 1; if (s->fmt.dwEffects & s->fmt.dwMask & CFM_STRIKEOUT) lf->lfStrikeOut = 1; @@ -352,14 +328,13 @@ void ME_CharFormatFromLogFont(HDC hDC, const LOGFONTW *lf, CHARFORMAT2W *fmt) ry = GetDeviceCaps(hDC, LOGPIXELSY); lstrcpyW(fmt->szFaceName, lf->lfFaceName); fmt->dwEffects = 0; - fmt->dwMask = CFM_WEIGHT|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT|CFM_SIZE|CFM_FACE|CFM_CHARSET; + fmt->dwMask = CFM_WEIGHT|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_UNDERLINETYPE|CFM_STRIKEOUT|CFM_SIZE|CFM_FACE|CFM_CHARSET; fmt->wWeight = lf->lfWeight; fmt->yHeight = -lf->lfHeight*1440/ry; if (lf->lfWeight > FW_NORMAL) fmt->dwEffects |= CFM_BOLD; if (lf->lfItalic) fmt->dwEffects |= CFM_ITALIC; if (lf->lfUnderline) fmt->dwEffects |= CFM_UNDERLINE; - /* notice that if a logfont was created with underline due to CFM_LINK, this - would add an erroneous CFM_UNDERLINE. This isn't currently ever a problem. */ + fmt->bUnderlineType = CFU_UNDERLINE; if (lf->lfStrikeOut) fmt->dwEffects |= CFM_STRIKEOUT; fmt->bPitchAndFamily = lf->lfPitchAndFamily; fmt->bCharSet = lf->lfCharSet; @@ -513,12 +488,13 @@ ME_Style *ME_GetInsertStyle(ME_TextEditor *editor, int nCursor) } } -void ME_SaveTempStyle(ME_TextEditor *editor) +void ME_SaveTempStyle(ME_TextEditor *editor, ME_Style *style) { ME_Style *old_style = editor->pBuffer->pCharStyle; - editor->pBuffer->pCharStyle = ME_GetInsertStyle(editor, 0); - if (old_style) - ME_ReleaseStyle(old_style); + + if (style) ME_AddRefStyle( style ); + editor->pBuffer->pCharStyle = style; + if (old_style) ME_ReleaseStyle( old_style ); } void ME_ClearTempStyle(ME_TextEditor *editor) diff --git a/reactos/dll/win32/riched20/table.c b/reactos/dll/win32/riched20/table.c index e78a1df20aa..b834bc7bc34 100644 --- a/reactos/dll/win32/riched20/table.c +++ b/reactos/dll/win32/riched20/table.c @@ -105,9 +105,9 @@ ME_DisplayItem* ME_InsertTableRowStartAtParagraph(ME_TextEditor *editor, para->member.para.pCell = prev_para->member.para.pCell; para->member.para.nFlags |= MEPF_CELL; para->member.para.nFlags &= ~(MEPF_ROWSTART|MEPF_ROWEND); - para->member.para.pFmt->dwMask |= PFM_TABLE|PFM_TABLEROWDELIMITER; - para->member.para.pFmt->wEffects |= PFE_TABLE; - para->member.para.pFmt->wEffects &= ~PFE_TABLEROWDELIMITER; + para->member.para.fmt.dwMask |= PFM_TABLE|PFM_TABLEROWDELIMITER; + para->member.para.fmt.wEffects |= PFE_TABLE; + para->member.para.fmt.wEffects &= ~PFE_TABLEROWDELIMITER; prev_para = para; para = para->member.para.next_para; } @@ -205,12 +205,12 @@ void ME_CheckTablesForCorruption(ME_TextEditor *editor) { while (p->type == diParagraph) { - assert(p->member.para.pFmt->dwMask & PFM_TABLE); - assert(p->member.para.pFmt->dwMask & PFM_TABLEROWDELIMITER); + assert(p->member.para.fmt.dwMask & PFM_TABLE); + assert(p->member.para.fmt.dwMask & PFM_TABLEROWDELIMITER); if (p->member.para.pCell) { assert(p->member.para.nFlags & MEPF_CELL); - assert(p->member.para.pFmt->wEffects & PFE_TABLE); + assert(p->member.para.fmt.wEffects & PFE_TABLE); } if (p->member.para.pCell != pPrev->member.para.pCell) { @@ -225,11 +225,11 @@ void ME_CheckTablesForCorruption(ME_TextEditor *editor) assert(pPrev->member.para.pCell); assert(p->member.para.pCell == pPrev->member.para.pCell->member.cell.parent_cell); - assert(p->member.para.pFmt->wEffects & PFE_TABLEROWDELIMITER); + assert(p->member.para.fmt.wEffects & PFE_TABLEROWDELIMITER); } else if (p->member.para.pCell) { - assert(!(p->member.para.pFmt->wEffects & PFE_TABLEROWDELIMITER)); + assert(!(p->member.para.fmt.wEffects & PFE_TABLEROWDELIMITER)); assert(pPrev->member.para.pCell || pPrev->member.para.nFlags & MEPF_ROWSTART); if (pPrev->member.para.pCell && @@ -244,7 +244,7 @@ void ME_CheckTablesForCorruption(ME_TextEditor *editor) } else if (!(p->member.para.nFlags & MEPF_ROWSTART)) { - assert(!(p->member.para.pFmt->wEffects & PFE_TABLEROWDELIMITER)); + assert(!(p->member.para.fmt.wEffects & PFE_TABLEROWDELIMITER)); /* ROWSTART must be followed by a cell. */ assert(!(p->member.para.nFlags & MEPF_CELL)); /* ROWSTART must be followed by a cell. */ @@ -257,8 +257,8 @@ void ME_CheckTablesForCorruption(ME_TextEditor *editor) while (p->type == diParagraph) { assert(!(p->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND|MEPF_CELL))); - assert(p->member.para.pFmt->dwMask & PFM_TABLE); - assert(!(p->member.para.pFmt->wEffects & PFE_TABLEROWDELIMITER)); + assert(p->member.para.fmt.dwMask & PFM_TABLE); + assert(!(p->member.para.fmt.wEffects & PFE_TABLEROWDELIMITER)); assert(!p->member.para.pCell); p = p->member.para.next_para; } @@ -279,7 +279,7 @@ BOOL ME_IsInTable(ME_DisplayItem *pItem) pItem = ME_GetParagraph(pItem); if (pItem->type != diParagraph) return FALSE; - pFmt = pItem->member.para.pFmt; + pFmt = &pItem->member.para.fmt; return pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE; } @@ -291,7 +291,7 @@ void ME_ProtectPartialTableDeletion(ME_TextEditor *editor, ME_Cursor *c, int *nC ME_DisplayItem *this_para = c->pPara; ME_DisplayItem *end_para; - ME_MoveCursorChars(editor, &c2, *nChars); + ME_MoveCursorChars(editor, &c2, *nChars, FALSE); end_para = c2.pPara; if (c2.pRun->member.run.nFlags & MERF_ENDPARA) { /* End offset might be in the middle of the end paragraph run. @@ -364,8 +364,8 @@ void ME_ProtectPartialTableDeletion(ME_TextEditor *editor, ME_Cursor *c, int *nC int nCharsToBoundary; if ((this_para->member.para.nCharOfs != nOfs || this_para == end_para) && - this_para->member.para.pFmt->dwMask & PFM_TABLE && - this_para->member.para.pFmt->wEffects & PFE_TABLE) + this_para->member.para.fmt.dwMask & PFM_TABLE && + this_para->member.para.fmt.wEffects & PFE_TABLE) { pRun = c->pRun; /* Find the next tab or end paragraph to use as a delete boundary */ @@ -375,8 +375,8 @@ void ME_ProtectPartialTableDeletion(ME_TextEditor *editor, ME_Cursor *c, int *nC - c->pRun->member.run.nCharOfs - c->nOffset; *nChars = min(*nChars, nCharsToBoundary); - } else if (end_para->member.para.pFmt->dwMask & PFM_TABLE && - end_para->member.para.pFmt->wEffects & PFE_TABLE) + } else if (end_para->member.para.fmt.dwMask & PFM_TABLE && + end_para->member.para.fmt.wEffects & PFE_TABLE) { /* The deletion starts from before the row, so don't join it with * previous non-empty paragraphs. */ @@ -438,12 +438,12 @@ ME_DisplayItem* ME_AppendTableRow(ME_TextEditor *editor, insertedCell->member.cell.border = cell->member.cell.border; }; para = ME_InsertTableRowEndFromCursor(editor); - *para->member.para.pFmt = *prevTableEnd->member.para.pFmt; + para->member.para.fmt = prevTableEnd->member.para.fmt; /* return the table row start for the inserted paragraph */ return ME_FindItemFwd(cell, diParagraph)->member.para.next_para; } else { /* v1.0 - 3.0 */ run = ME_FindItemBack(table_row->member.para.next_para, diRun); - pFmt = table_row->member.para.pFmt; + pFmt = &table_row->member.para.fmt; assert(pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE); editor->pCursors[0].pPara = table_row; editor->pCursors[0].pRun = run; diff --git a/reactos/dll/win32/riched20/undo.c b/reactos/dll/win32/riched20/undo.c index 7b22e6de57b..582f88860ca 100644 --- a/reactos/dll/win32/riched20/undo.c +++ b/reactos/dll/win32/riched20/undo.c @@ -155,7 +155,7 @@ BOOL add_undo_set_para_fmt( ME_TextEditor *editor, const ME_Paragraph *para ) 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.fmt = para->fmt; undo->u.set_para_fmt.border = para->border; return TRUE; @@ -189,7 +189,7 @@ BOOL add_undo_split_para( ME_TextEditor *editor, const ME_Paragraph *para, ME_St 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.fmt = para->fmt; undo->u.split_para.border = para->border; undo->u.split_para.flags = para->prev_para->member.para.nFlags & ~MEPF_CELL; @@ -339,7 +339,7 @@ static void ME_PlayUndoItem(ME_TextEditor *editor, struct undo_item *undo) ME_CursorFromCharOfs(editor, undo->u.set_para_fmt.pos, &tmp); para = ME_FindItemBack(tmp.pRun, diParagraph); add_undo_set_para_fmt( editor, ¶->member.para ); - *para->member.para.pFmt = undo->u.set_para_fmt.fmt; + para->member.para.fmt = undo->u.set_para_fmt.fmt; para->member.para.border = undo->u.set_para_fmt.border; para->member.para.nFlags |= MEPF_REWRAP; break; @@ -349,7 +349,7 @@ static void ME_PlayUndoItem(ME_TextEditor *editor, struct undo_item *undo) ME_Cursor start, end; ME_CursorFromCharOfs(editor, undo->u.set_char_fmt.pos, &start); end = start; - ME_MoveCursorChars(editor, &end, undo->u.set_char_fmt.len); + ME_MoveCursorChars(editor, &end, undo->u.set_char_fmt.len, FALSE); ME_SetCharFormat(editor, &start, &end, &undo->u.set_char_fmt.fmt); break; } @@ -398,7 +398,7 @@ static void ME_PlayUndoItem(ME_TextEditor *editor, struct undo_item *undo) undo->u.split_para.eol_str->szData, undo->u.split_para.eol_str->nLen, paraFlags); if (bFixRowStart) new_para->member.para.nFlags |= MEPF_ROWSTART; - *new_para->member.para.pFmt = undo->u.split_para.fmt; + new_para->member.para.fmt = undo->u.split_para.fmt; new_para->member.para.border = undo->u.split_para.border; if (paraFlags) { diff --git a/reactos/dll/win32/riched20/wrap.c b/reactos/dll/win32/riched20/wrap.c index b488bf17f87..e3a70f07d12 100644 --- a/reactos/dll/win32/riched20/wrap.c +++ b/reactos/dll/win32/riched20/wrap.c @@ -33,6 +33,22 @@ WINE_DECLARE_DEBUG_CHANNEL(richedit_check); * - no tabs */ +typedef struct tagME_WrapContext +{ + ME_Style *style; + ME_Context *context; + int nLeftMargin, nRightMargin; + int nFirstMargin; /* Offset to first line's text, always to the text itself even if a para number is present */ + int nParaNumOffset; /* Offset to the para number */ + int nAvailWidth; /* Width avail for text to wrap into. Does not include any para number text */ + int nRow; + POINT pt; + BOOL bOverflown, bWordWrap; + ME_DisplayItem *pPara; + ME_DisplayItem *pRowStart; + + ME_DisplayItem *pLastSplittableRun; +} ME_WrapContext; static BOOL get_run_glyph_buffers( ME_Run *run ) { @@ -182,7 +198,7 @@ static void ME_BeginRow(ME_WrapContext *wc) PARAFORMAT2 *pFmt; ME_DisplayItem *para = wc->pPara; - pFmt = para->member.para.pFmt; + pFmt = ¶->member.para.fmt; wc->pRowStart = NULL; wc->bOverflown = FALSE; wc->pLastSplittableRun = NULL; @@ -204,7 +220,7 @@ static void ME_BeginRow(ME_WrapContext *wc) width -= cell->prev_cell->member.cell.nRightBoundary; if (!cell->prev_cell) { - int rowIndent = ME_GetTableRowEnd(para)->member.para.pFmt->dxStartIndent; + int rowIndent = ME_GetTableRowEnd(para)->member.para.fmt.dxStartIndent; width -= rowIndent; } cell->nWidth = max(ME_twips2pointsX(wc->context, width), 0); @@ -289,7 +305,12 @@ static void ME_InsertRowStart(ME_WrapContext *wc, const ME_DisplayItem *pEnd) BOOL bSkippingSpaces = TRUE; int ascent = 0, descent = 0, width=0, shift = 0, align = 0; - /* wrap text */ + /* Include height of para numbering label */ + if (wc->nRow == 0 && para->fmt.wNumbering) + { + ascent = para->para_num.style->tm.tmAscent; + descent = para->para_num.style->tm.tmDescent; + } for (p = pEnd->prev; p!=wc->pRowStart->prev; p = p->prev) { @@ -326,7 +347,7 @@ static void ME_InsertRowStart(ME_WrapContext *wc, const ME_DisplayItem *pEnd) para->nWidth = max(para->nWidth, width); row = ME_MakeRow(ascent+descent, ascent, width); if (wc->context->editor->bEmulateVersion10 && /* v1.0 - 3.0 */ - (para->pFmt->dwMask & PFM_TABLE) && (para->pFmt->wEffects & PFE_TABLE)) + (para->fmt.dwMask & PFM_TABLE) && (para->fmt.wEffects & PFE_TABLE)) { /* The text was shifted down in ME_BeginRow so move the wrap context * back to where it should be. */ @@ -337,8 +358,8 @@ static void ME_InsertRowStart(ME_WrapContext *wc, const ME_DisplayItem *pEnd) row->member.row.pt = wc->pt; row->member.row.nLMargin = (!wc->nRow ? wc->nFirstMargin : wc->nLeftMargin); row->member.row.nRMargin = wc->nRightMargin; - assert(para->pFmt->dwMask & PFM_ALIGNMENT); - align = para->pFmt->wAlignment; + assert(para->fmt.dwMask & PFM_ALIGNMENT); + align = para->fmt.wAlignment; if (align == PFA_CENTER) shift = max((wc->nAvailWidth-width)/2, 0); if (align == PFA_RIGHT) @@ -353,6 +374,13 @@ static void ME_InsertRowStart(ME_WrapContext *wc, const ME_DisplayItem *pEnd) p->member.run.pt.x += row->member.row.nLMargin+shift; } } + + if (wc->nRow == 0 && para->fmt.wNumbering) + { + para->para_num.pt.x = wc->nParaNumOffset + shift; + para->para_num.pt.y = wc->pt.y + row->member.row.nBaseline; + } + ME_InsertBefore(wc->pRowStart, row); wc->nRow++; wc->pt.y += row->member.row.nHeight; @@ -362,7 +390,7 @@ static void ME_InsertRowStart(ME_WrapContext *wc, const ME_DisplayItem *pEnd) static void ME_WrapEndParagraph(ME_WrapContext *wc, ME_DisplayItem *p) { ME_DisplayItem *para = wc->pPara; - PARAFORMAT2 *pFmt = para->member.para.pFmt; + PARAFORMAT2 *pFmt = ¶->member.para.fmt; if (wc->pRowStart) ME_InsertRowStart(wc, p); if (wc->context->editor->bEmulateVersion10 && /* v1.0 - 3.0 */ @@ -610,8 +638,8 @@ static ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p) wc->pt.x + run->nWidth - wc->context->pt.x > wc->nAvailWidth) { int loc = wc->context->pt.x + wc->nAvailWidth - wc->pt.x; - /* total white run ? */ - if (run->nFlags & MERF_WHITESPACE) { + /* total white run or end para */ + if (run->nFlags & (MERF_WHITESPACE | MERF_ENDPARA)) { /* let the overflow logic handle it */ wc->bOverflown = TRUE; return p; @@ -685,19 +713,19 @@ static ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p) static int ME_GetParaLineSpace(ME_Context* c, ME_Paragraph* para) { int sp = 0, ls = 0; - if (!(para->pFmt->dwMask & PFM_LINESPACING)) return 0; + if (!(para->fmt.dwMask & PFM_LINESPACING)) return 0; /* FIXME: how to compute simply the line space in ls ??? */ /* FIXME: does line spacing include the line itself ??? */ - switch (para->pFmt->bLineSpacingRule) + switch (para->fmt.bLineSpacingRule) { case 0: sp = ls; break; case 1: sp = (3 * ls) / 2; break; case 2: sp = 2 * ls; break; - case 3: sp = ME_twips2pointsY(c, para->pFmt->dyLineSpacing); if (sp < ls) sp = ls; break; - case 4: sp = ME_twips2pointsY(c, para->pFmt->dyLineSpacing); break; - case 5: sp = para->pFmt->dyLineSpacing / 20; break; - default: FIXME("Unsupported spacing rule value %d\n", para->pFmt->bLineSpacingRule); + case 3: sp = ME_twips2pointsY(c, para->fmt.dyLineSpacing); if (sp < ls) sp = ls; break; + case 4: sp = ME_twips2pointsY(c, para->fmt.dyLineSpacing); break; + case 5: sp = para->fmt.dyLineSpacing / 20; break; + default: FIXME("Unsupported spacing rule value %d\n", para->fmt.bLineSpacingRule); } if (c->editor->nZoomNumerator == 0) return sp; @@ -746,7 +774,7 @@ static HRESULT itemize_para( ME_Context *c, ME_DisplayItem *p ) assert( p->type == diParagraph ); - if (para->pFmt->dwMask & PFM_RTLPARA && para->pFmt->wEffects & PFE_RTLPARA) + if (para->fmt.dwMask & PFM_RTLPARA && para->fmt.wEffects & PFE_RTLPARA) state.uBidiLevel = 1; TRACE( "Base embedding level %d\n", state.uBidiLevel ); @@ -855,6 +883,9 @@ static void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) { } ME_PrepareParagraphForWrapping(c, tp); + /* Calculate paragraph numbering label */ + para_num_init( c, &tp->member.para ); + /* For now treating all non-password text as complex for better testing */ if (!c->editor->cPasswordMask /* && ScriptIsComplex( tp->member.para.text->szData, tp->member.para.text->nLen, SIC_COMPLEX ) == S_OK */) @@ -863,21 +894,29 @@ static void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) { shape_para( c, tp ); } - pFmt = tp->member.para.pFmt; + pFmt = &tp->member.para.fmt; wc.context = c; wc.pPara = tp; /* wc.para_style = tp->member.para.style; */ wc.style = NULL; + wc.nParaNumOffset = 0; if (tp->member.para.nFlags & MEPF_ROWEND) { wc.nFirstMargin = wc.nLeftMargin = wc.nRightMargin = 0; } else { int dxStartIndent = pFmt->dxStartIndent; if (tp->member.para.pCell) { - dxStartIndent += ME_GetTableRowEnd(tp)->member.para.pFmt->dxOffset; + dxStartIndent += ME_GetTableRowEnd(tp)->member.para.fmt.dxOffset; } + wc.nLeftMargin = ME_twips2pointsX(c, dxStartIndent + pFmt->dxOffset); wc.nFirstMargin = ME_twips2pointsX(c, dxStartIndent); - wc.nLeftMargin = wc.nFirstMargin + ME_twips2pointsX(c, pFmt->dxOffset); + if (pFmt->wNumbering) + { + wc.nParaNumOffset = wc.nFirstMargin; + dxStartIndent = max( ME_twips2pointsX(c, pFmt->wNumberingTab), + tp->member.para.para_num.width ); + wc.nFirstMargin += dxStartIndent; + } wc.nRightMargin = ME_twips2pointsX(c, pFmt->dxRightIndent); if (wc.nFirstMargin < 0) @@ -897,7 +936,7 @@ static void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) { if (!(pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE) && pFmt->dwMask & PFM_BORDER) { - border = ME_GetParaBorderWidth(c, tp->member.para.pFmt->wBorders); + border = ME_GetParaBorderWidth(c, tp->member.para.fmt.wBorders); if (pFmt->wBorders & 1) { wc.nFirstMargin += border; wc.nLeftMargin += border; @@ -924,7 +963,7 @@ static void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) { if (!(pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE) && (pFmt->dwMask & PFM_BORDER) && (pFmt->wBorders & 8)) wc.pt.y += border; - if (tp->member.para.pFmt->dwMask & PFM_SPACEAFTER) + if (tp->member.para.fmt.dwMask & PFM_SPACEAFTER) wc.pt.y += ME_twips2pointsY(c, pFmt->dySpaceAfter); tp->member.para.nFlags &= ~MEPF_REWRAP; @@ -987,9 +1026,9 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) } c.pt.y += borderWidth; } - if (endRowPara->member.para.pFmt->dxStartIndent > 0) + if (endRowPara->member.para.fmt.dxStartIndent > 0) { - int dxStartIndent = endRowPara->member.para.pFmt->dxStartIndent; + int dxStartIndent = endRowPara->member.para.fmt.dxStartIndent; cell = ME_FindItemFwd(item, diCell); cell->member.cell.pt.x += ME_twips2pointsX(&c, dxStartIndent); c.pt.x = cell->member.cell.pt.x; diff --git a/reactos/dll/win32/riched20/writer.c b/reactos/dll/win32/riched20/writer.c index 96b8a406859..7d2b4b7889b 100644 --- a/reactos/dll/win32/riched20/writer.c +++ b/reactos/dll/win32/riched20/writer.c @@ -23,6 +23,27 @@ WINE_DEFAULT_DEBUG_CHANNEL(richedit); +#define STREAMOUT_BUFFER_SIZE 4096 +#define STREAMOUT_FONTTBL_SIZE 8192 +#define STREAMOUT_COLORTBL_SIZE 1024 + +typedef struct tagME_OutStream +{ + EDITSTREAM *stream; + char buffer[STREAMOUT_BUFFER_SIZE]; + UINT pos, written; + UINT nCodePage; + UINT nFontTblLen; + ME_FontTableItem fonttbl[STREAMOUT_FONTTBL_SIZE]; + UINT nColorTblLen; + COLORREF colortbl[STREAMOUT_COLORTBL_SIZE]; + UINT nDefaultFont; + UINT nDefaultCodePage; + /* nNestingLevel = 0 means we aren't in a cell, 1 means we are in a cell, + * an greater numbers mean we are in a cell nested within a cell. */ + UINT nNestingLevel; + CHARFORMAT2W cur_fmt; /* current character format */ +} ME_OutStream; static BOOL ME_StreamOutRTFText(ME_OutStream *pStream, const WCHAR *text, LONG nChars); @@ -39,6 +60,9 @@ ME_StreamOutInit(ME_TextEditor *editor, EDITSTREAM *stream) pStream->nFontTblLen = 0; pStream->nColorTblLen = 1; pStream->nNestingLevel = 0; + memset(&pStream->cur_fmt, 0, sizeof(pStream->cur_fmt)); + pStream->cur_fmt.dwEffects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR; + pStream->cur_fmt.bUnderlineType = CFU_UNDERLINE; return pStream; } @@ -208,6 +232,86 @@ ME_StreamOutRTFHeader(ME_OutStream *pStream, int dwFormat) return TRUE; } +static void add_font_to_fonttbl( ME_OutStream *stream, ME_Style *style ) +{ + ME_FontTableItem *table = stream->fonttbl; + CHARFORMAT2W *fmt = &style->fmt; + WCHAR *face = fmt->szFaceName; + BYTE charset = (fmt->dwMask & CFM_CHARSET) ? fmt->bCharSet : DEFAULT_CHARSET; + int i; + + if (fmt->dwMask & CFM_FACE) + { + for (i = 0; i < stream->nFontTblLen; i++) + if (table[i].bCharSet == charset + && (table[i].szFaceName == face || !lstrcmpW(table[i].szFaceName, face))) + break; + + if (i == stream->nFontTblLen && i < STREAMOUT_FONTTBL_SIZE) + { + table[i].bCharSet = charset; + table[i].szFaceName = face; + stream->nFontTblLen++; + } + } +} + +static BOOL find_font_in_fonttbl( ME_OutStream *stream, CHARFORMAT2W *fmt, unsigned int *idx ) +{ + WCHAR *facename; + int i; + + *idx = 0; + if (fmt->dwMask & CFM_FACE) + facename = fmt->szFaceName; + else + facename = stream->fonttbl[0].szFaceName; + for (i = 0; i < stream->nFontTblLen; i++) + { + if (facename == stream->fonttbl[i].szFaceName + || !lstrcmpW(facename, stream->fonttbl[i].szFaceName)) + if (!(fmt->dwMask & CFM_CHARSET) + || fmt->bCharSet == stream->fonttbl[i].bCharSet) + { + *idx = i; + break; + } + } + + return i < stream->nFontTblLen; +} + +static void add_color_to_colortbl( ME_OutStream *stream, COLORREF color ) +{ + int i; + + for (i = 1; i < stream->nColorTblLen; i++) + if (stream->colortbl[i] == color) + break; + + if (i == stream->nColorTblLen && i < STREAMOUT_COLORTBL_SIZE) + { + stream->colortbl[i] = color; + stream->nColorTblLen++; + } +} + +static BOOL find_color_in_colortbl( ME_OutStream *stream, COLORREF color, unsigned int *idx ) +{ + int i; + + *idx = 0; + for (i = 1; i < stream->nColorTblLen; i++) + { + if (stream->colortbl[i] == color) + { + *idx = i; + break; + } + } + + return i < stream->nFontTblLen; +} static BOOL ME_StreamOutRTFFontAndColorTbl(ME_OutStream *pStream, ME_DisplayItem *pFirstRun, @@ -216,82 +320,44 @@ ME_StreamOutRTFFontAndColorTbl(ME_OutStream *pStream, ME_DisplayItem *pFirstRun, ME_DisplayItem *item = pFirstRun; ME_FontTableItem *table = pStream->fonttbl; unsigned int i; - ME_DisplayItem *pLastPara = ME_GetParagraph(pLastRun); ME_DisplayItem *pCell = NULL; - + ME_Paragraph *prev_para = NULL; + do { CHARFORMAT2W *fmt = &item->member.run.style->fmt; - COLORREF crColor; - if (fmt->dwMask & CFM_FACE) { - WCHAR *face = fmt->szFaceName; - BYTE bCharSet = (fmt->dwMask & CFM_CHARSET) ? fmt->bCharSet : DEFAULT_CHARSET; - - for (i = 0; i < pStream->nFontTblLen; i++) - if (table[i].bCharSet == bCharSet - && (table[i].szFaceName == face || !lstrcmpW(table[i].szFaceName, face))) - break; - if (i == pStream->nFontTblLen && i < STREAMOUT_FONTTBL_SIZE) { - table[i].bCharSet = bCharSet; - table[i].szFaceName = face; - pStream->nFontTblLen++; - } - } - - if (fmt->dwMask & CFM_COLOR && !(fmt->dwEffects & CFE_AUTOCOLOR)) { - crColor = fmt->crTextColor; - for (i = 1; i < pStream->nColorTblLen; i++) - if (pStream->colortbl[i] == crColor) - break; - if (i == pStream->nColorTblLen && i < STREAMOUT_COLORTBL_SIZE) { - pStream->colortbl[i] = crColor; - pStream->nColorTblLen++; - } - } - if (fmt->dwMask & CFM_BACKCOLOR && !(fmt->dwEffects & CFE_AUTOBACKCOLOR)) { - crColor = fmt->crBackColor; - for (i = 1; i < pStream->nColorTblLen; i++) - if (pStream->colortbl[i] == crColor) - break; - if (i == pStream->nColorTblLen && i < STREAMOUT_COLORTBL_SIZE) { - pStream->colortbl[i] = crColor; - pStream->nColorTblLen++; + add_font_to_fonttbl( pStream, item->member.run.style ); + + if (fmt->dwMask & CFM_COLOR && !(fmt->dwEffects & CFE_AUTOCOLOR)) + add_color_to_colortbl( pStream, fmt->crTextColor ); + if (fmt->dwMask & CFM_BACKCOLOR && !(fmt->dwEffects & CFE_AUTOBACKCOLOR)) + add_color_to_colortbl( pStream, fmt->crBackColor ); + + if (item->member.run.para != prev_para) + { + /* check for any para numbering text */ + if (item->member.run.para->fmt.wNumbering) + add_font_to_fonttbl( pStream, item->member.run.para->para_num.style ); + + if ((pCell = item->member.para.pCell)) + { + ME_Border* borders[4] = { &pCell->member.cell.border.top, + &pCell->member.cell.border.left, + &pCell->member.cell.border.bottom, + &pCell->member.cell.border.right }; + for (i = 0; i < 4; i++) + if (borders[i]->width > 0) + add_color_to_colortbl( pStream, borders[i]->colorRef ); } + + prev_para = item->member.run.para; } if (item == pLastRun) break; item = ME_FindItemFwd(item, diRun); } while (item); - item = ME_GetParagraph(pFirstRun); - do { - if ((pCell = item->member.para.pCell)) - { - ME_Border* borders[4] = { &pCell->member.cell.border.top, - &pCell->member.cell.border.left, - &pCell->member.cell.border.bottom, - &pCell->member.cell.border.right }; - for (i = 0; i < 4; i++) - { - if (borders[i]->width > 0) - { - unsigned int j; - COLORREF crColor = borders[i]->colorRef; - for (j = 1; j < pStream->nColorTblLen; j++) - if (pStream->colortbl[j] == crColor) - break; - if (j == pStream->nColorTblLen && j < STREAMOUT_COLORTBL_SIZE) { - pStream->colortbl[j] = crColor; - pStream->nColorTblLen++; - } - } - } - } - if (item == pLastPara) - break; - item = item->member.para.next_para; - } while (item); - + if (!ME_StreamOutPrint(pStream, "{\\fonttbl")) return FALSE; @@ -344,7 +410,7 @@ ME_StreamOutRTFTableProps(ME_TextEditor *editor, ME_OutStream *pStream, if (!ME_StreamOutPrint(pStream, "\\trowd")) return FALSE; if (!editor->bEmulateVersion10) { /* v4.1 */ - PARAFORMAT2 *pFmt = ME_GetTableRowEnd(para)->member.para.pFmt; + PARAFORMAT2 *pFmt = &ME_GetTableRowEnd(para)->member.para.fmt; para = ME_GetTableRowStart(para); cell = para->member.para.next_para->member.para.pCell; assert(cell); @@ -361,17 +427,13 @@ ME_StreamOutRTFTableProps(ME_TextEditor *editor, ME_OutStream *pStream, { if (borders[i]->width) { - unsigned int j; + unsigned int idx; COLORREF crColor = borders[i]->colorRef; sprintf(props + strlen(props), "\\clbrdr%c", sideChar[i]); sprintf(props + strlen(props), "\\brdrs"); sprintf(props + strlen(props), "\\brdrw%d", borders[i]->width); - for (j = 1; j < pStream->nColorTblLen; j++) { - if (pStream->colortbl[j] == crColor) { - sprintf(props + strlen(props), "\\brdrcf%u", j); - break; - } - } + if (find_color_in_colortbl( pStream, crColor, &idx )) + sprintf(props + strlen(props), "\\brdrcf%u", idx); } } sprintf(props + strlen(props), "\\cellx%d", cell->member.cell.nRightBoundary); @@ -382,7 +444,7 @@ ME_StreamOutRTFTableProps(ME_TextEditor *editor, ME_OutStream *pStream, ¶->member.para.border.left, ¶->member.para.border.bottom, ¶->member.para.border.right }; - PARAFORMAT2 *pFmt = para->member.para.pFmt; + PARAFORMAT2 *pFmt = ¶->member.para.fmt; assert(!(para->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND|MEPF_CELL))); if (pFmt->dxOffset) @@ -393,17 +455,13 @@ ME_StreamOutRTFTableProps(ME_TextEditor *editor, ME_OutStream *pStream, { if (borders[i]->width) { - unsigned int j; + unsigned int idx; COLORREF crColor = borders[i]->colorRef; sprintf(props + strlen(props), "\\trbrdr%c", sideChar[i]); sprintf(props + strlen(props), "\\brdrs"); sprintf(props + strlen(props), "\\brdrw%d", borders[i]->width); - for (j = 1; j < pStream->nColorTblLen; j++) { - if (pStream->colortbl[j] == crColor) { - sprintf(props + strlen(props), "\\brdrcf%u", j); - break; - } - } + if (find_color_in_colortbl( pStream, crColor, &idx )) + sprintf(props + strlen(props), "\\brdrcf%u", idx); } } for (i = 0; i < pFmt->cTabCount; i++) @@ -417,13 +475,87 @@ ME_StreamOutRTFTableProps(ME_TextEditor *editor, ME_OutStream *pStream, return TRUE; } +static BOOL stream_out_para_num( ME_OutStream *stream, ME_Paragraph *para, BOOL pn_dest ) +{ + static const char fmt_label[] = "{\\*\\pn\\pnlvlbody\\pnf%u\\pnindent%d\\pnstart%d%s%s}"; + static const char fmt_bullet[] = "{\\*\\pn\\pnlvlblt\\pnf%u\\pnindent%d{\\pntxtb\\'b7}}"; + static const char dec[] = "\\pndec"; + static const char lcltr[] = "\\pnlcltr"; + static const char ucltr[] = "\\pnucltr"; + static const char lcrm[] = "\\pnlcrm"; + static const char ucrm[] = "\\pnucrm"; + static const char period[] = "{\\pntxta.}"; + static const char paren[] = "{\\pntxta)}"; + static const char parens[] = "{\\pntxtb(}{\\pntxta)}"; + const char *type, *style = ""; + unsigned int idx; + + find_font_in_fonttbl( stream, ¶->para_num.style->fmt, &idx ); + + if (!ME_StreamOutPrint( stream, "{\\pntext\\f%u ", idx )) return FALSE; + if (!ME_StreamOutRTFText( stream, para->para_num.text->szData, para->para_num.text->nLen )) + return FALSE; + if (!ME_StreamOutPrint( stream, "\\tab}" )) return FALSE; + + if (!pn_dest) return TRUE; + + if (para->fmt.wNumbering == PFN_BULLET) + { + if (!ME_StreamOutPrint( stream, fmt_bullet, idx, para->fmt.wNumberingTab )) + return FALSE; + } + else + { + switch (para->fmt.wNumbering) + { + case PFN_ARABIC: + default: + type = dec; + break; + case PFN_LCLETTER: + type = lcltr; + break; + case PFN_UCLETTER: + type = ucltr; + break; + case PFN_LCROMAN: + type = lcrm; + break; + case PFN_UCROMAN: + type = ucrm; + break; + } + switch (para->fmt.wNumberingStyle & 0xf00) + { + case PFNS_PERIOD: + style = period; + break; + case PFNS_PAREN: + style = paren; + break; + case PFNS_PARENS: + style = parens; + break; + } + + if (!ME_StreamOutPrint( stream, fmt_label, idx, para->fmt.wNumberingTab, + para->fmt.wNumberingStart, type, style )) + return FALSE; + } + return TRUE; +} + static BOOL ME_StreamOutRTFParaProps(ME_TextEditor *editor, ME_OutStream *pStream, ME_DisplayItem *para) { - PARAFORMAT2 *fmt = para->member.para.pFmt; + PARAFORMAT2 *fmt = ¶->member.para.fmt; char props[STREAMOUT_BUFFER_SIZE] = ""; int i; + ME_Paragraph *prev_para = NULL; + + if (para->member.para.prev_para->type == diParagraph) + prev_para = ¶->member.para.prev_para->member.para; if (!editor->bEmulateVersion10) { /* v4.1 */ if (para->member.para.nFlags & MEPF_ROWSTART) { @@ -443,24 +575,33 @@ ME_StreamOutRTFParaProps(ME_TextEditor *editor, ME_OutStream *pStream, if (!ME_StreamOutPrint(pStream, "\\nestrow}{\\nonesttables\\par}\r\n")) return FALSE; } else { - if (!ME_StreamOutPrint(pStream, "\\row \r\n")) + if (!ME_StreamOutPrint(pStream, "\\row\r\n")) return FALSE; } return TRUE; } } else { /* v1.0 - 3.0 */ - if (para->member.para.pFmt->dwMask & PFM_TABLE && - para->member.para.pFmt->wEffects & PFE_TABLE) + if (para->member.para.fmt.dwMask & PFM_TABLE && + para->member.para.fmt.wEffects & PFE_TABLE) { if (!ME_StreamOutRTFTableProps(editor, pStream, para)) return FALSE; } } - /* TODO: Don't emit anything if the last PARAFORMAT2 is inherited */ + if (prev_para && !memcmp( fmt, &prev_para->fmt, sizeof(*fmt) )) + { + if (fmt->wNumbering) + return stream_out_para_num( pStream, ¶->member.para, FALSE ); + return TRUE; + } + if (!ME_StreamOutPrint(pStream, "\\pard")) return FALSE; + if (fmt->wNumbering) + if (!stream_out_para_num( pStream, ¶->member.para, TRUE )) return FALSE; + if (!editor->bEmulateVersion10) { /* v4.1 */ if (pStream->nNestingLevel > 0) strcat(props, "\\intbl"); @@ -470,7 +611,7 @@ ME_StreamOutRTFParaProps(ME_TextEditor *editor, ME_OutStream *pStream, if (fmt->dwMask & PFM_TABLE && fmt->wEffects & PFE_TABLE) strcat(props, "\\intbl"); } - + /* TODO: PFM_BORDER. M$ does not emit any keywords for these properties, and * when streaming border keywords in, PFM_BORDER is set, but wBorder field is * set very different from the documentation. @@ -538,11 +679,11 @@ ME_StreamOutRTFParaProps(ME_TextEditor *editor, ME_OutStream *pStream, if (!(editor->bEmulateVersion10 && /* v1.0 - 3.0 */ fmt->dwMask & PFM_TABLE && fmt->wEffects & PFE_TABLE)) { - if (fmt->dwMask & PFM_OFFSET) + if (fmt->dxOffset) sprintf(props + strlen(props), "\\li%d", fmt->dxOffset); - if (fmt->dwMask & PFM_OFFSETINDENT || fmt->dwMask & PFM_STARTINDENT) + if (fmt->dxStartIndent) sprintf(props + strlen(props), "\\fi%d", fmt->dxStartIndent); - if (fmt->dwMask & PFM_RIGHTINDENT) + if (fmt->dxRightIndent) sprintf(props + strlen(props), "\\ri%d", fmt->dxRightIndent); if (fmt->dwMask & PFM_TABSTOPS) { static const char * const leader[6] = { "", "\\tldot", "\\tlhyph", "\\tlul", "\\tlth", "\\tleq" }; @@ -568,11 +709,11 @@ ME_StreamOutRTFParaProps(ME_TextEditor *editor, ME_OutStream *pStream, } } } - if (fmt->dwMask & PFM_SPACEAFTER) + if (fmt->dySpaceAfter) sprintf(props + strlen(props), "\\sa%d", fmt->dySpaceAfter); - if (fmt->dwMask & PFM_SPACEBEFORE) + if (fmt->dySpaceBefore) sprintf(props + strlen(props), "\\sb%d", fmt->dySpaceBefore); - if (fmt->dwMask & PFM_STYLE) + if (fmt->sStyle != -1) sprintf(props + strlen(props), "\\s%d", fmt->sStyle); if (fmt->dwMask & PFM_SHADING) { @@ -588,6 +729,8 @@ ME_StreamOutRTFParaProps(ME_TextEditor *editor, ME_OutStream *pStream, sprintf(props + strlen(props), "\\cfpat%d\\cbpat%d", (fmt->wShadingStyle >> 4) & 0xF, (fmt->wShadingStyle >> 8) & 0xF); } + if (*props) + strcat(props, " "); if (*props && !ME_StreamOutPrint(pStream, props)) return FALSE; @@ -601,125 +744,114 @@ ME_StreamOutRTFCharProps(ME_OutStream *pStream, CHARFORMAT2W *fmt) { char props[STREAMOUT_BUFFER_SIZE] = ""; unsigned int i; + CHARFORMAT2W *old_fmt = &pStream->cur_fmt; + static const struct + { + DWORD effect; + const char *on, *off; + } effects[] = + { + { CFE_ALLCAPS, "\\caps", "\\caps0" }, + { CFE_BOLD, "\\b", "\\b0" }, + { CFE_DISABLED, "\\disabled", "\\disabled0" }, + { CFE_EMBOSS, "\\embo", "\\embo0" }, + { CFE_HIDDEN, "\\v", "\\v0" }, + { CFE_IMPRINT, "\\impr", "\\impr0" }, + { CFE_ITALIC, "\\i", "\\i0" }, + { CFE_OUTLINE, "\\outl", "\\outl0" }, + { CFE_PROTECTED, "\\protect", "\\protect0" }, + { CFE_SHADOW, "\\shad", "\\shad0" }, + { CFE_SMALLCAPS, "\\scaps", "\\scaps0" }, + { CFE_STRIKEOUT, "\\strike", "\\strike0" }, + }; - if (fmt->dwMask & CFM_ALLCAPS && fmt->dwEffects & CFE_ALLCAPS) - strcat(props, "\\caps"); - if (fmt->dwMask & CFM_ANIMATION) + for (i = 0; i < sizeof(effects) / sizeof(effects[0]); i++) + { + if ((old_fmt->dwEffects ^ fmt->dwEffects) & effects[i].effect) + strcat( props, fmt->dwEffects & effects[i].effect ? effects[i].on : effects[i].off ); + } + + if ((old_fmt->dwEffects ^ fmt->dwEffects) & CFE_AUTOBACKCOLOR || + old_fmt->crBackColor != fmt->crBackColor) + { + if (fmt->dwEffects & CFE_AUTOBACKCOLOR) i = 0; + else find_color_in_colortbl( pStream, fmt->crBackColor, &i ); + sprintf(props + strlen(props), "\\cb%u", i); + } + if ((old_fmt->dwEffects ^ fmt->dwEffects) & CFE_AUTOCOLOR || + old_fmt->crTextColor != fmt->crTextColor) + { + if (fmt->dwEffects & CFE_AUTOCOLOR) i = 0; + else find_color_in_colortbl( pStream, fmt->crTextColor, &i ); + sprintf(props + strlen(props), "\\cf%u", i); + } + + if (old_fmt->bAnimation != fmt->bAnimation) sprintf(props + strlen(props), "\\animtext%u", fmt->bAnimation); - if (fmt->dwMask & CFM_BACKCOLOR) { - if (!(fmt->dwEffects & CFE_AUTOBACKCOLOR)) { - for (i = 1; i < pStream->nColorTblLen; i++) - if (pStream->colortbl[i] == fmt->crBackColor) { - sprintf(props + strlen(props), "\\cb%u", i); - break; - } - } - } - if (fmt->dwMask & CFM_BOLD && fmt->dwEffects & CFE_BOLD) - strcat(props, "\\b"); - if (fmt->dwMask & CFM_COLOR) { - if (!(fmt->dwEffects & CFE_AUTOCOLOR)) { - for (i = 1; i < pStream->nColorTblLen; i++) - if (pStream->colortbl[i] == fmt->crTextColor) { - sprintf(props + strlen(props), "\\cf%u", i); - break; - } - } - } - /* TODO: CFM_DISABLED */ - if (fmt->dwMask & CFM_EMBOSS && fmt->dwEffects & CFE_EMBOSS) - strcat(props, "\\embo"); - if (fmt->dwMask & CFM_HIDDEN && fmt->dwEffects & CFE_HIDDEN) - strcat(props, "\\v"); - if (fmt->dwMask & CFM_IMPRINT && fmt->dwEffects & CFE_IMPRINT) - strcat(props, "\\impr"); - if (fmt->dwMask & CFM_ITALIC && fmt->dwEffects & CFE_ITALIC) - strcat(props, "\\i"); - if (fmt->dwMask & CFM_KERNING) + if (old_fmt->wKerning != fmt->wKerning) sprintf(props + strlen(props), "\\kerning%u", fmt->wKerning); - if (fmt->dwMask & CFM_LCID) { + + if (old_fmt->lcid != fmt->lcid) + { /* TODO: handle SFF_PLAINRTF */ if (LOWORD(fmt->lcid) == 1024) strcat(props, "\\noproof\\lang1024\\langnp1024\\langfe1024\\langfenp1024"); else sprintf(props + strlen(props), "\\lang%u", LOWORD(fmt->lcid)); } - /* CFM_LINK is not streamed out by M$ */ - if (fmt->dwMask & CFM_OFFSET) { + + if (old_fmt->yOffset != fmt->yOffset) + { if (fmt->yOffset >= 0) sprintf(props + strlen(props), "\\up%d", fmt->yOffset); else sprintf(props + strlen(props), "\\dn%d", -fmt->yOffset); } - if (fmt->dwMask & CFM_OUTLINE && fmt->dwEffects & CFE_OUTLINE) - strcat(props, "\\outl"); - if (fmt->dwMask & CFM_PROTECTED && fmt->dwEffects & CFE_PROTECTED) - strcat(props, "\\protect"); - /* TODO: CFM_REVISED CFM_REVAUTHOR - probably using rsidtbl? */ - if (fmt->dwMask & CFM_SHADOW && fmt->dwEffects & CFE_SHADOW) - strcat(props, "\\shad"); - if (fmt->dwMask & CFM_SIZE) + if (old_fmt->yHeight != fmt->yHeight) sprintf(props + strlen(props), "\\fs%d", fmt->yHeight / 10); - if (fmt->dwMask & CFM_SMALLCAPS && fmt->dwEffects & CFE_SMALLCAPS) - strcat(props, "\\scaps"); - if (fmt->dwMask & CFM_SPACING) + if (old_fmt->sSpacing != fmt->sSpacing) sprintf(props + strlen(props), "\\expnd%u\\expndtw%u", fmt->sSpacing / 5, fmt->sSpacing); - if (fmt->dwMask & CFM_STRIKEOUT && fmt->dwEffects & CFE_STRIKEOUT) - strcat(props, "\\strike"); - if (fmt->dwMask & CFM_STYLE) { - sprintf(props + strlen(props), "\\cs%u", fmt->sStyle); - /* TODO: emit style contents here */ - } - if (fmt->dwMask & (CFM_SUBSCRIPT | CFM_SUPERSCRIPT)) { + if ((old_fmt->dwEffects ^ fmt->dwEffects) & (CFM_SUBSCRIPT | CFM_SUPERSCRIPT)) + { if (fmt->dwEffects & CFE_SUBSCRIPT) strcat(props, "\\sub"); else if (fmt->dwEffects & CFE_SUPERSCRIPT) strcat(props, "\\super"); + else + strcat(props, "\\nosupersub"); } - if (fmt->dwMask & CFM_UNDERLINE || fmt->dwMask & CFM_UNDERLINETYPE) { - if (fmt->dwMask & CFM_UNDERLINETYPE) - switch (fmt->bUnderlineType) { - case CFU_CF1UNDERLINE: - case CFU_UNDERLINE: + if ((old_fmt->dwEffects ^ fmt->dwEffects) & CFE_UNDERLINE || + old_fmt->bUnderlineType != fmt->bUnderlineType) + { + BYTE type = (fmt->dwEffects & CFE_UNDERLINE) ? fmt->bUnderlineType : CFU_UNDERLINENONE; + switch (type) + { + case CFU_UNDERLINE: strcat(props, "\\ul"); break; - case CFU_UNDERLINEDOTTED: + case CFU_UNDERLINEDOTTED: strcat(props, "\\uld"); break; - case CFU_UNDERLINEDOUBLE: + case CFU_UNDERLINEDOUBLE: strcat(props, "\\uldb"); break; - case CFU_UNDERLINEWORD: + case CFU_UNDERLINEWORD: strcat(props, "\\ulw"); break; - case CFU_UNDERLINENONE: - default: + case CFU_CF1UNDERLINE: + case CFU_UNDERLINENONE: + default: strcat(props, "\\ulnone"); break; } - else if (fmt->dwEffects & CFE_UNDERLINE) - strcat(props, "\\ul"); } - /* FIXME: How to emit CFM_WEIGHT? */ - if (fmt->dwMask & CFM_FACE || fmt->dwMask & CFM_CHARSET) { - WCHAR *szFaceName; - - if (fmt->dwMask & CFM_FACE) - szFaceName = fmt->szFaceName; - else - szFaceName = pStream->fonttbl[0].szFaceName; - for (i = 0; i < pStream->nFontTblLen; i++) { - if (szFaceName == pStream->fonttbl[i].szFaceName - || !lstrcmpW(szFaceName, pStream->fonttbl[i].szFaceName)) - if (!(fmt->dwMask & CFM_CHARSET) - || fmt->bCharSet == pStream->fonttbl[i].bCharSet) - break; - } - if (i < pStream->nFontTblLen) + if (strcmpW(old_fmt->szFaceName, fmt->szFaceName) || + old_fmt->bCharSet != fmt->bCharSet) + { + if (find_font_in_fonttbl( pStream, fmt, &i )) { - if (i != pStream->nDefaultFont) - sprintf(props + strlen(props), "\\f%u", i); + sprintf(props + strlen(props), "\\f%u", i); /* In UTF-8 mode, charsets/codepages are not used */ if (pStream->nDefaultCodePage != CP_UTF8) @@ -735,6 +867,7 @@ ME_StreamOutRTFCharProps(ME_OutStream *pStream, CHARFORMAT2W *fmt) strcat(props, " "); if (!ME_StreamOutPrint(pStream, props)) return FALSE; + *old_fmt = *fmt; return TRUE; } @@ -874,13 +1007,10 @@ static BOOL ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream, const ME_Cursor *start, int nChars, int dwFormat) { ME_Cursor cursor = *start; - ME_DisplayItem *prev_para = cursor.pPara; + ME_DisplayItem *prev_para = NULL; ME_Cursor endCur = cursor; - int actual_chars; - actual_chars = ME_MoveCursorChars(editor, &endCur, nChars); - /* Include the final \r which MoveCursorChars will ignore. */ - if (actual_chars != nChars) endCur.nOffset++; + ME_MoveCursorChars(editor, &endCur, nChars, TRUE); if (!ME_StreamOutRTFHeader(pStream, dwFormat)) return FALSE; @@ -890,8 +1020,7 @@ static BOOL ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream, /* TODO: stylesheet table */ - /* FIXME: maybe emit something smarter for the generator? */ - if (!ME_StreamOutPrint(pStream, "{\\*\\generator Wine Riched20 2.0.????;}")) + if (!ME_StreamOutPrint(pStream, "{\\*\\generator Wine Riched20 2.0;}")) return FALSE; /* TODO: information group */ @@ -902,9 +1031,6 @@ static BOOL ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream, /* TODO: section formatting properties */ - if (!ME_StreamOutRTFParaProps(editor, pStream, cursor.pPara)) - return FALSE; - do { if (cursor.pPara != prev_para) { @@ -924,8 +1050,8 @@ static BOOL ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream, return FALSE; } else if (cursor.pRun->member.run.nFlags & MERF_TAB) { if (editor->bEmulateVersion10 && /* v1.0 - 3.0 */ - cursor.pPara->member.para.pFmt->dwMask & PFM_TABLE && - cursor.pPara->member.para.pFmt->wEffects & PFE_TABLE) + cursor.pPara->member.para.fmt.dwMask & PFM_TABLE && + cursor.pPara->member.para.fmt.wEffects & PFE_TABLE) { if (!ME_StreamOutPrint(pStream, "\\cell ")) return FALSE; @@ -943,27 +1069,25 @@ static BOOL ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream, } nChars--; } else if (cursor.pRun->member.run.nFlags & MERF_ENDPARA) { - if (cursor.pPara->member.para.pFmt->dwMask & PFM_TABLE && - cursor.pPara->member.para.pFmt->wEffects & PFE_TABLE && + if (cursor.pPara->member.para.fmt.dwMask & PFM_TABLE && + cursor.pPara->member.para.fmt.wEffects & PFE_TABLE && !(cursor.pPara->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND|MEPF_CELL))) { - if (!ME_StreamOutPrint(pStream, "\\row \r\n")) + if (!ME_StreamOutPrint(pStream, "\\row\r\n")) return FALSE; } else { - if (!ME_StreamOutPrint(pStream, "\r\n\\par")) + if (!ME_StreamOutPrint(pStream, "\\par\r\n")) return FALSE; } /* Skip as many characters as required by current line break */ 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")) + if (!ME_StreamOutPrint(pStream, "\\line\r\n")) return FALSE; nChars--; } else { int nEnd; - if (!ME_StreamOutPrint(pStream, "{")) - return FALSE; TRACE("style %p\n", cursor.pRun->member.run.style); if (!ME_StreamOutRTFCharProps(pStream, &cursor.pRun->member.run.style->fmt)) return FALSE; @@ -973,8 +1097,6 @@ static BOOL ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream, nEnd - cursor.nOffset)) return FALSE; cursor.nOffset = 0; - if (!ME_StreamOutPrint(pStream, "}")) - return FALSE; } } while (cursor.pRun != endCur.pRun && ME_NextRun(&cursor.pPara, &cursor.pRun, TRUE)); diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE index 4dbb5f212b4..286692e77af 100644 --- a/reactos/media/doc/README.WINE +++ b/reactos/media/doc/README.WINE @@ -158,7 +158,7 @@ reactos/dll/win32/qmgrprxy # Synced to WineStaging-1.9.11 reactos/dll/win32/query # Synced to WineStaging-1.9.11 reactos/dll/win32/rasapi32 # Synced to WineStaging-1.9.11 reactos/dll/win32/resutils # Synced to WineStaging-1.9.11 -reactos/dll/win32/riched20 # Synced to WineStaging-1.9.16 +reactos/dll/win32/riched20 # Synced to WineStaging-1.9.23 reactos/dll/win32/riched32 # Synced to WineStaging-1.9.11 reactos/dll/win32/rpcrt4 # Synced to WineStaging-1.9.16 reactos/dll/win32/rsabase # Synced to WineStaging-1.9.11