Exemple #1
0
/******************************************************************************
 * ME_RunOfsFromCharOfs
 *
 * Find a run and relative character offset given an absolute character offset
 * (absolute offset being an offset relative to the start of the document).
 * Kind of a "global to local" offset conversion.
 */
void ME_RunOfsFromCharOfs(ME_TextEditor *editor,
                          int nCharOfs,
                          ME_DisplayItem **ppPara,
                          ME_DisplayItem **ppRun,
                          int *pOfs)
{
  ME_DisplayItem *item, *next_item;

  nCharOfs = max(nCharOfs, 0);
  nCharOfs = min(nCharOfs, ME_GetTextLength(editor));

  /* Find the paragraph at the offset. */
  next_item = editor->pBuffer->pFirst->member.para.next_para;
  do {
    item = next_item;
    next_item = item->member.para.next_para;
  } while (next_item->member.para.nCharOfs <= nCharOfs);
  assert(item->type == diParagraph);
  nCharOfs -= item->member.para.nCharOfs;
  if (ppPara) *ppPara = item;

  /* Find the run at the offset. */
  next_item = ME_FindItemFwd(item, diRun);
  do {
    item = next_item;
    next_item = ME_FindItemFwd(item, diRunOrParagraphOrEnd);
  } while (next_item->type == diRun &&
           next_item->member.run.nCharOfs <= nCharOfs);
  assert(item->type == diRun);
  nCharOfs -= item->member.run.nCharOfs;

  if (ppRun) *ppRun = item;
  if (pOfs) *pOfs = nCharOfs;
}
Exemple #2
0
/* Finds the run and offset from the pixel position.
 *
 * x & y are pixel positions in virtual coordinates into the rich edit control,
 * so client coordinates must first be adjusted by the scroll position.
 *
 * 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_DisplayItem *p = editor->pBuffer->pFirst->member.para.next_para;
  BOOL isExact = TRUE;

  x -= editor->rcFormat.left;
  y -= editor->rcFormat.top;

  if (is_eol)
    *is_eol = FALSE;

  /* find paragraph */
  for (; p != editor->pBuffer->pLast; p = p->member.para.next_para)
  {
    assert(p->type == diParagraph);
    if (y < p->member.para.pt.y + p->member.para.nHeight)
    {
      if (p->member.para.nFlags & MEPF_ROWSTART)
        p = ME_FindPixelPosInTableRow(x, y, p);
      y -= p->member.para.pt.y;
      p = ME_FindItemFwd(p, diStartRow);
      break;
    } else if (p->member.para.nFlags & MEPF_ROWSTART) {
      p = ME_GetTableRowEnd(p);
    }
  }
  /* find row */
  for (; p != editor->pBuffer->pLast; )
  {
    ME_DisplayItem *pp;
    assert(p->type == diStartRow);
    if (y < p->member.row.pt.y + p->member.row.nHeight) break;
    pp = ME_FindItemFwd(p, diStartRow);
    if (!pp) break;
    p = pp;
  }
  if (p == editor->pBuffer->pLast)
  {
    /* 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
     * determine the offset closest to the pixel position. */
    isExact = FALSE;
    p = ME_FindItemBack(p, diStartRow);
    if (!p) p = editor->pBuffer->pLast;
  }

  assert( p->type == diStartRow || p == editor->pBuffer->pLast );

  if( p->type == diStartRow )
      return ME_FindRunInRow( editor, p, x, result, is_eol ) && isExact;

  result->pRun = ME_FindItemBack(p, diRun);
  result->pPara = ME_GetParagraph(result->pRun);
  result->nOffset = 0;
  assert(result->pRun->member.run.nFlags & MERF_ENDPARA);
  return FALSE;
}
Exemple #3
0
static void
ME_SelectByType(ME_TextEditor *editor, ME_SelectionType selectionType)
{
  /* pCursor[0] is the end of the selection
   * pCursor[1] is the start of the selection (or the position selection anchor)
   * pCursor[2] and [3] are the selection anchors that are backed up
   * so they are kept when the selection changes for drag selection.
   */

  editor->nSelectionType = selectionType;
  switch(selectionType)
  {
    case stPosition:
      break;
    case stWord:
      ME_MoveCursorWords(editor, &editor->pCursors[0], +1);
      editor->pCursors[1] = editor->pCursors[0];
      ME_MoveCursorWords(editor, &editor->pCursors[1], -1);
      break;
    case stLine:
    case stParagraph:
    {
      ME_DisplayItem *pItem;
      ME_DIType fwdSearchType, backSearchType;
      if (selectionType == stParagraph) {
          backSearchType = diParagraph;
          fwdSearchType = diParagraphOrEnd;
      } else {
          backSearchType = diStartRow;
          fwdSearchType = diStartRowOrParagraphOrEnd;
      }
      pItem = ME_FindItemFwd(editor->pCursors[0].pRun, fwdSearchType);
      assert(pItem);
      if (pItem->type == diTextEnd)
          editor->pCursors[0].pRun = ME_FindItemBack(pItem, diRun);
      else
          editor->pCursors[0].pRun = ME_FindItemFwd(pItem, diRun);
      editor->pCursors[0].nOffset = 0;

      pItem = ME_FindItemBack(pItem, backSearchType);
      editor->pCursors[1].pRun = ME_FindItemFwd(pItem, diRun);
      editor->pCursors[1].nOffset = 0;
      break;
    }
    case stDocument:
      /* Select everything with cursor anchored from the start of the text */
      editor->nSelectionType = stDocument;
      editor->pCursors[1].pRun = ME_FindItemFwd(editor->pBuffer->pFirst, diRun);
      editor->pCursors[1].nOffset = 0;
      editor->pCursors[0].pRun = ME_FindItemBack(editor->pBuffer->pLast, diRun);
      editor->pCursors[0].nOffset = 0;
      break;
    default: assert(0);
  }
  /* Store the anchor positions for extending the selection. */
  editor->pCursors[2] = editor->pCursors[0];
  editor->pCursors[3] = editor->pCursors[1];
}
Exemple #4
0
static void ME_ArrowPageUp(ME_TextEditor *editor, ME_Cursor *pCursor)
{
  ME_DisplayItem *p = ME_FindItemFwd(editor->pBuffer->pFirst, diStartRow);

  if (editor->vert_si.nPos < p->member.row.nHeight)
  {
    pCursor->pRun = ME_FindItemFwd(editor->pBuffer->pFirst, diRun);
    pCursor->nOffset = 0;
    editor->bCaretAtEnd = FALSE;
    /* Native clears seems to clear this x value on page up at the top
     * of the text, but not on page down at the end of the text.
     * Doesn't make sense, but we try to be bug for bug compatible. */
    editor->nUDArrowX = -1;
  } else {
    ME_DisplayItem *pRun = pCursor->pRun;
    ME_DisplayItem *pLast;
    int x, y, ys, yd, yp, yprev;
    int yOldScrollPos = editor->vert_si.nPos;

    x = ME_GetXForArrow(editor, pCursor);
    if (!pCursor->nOffset && editor->bCaretAtEnd)
      pRun = ME_FindItemBack(pRun, diRun);

    p = ME_FindItemBack(pRun, diStartRowOrParagraph);
    assert(p->type == diStartRow);
    yp = ME_FindItemBack(p, diParagraph)->member.para.pt.y;
    yprev = ys = y = yp + p->member.row.pt.y;

    ME_ScrollUp(editor, editor->sizeWindow.cy);
    /* Only move the cursor by the amount scrolled. */
    yd = y + editor->vert_si.nPos - yOldScrollPos;
    pLast = p;

    do {
      p = ME_FindItemBack(p, diStartRowOrParagraph);
      if (!p)
        break;
      if (p->type == diParagraph) { /* crossing paragraphs */
        if (p->member.para.prev_para == NULL)
          break;
        yp = p->member.para.prev_para->member.para.pt.y;
        continue;
      }
      y = yp + p->member.row.pt.y;
      if (y < yd)
        break;
      pLast = p;
      yprev = y;
    } while(1);

    pCursor->pRun = ME_FindRunInRow(editor, pLast, x, &pCursor->nOffset,
                                    &editor->bCaretAtEnd);
  }
  assert(pCursor->pRun);
  assert(pCursor->pRun->type == diRun);
}
Exemple #5
0
ME_DisplayItem* ME_AppendTableRow(ME_TextEditor *editor,
                                  ME_DisplayItem *table_row)
{
  WCHAR endl = '\r', tab = '\t';
  ME_DisplayItem *run;
  PARAFORMAT2 *pFmt;
  int i;

  assert(table_row);
  assert(table_row->type == diParagraph);
  if (!editor->bEmulateVersion10) { /* v4.1 */
    ME_DisplayItem *insertedCell, *para, *cell, *prevTableEnd;
    cell = ME_FindItemFwd(ME_GetTableRowStart(table_row), diCell);
    prevTableEnd = ME_GetTableRowEnd(table_row);
    para = prevTableEnd->member.para.next_para;
    run = ME_FindItemFwd(para, diRun);
    editor->pCursors[0].pPara = para;
    editor->pCursors[0].pRun = run;
    editor->pCursors[0].nOffset = 0;
    editor->pCursors[1] = editor->pCursors[0];
    para = ME_InsertTableRowStartFromCursor(editor);
    insertedCell = ME_FindItemFwd(para, diCell);
    /* Copy cell properties */
    insertedCell->member.cell.nRightBoundary = cell->member.cell.nRightBoundary;
    insertedCell->member.cell.border = cell->member.cell.border;
    while (cell->member.cell.next_cell) {
      cell = cell->member.cell.next_cell;
      para = ME_InsertTableCellFromCursor(editor);
      insertedCell = ME_FindItemBack(para, diCell);
      /* Copy cell properties */
      insertedCell->member.cell.nRightBoundary = cell->member.cell.nRightBoundary;
      insertedCell->member.cell.border = cell->member.cell.border;
    };
    para = ME_InsertTableRowEndFromCursor(editor);
    *para->member.para.pFmt = *prevTableEnd->member.para.pFmt;
    /* 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;
    assert(pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE);
    editor->pCursors[0].pPara = table_row;
    editor->pCursors[0].pRun = run;
    editor->pCursors[0].nOffset = 0;
    editor->pCursors[1] = editor->pCursors[0];
    ME_InsertTextFromCursor(editor, 0, &endl, 1, run->member.run.style);
    run = editor->pCursors[0].pRun;
    for (i = 0; i < pFmt->cTabCount; i++) {
      ME_InsertTextFromCursor(editor, 0, &tab, 1, run->member.run.style);
    }
    return table_row->member.para.next_para;
  }
}
Exemple #6
0
/* Extends the selection with a word, line, or paragraph selection type.
 *
 * The selection is anchored by editor->pCursors[2-3] such that the text
 * between the anchors will remain selected, and one end will be extended.
 *
 * editor->pCursors[0] should have the position to extend the selection to
 * before this function is called.
 *
 * Nothing will be done if editor->nSelectionType equals stPosition.
 */
static void ME_ExtendAnchorSelection(ME_TextEditor *editor)
{
  ME_Cursor tmp_cursor;
  int curOfs, anchorStartOfs, anchorEndOfs;
  if (editor->nSelectionType == stPosition || editor->nSelectionType == stDocument)
      return;
  curOfs = ME_GetCursorOfs(&editor->pCursors[0]);
  anchorStartOfs = ME_GetCursorOfs(&editor->pCursors[3]);
  anchorEndOfs = ME_GetCursorOfs(&editor->pCursors[2]);

  tmp_cursor = editor->pCursors[0];
  editor->pCursors[0] = editor->pCursors[2];
  editor->pCursors[1] = editor->pCursors[3];
  if (curOfs < anchorStartOfs)
  {
      /* Extend the left side of selection */
      editor->pCursors[1] = tmp_cursor;
      if (editor->nSelectionType == stWord)
          ME_MoveCursorWords(editor, &editor->pCursors[1], -1);
      else
      {
          ME_DisplayItem *pItem;
          ME_DIType searchType = ((editor->nSelectionType == stLine) ?
                                  diStartRowOrParagraph:diParagraph);
          pItem = ME_FindItemBack(editor->pCursors[1].pRun, searchType);
          editor->pCursors[1].pRun = ME_FindItemFwd(pItem, diRun);
          editor->pCursors[1].pPara = ME_GetParagraph(editor->pCursors[1].pRun);
          editor->pCursors[1].nOffset = 0;
      }
  }
  else if (curOfs >= anchorEndOfs)
  {
      /* Extend the right side of selection */
      editor->pCursors[0] = tmp_cursor;
      if (editor->nSelectionType == stWord)
          ME_MoveCursorWords(editor, &editor->pCursors[0], +1);
      else
      {
          ME_DisplayItem *pItem;
          ME_DIType searchType = ((editor->nSelectionType == stLine) ?
                                  diStartRowOrParagraphOrEnd:diParagraphOrEnd);
          pItem = ME_FindItemFwd(editor->pCursors[0].pRun, searchType);
          if (pItem->type == diTextEnd)
              editor->pCursors[0].pRun = ME_FindItemBack(pItem, diRun);
          else
              editor->pCursors[0].pRun = ME_FindItemFwd(pItem, diRun);
          editor->pCursors[0].pPara = ME_GetParagraph(editor->pCursors[0].pRun);
          editor->pCursors[0].nOffset = 0;
      }
  }
}
Exemple #7
0
ME_DisplayItem* ME_InsertTableRowStartAtParagraph(ME_TextEditor *editor,
        ME_DisplayItem *para)
{
    ME_DisplayItem *prev_para, *end_para;
    ME_Cursor savedCursor = editor->pCursors[0];
    ME_DisplayItem *startRowPara;
    editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun);
    editor->pCursors[0].nOffset = 0;
    editor->pCursors[1] = editor->pCursors[0];
    startRowPara = ME_InsertTableRowStartFromCursor(editor);
    editor->pCursors[0] = savedCursor;
    editor->pCursors[1] = editor->pCursors[0];

    end_para = ME_GetParagraph(editor->pCursors[0].pRun)->member.para.next_para;
    prev_para = startRowPara->member.para.next_para;
    para = prev_para->member.para.next_para;
    while (para != end_para)
    {
        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;
        prev_para = para;
        para = para->member.para.next_para;
    }
    return startRowPara;
}
Exemple #8
0
static void
ME_MoveCursorLines(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs)
{
  ME_DisplayItem *pRun = pCursor->pRun;
  ME_DisplayItem *pItem;
  int x = ME_GetXForArrow(editor, pCursor);

  if (editor->bCaretAtEnd && !pCursor->nOffset)
    pRun = ME_FindItemBack(pRun, diRun);
  if (!pRun)
    return;
  if (nRelOfs == -1)
  {
    /* start of this row */
    pItem = ME_FindItemBack(pRun, diStartRow);
    assert(pItem);
    /* start of the previous row */
    pItem = ME_FindItemBack(pItem, diStartRow);
  }
  else
  {
    /* start of the next row */
    pItem = ME_FindItemFwd(pRun, diStartRow);
    /* FIXME If diParagraph is before diStartRow, wrap the next paragraph?
    */
  }
  if (!pItem)
  {
    /* row not found - ignore */
    return;
  }
  pCursor->pRun = ME_FindRunInRow(editor, pItem, x, &pCursor->nOffset, &editor->bCaretAtEnd);
  assert(pCursor->pRun);
  assert(pCursor->pRun->type == diRun);
}
Exemple #9
0
static void ME_ArrowPageDown(ME_TextEditor *editor, ME_Cursor *pCursor)
{
  ME_DisplayItem *pLast;
  int x, y;

  /* Find y position of the last row */
  pLast = editor->pBuffer->pLast;
  y = pLast->member.para.prev_para->member.para.pt.y
      + ME_FindItemBack(pLast, diStartRow)->member.row.pt.y;

  x = ME_GetXForArrow(editor, pCursor);

  if (editor->vert_si.nPos >= y - editor->sizeWindow.cy)
  {
    pCursor->pRun = ME_FindItemBack(editor->pBuffer->pLast, diRun);
    pCursor->nOffset = 0;
    editor->bCaretAtEnd = FALSE;
  } else {
    ME_DisplayItem *pRun = pCursor->pRun;
    ME_DisplayItem *p;
    int ys, yd, yp, yprev;
    int yOldScrollPos = editor->vert_si.nPos;

    if (!pCursor->nOffset && editor->bCaretAtEnd)
      pRun = ME_FindItemBack(pRun, diRun);

    p = ME_FindItemBack(pRun, diStartRowOrParagraph);
    assert(p->type == diStartRow);
    yp = ME_FindItemBack(p, diParagraph)->member.para.pt.y;
    yprev = ys = y = yp + p->member.row.pt.y;

    /* For native richedit controls:
     * v1.0 - v3.1 can only scroll down as far as the scrollbar lets us
     * v4.1 can scroll past this position here. */
    ME_ScrollDown(editor, editor->sizeWindow.cy);
    /* Only move the cursor by the amount scrolled. */
    yd = y + editor->vert_si.nPos - yOldScrollPos;
    pLast = p;

    do {
      p = ME_FindItemFwd(p, diStartRowOrParagraph);
      if (!p)
        break;
      if (p->type == diParagraph) {
        yp = p->member.para.pt.y;
        continue;
      }
      y = yp + p->member.row.pt.y;
      if (y >= yd)
        break;
      pLast = p;
      yprev = y;
    } while(1);

    pCursor->pRun = ME_FindRunInRow(editor, pLast, x, &pCursor->nOffset,
                                    &editor->bCaretAtEnd);
  }
  assert(pCursor->pRun);
  assert(pCursor->pRun->type == diRun);
}
Exemple #10
0
void
ME_InvalidateSelection(ME_TextEditor *editor)
{
  ME_DisplayItem *para1, *para2;
  int nStart, nEnd;
  int len = ME_GetTextLength(editor);

  ME_GetSelection(editor, &nStart, &nEnd);
  /* if both old and new selection are 0-char (= caret only), then
  there's no (inverted) area to be repainted, neither old nor new */
  if (nStart == nEnd && editor->nLastSelStart == editor->nLastSelEnd)
    return;
  ME_WrapMarkedParagraphs(editor);
  ME_GetSelectionParas(editor, &para1, &para2);
  assert(para1->type == diParagraph);
  assert(para2->type == diParagraph);
  /* last selection markers aren't always updated, which means
  they can point past the end of the document */ 
  if (editor->nLastSelStart > len)
    editor->nLastSelEnd = len; 
  if (editor->nLastSelEnd > len)
    editor->nLastSelEnd = len; 
    
  /* if the start part of selection is being expanded or contracted... */
  if (nStart < editor->nLastSelStart) {
    ME_MarkForPainting(editor, para1, ME_FindItemFwd(editor->pLastSelStartPara, diParagraphOrEnd));
  } else 
  if (nStart > editor->nLastSelStart) {
    ME_MarkForPainting(editor, editor->pLastSelStartPara, ME_FindItemFwd(para1, diParagraphOrEnd));
  }

  /* if the end part of selection is being contracted or expanded... */
  if (nEnd < editor->nLastSelEnd) {
    ME_MarkForPainting(editor, para2, ME_FindItemFwd(editor->pLastSelEndPara, diParagraphOrEnd));
  } else 
  if (nEnd > editor->nLastSelEnd) {
    ME_MarkForPainting(editor, editor->pLastSelEndPara, ME_FindItemFwd(para2, diParagraphOrEnd));
  }

  ME_InvalidateMarkedParagraphs(editor);
  /* remember the last invalidated position */
  ME_GetSelection(editor, &editor->nLastSelStart, &editor->nLastSelEnd);
  ME_GetSelectionParas(editor, &editor->pLastSelStartPara, &editor->pLastSelEndPara);
  assert(editor->pLastSelStartPara->type == diParagraph);
  assert(editor->pLastSelEndPara->type == diParagraph);
}
Exemple #11
0
static void
ME_GetCursorCoordinates(ME_TextEditor *editor, ME_Cursor *pCursor,
                        int *x, int *y, int *height)
{
  ME_DisplayItem *row;
  ME_DisplayItem *run = pCursor->pRun;
  ME_DisplayItem *para = pCursor->pPara;
  ME_DisplayItem *pSizeRun = run;
  ME_Context c;
  SIZE sz = {0, 0};

  assert(height && x && y);
  assert(~para->member.para.nFlags & MEPF_REWRAP);
  assert(run && run->type == diRun);
  assert(para && para->type == diParagraph);

  row = ME_FindItemBack(run, diStartRowOrParagraph);
  assert(row && row->type == diStartRow);

  ME_InitContext(&c, editor, ITextHost_TxGetDC(editor->texthost));

  if (!pCursor->nOffset)
  {
    ME_DisplayItem *prev = ME_FindItemBack(run, diRunOrParagraph);
    assert(prev);
    if (prev->type == diRun)
      pSizeRun = prev;
  }
  if (editor->bCaretAtEnd && !pCursor->nOffset &&
      run == ME_FindItemFwd(row, diRun))
  {
    ME_DisplayItem *tmp = ME_FindItemBack(row, diRunOrParagraph);
    assert(tmp);
    if (tmp->type == diRun)
    {
      row = ME_FindItemBack(tmp, diStartRow);
      pSizeRun = run = tmp;
      assert(run);
      assert(run->type == diRun);
      sz = ME_GetRunSize(&c, &para->member.para,
                         &run->member.run, run->member.run.len,
                         row->member.row.nLMargin);
    }
  }
  if (pCursor->nOffset) {
    sz = ME_GetRunSize(&c, &para->member.para, &run->member.run,
                       pCursor->nOffset, row->member.row.nLMargin);
  }

  *height = pSizeRun->member.run.nAscent + pSizeRun->member.run.nDescent;
  *x = c.rcView.left + run->member.run.pt.x + sz.cx - editor->horz_si.nPos;
  *y = c.rcView.top + para->member.para.pt.y + row->member.row.nBaseline
       + run->member.run.pt.y - pSizeRun->member.run.nAscent
       - editor->vert_si.nPos;
  ME_DestroyContext(&c);
  return;
}
Exemple #12
0
static BOOL ME_FindRunInRow(ME_TextEditor *editor, ME_DisplayItem *pRow,
                            int x, ME_Cursor *cursor, BOOL *pbCaretAtEnd)
{
  ME_DisplayItem *pNext, *pLastRun;
  ME_Row *row = &pRow->member.row;
  BOOL exact = TRUE;

  if (x < row->pt.x)
  {
      x = row->pt.x;
      exact = FALSE;
  }
  pNext = ME_FindItemFwd(pRow, diRunOrStartRow);
  assert(pNext->type == diRun);
  if (pbCaretAtEnd) *pbCaretAtEnd = FALSE;
  cursor->nOffset = 0;
  do {
    int run_x = pNext->member.run.pt.x;
    int width = pNext->member.run.nWidth;

    if (x >= run_x && x < run_x+width)
    {
      cursor->nOffset = ME_CharFromPoint(editor, x-run_x, &pNext->member.run, TRUE, TRUE);
      cursor->pRun = pNext;
      cursor->pPara = ME_GetParagraph( cursor->pRun );
      return exact;
    }
    pLastRun = pNext;
    pNext = ME_FindItemFwd(pNext, diRunOrStartRow);
  } while(pNext && pNext->type == diRun);

  if ((pLastRun->member.run.nFlags & MERF_ENDPARA) == 0)
  {
    cursor->pRun = ME_FindItemFwd(pNext, diRun);
    if (pbCaretAtEnd) *pbCaretAtEnd = TRUE;
  }
  else
    cursor->pRun = pLastRun;

  cursor->pPara = ME_GetParagraph( cursor->pRun );
  return FALSE;
}
Exemple #13
0
static ME_DisplayItem *ME_FindRunInRow(ME_TextEditor *editor, ME_DisplayItem *pRow, 
                                int x, int *pOffset, int *pbCaretAtEnd)
{
  ME_DisplayItem *pNext, *pLastRun;
  pNext = ME_FindItemFwd(pRow, diRunOrStartRow);
  assert(pNext->type == diRun);
  pLastRun = pNext;
  *pbCaretAtEnd = FALSE;
  do {
    int run_x = pNext->member.run.pt.x;
    int width = pNext->member.run.nWidth;
    if (x < run_x)
    {
      if (pOffset) *pOffset = 0;
      return pNext;
    }
    if (x >= run_x && x < run_x+width)
    {
      int ch = ME_CharFromPointCursor(editor, x-run_x, &pNext->member.run);
      ME_String *s = pNext->member.run.strText;
      if (ch < s->nLen) {
        if (pOffset)
          *pOffset = ch;
        return pNext;          
      }
    }
    pLastRun = pNext;
    pNext = ME_FindItemFwd(pNext, diRunOrStartRow);
  } while(pNext && pNext->type == diRun);
  
  if ((pLastRun->member.run.nFlags & MERF_ENDPARA) == 0)
  {
    pNext = ME_FindItemFwd(pNext, diRun);
    if (pbCaretAtEnd) *pbCaretAtEnd = 1;
    if (pOffset) *pOffset = 0;
    return pNext;
  } else {
    if (pbCaretAtEnd) *pbCaretAtEnd = 0;
    if (pOffset) *pOffset = 0;
    return pLastRun;
  }
}
Exemple #14
0
static void ME_ArrowCtrlHome(ME_TextEditor *editor, ME_Cursor *pCursor)
{
  ME_DisplayItem *pRow = ME_FindItemBack(pCursor->pRun, diTextStart);
  if (pRow) {
    ME_DisplayItem *pRun = ME_FindItemFwd(pRow, diRun);
    if (pRun) {
      pCursor->pRun = pRun;
      pCursor->nOffset = 0;
    }
  }
}
Exemple #15
0
static void ME_ArrowCtrlEnd(ME_TextEditor *editor, ME_Cursor *pCursor)
{
  ME_DisplayItem *p = ME_FindItemFwd(pCursor->pRun, diTextEnd);
  assert(p);
  p = ME_FindItemBack(p, diRun);
  assert(p);
  assert(p->member.run.nFlags & MERF_ENDPARA);
  pCursor->pRun = p;
  pCursor->nOffset = 0;
  editor->bCaretAtEnd = FALSE;
}
Exemple #16
0
/******************************************************************************
 * 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;
}
Exemple #17
0
BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
  ME_DisplayItem *item;
  ME_Context c;
  BOOL bModified = FALSE;
  int yStart = -1;

  ME_InitContext(&c, editor, GetDC(editor->hWnd));
  editor->nHeight = 0;
  item = editor->pBuffer->pFirst->next;
  while(item != editor->pBuffer->pLast) {
    BOOL bRedraw = FALSE;

    assert(item->type == diParagraph);
    editor->nHeight = max(editor->nHeight, item->member.para.nYPos);
    if ((item->member.para.nFlags & MEPF_REWRAP)
     || (item->member.para.nYPos != c.pt.y))
      bRedraw = TRUE;
    item->member.para.nYPos = c.pt.y;

    ME_WrapTextParagraph(&c, item, editor->selofs);

    if (bRedraw)
    {
      item->member.para.nFlags |= MEPF_REPAINT;
      if (yStart == -1)
        yStart = c.pt.y;
    }

    bModified = bModified | bRedraw;

    c.pt.y += item->member.para.nHeight;
    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;

  ME_DestroyContext(&c, editor->hWnd);

  /* Each paragraph may contain multiple rows, which should be scrollable, even
     if the containing paragraph has nYPos == 0 */
  item = editor->pBuffer->pFirst;
  while ((item = ME_FindItemFwd(item, diStartRow)) != NULL) {
    assert(item->type == diStartRow);
    editor->nHeight = max(editor->nHeight, item->member.row.nYPos);
  }

  if (bModified || editor->nTotalLength < editor->nLastTotalLength)
    ME_InvalidateMarkedParagraphs(editor);
  return bModified;
}
Exemple #18
0
/* Make sure the cursor is not in the hidden table row start paragraph
 * without a selection. */
