/****************************************************************************** * ME_SplitRunSimple * * Does the most basic job of splitting a run into two - it does not * update the positions and extents. */ ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_Cursor *cursor) { ME_DisplayItem *run = cursor->pRun; ME_DisplayItem *new_run; int i; int nOffset = cursor->nOffset; assert(!(run->member.run.nFlags & MERF_NONTEXT)); new_run = ME_MakeRun(run->member.run.style, run->member.run.nFlags & MERF_SPLITMASK); new_run->member.run.nCharOfs = run->member.run.nCharOfs + nOffset; new_run->member.run.len = run->member.run.len - nOffset; new_run->member.run.para = run->member.run.para; run->member.run.len = nOffset; cursor->pRun = new_run; cursor->nOffset = 0; ME_InsertBefore(run->next, new_run); ME_UpdateRunFlags(editor, &run->member.run); ME_UpdateRunFlags(editor, &new_run->member.run); for (i = 0; i < editor->nCursors; i++) { if (editor->pCursors[i].pRun == run && editor->pCursors[i].nOffset >= nOffset) { editor->pCursors[i].pRun = new_run; editor->pCursors[i].nOffset -= nOffset; } } cursor->pPara->member.para.nFlags |= MEPF_REWRAP; return run; }
void ME_MakeFirstParagraph(ME_TextEditor *editor) { ME_Context c; CHARFORMAT2W cf; LOGFONTW lf; HFONT hf; ME_TextBuffer *text = editor->pBuffer; ME_DisplayItem *para = make_para(editor); ME_DisplayItem *run; ME_Style *style; int eol_len; WCHAR cr_lf[] = {'\r','\n',0}; ME_InitContext(&c, editor, ITextHost_TxGetDC(editor->texthost)); hf = GetStockObject(SYSTEM_FONT); assert(hf); GetObjectW(hf, sizeof(LOGFONTW), &lf); ZeroMemory(&cf, sizeof(cf)); cf.cbSize = sizeof(cf); cf.dwMask = CFM_BACKCOLOR|CFM_COLOR|CFM_FACE|CFM_SIZE|CFM_CHARSET; cf.dwMask |= CFM_ALLCAPS|CFM_BOLD|CFM_DISABLED|CFM_EMBOSS|CFM_HIDDEN; cf.dwMask |= CFM_IMPRINT|CFM_ITALIC|CFM_LINK|CFM_OUTLINE|CFM_PROTECTED; cf.dwMask |= CFM_REVISED|CFM_SHADOW|CFM_SMALLCAPS|CFM_STRIKEOUT; cf.dwMask |= CFM_SUBSCRIPT|CFM_UNDERLINETYPE|CFM_WEIGHT; cf.dwEffects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR; lstrcpyW(cf.szFaceName, lf.lfFaceName); /* Convert system font height from logical units to twips for cf.yHeight */ cf.yHeight = (lf.lfHeight * 72 * 1440) / (c.dpi.cy * c.dpi.cy); 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.lfStrikeOut) cf.dwEffects |= CFE_STRIKEOUT; cf.bPitchAndFamily = lf.lfPitchAndFamily; cf.bCharSet = lf.lfCharSet; style = ME_MakeStyle(&cf); text->pDefaultStyle = style; eol_len = editor->bEmulateVersion10 ? 2 : 1; para->member.para.text = ME_MakeStringN( cr_lf, eol_len ); run = ME_MakeRun(style, MERF_ENDPARA); run->member.run.nCharOfs = 0; run->member.run.len = eol_len; run->member.run.para = ¶->member.para; ME_InsertBefore(text->pLast, para); ME_InsertBefore(text->pLast, run); para->member.para.prev_para = text->pFirst; para->member.para.next_para = text->pLast; text->pFirst->member.para.next_para = para; text->pLast->member.para.prev_para = para; text->pLast->member.para.nCharOfs = editor->bEmulateVersion10 ? 2 : 1; ME_DestroyContext(&c); }
/****************************************************************************** * ME_InsertRunAtCursor * * Inserts a new run with given style, flags and content at a given position, * which is passed as a cursor structure (which consists of a run and * a run-relative character offset). */ ME_DisplayItem * ME_InsertRunAtCursor(ME_TextEditor *editor, ME_Cursor *cursor, ME_Style *style, const WCHAR *str, int len, int flags) { ME_DisplayItem *pDI, *insert_before = cursor->pRun, *prev; if (cursor->nOffset) { if (cursor->nOffset == cursor->pRun->member.run.len) { insert_before = ME_FindItemFwd( cursor->pRun, diRun ); if (!insert_before) insert_before = cursor->pRun; /* Always insert before the final eop run */ } else { ME_SplitRunSimple( editor, cursor ); insert_before = cursor->pRun; } } add_undo_delete_run( editor, insert_before->member.run.para->nCharOfs + insert_before->member.run.nCharOfs, len ); pDI = ME_MakeRun(style, flags); pDI->member.run.nCharOfs = insert_before->member.run.nCharOfs; pDI->member.run.len = len; pDI->member.run.para = insert_before->member.run.para; ME_InsertString( pDI->member.run.para->text, pDI->member.run.nCharOfs, str, len ); ME_InsertBefore( insert_before, pDI ); TRACE("Shift length:%d\n", len); ME_PropagateCharOffset( insert_before, len ); insert_before->member.run.para->nFlags |= MEPF_REWRAP; /* Move any cursors that were at the end of the previous run to the end of the inserted run */ prev = ME_FindItemBack( pDI, diRun ); if (prev) { int i; for (i = 0; i < editor->nCursors; i++) { if (editor->pCursors[i].pRun == prev && editor->pCursors[i].nOffset == prev->member.run.len) { editor->pCursors[i].pRun = pDI; editor->pCursors[i].nOffset = len; } } } return pDI; }
/* split paragraph at the beginning of the run */ ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, ME_Style *style, const WCHAR *eol_str, int eol_len, int paraFlags) { ME_DisplayItem *next_para = NULL; ME_DisplayItem *run_para = NULL; ME_DisplayItem *new_para = make_para(editor); ME_DisplayItem *end_run; int ofs, i; ME_DisplayItem *pp; int run_flags = MERF_ENDPARA; if (!editor->bEmulateVersion10) { /* v4.1 */ /* At most 1 of MEPF_CELL, MEPF_ROWSTART, or MEPF_ROWEND should be set. */ assert(!(paraFlags & ~(MEPF_CELL|MEPF_ROWSTART|MEPF_ROWEND))); assert(!(paraFlags & (paraFlags-1))); if (paraFlags == MEPF_CELL) run_flags |= MERF_ENDCELL; else if (paraFlags == MEPF_ROWSTART) run_flags |= MERF_TABLESTART|MERF_HIDDEN; } else { /* v1.0 - v3.0 */ assert(!(paraFlags & (MEPF_CELL|MEPF_ROWSTART|MEPF_ROWEND))); } assert(run->type == diRun); run_para = ME_GetParagraph(run); assert(run_para->member.para.pFmt->cbSize == sizeof(PARAFORMAT2)); new_para->member.para.text = ME_VSplitString( run_para->member.para.text, run->member.run.nCharOfs ); end_run = ME_MakeRun(style, run_flags); ofs = end_run->member.run.nCharOfs = run->member.run.nCharOfs; end_run->member.run.len = eol_len; end_run->member.run.para = run->member.run.para; ME_AppendString( run_para->member.para.text, eol_str, eol_len ); next_para = run_para->member.para.next_para; assert(next_para == ME_FindItemFwd(run_para, diParagraphOrEnd)); add_undo_join_paras( editor, run_para->member.para.nCharOfs + ofs ); /* Update selection cursors to point to the correct paragraph. */ for (i = 0; i < editor->nCursors; i++) { if (editor->pCursors[i].pPara == run_para && run->member.run.nCharOfs <= editor->pCursors[i].pRun->member.run.nCharOfs) { editor->pCursors[i].pPara = new_para; } } /* the new paragraph will have a different starting offset, so let's update its runs */ pp = run; while(pp->type == diRun) { pp->member.run.nCharOfs -= ofs; pp->member.run.para = &new_para->member.para; pp = ME_FindItemFwd(pp, diRunOrParagraphOrEnd); } new_para->member.para.nCharOfs = run_para->member.para.nCharOfs + ofs; new_para->member.para.nCharOfs += eol_len; 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.border = run_para->member.para.border; /* insert paragraph into paragraph double linked list */ new_para->member.para.prev_para = run_para; new_para->member.para.next_para = next_para; run_para->member.para.next_para = new_para; next_para->member.para.prev_para = new_para; /* insert end run of the old paragraph, and new paragraph, into DI double linked list */ ME_InsertBefore(run, new_para); ME_InsertBefore(new_para, end_run); if (!editor->bEmulateVersion10) { /* v4.1 */ if (paraFlags & (MEPF_ROWSTART|MEPF_CELL)) { ME_DisplayItem *cell = ME_MakeDI(diCell); ME_InsertBefore(new_para, cell); new_para->member.para.pCell = cell; cell->member.cell.next_cell = NULL; if (paraFlags & MEPF_ROWSTART) { run_para->member.para.nFlags |= MEPF_ROWSTART; cell->member.cell.prev_cell = NULL; cell->member.cell.parent_cell = run_para->member.para.pCell; if (run_para->member.para.pCell) cell->member.cell.nNestingLevel = run_para->member.para.pCell->member.cell.nNestingLevel + 1; else cell->member.cell.nNestingLevel = 1; } else { cell->member.cell.prev_cell = run_para->member.para.pCell; assert(cell->member.cell.prev_cell); cell->member.cell.prev_cell->member.cell.next_cell = cell; assert(run_para->member.para.nFlags & MEPF_CELL); assert(!(run_para->member.para.nFlags & MEPF_ROWSTART)); cell->member.cell.nNestingLevel = cell->member.cell.prev_cell->member.cell.nNestingLevel; cell->member.cell.parent_cell = cell->member.cell.prev_cell->member.cell.parent_cell; } } else if (paraFlags & MEPF_ROWEND) { run_para->member.para.nFlags |= MEPF_ROWEND; run_para->member.para.pCell = run_para->member.para.pCell->member.cell.parent_cell; new_para->member.para.pCell = run_para->member.para.pCell; assert(run_para->member.para.prev_para->member.para.nFlags & MEPF_CELL); assert(!(run_para->member.para.prev_para->member.para.nFlags & MEPF_ROWSTART)); if (new_para->member.para.pCell != new_para->member.para.next_para->member.para.pCell && new_para->member.para.next_para->member.para.pCell && !new_para->member.para.next_para->member.para.pCell->member.cell.prev_cell) { /* Row starts just after the row that was ended. */ new_para->member.para.nFlags |= MEPF_ROWSTART; } } else { new_para->member.para.pCell = run_para->member.para.pCell; } ME_UpdateTableFlags(run_para); ME_UpdateTableFlags(new_para); } /* force rewrap of the */ run_para->member.para.prev_para->member.para.nFlags |= MEPF_REWRAP; new_para->member.para.prev_para->member.para.nFlags |= MEPF_REWRAP; /* we've added the end run, so we need to modify nCharOfs in the next paragraphs */ ME_PropagateCharOffset(next_para, eol_len); editor->nParagraphs++; return new_para; }
/* split paragraph at the beginning of the run */ ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, ME_Style *style, int numCR, int numLF, int paraFlags) { ME_DisplayItem *next_para = NULL; ME_DisplayItem *run_para = NULL; ME_DisplayItem *new_para = ME_MakeDI(diParagraph); ME_DisplayItem *end_run; ME_UndoItem *undo = NULL; int ofs; ME_DisplayItem *pp; int end_len = numCR + numLF; int run_flags = MERF_ENDPARA; if (!editor->bEmulateVersion10) { /* v4.1 */ /* At most 1 of MEPF_CELL, MEPF_ROWSTART, or MEPF_ROWEND should be set. */ assert(!(paraFlags & ~(MEPF_CELL|MEPF_ROWSTART|MEPF_ROWEND))); assert(!(paraFlags & (paraFlags-1))); if (paraFlags == MEPF_CELL) run_flags |= MERF_ENDCELL; else if (paraFlags == MEPF_ROWSTART) run_flags |= MERF_TABLESTART|MERF_HIDDEN; } else { /* v1.0 - v3.0 */ assert(!(paraFlags & (MEPF_CELL|MEPF_ROWSTART|MEPF_ROWEND))); } end_run = ME_MakeRun(style,ME_MakeString(wszParagraphSign), run_flags); assert(run->type == diRun); end_run->member.run.nCR = numCR; end_run->member.run.nLF = numLF; run_para = ME_GetParagraph(run); assert(run_para->member.para.pFmt->cbSize == sizeof(PARAFORMAT2)); ofs = end_run->member.run.nCharOfs = run->member.run.nCharOfs; next_para = run_para->member.para.next_para; assert(next_para == ME_FindItemFwd(run_para, diParagraphOrEnd)); undo = ME_AddUndoItem(editor, diUndoJoinParagraphs, NULL); if (undo) undo->nStart = run_para->member.para.nCharOfs + ofs; /* the new paragraph will have a different starting offset, so let's update its runs */ pp = run; while(pp->type == diRun) { pp->member.run.nCharOfs -= ofs; pp = ME_FindItemFwd(pp, diRunOrParagraphOrEnd); } new_para->member.para.nCharOfs = ME_GetParagraph(run)->member.para.nCharOfs+ofs; new_para->member.para.nCharOfs += end_len; 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.border = run_para->member.para.border; /* insert paragraph into paragraph double linked list */ new_para->member.para.prev_para = run_para; new_para->member.para.next_para = next_para; run_para->member.para.next_para = new_para; next_para->member.para.prev_para = new_para; /* insert end run of the old paragraph, and new paragraph, into DI double linked list */ ME_InsertBefore(run, new_para); ME_InsertBefore(new_para, end_run); if (!editor->bEmulateVersion10) { /* v4.1 */ if (paraFlags & (MEPF_ROWSTART|MEPF_CELL)) { ME_DisplayItem *cell = ME_MakeDI(diCell); ME_InsertBefore(new_para, cell); new_para->member.para.pCell = cell; cell->member.cell.next_cell = NULL; if (paraFlags & MEPF_ROWSTART) { run_para->member.para.nFlags |= MEPF_ROWSTART; cell->member.cell.prev_cell = NULL; cell->member.cell.parent_cell = run_para->member.para.pCell; if (run_para->member.para.pCell) cell->member.cell.nNestingLevel = run_para->member.para.pCell->member.cell.nNestingLevel + 1; else cell->member.cell.nNestingLevel = 1; } else { cell->member.cell.prev_cell = run_para->member.para.pCell; assert(cell->member.cell.prev_cell); cell->member.cell.prev_cell->member.cell.next_cell = cell; assert(run_para->member.para.nFlags & MEPF_CELL); assert(!(run_para->member.para.nFlags & MEPF_ROWSTART)); cell->member.cell.nNestingLevel = cell->member.cell.prev_cell->member.cell.nNestingLevel; cell->member.cell.parent_cell = cell->member.cell.prev_cell->member.cell.parent_cell; } } else if (paraFlags & MEPF_ROWEND) { run_para->member.para.nFlags |= MEPF_ROWEND; run_para->member.para.pCell = run_para->member.para.pCell->member.cell.parent_cell; new_para->member.para.pCell = run_para->member.para.pCell; assert(run_para->member.para.prev_para->member.para.nFlags & MEPF_CELL); assert(!(run_para->member.para.prev_para->member.para.nFlags & MEPF_ROWSTART)); if (new_para->member.para.pCell != new_para->member.para.next_para->member.para.pCell && new_para->member.para.next_para->member.para.pCell && !new_para->member.para.next_para->member.para.pCell->member.cell.prev_cell) { /* Row starts just after the row that was ended. */ new_para->member.para.nFlags |= MEPF_ROWSTART; } } else { new_para->member.para.pCell = run_para->member.para.pCell; } ME_UpdateTableFlags(run_para); ME_UpdateTableFlags(new_para); } /* force rewrap of the */ run_para->member.para.prev_para->member.para.nFlags |= MEPF_REWRAP; new_para->member.para.prev_para->member.para.nFlags |= MEPF_REWRAP; /* we've added the end run, so we need to modify nCharOfs in the next paragraphs */ ME_PropagateCharOffset(next_para, end_len); editor->nParagraphs++; return new_para; }