Sync up to trunk head.
[reactos.git] / subsystems / win32 / win32k / objects / gdibatch.c
1
2 #include <win32k.h>
3
4 #define NDEBUG
5 #include <debug.h>
6
7
8 //
9 //
10 // Gdi Batch Flush support functions.
11 //
12
13 //
14 // DoDeviceSync
15 //
16 // based on IntEngEnter from eng/engmisc.c
17 //
18 VOID
19 FASTCALL
20 DoDeviceSync( SURFOBJ *Surface, PRECTL Rect, FLONG fl)
21 {
22 PPDEVOBJ Device = (PDEVOBJ*)Surface->hdev;
23 // No punting and "Handle to a surface, provided that the surface is device-managed.
24 // Otherwise, dhsurf is zero".
25 if (!(Device->flFlags & PDEV_DRIVER_PUNTED_CALL) && (Surface->dhsurf))
26 {
27 if (Device->DriverFunctions.SynchronizeSurface)
28 {
29 Device->DriverFunctions.SynchronizeSurface(Surface, Rect, fl);
30 }
31 else
32 {
33 if (Device->DriverFunctions.Synchronize)
34 {
35 Device->DriverFunctions.Synchronize(Surface->dhpdev, Rect);
36 }
37 }
38 }
39 }
40
41 VOID
42 FASTCALL
43 SynchonizeDriver(FLONG Flags)
44 {
45 SURFOBJ *SurfObj;
46 PPDEVOBJ Device;
47
48 if (Flags & GCAPS2_SYNCFLUSH)
49 Flags = DSS_FLUSH_EVENT;
50 if (Flags & GCAPS2_SYNCTIMER)
51 Flags = DSS_TIMER_EVENT;
52
53 Device = IntEnumHDev();
54
55 SurfObj = EngLockSurface( Device->pSurface );
56 if(!SurfObj) return;
57 DoDeviceSync( SurfObj, NULL, Flags);
58 EngUnlockSurface(SurfObj);
59 return;
60 }
61
62 //
63 // Process the batch.
64 //
65 ULONG
66 FASTCALL
67 GdiFlushUserBatch(PDC dc, PGDIBATCHHDR pHdr)
68 {
69 BOOL Hit = FALSE;
70 ULONG Cmd = 0, Size = 0;
71 PDC_ATTR pdcattr = NULL;
72
73 if (dc)
74 {
75 pdcattr = dc->pdcattr;
76 }
77
78 _SEH2_TRY
79 {
80 Cmd = pHdr->Cmd;
81 Size = pHdr->Size; // Return the full size of the structure.
82 }
83 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
84 {
85 Hit = TRUE;
86 }
87 _SEH2_END;
88
89 if (Hit)
90 {
91 DPRINT1("WARNING! GdiBatch Fault!\n");
92 return 0;
93 }
94
95 // FYI! The thread is approaching the end of sunset.
96 switch(Cmd)
97 {
98 case GdiBCPatBlt: // Highest pri first!
99 break;
100 case GdiBCPolyPatBlt:
101 break;
102 case GdiBCTextOut:
103 break;
104 case GdiBCExtTextOut:
105 break;
106 case GdiBCSetBrushOrg:
107 {
108 PGDIBSSETBRHORG pgSBO;
109 if (!dc) break;
110 pgSBO = (PGDIBSSETBRHORG) pHdr;
111 pdcattr->ptlBrushOrigin = pgSBO->ptlBrushOrigin;
112 IntptlBrushOrigin(dc, pgSBO->ptlBrushOrigin.x, pgSBO->ptlBrushOrigin.y);
113 break;
114 }
115 case GdiBCExtSelClipRgn:
116 break;
117 case GdiBCSelObj:
118 {
119 PGDIBSOBJECT pgO;
120 PTEXTOBJ pOrgFnt, pNewFnt = NULL;
121 HFONT hOrgFont = NULL;
122
123 if (!dc) break;
124 pgO = (PGDIBSOBJECT) pHdr;
125
126 if (NT_SUCCESS(TextIntRealizeFont((HFONT)pgO->hgdiobj,NULL)))
127 {
128 /* LFONTOBJ use share and locking. */
129 pNewFnt = TEXTOBJ_LockText(pgO->hgdiobj);
130
131 pOrgFnt = dc->dclevel.plfnt;
132 if (pOrgFnt)
133 {
134 hOrgFont = pOrgFnt->BaseObject.hHmgr;
135 }
136 else
137 {
138 hOrgFont = pdcattr->hlfntNew;
139 }
140 dc->dclevel.plfnt = pNewFnt;
141 dc->hlfntCur = pgO->hgdiobj;
142 pdcattr->hlfntNew = pgO->hgdiobj;
143 pdcattr->ulDirty_ |= DIRTY_CHARSET;
144 pdcattr->ulDirty_ &= ~SLOW_WIDTHS;
145 }
146 if (pNewFnt) TEXTOBJ_UnlockText(pNewFnt);
147 break;
148 }
149 case GdiBCDelRgn:
150 DPRINT("Delete Region Object!\n");
151 case GdiBCDelObj:
152 {
153 PGDIBSOBJECT pgO = (PGDIBSOBJECT) pHdr;
154 GreDeleteObject( pgO->hgdiobj );
155 break;
156 }
157 default:
158 break;
159 }
160
161 return Size;
162 }
163
164 /*
165 * NtGdiFlush
166 *
167 * Flushes the calling thread's current batch.
168 */
169 VOID
170 APIENTRY
171 NtGdiFlush(VOID)
172 {
173 SynchonizeDriver(GCAPS2_SYNCFLUSH);
174 }
175
176 /*
177 * NtGdiFlushUserBatch
178 *
179 * Callback for thread batch flush routine.
180 *
181 * Think small & fast!
182 */
183 NTSTATUS
184 APIENTRY
185 NtGdiFlushUserBatch(VOID)
186 {
187 PTEB pTeb = NtCurrentTeb();
188 ULONG GdiBatchCount = pTeb->GdiBatchCount;
189
190 if( (GdiBatchCount > 0) && (GdiBatchCount <= (GDIBATCHBUFSIZE/4)))
191 {
192 HDC hDC = (HDC) pTeb->GdiTebBatch.HDC;
193
194 /* If hDC is zero and the buffer fills up with delete objects we need
195 to run anyway.
196 */
197 if (hDC || GdiBatchCount)
198 {
199 PCHAR pHdr = (PCHAR)&pTeb->GdiTebBatch.Buffer[0];
200 PDC pDC = NULL;
201
202 if (hDC && !IsObjectDead(hDC))
203 {
204 pDC = DC_LockDc(hDC);
205 }
206
207 // No need to init anything, just go!
208 for (; GdiBatchCount > 0; GdiBatchCount--)
209 {
210 ULONG Size;
211 // Process Gdi Batch!
212 Size = GdiFlushUserBatch(pDC, (PGDIBATCHHDR) pHdr);
213 if (!Size) break;
214 pHdr += Size;
215 }
216
217 if (pDC)
218 {
219 DC_UnlockDc(pDC);
220 }
221
222 // Exit and clear out for the next round.
223 pTeb->GdiTebBatch.Offset = 0;
224 pTeb->GdiBatchCount = 0;
225 pTeb->GdiTebBatch.HDC = 0;
226 }
227 }
228
229 // FIXME: on xp the function returns &pTeb->RealClientId, maybe VOID?
230 return STATUS_SUCCESS;
231 }
232
233