void ME_MoveCursorFromTableRowStartParagraph(ME_TextEditor *editor)
{
    ME_DisplayItem *para = ME_GetParagraph(editor->pCursors[0].pRun);
    if (para == ME_GetParagraph(editor->pCursors[1].pRun) &&
            para->member.para.nFlags & MEPF_ROWSTART) {
        /* The cursors should not be at the hidden start row paragraph without
         * a selection, so the cursor is moved into the first cell. */
        para = para->member.para.next_para;
        editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun);
        editor->pCursors[0].nOffset = 0;
        editor->pCursors[1] = editor->pCursors[0];
    }
}
Exemple #19
0
static void ME_ArrowEnd(ME_TextEditor *editor, ME_Cursor *pCursor)
{
  ME_DisplayItem *pRow;
  
  if (editor->bCaretAtEnd && !pCursor->nOffset)
    return;
  
  pRow = ME_FindItemFwd(pCursor->pRun, diStartRowOrParagraphOrEnd);
  assert(pRow);
  if (pRow->type == diStartRow) {
    /* FIXME WTF was I thinking about here ? */
    ME_DisplayItem *pRun = ME_FindItemFwd(pRow, diRun);
    assert(pRun);
    pCursor->pRun = pRun;
    pCursor->nOffset = 0;
    editor->bCaretAtEnd = 1;
    return;
  }
  pCursor->pRun = ME_FindItemBack(pRow, diRun);
  assert(pCursor->pRun && pCursor->pRun->member.run.nFlags & MERF_ENDPARA);
  pCursor->nOffset = 0;
  editor->bCaretAtEnd = FALSE;
}
Exemple #20
0
/* Helper function for ME_FindPixelPos to find paragraph within tables */
static ME_DisplayItem* ME_FindPixelPosInTableRow(int x, int y,
                                                 ME_DisplayItem *para)
{
  ME_DisplayItem *cell, *next_cell;
  assert(para->member.para.nFlags & MEPF_ROWSTART);
  cell = para->member.para.next_para->member.para.pCell;
  assert(cell);

  /* find the cell we are in */
  while ((next_cell = cell->member.cell.next_cell) != NULL) {
    if (x < next_cell->member.cell.pt.x)
    {
      para = ME_FindItemFwd(cell, diParagraph);
      /* Found the cell, but there might be multiple paragraphs in
       * the cell, so need to search down the cell for the paragraph. */
      while (cell == para->member.para.pCell) {
        if (y < para->member.para.pt.y + para->member.para.nHeight)
        {
          if (para->member.para.nFlags & MEPF_ROWSTART)
            return ME_FindPixelPosInTableRow(x, y, para);
          else
            return para;
        }
        para = para->member.para.next_para;
      }
      /* Past the end of the cell, so go back to the last cell paragraph */
      return para->member.para.prev_para;
    }
    cell = next_cell;
  }
  /* 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);
  return para;
}
Exemple #21
0
static void ME_ArrowPageUp(ME_TextEditor *editor, ME_Cursor *pCursor)
{
  ME_DisplayItem *pRun = pCursor->pRun;
  ME_DisplayItem *pLast, *p;
  int x, y, ys, yd, yp, yprev;
  ME_Cursor tmp_curs = *pCursor;
  
  x = ME_GetXForArrow(editor, pCursor);
  if (!pCursor->nOffset && editor->bCaretAtEnd)
    pRun = ME_FindItemBack(pRun, diRun);
  
  p = ME_FindItemBack(pRun, diStartRowOrParagraph);
  assert(p->type == diStartRow);
  yp = ME_FindItemBack(p, diParagraph)->member.para.nYPos;
  yprev = ys = y = yp + p->member.row.nYPos;
  yd = y - editor->sizeWindow.cy;
  pLast = p;
  
  do {
    p = ME_FindItemBack(p, diStartRowOrParagraph);
    if (!p)
      break;
    if (p->type == diParagraph) { /* crossing paragraphs */
      if (p->member.para.prev_para == NULL)
        break;
      yp = p->member.para.prev_para->member.para.nYPos;
      continue;
    }
    y = yp + p->member.row.nYPos;
    if (y < yd)
      break;
    pLast = p;
    yprev = y;
  } while(1);
  
  pCursor->pRun = ME_FindRunInRow(editor, pLast, x, &pCursor->nOffset, &editor->bCaretAtEnd);
  ME_UpdateSelection(editor, &tmp_curs);
  if (yprev < editor->sizeWindow.cy)
  {
    ME_EnsureVisible(editor, ME_FindItemFwd(editor->pBuffer->pFirst, diRun));
    ME_Repaint(editor);
  }
  else 
  {
    ME_ScrollUp(editor, ys-yprev);
  }
  assert(pCursor->pRun);
  assert(pCursor->pRun->type == diRun);
}
Exemple #22
0
static BOOL ME_ReturnFoundPos(ME_TextEditor *editor, ME_DisplayItem *found,
                               ME_Cursor *result, int rx, BOOL isExact)
{
  assert(found);
  assert(found->type == diRun);
  if ((found->member.run.nFlags & MERF_ENDPARA) || rx < 0)
    rx = 0;
  result->pRun = found;
  result->nOffset = ME_CharFromPointCursor(editor, rx, &found->member.run);
  if (editor->pCursors[0].nOffset == found->member.run.strText->nLen && rx)
  {
    result->pRun = ME_FindItemFwd(editor->pCursors[0].pRun, diRun);
    result->nOffset = 0;
  }
  return isExact;
}
Exemple #23
0
static ME_DisplayItem* ME_InsertEndParaFromCursor(ME_TextEditor *editor,
                                                  int nCursor,
                                                  const WCHAR *eol_str, int eol_len,
                                                  int paraFlags)
{
  ME_Style *pStyle = ME_GetInsertStyle(editor, nCursor);
  ME_DisplayItem *tp;
  ME_Cursor* cursor = &editor->pCursors[nCursor];
  if (cursor->nOffset)
    ME_SplitRunSimple(editor, cursor);

  tp = ME_SplitParagraph(editor, cursor->pRun, pStyle, eol_str, eol_len, paraFlags);
  ME_ReleaseStyle(pStyle);
  cursor->pPara = tp;
  cursor->pRun = ME_FindItemFwd(tp, diRun);
  return tp;
}
Exemple #24
0
ME_DisplayItem* ME_GetTableRowEnd(ME_DisplayItem *para)
{
    ME_DisplayItem *cell;
    assert(para);
    if (para->member.para.nFlags & MEPF_ROWEND)
        return para;
    if (para->member.para.nFlags & MEPF_ROWSTART)
        para = para->member.para.next_para;
    cell = para->member.para.pCell;
    assert(cell && cell->type == diCell);
    while (cell->member.cell.next_cell)
        cell = cell->member.cell.next_cell;

    para = ME_FindItemFwd(cell, diParagraph);
    assert(para && para->member.para.nFlags & MEPF_ROWEND);
    return para;
}
Exemple #25
0
static ME_DisplayItem* ME_InsertEndParaFromCursor(ME_TextEditor *editor,
        int nCursor,
        int numCR,
        int numLF,
        int paraFlags)
{
    ME_Style *pStyle = ME_GetInsertStyle(editor, nCursor);
    ME_DisplayItem *tp;
    ME_Cursor* cursor = &editor->pCursors[nCursor];
    if (cursor->nOffset) {
        ME_SplitRunSimple(editor, cursor->pRun, cursor->nOffset);
        cursor = &editor->pCursors[nCursor];
    }

    tp = ME_SplitParagraph(editor, cursor->pRun, pStyle, numCR, numLF, paraFlags);
    cursor->pRun = ME_FindItemFwd(tp, diRun);
    return tp;
}
Exemple #26
0
/******************************************************************************
 * ME_CheckCharOffsets
 * 
 * Checks if editor lists' validity and optionally dumps the document structure
 */      
