<div dir="ltr">I had tried to submit a patch for that <a href="http://www.winehq.org/pipermail/wine-devel/2009-December/080391.html" target="_blank">5 years ago</a>, but couldn't figure out how to make a patch/test it, and eventually gave up and forgot about it. But recently I remembered about it, and now I want to try again.<div>

<br></div><div>So, this time I've prepared a test that can prove that the previous implementation does not calculate the XFORM matrix correctly, and that my patch will fix it.</div><div><br></div><div>The test is a VC6 project, you can find it at <a href="https://drive.google.com/file/d/0B9PGUhmmnsm1S2VvZzc3WmhBY3c/edit?usp=sharing" target="_blank">https://drive.google.com/file/d/0B9PGUhmmnsm1S2VvZzc3WmhBY3c/edit?usp=sharing</a>. The test is a demo of PlgBlt that I <a href="http://www.codeproject.com/Articles/17712/The-GDI-magic-Rendering-reflections-and-smooth-sha" target="_blank">found on CodeProject</a>. You can compare how it works on XP and on Wine. For testing, I directly inserted the original Wine implementation of PlgBlt, as well as my patched version, into the VC6 project, and tested on that. This is because there seems to be an additional problem with MaskBlt, which I'll try tackling next.</div>

<div><br></div><div>I have screenshots of what the demo looks using <a href="http://imgur.com/q8qKGd7" target="_blank">Windows's PlgBlt</a>, and <a href="http://imgur.com/smYEV6z" target="_blank">Wine's PlgBlt</a>.</div>
<div><br></div>
<div>To test it, simply look at this function in the VC6 project:</div><div><br></div><div><div>BOOL MyPlgBlt( HDC hdcDest, const POINT *lpPoint,</div><div>                        HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,</div>
<div>                        INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)</div><div>{</div><div>//      return MyPlgBltWinePatched(hdcDest, lpPoint, hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hbmMask, xMask, yMask);</div>
<div>        return MyPlgBltWineUnpatched(hdcDest, lpPoint, hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hbmMask, xMask, yMask);</div><div>//      return PlgBlt(hdcDest, lpPoint, hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hbmMask, xMask, yMask);</div>
<div>}</div></div><div><br></div><div>Uncomment the function you want to test. If you need something else (like binaries), just write.</div><div><br></div><div>And this is the patch itself. I've tried to keep the changes minimal, with respect to white-space, etc. I've removed a "return FALSE", because I don't calculate a determinant explicitly.<br>
</div><div><br></div><div><div>commit c9ca2cab58fa0cba3d6b24cfb2af507fd1c07227</div>
<div>Author: Alexander Almaleh <<a href="mailto:sashoalm@gmail.com" target="_blank">sashoalm@gmail.com</a>></div><div>Date:   Tue May 20 18:33:55 2014 +0300</div><div><br></div><div>    Fix for the calculation of the XFORM matrix in PlgBlt.</div>

<div><br></div><div>diff --git a/dlls/gdi32/bitblt.c b/dlls/gdi32/bitblt.c</div><div>index 4750d1b..1de25b9 100644</div><div>--- a/dlls/gdi32/bitblt.c</div><div>+++ b/dlls/gdi32/bitblt.c</div><div>@@ -992,22 +992,32 @@ BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,</div>

<div>                         HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,</div><div>                         INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)</div><div> {</div><div>+    /* we need to use floating-point precision when calculating the </div>

<div>+     * XFORM matrix to avoid loss of precision due to rounding */</div><div>+    typedef struct tagPOINTLF</div><div>+    {</div><div>+        double x, y;</div><div>+    } POINTLF;</div><div>+</div><div>     int oldgMode;</div>

<div>     /* parallelogram coords */</div><div>-    POINT plg[3];</div><div>+    POINTLF plg[3];</div><div>     /* rect coords */</div><div>-    POINT rect[3];</div><div>+    POINTLF rect[3];</div><div>     XFORM xf;</div>

<div>     XFORM SrcXf;</div><div>     XFORM oldDestXf;</div><div>-    double det;</div><div>+    int ii;</div><div> </div><div>     /* save actual mode, set GM_ADVANCED */</div><div>     oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);</div>

<div>     if (oldgMode == 0)</div><div>         return FALSE;</div><div> </div><div>-    memcpy(plg,lpPoint,sizeof(POINT)*3);</div><div>+    for (ii = 0; ii < 3; ii++) {</div><div>+        plg[ii].x = lpPoint[ii].x;</div>

<div>+        plg[ii].y = lpPoint[ii].y;</div><div>+    }</div><div>     rect[0].x = nXSrc;</div><div>     rect[0].y = nYSrc;</div><div>     rect[1].x = nXSrc + nWidth;</div><div>@@ -1015,33 +1025,39 @@ BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,</div>

<div>     rect[2].x = nXSrc;</div><div>     rect[2].y = nYSrc + nHeight;</div><div>     /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */</div><div>-    /* determinant */</div><div>-    det = rect[1].x*(rect[2].y - rect[0].y) - rect[2].x*(rect[1].y - rect[0].y) - rect[0].x*(rect[2].y - rect[1].y);</div>

<div>-</div><div>-    if (fabs(det) < 1e-5)</div><div>-    {</div><div>-        SetGraphicsMode(hdcDest,oldgMode);</div><div>-        return FALSE;</div><div>-    }</div><div> </div><div>     TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",</div>

