Huw Davies : riched20: Implement parsing of the paragraph numbering destination.

Alexandre Julliard julliard at winehq.org
Fri Oct 7 14:46:47 CDT 2016


Module: wine
Branch: master
Commit: 880b45ffb011a191c8b535cb346f88c220d74db7
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=880b45ffb011a191c8b535cb346f88c220d74db7

Author: Huw Davies <huw at codeweavers.com>
Date:   Fri Oct  7 10:49:32 2016 +0100

riched20: Implement parsing of the paragraph numbering destination.

Signed-off-by: Huw Davies <huw at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/riched20/editor.c       | 117 ++++++++++++++++++++++++++++++++++++++-----
 dlls/riched20/reader.c       |   4 +-
 dlls/riched20/tests/editor.c |  69 +++++++++++++++++++++++++
 3 files changed, 176 insertions(+), 14 deletions(-)

diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c
index da9425e..162daa8 100644
--- a/dlls/riched20/editor.c
+++ b/dlls/riched20/editor.c
@@ -763,18 +763,6 @@ void ME_RTFParAttrHook(RTF_Info *info)
     info->fmt.dwMask |= PFM_NUMBERING;
     info->fmt.wNumbering = 2; /* FIXME: MSDN says it's not used ?? */
     break;
-  case rtfParNumDecimal:
-    info->fmt.dwMask |= PFM_NUMBERING;
-    info->fmt.wNumbering = 2; /* FIXME: MSDN says it's not used ?? */
-    break;
-  case rtfParNumIndent:
-    info->fmt.dwMask |= PFM_NUMBERINGTAB;
-    info->fmt.wNumberingTab = info->rtfParam;
-    break;
-  case rtfParNumStartAt:
-    info->fmt.dwMask |= PFM_NUMBERINGSTART;
-    info->fmt.wNumberingStart = info->rtfParam;
-    break;
   case rtfBorderLeft:
     info->borderType = RTFBorderParaLeft;
     info->fmt.wBorders |= 1;
@@ -1432,6 +1420,110 @@ static void ME_RTFReadObjectGroup(RTF_Info *info)
   RTFRouteToken(info);	/* feed "}" back to router */
 }
 
