[Gdi32]
[reactos.git] / reactos / win32ss / gdi / gdi32 / misc / misc.c
index f326114..50eac9c 100644 (file)
@@ -18,7 +18,7 @@
  */
 /*
  * PROJECT:         ReactOS gdi32.dll
- * FILE:            dll/win32/gdi32/misc/misc.c
+ * FILE:            win32ss/gdi/gdi32/misc/misc.c
  * PURPOSE:         Miscellaneous functions
  * PROGRAMMER:      Thomas Weidenmueller <w3seek@reactos.com>
  * UPDATE HISTORY:
@@ -34,41 +34,683 @@ PGDI_TABLE_ENTRY GdiHandleTable = NULL;
 PGDI_SHARED_HANDLE_TABLE GdiSharedHandleTable = NULL;
 HANDLE CurrentProcessId = NULL;
 DWORD GDI_BatchLimit = 1;
+extern PGDIHANDLECACHE GdiHandleCache;
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+GdiFlush(VOID)
+{
+    NtGdiFlush();
+    return TRUE;
+}
+
+/*
+ * @unimplemented
+ */
+INT
+WINAPI
+Escape(
+    _In_ HDC hdc,
+    _In_ INT nEscape,
+    _In_ INT cbInput,
+    _In_ LPCSTR lpvInData,
+    _Out_ LPVOID lpvOutData)
+{
+    INT retValue = SP_ERROR;
+    ULONG ulObjType;
+
+    ulObjType = GDI_HANDLE_GET_TYPE(hdc);
+
+    if (ulObjType == GDILoObjType_LO_METADC16_TYPE)
+    {
+        return METADC16_Escape(hdc, nEscape, cbInput, lpvInData, lpvOutData);
+    }
+
+    switch (nEscape)
+    {
+        case ABORTDOC:
+            /* Note: Windows checks if the handle has any user data for the ABORTDOC command
+             * ReactOS copies this behavior to be compatible with windows 2003
+             */
+            if (GdiGetDcAttr(hdc) == NULL)
+            {
+                GdiSetLastError(ERROR_INVALID_HANDLE);
+                retValue = FALSE;
+            }
+            else
+            {
+                retValue = AbortDoc(hdc);
+            }
+            break;
+
+        case DRAFTMODE:
+        case FLUSHOUTPUT:
+        case SETCOLORTABLE:
+            /* Note 1: DRAFTMODE, FLUSHOUTPUT, SETCOLORTABLE are outdated */
+            /* Note 2: Windows checks if the handle has any user data for the DRAFTMODE, FLUSHOUTPUT, SETCOLORTABLE commands
+             * ReactOS copies this behavior to be compatible with windows 2003
+             */
+            if (GdiGetDcAttr(hdc) == NULL)
+            {
+                GdiSetLastError(ERROR_INVALID_HANDLE);
+            }
+            retValue = FALSE;
+            break;
+
+        case SETABORTPROC:
+            /* Note: Windows checks if the handle has any user data for the SETABORTPROC command
+             * ReactOS copies this behavior to be compatible with windows 2003
+             */
+            if (GdiGetDcAttr(hdc) == NULL)
+            {
+                GdiSetLastError(ERROR_INVALID_HANDLE);
+                retValue = FALSE;
+            }
+            retValue = SetAbortProc(hdc, (ABORTPROC)lpvInData);
+            break;
+
+        case GETCOLORTABLE:
+            retValue = GetSystemPaletteEntries(hdc, (UINT)*lpvInData, 1, (LPPALETTEENTRY)lpvOutData);
+            if (!retValue)
+            {
+                retValue = SP_ERROR;
+            }
+            break;
+
+        case ENDDOC:
+            /* Note: Windows checks if the handle has any user data for the ENDDOC command
+             * ReactOS copies this behavior to be compatible with windows 2003
+             */
+            if (GdiGetDcAttr(hdc) == NULL)
+            {
+                GdiSetLastError(ERROR_INVALID_HANDLE);
+                retValue = FALSE;
+            }
+            retValue = EndDoc(hdc);
+            break;
+
+        case GETSCALINGFACTOR:
+            /* Note GETSCALINGFACTOR is outdated have been replace by GetDeviceCaps */
+            if (ulObjType == GDI_OBJECT_TYPE_DC)
+            {
+                if (lpvOutData)
+                {
+                    PPOINT ptr = (PPOINT)lpvOutData;
+                    ptr->x = 0;
+                    ptr->y = 0;
+                }
+            }
+            retValue = FALSE;
+            break;
+
+        case GETEXTENDEDTEXTMETRICS:
+            retValue = GetETM(hdc, (EXTTEXTMETRIC *)lpvOutData) != 0;
+            break;
+
+        case STARTDOC:
+        {
+            DOCINFOA di;
+
+            /* Note: Windows checks if the handle has any user data for the STARTDOC command
+             * ReactOS copies this behavior to be compatible with windows 2003
+             */
+            if (GdiGetDcAttr(hdc) == NULL)
+            {
+                GdiSetLastError(ERROR_INVALID_HANDLE);
+                retValue = FALSE;
+            }
+
+            di.cbSize = sizeof(DOCINFOA);
+            di.lpszOutput = 0;
+            di.lpszDatatype = 0;
+            di.fwType = 0;
+            di.lpszDocName = lpvInData;
+
+            /* NOTE : doc for StartDocA/W at msdn http://msdn2.microsoft.com/en-us/library/ms535793(VS.85).aspx */
+            retValue = StartDocA(hdc, &di);
+
+            /* Check if StartDocA failed */
+            if (retValue < 0)
+            {
+                {
+                    retValue = GetLastError();
+
+                    /* Translate StartDocA error code to STARTDOC error code
+                     * see msdn http://msdn2.microsoft.com/en-us/library/ms535472.aspx
+                     */
+                    switch(retValue)
+                    {
+                    case ERROR_NOT_ENOUGH_MEMORY:
+                        retValue = SP_OUTOFMEMORY;
+                        break;
+
+                    case ERROR_PRINT_CANCELLED:
+                        retValue = SP_USERABORT;
+                        break;
+
+                    case ERROR_DISK_FULL:
+                        retValue = SP_OUTOFDISK;
+                        break;
+
+                    default:
+                        retValue = SP_ERROR;
+                        break;
+                    }
+                }
+            }
+        }
+        break;
+
+        default:
+            UNIMPLEMENTED;
+            SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    }
+
+    return retValue;
+}
+
+INT
+WINAPI
+ExtEscape(HDC hDC,
+          int nEscape,
+          int cbInput,
+          LPCSTR lpszInData,
+          int cbOutput,
+          LPSTR lpszOutData)
+{
+    return NtGdiExtEscape(hDC, NULL, 0, nEscape, cbInput, (LPSTR)lpszInData, cbOutput, lpszOutData);
+}
+
+INT
+WINAPI
+NamedEscape(HDC hdc,
+            PWCHAR pDriver,
+            INT iEsc,
+            INT cjIn,
+            LPSTR pjIn,
+            INT cjOut,
+            LPSTR pjOut)
+{
+    /* FIXME metadc, metadc are done most in user mode, and we do not support it
+     * Windows 2000/XP/Vista ignore the current hdc, that are being pass and always set hdc to NULL
+     * when it calls to NtGdiExtEscape from NamedEscape
+     */
+    return NtGdiExtEscape(NULL,pDriver,wcslen(pDriver),iEsc,cjIn,pjIn,cjOut,pjOut);
+}
+
+/*
+ * @implemented
+ */
+int
+WINAPI
+DrawEscape(HDC  hDC,
+           INT nEscape,
+           INT cbInput,
+           LPCSTR lpszInData)
+{
+    if (GDI_HANDLE_GET_TYPE(hDC) == GDI_OBJECT_TYPE_DC)
+        return NtGdiDrawEscape(hDC, nEscape, cbInput, (LPSTR) lpszInData);
+
+    if (GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_METADC)
+    {
+        PLDC pLDC = GdiGetLDC(hDC);
+        if ( pLDC )
+        {
+            if (pLDC->Flags & LDC_META_PRINT)
+            {
+//           if (nEscape != QUERYESCSUPPORT)
+//              return EMFDRV_WriteEscape(hDC, nEscape, cbInput, lpszInData, EMR_DRAWESCAPE);
+
+                return NtGdiDrawEscape(hDC, nEscape, cbInput, (LPSTR) lpszInData);
+            }
+        }
+        SetLastError(ERROR_INVALID_HANDLE);
+    }
+    return 0;
+}
+
+#define ALPHABLEND_NONE             0
+#define ALPHABLEND_BINARY           1
+#define ALPHABLEND_FULL             2
+
+typedef struct _MARGINS {
+    int cxLeftWidth;
+    int cxRightWidth;
+    int cyTopHeight;
+    int cyBottomHeight;
+} MARGINS, *PMARGINS;
+
+enum SIZINGTYPE {
+    ST_TRUESIZE = 0,
+    ST_STRETCH = 1,
+    ST_TILE = 2,
+};
 
