riched20: Initial support for simple tables

Phil Krylov phil at newstar.rinet.ru
Fri Feb 3 16:59:44 CST 2006


Hi,

this patch needs to be applied after the
"Simplified ME_InsertGraphicsFromCursor()" patch.


ChangeLog:

Added initial support for simple tables in rich edit control. 

---

 dlls/riched20/caret.c   |   30 ++++++++++++++++++++++++--
 dlls/riched20/editor.c  |   55 ++++++++++++++++++++++++++++++++++++++++++++++-
 dlls/riched20/editor.h  |    2 ++
 dlls/riched20/editstr.h |   16 ++++++++++++++
 dlls/riched20/list.c    |   18 +++++++++++++++
 dlls/riched20/paint.c   |    2 +-
 dlls/riched20/para.c    |   12 ++++++++++
 dlls/riched20/reader.c  |    4 +--
 dlls/riched20/run.c     |   15 +++++++++----
 dlls/riched20/writer.c  |   39 ++++++++++++++++++++++++++++++---
 10 files changed, 178 insertions(+), 15 deletions(-)

f242e9e7515ae3aa5be4b9423ea7bbbaa278862d
diff --git a/dlls/riched20/caret.c b/dlls/riched20/caret.c
index 11fa20e..06e8c6f 100644
--- a/dlls/riched20/caret.c
+++ b/dlls/riched20/caret.c
@@ -314,7 +314,7 @@ void ME_DeleteTextAtCursor(ME_TextEditor
   ME_InternalDeleteText(editor, ME_GetCursorOfs(editor, nCursor), nChars);
 }
 
-static void
+static ME_DisplayItem *
 ME_InternalInsertTextFromCursor(ME_TextEditor *editor, int nCursor,
                                 const WCHAR *str, int len, ME_Style *style,
                                 int flags)
@@ -325,7 +325,7 @@ ME_InternalInsertTextFromCursor(ME_TextE
   
   assert(p->pRun->type == diRun);
   
-  ME_InsertRunAtCursor(editor, p, style, str, len, flags);
+  return ME_InsertRunAtCursor(editor, p, style, str, len, flags);
 }
 
 
@@ -345,6 +345,32 @@ void ME_InsertGraphicsFromCursor(ME_Text
 }
 
 