+static void ME_RTFReadParnumGroup( RTF_Info *info )
+{
+    int level = 1, type = -1;
+    WORD indent = 0, start = 1;
+    WCHAR txt_before = 0, txt_after = 0;
+
+    for (;;)
+    {
+        RTFGetToken( info );
+
+        if (RTFCheckCMM( info, rtfControl, rtfDestination, rtfParNumTextBefore ) ||
+            RTFCheckCMM( info, rtfControl, rtfDestination, rtfParNumTextAfter ))
+        {
+            int loc = info->rtfMinor;
+
+            RTFGetToken( info );
+            if (info->rtfClass == rtfText)
+            {
+                if (loc == rtfParNumTextBefore)
+                    txt_before = info->rtfMajor;
+                else
+                    txt_after = info->rtfMajor;
+                continue;
+            }
+            /* falling through to catch EOFs and group level changes */
+        }
+
+        if (info->rtfClass == rtfEOF)
+            return;
+
+        if (RTFCheckCM( info, rtfGroup, rtfEndGroup ))
+        {
+            if (--level == 0) break;
+            continue;
+        }
+
+        if (RTFCheckCM( info, rtfGroup, rtfBeginGroup ))
+        {
+            level++;
+            continue;
+        }
+
+        /* Ignore non para-attr */
+        if (!RTFCheckCM( info, rtfControl, rtfParAttr ))
+            continue;
+
+        switch (info->rtfMinor)
+        {
+        case rtfParLevel: /* Para level is ignored */
+        case rtfParSimple:
+            break;
+        case rtfParBullet:
+            type = PFN_BULLET;
+            break;
+
+        case rtfParNumDecimal:
+            type = PFN_ARABIC;
+            break;
+        case rtfParNumULetter:
+            type = PFN_UCLETTER;
+            break;
+        case rtfParNumURoman:
+            type = PFN_UCROMAN;
+            break;
+        case rtfParNumLLetter:
+            type = PFN_LCLETTER;
+            break;
+        case rtfParNumLRoman:
+            type = PFN_LCROMAN;
+            break;
+
+        case rtfParNumIndent:
+            indent = info->rtfParam;
+            break;
+        case rtfParNumStartAt:
+            start = info->rtfParam;
+            break;
+        }
+    }
+
+    if (type != -1)
+    {
+        info->fmt.dwMask |= (PFM_NUMBERING | PFM_NUMBERINGSTART | PFM_NUMBERINGSTYLE | PFM_NUMBERINGTAB);
+        info->fmt.wNumbering = type;
+        info->fmt.wNumberingStart = start;
+        info->fmt.wNumberingStyle = PFNS_PAREN;
+        if (type != PFN_BULLET)
+        {
+            if (txt_before == 0 && txt_after == 0)
+                info->fmt.wNumberingStyle = PFNS_PLAIN;
+            else if (txt_after == '.')
+                info->fmt.wNumberingStyle = PFNS_PERIOD;
+            else if (txt_before == '(' && txt_after == ')')
+                info->fmt.wNumberingStyle = PFNS_PARENS;
+        }
+        info->fmt.wNumberingTab = indent;
+    }
+
+    TRACE("type %d indent %d start %d txt before %04x txt after %04x\n",
+          type, indent, start, txt_before, txt_after);
+
+    RTFRouteToken( info );     /* feed "}" back to router */
+}
+
 static void ME_RTFReadHook(RTF_Info *info)
 {
   switch(info->rtfClass)
@@ -1581,6 +1673,7 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre
       RTFSetDestinationCallback(&parser, rtfShpPict, ME_RTFReadShpPictGroup);
       RTFSetDestinationCallback(&parser, rtfPict, ME_RTFReadPictGroup);
       RTFSetDestinationCallback(&parser, rtfObject, ME_RTFReadObjectGroup);
+      RTFSetDestinationCallback(&parser, rtfParNumbering, ME_RTFReadParnumGroup);
       if (!parser.editor->bEmulateVersion10) /* v4.1 */
       {
         RTFSetDestinationCallback(&parser, rtfNoNestTables, RTFSkipGroup);
diff --git a/dlls/riched20/reader.c b/dlls/riched20/reader.c
index 2e5dafd..a05b7fc 100644
--- a/dlls/riched20/reader.c
+++ b/dlls/riched20/reader.c
@@ -1774,8 +1774,8 @@ static RTFKey	rtfKey[] =
 	{ rtfDestination,	rtfFooterFirst,		"footerf",	0 },
 	{ rtfDestination,	rtfParNumText,		"pntext",	0 },
 	{ rtfDestination,	rtfParNumbering,	"pn",		0 },
-	{ rtfDestination,	rtfParNumTextAfter,	"pntexta",	0 },
-	{ rtfDestination,	rtfParNumTextBefore,	"pntextb",	0 },
+	{ rtfDestination,	rtfParNumTextAfter,	"pntxta",	0 },
+	{ rtfDestination,	rtfParNumTextBefore,	"pntxtb",	0 },
 	{ rtfDestination,	rtfBookmarkStart,	"bkmkstart",	0 },
 	{ rtfDestination,	rtfBookmarkEnd,		"bkmkend",	0 },
 	{ rtfDestination,	rtfPict,		"pict",		0 },
diff --git a/dlls/riched20/tests/editor.c b/dlls/riched20/tests/editor.c
index ad51e64..d694d28 100644
--- a/dlls/riched20/tests/editor.c
+++ b/dlls/riched20/tests/editor.c
@@ -8414,6 +8414,74 @@ static void test_eop_char_fmt(void)
     DestroyWindow( edit );
 }
 
+static void test_para_numbering(void)
+{
+    HWND edit = new_richeditW( NULL );
+    const char *numbers = "{\\rtf1{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 Arial;}{\\f1\\fnil\\fcharset2 Symbol;}}"
+        "\\pard{\\pntext\\f0 3.\\tab}{\\*\\pn\\pnlvlbody\\pnfs32\\pnf0\\pnindent1000\\pnstart2\\pndec{\\pntxta.}}"
+        "\\fs20\\fi200\\li360\\f0 First\\par"
+        "{\\pntext\\f0 4.\\tab}\\f0 Second\\par"
+        "{\\pntext\\f0 6.\\tab}\\f0 Third\\par}";
+    const WCHAR expect_numbers_txt[] = {'F','i','r','s','t','\r','S','e','c','o','n','d','\r','T','h','i','r','d',0};
+    EDITSTREAM es;
+    WCHAR buf[80];
+    LRESULT result;
+    PARAFORMAT2 fmt, fmt2;
+    GETTEXTEX get_text;
+    CHARFORMAT2W cf;
+
+    get_text.cb = sizeof(buf);
+    get_text.flags = GT_RAWTEXT;
+    get_text.codepage = 1200;
+    get_text.lpDefaultChar = NULL;
+    get_text.lpUsedDefChar = NULL;
+
+    es.dwCookie = (DWORD_PTR)&numbers;
+    es.dwError = 0;
+    es.pfnCallback = test_EM_STREAMIN_esCallback;
+    result = SendMessageA( edit, EM_STREAMIN, SF_RTF, (LPARAM)&es );
+    ok( result == lstrlenW( expect_numbers_txt ), "got %ld\n", result );
+
+    result = SendMessageW( edit, EM_GETTEXTEX, (WPARAM)&get_text, (LPARAM)buf );
+    ok( result == lstrlenW( expect_numbers_txt ), "got %ld\n", result );
+    ok( !lstrcmpW( buf, expect_numbers_txt ), "got %s\n", wine_dbgstr_w(buf) );
+
+    SendMessageW( edit, EM_SETSEL, 1, 1 );
+    memset( &fmt, 0, sizeof(fmt) );
+    fmt.cbSize = sizeof(fmt);
+    fmt.dwMask = PFM_ALL2;
+    SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
+    ok( fmt.wNumbering == PFN_ARABIC, "got %d\n", fmt.wNumbering );
+    ok( fmt.wNumberingStart == 2, "got %d\n", fmt.wNumberingStart );
+    ok( fmt.wNumberingStyle == PFNS_PERIOD, "got %04x\n", fmt.wNumberingStyle );
+    ok( fmt.wNumberingTab == 1000, "got %d\n", fmt.wNumberingTab );
+    ok( fmt.dxStartIndent == 560, "got %d\n", fmt.dxStartIndent );
+    ok( fmt.dxOffset == -200, "got %d\n", fmt.dxOffset );
+
+    /* Second para should have identical fmt */
+    SendMessageW( edit, EM_SETSEL, 10, 10 );
+    memset( &fmt2, 0, sizeof(fmt2) );
+    fmt2.cbSize = sizeof(fmt2);
+    fmt2.dwMask = PFM_ALL2;
+    SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt2 );
+    ok( !memcmp( &fmt, &fmt2, sizeof(fmt) ), "format mismatch\n" );
+
+    /* Check the eop heights - this determines the label height */
+    SendMessageW( edit, EM_SETSEL, 12, 13 );
+    cf.cbSize = sizeof(cf);
+    cf.dwMask = CFM_SIZE;
+    SendMessageW( edit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf );
+    ok( cf.yHeight == 200, "got %d\n", cf.yHeight );
+
+    SendMessageW( edit, EM_SETSEL, 18, 19 );
+    cf.cbSize = sizeof(cf);
+    cf.dwMask = CFM_SIZE;
+    SendMessageW( edit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf );
+    ok( cf.yHeight == 200, "got %d\n", cf.yHeight );
+
+    DestroyWindow( edit );
+}
+
 START_TEST( editor )
 {
   BOOL ret;
@@ -8486,6 +8554,7 @@ START_TEST( editor )
   test_rtf_specials();
   test_background();
   test_eop_char_fmt();
+  test_para_numbering();
 
   /* Set the environment variable WINETEST_RICHED20 to keep windows
    * responsive and open for 30 seconds. This is useful for debugging.




More information about the wine-cvs mailing list