+#define TransparentBlt GdiTransparentBlt
+#define AlphaBlend GdiAlphaBlend
+
+/***********************************************************************
+ *      UXTHEME_StretchBlt
+ *
+ * Pseudo TransparentBlt/StretchBlt
+ */
+static inline BOOL UXTHEME_StretchBlt(HDC hdcDst, int nXOriginDst, int nYOriginDst, int nWidthDst, int nHeightDst,
+                                      HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
+                                      INT transparent, COLORREF transcolor)
+{
+    static const BLENDFUNCTION blendFunc = 
+    {
+      AC_SRC_OVER, /* BlendOp */
+      0,           /* BlendFlag */
+      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 */
+        ret = TransparentBlt(hdcDst, nXOriginDst, nYOriginDst, abs(nWidthDst), abs(nHeightDst),
+                              hdcSrc, nXOriginSrc, nYOriginSrc, abs(nWidthSrc), abs(nHeightSrc),
+                              transcolor);
+    } else if ((transparent == ALPHABLEND_NONE) ||
+        !AlphaBlend(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
+                    hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
+                    blendFunc))
+    {
+        ret = StretchBlt(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
+                          hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
+                          SRCCOPY);
+    }
+
+    SetBrushOrgEx(hdcDst, old_brush_org.x, old_brush_org.y, NULL);
+    SetStretchBltMode(hdcDst, old_stretch_mode);
+
+    return ret;
+}
+
+/***********************************************************************
+ *      UXTHEME_Blt
+ *
+ * Simplify sending same width/height for both source and dest
+ */
+static inline BOOL UXTHEME_Blt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
+                               HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
+                               INT transparent, COLORREF transcolor)
+{
+    return UXTHEME_StretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
+                              hdcSrc, nXOriginSrc, nYOriginSrc, nWidthDest, nHeightDest,
+                              transparent, transcolor);
+}
+
+/***********************************************************************
+ *      UXTHEME_SizedBlt
+ *
+ * Stretches or tiles, depending on sizingtype.
+ */
+static inline BOOL UXTHEME_SizedBlt (HDC hdcDst, int nXOriginDst, int nYOriginDst, 
+                                     int nWidthDst, int nHeightDst,
+                                     HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, 
+                                     int nWidthSrc, int nHeightSrc,
+                                     int sizingtype, 
+                                     INT transparent, COLORREF transcolor)
+{
+    if (sizingtype == ST_TILE)
+    {
+        HDC hdcTemp;
+        BOOL result = FALSE;
+
+        if (!nWidthSrc || !nHeightSrc) return TRUE;
+
+        /* For destination width/height less than or equal to source
+           width/height, do not bother with memory bitmap optimization */
+        if (nWidthSrc >= nWidthDst && nHeightSrc >= nHeightDst)
+        {
+            int bltWidth = min (nWidthDst, nWidthSrc);
+            int bltHeight = min (nHeightDst, nHeightSrc);
 
+            return UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, bltWidth, bltHeight,
+                                hdcSrc, nXOriginSrc, nYOriginSrc,
+                                transparent, transcolor);
+        }
+
+        /* Create a DC with a bitmap consisting of a tiling of the source
+           bitmap, with standard GDI functions. This is faster than an
+           iteration with UXTHEME_Blt(). */
+        hdcTemp = CreateCompatibleDC(hdcSrc);
+        if (hdcTemp != 0)
+        {
+            HBITMAP bitmapTemp;
+            HBITMAP bitmapOrig;
+            int nWidthTemp, nHeightTemp;
+            int xOfs, xRemaining;
+            int yOfs, yRemaining;
+            int growSize;
+
+            /* Calculate temp dimensions of integer multiples of source dimensions */
+            nWidthTemp = ((nWidthDst + nWidthSrc - 1) / nWidthSrc) * nWidthSrc;
+            nHeightTemp = ((nHeightDst + nHeightSrc - 1) / nHeightSrc) * nHeightSrc;
+            bitmapTemp = CreateCompatibleBitmap(hdcSrc, nWidthTemp, nHeightTemp);
+            bitmapOrig = SelectObject(hdcTemp, bitmapTemp);
+
+            /* Initial copy of bitmap */
+            BitBlt(hdcTemp, 0, 0, nWidthSrc, nHeightSrc, hdcSrc, nXOriginSrc, nYOriginSrc, SRCCOPY);
+
+            /* Extend bitmap in the X direction. Growth of width is exponential */
+            xOfs = nWidthSrc;
+            xRemaining = nWidthTemp - nWidthSrc;
+            growSize = nWidthSrc;
+            while (xRemaining > 0)
+            {
+                growSize = min(growSize, xRemaining);
+                BitBlt(hdcTemp, xOfs, 0, growSize, nHeightSrc, hdcTemp, 0, 0, SRCCOPY);
+                xOfs += growSize;
+                xRemaining -= growSize;
+                growSize *= 2;
+            }
+
+            /* Extend bitmap in the Y direction. Growth of height is exponential */
+            yOfs = nHeightSrc;
+            yRemaining = nHeightTemp - nHeightSrc;
+            growSize = nHeightSrc;
+            while (yRemaining > 0)
+            {
+                growSize = min(growSize, yRemaining);
+                BitBlt(hdcTemp, 0, yOfs, nWidthTemp, growSize, hdcTemp, 0, 0, SRCCOPY);
+                yOfs += growSize;
+                yRemaining -= growSize;
+                growSize *= 2;
+            }
+
+            /* Use temporary hdc for source */
+            result = UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
+                          hdcTemp, 0, 0,
+                          transparent, transcolor);
+
+            SelectObject(hdcTemp, bitmapOrig);
+            DeleteObject(bitmapTemp);
+        }
+        DeleteDC(hdcTemp);
+        return result;
+    }
+    else
+    {
+        return UXTHEME_StretchBlt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
+                                   hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
+                                   transparent, transcolor);
+    }
+}
+
+/***********************************************************************
+ *      UXTHEME_DrawImageBackground
+ *
+ * Draw an imagefile background
+ */
+static HRESULT UXTHEME_DrawImageBackground(HDC hdc, HBITMAP bmpSrc, RECT *prcSrc, INT transparent,
+                                    COLORREF transparentcolor, BOOL borderonly, int sizingtype, MARGINS *psm, RECT *pRect)
+{
+    HRESULT hr = S_OK;
+    HBITMAP bmpSrcResized = NULL;
+    HGDIOBJ oldSrc;
+    HDC hdcSrc, hdcOrigSrc = NULL;
+    RECT rcDst;
+    POINT dstSize;
+    POINT srcSize;
+    RECT rcSrc;
+    MARGINS sm;
+
+    rcDst = *pRect;
+    rcSrc = *prcSrc;
+    sm = *psm;
+
+    hdcSrc = CreateCompatibleDC(hdc);
+    if(!hdcSrc) {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        return hr;
+    }
+    oldSrc = SelectObject(hdcSrc, bmpSrc);
+
+    dstSize.x = rcDst.right-rcDst.left;
+    dstSize.y = rcDst.bottom-rcDst.top;
+    srcSize.x = rcSrc.right-rcSrc.left;
+    srcSize.y = rcSrc.bottom-rcSrc.top;
+
+    if(sizingtype == ST_TRUESIZE) {
+        if(!UXTHEME_StretchBlt(hdc, rcDst.left, rcDst.top, dstSize.x, dstSize.y,
+                                hdcSrc, rcSrc.left, rcSrc.top, srcSize.x, srcSize.y,
+                                transparent, transparentcolor))
+            hr = HRESULT_FROM_WIN32(GetLastError());
+    }
+    else {
+        HDC hdcDst = NULL;
+        POINT org;
+
+        dstSize.x = abs(dstSize.x);
+        dstSize.y = abs(dstSize.y);
+
+        /* 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);
+
+        /* Upper left corner */
+        if(!UXTHEME_Blt(hdcDst, 0, 0, sm.cxLeftWidth, sm.cyTopHeight,
+                        hdcSrc, rcSrc.left, rcSrc.top, 
+                        transparent, transparentcolor)) {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto draw_error; 
+        }
+        /* Upper right corner */
+        if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, 0, 
+                         sm.cxRightWidth, sm.cyTopHeight,
+                         hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top, 
+                         transparent, transparentcolor)) {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto draw_error; 
+        }
+        /* Lower left corner */
+        if(!UXTHEME_Blt (hdcDst, 0, dstSize.y-sm.cyBottomHeight, 
+                         sm.cxLeftWidth, sm.cyBottomHeight,
+                         hdcSrc, rcSrc.left, rcSrc.bottom-sm.cyBottomHeight, 
+                         transparent, transparentcolor)) {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto draw_error; 
+        }
+        /* Lower right corner */
+        if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, dstSize.y-sm.cyBottomHeight, 
+                         sm.cxRightWidth, sm.cyBottomHeight,
+                         hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.bottom-sm.cyBottomHeight, 
+                         transparent, transparentcolor)) {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto draw_error; 
+        }
+
+        if ((sizingtype == ST_STRETCH) || (sizingtype == ST_TILE)) {
+            int destCenterWidth  = dstSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
+            int srcCenterWidth   = srcSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
+            int destCenterHeight = dstSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
+            int srcCenterHeight  = srcSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
+
+            if(destCenterWidth > 0) {
+                /* Center top */
+                if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, 0, 
+                                      destCenterWidth, sm.cyTopHeight,
+                                      hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top, 
+                                      srcCenterWidth, sm.cyTopHeight, 
+                                      sizingtype, transparent, transparentcolor)) {
+                    hr = HRESULT_FROM_WIN32(GetLastError());
+                    goto draw_error; 
+                }
+                /* Center bottom */
+                if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, dstSize.y-sm.cyBottomHeight, 
+                                      destCenterWidth, sm.cyBottomHeight,
+                                      hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.bottom-sm.cyBottomHeight, 
+                                      srcCenterWidth, sm.cyBottomHeight, 
+                                      sizingtype, transparent, transparentcolor)) {
+                    hr = HRESULT_FROM_WIN32(GetLastError());
+                    goto draw_error; 
+                }
+            }
+            if(destCenterHeight > 0) {
+                /* Left center */
+                if(!UXTHEME_SizedBlt (hdcDst, 0, sm.cyTopHeight, 
+                                      sm.cxLeftWidth, destCenterHeight,
+                                      hdcSrc, rcSrc.left, rcSrc.top+sm.cyTopHeight, 
+                                      sm.cxLeftWidth, srcCenterHeight, 
+                                      sizingtype, 
+                                      transparent, transparentcolor)) {
+                    hr = HRESULT_FROM_WIN32(GetLastError());
+                    goto draw_error; 
+                }
+                /* Right center */
+                if(!UXTHEME_SizedBlt (hdcDst, dstSize.x-sm.cxRightWidth, sm.cyTopHeight, 
+                                      sm.cxRightWidth, destCenterHeight,
+                                      hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top+sm.cyTopHeight, 
+                                      sm.cxRightWidth, srcCenterHeight, 
+                                      sizingtype, transparent, transparentcolor)) {
+                    hr = HRESULT_FROM_WIN32(GetLastError());
+                    goto draw_error; 
+                }
+            }
+            if(destCenterHeight > 0 && destCenterWidth > 0) {
+                if(!borderonly) {
+                    /* Center */
+                    if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, sm.cyTopHeight, 
+                                          destCenterWidth, destCenterHeight,
+                                          hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top+sm.cyTopHeight, 
+                                          srcCenterWidth, srcCenterHeight, 
+                                          sizingtype, transparent, transparentcolor)) {
+                        hr = HRESULT_FROM_WIN32(GetLastError());
+                        goto draw_error; 
+                    }
+                }
+            }
+        }
+
+draw_error:
+        SetViewportOrgEx (hdcDst, org.x, org.y, NULL);
+    }
+    SelectObject(hdcSrc, oldSrc);
+    DeleteDC(hdcSrc);
+    if (bmpSrcResized) DeleteObject(bmpSrcResized);
+    if (hdcOrigSrc) DeleteDC(hdcOrigSrc);
+    *pRect = rcDst;
+    return hr;
+}
+
+/*
+ * @unimplemented
+ */
 BOOL
 WINAPI
