xref: /reactos/win32ss/gdi/ntgdi/gdibatch.c (revision 1734f297)
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         dc->pdcattr->flXform  |= saveflXform | flXform;
354         break;
355      }
356 
357      case GdiBCExtTextOut:
358      {
359         PGDIBSEXTTEXTOUT pgO;
360         COLORREF crBkColor;
361         ULONG ulBackgroundClr;
362         POINTL ptlViewportOrg;
363         DWORD flags = 0, flXform = 0, saveflags, saveflXform = 0;
364         if (!dc) break;
365         pgO = (PGDIBSEXTTEXTOUT) pHdr;
366 
367         saveflags = dc->pdcattr->ulDirty_ & (DIRTY_BACKGROUND|DIRTY_TEXT|DIRTY_FILL|DC_BRUSH_DIRTY|DIRTY_CHARSET);
368 
369         if (dc->pdcattr->crBackgroundClr != pgO->ulBackgroundClr)
370         {
371             crBkColor = dc->pdcattr->crBackgroundClr;
372             ulBackgroundClr = dc->pdcattr->ulBackgroundClr;
373             dc->pdcattr->crBackgroundClr = pgO->ulBackgroundClr;
374             dc->pdcattr->ulBackgroundClr = pgO->ulBackgroundClr;
375             flags |= (DIRTY_BACKGROUND|DIRTY_LINE|DIRTY_FILL);
376         }
377 
378         if ( dc->pdcattr->ptlViewportOrg.x != pgO->ptlViewportOrg.x ||
379              dc->pdcattr->ptlViewportOrg.y != pgO->ptlViewportOrg.y )
380         {
381             saveflXform = dc->pdcattr->flXform & (PAGE_XLATE_CHANGED|WORLD_XFORM_CHANGED|DEVICE_TO_WORLD_INVALID);
382             ptlViewportOrg = dc->pdcattr->ptlViewportOrg;
383             dc->pdcattr->ptlViewportOrg = pgO->ptlViewportOrg;
384             flXform = (PAGE_XLATE_CHANGED|WORLD_XFORM_CHANGED|DEVICE_TO_WORLD_INVALID);
385         }
386 
387         dc->pdcattr->flXform  |= flXform;
388         dc->pdcattr->ulDirty_ |= flags;
389 
390         IntExtTextOutW( dc,
391                         0,
392                         0,
393                         pgO->Options,
394                        &pgO->Rect,
395                         NULL,
396                         pgO->Count,
397                         NULL,
398                         0 );
399 
400         if (saveflXform)
401         {
402             dc->pdcattr->ptlViewportOrg = ptlViewportOrg;
403             dc->pdcattr->flXform |= saveflXform|flXform;
404         }
405 
406         if (flags & DIRTY_BACKGROUND)
407         {
408             dc->pdcattr->crBackgroundClr = crBkColor;
409             dc->pdcattr->ulBackgroundClr = ulBackgroundClr;
410         }
411         dc->pdcattr->ulDirty_ |= saveflags | flags;
412         dc->pdcattr->flXform  |= saveflXform | flXform;
413         break;
414      }
415 
416      case GdiBCSetBrushOrg:
417      {
418         PGDIBSSETBRHORG pgSBO;
419         if (!dc) break;
420         pgSBO = (PGDIBSSETBRHORG) pHdr;
421         pdcattr->ptlBrushOrigin = pgSBO->ptlBrushOrigin;
422         DC_vSetBrushOrigin(dc, pgSBO->ptlBrushOrigin.x, pgSBO->ptlBrushOrigin.y);
423         break;
424      }
425 
426      case GdiBCExtSelClipRgn:
427      {
428         PGDIBSEXTSELCLPRGN pgO;
429         if (!dc) break;
430         pgO = (PGDIBSEXTSELCLPRGN) pHdr;
431         IntGdiExtSelectClipRect( dc, &pgO->rcl, pgO->fnMode);
432         break;
433      }
434 
435      case GdiBCSelObj:
436      {
437         PGDIBSOBJECT pgO;
438 
439         if (!dc) break;
440         pgO = (PGDIBSOBJECT) pHdr;
441 
442         DC_hSelectFont(dc, (HFONT)pgO->hgdiobj);
443         break;
444      }
445 
446      case GdiBCDelRgn:
447         DPRINT("Delete Region Object!\n");
448         /* Fall through */
449      case GdiBCDelObj:
450      {
451         PGDIBSOBJECT pgO = (PGDIBSOBJECT) pHdr;
452         GreDeleteObject( pgO->hgdiobj );
453         break;
454      }
455 
456      default:
457         break;
458   }
459 
460   return Size;
461 }
462 
463 /*
464  * NtGdiFlush
465  *
466  * Flushes the calling thread's current batch.
467  */
468 __kernel_entry
469 NTSTATUS
470 APIENTRY
471 NtGdiFlush(
472     VOID)
473 {
474     SynchronizeDriver(GCAPS2_SYNCFLUSH);
475     return STATUS_SUCCESS;
476 }
477 
478 /*
479  * NtGdiFlushUserBatch
480  *
481  * Callback for thread batch flush routine.
482  *
483  * Think small & fast!
484  */
485 NTSTATUS
486 APIENTRY
487 NtGdiFlushUserBatch(VOID)
488 {
489   PTEB pTeb = NtCurrentTeb();
490   ULONG GdiBatchCount = pTeb->GdiBatchCount;
491 
492   if( (GdiBatchCount > 0) && (GdiBatchCount <= (GDIBATCHBUFSIZE/4)))
493   {
494     HDC hDC = (HDC) pTeb->GdiTebBatch.HDC;
495 
496     /*  If hDC is zero and the buffer fills up with delete objects we need
497         to run anyway.
498      */
499     if (hDC || GdiBatchCount)
500     {
501       PCHAR pHdr = (PCHAR)&pTeb->GdiTebBatch.Buffer[0];
502       PDC pDC = NULL;
503 
504       if (GDI_HANDLE_GET_TYPE(hDC) == GDILoObjType_LO_DC_TYPE && GreIsHandleValid(hDC))
505       {
506           pDC = DC_LockDc(hDC);
507       }
508 
509        // No need to init anything, just go!
510        for (; GdiBatchCount > 0; GdiBatchCount--)
511        {
512            ULONG Size;
513            // Process Gdi Batch!
514            Size = GdiFlushUserBatch(pDC, (PGDIBATCHHDR) pHdr);
515            if (!Size) break;
516            pHdr += Size;
517        }
518 
519        if (pDC)
520        {
521            DC_UnlockDc(pDC);
522        }
523 
524        // Exit and clear out for the next round.
525        pTeb->GdiTebBatch.Offset = 0;
526        pTeb->GdiBatchCount = 0;
527        pTeb->GdiTebBatch.HDC = 0;
528     }
529   }
530 
531   // FIXME: On Windows XP the function returns &pTeb->RealClientId, maybe VOID?
532   return STATUS_SUCCESS;
533 }
534