[PATCH 2/9] [WinHelp]: start feeding the richedit control with relevant RTF stream

Eric Pouech eric.pouech at orange.fr
Wed Apr 23 14:37:51 CDT 2008




A+
---

 programs/winhelp/hlpfile.c |  158 ++++++++++++++++++++++++++++++++++++++++----
 programs/winhelp/hlpfile.h |   12 +++
 programs/winhelp/winhelp.c |   76 ++++++++++++++++++---
 3 files changed, 220 insertions(+), 26 deletions(-)


diff --git a/programs/winhelp/hlpfile.c b/programs/winhelp/hlpfile.c
index 498136d..ac270c7 100644
--- a/programs/winhelp/hlpfile.c
+++ b/programs/winhelp/hlpfile.c
@@ -618,6 +618,58 @@ static BYTE*    HLPFILE_DecompressGfx(BYTE* src, unsigned csz, unsigned sz, BYTE
     return dst;
 }
 
+static BOOL HLPFILE_RtfAddRawString(struct RtfData* rd, const char* str, size_t sz)
+{
+    if (!rd) return TRUE; /* FIXME: TEMP */
+    if (rd->ptr + sz >= rd->data + rd->allocated)
+    {
+        char*   new = HeapReAlloc(GetProcessHeap(), 0, rd->data, rd->allocated *= 2);
+        if (!new) return FALSE;
+        rd->ptr = new + (rd->ptr - rd->data);
+        rd->data = new;
+    }
+    memcpy(rd->ptr, str, sz);
+    rd->ptr += sz;
+
+    return TRUE;
+}
+
+static BOOL HLPFILE_RtfAddControl(struct RtfData* rd, const char* str)
+{
+    if (!rd) return TRUE; /* FIXME: TEMP */
+    if (*str == '\\' || *str == '{') rd->in_text = FALSE;
+    else if (*str == '}') rd->in_text = TRUE;
+    return HLPFILE_RtfAddRawString(rd, str, strlen(str));
+}
+
+static BOOL HLPFILE_RtfAddText(struct RtfData* rd, const char* str)
+{
+    const char* p;
+    const char* last;
+    const char* replace;
+
+    if (!rd) return TRUE; /* FIXME: TEMP */
+    if (!rd->in_text)
+    {
+        if (!HLPFILE_RtfAddRawString(rd, " ", 1)) return FALSE;
+        rd->in_text = TRUE;
+    }
+    for (last = p = str; *p; p++)
+    {
+        switch (*p)
+        {
+        case '{':  replace = "\\{";  break;
+        case '}':  replace = "\\}";  break;
+        case '\\': replace = "\\\\"; break;
+        default:   continue;
+        }
+        if ((p != last && !HLPFILE_RtfAddRawString(rd, last, p - last)) ||
+            !HLPFILE_RtfAddRawString(rd, replace, 2)) return FALSE;
+        last = p + 1;
+    }
+    return HLPFILE_RtfAddRawString(rd, last, p - last);
+}
+
 /******************************************************************
  *		HLPFILE_LoadBitmap
  *
@@ -875,7 +927,7 @@ static HLPFILE_LINK*       HLPFILE_AllocLink(int cookie, const char* str, LONG h
  *
  *           HLPFILE_BrowseParagraph
  */
