xref: /reactos/win32ss/gdi/ntgdi/gdibatch.c (revision 23373acb)
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, saveflags;
250         FLONG flTextAlign = -1;
251         HANDLE hlfntNew;
252         PRECTL lprc;
253         USHORT jBkMode;
254         LONG lBkMode;
255         if (!dc) break;
256         pgO = (PGDIBSTEXTOUT) pHdr;
257 
258         // Save current attributes, flags and Set the attribute snapshots
259         saveflags = dc->pdcattr->ulDirty_ & (DIRTY_BACKGROUND|DIRTY_LINE|DIRTY_TEXT|DIRTY_FILL|DC_BRUSH_DIRTY|DIRTY_CHARSET);
260 
261         // In this instance check for differences and set the appropriate dirty flags.
262         if ( dc->pdcattr->crForegroundClr != pgO->crForegroundClr)
263         {
264             crColor = dc->pdcattr->crForegroundClr;
265             dc->pdcattr->crForegroundClr = pgO->crForegroundClr;
266             ulForegroundClr = dc->pdcattr->ulForegroundClr;
267             dc->pdcattr->ulForegroundClr = pgO->ulForegroundClr;
268             flags |= (DIRTY_FILL|DIRTY_LINE|DIRTY_TEXT);
269         }
270         if (dc->pdcattr->crBackgroundClr != pgO->crBackgroundClr)
271         {
272             crBkColor = dc->pdcattr->ulBackgroundClr;
273             dc->pdcattr->crBackgroundClr = pgO->crBackgroundClr;
274             ulBackgroundClr = dc->pdcattr->ulBackgroundClr;
275             dc->pdcattr->ulBackgroundClr = pgO->ulBackgroundClr;
276             flags |= (DIRTY_FILL|DIRTY_LINE|DIRTY_TEXT|DIRTY_BACKGROUND);
277         }
278         if (dc->pdcattr->flTextAlign != pgO->flTextAlign)
279         {
280             flTextAlign = dc->pdcattr->flTextAlign;
281             dc->pdcattr->flTextAlign = pgO->flTextAlign;
282         }
283         if (dc->pdcattr->hlfntNew != pgO->hlfntNew)
284         {
285             hlfntNew = dc->pdcattr->hlfntNew;
286             dc->pdcattr->hlfntNew = pgO->hlfntNew;
287             dc->pdcattr->ulDirty_ &= ~SLOW_WIDTHS;
288             flags |= DIRTY_CHARSET;
289         }
290 
291         dc->pdcattr->ulDirty_ |= flags;
292 
293         jBkMode = dc->pdcattr->jBkMode;
294         dc->pdcattr->jBkMode = pgO->lBkMode;
295         lBkMode = dc->pdcattr->lBkMode;
296         dc->pdcattr->lBkMode = pgO->lBkMode;
297 
298         lprc = (pgO->Options & GDIBS_NORECT) ? NULL : &pgO->Rect;
299         pgO->Options &= ~GDIBS_NORECT;
300 
301         IntExtTextOutW( dc,
302                         pgO->x,
303                         pgO->y,
304                         pgO->Options,
305                         lprc,
306                         (LPCWSTR)&pgO->String[pgO->Size/sizeof(WCHAR)],
307                         pgO->cbCount,
308                         pgO->Size ? (LPINT)&pgO->Buffer : NULL,
309                         pgO->iCS_CP );
310 
311         // Restore attributes and flags
312         dc->pdcattr->jBkMode = jBkMode;
313         dc->pdcattr->lBkMode = lBkMode;
314 
315         if (flags & DIRTY_TEXT && crColor != -1)
316         {
317             dc->pdcattr->crForegroundClr = crColor;
318             dc->pdcattr->ulForegroundClr = ulForegroundClr;
319         }
320         if (flags & DIRTY_BACKGROUND)
321         {
322             dc->pdcattr->crBackgroundClr = crBkColor;
323             dc->pdcattr->ulBackgroundClr = ulBackgroundClr;
324         }
325         if (flTextAlign != -1)
326         {
327             dc->pdcattr->flTextAlign = flTextAlign;
328         }
329 
330         if (flags & DIRTY_CHARSET)
331         {
332            dc->pdcattr->hlfntNew = hlfntNew;
333            dc->pdcattr->ulDirty_ &= ~SLOW_WIDTHS;
334         }
335         dc->pdcattr->ulDirty_ |= saveflags | flags;
336         break;
337      }
338 
339      case GdiBCExtTextOut:
340      {
341         PGDIBSEXTTEXTOUT pgO;
342         COLORREF crBkColor;
343         ULONG ulBackgroundClr;
344         DWORD flags = 0, saveflags;
345         if (!dc) break;
346         pgO = (PGDIBSEXTTEXTOUT) pHdr;
347 
348         saveflags = dc->pdcattr->ulDirty_ & (DIRTY_BACKGROUND|DIRTY_TEXT|DIRTY_FILL|DC_BRUSH_DIRTY|DIRTY_CHARSET);
349 
350         if (dc->pdcattr->crBackgroundClr != pgO->ulBackgroundClr)
351         {
352             crBkColor = dc->pdcattr->crBackgroundClr;
353             ulBackgroundClr = dc->pdcattr->ulBackgroundClr;
354             dc->pdcattr->crBackgroundClr = pgO->ulBackgroundClr;
355             dc->pdcattr->ulBackgroundClr = pgO->ulBackgroundClr;
356             flags |= (DIRTY_BACKGROUND|DIRTY_LINE|DIRTY_FILL);
357         }
358 
359         dc->pdcattr->ulDirty_ |= flags;
360 
361         IntExtTextOutW( dc,
362                         0,
363                         0,
364                         pgO->Options,
365                        &pgO->Rect,
366                         NULL,
367                         pgO->Count,
368                         NULL,
369                         0 );
370 
371         if (flags & DIRTY_BACKGROUND)
372         {
373             dc->pdcattr->crBackgroundClr = crBkColor;
374             dc->pdcattr->ulBackgroundClr = ulBackgroundClr;
375         }
376         dc->pdcattr->ulDirty_ |= saveflags | flags;
377         break;
378      }
379 
380      case GdiBCSetBrushOrg:
381      {
382         PGDIBSSETBRHORG pgSBO;
383         if (!dc) break;
384         pgSBO = (PGDIBSSETBRHORG) pHdr;
385         pdcattr->ptlBrushOrigin = pgSBO->ptlBrushOrigin;
386         DC_vSetBrushOrigin(dc, pgSBO->ptlBrushOrigin.x, pgSBO->ptlBrushOrigin.y);
387         break;
388      }
389 
390      case GdiBCExtSelClipRgn:
391         break;
392 
393      case GdiBCSelObj:
394      {
395         PGDIBSOBJECT pgO;
396 
397         if (!dc) break;
398         pgO = (PGDIBSOBJECT) pHdr;
399 
400         DC_hSelectFont(dc, (HFONT)pgO->hgdiobj);
401         break;
402      }
403 
404      case GdiBCDelRgn:
405         DPRINT("Delete Region Object!\n");
406         /* Fall through */
407      case GdiBCDelObj:
408      {
409         PGDIBSOBJECT pgO = (PGDIBSOBJECT) pHdr;
410         GreDeleteObject( pgO->hgdiobj );
411         break;
412      }
413 
414      default:
415         break;
416   }
417 
418   return Size;
419 }
420 
421 /*
422  * NtGdiFlush
423  *
424  * Flushes the calling thread's current batch.
425  */
426 __kernel_entry
427 NTSTATUS
428 APIENTRY
429 NtGdiFlush(
430     VOID)
431 {
432     SynchronizeDriver(GCAPS2_SYNCFLUSH);
433     return STATUS_SUCCESS;
434 }
435 
436 /*
437  * NtGdiFlushUserBatch
438  *
439  * Callback for thread batch flush routine.
440  *
441  * Think small & fast!
442  */
443 NTSTATUS
444 APIENTRY
445 NtGdiFlushUserBatch(VOID)
446 {
447   PTEB pTeb = NtCurrentTeb();
448   ULONG GdiBatchCount = pTeb->GdiBatchCount;
449 
450   if( (GdiBatchCount > 0) && (GdiBatchCount <= (GDIBATCHBUFSIZE/4)))
451   {
452     HDC hDC = (HDC) pTeb->GdiTebBatch.HDC;
453 
454     /*  If hDC is zero and the buffer fills up with delete objects we need
455         to run anyway.
456      */
457     if (hDC || GdiBatchCount)
458     {
459       PCHAR pHdr = (PCHAR)&pTeb->GdiTebBatch.Buffer[0];
460       PDC pDC = NULL;
461 
462       if (GDI_HANDLE_GET_TYPE(hDC) == GDILoObjType_LO_DC_TYPE && GreIsHandleValid(hDC))
463       {
464           pDC = DC_LockDc(hDC);
465       }
466 
467        // No need to init anything, just go!
468        for (; GdiBatchCount > 0; GdiBatchCount--)
469        {
470            ULONG Size;
471            // Process Gdi Batch!
472            Size = GdiFlushUserBatch(pDC, (PGDIBATCHHDR) pHdr);
473            if (!Size) break;
474            pHdr += Size;
475        }
476 
477        if (pDC)
478        {
479            DC_UnlockDc(pDC);
480        }
481 
482        // Exit and clear out for the next round.
483        pTeb->GdiTebBatch.Offset = 0;
484        pTeb->GdiBatchCount = 0;
485        pTeb->GdiTebBatch.HDC = 0;
486     }
487   }
488 
489   // FIXME: On Windows XP the function returns &pTeb->RealClientId, maybe VOID?
490   return STATUS_SUCCESS;
491 }
492 
493 
494