Author: gadamopoulos
Date: Fri Apr 7 14:09:24 2017
New Revision: 74280
URL:
http://svn.reactos.org/svn/reactos?rev=74280&view=rev
Log:
[GDI32] -Implement GdiDrawStream.
- This is based on the prototype I found in a sample app on codeproject. I don't
really know what the unknown parameters are for but I haven't found anything yet
passing different values. Almost all of the code is from the drawing code from uxtheme
with the only difference that in uxtheme UXTHEME_DrawImageBackground reads several values
from the theme but his takes them as parameters. I don't see any reason to spend time
understanding what these are for. I found what the draw flags are for by passing different
values in the test application and trying to replicate the parameters that
UXTHEME_DrawImageBackground need. I decided to keep the naming like that since it is
almost verbatim wine code. At some point it should be moved to win32k however.
CORE-4420
Modified:
trunk/reactos/win32ss/gdi/gdi32/misc/misc.c
Modified: trunk/reactos/win32ss/gdi/gdi32/misc/misc.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/gdi/gdi32/misc/mis…
==============================================================================
--- trunk/reactos/win32ss/gdi/gdi32/misc/misc.c [iso-8859-1] (original)
+++ trunk/reactos/win32ss/gdi/gdi32/misc/misc.c [iso-8859-1] Fri Apr 7 14:09:24 2017
@@ -272,16 +272,441 @@
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;
+
+typedef struct GDI_DRAW_STREAM_TAG
+{
+ DWORD signature; // must be 0x44727753;//"Swrd"
+ DWORD reserved; // must be 0
+ HDC hDC; // handle to the device object of windiw to draw.
+ RECT rcDest; // desination rect of window to draw.
+ DWORD unknown1; // must be 1.
+ HBITMAP hImage;
+ DWORD unknown2; // must be 9.
+ RECT rcClip; // desination rect of window to draw.
+ RECT rcSrc; // source rect of bitmap to draw.
+ DWORD drawOption; // 0x2 is tile instead of stretch. 0x4 is transparent. 0x20 is
true size
+ DWORD leftSizingMargin;
+ DWORD rightSizingMargin;
+ DWORD topSizingMargin;
+ DWORD bottomSizingMargin;
+ DWORD crTransparent; // transparent color.
+
+} GDI_DRAW_STREAM, *PGDI_DRAW_STREAM;
+
+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
-GdiDrawStream(HDC dc, ULONG l, VOID *v) // See Bug 4784
-{
- UNIMPLEMENTED;
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+GdiDrawStream(HDC dc, ULONG l, PGDI_DRAW_STREAM pDS)
+{
+ 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 & 0x4)
+ transparent = ALPHABLEND_FULL;
+ else if (pDS->drawOption & 0x8)
+ transparent = ALPHABLEND_BINARY;
+ else
+ transparent = ALPHABLEND_NONE;
+
+ if (pDS->drawOption & 0x2)
+ sizingtype = ST_TILE;
+ else if (pDS->drawOption & 0x20)
+ 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;
}