-static BOOL HLPFILE_BrowseParagraph(HLPFILE_PAGE* page, BYTE *buf, BYTE* end)
+static BOOL HLPFILE_BrowseParagraph(HLPFILE_PAGE* page, struct RtfData* rd, BYTE *buf, BYTE* end)
 {
     HLPFILE_PARAGRAPH *paragraph, **paragraphptr;
     UINT               textsize;
@@ -885,6 +937,8 @@ static BOOL HLPFILE_BrowseParagraph(HLPFILE_PAGE* page, BYTE *buf, BYTE* end)
     unsigned short     bits;
     unsigned           nc, ncol = 1;
     BOOL               in_table = FALSE;
+    char               tmp[256];
+    BOOL               ret = FALSE;
 
     for (paragraphptr = &page->first_paragraph; *paragraphptr;
          paragraphptr = &(*paragraphptr)->next) /* Nothing */;
@@ -976,11 +1030,11 @@ static BOOL HLPFILE_BrowseParagraph(HLPFILE_PAGE* page, BYTE *buf, BYTE* end)
         while (text < text_end && format < format_end)
         {
             WINE_TRACE("Got text: %s (%p/%p - %p/%p)\n", wine_dbgstr_a(text), text, text_end, format, format_end);
-            textsize = strlen(text) + 1;
-            if (textsize > 1)
+            textsize = strlen(text);
+            if (textsize)
             {
                 paragraph = HeapAlloc(GetProcessHeap(), 0,
-                                      sizeof(HLPFILE_PARAGRAPH) + textsize);
+                                      sizeof(HLPFILE_PARAGRAPH) + textsize + 1);
                 if (!paragraph) return FALSE;
                 *paragraphptr = paragraph;
                 paragraphptr = &paragraph->next;
@@ -998,9 +1052,15 @@ static BOOL HLPFILE_BrowseParagraph(HLPFILE_PAGE* page, BYTE *buf, BYTE* end)
 
                 attributes.wVSpace = 0;
                 attributes.wHSpace = 0;
+                if (rd) /* FIXME: TEMP */ {
+                if (rd->force_color && !HLPFILE_RtfAddControl(rd, "{\\ul\\cf1 ")) goto done;
+                if (!HLPFILE_RtfAddText(rd, text)) goto done;
+                if (rd->force_color && !HLPFILE_RtfAddControl(rd, "}")) goto done;
+                rd->char_pos += textsize;
+                }
             }
             /* else: null text, keep on storing attributes */
-            text += textsize;
+            text += textsize + 1;
 
 	    if (*format == 0xff)
             {
@@ -1022,25 +1082,43 @@ static BOOL HLPFILE_BrowseParagraph(HLPFILE_PAGE* page, BYTE *buf, BYTE* end)
                 break;
 
 	    case 0x80:
-                attributes.wFont = GET_USHORT(format, 1);
-                WINE_TRACE("Changing font to %d\n", attributes.wFont);
-                format += 3;
-                break;
+                {
+                    unsigned    font = GET_USHORT(format, 1);
+                    attributes.wFont = font;
+                    WINE_TRACE("Changing font to %d\n", attributes.wFont);
+                    format += 3;
+                    /* FIXME: missing at least colors, also bold attribute looses information */
+                    sprintf(tmp, "\\f%d\\cf%d\\fs%d%s%s%s%s",
+                            font, font + 2,
+                            -2 * page->file->fonts[font].LogFont.lfHeight,
+                            page->file->fonts[font].LogFont.lfWeight > 400 ? "\\b" : "\\b0",
+                            page->file->fonts[font].LogFont.lfItalic ? "\\i" : "\\i0",
+                            page->file->fonts[font].LogFont.lfUnderline ? "\\ul" : "\\ul0",
+                            page->file->fonts[font].LogFont.lfStrikeOut ? "\\strike" : "\\strike0");
+                    if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;
+                }
+               break;
 
 	    case 0x81:
+                if (!HLPFILE_RtfAddControl(rd, "\\line")) goto done;
                 attributes.wVSpace++;
                 format += 1;
+                if (rd) /* FIXME: TEMP */ rd->char_pos++;
                 break;
 
 	    case 0x82:
+                if (!HLPFILE_RtfAddControl(rd, "\\par\\pard")) goto done;
                 attributes.wVSpace++;
                 attributes.wIndent = 0;
                 format += 1;
+                if (rd)  /* FIXME: TEMP */ rd->char_pos++;
                 break;
 
 	    case 0x83:
+                if (!HLPFILE_RtfAddControl(rd, "\\tab")) goto done;
                 attributes.wIndent++;
                 format += 1;
+                if (rd)  /* FIXME: TEMP */ rd->char_pos++;
                 break;
 
 #if 0
@@ -1206,20 +1284,74 @@ static BOOL HLPFILE_BrowseParagraph(HLPFILE_PAGE* page, BYTE *buf, BYTE* end)
 	    }
 	}
     }
+    ret = TRUE;
+done:
     HeapFree(GetProcessHeap(), 0, text_base);
-    return TRUE;
+    return ret;
 }
 
 /******************************************************************
  *		HLPFILE_BrowsePage
  *
  */