void ME_CheckCharOffsets(ME_TextEditor *editor)
{
  ME_DisplayItem *p = editor->pBuffer->pFirst;
  int ofs = 0, ofsp = 0;

  TRACE_(richedit_check)("Checking begin\n");
  if(TRACE_ON(richedit_lists))
  {
    TRACE_(richedit_lists)("---\n");
    ME_DumpDocument(editor->pBuffer);
  }
  do {
    p = ME_FindItemFwd(p, diRunOrParagraphOrEnd);
    switch(p->type) {
      case diTextEnd:
        TRACE_(richedit_check)("tend, real ofsp = %d, counted = %d\n", p->member.para.nCharOfs, ofsp+ofs);
        assert(ofsp+ofs == p->member.para.nCharOfs);
        TRACE_(richedit_check)("Checking finished\n");
        return;
      case diParagraph:
        TRACE_(richedit_check)("para, real ofsp = %d, counted = %d\n", p->member.para.nCharOfs, ofsp+ofs);
        assert(ofsp+ofs == p->member.para.nCharOfs);
        ofsp = p->member.para.nCharOfs;
        ofs = 0;
        break;
      case diRun:
        TRACE_(richedit_check)("run, real ofs = %d (+ofsp = %d), counted = %d, len = %d, txt = %s, flags=%08x, fx&mask = %08x\n",
          p->member.run.nCharOfs, p->member.run.nCharOfs+ofsp, ofsp+ofs,
          p->member.run.len, debugstr_run( &p->member.run ),
          p->member.run.nFlags,
          p->member.run.style->fmt.dwMask & p->member.run.style->fmt.dwEffects);
        assert(ofs == p->member.run.nCharOfs);
        assert(p->member.run.len);
        ofs += p->member.run.len;
        break;
      case diCell:
        TRACE_(richedit_check)("cell\n");
        break;
      default:
        assert(0);
    }
  } while(1);
  TRACE_(richedit_check)("Checking finished\n");
}
Exemple #27
0
static void ME_ArrowHome(ME_TextEditor *editor, ME_Cursor *pCursor)
{
  ME_DisplayItem *pRow = ME_FindItemBack(pCursor->pRun, diStartRow);
  ME_WrapMarkedParagraphs(editor);
  if (pRow) {
    ME_DisplayItem *pRun;
    if (editor->bCaretAtEnd && !pCursor->nOffset) {
      pRow = ME_FindItemBack(pRow, diStartRow);
      if (!pRow)
        return;
    }
    pRun = ME_FindItemFwd(pRow, diRun);
    if (pRun) {
      pCursor->pRun = pRun;
      pCursor->nOffset = 0;
    }
  }
  editor->bCaretAtEnd = FALSE;
}
Exemple #28
0
static void ME_ArrowHome(ME_TextEditor *editor, ME_Cursor *pCursor)
{
  ME_DisplayItem *pRow = ME_FindItemBack(pCursor->pRun, diStartRow);
  /* bCaretAtEnd doesn't make sense if the cursor isn't set at the
  first character of the next row */
  assert(!editor->bCaretAtEnd || !pCursor->nOffset);
  ME_WrapMarkedParagraphs(editor);
  if (pRow) {
    ME_DisplayItem *pRun;
    if (editor->bCaretAtEnd && !pCursor->nOffset) {
      pRow = ME_FindItemBack(pRow, diStartRow);
      if (!pRow)
        return;
    }
    pRun = ME_FindItemFwd(pRow, diRun);
    if (pRun) {
      pCursor->pRun = pRun;
      pCursor->nOffset = 0;
    }
  }
  editor->bCaretAtEnd = FALSE;
}
Exemple #29
0
/******************************************************************************
 * ME_PropagateCharOffsets
 *
 * Shifts (increases or decreases) character offset (relative to beginning of 
 * the document) of the part of the text starting from given place.  
 */ 