+void
+ME_InsertTableCellFromCursor(ME_TextEditor *editor, int nCursor)
+{
+  WCHAR tab = '\t';
+  ME_DisplayItem *p, *run;
+  ME_Style *pStyle = ME_GetInsertStyle(editor, nCursor);
+  
+  p = ME_InternalInsertTextFromCursor(editor, nCursor, &tab, 1, pStyle,
+                                      MERF_CELL);
+  run = p;
+  while ((run = ME_FindItemBack(run, diRunOrParagraph))->type == diRun)
+  {
+    if (run->member.run.nFlags & MERF_CELL)
+    {
+      assert(run->member.run.pCell->next);
+      p->member.run.pCell = run->member.run.pCell->next;
+      return;
+    }
+  }
+  assert(run->type == diParagraph);
+  assert(run->member.para.bTable);
+  assert(run->member.para.pCells);
+  p->member.run.pCell = run->member.para.pCells;
+}
+
+
 void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, 
   const WCHAR *str, int len, ME_Style *style)
 {
diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c
index 175c4a7..0c9b3ff 100644
--- a/dlls/riched20/editor.c
+++ b/dlls/riched20/editor.c
@@ -414,12 +414,24 @@ static void ME_RTFParAttrHook(RTF_Info *
   
   switch(info->rtfMinor)
   {
-  case rtfParDef: /* I'm not 100% sure what does it do, but I guess it restores default paragraph attributes */
+  case rtfParDef: /* restores default paragraph attributes */
     fmt.dwMask = PFM_ALIGNMENT | PFM_TABSTOPS | PFM_OFFSET | PFM_STARTINDENT;
     fmt.wAlignment = PFA_LEFT;
     fmt.cTabCount = 0;
     fmt.dxOffset = fmt.dxStartIndent = 0;
+    RTFFlushOutputBuffer(info);
+    ME_GetParagraph(info->editor->pCursors[0].pRun)->member.para.bTable = FALSE;
     break;
+  case rtfInTable:
+  {
+    ME_DisplayItem *para;
+    
+    RTFFlushOutputBuffer(info);
+    para = ME_GetParagraph(info->editor->pCursors[0].pRun);
+    assert(para->member.para.pCells);
+    para->member.para.bTable = TRUE;
+    return;
+  }
   case rtfFirstIndent:
     ME_GetSelectionParaFormat(info->editor, &fmt);
     fmt.dwMask = PFM_STARTINDENT | PFM_OFFSET;
@@ -466,6 +478,38 @@ static void ME_RTFParAttrHook(RTF_Info *
   }
 }
 
+static void ME_RTFTblAttrHook(RTF_Info *info)
+{
+  ME_DisplayItem *para;
+  
+  switch (info->rtfMinor)
+  {
+    case rtfRowDef:
+      RTFFlushOutputBuffer(info);
+      para = ME_GetParagraph(info->editor->pCursors[0].pRun);
+      
+      para->member.para.pCells = ALLOC_OBJ(ME_TableCell);
+      para->member.para.pCells->nRightBoundary = 0;
+      para->member.para.pCells->next = NULL;
+      para->member.para.pLastCell = para->member.para.pCells;
+      break;
+    case rtfCellPos:
+      RTFFlushOutputBuffer(info);
+      para = ME_GetParagraph(info->editor->pCursors[0].pRun);
+      
+      if (para->member.para.pLastCell->nRightBoundary)
+      {
+        ME_TableCell *pCell = ALLOC_OBJ(ME_TableCell);
+        
+        pCell->next = NULL;
+        para->member.para.pLastCell->next = pCell;
+        para->member.para.pLastCell = pCell;
+      }
+      para->member.para.pLastCell->nRightBoundary = info->rtfParam;
+      break;
+  }
+}
+
 static void ME_RTFReadHook(RTF_Info *info) {
   switch(info->rtfClass)
   {
@@ -513,6 +557,15 @@ static void ME_RTFReadHook(RTF_Info *inf
         case rtfParAttr:
           ME_RTFParAttrHook(info);
           break;
+        case rtfTblAttr:
+          ME_RTFTblAttrHook(info);
+          break;
+        case rtfSpecialChar:
+          if (info->rtfMinor == rtfCell)
+          {
+            RTFFlushOutputBuffer(info);
+            ME_InsertTableCellFromCursor(info->editor, 0);
+          }
       }
       break;
   }
diff --git a/dlls/riched20/editor.h b/dlls/riched20/editor.h
index 56d1c48..e3c7c5e 100644
--- a/dlls/riched20/editor.h
+++ b/dlls/riched20/editor.h
@@ -56,6 +56,7 @@ ME_DisplayItem *ME_FindItemFwdOrHere(ME_
 BOOL ME_DITypesEqual(ME_DIType type, ME_DIType nTypeOrClass);
 ME_DisplayItem *ME_MakeDI(ME_DIType type);
 void ME_DestroyDisplayItem(ME_DisplayItem *item);
+void ME_DestroyTableCellList(ME_DisplayItem *item);
 void ME_DumpDocument(ME_TextBuffer *buffer);
 const char *ME_GetDITypeName(ME_DIType type);
 
@@ -169,6 +170,7 @@ BOOL ME_IsSelection(ME_TextEditor *edito
 void ME_DeleteSelection(ME_TextEditor *editor);
 void ME_SendSelChange(ME_TextEditor *editor);
 void ME_InsertGraphicsFromCursor(ME_TextEditor *editor, int nCursor);
+void ME_InsertTableCellFromCursor(ME_TextEditor *editor, int nCursor);
 void ME_InternalDeleteText(ME_TextEditor *editor, int nOfs, int nChars);
 int ME_GetTextLength(ME_TextEditor *editor);
 int ME_GetTextLengthEx(ME_TextEditor *editor, GETTEXTLENGTHEX *how);
diff --git a/dlls/riched20/editstr.h b/dlls/riched20/editstr.h
index d27eab9..7a60124 100644
--- a/dlls/riched20/editstr.h
+++ b/dlls/riched20/editstr.h
@@ -91,6 +91,10 @@ typedef enum {
 #define MERF_GRAPHICS 1
 /* run is a tab (or, in future, any kind of content whose size is dependent on run position) */
 #define MERF_TAB 2
+/* run is a cell boundary */
+#define MERF_CELL 4
+
+#define MERF_NONTEXT (MERF_GRAPHICS | MERF_TAB | MERF_CELL)
 
 /* run is splittable (contains white spaces in the middle or end) */
 #define MERF_SPLITTABLE 0x001000
@@ -136,6 +140,7 @@ typedef struct tagME_Run
   int nFlags;
   int nAscent, nDescent; /* pixels above/below baseline */
   POINT pt; /* relative to para's position */
+  struct tagME_TableCell *pCell; /* for MERF_CELL: points to respective cell in ME_Paragraph */
 } ME_Run;
 
 typedef struct tagME_Document {
@@ -144,9 +149,20 @@ typedef struct tagME_Document {
   int last_wrapped_line;
 } ME_Document;
 
+typedef struct tagME_TableCell
+{
+  int nRightBoundary;
+  struct tagME_TableCell *next;
+} ME_TableCell;
+
 typedef struct tagME_Paragraph
 {
   PARAFORMAT2 *pFmt;
+  
+  BOOL bTable;                       /* this paragraph is a table row */
+  struct tagME_TableCell *pCells;    /* list of cells and their properties */
+  struct tagME_TableCell *pLastCell; /* points to the last cell in the list */
+
   int nLeftMargin, nRightMargin, nFirstMargin;
   int nCharOfs;
   int nFlags;
diff --git a/dlls/riched20/list.c b/dlls/riched20/list.c
index f0d15dd..cf30474 100644
--- a/dlls/riched20/list.c
+++ b/dlls/riched20/list.c
@@ -112,6 +112,7 @@ void ME_DestroyDisplayItem(ME_DisplayIte
 /*  TRACE("type=%s\n", ME_GetDITypeName(item->type)); */
   if (item->type==diParagraph || item->type == diUndoSetParagraphFormat) {
     FREE_OBJ(item->member.para.pFmt);
+    ME_DestroyTableCellList(item);
   }
   if (item->type==diRun || item->type == diUndoInsertRun) {
     ME_ReleaseStyle(item->member.run.style);
@@ -123,6 +124,23 @@ void ME_DestroyDisplayItem(ME_DisplayIte
   FREE_OBJ(item);
 }
 
+void
+ME_DestroyTableCellList(ME_DisplayItem *item)
+{
+  if (item->member.para.pCells)
+  {
+    ME_TableCell *pCell = item->member.para.pCells;
+    ME_TableCell *pNext;
+
+    while (pCell) {
+      pNext = pCell->next;
+      FREE_OBJ(pCell);
+      pCell = pNext;
+    }
+    item->member.para.pCells = NULL;
+  }
+}
+
 ME_DisplayItem *ME_MakeDI(ME_DIType type) {
   ME_DisplayItem *item = ALLOC_OBJ(ME_DisplayItem);
   ZeroMemory(item, sizeof(ME_DisplayItem));
diff --git a/dlls/riched20/paint.c b/dlls/riched20/paint.c
index 6a87063..80cc036 100644
--- a/dlls/riched20/paint.c
+++ b/dlls/riched20/paint.c
@@ -237,7 +237,7 @@ static void ME_DrawRun(ME_Context *c, in
                          start->member.row.nHeight);
           
   /* you can always comment it out if you need visible paragraph marks */
-  if (run->nFlags & (MERF_ENDPARA|MERF_TAB)) 
+  if (run->nFlags & (MERF_ENDPARA | MERF_TAB | MERF_CELL)) 
     return;
 
   if (run->nFlags & MERF_GRAPHICS)
diff --git a/dlls/riched20/para.c b/dlls/riched20/para.c
index 12f63ac..174514e 100644
--- a/dlls/riched20/para.c
+++ b/dlls/riched20/para.c
@@ -2,6 +2,7 @@
  * RichEdit - functions working on paragraphs of text (diParagraph).
  * 
  * Copyright 2004 by Krzysztof Foltman
+ * Copyright 2006 by Phil Krylov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -133,6 +134,17 @@ ME_DisplayItem *ME_SplitParagraph(ME_Tex
   new_para->member.para.nLeftMargin = run_para->member.para.nLeftMargin;
   new_para->member.para.nRightMargin = run_para->member.para.nRightMargin;
   new_para->member.para.nFirstMargin = run_para->member.para.nFirstMargin;
+
+  new_para->member.para.bTable = run_para->member.para.bTable;
+  new_para->member.para.pCells = NULL;
+
+  /* fix paragraph properties. FIXME only needed when called from RTF reader */
+  if (run_para->member.para.pCells && !run_para->member.para.bTable)
+  {
+    /* Paragraph does not have an \intbl keyword, so any table definition
+     * stored is invalid */
+    ME_DestroyTableCellList(run_para);
+  }
   
   /* insert paragraph into paragraph double linked list */
   new_para->member.para.prev_para = run_para;
diff --git a/dlls/riched20/reader.c b/dlls/riched20/reader.c
index 72cff65..0a8d52a 100644
--- a/dlls/riched20/reader.c
+++ b/dlls/riched20/reader.c
@@ -2,6 +2,7 @@
  * WINE RTF file reader
  *
  * Portions Copyright 2004 Mike McCormack for CodeWeavers
+ * Portions Copyright 2006 by Phil Krylov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -2652,9 +2653,6 @@ static void SpecialChar (RTF_Info *info)
 	case rtfPar:
 		RTFPutUnicodeChar (info, '\n');
 		break;
-	case rtfCell:
-                RTFPutUnicodeChar (info, ' ');	/* make sure cells are separated */
-		break;
 	case rtfNoBrkSpace:
 		RTFPutUnicodeChar (info, 0x00A0);
 		break;
diff --git a/dlls/riched20/run.c b/dlls/riched20/run.c
index 4730784..86a8c27 100644
--- a/dlls/riched20/run.c
+++ b/dlls/riched20/run.c
@@ -4,6 +4,7 @@
  * Character/pixel conversions.
  *
  * Copyright 2004 by Krzysztof Foltman
+ * Copyright 2006 by Phil Krylov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -256,7 +257,7 @@ ME_DisplayItem *ME_SplitRunSimple(ME_Tex
   int i;
   assert(nVChar > 0 && nVChar < ME_StrVLen(run->strText));
   assert(item->type == diRun);
-  assert(!(item->member.run.nFlags & (MERF_GRAPHICS | MERF_TAB)));
+  assert(!(item->member.run.nFlags & MERF_NONTEXT));
   assert(item->member.run.nCharOfs != -1);
 
   item2 = ME_MakeRun(run->style,
@@ -390,7 +391,7 @@ int ME_CharFromPoint(ME_TextEditor *edit
   if (!run->strText->nLen)
     return 0;
 
-  if (run->nFlags & MERF_TAB)
+  if (run->nFlags & (MERF_TAB | MERF_CELL))
   {
     if (cx < run->nWidth/2)
       return 0;
@@ -422,7 +423,7 @@ int ME_CharFromPointCursor(ME_TextEditor
   if (!run->strText->nLen)
     return 0;
 
-  if (run->nFlags & MERF_TAB)
+  if (run->nFlags & (MERF_TAB | MERF_CELL))
   {
     if (cx < run->nWidth/2)
       return 0;
@@ -494,7 +495,7 @@ SIZE ME_GetRunSizeCommon(ME_Context *c, 
     nLen = nMaxLen;
 
   /* FIXME the following call also ensures that TEXTMETRIC structure is filled
-   * this is wasteful for graphics and TAB runs, but that shouldn't matter
+   * this is wasteful for MERF_NONTEXT runs, but that shouldn't matter
    * in practice
    */
   ME_GetTextExtent(c, run->strText->szData, nLen, run->style, &size);
@@ -534,7 +535,13 @@ SIZE ME_GetRunSizeCommon(ME_Context *c, 
     /* descent is unchanged */
     return size;
   }
+  if (run->nFlags & MERF_CELL)
+  {
+    int lpsx = GetDeviceCaps(c->hDC, LOGPIXELSX);
 
+    size.cx = run->pCell->nRightBoundary * lpsx / 1440 - run->pt.x;
+    return size;
+  }
   return size;
 }
 
diff --git a/dlls/riched20/writer.c b/dlls/riched20/writer.c
index c8d1226..5e2cee5 100644
--- a/dlls/riched20/writer.c
+++ b/dlls/riched20/writer.c
@@ -290,9 +290,27 @@ ME_StreamOutRTFParaProps(ME_TextEditor *
   char props[STREAMOUT_BUFFER_SIZE] = "";
   int i;
 
+  if (para->member.para.pCells)
+  {
+    ME_TableCell *cell = para->member.para.pCells;
+    
+    if (!ME_StreamOutPrint(editor, "\\trowd"))
+      return FALSE;
+    do {
+      sprintf(props, "\\cellx%d", cell->nRightBoundary);
+      if (!ME_StreamOutPrint(editor, props))
+        return FALSE;
+      cell = cell->next;
+    } while (cell);
+    props[0] = '\0';
+  }
+  
   /* TODO: Don't emit anything if the last PARAFORMAT2 is inherited */
   if (!ME_StreamOutPrint(editor, "\\pard"))
     return FALSE;
+
+  if (para->member.para.bTable)
+    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
@@ -634,11 +652,14 @@ ME_StreamOutRTFText(ME_TextEditor *edito
 static BOOL
 ME_StreamOutRTF(ME_TextEditor *editor, int nStart, int nChars, int dwFormat)
 {
-  ME_DisplayItem *p, *pEnd;
-  int nOffset, nEndLen;
+  ME_DisplayItem *p, *pEnd, *pPara;
+  int nOffset, nEndLen; 
+  
   ME_RunOfsFromCharOfs(editor, nStart, &p, &nOffset);
   ME_RunOfsFromCharOfs(editor, nStart+nChars, &pEnd, &nEndLen);
   
+  pPara = ME_GetParagraph(p);
+  
   if (!ME_StreamOutRTFHeader(editor, dwFormat))
     return FALSE;
 
@@ -669,6 +690,7 @@ ME_StreamOutRTF(ME_TextEditor *editor, i
       case diParagraph:
         if (!ME_StreamOutRTFParaProps(editor, p))
           return FALSE;
+        pPara = p;
         break;
       case diRun:
         if (p == pEnd && !nEndLen)
@@ -677,10 +699,19 @@ ME_StreamOutRTF(ME_TextEditor *editor, i
         /* TODO: emit embedded objects */
         if (p->member.run.nFlags & MERF_GRAPHICS)
           FIXME("embedded objects are not handled\n");
-        if (p->member.run.nFlags & MERF_ENDPARA) {
-          if (!ME_StreamOutPrint(editor, "\r\n\\par"))
+        if (p->member.run.nFlags & MERF_CELL) {
+          if (!ME_StreamOutPrint(editor, "\\cell "))
             return FALSE;
           nChars--;
+        } else if (p->member.run.nFlags & MERF_ENDPARA) {
+          if (pPara->member.para.bTable) {
+            if (!ME_StreamOutPrint(editor, "\\row \r\n"))
+              return FALSE;
+          } else {
+            if (!ME_StreamOutPrint(editor, "\r\n\\par"))
+              return FALSE;
+          }
+          nChars--;
           if (editor->bEmulateVersion10 && nChars)
             nChars--;
         } else {
-- 
1.0.GIT



More information about the wine-patches mailing list