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