void ME_PropagateCharOffset(ME_DisplayItem *p, int shift)
{
	/* Runs in one paragraph contain character offset relative to their owning
	 * paragraph. If we start the shifting from the run, we need to shift
	 * all the relative offsets until the end of the paragraph
	 */	 	    
  if (p->type == diRun) /* propagate in all runs in this para */
  {
    TRACE("PropagateCharOffset(%s, %d)\n", debugstr_run( &p->member.run ), shift);
    do {
      p->member.run.nCharOfs += shift;
      assert(p->member.run.nCharOfs >= 0);
      p = ME_FindItemFwd(p, diRunOrParagraphOrEnd);
    } while(p->type == diRun);
  }
	/* Runs in next paragraphs don't need their offsets updated, because they, 
	 * again, those offsets are relative to their respective paragraphs.
	 * Instead of that, we're updating paragraphs' character offsets.	  
	 */	 	    
  if (p->type == diParagraph) /* propagate in all next paras */
  {
    do {
      p->member.para.nCharOfs += shift;
      assert(p->member.para.nCharOfs >= 0);
      p = p->member.para.next_para;
    } while(p->type == diParagraph);
  }
  /* diTextEnd also has character offset in it, which makes finding text length
   * easier. But it needs to be up to date first.
   */
  if (p->type == diTextEnd)
  {
    p->member.para.nCharOfs += shift;
    assert(p->member.para.nCharOfs >= 0);
  }
}
Exemple #30
0
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;
}