-BOOL    HLPFILE_BrowsePage(HLPFILE_PAGE* page)
+BOOL    HLPFILE_BrowsePage(HLPFILE_PAGE* page, struct RtfData* rd)
 {
     HLPFILE     *hlpfile = page->file;
     BYTE        *buf, *end;
     DWORD       ref = page->reference;
     unsigned    index, old_index = -1, offset, count = 0;
+    char        tmp[1024];
+
+    if (rd) { /* FIXME: TEMP */
+    rd->in_text = TRUE;
+    rd->data = rd->ptr = HeapAlloc(GetProcessHeap(), 0, rd->allocated = 32768);
+    rd->char_pos = 0;
+    rd->force_color = FALSE;
+    }
+
+    if (!HLPFILE_RtfAddControl(rd, "{\\rtf1\\ansi\\ansicpg1252\\deff0")) return FALSE;
+    /* generate font table */
+    if (!HLPFILE_RtfAddControl(rd, "{\\fonttbl")) return FALSE;
+    for (index = 0; index < hlpfile->numFonts; index++)
+    {
+        const char* family;
+        switch (hlpfile->fonts[index].LogFont.lfPitchAndFamily & 0xF0)
+        {
+        case FF_MODERN:     family = "modern";  break;
+        case FF_ROMAN:      family = "roman";   break;
+        case FF_SWISS:      family = "swiss";   break;
+        case FF_SCRIPT:     family = "script";  break;
+        case FF_DECORATIVE: family = "decor";   break;
+        default:            family = "nil";     break;
+        }
+        sprintf(tmp, "{\\f%d\\f%s\\fprq%d\\fcharset0 %s;}",
+                index, family,
+                hlpfile->fonts[index].LogFont.lfPitchAndFamily & 0x0F,
+                hlpfile->fonts[index].LogFont.lfFaceName);
+        if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE;
+    }
+    if (!HLPFILE_RtfAddControl(rd, "}")) return FALSE;
+    /* generate color table */
+    if (!HLPFILE_RtfAddControl(rd, "{\\colortbl ;\\red0\\green128\\blue0;")) return FALSE;
+    for (index = 0; index < hlpfile->numFonts; index++)
+    {
+        const char* family;
+        switch (hlpfile->fonts[index].LogFont.lfPitchAndFamily & 0xF0)
+        {
+        case FF_MODERN:     family = "modern";  break;
+        case FF_ROMAN:      family = "roman";   break;
+        case FF_SWISS:      family = "swiss";   break;
+        case FF_SCRIPT:     family = "script";  break;
+        case FF_DECORATIVE: family = "decor";   break;
+        default:            family = "nil";     break;
+        }
+        sprintf(tmp, "\\red%d\\green%d\\blue%d;",
+                GetRValue(hlpfile->fonts[index].color),
+                GetGValue(hlpfile->fonts[index].color),
+                GetBValue(hlpfile->fonts[index].color));
+        if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE;
+    }
+    if (!HLPFILE_RtfAddControl(rd, "}")) return FALSE;
 
     do
     {
@@ -1255,7 +1387,7 @@ BOOL    HLPFILE_BrowsePage(HLPFILE_PAGE* page)
         case 0x01:
         case 0x20:
         case 0x23:
-            if (!HLPFILE_BrowseParagraph(page, buf, end)) return FALSE;
+            if (!HLPFILE_BrowseParagraph(page, rd, buf, end)) return FALSE;
             break;
         default:
             WINE_ERR("buf[0x14] = %x\n", buf[0x14]);
@@ -1270,7 +1402,7 @@ BOOL    HLPFILE_BrowsePage(HLPFILE_PAGE* page)
             ref = GET_UINT(buf, 0xc);
     } while (ref != 0xffffffff);
 done:
-    return TRUE;
+    return HLPFILE_RtfAddControl(rd, "}");
 }
 
 /******************************************************************
diff --git a/programs/winhelp/hlpfile.h b/programs/winhelp/hlpfile.h
index 548a6e2..f4e72d7 100644
--- a/programs/winhelp/hlpfile.h
+++ b/programs/winhelp/hlpfile.h
@@ -199,4 +199,14 @@ void          HLPFILE_FreeHlpFile(HLPFILE*);
 void* HLPFILE_BPTreeSearch(BYTE*, const void*, HLPFILE_BPTreeCompare);
 void  HLPFILE_BPTreeEnum(BYTE*, HLPFILE_BPTreeCallback cb, void *cookie);
 
-BOOL          HLPFILE_BrowsePage(HLPFILE_PAGE*);
+struct RtfData {
+    BOOL        in_text;
+    char*       data;           /* RTF stream start */
+    char*       ptr;            /* current position in stream */
+    unsigned    allocated;      /* overall allocated size */
+    unsigned    char_pos;       /* current char position (in richedit) */
+    char*       where;          /* pointer to feed back richedit */
+    BOOL        force_color;
+};
+
+BOOL          HLPFILE_BrowsePage(HLPFILE_PAGE*, struct RtfData* rd);
diff --git a/programs/winhelp/winhelp.c b/programs/winhelp/winhelp.c
index 12ab516..ce57b6a 100644
--- a/programs/winhelp/winhelp.c
+++ b/programs/winhelp/winhelp.c
@@ -54,7 +54,7 @@ static void    WINHELP_InitFonts(HWND hWnd);
 static void    WINHELP_DeleteLines(WINHELP_WINDOW*);
 static void    WINHELP_DeleteWindow(WINHELP_WINDOW*);
 static void    WINHELP_DeleteButtons(WINHELP_WINDOW*);