-GdiAlphaBlend(
-    HDC hDCDst,
-    int DstX,
-    int DstY,
-    int DstCx,
-    int DstCy,
-    HDC hDCSrc,
-    int SrcX,
-    int SrcY,
-    int SrcCx,
-    int SrcCy,
-    BLENDFUNCTION BlendFunction
-)
+GdiDrawStream(HDC dc, ULONG l, PGDI_DRAW_STREAM pDS)
 {
-    if ( hDCSrc == NULL ) return FALSE;
-
-    if (GDI_HANDLE_GET_TYPE(hDCSrc) == GDI_OBJECT_TYPE_METADC) return FALSE;
-
-    return NtGdiAlphaBlend(
-               hDCDst,
-               DstX,
-               DstY,
-               DstCx,
-               DstCy,
-               hDCSrc,
-               SrcX,
-               SrcY,
-               SrcCx,
-               SrcCy,
-               BlendFunction,
-               0 );
+    if (!pDS || l != sizeof(*pDS))
+    {
+        DPRINT1("GdiDrawStream: Invalid params\n");
+        return 0;
+    }
+
+    if (pDS->signature != 0x44727753 ||
+        pDS->reserved != 0 ||
+        pDS->unknown1 != 1 ||
+        pDS->unknown2 != 9)
+    {
+        DPRINT1("GdiDrawStream: Got unknown pDS data\n");
+        return 0;
+    }
+
+    {
+        MARGINS sm = {pDS->leftSizingMargin, pDS->rightSizingMargin, pDS->topSizingMargin, pDS->bottomSizingMargin};
+        INT transparent = 0;
+        int sizingtype;
+
+        if (pDS->drawOption & DS_TRANSPARENTALPHA)
+            transparent = ALPHABLEND_FULL;
+        else if (pDS->drawOption & DS_TRANSPARENTCLR)
+            transparent = ALPHABLEND_BINARY;
+        else 
+            transparent = ALPHABLEND_NONE;
+
+        if (pDS->drawOption & DS_TILE)
+            sizingtype = ST_TILE;
+        else if (pDS->drawOption & DS_TRUESIZE)
+            sizingtype = ST_TRUESIZE;
+        else
+            sizingtype = ST_STRETCH;
+
+        UXTHEME_DrawImageBackground(pDS->hDC, 
+                                    pDS->hImage, 
+                                    &pDS->rcSrc, 
+                                    transparent, 
+                                    pDS->crTransparent, 
+                                    FALSE,
+                                    sizingtype,
+                                    &sm,
+                                    &pDS->rcDest);
+    }
+    return 0;
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+GdiValidateHandle(HGDIOBJ hobj)
+{
+    PGDI_TABLE_ENTRY Entry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hobj);
+    if ( (Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0 &&
+            ( (Entry->Type << GDI_ENTRY_UPPER_SHIFT) & GDI_HANDLE_TYPE_MASK ) ==
+            GDI_HANDLE_GET_TYPE(hobj) )
+    {
+        HANDLE pid = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1);
+        if(pid == NULL || pid == CurrentProcessId)
+        {
+            return TRUE;
+        }
+    }
+    return FALSE;
+
 }
 
 /*
@@ -145,41 +787,40 @@ BOOL GdiGetHandleUserData(HGDIOBJ hGdiObj, DWORD ObjectType, PVOID *UserData)
 
 PLDC
 FASTCALL
-GdiGetLDC(HDC hDC)
+GdiGetLDC(HDC hdc)
 {
-    PDC_ATTR Dc_Attr;
-    PGDI_TABLE_ENTRY Entry = GdiHandleTable + GDI_HANDLE_GET_INDEX((HGDIOBJ) hDC);
-    HANDLE pid = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1);
-    // Don't check the mask, just the object type.
-    if ( Entry->ObjectType == GDIObjType_DC_TYPE &&
-            (pid == NULL || pid == CurrentProcessId) )
+    PDC_ATTR pdcattr;
+
+    /* Get the DC attribute */
+    pdcattr = GdiGetDcAttr(hdc);
+    if (pdcattr == NULL)
     {
-        BOOL Result = TRUE;
-        if (Entry->UserData)
-        {
-            volatile CHAR *Current = (volatile CHAR*)Entry->UserData;
-            _SEH2_TRY
-            {
-                *Current = *Current;
-            }
-            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-            {
-                Result = FALSE;
-            }
-            _SEH2_END
-        }
-        else
-            Result = FALSE;
+        return NULL;
+    }
 
