[UXTHME] Implement drawing themed text with shadows.
[reactos.git] / reactos / dll / win32 / uxtheme / draw.c
index f0430e7..f9d9eec 100644 (file)
@@ -82,9 +82,9 @@ HRESULT WINAPI DrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc)
     if(!hParent)
         hParent = hwnd;
     if(prc) {
-        CopyRect(&rt, prc);
+        rt = *prc;
         MapWindowPoints(hwnd, hParent, (LPPOINT)&rt, 2);
-        
+
         clip = CreateRectRgn(0,0,1,1);
         hasClip = GetClipRgn(hdc, clip);
         if(hasClip == -1)
@@ -126,7 +126,7 @@ HRESULT WINAPI DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId,
     opts.dwFlags = 0;
     if(pClipRect) {
         opts.dwFlags |= DTBG_CLIPRECT;
-        CopyRect(&opts.rcClip, pClipRect);
+        opts.rcClip = *pClipRect;
     }
     return DrawThemeBackgroundEx(hTheme, hdc, iPartId, iStateId, pRect, &opts);
 }
@@ -241,6 +241,9 @@ static HRESULT UXTHEME_LoadImage(HTHEME hTheme, HDC hdc, int iPartId, int iState
 
     imagenum = max (min (imagecount, iStateId), 1) - 1;
     GetObjectW(*hBmp, sizeof(bmp), &bmp);
+
+    if(imagecount < 1) imagecount = 1;
+
     if(imagelayout == IL_VERTICAL) {
         int height = bmp.bmHeight/imagecount;
         bmpRect->left = 0;
@@ -274,22 +277,33 @@ static inline BOOL UXTHEME_StretchBlt(HDC hdcDst, int nXOriginDst, int nYOriginD
       255,         /* SourceConstantAlpha */
       AC_SRC_ALPHA /* AlphaFormat */
     };
+
+    BOOL ret = TRUE;
+    int old_stretch_mode;
+    POINT old_brush_org;
+
+    old_stretch_mode = SetStretchBltMode(hdcDst, HALFTONE);
+    SetBrushOrgEx(hdcDst, nXOriginDst, nYOriginDst, &old_brush_org);
+
     if (transparent == ALPHABLEND_BINARY) {
         /* Ensure we don't pass any negative values to TransparentBlt */
-        return TransparentBlt(hdcDst, nXOriginDst, nYOriginDst, abs(nWidthDst), abs(nHeightDst),
+        ret = TransparentBlt(hdcDst, nXOriginDst, nYOriginDst, abs(nWidthDst), abs(nHeightDst),
                               hdcSrc, nXOriginSrc, nYOriginSrc, abs(nWidthSrc), abs(nHeightSrc),
                               transcolor);
-    }
-    if ((transparent == ALPHABLEND_NONE) ||
+    } else if ((transparent == ALPHABLEND_NONE) ||
         !AlphaBlend(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
                     hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
                     blendFunc))
     {
-        return StretchBlt(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
+        ret = StretchBlt(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
                           hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
                           SRCCOPY);
     }
-    return TRUE;
+
+    SetBrushOrgEx(hdcDst, old_brush_org.x, old_brush_org.y, NULL);
+    SetStretchBltMode(hdcDst, old_stretch_mode);
+
+    return ret;
 }
 
 /***********************************************************************
@@ -449,7 +463,7 @@ static HRESULT UXTHEME_DrawImageGlyph(HTHEME hTheme, HDC hdc, int iPartId,
     HDC hdcSrc = NULL;
     HGDIOBJ oldSrc = NULL;
     RECT rcSrc;
-    INT transparent = FALSE;
+    INT transparent = 0;
     COLORREF transparentcolor;
     int valign = VA_CENTER;
     int halign = HA_CENTER;
@@ -548,7 +562,7 @@ static HRESULT get_image_part_size (HTHEME hTheme, HDC hdc, int iPartId,
                 int sizingtype = ST_STRETCH;
                 BOOL uniformsizing = FALSE;
 
-                CopyRect(&rcDst, prc);
+                rcDst = *prc;
 
                 dstSize.x = rcDst.right-rcDst.left;
                 dstSize.y = rcDst.bottom-rcDst.top;
@@ -633,9 +647,9 @@ static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId,
                                     const DTBGOPTS *pOptions)
 {
     HRESULT hr = S_OK;
-    HBITMAP bmpSrc;
+    HBITMAP bmpSrc, bmpSrcResized = NULL;
     HGDIOBJ oldSrc;
-    HDC hdcSrc;
+    HDC hdcSrc, hdcOrigSrc = NULL;
     RECT rcSrc;
     RECT rcDst;
     POINT dstSize;
@@ -656,7 +670,7 @@ static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId,
     }
     oldSrc = SelectObject(hdcSrc, bmpSrc);
 
-    CopyRect(&rcDst, pRect);
+    rcDst = *pRect;
     
     get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
         &transparentcolor, FALSE);
@@ -699,6 +713,38 @@ static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId,
 
         GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_SIZINGMARGINS, NULL, &sm);
 
+        /* Resize source image if destination smaller than margins */
+#ifndef __REACTOS__
+        /* Revert Wine Commit 2b650fa as it breaks themed Explorer Toolbar Separators
+           FIXME: Revisit this when the bug is fixed. CORE-9636 and Wine Bug #38538 */
+        if (sm.cyTopHeight + sm.cyBottomHeight > dstSize.y || sm.cxLeftWidth + sm.cxRightWidth > dstSize.x) {
+            if (sm.cyTopHeight + sm.cyBottomHeight > dstSize.y) {
+                sm.cyTopHeight = MulDiv(sm.cyTopHeight, dstSize.y, srcSize.y);
+                sm.cyBottomHeight = dstSize.y - sm.cyTopHeight;
+                srcSize.y = dstSize.y;
+            }
+
+            if (sm.cxLeftWidth + sm.cxRightWidth > dstSize.x) {
+                sm.cxLeftWidth = MulDiv(sm.cxLeftWidth, dstSize.x, srcSize.x);
+                sm.cxRightWidth = dstSize.x - sm.cxLeftWidth;
+                srcSize.x = dstSize.x;
+            }
+
+            hdcOrigSrc = hdcSrc;
+            hdcSrc = CreateCompatibleDC(NULL);
+            bmpSrcResized = CreateBitmap(srcSize.x, srcSize.y, 1, 32, NULL);
+            SelectObject(hdcSrc, bmpSrcResized);
+
+            UXTHEME_StretchBlt(hdcSrc, 0, 0, srcSize.x, srcSize.y, hdcOrigSrc, rcSrc.left, rcSrc.top,
+                               rcSrc.right - rcSrc.left, rcSrc.bottom - rcSrc.top, transparent, transparentcolor);
+
+            rcSrc.left = 0;
+            rcSrc.top = 0;
+            rcSrc.right = srcSize.x;
+            rcSrc.bottom = srcSize.y;
+        }
+#endif /* __REACTOS__ */
+
         hdcDst = hdc;
         OffsetViewportOrgEx(hdcDst, rcDst.left, rcDst.top, &org);
 
@@ -803,7 +849,9 @@ draw_error:
     }
     SelectObject(hdcSrc, oldSrc);
     DeleteDC(hdcSrc);
-    CopyRect(pRect, &rcDst);
+    if (bmpSrcResized) DeleteObject(bmpSrcResized);
+    if (hdcOrigSrc) DeleteDC(hdcOrigSrc);
+    *pRect = rcDst;
     return hr;
 }
 
@@ -941,7 +989,7 @@ static HRESULT UXTHEME_DrawBorderBackground(HTHEME hTheme, HDC hdc, int iPartId,
     HRESULT hr;
     RECT rt;
 
-    CopyRect(&rt, pRect);
+    rt = *pRect;
 
     hr = UXTHEME_DrawBorderRectangle(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
     if(FAILED(hr))
@@ -983,7 +1031,7 @@ HRESULT WINAPI DrawThemeBackgroundEx(HTHEME hTheme, HDC hdc, int iPartId,
         else
             IntersectClipRect(hdc, opts->rcClip.left, opts->rcClip.top, opts->rcClip.right, opts->rcClip.bottom);
     }
-    CopyRect(&rt, pRect);
+    rt = *pRect;
 
     if(bgtype == BT_IMAGEFILE)
         hr = UXTHEME_DrawImageBackground(hTheme, hdc, iPartId, iStateId, &rt, opts);
@@ -1566,9 +1614,12 @@ HRESULT WINAPI DrawThemeIcon(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
     FIXME("%d %d: stub\n", iPartId, iStateId);
     if(!hTheme)
         return E_HANDLE;
-    return ERROR_CALL_NOT_IMPLEMENTED;
+    return E_NOTIMPL;
 }
 
+typedef int (WINAPI * DRAWSHADOWTEXT)(HDC hdc, LPCWSTR pszText, UINT cch, RECT *prc, DWORD dwFlags,
+                          COLORREF crText, COLORREF crShadow, int ixOffset, int iyOffset);
+
 /***********************************************************************
  *      DrawThemeText                                       (UXTHEME.@)
  */
@@ -1582,34 +1633,89 @@ HRESULT WINAPI DrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
     LOGFONTW logfont;
     COLORREF textColor;
     COLORREF oldTextColor;
+    COLORREF shadowColor;
+    POINT ptShadowOffset;
     int oldBkMode;
     RECT rt;
-    
+    int iShadowType;
+
     TRACE("%d %d: stub\n", iPartId, iStateId);
     if(!hTheme)
         return E_HANDLE;
-    
+
     hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
-    if(SUCCEEDED(hr)) {
+    if(SUCCEEDED(hr)) 
+    {
         hFont = CreateFontIndirectW(&logfont);
         if(!hFont)
-            TRACE("Failed to create font\n");
+        {
+            ERR("Failed to create font\n");
+        }
     }
+
     CopyRect(&rt, pRect);
     if(hFont)
         oldFont = SelectObject(hdc, hFont);
-        
+
+    oldBkMode = SetBkMode(hdc, TRANSPARENT);
+
     if(dwTextFlags2 & DTT_GRAYED)
         textColor = GetSysColor(COLOR_GRAYTEXT);
     else {
         if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTCOLOR, &textColor)))
             textColor = GetTextColor(hdc);
     }
+
+    hr = GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_TEXTSHADOWTYPE, &iShadowType);
+    if (SUCCEEDED(hr))
+    {
+        ERR("Got shadow type %d\n", iShadowType);
+
+        hr = GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTSHADOWCOLOR, &shadowColor);
+        if (FAILED(hr))
+        {
+            ERR("GetThemeColor failed\n");
+        }
+
+        hr = GetThemePosition(hTheme, iPartId, iStateId, TMT_TEXTSHADOWOFFSET, &ptShadowOffset);
+        if (FAILED(hr))
+        {
+            ERR("GetThemePosition failed\n");
+        }
+
+        if (iShadowType == TST_SINGLE)
+        {
+            oldTextColor = SetTextColor(hdc, shadowColor);
+            OffsetRect(&rt, ptShadowOffset.x, ptShadowOffset.y);
+            DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
+            OffsetRect(&rt, -ptShadowOffset.x, -ptShadowOffset.y);
+            SetTextColor(hdc, oldTextColor);
+        }
+        else if (iShadowType == TST_CONTINUOUS)
+        {
+            HANDLE hcomctl32 = GetModuleHandleW(L"comctl32.dll");
+            DRAWSHADOWTEXT pDrawShadowText;
+            if (!hcomctl32)
+            {
+                hcomctl32 = LoadLibraryW(L"comctl32.dll");
+                if (!hcomctl32)
+                    ERR("Failed to load comctl32\n");
+            }
+
+            pDrawShadowText = (DRAWSHADOWTEXT)GetProcAddress(hcomctl32, "DrawShadowText");
+            if (pDrawShadowText)
+            {
+                pDrawShadowText(hdc, pszText, iCharCount, &rt, dwTextFlags, textColor, shadowColor, ptShadowOffset.x, ptShadowOffset.y);
+                goto cleanup;
+            }
+        }
+    }
+
     oldTextColor = SetTextColor(hdc, textColor);