-static void    WINHELP_SetupText(HWND hWnd, ULONG relative);
+static void    WINHELP_SetupText(HWND hWnd, WINHELP_WINDOW *win, ULONG relative);
 static WINHELP_LINE_PART* WINHELP_IsOverLink(WINHELP_WINDOW*, WPARAM, LPARAM);
 
 WINHELP_GLOBALS Globals = {3, NULL, TRUE, NULL, NULL, NULL, NULL, NULL, {{{NULL,NULL}},0}};
@@ -539,11 +539,12 @@ BOOL WINHELP_CreateHelpWindow(WINHELP_WNDPAGE* wpage, int nCmdShow, BOOL remembe
     BOOL                bPrimary, bPopup, bReUsed = FALSE;
     LPSTR               name;
     HICON               hIcon;
+    HWND                hTextWnd = NULL;
 
     bPrimary = !lstrcmpi(wpage->wininfo->name, "main");
     bPopup = !bPrimary && (wpage->wininfo->win_style & WS_POPUP);
 
-    if (wpage->page && !wpage->page->first_paragraph) HLPFILE_BrowsePage(wpage->page);
+    if (wpage->page && !wpage->page->first_paragraph) HLPFILE_BrowsePage(wpage->page, NULL);
 
     if (!bPopup)
     {
@@ -578,7 +579,8 @@ BOOL WINHELP_CreateHelpWindow(WINHELP_WNDPAGE* wpage, int nCmdShow, BOOL remembe
 
                 win->page = wpage->page;
                 win->info = wpage->wininfo;
-                WINHELP_SetupText(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), wpage->relative);
+                hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);
+                WINHELP_SetupText(hTextWnd, win, wpage->relative);
 
                 InvalidateRect(win->hMainWnd, NULL, TRUE);
                 if (win->hHistoryWnd) InvalidateRect(win->hHistoryWnd, NULL, TRUE);
@@ -652,12 +654,12 @@ BOOL WINHELP_CreateHelpWindow(WINHELP_WNDPAGE* wpage, int nCmdShow, BOOL remembe
                          0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_BUTTON, Globals.hInstance, NULL);
 
         if (!use_richedit)
-            CreateWindow(TEXT_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE,
-                         0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_TEXT, Globals.hInstance, win);
+            hTextWnd = CreateWindow(TEXT_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE,
+                                    0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_TEXT, Globals.hInstance, win);
         else
-            CreateWindow(RICHEDIT_CLASS, NULL,
-                         ES_MULTILINE | ES_READONLY | WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE,
-                         0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_TEXT, Globals.hInstance, NULL);
+            hTextWnd = CreateWindow(RICHEDIT_CLASS, NULL,
+                                    ES_MULTILINE | ES_READONLY | WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE,
+                                    0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_TEXT, Globals.hInstance, NULL);
     }
 
     hIcon = (wpage->page) ? wpage->page->file->hIcon : NULL;
