1 /*
2  * PROJECT:         ReactOS api tests
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * PURPOSE:         Tests for SetLayout and its effects on other gdi functions
5  *                  such as StretchBlt, BitBlt, LPtoDP, DPtoLP
6  * PROGRAMMERS:     Baruch Rutman
7  *                  Inspired by the StretchBlt test
8  */
9 
10 #include "precomp.h"
11 
12 static void copy(PUINT32 buffer, UINT32 value, int width, int start_x, int start_y, int end_x, int end_y)
13 {
14     for (int y = start_y; y < end_y; y++)
15     {
16         for (int x = start_x; x < end_x; x++)
17             buffer[y * width + x] = value;
18     }
19 }
20 
21 #define BLACK_PIXEL 0x000000
22 #define BLUE_PIXEL  0x0000FF
23 #define GREEN_PIXEL 0x00FF00
24 #define RED_PIXEL   0xFF0000
25 #define WHITE_PIXEL 0xFFFFFF
26 
27 #if 0
28 #include "wincon.h"
29 
30 /* Draw the bitmap as colored letters on white background */
31 static void
32 dump(PUINT32 buffer, int width, LPCSTR title)
33 {
34     HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
35     CONSOLE_SCREEN_BUFFER_INFO info;
36 
37     GetConsoleScreenBufferInfo(hConsole, &info);
38 
39     if (title)
40         printf("%s", title);
41 
42     for (int i = 0; i < width * width; i++)
43     {
44         char c;
45         WORD attributes = 0;
46         UINT32 pixel_value = buffer[i];
47 
48         if (i % width == 0)
49         {
50             SetConsoleTextAttribute(hConsole, info.wAttributes);
51             putchar('\n');
52         }
53 
54         switch (pixel_value)
55         {
56             case WHITE_PIXEL:
57                 c = 'W';
58                 break;
59             case BLUE_PIXEL:
60                 c = 'B';
61                 break;
62             case GREEN_PIXEL:
63                 c = 'G';
64                 break;
65             case RED_PIXEL:
66                 c = 'R';
67                 break;
68             case BLACK_PIXEL:
69                 c = 'E'; /* Use 'E' for 'Empty' because 'B' is taken */
70                 break;
71             default:
72                 c = '?';
73         }
74 
75         if (pixel_value != WHITE_PIXEL && c != '?')
76         {
77             attributes = (pixel_value & RED_PIXEL) ? FOREGROUND_RED : 0 |
78                          (pixel_value & GREEN_PIXEL) ? FOREGROUND_GREEN : 0 |
79                          (pixel_value & BLUE_PIXEL) ? FOREGROUND_BLUE : 0;
80         }
81 
82         SetConsoleTextAttribute(hConsole, attributes | BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED);
83         putchar(c);
84     }
85     SetConsoleTextAttribute(hConsole, info.wAttributes);
86     putchar('\n');
87 }
88 #endif
89 
90 static void nomirror_test(PUINT32 dstBuffer, PUINT32 srcBuffer, int width, int line)
91 {
92     for (int y = 0; y < width; y++)
93     {
94         for (int x = 0; x < width; x++)
95         {
96             if (x == width - 1)
97             {
98                 ok(dstBuffer[y * width + x] == BLACK_PIXEL,
99                    "Expected blank (black) pixel (0x0), got (%06X), coordinates (%d, %d). line: %d\n",
100                    dstBuffer[y * width + x], x, y, line);
101             }
102             else
103             {
104                 ok(dstBuffer[y * width + x] == srcBuffer[y * width + x + 1],
105                    "Coordinates: (%d, %d), expected (%06X), got (%06X). line: %d\n",
106                    x, y, srcBuffer[y * width + x + 1], dstBuffer[y * width + x], line);
107             }
108         }
109     }
110 }
111 
112 #define WIDTH 10
113 START_TEST(SetLayout)
114 {
115     HBITMAP bmpDst, bmpSrc, oldDst, oldSrc;
116     HDC hdc, hdcDst, hdcSrc;
117     PUINT32 dstBuffer, srcBuffer;
118     BITMAPINFO info = { 0 };
119     size_t nBuf = WIDTH * WIDTH * sizeof(UINT32);
120 
121     hdc = CreateCompatibleDC(NULL);
122     hdcDst = CreateCompatibleDC(hdc);
123     hdcSrc = CreateCompatibleDC(hdc);
124 
125     info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
126     info.bmiHeader.biWidth = WIDTH;
127     info.bmiHeader.biHeight = -WIDTH;
128     info.bmiHeader.biPlanes = 1;
129     info.bmiHeader.biBitCount = 32;
130     info.bmiHeader.biCompression = BI_RGB;
131 
132     /* Create bitmaps to test with */
133     bmpSrc = CreateDIBSection(hdcSrc, &info, DIB_RGB_COLORS, (PVOID*)&srcBuffer, NULL, 0);
134     bmpDst = CreateDIBSection(hdcDst, &info, DIB_RGB_COLORS, (PVOID*)&dstBuffer, NULL, 0);
135 
136     if (!bmpSrc || !bmpDst)
137     {
138         skip("Failed to create bitmaps");
139         goto cleanup;
140     }
141 
142     oldSrc = SelectObject(hdcSrc, bmpSrc);
143     oldDst = SelectObject(hdcDst, bmpDst);
144 
145     /* Create base "image" for use in the tests */
146     copy(srcBuffer, WHITE_PIXEL, WIDTH, 0, 0, WIDTH / 2, WIDTH / 2);
147     copy(srcBuffer, BLUE_PIXEL, WIDTH, 0, WIDTH / 2, WIDTH / 2, WIDTH);
148     copy(srcBuffer, GREEN_PIXEL, WIDTH, WIDTH / 2, 0, WIDTH, WIDTH / 2);
149     copy(srcBuffer, RED_PIXEL, WIDTH, WIDTH / 2, WIDTH / 2, WIDTH, WIDTH);
150 
151     /* Mirror destination DC */
152     SetLayout(hdcDst, LAYOUT_RTL);
153     ok(GetLayout(hdcDst) == LAYOUT_RTL, "DC layout is not RTL\n");
154     ok(GetMapMode(hdcDst) == MM_ANISOTROPIC, "DC Map mode is not MM_ANISOTROPIC\n");
155 
156     /* Test RTL transform (using LPtoDP) and the inverse transform (DPtoLP) */
157     for (int y = 0; y < WIDTH; y++)
158     {
159         for (int x = 0; x < WIDTH; x++)
160         {
161             POINT pt = { x, y };
162             POINT mirrored = { WIDTH - 1 - x, y }; /* Expected results */
163 
164             LPtoDP(hdcDst, &pt, 1);
165             /* Test LPtoDP */
166             ok(pt.x == mirrored.x && pt.y == mirrored.y,
167               "Coodinates: (%d, %d), expected (%ld, %ld), got (%ld, %ld)\n",
168               x, y, mirrored.x, mirrored.y, pt.x, pt.y);
169 
170             pt = mirrored;
171 
172             /* Test DPtoLP */
173             DPtoLP(hdcDst, &pt, 1);
174             ok(pt.x == x && pt.y == y,
175                "Mirrored Coodinates: (%ld, %ld), expected (%d, %d), got (%ld, %ld)\n",
176                mirrored.x, mirrored.y, x, y, pt.x, pt.y);
177         }
178     }
179 
180     ZeroMemory(dstBuffer, nBuf);
181     StretchBlt(hdcDst, 0, 0, WIDTH, WIDTH, hdcSrc, 0, 0, WIDTH, WIDTH, SRCCOPY);
182     for (int y = 0; y < WIDTH; y++)
183     {
184         for (int x = 0; x < WIDTH; x++)
185         {
186             /* Test if the image is mirrored using the assumed RTL transform results */
187             ok(dstBuffer[y * WIDTH + (WIDTH - 1 - x)] == srcBuffer[y * WIDTH + x],
188                "Coordinates: (%d, %d), expected (%06X), got (%06X)\n",
189                x, y, srcBuffer[y * WIDTH + x], dstBuffer[y * WIDTH + (WIDTH - 1 - x)]);
190         }
191     }
192 
193     ZeroMemory(dstBuffer, nBuf);
194     StretchBlt(hdcDst, 0, 0, WIDTH, WIDTH, hdcSrc, 0, 0, WIDTH, WIDTH, SRCCOPY | NOMIRRORBITMAP);
195     nomirror_test(dstBuffer, srcBuffer, WIDTH, __LINE__);
196 
197     ZeroMemory(dstBuffer, nBuf);
198     BitBlt(hdcDst, 0, 0, WIDTH, WIDTH, hdcSrc, 0, 0, SRCCOPY);
199     for (int y = 0; y < WIDTH; y++)
200     {
201         for (int x = 0; x < WIDTH; x++)
202         {
203             /* Test if the image is mirrored using the assumed RTL transform results */
204             ok(dstBuffer[y * WIDTH + (WIDTH - 1 - x)] == srcBuffer[y * WIDTH + x],
205                "Coordinates: (%d, %d), expected (%06X), got (%06X)\n",
206                x, y, srcBuffer[y * WIDTH + x], dstBuffer[y * WIDTH + (WIDTH - 1 - x)]);
207         }
208     }
209 
210     ZeroMemory(dstBuffer, nBuf);
211     BitBlt(hdcDst, 0, 0, WIDTH, WIDTH, hdcSrc, 0, 0, SRCCOPY | NOMIRRORBITMAP);
212     nomirror_test(dstBuffer, srcBuffer, WIDTH, __LINE__);
213 
214     SetLayout(hdcDst, LAYOUT_RTL | LAYOUT_BITMAPORIENTATIONPRESERVED);
215 
216     ok(GetLayout(hdcDst) == (LAYOUT_RTL | LAYOUT_BITMAPORIENTATIONPRESERVED),
217        "DC Layout is not LAYOUT_RTL | LAYOUT_BITMAPORIENTATIONPRESERVED\n");
218     ok(GetMapMode(hdcDst) == MM_ANISOTROPIC, "DC Map mode is not MM_ANISOTROPIC\n");
219 
220     ZeroMemory(dstBuffer, nBuf);
221     StretchBlt(hdcDst, 0, 0, WIDTH, WIDTH, hdcSrc, 0, 0, WIDTH, WIDTH, SRCCOPY);
222     nomirror_test(dstBuffer, srcBuffer, WIDTH, __LINE__);
223 
224     ZeroMemory(dstBuffer, nBuf);
225     StretchBlt(hdcDst, 0, 0, WIDTH, WIDTH, hdcSrc, 0, 0, WIDTH, WIDTH, SRCCOPY | NOMIRRORBITMAP);
226     nomirror_test(dstBuffer, srcBuffer, WIDTH, __LINE__);
227 
228     ZeroMemory(dstBuffer, nBuf);
229     BitBlt(hdcDst, 0, 0, WIDTH, WIDTH, hdcSrc, 0, 0, SRCCOPY);
230     nomirror_test(dstBuffer, srcBuffer, WIDTH, __LINE__);
231 
232     ZeroMemory(dstBuffer, nBuf);
233     BitBlt(hdcDst, 0, 0, WIDTH, WIDTH, hdcSrc, 0, 0, SRCCOPY | NOMIRRORBITMAP);
234     nomirror_test(dstBuffer, srcBuffer, WIDTH, __LINE__);
235 
236     /* Reset DC layout to default (LTR) */
237     SetLayout(hdcDst, LAYOUT_LTR);
238     ok(GetLayout(hdcDst) == LAYOUT_LTR, "DC layout is not LAYOUT_LTR");
239 
240     for (int y = 0; y < WIDTH; y++)
241     {
242         for (int x = 0; x < WIDTH; x++)
243         {
244             POINT pt = { x, y };
245 
246             LPtoDP(hdcDst, &pt, 1);
247             /* Confirm that RTL transform is not the current one */
248             ok(pt.x == x && pt.y == y,
249                "Expected (%d, %d) got (%ld, %ld)\n", x, y, pt.x, pt.y);
250         }
251     }
252 
253     ZeroMemory(dstBuffer, nBuf);
254     StretchBlt(hdcDst, 0, 0, WIDTH, WIDTH, hdcSrc, 0, 0, WIDTH, WIDTH, SRCCOPY);
255     ok(memcmp(dstBuffer, srcBuffer, nBuf) == 0, "Bitmaps are not identical\n");
256 
257     SetLayout(hdcDst, LAYOUT_BITMAPORIENTATIONPRESERVED);
258     ok(GetLayout(hdcDst) == LAYOUT_BITMAPORIENTATIONPRESERVED, "DC Layout is not LAYOUT_BITMAPORIENTATIONPRESERVED");
259 
260     SelectObject(hdcSrc, oldSrc);
261     SelectObject(hdcDst, oldDst);
262     DeleteObject(bmpSrc);
263     DeleteObject(bmpDst);
264 cleanup:
265     DeleteDC(hdcSrc);
266     DeleteDC(hdcDst);
267     DeleteDC(hdc);
268 }
269