-    oldBkMode = SetBkMode(hdc, TRANSPARENT);
     DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
-    SetBkMode(hdc, oldBkMode);
     SetTextColor(hdc, oldTextColor);
+cleanup:
+    SetBkMode(hdc, oldBkMode);
 
     if(hFont) {
         SelectObject(hdc, oldFont);
@@ -1662,7 +1768,7 @@ HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId
         /* If nothing was found, leave unchanged */
     }
 
-    TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pContentRect->left, pContentRect->top, pContentRect->right, pContentRect->bottom);
+    TRACE("%s\n", wine_dbgstr_rect(pContentRect));
 
     return S_OK;
 }
@@ -1710,7 +1816,7 @@ HRESULT WINAPI GetThemeBackgroundExtent(HTHEME hTheme, HDC hdc, int iPartId,
         /* If nothing was found, leave unchanged */
     }
 
-    TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pExtentRect->left, pExtentRect->top, pExtentRect->right, pExtentRect->bottom);
+    TRACE("%s\n", wine_dbgstr_rect(pExtentRect));
 
     return S_OK;
 }
@@ -1755,20 +1861,15 @@ static HBITMAP UXTHEME_DrawThemePartToDib(HTHEME hTheme, HDC hdc, int iPartId, i
 static HRGN UXTHEME_RegionFromDibBits(RGBQUAD* pBuffer, RGBQUAD* pclrTransparent, LPCRECT pRect)
 {
     int x, y, xstart;
-#ifdef EXTCREATEREGION_WORKS
     int cMaxRgnRects, cRgnDataSize, cRgnRects;
     RECT* prcCurrent;
     PRGNDATA prgnData;
-#else
-    HRGN hrgnTemp;
-#endif
     ULONG clrTransparent, *pclrCurrent;
     HRGN hrgnRet;
 
     pclrCurrent = (PULONG)pBuffer;
     clrTransparent = *(PULONG)pclrTransparent;
 
-#ifdef EXTCREATEREGION_WORKS
     /* Create a region and pre-allocate memory enough for 3 spaces in one row*/
     cRgnRects = 0;
     cMaxRgnRects = 4* (pRect->bottom-pRect->top);
@@ -1778,9 +1879,6 @@ static HRGN UXTHEME_RegionFromDibBits(RGBQUAD* pBuffer, RGBQUAD* pclrTransparent
     prgnData = (PRGNDATA)HeapAlloc(GetProcessHeap(), 0, cRgnDataSize);
 
     prcCurrent = (PRECT)prgnData->Buffer;
-#else
-    hrgnRet = CreateRectRgn(0,0,0,0);
-#endif
     
     /* Calculate the region rects */
     y=0;
@@ -1804,7 +1902,6 @@ static HRGN UXTHEME_RegionFromDibBits(RGBQUAD* pBuffer, RGBQUAD* pclrTransparent
                     pclrCurrent++;
                 }
 
-#ifdef EXTCREATEREGION_WORKS
                 /* Add the scaned line to the region */
                 SetRect(prcCurrent, xstart, y,x,y+1);
                 prcCurrent++;
@@ -1821,11 +1918,6 @@ static HRGN UXTHEME_RegionFromDibBits(RGBQUAD* pBuffer, RGBQUAD* pclrTransparent
                                                      cRgnDataSize);
                     prcCurrent = (RECT*)prgnData->Buffer + cRgnRects;
                 }
-#else
-                hrgnTemp = CreateRectRgn(xstart, y,x,y+1);
-                CombineRgn(hrgnRet, hrgnRet, hrgnTemp, RGN_OR );
-                DeleteObject(hrgnTemp);
-#endif
             }
             else
             {
@@ -1836,7 +1928,6 @@ static HRGN UXTHEME_RegionFromDibBits(RGBQUAD* pBuffer, RGBQUAD* pclrTransparent
         y++;
     }
 
-#ifdef EXTCREATEREGION_WORKS
     /* Fill the region data header */
     prgnData->rdh.dwSize = sizeof(prgnData->rdh);
     prgnData->rdh.iType = RDH_RECTANGLES;
@@ -1849,7 +1940,6 @@ static HRGN UXTHEME_RegionFromDibBits(RGBQUAD* pBuffer, RGBQUAD* pclrTransparent
 
     /* Free the region data*/
     HeapFree(GetProcessHeap(),0,prgnData);
-#endif
 
     /* return the region*/
     return hrgnRet;
@@ -1983,8 +2073,8 @@ HRESULT WINAPI GetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId,
         return E_HANDLE;
 
     if(pBoundingRect)
-        CopyRect(&rt, pBoundingRect);
-            
+        rt = *pBoundingRect;
+
     hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
     if(SUCCEEDED(hr)) {
         hFont = CreateFontIndirectW(&logfont);
@@ -1995,7 +2085,7 @@ HRESULT WINAPI GetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId,
         oldFont = SelectObject(hdc, hFont);
         
     DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags|DT_CALCRECT);
-    CopyRect(pExtentRect, &rt);
+    *pExtentRect = rt;
 
     if(hFont) {
         SelectObject(hdc, oldFont);
@@ -2059,6 +2149,9 @@ BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId,
 
     GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
 
+#ifdef __REACTOS__
+    if (bgtype == BT_NONE) return TRUE;
+#endif
     if (bgtype != BT_IMAGEFILE) return FALSE;
 
     if(FAILED (UXTHEME_LoadImage (hTheme, 0, iPartId, iStateId, &rect, FALSE,