@@ -678,7 +680,7 @@ BOOL WINHELP_CreateHelpWindow(WINHELP_WNDPAGE* wpage, int nCmdShow, BOOL remembe
     WINHELP_LayoutMainWindow(win);
 
     ShowWindow(win->hMainWnd, nCmdShow);
-    UpdateWindow(win->hMainWnd);
+    WINHELP_SetupText(hTextWnd, win, wpage->relative);
 
     return TRUE;
 }
@@ -827,6 +829,53 @@ static LRESULT CALLBACK WINHELP_MainWndProc(HWND hWnd, UINT msg, WPARAM wParam,
     return DefWindowProc(hWnd, msg, wParam, lParam);
 }
 
+static DWORD CALLBACK WINHELP_RtfStreamIn(DWORD_PTR cookie, BYTE* buff,
+                                          LONG cb, LONG* pcb)
+{
+    struct RtfData*     rd = (struct RtfData*)cookie;
+
+    if (rd->where >= rd->ptr) return 1;
+    if (rd->where + cb > rd->ptr)
+        cb = rd->ptr - rd->where;
+    memcpy(buff, rd->where, cb);
+    rd->where += cb;
+    *pcb = cb;
+    return 0;
+}
+
+static void WINHELP_FillRichEdit(HWND hTextWnd, WINHELP_WINDOW *win, ULONG relative)
+{
+    SendMessage(hTextWnd, WM_SETREDRAW, FALSE, 0);
+    SendMessage(hTextWnd, EM_SETBKGNDCOLOR, 0, (LPARAM)win->info->sr_color);
+    /* set word-wrap to window size (undocumented) */
+    SendMessage(hTextWnd, EM_SETTARGETDEVICE, 0, 0);
+    if (win->page)
+    {
+        struct RtfData  rd;
+        EDITSTREAM      es;
+
+        if (HLPFILE_BrowsePage(win->page, &rd))
+        {
+            rd.where = rd.data;
+            es.dwCookie = (DWORD_PTR)&rd;
+            es.dwError = 0;
+            es.pfnCallback = WINHELP_RtfStreamIn;
+
+            SendMessageW(hTextWnd, EM_STREAMIN, SF_RTF, (LPARAM)&es);
+        }
+        /* FIXME: else leaking potentially the rd.first_link chain */
+        HeapFree(GetProcessHeap(), 0, rd.data);
+    }
+    else
+    {
+        SendMessage(hTextWnd, WM_SETTEXT, 0, (LPARAM)"");
+    }
+    SendMessage(hTextWnd, WM_SETREDRAW, TRUE, 0);
+    SendMessage(hTextWnd, EM_SETSEL, 0, 0);
+    SendMessage(hTextWnd, EM_SCROLLCARET, 0, 0);
+    InvalidateRect(hTextWnd, NULL, TRUE);
+}
+
 /***********************************************************************
  *
  *           WINHELP_ButtonBoxWndProc
@@ -1014,7 +1063,7 @@ static LRESULT CALLBACK WINHELP_TextWndProc(HWND hWnd, UINT msg, WPARAM wParam,
     case WM_WINDOWPOSCHANGED:
         winpos = (WINDOWPOS*) lParam;
 
-        if (!(winpos->flags & SWP_NOSIZE)) WINHELP_SetupText(hWnd, 0);
+        if (!(winpos->flags & SWP_NOSIZE)) WINHELP_SetupText(hWnd, NULL, 0);
         break;
 
     case WM_MOUSEWHEEL:
@@ -1355,12 +1404,15 @@ static LRESULT CALLBACK WINHELP_ShadowWndProc(HWND hWnd, UINT msg, WPARAM wParam
  *
  *           SetupText
  */
-static void WINHELP_SetupText(HWND hWnd, ULONG relative)
+static void WINHELP_SetupText(HWND hWnd, WINHELP_WINDOW* win, ULONG relative)
 {
-    HDC  hDc = GetDC(hWnd);
+    HDC  hDc;
     RECT rect;
     SIZE newsize;
 
+    if (!win) win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
+    if (use_richedit) return WINHELP_FillRichEdit(hWnd, win, relative);
+    hDc = GetDC(hWnd);
     ShowScrollBar(hWnd, SB_VERT, FALSE);
     if (!WINHELP_SplitLines(hWnd, NULL))
     {





More information about the wine-patches mailing list