[NtGDI] Set Xform flags if a changed
[reactos.git] / win32ss / gdi / ntgdi / gdibatch.c
1
2 #include <win32k.h>
3
4 #define NDEBUG
5 #include <debug.h>
6
7 BOOL FASTCALL IntPatBlt( PDC,INT,INT,INT,INT,DWORD,PEBRUSHOBJ);
8 BOOL APIENTRY IntExtTextOutW(IN PDC,IN INT,IN INT,IN UINT,IN OPTIONAL PRECTL,IN LPCWSTR,IN INT,IN OPTIONAL LPINT,IN DWORD);
9
10
11 //
12 // Gdi Batch Flush support functions.
13 //
14
15 //
16 // DoDeviceSync
17 //
18 // based on IntEngEnter from eng/engmisc.c
19 //
20 VOID
21 FASTCALL
22 DoDeviceSync( SURFOBJ *Surface, PRECTL Rect, FLONG fl)
23 {
24 PPDEVOBJ Device = (PDEVOBJ*)Surface->hdev;
25 // No punting and "Handle to a surface, provided that the surface is device-managed.
26 // Otherwise, dhsurf is zero".
27 if (!(Device->flFlags & PDEV_DRIVER_PUNTED_CALL) && (Surface->dhsurf))
28 {
29 if (Device->DriverFunctions.SynchronizeSurface)
30 {
31 Device->DriverFunctions.SynchronizeSurface(Surface, Rect, fl);
32 }
33 else
34 {
35 if (Device->DriverFunctions.Synchronize)
36 {
37 Device->DriverFunctions.Synchronize(Surface->dhpdev, Rect);
38 }
39 }
40 }
41 }
42
43 VOID
44 FASTCALL
45 SynchronizeDriver(FLONG Flags)
46 {
47 SURFOBJ *SurfObj;
48 //PPDEVOBJ Device;
49
50 if (Flags & GCAPS2_SYNCFLUSH)
51 Flags = DSS_FLUSH_EVENT;
52 if (Flags & GCAPS2_SYNCTIMER)
53 Flags = DSS_TIMER_EVENT;
54
55 //Device = IntEnumHDev();
56 // UNIMPLEMENTED;
57 //ASSERT(FALSE);
58 SurfObj = 0;// EngLockSurface( Device->pSurface );
59 if(!SurfObj) return;
60 DoDeviceSync( SurfObj, NULL, Flags);
61 EngUnlockSurface(SurfObj);
62 return;
63 }
64
65 //
66 // Process the batch.
67 //
68 ULONG
69 FASTCALL
70 GdiFlushUserBatch(PDC dc, PGDIBATCHHDR pHdr)
71 {
72 ULONG Cmd = 0, Size = 0;
73 PDC_ATTR pdcattr = NULL;
74
75 if (dc)
76 {
77 pdcattr = dc->pdcattr;
78 }
79
80 _SEH2_TRY
81 {
82 Cmd = pHdr->Cmd;
83 Size = pHdr->Size; // Return the full size of the structure.
84 }
85 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
86 {
87 DPRINT1("WARNING! GdiBatch Fault!\n");
88 _SEH2_YIELD(return 0;)
89 }
90 _SEH2_END;
91
92 switch(Cmd)
93 {
94 case GdiBCPatBlt:
95 {
96 PGDIBSPATBLT pgDPB;
97 DWORD dwRop, flags;
98 HBRUSH hOrgBrush;
99 COLORREF crColor, crBkColor, crBrushClr;
100 ULONG ulForegroundClr, ulBackgroundClr, ulBrushClr;
101 if (!dc) break;
102 pgDPB = (PGDIBSPATBLT) pHdr;
103 /* Convert the ROP3 to a ROP4 */
104 dwRop = pgDPB->dwRop;
105 dwRop = MAKEROP4(dwRop & 0xFF0000, dwRop);
106 /* Check if the rop uses a source */
107 if (WIN32_ROP4_USES_SOURCE(dwRop))
108 {
109 /* This is not possible */
110 break;
111 }
112 /* Check if the DC has no surface (empty mem or info DC) */
113 if (dc->dclevel.pSurface == NULL)
114 {
115 /* Nothing to do */
116 break;
117 }
118 // Save current attributes and flags
119 crColor = dc->pdcattr->crForegroundClr;
120 crBkColor = dc->pdcattr->ulBackgroundClr;
121 crBrushClr = dc->pdcattr->crBrushClr;
122 ulForegroundClr = dc->pdcattr->ulForegroundClr;
123 ulBackgroundClr = dc->pdcattr->ulBackgroundClr;
124 ulBrushClr = dc->pdcattr->ulBrushClr;
125 hOrgBrush = dc->pdcattr->hbrush;
126 flags = dc->pdcattr->ulDirty_ & (DIRTY_BACKGROUND | DIRTY_TEXT | DIRTY_FILL | DC_BRUSH_DIRTY);
127 // Set the attribute snapshot
128 dc->pdcattr->hbrush = pgDPB->hbrush;
129 dc->pdcattr->crForegroundClr = pgDPB->crForegroundClr;
130 dc->pdcattr->crBackgroundClr = pgDPB->crBackgroundClr;
131 dc->pdcattr->crBrushClr = pgDPB->crBrushClr;
132 dc->pdcattr->ulForegroundClr = pgDPB->ulForegroundClr;
133 dc->pdcattr->ulBackgroundClr = pgDPB->ulBackgroundClr;
134 dc->pdcattr->ulBrushClr = pgDPB->ulBrushClr;
135 // Process dirty attributes if any.
136 if (dc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
137 DC_vUpdateFillBrush(dc);
138 if (dc->pdcattr->ulDirty_ & DIRTY_TEXT)
139 DC_vUpdateTextBrush(dc);
140 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
141 DC_vUpdateBackgroundBrush(dc);
142 /* Call the internal function */
143 IntPatBlt(dc, pgDPB->nXLeft, pgDPB->nYLeft, pgDPB->nWidth, pgDPB->nHeight, dwRop, &dc->eboFill);
144 // Restore attributes and flags
145 dc->pdcattr->hbrush = hOrgBrush;
146 dc->pdcattr->crForegroundClr = crColor;
147 dc->pdcattr->crBackgroundClr = crBkColor;
148 dc->pdcattr->crBrushClr = crBrushClr;
149 dc->pdcattr->ulForegroundClr = ulForegroundClr;
150 dc->pdcattr->ulBackgroundClr = ulBackgroundClr;
151 dc->pdcattr->ulBrushClr = ulBrushClr;
152 dc->pdcattr->ulDirty_ |= flags;
153 break;
154 }
155
156 case GdiBCPolyPatBlt:
157 {
158 PGDIBSPPATBLT pgDPB;
159 EBRUSHOBJ eboFill;
160 PBRUSH pbrush;
161 PPATRECT pRects;
162 INT i;
163 DWORD dwRop, flags;
164 COLORREF crColor, crBkColor, crBrushClr;
165 ULONG ulForegroundClr, ulBackgroundClr, ulBrushClr;
166 if (!dc) break;
167 pgDPB = (PGDIBSPPATBLT) pHdr;
168 /* Convert the ROP3 to a ROP4 */
169 dwRop = pgDPB->rop4;
170 dwRop = MAKEROP4(dwRop & 0xFF0000, dwRop);
171 /* Check if the rop uses a source */
172 if (WIN32_ROP4_USES_SOURCE(dwRop))
173 {
174 /* This is not possible */
175 break;
176 }
177 /* Check if the DC has no surface (empty mem or info DC) */
178 if (dc->dclevel.pSurface == NULL)
179 {
180 /* Nothing to do */
181 break;
182 }
183 // Save current attributes and flags
184 crColor = dc->pdcattr->crForegroundClr;
185 crBkColor = dc->pdcattr->ulBackgroundClr;
186 crBrushClr = dc->pdcattr->crBrushClr;
187 ulForegroundClr = dc->pdcattr->ulForegroundClr;
188 ulBackgroundClr = dc->pdcattr->ulBackgroundClr;
189 ulBrushClr = dc->pdcattr->ulBrushClr;
190 flags = dc->pdcattr->ulDirty_ & (DIRTY_BACKGROUND | DIRTY_TEXT | DIRTY_FILL | DC_BRUSH_DIRTY);
191 // Set the attribute snapshot
192 dc->pdcattr->crForegroundClr = pgDPB->crForegroundClr;
193 dc->pdcattr->crBackgroundClr = pgDPB->crBackgroundClr;
194 dc->pdcattr->crBrushClr = pgDPB->crBrushClr;
195 dc->pdcattr->ulForegroundClr = pgDPB->ulForegroundClr;
196 dc->pdcattr->ulBackgroundClr = pgDPB->ulBackgroundClr;
197 dc->pdcattr->ulBrushClr = pgDPB->ulBrushClr;
198 // Process dirty attributes if any
199 if (dc->pdcattr->ulDirty_ & DIRTY_TEXT)
200 DC_vUpdateTextBrush(dc);
201 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
202 DC_vUpdateBackgroundBrush(dc);
203
204 DPRINT1("GdiBCPolyPatBlt Testing\n");
205 pRects = &pgDPB->pRect[0];
206
207 for (i = 0; i < pgDPB->Count; i++)
208 {
209 pbrush = BRUSH_ShareLockBrush(pRects->hBrush);
210
211 /* Check if we could lock the brush */
212 if (pbrush != NULL)
213 {
214 /* Initialize a brush object */
215 EBRUSHOBJ_vInitFromDC(&eboFill, pbrush, dc);
216
217 IntPatBlt(
218 dc,
219 pRects->r.left,
220 pRects->r.top,
221 pRects->r.right,
222 pRects->r.bottom,
223 dwRop,
224 &eboFill);
225
226 /* Cleanup the brush object and unlock the brush */
227 EBRUSHOBJ_vCleanup(&eboFill);
228 BRUSH_ShareUnlockBrush(pbrush);
229 }
230 pRects++;
231 }
232
233 // Restore attributes and flags
234 dc->pdcattr->crForegroundClr = crColor;
235 dc->pdcattr->crBackgroundClr = crBkColor;
236 dc->pdcattr->crBrushClr = crBrushClr;
237 dc->pdcattr->ulForegroundClr = ulForegroundClr;
238 dc->pdcattr->ulBackgroundClr = ulBackgroundClr;
239 dc->pdcattr->ulBrushClr = ulBrushClr;
240 dc->pdcattr->ulDirty_ |= flags;
241 break;
242 }
243
244 case GdiBCTextOut:
245 {
246 PGDIBSTEXTOUT pgO;
247 COLORREF crColor = -1, crBkColor;
248 ULONG ulForegroundClr, ulBackgroundClr;
249 DWORD flags = 0, flXform = 0, saveflags, saveflXform = 0;
250 FLONG flTextAlign = -1;
251 HANDLE hlfntNew;
252 PRECTL lprc;
253 USHORT jBkMode;
254 LONG lBkMode;
255 POINTL ptlViewportOrg;
256 if (!dc) break;
257 pgO = (PGDIBSTEXTOUT) pHdr;
258
259 // Save current attributes, flags and Set the attribute snapshots
260 saveflags = dc->pdcattr->ulDirty_ & (DIRTY_BACKGROUND|DIRTY_LINE|DIRTY_TEXT|DIRTY_FILL|DC_BRUSH_DIRTY|DIRTY_CHARSET);
261
262 // In this instance check for differences and set the appropriate dirty flags.
263 if ( dc->pdcattr->crForegroundClr != pgO->crForegroundClr)
264 {
265 crColor = dc->pdcattr->crForegroundClr;
266 dc->pdcattr->crForegroundClr = pgO->crForegroundClr;
267 ulForegroundClr = dc->pdcattr->ulForegroundClr;
268 dc->pdcattr->ulForegroundClr = pgO->ulForegroundClr;
269 flags |= (DIRTY_FILL|DIRTY_LINE|DIRTY_TEXT);
270 }
271 if (dc->pdcattr->crBackgroundClr != pgO->crBackgroundClr)
272 {
273 crBkColor = dc->pdcattr->ulBackgroundClr;
274 dc->pdcattr->crBackgroundClr = pgO->crBackgroundClr;
275 ulBackgroundClr = dc->pdcattr->ulBackgroundClr;
276 dc->pdcattr->ulBackgroundClr = pgO->ulBackgroundClr;
277 flags |= (DIRTY_FILL|DIRTY_LINE|DIRTY_TEXT|DIRTY_BACKGROUND);
278 }
279 if (dc->pdcattr->flTextAlign != pgO->flTextAlign)
280 {
281 flTextAlign = dc->pdcattr->flTextAlign;
282 dc->pdcattr->flTextAlign = pgO->flTextAlign;
283 }
284 if (dc->pdcattr->hlfntNew != pgO->hlfntNew)
285 {
286 hlfntNew = dc->pdcattr->hlfntNew;
287 dc->pdcattr->hlfntNew = pgO->hlfntNew;
288 dc->pdcattr->ulDirty_ &= ~SLOW_WIDTHS;
289 flags |= DIRTY_CHARSET;
290 }
291
292 if ( dc->pdcattr->ptlViewportOrg.x != pgO->ptlViewportOrg.x ||
293 dc->pdcattr->ptlViewportOrg.y != pgO->ptlViewportOrg.y )
294 {
295 saveflXform = dc->pdcattr->flXform & (PAGE_XLATE_CHANGED|WORLD_XFORM_CHANGED|DEVICE_TO_WORLD_INVALID);
296 ptlViewportOrg = dc->pdcattr->ptlViewportOrg;
297 dc->pdcattr->ptlViewportOrg = pgO->ptlViewportOrg;
298 flXform = (PAGE_XLATE_CHANGED|WORLD_XFORM_CHANGED|DEVICE_TO_WORLD_INVALID);
299 }
300
301 dc->pdcattr->flXform |= flXform;
302 dc->pdcattr->ulDirty_ |= flags;
303
304 jBkMode = dc->pdcattr->jBkMode;
305 dc->pdcattr->jBkMode = pgO->lBkMode;
306 lBkMode = dc->pdcattr->lBkMode;
307 dc->pdcattr->lBkMode = pgO->lBkMode;
308
309 lprc = (pgO->Options & GDIBS_NORECT) ? NULL : &pgO->Rect;
310 pgO->Options &= ~GDIBS_NORECT;
311
312 IntExtTextOutW( dc,
313 pgO->x,
314 pgO->y,
315 pgO->Options,
316 lprc,
317 (LPCWSTR)&pgO->String[pgO->Size/sizeof(WCHAR)],
318 pgO->cbCount,
319 pgO->Size ? (LPINT)&pgO->Buffer : NULL,
320 pgO->iCS_CP );
321
322 // Restore attributes and flags
323 dc->pdcattr->jBkMode = jBkMode;
324 dc->pdcattr->lBkMode = lBkMode;
325
326 if (saveflXform)
327 {
328 dc->pdcattr->ptlViewportOrg = ptlViewportOrg;
329 dc->pdcattr->flXform |= saveflXform|flXform;
330 }
331
332 if (flags & DIRTY_TEXT && crColor != -1)
333 {
334 dc->pdcattr->crForegroundClr = crColor;
335 dc->pdcattr->ulForegroundClr = ulForegroundClr;
336 }
337 if (flags & DIRTY_BACKGROUND)
338 {
339 dc->pdcattr->crBackgroundClr = crBkColor;
340 dc->pdcattr->ulBackgroundClr = ulBackgroundClr;
341 }
342 if (flTextAlign != -1)
343 {
344 dc->pdcattr->flTextAlign = flTextAlign;
345 }
346
347 if (flags & DIRTY_CHARSET)
348 {
349 dc->pdcattr->hlfntNew = hlfntNew;
350 dc->pdcattr->ulDirty_ &= ~SLOW_WIDTHS;
351 }
352 dc->pdcattr->ulDirty_ |= saveflags | flags;
353 break;
354 }
355
356 case GdiBCExtTextOut:
357 {
358 PGDIBSEXTTEXTOUT pgO;
359 COLORREF crBkColor;
360 ULONG ulBackgroundClr;
361 POINTL ptlViewportOrg;
362 DWORD flags = 0, flXform = 0, saveflags, saveflXform = 0;
363 if (!dc) break;
364 pgO = (PGDIBSEXTTEXTOUT) pHdr;
365
366 saveflags = dc->pdcattr->ulDirty_ & (DIRTY_BACKGROUND|DIRTY_TEXT|DIRTY_FILL|DC_BRUSH_DIRTY|DIRTY_CHARSET);
367
368 if (dc->pdcattr->crBackgroundClr != pgO->ulBackgroundClr)
369 {
370 crBkColor = dc->pdcattr->crBackgroundClr;
371 ulBackgroundClr = dc->pdcattr->ulBackgroundClr;
372 dc->pdcattr->crBackgroundClr = pgO->ulBackgroundClr;
373 dc->pdcattr->ulBackgroundClr = pgO->ulBackgroundClr;
374 flags |= (DIRTY_BACKGROUND|DIRTY_LINE|DIRTY_FILL);
375 }
376
377 if ( dc->pdcattr->ptlViewportOrg.x != pgO->ptlViewportOrg.x ||
378 dc->pdcattr->ptlViewportOrg.y != pgO->ptlViewportOrg.y )
379 {
380 saveflXform = dc->pdcattr->flXform & (PAGE_XLATE_CHANGED|WORLD_XFORM_CHANGED|DEVICE_TO_WORLD_INVALID);
381 ptlViewportOrg = dc->pdcattr->ptlViewportOrg;
382 dc->pdcattr->ptlViewportOrg = pgO->ptlViewportOrg;
383 flXform = (PAGE_XLATE_CHANGED|WORLD_XFORM_CHANGED|DEVICE_TO_WORLD_INVALID);
384 }
385
386 dc->pdcattr->flXform |= flXform;
387 dc->pdcattr->ulDirty_ |= flags;
388
389 IntExtTextOutW( dc,
390 0,
391 0,
392 pgO->Options,
393 &pgO->Rect,
394 NULL,
395 pgO->Count,
396 NULL,
397 0 );
398
399 if (saveflXform)
400 {
401 dc->pdcattr->ptlViewportOrg = ptlViewportOrg;
402 dc->pdcattr->flXform |= saveflXform|flXform;
403 }
404
405 if (flags & DIRTY_BACKGROUND)
406 {
407 dc->pdcattr->crBackgroundClr = crBkColor;
408 dc->pdcattr->ulBackgroundClr = ulBackgroundClr;
409 }
410 dc->pdcattr->ulDirty_ |= saveflags | flags;
411 break;
412 }
413
414 case GdiBCSetBrushOrg:
415 {
416 PGDIBSSETBRHORG pgSBO;
417 if (!dc) break;
418 pgSBO = (PGDIBSSETBRHORG) pHdr;
419 pdcattr->ptlBrushOrigin = pgSBO->ptlBrushOrigin;
420 DC_vSetBrushOrigin(dc, pgSBO->ptlBrushOrigin.x, pgSBO->ptlBrushOrigin.y);
421 break;
422 }
423
424 case GdiBCExtSelClipRgn:
425 break;
426
427 case GdiBCSelObj:
428 {
429 PGDIBSOBJECT pgO;
430
431 if (!dc) break;
432 pgO = (PGDIBSOBJECT) pHdr;
433
434 DC_hSelectFont(dc, (HFONT)pgO->hgdiobj);
435 break;
436 }
437
438 case GdiBCDelRgn:
439 DPRINT("Delete Region Object!\n");
440 /* Fall through */
441 case GdiBCDelObj:
442 {
443 PGDIBSOBJECT pgO = (PGDIBSOBJECT) pHdr;
444 GreDeleteObject( pgO->hgdiobj );
445 break;
446 }
447
448 default:
449 break;
450 }
451
452 return Size;
453 }
454
455 /*
456 * NtGdiFlush
457 *
458 * Flushes the calling thread's current batch.
459 */
460 __kernel_entry
461 NTSTATUS
462 APIENTRY
463 NtGdiFlush(
464 VOID)
465 {
466 SynchronizeDriver(GCAPS2_SYNCFLUSH);
467 return STATUS_SUCCESS;
468 }
469
470 /*
471 * NtGdiFlushUserBatch
472 *
473 * Callback for thread batch flush routine.
474 *
475 * Think small & fast!
476 */
477 NTSTATUS
478 APIENTRY
479 NtGdiFlushUserBatch(VOID)
480 {
481 PTEB pTeb = NtCurrentTeb();
482 ULONG GdiBatchCount = pTeb->GdiBatchCount;
483
484 if( (GdiBatchCount > 0) && (GdiBatchCount <= (GDIBATCHBUFSIZE/4)))
485 {
486 HDC hDC = (HDC) pTeb->GdiTebBatch.HDC;
487
488 /* If hDC is zero and the buffer fills up with delete objects we need
489 to run anyway.
490 */
491 if (hDC || GdiBatchCount)
492 {
493 PCHAR pHdr = (PCHAR)&pTeb->GdiTebBatch.Buffer[0];
494 PDC pDC = NULL;
495
496 if (GDI_HANDLE_GET_TYPE(hDC) == GDILoObjType_LO_DC_TYPE && GreIsHandleValid(hDC))
497 {
498 pDC = DC_LockDc(hDC);
499 }
500
501 // No need to init anything, just go!
502 for (; GdiBatchCount > 0; GdiBatchCount--)
503 {
504 ULONG Size;
505 // Process Gdi Batch!
506 Size = GdiFlushUserBatch(pDC, (PGDIBATCHHDR) pHdr);
507 if (!Size) break;
508 pHdr += Size;
509 }
510
511 if (pDC)
512 {
513 DC_UnlockDc(pDC);
514 }
515
516 // Exit and clear out for the next round.
517 pTeb->GdiTebBatch.Offset = 0;
518 pTeb->GdiBatchCount = 0;
519 pTeb->GdiTebBatch.HDC = 0;
520 }
521 }
522
523 // FIXME: On Windows XP the function returns &pTeb->RealClientId, maybe VOID?
524 return STATUS_SUCCESS;
525 }
526
527