[COMCTL32] Sync with Wine Staging 1.7.55. CORE-10536
[reactos.git] / reactos / dll / win32 / comctl32 / syslink.c
index 9340fc6..1c7039c 100644 (file)
  * If you discover missing features, or bugs, please note them below.
  */
 
-#include <stdarg.h>
-#include <string.h>
-#include "windef.h"
-#include "winbase.h"
-#include "wingdi.h"
-#include "winuser.h"
-#include "winnls.h"
-#include "commctrl.h"
 #include "comctl32.h"
-#include "wine/unicode.h"
-#include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(syslink);
 
@@ -94,7 +84,6 @@ typedef struct
     COLORREF  TextColor;    /* Color of the text */
     COLORREF  LinkColor;    /* Color of links */
     COLORREF  VisitedColor; /* Color of visited links */
-    COLORREF  BackColor;    /* Background color, set on creation */
     WCHAR     BreakChar;    /* Break Character for the current font */
     BOOL      IgnoreReturn; /* (infoPtr->Style & LWS_IGNORERETURN) on creation */
 } SYSLINK_INFO;
@@ -184,6 +173,26 @@ static VOID SYSLINK_ClearDoc (SYSLINK_INFO *infoPtr)
     infoPtr->Items = NULL;
 }
 
+/***********************************************************************
+ * SYSLINK_StrCmpNIW
+ * Wrapper for StrCmpNIW to ensure 'len' is not too big.
+ */
+static INT SYSLINK_StrCmpNIW (LPCWSTR str, LPCWSTR comp, INT len)
+{
+    INT i;
+
+    for(i = 0; i < len; i++)
+    {
+        if(!str[i])
+        {
+            len = i + 1;
+            break;
+        }
+    }
+
+    return StrCmpNIW(str, comp, len);
+}
+
 /***********************************************************************
  * SYSLINK_ParseText
  * Parses the window text string and creates a document. Returns the
@@ -204,7 +213,7 @@ static UINT SYSLINK_ParseText (SYSLINK_INFO *infoPtr, LPCWSTR Text)
     {
         if(*current == '<')
         {
-            if(!StrCmpNIW(current, SL_LINKOPEN, 2) && (CurrentType == slText))
+            if(!SYSLINK_StrCmpNIW(current, SL_LINKOPEN, 2) && (CurrentType == slText))
             {
                 BOOL ValidParam = FALSE, ValidLink = FALSE;
 
@@ -232,14 +241,14 @@ static UINT SYSLINK_ParseText (SYSLINK_INFO *infoPtr, LPCWSTR Text)
                     
 CheckParameter:
                     /* compare the current position with all known parameters */
-                    if(!StrCmpNIW(tmp, SL_HREF, 6))
+                    if(!SYSLINK_StrCmpNIW(tmp, SL_HREF, 6))
                     {
                         taglen += 6;
                         ValidParam = TRUE;
                         CurrentParameter = &lpUrl;
                         CurrentParameterLen = &lenUrl;
                     }
-                    else if(!StrCmpNIW(tmp, SL_ID, 4))
+                    else if(!SYSLINK_StrCmpNIW(tmp, SL_ID, 4))
                     {
                         taglen += 4;
                         ValidParam = TRUE;
@@ -313,7 +322,7 @@ CheckParameter:
                     }
                 }
             }
