[PATCH 13/45] [WinHelp]: starting feeding the richedit control with an RTF stream out of the HELP page
Eric Pouech
eric.pouech at orange.fr
Sun Mar 23 04:18:31 CDT 2008
A+
---
programs/winhelp/hlpfile.c | 130 ++++++++++++++++++++++++++++++++++++++++++--
programs/winhelp/hlpfile.h | 12 ++++
programs/winhelp/winhelp.c | 59 ++++++++++++++++++--
3 files changed, 189 insertions(+), 12 deletions(-)
diff --git a/programs/winhelp/hlpfile.c b/programs/winhelp/hlpfile.c
index 3c7ee7b..49eaba4 100644
--- a/programs/winhelp/hlpfile.c
+++ b/programs/winhelp/hlpfile.c
@@ -582,6 +582,55 @@ 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->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 (*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->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);
+}
+
#if 0
/******************************************************************
* HLPFILE_LoadBitmap
@@ -832,7 +881,7 @@ static BOOL HLPFILE_SkipParagraph(HLPFILE *hlpfile, BYTE *buf, BYTE *end, unsign
*
* HLPFILE_BrowseParagraph
*/
-BOOL HLPFILE_BrowseParagraph(HLPFILE *hlpfile, BYTE *buf, BYTE *end)
+BOOL HLPFILE_BrowseParagraph(HLPFILE *hlpfile, struct RtfData* rd, BYTE *buf, BYTE *end)
{
UINT textsize;
BYTE *format, *format_end;
@@ -840,6 +889,7 @@ BOOL HLPFILE_BrowseParagraph(HLPFILE *hlpfile, BYTE *buf, BYTE *end)
long size, blocksize, datalen;
unsigned short bits;
unsigned nc, ncol = 1;
+ char tmp[256];
BOOL ret = FALSE;
if (buf + 0x19 > end) {WINE_WARN("header too small\n"); return FALSE;};
@@ -926,6 +976,10 @@ BOOL HLPFILE_BrowseParagraph(HLPFILE *hlpfile, BYTE *buf, BYTE *end)
textsize = strlen(text);
if (textsize)
{
+ 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 + 1;
@@ -952,21 +1006,36 @@ BOOL HLPFILE_BrowseParagraph(HLPFILE *hlpfile, BYTE *buf, BYTE *end)
case 0x80:
{
unsigned font = GET_USHORT(format, 1);
+ /* 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 * hlpfile->fonts[font].LogFont.lfHeight,
+ hlpfile->fonts[font].LogFont.lfWeight > 400 ? "\\b" : "\\b0",
+ hlpfile->fonts[font].LogFont.lfItalic ? "\\i" : "\\i0",
+ hlpfile->fonts[font].LogFont.lfUnderline ? "\\ul" : "\\ul0",
+ hlpfile->fonts[font].LogFont.lfStrikeOut ? "\\strike" : "\\strike0");
+ if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;
WINE_TRACE("Changing font to %u\n", font);
format += 3;
}
break;
case 0x81:
+ if (!HLPFILE_RtfAddControl(rd, "\\line")) goto done;
format += 1;
+ rd->char_pos++;
break;
case 0x82:
+ if (!HLPFILE_RtfAddControl(rd, "\\par\\pard")) goto done;
format += 1;
+ rd->char_pos++;
break;
case 0x83:
+ if (!HLPFILE_RtfAddControl(rd, "\\tab")) goto done;
format += 1;
+ rd->char_pos++;
break;
#if 0
@@ -1097,16 +1166,67 @@ BOOL HLPFILE_BrowseParagraph(HLPFILE *hlpfile, BYTE *buf, BYTE *end)
}
}
ret = TRUE;
+done:
HeapFree(GetProcessHeap(), 0, text_base);
return ret;
}
-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;
+ unsigned index, offset, old_index = -1, count = 0;
+ char tmp[1024];
+
+ 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
{
@@ -1141,7 +1261,7 @@ BOOL HLPFILE_BrowsePage(HLPFILE_PAGE* page)
break;
case 0x20:
case 0x23:
- if (!HLPFILE_BrowseParagraph(hlpfile, buf, end)) return FALSE;
+ if (!HLPFILE_BrowseParagraph(hlpfile, rd, buf, end)) return FALSE;
break;
default:
@@ -1157,7 +1277,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 75e6f7b..b50664b 100644
--- a/programs/winhelp/hlpfile.h
+++ b/programs/winhelp/hlpfile.h
@@ -150,4 +150,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 b4ae6a1..f864abb 100644
--- a/programs/winhelp/winhelp.c
+++ b/programs/winhelp/winhelp.c
@@ -49,6 +49,7 @@ static LRESULT CALLBACK WINHELP_HistoryWndProc(HWND, UINT, WPARAM, LPARAM);
static LRESULT CALLBACK WINHELP_ShadowWndProc(HWND, UINT, WPARAM, LPARAM);
static void WINHELP_CheckPopup(UINT);
static void WINHELP_DeleteWindow(WINHELP_WINDOW*);
+static void WINHELP_FillRichEdit(HWND hText, WINHELP_WINDOW *win);
WINHELP_GLOBALS Globals = {3, NULL, NULL, TRUE, NULL, NULL, NULL, NULL};
@@ -461,8 +462,8 @@ static BOOL WINHELP_ReuseWindow(WINHELP_WINDOW* win, WINHELP_WINDOW* oldwin,
hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);
InvalidateRect(hTextWnd, NULL, TRUE);
WINHELP_LayoutMainWindow(win);
+ WINHELP_FillRichEdit(hTextWnd, win);
ShowWindow(win->hMainWnd, nCmdShow);
- UpdateWindow(hTextWnd);
if (!(win->info->win_style & WS_POPUP))
{
@@ -530,7 +531,7 @@ BOOL WINHELP_CreateHelpWindow(HLPFILE_PAGE* page, HLPFILE_WINDOWINFO* wi,
int nCmdShow)
{
WINHELP_WINDOW *win, *oldwin;
- HWND hWnd;
+ HWND hWnd, hTextWnd;
BOOL bPrimary;
BOOL bPopup;
LPSTR name;
@@ -553,7 +554,7 @@ BOOL WINHELP_CreateHelpWindow(HLPFILE_PAGE* page, HLPFILE_WINDOWINFO* wi,
win->page = page;
- win->hHandCur = LoadCursorA(0, (LPSTR)IDC_HAND);
+ win->hHandCur = LoadCursorW(0, (LPWSTR)IDC_HAND);
win->info = wi;
@@ -619,13 +620,16 @@ BOOL WINHELP_CreateHelpWindow(HLPFILE_PAGE* page, HLPFILE_WINDOWINFO* wi,
CreateWindow(BUTTON_BOX_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE,
0, 0, 0, 0, hWnd, (HMENU)CTL_ID_BUTTON, Globals.hInstance, NULL);
- CreateWindow(RICHEDIT_CLASS, NULL,
- ES_MULTILINE | ES_READONLY | WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE,
- 0, 0, 0, 0, hWnd, (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, hWnd, (HMENU)CTL_ID_TEXT, Globals.hInstance, NULL);
+ SendMessage(hTextWnd, EM_SETEVENTMASK, 0,
+ SendMessage(hTextWnd, EM_GETEVENTMASK, 0, 0) | ENM_MOUSEEVENTS);
WINHELP_LayoutMainWindow(win);
if (bPopup) Globals.hPopupWnd = hWnd;
+ if (bPopup) WINHELP_FillRichEdit(hWnd, win);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
@@ -767,6 +771,49 @@ 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)
+{
+ 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);
+ }
+ SendMessage(hTextWnd, WM_SETREDRAW, TRUE, 0);
+ SendMessage(hTextWnd, EM_SETSEL, 0, 0);
+ SendMessage(hTextWnd, EM_SCROLLCARET, 0, 0);
+ InvalidateRect(hTextWnd, NULL, TRUE);
+}
+
/***********************************************************************
*
* WINHELP_ButtonBoxWndProc
More information about the wine-patches
mailing list