<div>         hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);</div><div> </div><div>     /* X components */</div><div>-    xf.eM11 = (plg[1].x*(rect[2].y - rect[0].y) - plg[2].x*(rect[1].y - rect[0].y) - plg[0].x*(rect[2].y - rect[1].y)) / det;</div>

<div>-    xf.eM21 = (rect[1].x*(plg[2].x - plg[0].x) - rect[2].x*(plg[1].x - plg[0].x) - rect[0].x*(plg[2].x - plg[1].x)) / det;</div><div>-    xf.eDx  = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -</div><div>-               rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +</div>

<div>-               rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)</div><div>-               ) / det;</div><div>+    xf.eM11 = -(rect[1].y*plg[2].x+rect[0].y*(plg[1].x-plg[2].x)</div><div>+<span style="white-space:pre-wrap">                </span>-rect[2].y*plg[1].x+plg[0].x*(rect[2].y-rect[1].y))</div>

<div>+<span style="white-space:pre-wrap">         </span>/(rect[0].y*(rect[2].x-rect[1].x)-rect[1].y*rect[2].x+</div><div>+<span style="white-space:pre-wrap">          </span>rect[2].y*rect[1].x+(rect[1].y-rect[2].y)*rect[0].x);</div>
<div>+    xf.eM21 = (plg[0].x*(rect[2].x-rect[1].x)-plg[1].x*rect[2].x</div><div>+<span style="white-space:pre-wrap">               </span>+plg[2].x*rect[1].x+(plg[1].x-plg[2].x)*rect[0].x)</div><div>+<span style="white-space:pre-wrap">              </span>/(rect[0].y*(rect[2].x-rect[1].x)-rect[1].y*rect[2].x</div>

<div>+<span style="white-space:pre-wrap">         </span>+rect[2].y*rect[1].x+(rect[1].y-rect[2].y)*rect[0].x);</div><div>+    xf.eDx = -(rect[0].y*(plg[2].x*rect[1].x-plg[1].x*rect[2].x)</div><div>+<span style="white-space:pre-wrap">                </span>+plg[0].x*(rect[1].y*rect[2].x-rect[2].y*rect[1].x)</div>

<div>+<span style="white-space:pre-wrap">         </span>+(rect[2].y*plg[1].x-rect[1].y*plg[2].x)*rect[0].x) </div><div>+<span style="white-space:pre-wrap">           </span>/(rect[0].y*(rect[2].x-rect[1].x)-rect[1].y*rect[2].x+rect[2].y</div>

<div>+<span style="white-space:pre-wrap">         </span>*rect[1].x+(rect[1].y-rect[2].y)*rect[0].x);</div><div> </div><div>     /* Y components */</div><div>-    xf.eM12 = (plg[1].y*(rect[2].y - rect[0].y) - plg[2].y*(rect[1].y - rect[0].y) - plg[0].y*(rect[2].y - rect[1].y)) / det;</div>

<div>-    xf.eM22 = (plg[1].x*(rect[2].y - rect[0].y) - plg[2].x*(rect[1].y - rect[0].y) - plg[0].x*(rect[2].y - rect[1].y)) / det;</div><div>-    xf.eDy  = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -</div><div>

-               rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +</div><div>-               rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)</div><div>-               ) / det;</div><div>+    xf.eM12 = -(rect[1].y*(plg[2].y-plg[0].y)+rect[0].y*(plg[1].y</div>

<div>+<span style="white-space:pre-wrap">         </span>-plg[2].y)+rect[2].y*(plg[0].y-plg[1].y))/(rect[0].y*(rect[2].x</div><div>+<span style="white-space:pre-wrap">         </span>-rect[1].x)-rect[1].y*rect[2].x+rect[2].y*rect[1].x+(rect[1].y</div>

<div>+<span style="white-space:pre-wrap">         </span>-rect[2].y)*rect[0].x);</div><div>+    xf.eM22 = ((plg[0].y-plg[1].y)*rect[2].x+(plg[2].y-plg[0].y)*rect[1].x</div><div>+<span style="white-space:pre-wrap">             </span>+(plg[1].y-plg[2].y)*rect[0].x) /(rect[0].y*(rect[2].x-rect[1].x)</div>

<div>+<span style="white-space:pre-wrap">         </span>-rect[1].y*rect[2].x+rect[2].y*rect[1].x+(rect[1].y-rect[2].y)</div><div>+<span style="white-space:pre-wrap">          </span>*rect[0].x);</div><div>+    xf.eDy = (rect[0].y*(plg[1].y*rect[2].x-plg[2].y*rect[1].x)</div>

<div>+<span style="white-space:pre-wrap">         </span>-rect[1].y*plg[0].y*rect[2].x+rect[2].y*plg[0].y*rect[1].x</div><div>+<span style="white-space:pre-wrap">              </span>+(rect[1].y*plg[2].y-rect[2].y*plg[1].y)*rect[0].x)/(rect[0].y</div>

<div>+<span style="white-space:pre-wrap">         </span>*(rect[2].x-rect[1].x)-rect[1].y*rect[2].x+rect[2].y*rect[1].x</div><div>+<span style="white-space:pre-wrap">          </span>+(rect[1].y-rect[2].y)*rect[0].x);</div><div>
 </div><div>     GetWorldTransform(hdcSrc,&SrcXf);</div><div>     CombineTransform(&xf,&xf,&SrcXf);</div></div><div><br></div></div>