-            else if(!StrCmpNIW(current, SL_LINKCLOSE, 4) && (CurrentType == slLink) && firsttag)
+            else if(!SYSLINK_StrCmpNIW(current, SL_LINKCLOSE, 4) && (CurrentType == slLink) && firsttag)
             {
                 /* there's a <a...> tag opened, first add the previous text, if present */
                 if(textstart != NULL && textlen > 0 && firsttag > textstart)
@@ -529,7 +538,7 @@ static PDOC_ITEM SYSLINK_GetFocusLink (const SYSLINK_INFO *infoPtr, int *LinkId)
 
     while(Current != NULL)
     {
-        if((Current->Type == slLink))
+        if(Current->Type == slLink)
         {
             if(Current->u.Link.state & LIS_FOCUSED)
             {
@@ -606,38 +615,29 @@ static PDOC_ITEM SYSLINK_GetPrevLink (const SYSLINK_INFO *infoPtr, PDOC_ITEM Cur
  * SYSLINK_WrapLine
  * Tries to wrap a line.
  */
-static BOOL SYSLINK_WrapLine (LPWSTR Text, WCHAR BreakChar, int *LineLen,
+static BOOL SYSLINK_WrapLine (LPWSTR Text, WCHAR BreakChar, int x, int *LineLen,
                              int nFit, LPSIZE Extent)
 {
-    WCHAR *Current;
+    int i;
 
-    if(nFit == *LineLen)
-    {
-        return FALSE;
-    }
+    for (i = 0; i < nFit; i++) if (Text[i] == '\n') break;
 
-    *LineLen = nFit;
+    if (i == *LineLen) return FALSE;
 
-    Current = Text + nFit;
-    
     /* check if we're in the middle of a word */
-    if((*Current) != BreakChar)
+    if (Text[i] != '\n' && Text[i] != BreakChar)
     {
         /* search for the beginning of the word */
-        while(Current > Text && (*(Current - 1)) != BreakChar)
-        {
-            Current--;
-            (*LineLen)--;
-        }
-        
-        if((*LineLen) == 0)
+        while (i && Text[i - 1] != BreakChar) i--;
+
+        if (i == 0)
         {
             Extent->cx = 0;
             Extent->cy = 0;
+            if (x == SL_LEFTMARGIN) i = max( nFit, 1 );
         }
-        return TRUE;
     }
-
+    *LineLen = i;
     return TRUE;
 }
 
@@ -652,6 +652,7 @@ static VOID SYSLINK_Render (const SYSLINK_INFO *infoPtr, HDC hdc, PRECT pRect)
     HGDIOBJ hOldFont;
     int x, y, LineHeight;
     SIZE szDoc;
+    TEXTMETRICW tm;
 
     szDoc.cx = szDoc.cy = 0;
 
@@ -668,8 +669,9 @@ static VOID SYSLINK_Render (const SYSLINK_INFO *infoPtr, HDC hdc, PRECT pRect)
     
     x = SL_LEFTMARGIN;
     y = SL_TOPMARGIN;
-    LineHeight = 0;
-    
+    GetTextMetricsW( hdc, &tm );
+    LineHeight = tm.tmHeight + tm.tmExternalLeading;
+
     for(Current = infoPtr->Items; Current != NULL; Current = Current->Next)
     {
         int n, nBlocks;
@@ -677,6 +679,7 @@ static VOID SYSLINK_Render (const SYSLINK_INFO *infoPtr, HDC hdc, PRECT pRect)
         PDOC_TEXTBLOCK bl, cbl;
         INT nFit;
         SIZE szDim;
+        int SkipChars = 0;
 
         if(Current->nText == 0)
         {
@@ -702,11 +705,15 @@ static VOID SYSLINK_Render (const SYSLINK_INFO *infoPtr, HDC hdc, PRECT pRect)
         
         while(n > 0)
         {
-            int SkipChars = 0;
-
             /* skip break characters unless they're the first of the doc item */
             if(tx != Current->Text || x == SL_LEFTMARGIN)
             {
+                if (n && *tx == '\n')
+                {
+                    tx++;
+                    SkipChars++;
+                    n--;
+                }
                 while(n > 0 && (*tx) == infoPtr->BreakChar)
                 {
                     tx++;
@@ -724,24 +731,14 @@ static VOID SYSLINK_Render (const SYSLINK_INFO *infoPtr, HDC hdc, PRECT pRect)
                 
                 if(n != 0)
                 {
-                    Wrap = SYSLINK_WrapLine(tx, infoPtr->BreakChar, &LineLen, nFit, &szDim);
+                    Wrap = SYSLINK_WrapLine(tx, infoPtr->BreakChar, x, &LineLen, nFit, &szDim);
 
                     if(LineLen == 0)
                     {
-                        if(x > SL_LEFTMARGIN)
-                        {
-                            /* move one line down, the word didn't fit into the line */
-                            x = SL_LEFTMARGIN;
-                            y += LineHeight;
-                            LineHeight = 0;
-                            continue;
-                        }
-                        else
-                        {
-                            /* the word starts at the beginning of the line and doesn't
-                               fit into the line, so break it at the last character that fits */
-                            LineLen = max(nFit, 1);
-                        }
+                        /* move one line down, the word didn't fit into the line */
+                        x = SL_LEFTMARGIN;
+                        y += LineHeight;
+                        continue;
                     }
 
                     if(LineLen != n)
@@ -782,13 +779,10 @@ static VOID SYSLINK_Render (const SYSLINK_INFO *infoPtr, HDC hdc, PRECT pRect)
                     if(LineLen != 0)
                     {
                         x += szDim.cx;
-                        LineHeight = max(LineHeight, szDim.cy);
-
                         if(Wrap)
                         {
                             x = SL_LEFTMARGIN;
                             y += LineHeight;
-                            LineHeight = 0;
                         }
                     }
                 }
@@ -803,6 +797,7 @@ static VOID SYSLINK_Render (const SYSLINK_INFO *infoPtr, HDC hdc, PRECT pRect)
                 }
                 n -= LineLen;
                 tx += LineLen;
+                SkipChars = 0;
             }
             else
             {
@@ -832,17 +827,31 @@ static LRESULT SYSLINK_Draw (const SYSLINK_INFO *infoPtr, HDC hdc)
     PDOC_ITEM Current;
     HFONT hOldFont;
     COLORREF OldTextColor, OldBkColor;
+    HBRUSH hBrush;
+    UINT text_flags = ETO_CLIPPED;
+    UINT mode = GetBkMode( hdc );
 
     hOldFont = SelectObject(hdc, infoPtr->Font);
     OldTextColor = SetTextColor(hdc, infoPtr->TextColor);
-    OldBkColor = SetBkColor(hdc, infoPtr->BackColor);
-    
+    OldBkColor = SetBkColor(hdc, comctl32_color.clrWindow);
+
     GetClientRect(infoPtr->Self, &rc);
     rc.right -= SL_RIGHTMARGIN + SL_LEFTMARGIN;
     rc.bottom -= SL_BOTTOMMARGIN + SL_TOPMARGIN;
 
     if(rc.right < 0 || rc.bottom < 0) return 0;
 
+    hBrush = (HBRUSH)SendMessageW(infoPtr->Notify, WM_CTLCOLORSTATIC,
+                                  (WPARAM)hdc, (LPARAM)infoPtr->Self);
+    if (!(infoPtr->Style & LWS_TRANSPARENT))
+    {
+        FillRect(hdc, &rc, hBrush);
+        if (GetBkMode( hdc ) == OPAQUE) text_flags |= ETO_OPAQUE;
+    }
+    else SetBkMode( hdc, TRANSPARENT );
+
+    DeleteObject(hBrush);
+
     for(Current = infoPtr->Items; Current != NULL; Current = Current->Next)
     {
         int n;
@@ -869,7 +878,7 @@ static LRESULT SYSLINK_Draw (const SYSLINK_INFO *infoPtr, HDC hdc)
             while(n > 0)
             {
                 tx += bl->nSkip;
-                ExtTextOutW(hdc, bl->rc.left, bl->rc.top, ETO_OPAQUE | ETO_CLIPPED, &bl->rc, tx, bl->nChars, NULL);
+                ExtTextOutW(hdc, bl->rc.left, bl->rc.top, text_flags, &bl->rc, tx, bl->nChars, NULL);
                 if((Current->Type == slLink) && (Current->u.Link.state & LIS_FOCUSED) && infoPtr->HasFocus)
                 {
                     COLORREF PrevTextColor;
@@ -887,7 +896,7 @@ static LRESULT SYSLINK_Draw (const SYSLINK_INFO *infoPtr, HDC hdc)
     SetBkColor(hdc, OldBkColor);
     SetTextColor(hdc, OldTextColor);
     SelectObject(hdc, hOldFont);
-    
+    SetBkMode(hdc, mode);
     return 0;
 }
 
@@ -910,23 +919,6 @@ static LRESULT SYSLINK_Paint (const SYSLINK_INFO *infoPtr, HDC hdcParam)
     return 0;
 }
 
-/***********************************************************************
- * SYSLINK_EraseBkgnd
- * Handles the WM_ERASEBKGND message.
- */
-static LRESULT SYSLINK_EraseBkgnd (const SYSLINK_INFO *infoPtr, HDC hdc)
-{
-   HBRUSH hbr;
-   RECT r;
-
-   GetClientRect(infoPtr->Self, &r);
-   hbr = CreateSolidBrush(infoPtr->BackColor);
-   FillRect(hdc, &r, hbr);
-   DeleteObject(hbr);
-
-   return 1;
-}
-
 /***********************************************************************
  *           SYSLINK_SetFont
  * Set new Font for the SysLink control.
@@ -1385,7 +1377,7 @@ static PDOC_ITEM SYSLINK_LinkAtPt (const SYSLINK_INFO *infoPtr, const POINT *pt,
     for(Current = infoPtr->Items; Current != NULL; Current = Current->Next)
     {
         if((Current->Type == slLink) && SYSLINK_PtInDocItem(Current, *pt) &&
-           (!MustBeEnabled || (MustBeEnabled && (Current->u.Link.state & LIS_ENABLED))))
+           (!MustBeEnabled || (Current->u.Link.state & LIS_ENABLED)))
         {
             if(LinkId != NULL)
             {
@@ -1564,7 +1556,7 @@ static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message,
     infoPtr = (SYSLINK_INFO *)GetWindowLongPtrW(hwnd, 0);
 
     if (!infoPtr && message != WM_CREATE)
-        goto HandleDefaultMessage;
+        return DefWindowProcW(hwnd, message, wParam, lParam);
 
     switch(message) {
     case WM_PRINTCLIENT:
@@ -1572,7 +1564,18 @@ static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message,
         return SYSLINK_Paint (infoPtr, (HDC)wParam);
 
     case WM_ERASEBKGND:
-        return SYSLINK_EraseBkgnd(infoPtr, (HDC)wParam);
+        if (!(infoPtr->Style & LWS_TRANSPARENT))
+        {
+            HDC hdc = (HDC)wParam;
+            HBRUSH brush = CreateSolidBrush( comctl32_color.clrWindow );
+            RECT rect;
+
+            GetClipBox( hdc, &rect );
+            FillRect( hdc, &rect, brush );
+            DeleteObject( brush );
+            return 1;
+        }
+        return 0;
 
     case WM_SETCURSOR:
     {
@@ -1588,8 +1591,8 @@ static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message,
             SetCursor(LoadCursorW(0, (LPCWSTR)IDC_HAND));
             return TRUE;
         }
-        /* let the default window proc handle this message */
-        goto HandleDefaultMessage;
+
+        return DefWindowProcW(hwnd, message, wParam, lParam);
     }
 
     case WM_SIZE:
@@ -1615,7 +1618,7 @@ static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message,
 
     case WM_SETTEXT:
         SYSLINK_SetText(infoPtr, (LPWSTR)lParam);
-        goto HandleDefaultMessage;
+        return DefWindowProcW(hwnd, message, wParam, lParam);
 
     case WM_LBUTTONDOWN:
     {
@@ -1645,8 +1648,9 @@ static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message,
             SYSKEY_SelectNextPrevLink(infoPtr, shift);
             return 0;
         }
+        default:
+            return DefWindowProcW(hwnd, message, wParam, lParam);
         }
-        goto HandleDefaultMessage;
     }
     
     case WM_GETDLGCODE:
@@ -1753,8 +1757,6 @@ static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message,
         infoPtr->TextColor = comctl32_color.clrWindowText;
         infoPtr->LinkColor = comctl32_color.clrHighlight;
         infoPtr->VisitedColor = comctl32_color.clrHighlight;
-        infoPtr->BackColor = infoPtr->Style & LWS_TRANSPARENT ?
-                             comctl32_color.clrWindow : comctl32_color.clrBtnFace;
         infoPtr->BreakChar = ' ';
         infoPtr->IgnoreReturn = infoPtr->Style & LWS_IGNORERETURN;
         TRACE("SysLink Ctrl creation, hwnd=%p\n", hwnd);
@@ -1772,12 +1774,9 @@ static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message,
 
     case WM_SYSCOLORCHANGE:
         COMCTL32_RefreshSysColors();
-        if (infoPtr->Style & LWS_TRANSPARENT)
-            infoPtr->BackColor = comctl32_color.clrWindow;
         return 0;
 
     default:
-HandleDefaultMessage:
         if ((message >= WM_USER) && (message < WM_APP) && !COMCTL32_IsReflectedMessage(message))
         {
             ERR("unknown msg %04x wp=%04lx lp=%08lx\n", message, wParam, lParam );