riched20: WM_SETFONT support

Matt Finnicum mattfinn at gmail.com
Sat Jun 24 20:16:41 CDT 2006


I was just about to send in the same patch when you did. I'll have to
keep you updated on what I'm working on in the future. (You can see
what I'm planning to do for my SoC project at
http://wiki.winehq.org/MatthewFinnicum)

I've attached the patch I was going to send - I suggest we use some
parts of each (either I can merge them into a patch or you can, your
call).

Our code is actually quite similar - though your
"ME_CharFormatFromLogFont" is definitely superior to mine (I just did
it all in function / was slightly less awesome).

Aside from my conformance tests (Which your patch passed just fine),
my patch covers some extra things:

1) You need to rewrap the paragraphs, since line lengths change.
2) Your code ignores lParam (which is supposed to specify if it
repaints immediately)
3) You need to invalidate the entire control - otherwise just the are
the text takes up will be redrawn - if the text shrinks, then the area
outside it's new size won't be blanked / you'll see fragments of the
old text.
4) Your code (I believe) will reset the scroll position - I store it
ahead of time and then restore it.

Thanks,
--Matt


On 6/24/06, Krzysztof Foltman <wdev at foltman.com> wrote:
> ChangeLog:
>   * WM_SETFONT implementation - sets the default font and the font for
> the whole pre-existing text
>
> Seems to fix bug 4563 and half of the bug 3917.
>
> Krzysztof
>
>
> diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c
> old mode 100644
> new mode 100755
> index 50527ca..61ecc72
> --- a/dlls/riched20/editor.c
> +++ b/dlls/riched20/editor.c
> @@ -92,7 +92,7 @@
>    - EM_SELECTIONTYPE
>    - EM_SETBIDIOPTIONS 3.0
>    + EM_SETBKGNDCOLOR
> -  - EM_SETCHARFORMAT (partly done, no ANSI)
> +  + EM_SETCHARFORMAT (partly done, no ANSI)
>    - EM_SETEDITSTYLE
>    + EM_SETEVENTMASK (few notifications supported)
>    - EM_SETFONTSIZE
> @@ -135,7 +135,7 @@
>    + WM_GETTEXT (ANSI&Unicode)
>    + WM_GETTEXTLENGTH (ANSI version sucks)
>    + WM_PASTE
> -  - WM_SETFONT
> +  + WM_SETFONT
>    + WM_SETTEXT (resets undo stack !) (proper style?) ANSI&Unicode
>    - WM_STYLECHANGING
>    - WM_STYLECHANGED (things like read-only flag)
> @@ -1442,7 +1442,6 @@ LRESULT WINAPI RichEditANSIWndProc(HWND
>    UNSUPPORTED_MSG(EM_SETTYPOGRAPHYOPTIONS)
>    UNSUPPORTED_MSG(EM_SETWORDBREAKPROCEX)
>    UNSUPPORTED_MSG(EM_SHOWSCROLLBAR)
> -  UNSUPPORTED_MSG(WM_SETFONT)
>    UNSUPPORTED_MSG(WM_STYLECHANGING)
>    UNSUPPORTED_MSG(WM_STYLECHANGED)
>  /*  UNSUPPORTED_MSG(WM_UNICHAR) FIXME missing in Wine headers */
> @@ -1844,6 +1843,27 @@ LRESULT WINAPI RichEditANSIWndProc(HWND
>
>      return 0;
>    }
> +  case WM_SETFONT:
> +  {
> +    LOGFONTW lf;
> +    CHARFORMAT2W fmt;
> +    HDC hDC;
> +    BOOL bRepaint = LOWORD(lParam);
> +
> +    if (!wParam)
> +      wParam = (WPARAM)GetStockObject(DEFAULT_GUI_FONT);
> +    GetObjectW((HGDIOBJ)wParam, sizeof(LOGFONTW), &lf);
> +    hDC = GetDC(hWnd);
> +    ME_CharFormatFromLogFont(hDC, &lf, &fmt);
> +    ReleaseDC(hWnd, hDC);
> +    ME_SetCharFormat(editor, 0, ME_GetTextLength(editor), &fmt);
> +    ME_SetDefaultCharFormat(editor, &fmt);
> +
> +    ME_CommitUndo(editor);
> +    if (bRepaint)
> +      ME_UpdateRepaint(editor);
> +    return 0;
> +  }
>    case WM_SETTEXT:
>    {
>      ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor));
> diff --git a/dlls/riched20/editor.h b/dlls/riched20/editor.h
> old mode 100644
> new mode 100755
> index 33b7626..a4d4980
> --- a/dlls/riched20/editor.h
> +++ b/dlls/riched20/editor.h
> @@ -55,6 +55,7 @@ void ME_CopyToCF2W(CHARFORMAT2W *to, CHA
>  CHARFORMAT2W *ME_ToCFAny(CHARFORMAT2W *to, CHARFORMAT2W *from);
>  void ME_CopyToCFAny(CHARFORMAT2W *to, CHARFORMAT2W *from);
>  void ME_CopyCharFormat(CHARFORMAT2W *pDest, CHARFORMAT2W *pSrc); /* only works with 2W structs */
> +void ME_CharFormatFromLogFont(HDC hDC, LOGFONTW *lf, CHARFORMAT2W *fmt); /* ditto */
>
>  /* list.c */
>  void ME_InsertBefore(ME_DisplayItem *diWhere, ME_DisplayItem *diWhat);
> diff --git a/dlls/riched20/style.c b/dlls/riched20/style.c
> old mode 100644
> new mode 100755
> index f420f09..6104a0c
> --- a/dlls/riched20/style.c
> +++ b/dlls/riched20/style.c
> @@ -286,6 +286,25 @@ ME_LogFontFromStyle(HDC hDC, LOGFONTW *l
>    lf->lfCharSet = s->fmt.bCharSet;
>  }
>
> +void ME_CharFormatFromLogFont(HDC hDC, LOGFONTW *lf, CHARFORMAT2W *fmt)
> +{
> +  int rx, ry;
> +
> +  ME_InitCharFormat2W(fmt);
> +  rx = GetDeviceCaps(hDC, LOGPIXELSX);
> +  ry = GetDeviceCaps(hDC, LOGPIXELSY);
> +  lstrcpyW(fmt->szFaceName, lf->lfFaceName);
> +  fmt->dwEffects = 0;
> +  fmt->dwMask = CFM_WEIGHT|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT|CFM_SIZE|CFM_FACE|CFM_CHARSET;
> +  fmt->wWeight = lf->lfWeight;
> +  fmt->yHeight = -lf->lfHeight*1440/ry;
> +  if (lf->lfWeight>400) fmt->dwEffects |= CFM_BOLD;
> +  if (lf->lfItalic) fmt->dwEffects |= CFM_ITALIC;
> +  if (lf->lfUnderline) fmt->dwEffects |= CFM_UNDERLINE;
> +  if (lf->lfStrikeOut) fmt->dwEffects |= CFM_STRIKEOUT;
> +  fmt->bPitchAndFamily = lf->lfPitchAndFamily;
> +  fmt->bCharSet = lf->lfCharSet;
> +}
>
>  BOOL ME_IsFontEqual(LOGFONTW *p1, LOGFONTW *p2)
>  {
>
>
>
>
>
>
-------------- next part --------------
From 9ab4884c58a4de506ca43c761b1d55769dfc0614 Mon Sep 17 00:00:00 2001
From: Matthew Finnicum <MattFinn at gmail.com>
Date: Sat, 24 Jun 2006 16:27:11 -0400
Subject: [PATCH] riched20: Implement WM_SETFONT and its conformance tests
---
 dlls/riched20/editor.c       |   75 ++++++++++++++++++++++++++++++++++++++++--
 dlls/riched20/tests/editor.c |   64 ++++++++++++++++++++++++++++++++++++
 2 files changed, 136 insertions(+), 3 deletions(-)

diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c
index 21f951e..467e4d3 100644
--- a/dlls/riched20/editor.c
+++ b/dlls/riched20/editor.c
@@ -132,10 +132,11 @@
   + WM_COPY
   + WM_CUT
   + WM_GETDLGCODE (the current implementation is incomplete)
+  + WM_GETFONT
   + WM_GETTEXT (ANSI&Unicode)
   + WM_GETTEXTLENGTH (ANSI version sucks)
   + WM_PASTE
-  - WM_SETFONT
+  + WM_SETFONT
   + WM_SETTEXT (resets undo stack !) (proper style?) ANSI&Unicode
   - WM_STYLECHANGING
   - WM_STYLECHANGED (things like read-only flag)
@@ -1381,7 +1382,7 @@ static const char * const richedit_messa
 static const char *
 get_msg_name(UINT msg)
 {
-  if (msg >= EM_GETSEL && msg <= EM_SETLIMITTEXT)
+  if (msg >= EM_GETSEL && msg <= EM_CHARFROMPOS)
     return edit_messages[msg - EM_GETSEL];
   if (msg >= EM_CANPASTE && msg <= EM_GETIMEMODEBIAS)
     return richedit_messages[msg - EM_CANPASTE];
@@ -1434,7 +1435,6 @@ LRESULT WINAPI RichEditANSIWndProc(HWND 
   UNSUPPORTED_MSG(EM_SETTYPOGRAPHYOPTIONS)
   UNSUPPORTED_MSG(EM_SETWORDBREAKPROCEX)
   UNSUPPORTED_MSG(EM_SHOWSCROLLBAR)
-  UNSUPPORTED_MSG(WM_SETFONT)
   UNSUPPORTED_MSG(WM_STYLECHANGING)
   UNSUPPORTED_MSG(WM_STYLECHANGED)
 /*  UNSUPPORTED_MSG(WM_UNICHAR) FIXME missing in Wine headers */
@@ -1836,6 +1836,75 @@ LRESULT WINAPI RichEditANSIWndProc(HWND 
 
     return 0;
   }
+  case WM_SETFONT:
+  {
+    /* wParam - Handle to the font. If this parameter is NULL, 
+        the control uses the default system font to draw text. 
+     * lParam - The low-order word of lParam specifies whether the control
+        should be redrawn immediately upon setting the font. 
+     * Expected Behaviour (documentation is lacking):
+     * 1 - Change the default font for the control
+     * 2 - Change all text currently in the control to the new font
+     * 3 - After SETFONT, text pasted in the old font will remain that font.
+     * 4 - Do not unselect / alter cursor location.
+     * 5 - Keep current scroll position
+     * 6 - Even if lParam is false, a repaint should be queued.
+     */
+    
+    CHARFORMAT2W p;
+    LOGFONTW lf;
+    HDC hdc;
+    int prevScrollPosY;
+    
+    ZeroMemory(&p,sizeof(p));
+    p.cbSize = sizeof(CHARFORMAT2W);
+    
+    if ((HFONT *)wParam == NULL)
+      wParam = (WPARAM)GetStockObject(SYSTEM_FONT);
+    
+    hdc = GetDC(editor->hWnd);
+    
+    /* Create a LOGFONT from the passed in HFONT */
+    GetObjectW((HFONT*)wParam,sizeof(LOGFONTW),&lf);
+    
+    /* We use the old default format, then only modify its font */
+    ME_GetDefaultCharFormat(editor, &p);
+    
+    p.bCharSet = lf.lfCharSet;
+    p.bPitchAndFamily = lf.lfPitchAndFamily;
+    p.wWeight = lf.lfWeight;
+    p.yHeight = -MulDiv(lf.lfHeight, 1440, GetDeviceCaps(hdc, LOGPIXELSY));
+    CopyMemory(p.szFaceName,lf.lfFaceName,sizeof(lf.lfFaceName));
+    
+    /* The scrollbar gets reset, so we need to move it back when we're done. */
+    prevScrollPosY = editor->nScrollPosY;  
+    
+    ME_SetCharFormat(editor, 0, ME_GetTextLength(editor), &p);
+    ME_SetDefaultCharFormat(editor, &p);
+
+    /* A bigger font means we might need to rewrap */
+    ME_MarkAllForWrapping(editor);
+    ME_WrapMarkedParagraphs(editor);
+    
+    editor->nScrollPosY = prevScrollPosY;
+    SetScrollPos(hWnd, SB_VERT, editor->nScrollPosY, TRUE);
+    ME_UpdateScrollBar(editor);
+    
+     /* InvalidateRect causes a WM_PAINT message to be added to the queue */
+    InvalidateRect(editor->hWnd, NULL, TRUE);
+    
+    /* This is an immediate repaint. It dosn't wait for the queue to be procesed*/
+    if (LOWORD(lParam)) 
+      ME_Repaint(editor);
+    
+    ME_CommitUndo(editor);
+    
+    return 0;
+  }
+  case WM_GETFONT:
+  {  
+    return (LRESULT)editor->pBuffer->pDefaultStyle->hFont;    
+  }
   case WM_SETTEXT:
   {
     ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor));
diff --git a/dlls/riched20/tests/editor.c b/dlls/riched20/tests/editor.c
index c71ca7f..d4c3640 100644
--- a/dlls/riched20/tests/editor.c
+++ b/dlls/riched20/tests/editor.c
@@ -811,6 +811,69 @@ static void test_EM_SETUNDOLIMIT()
   DestroyWindow(hwndRichEdit);
 }
 
+static void test_WM_SETFONT()
+{
+  /* There is no invalid input or error conditions for this function.
+   * NULL wParam and lParam just fall back to their default values 
+   * It should be noted that even if you use a gibberish name for your fonts
+   * here, it will still work because the name is stored. They will display as
+   * System, but will report their name to be whatever they were created as */
+  
+  HWND hwndRichEdit = new_richedit(NULL);
+  HFONT testFont1 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET, 
+    OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | 
+    FF_DONTCARE, "Marlett");
+  HFONT testFont2 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET, 
+    OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | 
+    FF_DONTCARE, "MS Sans Serif");
+  HFONT testFont3 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET, 
+    OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | 
+    FF_DONTCARE, "Courier");
+  LOGFONTA sentLogFont;
+  CHARFORMAT2A returnedCF2A;
+  
+  returnedCF2A.cbSize = sizeof(returnedCF2A);
+  
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "x");
+  SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont1,(LPARAM) MAKELONG((WORD) TRUE, 0));
+  SendMessage(hwndRichEdit, EM_GETCHARFORMAT,   SCF_DEFAULT,  (LPARAM) &returnedCF2A);
+
+  GetObjectA(testFont1, sizeof(LOGFONTA), &sentLogFont);
+  ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
+    "EM_GETCHARFOMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n",
+    sentLogFont.lfFaceName,returnedCF2A.szFaceName);
+    
+  //ok (0,"Test 1 Sent: %s Recieved: %s",sentLogFont.bPitchAndFamily,lfPitchAndFamily);
+  
+  SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont2,(LPARAM) MAKELONG((WORD) TRUE, 0));
+  SendMessage(hwndRichEdit, EM_GETCHARFORMAT,   SCF_DEFAULT,  (LPARAM) &returnedCF2A);
+  GetObjectA(testFont2, sizeof(LOGFONTA), &sentLogFont);
+  ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
+    "EM_GETCHARFOMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n",
+    sentLogFont.lfFaceName,returnedCF2A.szFaceName);
+    
+  SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont3,(LPARAM) MAKELONG((WORD) TRUE, 0));
+  SendMessage(hwndRichEdit, EM_GETCHARFORMAT,   SCF_DEFAULT,  (LPARAM) &returnedCF2A);
+  GetObjectA(testFont3, sizeof(LOGFONTA), &sentLogFont);
+  ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
+    "EM_GETCHARFOMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n",
+    sentLogFont.lfFaceName,returnedCF2A.szFaceName);
+    
+  /* This last test is special since we send in NULL. We clear the variables
+   * and just compare to "System" instead of the sent in font name. */
+  ZeroMemory(&returnedCF2A,sizeof(returnedCF2A));
+  ZeroMemory(&sentLogFont,sizeof(sentLogFont));
+  returnedCF2A.cbSize = sizeof(returnedCF2A);
+  
+  SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)NULL,(LPARAM) MAKELONG((WORD) TRUE, 0));
+  SendMessage(hwndRichEdit, EM_GETCHARFORMAT,   SCF_DEFAULT,  (LPARAM) &returnedCF2A);
+  GetObjectA(NULL, sizeof(LOGFONTA), &sentLogFont);
+  ok (!strcmp("System",returnedCF2A.szFaceName),
+    "EM_GETCHARFOMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A.szFaceName);
+  
+  DestroyWindow(hwndRichEdit);
+}
+
 
 START_TEST( editor )
 {
@@ -830,6 +893,7 @@ START_TEST( editor )
   test_WM_GETTEXT();
   test_EM_AUTOURLDETECT();
   test_EM_SETUNDOLIMIT();
+  test_WM_SETFONT();
 
   /* Set the environment variable WINETEST_RICHED20 to keep windows
    * responsive and open for 30 seconds. This is useful for debugging.
-- 
1.4.0



More information about the wine-devel mailing list