-        if (Result)
-        {
-            Dc_Attr = (PDC_ATTR)Entry->UserData;
-            return Dc_Attr->pvLDC;
-        }
+    /* Return the LDC pointer */
+    return pdcattr->pvLDC;
+}
+
+BOOL
+FASTCALL
+GdiSetLDC(HDC hdc, PVOID pvLDC)
+{
+    PDC_ATTR pdcattr;
+
+    /* Get the DC attribute */
+    pdcattr = GdiGetDcAttr(hdc);
+    if (pdcattr == NULL)
+    {
+        return FALSE;
     }
-    return NULL;
+
+    /* Set the LDC pointer */
+    pdcattr->pvLDC = pvLDC;
+    return TRUE;
 }
 
+
 VOID GdiSAPCallback(PLDC pldc)
 {
     DWORD Time, NewTime = GetTickCount();
@@ -223,32 +864,11 @@ GdiSetBatchLimit(DWORD    Limit)
  */
 DWORD
 WINAPI
-GdiGetBatchLimit()
+GdiGetBatchLimit(VOID)
 {
     return GDI_BatchLimit;
 }
 
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-GdiReleaseDC(HDC hdc)
-{
-    return 0;
-}
-
-INT
-WINAPI
-ExtEscape(HDC hDC,
-          int nEscape,
-          int cbInput,
-          LPCSTR lpszInData,
-          int cbOutput,
-          LPSTR lpszOutData)
-{
-    return NtGdiExtEscape(hDC, NULL, 0, nEscape, cbInput, (LPSTR)lpszInData, cbOutput, lpszOutData);
-}
 
 /*
  * @implemented
@@ -260,16 +880,6 @@ GdiSetLastError(DWORD dwErrCode)
     NtCurrentTeb()->LastErrorValue = (ULONG) dwErrCode;
 }
 
-BOOL
-WINAPI
-GdiAddGlsBounds(HDC hdc,LPRECT prc)
-{
-    //FIXME: Lookup what 0x8000 means
-    return NtGdiSetBoundsRect(hdc, prc, 0x8000 |  DCB_ACCUMULATE ) ? TRUE : FALSE;
-}
-
-extern PGDIHANDLECACHE GdiHandleCache;
-
 HGDIOBJ
 FASTCALL
 hGetPEBHandle(HANDLECACHETYPE Type, COLORREF cr)
@@ -343,3 +953,120 @@ hGetPEBHandle(HANDLECACHETYPE Type, COLORREF cr)
     return Handle;
 }
 
+/*
+ * @unimplemented
+ */
+BOOL
+WINAPI
+bMakePathNameW(LPWSTR lpBuffer,LPCWSTR lpFileName,LPWSTR *lpFilePart,DWORD unknown)
+{
+    UNIMPLEMENTED;
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return 0;
+}
+
+/*
+ * @implemented
+ */
+DEVMODEW *
+WINAPI
+GdiConvertToDevmodeW(const DEVMODEA *dmA)
+{
+    DEVMODEW *dmW;
+    WORD dmW_size, dmA_size;
+
+    dmA_size = dmA->dmSize;
+
+    /* this is the minimal dmSize that XP accepts */
+    if (dmA_size < FIELD_OFFSET(DEVMODEA, dmFields))
+        return NULL;
+
+    if (dmA_size > sizeof(DEVMODEA))
+        dmA_size = sizeof(DEVMODEA);
+
+    dmW_size = dmA_size + CCHDEVICENAME;
+    if (dmA_size >= FIELD_OFFSET(DEVMODEA, dmFormName) + CCHFORMNAME)
+        dmW_size += CCHFORMNAME;
+
+    dmW = HeapAlloc(GetProcessHeap(), 0, dmW_size + dmA->dmDriverExtra);
+    if (!dmW) return NULL;
+
+    MultiByteToWideChar(CP_ACP, 0, (const char*) dmA->dmDeviceName, CCHDEVICENAME,
+                        dmW->dmDeviceName, CCHDEVICENAME);
+    /* copy slightly more, to avoid long computations */
+    memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion, dmA_size - CCHDEVICENAME);
+
+    if (dmA_size >= FIELD_OFFSET(DEVMODEA, dmFormName) + CCHFORMNAME)
+    {
+        MultiByteToWideChar(CP_ACP, 0, (const char*) dmA->dmFormName, CCHFORMNAME,
+                            dmW->dmFormName, CCHFORMNAME);
+        if (dmA_size > FIELD_OFFSET(DEVMODEA, dmLogPixels))
+            memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA_size - FIELD_OFFSET(DEVMODEA, dmLogPixels));
+    }
+
+    if (dmA->dmDriverExtra)
+        memcpy((char *)dmW + dmW_size, (const char *)dmA + dmA_size, dmA->dmDriverExtra);
+
+    dmW->dmSize = dmW_size;
+
+    return dmW;
+}
+
+/*
+ * @unimplemented
+ */
+BOOL
+WINAPI
+GdiRealizationInfo(HDC hdc,
+                   PREALIZATION_INFO pri)
+{
+    // ATM we do not support local font data and Language Pack.
+    return NtGdiGetRealizationInfo(hdc, pri, (HFONT) NULL);
+}
+
+
+/*
+ * @unimplemented
+ */
+VOID WINAPI GdiInitializeLanguagePack(DWORD InitParam)
+{
+    UNIMPLEMENTED;
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+}
+
+BOOL
+WINAPI
+GdiAddGlsBounds(HDC hdc,LPRECT prc)
+{
+    return NtGdiSetBoundsRect(hdc, prc, DCB_WINDOWMGR|DCB_ACCUMULATE ) ? TRUE : FALSE;
+}
+
+BOOL
+WINAPI
+GetBoundsRectAlt(HDC hdc,LPRECT prc,UINT flags)
+{
+    return NtGdiGetBoundsRect(hdc, prc, flags);
+}
+
+BOOL
+WINAPI
+SetBoundsRectAlt(HDC hdc,LPRECT prc,UINT flags)
+{
+    return NtGdiSetBoundsRect(hdc, prc, flags );
+}
+
+/*
+ * @unimplemented
+ */
+BOOL
+WINAPI
+GdiAddGlsRecord(HDC hdc,
+                DWORD unknown1,
+                LPCSTR unknown2,
+                LPRECT unknown3)
+{
+    UNIMPLEMENTED;
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return 0;
+}
+