/****************************************************************************** * ME_GetRunSizeCommon * * Finds width, height, ascent and descent of a run, up to given character * (nLen). */ SIZE ME_GetRunSizeCommon(ME_Context *c, const ME_Paragraph *para, ME_Run *run, int nLen, int startx, int *pAscent, int *pDescent) { SIZE size; WCHAR spaceW[] = {' ',0}; nLen = min( nLen, run->len ); 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; } else if (c->editor->cPasswordMask) { ME_String *szMasked = ME_MakeStringR(c->editor->cPasswordMask,nLen); ME_GetTextExtent(c, szMasked->szData, nLen,run->style, &size); ME_DestroyString(szMasked); } else { ME_GetTextExtent(c, get_text( run, 0 ), nLen, run->style, &size); } *pAscent = run->style->tm.tmAscent; *pDescent = run->style->tm.tmDescent; size.cy = *pAscent + *pDescent; if (run->nFlags & MERF_TAB) { int pos = 0, i = 0, ppos, shift = 0; const PARAFORMAT2 *pFmt = ¶->fmt; if (c->editor->bEmulateVersion10 && /* v1.0 - 3.0 */ pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE) /* The horizontal gap shifts the tab positions to leave the gap. */ shift = pFmt->dxOffset * 2; do { if (i < pFmt->cTabCount) { /* Only one side of the horizontal gap is needed at the end of * the table row. */ if (i == pFmt->cTabCount -1) shift = shift >> 1; pos = shift + (pFmt->rgxTabs[i]&0x00FFFFFF); i++; } else { pos += lDefaultTab - (pos % lDefaultTab); } ppos = ME_twips2pointsX(c, pos); if (ppos > startx + run->pt.x) { size.cx = ppos - startx - run->pt.x; break; } } while(1);
/****************************************************************************** * ME_GetRunSizeCommon * * Finds width, height, ascent and descent of a run, up to given character * (nLen). */ SIZE ME_GetRunSizeCommon(ME_Context *c, const ME_Paragraph *para, ME_Run *run, int nLen, int startx, int *pAscent, int *pDescent) { SIZE size; int nMaxLen = run->len; if (nLen>nMaxLen) nLen = nMaxLen; /* 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 (c->editor->cPasswordMask) { ME_String *szMasked = ME_MakeStringR(c->editor->cPasswordMask,nLen); ME_GetTextExtent(c, szMasked->szData, nLen,run->style, &size); ME_DestroyString(szMasked); } else { ME_GetTextExtent(c, get_text( run, 0 ), nLen, run->style, &size); } *pAscent = run->style->tm.tmAscent; *pDescent = run->style->tm.tmDescent; size.cy = *pAscent + *pDescent; if (run->nFlags & MERF_TAB) { int pos = 0, i = 0, ppos, shift = 0; PARAFORMAT2 *pFmt = para->pFmt; if (c->editor->bEmulateVersion10 && /* v1.0 - 3.0 */ pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE) /* The horizontal gap shifts the tab positions to leave the gap. */ shift = pFmt->dxOffset * 2; do { if (i < pFmt->cTabCount) { /* Only one side of the horizontal gap is needed at the end of * the table row. */ if (i == pFmt->cTabCount -1) shift = shift >> 1; pos = shift + (pFmt->rgxTabs[i]&0x00FFFFFF); i++; } else { pos += lDefaultTab - (pos % lDefaultTab); } ppos = ME_twips2pointsX(c, pos); if (ppos > startx + run->pt.x) { size.cx = ppos - startx - run->pt.x; break; } } while(1);
static void ME_BeginRow(ME_WrapContext *wc) { PARAFORMAT2 *pFmt; ME_DisplayItem *para = wc->pPara; pFmt = para->member.para.pFmt; wc->pRowStart = NULL; wc->bOverflown = FALSE; wc->pLastSplittableRun = NULL; wc->bWordWrap = wc->context->editor->bWordWrap; if (para->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND)) { wc->nAvailWidth = 0; wc->bWordWrap = FALSE; if (para->member.para.nFlags & MEPF_ROWEND) { ME_Cell *cell = &ME_FindItemBack(para, diCell)->member.cell; cell->nWidth = 0; } } else if (para->member.para.pCell) { ME_Cell *cell = ¶->member.para.pCell->member.cell; int width; width = cell->nRightBoundary; if (cell->prev_cell) width -= cell->prev_cell->member.cell.nRightBoundary; if (!cell->prev_cell) { int rowIndent = ME_GetTableRowEnd(para)->member.para.pFmt->dxStartIndent; width -= rowIndent; } cell->nWidth = max(ME_twips2pointsX(wc->context, width), 0); wc->nAvailWidth = cell->nWidth - (wc->nRow ? wc->nLeftMargin : wc->nFirstMargin) - wc->nRightMargin; wc->bWordWrap = TRUE; } else { wc->nAvailWidth = wc->context->nAvailWidth - (wc->nRow ? wc->nLeftMargin : wc->nFirstMargin) - wc->nRightMargin; } wc->pt.x = wc->context->pt.x; if (wc->context->editor->bEmulateVersion10 && /* v1.0 - 3.0 */ pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE) /* Shift the text down because of the border. */ wc->pt.y++; }
void ME_InitContext(ME_Context *c, ME_TextEditor *editor, HDC hDC) { c->nSequence = editor->nSequence++; c->hDC = hDC; c->editor = editor; c->pt.x = 0; c->pt.y = 0; c->hbrMargin = CreateSolidBrush(RGB(224,224,224)); c->rcView = editor->rcFormat; if (hDC) { c->dpi.cx = GetDeviceCaps(hDC, LOGPIXELSX); c->dpi.cy = GetDeviceCaps(hDC, LOGPIXELSY); } else { c->dpi.cx = c->dpi.cy = 96; } if (editor->nAvailWidth) c->nAvailWidth = ME_twips2pointsX(c, editor->nAvailWidth); else c->nAvailWidth = c->rcView.right - c->rcView.left; }
BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) { ME_DisplayItem *item; ME_Context c; int totalWidth = 0; ME_DisplayItem *repaint_start = NULL, *repaint_end = NULL; ME_InitContext(&c, editor, ITextHost_TxGetDC(editor->texthost)); c.pt.x = 0; item = editor->pBuffer->pFirst->next; while(item != editor->pBuffer->pLast) { BOOL bRedraw = FALSE; assert(item->type == diParagraph); if ((item->member.para.nFlags & MEPF_REWRAP) || (item->member.para.pt.y != c.pt.y)) bRedraw = TRUE; item->member.para.pt = c.pt; ME_WrapTextParagraph(&c, item); if (bRedraw) ME_MarkRepaintEnd(item, &repaint_start, &repaint_end); if (item->member.para.nFlags & MEPF_ROWSTART) { ME_DisplayItem *cell = ME_FindItemFwd(item, diCell); ME_DisplayItem *endRowPara; int borderWidth = 0; cell->member.cell.pt = c.pt; /* Offset the text by the largest top border width. */ while (cell->member.cell.next_cell) { borderWidth = max(borderWidth, cell->member.cell.border.top.width); cell = cell->member.cell.next_cell; } endRowPara = ME_FindItemFwd(cell, diParagraph); assert(endRowPara->member.para.nFlags & MEPF_ROWEND); if (borderWidth > 0) { borderWidth = max(ME_twips2pointsY(&c, borderWidth), 1); while (cell) { cell->member.cell.yTextOffset = borderWidth; cell = cell->member.cell.prev_cell; } c.pt.y += borderWidth; } if (endRowPara->member.para.pFmt->dxStartIndent > 0) { int dxStartIndent = endRowPara->member.para.pFmt->dxStartIndent; cell = ME_FindItemFwd(item, diCell); cell->member.cell.pt.x += ME_twips2pointsX(&c, dxStartIndent); c.pt.x = cell->member.cell.pt.x; } } else if (item->member.para.nFlags & MEPF_ROWEND) { /* Set all the cells to the height of the largest cell */ ME_DisplayItem *startRowPara; int prevHeight, nHeight, bottomBorder = 0; ME_DisplayItem *cell = ME_FindItemBack(item, diCell); item->member.para.nWidth = cell->member.cell.pt.x + cell->member.cell.nWidth; if (!(item->member.para.next_para->member.para.nFlags & MEPF_ROWSTART)) { /* Last row, the bottom border is added to the height. */ cell = cell->member.cell.prev_cell; while (cell) { bottomBorder = max(bottomBorder, cell->member.cell.border.bottom.width); cell = cell->member.cell.prev_cell; } bottomBorder = ME_twips2pointsY(&c, bottomBorder); cell = ME_FindItemBack(item, diCell); } prevHeight = cell->member.cell.nHeight; nHeight = cell->member.cell.prev_cell->member.cell.nHeight + bottomBorder; cell->member.cell.nHeight = nHeight; item->member.para.nHeight = nHeight; cell = cell->member.cell.prev_cell; cell->member.cell.nHeight = nHeight; while (cell->member.cell.prev_cell) { cell = cell->member.cell.prev_cell; cell->member.cell.nHeight = nHeight; } /* Also set the height of the start row paragraph */ startRowPara = ME_FindItemBack(cell, diParagraph); startRowPara->member.para.nHeight = nHeight; c.pt.x = startRowPara->member.para.pt.x; c.pt.y = cell->member.cell.pt.y + nHeight; if (prevHeight < nHeight) { /* The height of the cells has grown, so invalidate the bottom of * the cells. */ ME_MarkRepaintEnd(item, &repaint_start, &repaint_end); cell = ME_FindItemBack(item, diCell); while (cell) { ME_MarkRepaintEnd(ME_FindItemBack(cell, diParagraph), &repaint_start, &repaint_end); cell = cell->member.cell.prev_cell; } } } else if (item->member.para.pCell && item->member.para.pCell != item->member.para.next_para->member.para.pCell) { /* The next paragraph is in the next cell in the table row. */ ME_Cell *cell = &item->member.para.pCell->member.cell; cell->nHeight = c.pt.y + item->member.para.nHeight - cell->pt.y; /* Propagate the largest height to the end so that it can be easily * sent back to all the cells at the end of the row. */ if (cell->prev_cell) cell->nHeight = max(cell->nHeight, cell->prev_cell->member.cell.nHeight); c.pt.x = cell->pt.x + cell->nWidth; c.pt.y = cell->pt.y; cell->next_cell->member.cell.pt = c.pt; if (!(item->member.para.next_para->member.para.nFlags & MEPF_ROWEND)) c.pt.y += cell->yTextOffset; } else { if (item->member.para.pCell) { /* Next paragraph in the same cell. */ c.pt.x = item->member.para.pCell->member.cell.pt.x; } else { /* Normal paragraph */ c.pt.x = 0; } c.pt.y += item->member.para.nHeight; } totalWidth = max(totalWidth, item->member.para.nWidth); item = item->member.para.next_para; } editor->sizeWindow.cx = c.rcView.right-c.rcView.left; editor->sizeWindow.cy = c.rcView.bottom-c.rcView.top; editor->nTotalLength = c.pt.y; editor->nTotalWidth = totalWidth; editor->pBuffer->pLast->member.para.pt.x = 0; editor->pBuffer->pLast->member.para.pt.y = c.pt.y; ME_DestroyContext(&c); if (repaint_start || editor->nTotalLength < editor->nLastTotalLength) ME_InvalidateParagraphRange(editor, repaint_start, repaint_end); return !!repaint_start; }
static void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) { ME_DisplayItem *p; ME_WrapContext wc; int border = 0; int linespace = 0; PARAFORMAT2 *pFmt; assert(tp->type == diParagraph); if (!(tp->member.para.nFlags & MEPF_REWRAP)) { return; } ME_PrepareParagraphForWrapping(c, tp); /* 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 */) { if (SUCCEEDED( itemize_para( c, tp ) )) shape_para( c, tp ); } pFmt = tp->member.para.pFmt; wc.context = c; wc.pPara = tp; /* wc.para_style = tp->member.para.style; */ wc.style = NULL; 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; } wc.nFirstMargin = ME_twips2pointsX(c, dxStartIndent); wc.nLeftMargin = wc.nFirstMargin + ME_twips2pointsX(c, pFmt->dxOffset); wc.nRightMargin = ME_twips2pointsX(c, pFmt->dxRightIndent); } if (c->editor->bEmulateVersion10 && /* v1.0 - 3.0 */ pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE) { wc.nFirstMargin += ME_twips2pointsX(c, pFmt->dxOffset * 2); } wc.nRow = 0; wc.pt.y = 0; if (pFmt->dwMask & PFM_SPACEBEFORE) wc.pt.y += ME_twips2pointsY(c, pFmt->dySpaceBefore); if (!(pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE) && pFmt->dwMask & PFM_BORDER) { border = ME_GetParaBorderWidth(c, tp->member.para.pFmt->wBorders); if (pFmt->wBorders & 1) { wc.nFirstMargin += border; wc.nLeftMargin += border; } if (pFmt->wBorders & 2) wc.nRightMargin -= border; if (pFmt->wBorders & 4) wc.pt.y += border; } linespace = ME_GetParaLineSpace(c, &tp->member.para); ME_BeginRow(&wc); for (p = tp->next; p!=tp->member.para.next_para; ) { assert(p->type != diStartRow); if (p->type == diRun) { p = ME_WrapHandleRun(&wc, p); } else p = p->next; if (wc.nRow && p == wc.pRowStart) wc.pt.y += linespace; } ME_WrapEndParagraph(&wc, p); 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) wc.pt.y += ME_twips2pointsY(c, pFmt->dySpaceAfter); tp->member.para.nFlags &= ~MEPF_REWRAP; tp->member.para.nHeight = wc.pt.y; tp->member.para.nRows = wc.nRow; }
static void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp, DWORD beginofs) { ME_DisplayItem *p; ME_WrapContext wc; int border = 0; int linespace = 0; assert(tp->type == diParagraph); if (!(tp->member.para.nFlags & MEPF_REWRAP)) { return; } ME_PrepareParagraphForWrapping(c, tp); wc.context = c; /* wc.para_style = tp->member.para.style; */ wc.style = NULL; wc.nFirstMargin = ME_twips2pointsX(c, tp->member.para.pFmt->dxStartIndent) + beginofs; wc.nLeftMargin = wc.nFirstMargin + ME_twips2pointsX(c, tp->member.para.pFmt->dxOffset); wc.nRightMargin = ME_twips2pointsX(c, tp->member.para.pFmt->dxRightIndent); wc.nRow = 0; wc.pt.x = 0; wc.pt.y = 0; if (tp->member.para.pFmt->dwMask & PFM_SPACEBEFORE) wc.pt.y += ME_twips2pointsY(c, tp->member.para.pFmt->dySpaceBefore); if (tp->member.para.pFmt->dwMask & PFM_BORDER) { border = ME_GetParaBorderWidth(c->editor, tp->member.para.pFmt->wBorders); if (tp->member.para.pFmt->wBorders & 1) { wc.nFirstMargin += border; wc.nLeftMargin += border; } if (tp->member.para.pFmt->wBorders & 2) wc.nRightMargin -= border; if (tp->member.para.pFmt->wBorders & 4) wc.pt.y += border; } if (c->editor->bWordWrap) wc.nAvailWidth = c->rcView.right - c->rcView.left - wc.nFirstMargin - wc.nRightMargin; else wc.nAvailWidth = ~0u >> 1; wc.pRowStart = NULL; linespace = ME_GetParaLineSpace(c, &tp->member.para); ME_BeginRow(&wc); for (p = tp->next; p!=tp->member.para.next_para; ) { assert(p->type != diStartRow); if (p->type == diRun) { p = ME_WrapHandleRun(&wc, p); } else p = p->next; if (wc.nRow && p == wc.pRowStart) wc.pt.y += linespace; } ME_WrapEndParagraph(&wc, p); if ((tp->member.para.pFmt->dwMask & PFM_BORDER) && (tp->member.para.pFmt->wBorders & 8)) wc.pt.y += border; if (tp->member.para.pFmt->dwMask & PFM_SPACEAFTER) wc.pt.y += ME_twips2pointsY(c, tp->member.para.pFmt->dySpaceAfter); tp->member.para.nFlags &= ~MEPF_REWRAP; tp->member.para.nHeight = wc.pt.y; tp->member.para.nRows = wc.nRow; }