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_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; }
/****************************************************************************** * 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; }
static void ME_InsertRowStart(ME_WrapContext *wc, const ME_DisplayItem *pEnd) { ME_DisplayItem *p, *row, *para; int ascent = 0, descent = 0, width=0, shift = 0, align = 0; /* wrap text */ para = ME_GetParagraph(wc->pRowStart); for (p = wc->pRowStart; p!=pEnd; p = p->next) { /* ENDPARA run shouldn't affect row height, except if it's the only run in the paragraph */ if (p->type==diRun && ((p==wc->pRowStart) || !(p->member.run.nFlags & MERF_ENDPARA))) { /* FIXME add more run types */ if (p->member.run.nAscent>ascent) ascent = p->member.run.nAscent; if (p->member.run.nDescent>descent) descent = p->member.run.nDescent; if (!(p->member.run.nFlags & (MERF_ENDPARA|MERF_SKIPPED))) width += p->member.run.nWidth; } } row = ME_MakeRow(ascent+descent, ascent, width); row->member.row.nYPos = wc->pt.y; row->member.row.nLMargin = (!wc->nRow ? wc->nFirstMargin : wc->nLeftMargin); row->member.row.nRMargin = wc->nRightMargin; assert(para->member.para.pFmt->dwMask & PFM_ALIGNMENT); align = para->member.para.pFmt->wAlignment; if (align == PFA_CENTER) shift = (wc->nAvailWidth-width)/2; if (align == PFA_RIGHT) shift = wc->nAvailWidth-width; for (p = wc->pRowStart; p!=pEnd; p = p->next) { if (p->type==diRun) { /* FIXME add more run types */ p->member.run.pt.x += row->member.row.nLMargin+shift; } } ME_InsertBefore(wc->pRowStart, row); wc->nRow++; wc->pt.y += ascent+descent; ME_BeginRow(wc); }
static void ME_InsertRowStart(ME_WrapContext *wc, const ME_DisplayItem *pEnd) { ME_DisplayItem *p, *row; ME_Paragraph *para = &wc->pPara->member.para; BOOL bSkippingSpaces = TRUE; int ascent = 0, descent = 0, width=0, shift = 0, align = 0; /* wrap text */ for (p = pEnd->prev; p!=wc->pRowStart->prev; p = p->prev) { /* ENDPARA run shouldn't affect row height, except if it's the only run in the paragraph */ if (p->type==diRun && ((p==wc->pRowStart) || !(p->member.run.nFlags & MERF_ENDPARA))) { /* FIXME add more run types */ if (p->member.run.nAscent>ascent) ascent = p->member.run.nAscent; if (p->member.run.nDescent>descent) descent = p->member.run.nDescent; if (bSkippingSpaces) { /* Exclude space characters from run width. * Other whitespace or delimiters are not treated this way. */ int len = p->member.run.len; WCHAR *text = get_text( &p->member.run, len - 1 ); assert (len); if (~p->member.run.nFlags & MERF_GRAPHICS) while (len && *(text--) == ' ') len--; if (len) { if (len == p->member.run.len) width += p->member.run.nWidth; else width += ME_PointFromCharContext( wc->context, &p->member.run, len, FALSE ); } bSkippingSpaces = !len; } else if (!(p->member.run.nFlags & MERF_ENDPARA)) width += p->member.run.nWidth; } } 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)) { /* The text was shifted down in ME_BeginRow so move the wrap context * back to where it should be. */ wc->pt.y--; /* The height of the row is increased by the borders. */ row->member.row.nHeight += 2; } 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; if (align == PFA_CENTER) shift = max((wc->nAvailWidth-width)/2, 0); if (align == PFA_RIGHT) shift = max(wc->nAvailWidth-width, 0); if (para->nFlags & MEPF_COMPLEX) layout_row( wc->pRowStart, pEnd ); row->member.row.pt.x = row->member.row.nLMargin + shift; for (p = wc->pRowStart; p!=pEnd; p = p->next) { if (p->type==diRun) { /* FIXME add more run types */ p->member.run.pt.x += row->member.row.nLMargin+shift; } } ME_InsertBefore(wc->pRowStart, row); wc->nRow++; wc->pt.y += row->member.row.nHeight; ME_BeginRow(wc); }
/* 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; }