[WIN32SS][FONT] Fix GetTextFace function and related (#829)
[reactos.git] / win32ss / gdi / ntgdi / bitblt.c
1 /*
2 * COPYRIGHT: GNU GPL, See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Bit blit functions
5 * FILE: win32ss/gdi/ntgdi/bitblt.c
6 * PROGRAMER: Unknown
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(GdiBlt);
11
12 BOOL APIENTRY
13 NtGdiAlphaBlend(
14 HDC hDCDest,
15 LONG XOriginDest,
16 LONG YOriginDest,
17 LONG WidthDest,
18 LONG HeightDest,
19 HDC hDCSrc,
20 LONG XOriginSrc,
21 LONG YOriginSrc,
22 LONG WidthSrc,
23 LONG HeightSrc,
24 BLENDFUNCTION BlendFunc,
25 HANDLE hcmXform)
26 {
27 PDC DCDest;
28 PDC DCSrc;
29 HDC ahDC[2];
30 PGDIOBJ apObj[2];
31 SURFACE *BitmapDest, *BitmapSrc;
32 RECTL DestRect, SourceRect;
33 BOOL bResult;
34 EXLATEOBJ exlo;
35 BLENDOBJ BlendObj;
36 BlendObj.BlendFunction = BlendFunc;
37
38 if (WidthDest < 0 || HeightDest < 0 || WidthSrc < 0 || HeightSrc < 0)
39 {
40 EngSetLastError(ERROR_INVALID_PARAMETER);
41 return FALSE;
42 }
43
44 if ((hDCDest == NULL) || (hDCSrc == NULL))
45 {
46 EngSetLastError(ERROR_INVALID_PARAMETER);
47 return FALSE;
48 }
49
50 TRACE("Locking DCs\n");
51 ahDC[0] = hDCDest;
52 ahDC[1] = hDCSrc ;
53 if (!GDIOBJ_bLockMultipleObjects(2, (HGDIOBJ*)ahDC, apObj, GDIObjType_DC_TYPE))
54 {
55 WARN("Invalid dc handle (dest=0x%p, src=0x%p) passed to NtGdiAlphaBlend\n", hDCDest, hDCSrc);
56 EngSetLastError(ERROR_INVALID_HANDLE);
57 return FALSE;
58 }
59 DCDest = apObj[0];
60 DCSrc = apObj[1];
61
62 if (DCDest->dctype == DC_TYPE_INFO || DCDest->dctype == DCTYPE_INFO)
63 {
64 GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
65 GDIOBJ_vUnlockObject(&DCDest->BaseObject);
66 /* Yes, Windows really returns TRUE in this case */
67 return TRUE;
68 }
69
70 DestRect.left = XOriginDest;
71 DestRect.top = YOriginDest;
72 DestRect.right = XOriginDest + WidthDest;
73 DestRect.bottom = YOriginDest + HeightDest;
74 IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
75
76 DestRect.left += DCDest->ptlDCOrig.x;
77 DestRect.top += DCDest->ptlDCOrig.y;
78 DestRect.right += DCDest->ptlDCOrig.x;
79 DestRect.bottom += DCDest->ptlDCOrig.y;
80
81 if (DCDest->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
82 {
83 IntUpdateBoundsRect(DCDest, &DestRect);
84 }
85
86 SourceRect.left = XOriginSrc;
87 SourceRect.top = YOriginSrc;
88 SourceRect.right = XOriginSrc + WidthSrc;
89 SourceRect.bottom = YOriginSrc + HeightSrc;
90 IntLPtoDP(DCSrc, (LPPOINT)&SourceRect, 2);
91
92 SourceRect.left += DCSrc->ptlDCOrig.x;
93 SourceRect.top += DCSrc->ptlDCOrig.y;
94 SourceRect.right += DCSrc->ptlDCOrig.x;
95 SourceRect.bottom += DCSrc->ptlDCOrig.y;
96
97 if (!DestRect.right ||
98 !DestRect.bottom ||
99 !SourceRect.right ||
100 !SourceRect.bottom)
101 {
102 GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
103 GDIOBJ_vUnlockObject(&DCDest->BaseObject);
104 return TRUE;
105 }
106
107 /* Prepare DCs for blit */
108 TRACE("Preparing DCs for blit\n");
109 DC_vPrepareDCsForBlit(DCDest, &DestRect, DCSrc, &SourceRect);
110
111 /* Determine surfaces to be used in the bitblt */
112 BitmapDest = DCDest->dclevel.pSurface;
113 if (!BitmapDest)
114 {
115 bResult = FALSE ;
116 goto leave ;
117 }
118
119 BitmapSrc = DCSrc->dclevel.pSurface;
120 if (!BitmapSrc)
121 {
122 bResult = FALSE;
123 goto leave;
124 }
125
126 /* Create the XLATEOBJ. */
127 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
128
129 /* Perform the alpha blend operation */
130 TRACE("Performing the alpha blend\n");
131 bResult = IntEngAlphaBlend(&BitmapDest->SurfObj,
132 &BitmapSrc->SurfObj,
133 (CLIPOBJ *)&DCDest->co,
134 &exlo.xlo,
135 &DestRect,
136 &SourceRect,
137 &BlendObj);
138
139 EXLATEOBJ_vCleanup(&exlo);
140 leave :
141 TRACE("Finishing blit\n");
142 DC_vFinishBlit(DCDest, DCSrc);
143 GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
144 GDIOBJ_vUnlockObject(&DCDest->BaseObject);
145
146 return bResult;
147 }
148
149 BOOL APIENTRY
150 NtGdiBitBlt(
151 HDC hDCDest,
152 INT XDest,
153 INT YDest,
154 INT Width,
155 INT Height,
156 HDC hDCSrc,
157 INT XSrc,
158 INT YSrc,
159 DWORD dwRop,
160 IN DWORD crBackColor,
161 IN FLONG fl)
162 {
163
164 if (dwRop & CAPTUREBLT)
165 {
166 return NtGdiStretchBlt(hDCDest,
167 XDest,
168 YDest,
169 Width,
170 Height,
171 hDCSrc,
172 XSrc,
173 YSrc,
174 Width,
175 Height,
176 dwRop,
177 crBackColor);
178 }
179
180 dwRop = dwRop & ~(NOMIRRORBITMAP|CAPTUREBLT);
181
182 /* Forward to NtGdiMaskBlt */
183 // TODO: What's fl for? LOL not to send this to MaskBit!
184 return NtGdiMaskBlt(hDCDest,
185 XDest,
186 YDest,
187 Width,
188 Height,
189 hDCSrc,
190 XSrc,
191 YSrc,
192 NULL,
193 0,
194 0,
195 MAKEROP4(dwRop, dwRop),
196 crBackColor);
197 }
198
199 BOOL APIENTRY
200 NtGdiTransparentBlt(
201 HDC hdcDst,
202 INT xDst,
203 INT yDst,
204 INT cxDst,
205 INT cyDst,
206 HDC hdcSrc,
207 INT xSrc,
208 INT ySrc,
209 INT cxSrc,
210 INT cySrc,
211 COLORREF TransColor)
212 {
213 PDC DCDest, DCSrc;
214 HDC ahDC[2];
215 PGDIOBJ apObj[2];
216 RECTL rcDest, rcSrc;
217 SURFACE *BitmapDest, *BitmapSrc = NULL;
218 ULONG TransparentColor = 0;
219 BOOL Ret = FALSE;
220 EXLATEOBJ exlo;
221
222 if ((hdcDst == NULL) || (hdcSrc == NULL))
223 {
224 EngSetLastError(ERROR_INVALID_PARAMETER);
225 return FALSE;
226 }
227
228 TRACE("Locking DCs\n");
229 ahDC[0] = hdcDst;
230 ahDC[1] = hdcSrc ;
231 if (!GDIOBJ_bLockMultipleObjects(2, (HGDIOBJ*)ahDC, apObj, GDIObjType_DC_TYPE))
232 {
233 WARN("Invalid dc handle (dest=0x%p, src=0x%p) passed to NtGdiAlphaBlend\n", hdcDst, hdcSrc);
234 EngSetLastError(ERROR_INVALID_HANDLE);
235 return FALSE;
236 }
237 DCDest = apObj[0];
238 DCSrc = apObj[1];
239
240 if (DCDest->dctype == DC_TYPE_INFO || DCDest->dctype == DCTYPE_INFO)
241 {
242 GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
243 GDIOBJ_vUnlockObject(&DCDest->BaseObject);
244 /* Yes, Windows really returns TRUE in this case */
245 return TRUE;
246 }
247
248 rcDest.left = xDst;
249 rcDest.top = yDst;
250 rcDest.right = rcDest.left + cxDst;
251 rcDest.bottom = rcDest.top + cyDst;
252 IntLPtoDP(DCDest, (LPPOINT)&rcDest, 2);
253
254 rcDest.left += DCDest->ptlDCOrig.x;
255 rcDest.top += DCDest->ptlDCOrig.y;
256 rcDest.right += DCDest->ptlDCOrig.x;
257 rcDest.bottom += DCDest->ptlDCOrig.y;
258
259 rcSrc.left = xSrc;
260 rcSrc.top = ySrc;
261 rcSrc.right = rcSrc.left + cxSrc;
262 rcSrc.bottom = rcSrc.top + cySrc;
263 IntLPtoDP(DCSrc, (LPPOINT)&rcSrc, 2);
264
265 rcSrc.left += DCSrc->ptlDCOrig.x;
266 rcSrc.top += DCSrc->ptlDCOrig.y;
267 rcSrc.right += DCSrc->ptlDCOrig.x;
268 rcSrc.bottom += DCSrc->ptlDCOrig.y;
269
270 if (DCDest->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
271 {
272 IntUpdateBoundsRect(DCDest, &rcDest);
273 }
274
275 /* Prepare for blit */
276 DC_vPrepareDCsForBlit(DCDest, &rcDest, DCSrc, &rcSrc);
277
278 BitmapDest = DCDest->dclevel.pSurface;
279 if (!BitmapDest)
280 {
281 goto done;
282 }
283
284 BitmapSrc = DCSrc->dclevel.pSurface;
285 if (!BitmapSrc)
286 {
287 goto done;
288 }
289
290 /* Translate Transparent (RGB) Color to the source palette */
291 EXLATEOBJ_vInitialize(&exlo, &gpalRGB, BitmapSrc->ppal, 0, 0, 0);
292 TransparentColor = XLATEOBJ_iXlate(&exlo.xlo, (ULONG)TransColor);
293 EXLATEOBJ_vCleanup(&exlo);
294
295 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
296
297 Ret = IntEngTransparentBlt(&BitmapDest->SurfObj, &BitmapSrc->SurfObj,
298 (CLIPOBJ *)&DCDest->co, &exlo.xlo, &rcDest, &rcSrc,
299 TransparentColor, 0);
300
301 EXLATEOBJ_vCleanup(&exlo);
302
303 done:
304 DC_vFinishBlit(DCDest, DCSrc);
305 GDIOBJ_vUnlockObject(&DCDest->BaseObject);
306 GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
307
308 return Ret;
309 }
310
311 BOOL APIENTRY
312 NtGdiMaskBlt(
313 HDC hdcDest,
314 INT nXDest,
315 INT nYDest,
316 INT nWidth,
317 INT nHeight,
318 HDC hdcSrc,
319 INT nXSrc,
320 INT nYSrc,
321 HBITMAP hbmMask,
322 INT xMask,
323 INT yMask,
324 DWORD dwRop4,
325 IN DWORD crBackColor)
326 {
327 PDC DCDest;
328 PDC DCSrc = NULL;
329 HDC ahDC[2];
330 PGDIOBJ apObj[2];
331 PDC_ATTR pdcattr = NULL;
332 SURFACE *BitmapDest, *BitmapSrc = NULL, *psurfMask = NULL;
333 RECTL DestRect, SourceRect;
334 POINTL SourcePoint, MaskPoint;
335 BOOL Status = FALSE;
336 EXLATEOBJ exlo;
337 XLATEOBJ *XlateObj = NULL;
338 BOOL UsesSource;
339 ROP4 rop4;
340
341 rop4 = WIN32_ROP4_TO_ENG_ROP4(dwRop4);
342
343 UsesSource = ROP4_USES_SOURCE(rop4);
344 if (!hdcDest || (UsesSource && !hdcSrc))
345 {
346 EngSetLastError(ERROR_INVALID_PARAMETER);
347 return FALSE;
348 }
349
350 /* Check if we need a mask and have a mask bitmap */
351 if (ROP4_USES_MASK(rop4) && (hbmMask != NULL))
352 {
353 /* Reference the mask bitmap */
354 psurfMask = SURFACE_ShareLockSurface(hbmMask);
355 if (psurfMask == NULL)
356 {
357 EngSetLastError(ERROR_INVALID_HANDLE);
358 return FALSE;
359 }
360
361 /* Make sure the mask bitmap is 1 BPP */
362 if (gajBitsPerFormat[psurfMask->SurfObj.iBitmapFormat] != 1)
363 {
364 EngSetLastError(ERROR_INVALID_PARAMETER);
365 SURFACE_ShareUnlockSurface(psurfMask);
366 return FALSE;
367 }
368 }
369 else
370 {
371 /* We use NULL, if we need a mask, the Eng function will take care of
372 that and use the brushobject to get a mask */
373 psurfMask = NULL;
374 }
375
376 MaskPoint.x = xMask;
377 MaskPoint.y = yMask;
378
379 /* Take care of source and destination bitmap */
380 TRACE("Locking DCs\n");
381 ahDC[0] = hdcDest;
382 ahDC[1] = UsesSource ? hdcSrc : NULL;
383 if (!GDIOBJ_bLockMultipleObjects(2, (HGDIOBJ*)ahDC, apObj, GDIObjType_DC_TYPE))
384 {
385 WARN("Invalid dc handle (dest=0x%p, src=0x%p) passed to NtGdiMaskBlt\n", hdcDest, hdcSrc);
386 EngSetLastError(ERROR_INVALID_HANDLE);
387 return FALSE;
388 }
389 DCDest = apObj[0];
390 DCSrc = apObj[1];
391
392 ASSERT(DCDest);
393 if (NULL == DCDest)
394 {
395 if(DCSrc) DC_UnlockDc(DCSrc);
396 WARN("Invalid destination dc handle (0x%p) passed to NtGdiMaskBlt\n", hdcDest);
397 return FALSE;
398 }
399
400 if (DCDest->dctype == DC_TYPE_INFO)
401 {
402 if(DCSrc) DC_UnlockDc(DCSrc);
403 DC_UnlockDc(DCDest);
404 /* Yes, Windows really returns TRUE in this case */
405 return TRUE;
406 }
407
408 if (UsesSource)
409 {
410 ASSERT(DCSrc);
411 if (DCSrc->dctype == DC_TYPE_INFO)
412 {
413 DC_UnlockDc(DCDest);
414 DC_UnlockDc(DCSrc);
415 /* Yes, Windows really returns TRUE in this case */
416 return TRUE;
417 }
418 }
419
420 pdcattr = DCDest->pdcattr;
421
422 DestRect.left = nXDest;
423 DestRect.top = nYDest;
424 DestRect.right = nXDest + nWidth;
425 DestRect.bottom = nYDest + nHeight;
426 IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
427
428 DestRect.left += DCDest->ptlDCOrig.x;
429 DestRect.top += DCDest->ptlDCOrig.y;
430 DestRect.right += DCDest->ptlDCOrig.x;
431 DestRect.bottom += DCDest->ptlDCOrig.y;
432
433 if (DCDest->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
434 {
435 IntUpdateBoundsRect(DCDest, &DestRect);
436 }
437
438 SourcePoint.x = nXSrc;
439 SourcePoint.y = nYSrc;
440
441 if (UsesSource)
442 {
443 IntLPtoDP(DCSrc, (LPPOINT)&SourcePoint, 1);
444
445 SourcePoint.x += DCSrc->ptlDCOrig.x;
446 SourcePoint.y += DCSrc->ptlDCOrig.y;
447 /* Calculate Source Rect */
448 SourceRect.left = SourcePoint.x;
449 SourceRect.top = SourcePoint.y;
450 SourceRect.right = SourcePoint.x + DestRect.right - DestRect.left;
451 SourceRect.bottom = SourcePoint.y + DestRect.bottom - DestRect.top ;
452 }
453 else
454 {
455 SourceRect.left = 0;
456 SourceRect.top = 0;
457 SourceRect.right = 0;
458 SourceRect.bottom = 0;
459 }
460
461 /* Prepare blit */
462 DC_vPrepareDCsForBlit(DCDest, &DestRect, DCSrc, &SourceRect);
463
464 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
465 DC_vUpdateFillBrush(DCDest);
466
467 /* Determine surfaces to be used in the bitblt */
468 BitmapDest = DCDest->dclevel.pSurface;
469 if (!BitmapDest)
470 goto cleanup;
471
472 if (UsesSource)
473 {
474 {
475 BitmapSrc = DCSrc->dclevel.pSurface;
476 if (!BitmapSrc)
477 goto cleanup;
478 }
479 }
480
481 /* Create the XLATEOBJ. */
482 if (UsesSource)
483 {
484 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
485 XlateObj = &exlo.xlo;
486 }
487
488 /* Perform the bitblt operation */
489 Status = IntEngBitBlt(&BitmapDest->SurfObj,
490 BitmapSrc ? &BitmapSrc->SurfObj : NULL,
491 psurfMask ? &psurfMask->SurfObj : NULL,
492 (CLIPOBJ *)&DCDest->co,
493 XlateObj,
494 &DestRect,
495 &SourcePoint,
496 &MaskPoint,
497 &DCDest->eboFill.BrushObject,
498 &DCDest->dclevel.pbrFill->ptOrigin,
499 rop4);
500
501 if (UsesSource)
502 EXLATEOBJ_vCleanup(&exlo);
503 cleanup:
504 DC_vFinishBlit(DCDest, DCSrc);
505 if (UsesSource)
506 {
507 DC_UnlockDc(DCSrc);
508 }
509 DC_UnlockDc(DCDest);
510 if(psurfMask) SURFACE_ShareUnlockSurface(psurfMask);
511
512 return Status;
513 }
514
515 BOOL
516 APIENTRY
517 NtGdiPlgBlt(
518 IN HDC hdcTrg,
519 IN LPPOINT pptlTrg,
520 IN HDC hdcSrc,
521 IN INT xSrc,
522 IN INT ySrc,
523 IN INT cxSrc,
524 IN INT cySrc,
525 IN HBITMAP hbmMask,
526 IN INT xMask,
527 IN INT yMask,
528 IN DWORD crBackColor)
529 {
530 FIXME("NtGdiPlgBlt: unimplemented.\n");
531 return FALSE;
532 }
533
534 BOOL
535 NTAPI
536 GreStretchBltMask(
537 HDC hDCDest,
538 INT XOriginDest,
539 INT YOriginDest,
540 INT WidthDest,
541 INT HeightDest,
542 HDC hDCSrc,
543 INT XOriginSrc,
544 INT YOriginSrc,
545 INT WidthSrc,
546 INT HeightSrc,
547 DWORD dwRop4,
548 IN DWORD dwBackColor,
549 HDC hDCMask,
550 INT XOriginMask,
551 INT YOriginMask)
552 {
553 PDC DCDest;
554 PDC DCSrc = NULL;
555 PDC DCMask = NULL;
556 HDC ahDC[3];
557 PGDIOBJ apObj[3];
558 PDC_ATTR pdcattr;
559 SURFACE *BitmapDest, *BitmapSrc = NULL;
560 SURFACE *BitmapMask = NULL;
561 RECTL DestRect;
562 RECTL SourceRect;
563 POINTL MaskPoint;
564 BOOL Status = FALSE;
565 EXLATEOBJ exlo;
566 XLATEOBJ *XlateObj = NULL;
567 POINTL BrushOrigin;
568 BOOL UsesSource;
569 BOOL UsesMask;
570 ROP4 rop4;
571
572 rop4 = WIN32_ROP4_TO_ENG_ROP4(dwRop4);
573
574 UsesSource = ROP4_USES_SOURCE(rop4);
575 UsesMask = ROP4_USES_MASK(rop4);
576
577 if (0 == WidthDest || 0 == HeightDest || 0 == WidthSrc || 0 == HeightSrc)
578 {
579 EngSetLastError(ERROR_INVALID_PARAMETER);
580 return TRUE;
581 }
582
583 if (!hDCDest || (UsesSource && !hDCSrc) || (UsesMask && !hDCMask))
584 {
585 EngSetLastError(ERROR_INVALID_PARAMETER);
586 return FALSE;
587 }
588
589 ahDC[0] = hDCDest;
590 ahDC[1] = UsesSource ? hDCSrc : NULL;
591 ahDC[2] = UsesMask ? hDCMask : NULL;
592 if (!GDIOBJ_bLockMultipleObjects(3, (HGDIOBJ*)ahDC, apObj, GDIObjType_DC_TYPE))
593 {
594 WARN("Invalid dc handle (dest=0x%p, src=0x%p) passed to GreStretchBltMask\n", hDCDest, hDCSrc);
595 EngSetLastError(ERROR_INVALID_HANDLE);
596 return FALSE;
597 }
598 DCDest = apObj[0];
599 DCSrc = apObj[1];
600 DCMask = apObj[2];
601
602 if (DCDest->dctype == DC_TYPE_INFO)
603 {
604 if(DCSrc) GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
605 if(DCMask) GDIOBJ_vUnlockObject(&DCMask->BaseObject);
606 GDIOBJ_vUnlockObject(&DCDest->BaseObject);
607 /* Yes, Windows really returns TRUE in this case */
608 return TRUE;
609 }
610
611 if (UsesSource)
612 {
613 if (DCSrc->dctype == DC_TYPE_INFO)
614 {
615 GDIOBJ_vUnlockObject(&DCDest->BaseObject);
616 GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
617 if(DCMask) GDIOBJ_vUnlockObject(&DCMask->BaseObject);
618 /* Yes, Windows really returns TRUE in this case */
619 return TRUE;
620 }
621 }
622
623 pdcattr = DCDest->pdcattr;
624
625 DestRect.left = XOriginDest;
626 DestRect.top = YOriginDest;
627 DestRect.right = XOriginDest+WidthDest;
628 DestRect.bottom = YOriginDest+HeightDest;
629 IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
630
631 DestRect.left += DCDest->ptlDCOrig.x;
632 DestRect.top += DCDest->ptlDCOrig.y;
633 DestRect.right += DCDest->ptlDCOrig.x;
634 DestRect.bottom += DCDest->ptlDCOrig.y;
635
636 if (DCDest->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
637 {
638 IntUpdateBoundsRect(DCDest, &DestRect);
639 }
640
641 SourceRect.left = XOriginSrc;
642 SourceRect.top = YOriginSrc;
643 SourceRect.right = XOriginSrc+WidthSrc;
644 SourceRect.bottom = YOriginSrc+HeightSrc;
645
646 if (UsesSource)
647 {
648 IntLPtoDP(DCSrc, (LPPOINT)&SourceRect, 2);
649
650 SourceRect.left += DCSrc->ptlDCOrig.x;
651 SourceRect.top += DCSrc->ptlDCOrig.y;
652 SourceRect.right += DCSrc->ptlDCOrig.x;
653 SourceRect.bottom += DCSrc->ptlDCOrig.y;
654 }
655
656 BrushOrigin.x = 0;
657 BrushOrigin.y = 0;
658
659 /* Only prepare Source and Dest, hdcMask represents a DIB */
660 DC_vPrepareDCsForBlit(DCDest, &DestRect, DCSrc, &SourceRect);
661
662 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
663 DC_vUpdateFillBrush(DCDest);
664
665 /* Determine surfaces to be used in the bitblt */
666 BitmapDest = DCDest->dclevel.pSurface;
667 if (BitmapDest == NULL)
668 goto failed;
669 if (UsesSource)
670 {
671 BitmapSrc = DCSrc->dclevel.pSurface;
672 if (BitmapSrc == NULL)
673 goto failed;
674
675 /* Create the XLATEOBJ. */
676 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
677 XlateObj = &exlo.xlo;
678 }
679
680 /* Offset the brush */
681 BrushOrigin.x += DCDest->ptlDCOrig.x;
682 BrushOrigin.y += DCDest->ptlDCOrig.y;
683
684 /* Make mask surface for source surface */
685 if (BitmapSrc && DCMask)
686 {
687 BitmapMask = DCMask->dclevel.pSurface;
688 if (BitmapMask &&
689 (BitmapMask->SurfObj.sizlBitmap.cx < WidthSrc ||
690 BitmapMask->SurfObj.sizlBitmap.cy < HeightSrc))
691 {
692 WARN("%dx%d mask is smaller than %dx%d bitmap\n",
693 BitmapMask->SurfObj.sizlBitmap.cx, BitmapMask->SurfObj.sizlBitmap.cy,
694 WidthSrc, HeightSrc);
695 EXLATEOBJ_vCleanup(&exlo);
696 goto failed;
697 }
698 /* Create mask offset point */
699 MaskPoint.x = XOriginMask;
700 MaskPoint.y = YOriginMask;
701 IntLPtoDP(DCMask, &MaskPoint, 1);
702 MaskPoint.x += DCMask->ptlDCOrig.x;
703 MaskPoint.y += DCMask->ptlDCOrig.y;
704 }
705
706 /* Perform the bitblt operation */
707 Status = IntEngStretchBlt(&BitmapDest->SurfObj,
708 BitmapSrc ? &BitmapSrc->SurfObj : NULL,
709 BitmapMask ? &BitmapMask->SurfObj : NULL,
710 (CLIPOBJ *)&DCDest->co,
711 XlateObj,
712 &DCDest->dclevel.ca,
713 &DestRect,
714 &SourceRect,
715 BitmapMask ? &MaskPoint : NULL,
716 &DCDest->eboFill.BrushObject,
717 &BrushOrigin,
718 rop4);
719 if (UsesSource)
720 {
721 EXLATEOBJ_vCleanup(&exlo);
722 }
723
724 failed:
725 DC_vFinishBlit(DCDest, DCSrc);
726 if (UsesSource)
727 {
728 DC_UnlockDc(DCSrc);
729 }
730 if (DCMask)
731 {
732 DC_UnlockDc(DCMask);
733 }
734 DC_UnlockDc(DCDest);
735
736 return Status;
737 }
738
739
740 BOOL APIENTRY
741 NtGdiStretchBlt(
742 HDC hDCDest,
743 INT XOriginDest,
744 INT YOriginDest,
745 INT WidthDest,
746 INT HeightDest,
747 HDC hDCSrc,
748 INT XOriginSrc,
749 INT YOriginSrc,
750 INT WidthSrc,
751 INT HeightSrc,
752 DWORD dwRop3,
753 IN DWORD dwBackColor)
754 {
755 dwRop3 = dwRop3 & ~(NOMIRRORBITMAP|CAPTUREBLT);
756
757 return GreStretchBltMask(
758 hDCDest,
759 XOriginDest,
760 YOriginDest,
761 WidthDest,
762 HeightDest,
763 hDCSrc,
764 XOriginSrc,
765 YOriginSrc,
766 WidthSrc,
767 HeightSrc,
768 MAKEROP4(dwRop3 & 0xFF0000, dwRop3),
769 dwBackColor,
770 NULL,
771 0,
772 0);
773 }
774
775
776 BOOL FASTCALL
777 IntPatBlt(
778 PDC pdc,
779 INT XLeft,
780 INT YLeft,
781 INT Width,
782 INT Height,
783 DWORD dwRop3,
784 PEBRUSHOBJ pebo)
785 {
786 RECTL DestRect;
787 SURFACE *psurf;
788 POINTL BrushOrigin;
789 BOOL ret;
790 PBRUSH pbrush;
791
792 ASSERT(pebo);
793 pbrush = pebo->pbrush;
794 ASSERT(pbrush);
795
796 if (pbrush->flAttrs & BR_IS_NULL)
797 {
798 return TRUE;
799 }
800
801 if (Width > 0)
802 {
803 DestRect.left = XLeft;
804 DestRect.right = XLeft + Width;
805 }
806 else
807 {
808 DestRect.left = XLeft + Width + 1;
809 DestRect.right = XLeft + 1;
810 }
811
812 if (Height > 0)
813 {
814 DestRect.top = YLeft;
815 DestRect.bottom = YLeft + Height;
816 }
817 else
818 {
819 DestRect.top = YLeft + Height + 1;
820 DestRect.bottom = YLeft + 1;
821 }
822
823 IntLPtoDP(pdc, (LPPOINT)&DestRect, 2);
824
825 DestRect.left += pdc->ptlDCOrig.x;
826 DestRect.top += pdc->ptlDCOrig.y;
827 DestRect.right += pdc->ptlDCOrig.x;
828 DestRect.bottom += pdc->ptlDCOrig.y;
829
830 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
831 {
832 IntUpdateBoundsRect(pdc, &DestRect);
833 }
834
835 #ifdef _USE_DIBLIB_
836 BrushOrigin.x = pbrush->ptOrigin.x + pdc->ptlDCOrig.x + XLeft;
837 BrushOrigin.y = pbrush->ptOrigin.y + pdc->ptlDCOrig.y + YLeft;
838 #else
839 BrushOrigin.x = pbrush->ptOrigin.x + pdc->ptlDCOrig.x;
840 BrushOrigin.y = pbrush->ptOrigin.y + pdc->ptlDCOrig.y;
841 #endif
842
843 DC_vPrepareDCsForBlit(pdc, &DestRect, NULL, NULL);
844
845 psurf = pdc->dclevel.pSurface;
846
847 ret = IntEngBitBlt(&psurf->SurfObj,
848 NULL,
849 NULL,
850 (CLIPOBJ *)&pdc->co,
851 NULL,
852 &DestRect,
853 NULL,
854 NULL,
855 &pebo->BrushObject,
856 &BrushOrigin,
857 WIN32_ROP3_TO_ENG_ROP4(dwRop3));
858
859 DC_vFinishBlit(pdc, NULL);
860
861 return ret;
862 }
863
864 BOOL FASTCALL
865 IntGdiPolyPatBlt(
866 HDC hDC,
867 DWORD dwRop,
868 PPATRECT pRects,
869 INT cRects,
870 ULONG Reserved)
871 {
872 INT i;
873 PBRUSH pbrush;
874 PDC pdc;
875 EBRUSHOBJ eboFill;
876
877 pdc = DC_LockDc(hDC);
878 if (!pdc)
879 {
880 EngSetLastError(ERROR_INVALID_HANDLE);
881 return FALSE;
882 }
883
884 if (pdc->dctype == DC_TYPE_INFO)
885 {
886 DC_UnlockDc(pdc);
887 /* Yes, Windows really returns TRUE in this case */
888 return TRUE;
889 }
890
891 for (i = 0; i < cRects; i++)
892 {
893 pbrush = BRUSH_ShareLockBrush(pRects->hBrush);
894
895 /* Check if we could lock the brush */
896 if (pbrush != NULL)
897 {
898 /* Initialize a brush object */
899 EBRUSHOBJ_vInitFromDC(&eboFill, pbrush, pdc);
900
901 IntPatBlt(
902 pdc,
903 pRects->r.left,
904 pRects->r.top,
905 pRects->r.right,
906 pRects->r.bottom,
907 dwRop,
908 &eboFill);
909
910 /* Cleanup the brush object and unlock the brush */
911 EBRUSHOBJ_vCleanup(&eboFill);
912 BRUSH_ShareUnlockBrush(pbrush);
913 }
914 pRects++;
915 }
916
917 DC_UnlockDc(pdc);
918
919 return TRUE;
920 }
921
922 BOOL
923 APIENTRY
924 NtGdiPatBlt(
925 _In_ HDC hdcDest,
926 _In_ INT x,
927 _In_ INT y,
928 _In_ INT cx,
929 _In_ INT cy,
930 _In_ DWORD dwRop)
931 {
932 BOOL bResult;
933 PDC pdc;
934
935 /* Convert the ROP3 to a ROP4 */
936 dwRop = MAKEROP4(dwRop & 0xFF0000, dwRop);
937
938 /* Check if the rop uses a source */
939 if (WIN32_ROP4_USES_SOURCE(dwRop))
940 {
941 /* This is not possible */
942 return FALSE;
943 }
944
945 /* Lock the DC */
946 pdc = DC_LockDc(hdcDest);
947 if (pdc == NULL)
948 {
949 EngSetLastError(ERROR_INVALID_HANDLE);
950 return FALSE;
951 }
952
953 /* Check if the DC has no surface (empty mem or info DC) */
954 if (pdc->dclevel.pSurface == NULL)
955 {
956 /* Nothing to do, Windows returns TRUE! */
957 DC_UnlockDc(pdc);
958 return TRUE;
959 }
960
961 /* Update the fill brush, if necessary */
962 if (pdc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
963 DC_vUpdateFillBrush(pdc);
964
965 /* Call the internal function */
966 bResult = IntPatBlt(pdc, x, y, cx, cy, dwRop, &pdc->eboFill);
967
968 /* Unlock the DC and return the result */
969 DC_UnlockDc(pdc);
970 return bResult;
971 }
972
973 BOOL
974 APIENTRY
975 NtGdiPolyPatBlt(
976 HDC hDC,
977 DWORD dwRop,
978 IN PPOLYPATBLT pRects,
979 IN DWORD cRects,
980 IN DWORD Mode)
981 {
982 PPATRECT rb = NULL;
983 NTSTATUS Status = STATUS_SUCCESS;
984 BOOL Ret;
985
986 if (cRects > 0)
987 {
988 rb = ExAllocatePoolWithTag(PagedPool, sizeof(PATRECT) * cRects, GDITAG_PLGBLT_DATA);
989 if (!rb)
990 {
991 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
992 return FALSE;
993 }
994 _SEH2_TRY
995 {
996 ProbeForRead(pRects,
997 cRects * sizeof(PATRECT),
998 1);
999 RtlCopyMemory(rb,
1000 pRects,
1001 cRects * sizeof(PATRECT));
1002 }
1003 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1004 {
1005 Status = _SEH2_GetExceptionCode();
1006 }
1007 _SEH2_END;
1008
1009 if (!NT_SUCCESS(Status))
1010 {
1011 ExFreePoolWithTag(rb, GDITAG_PLGBLT_DATA);
1012 SetLastNtError(Status);
1013 return FALSE;
1014 }
1015 }
1016
1017 Ret = IntGdiPolyPatBlt(hDC, dwRop, rb, cRects, Mode);
1018
1019 if (cRects > 0)
1020 ExFreePoolWithTag(rb, GDITAG_PLGBLT_DATA);
1021
1022 return Ret;
1023 }
1024
1025 static
1026 BOOL
1027 FASTCALL
1028 REGION_LPTODP(
1029 _In_ PDC pdc,
1030 _Inout_ PREGION prgnDest,
1031 _In_ PREGION prgnSrc)
1032 {
1033 if (IntGdiCombineRgn(prgnDest, prgnSrc, NULL, RGN_COPY) == ERROR)
1034 return FALSE;
1035
1036 return REGION_bXformRgn(prgnDest, DC_pmxWorldToDevice(pdc));
1037 }
1038
1039 BOOL
1040 APIENTRY
1041 IntGdiBitBltRgn(
1042 _In_ PDC pdc,
1043 _In_ PREGION prgn,
1044 _In_opt_ BRUSHOBJ *pbo,
1045 _In_opt_ POINTL *pptlBrush,
1046 _In_ ROP4 rop4)
1047 {
1048 PREGION prgnClip;
1049 XCLIPOBJ xcoClip;
1050 BOOL bResult;
1051 NT_ASSERT((pdc != NULL) && (prgn != NULL));
1052
1053 /* Check if we have a surface */
1054 if (pdc->dclevel.pSurface == NULL)
1055 {
1056 return TRUE;
1057 }
1058
1059 /* Create an empty clip region */
1060 prgnClip = IntSysCreateRectpRgn(0, 0, 0, 0);
1061 if (prgnClip == NULL)
1062 {
1063 return FALSE;
1064 }
1065
1066 /* Transform given region into device coordinates */
1067 if (!REGION_LPTODP(pdc, prgnClip, prgn))
1068 {
1069 REGION_Delete(prgnClip);
1070 return FALSE;
1071 }
1072
1073 /* Intersect with the system or RAO region (these are (atm) without DC-origin) */
1074 if (pdc->prgnRao)
1075 IntGdiCombineRgn(prgnClip, prgnClip, pdc->prgnRao, RGN_AND);
1076 else
1077 IntGdiCombineRgn(prgnClip, prgnClip, pdc->prgnVis, RGN_AND);
1078
1079 /* Now account for the DC-origin */
1080 if (!REGION_bOffsetRgn(prgnClip, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y))
1081 {
1082 REGION_Delete(prgnClip);
1083 return FALSE;
1084 }
1085
1086 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
1087 {
1088 RECTL rcrgn;
1089 REGION_GetRgnBox(prgnClip, &rcrgn);
1090 IntUpdateBoundsRect(pdc, &rcrgn);
1091 }
1092
1093 /* Prepare the DC */
1094 DC_vPrepareDCsForBlit(pdc, &prgnClip->rdh.rcBound, NULL, NULL);
1095
1096 /* Initialize a clip object */
1097 IntEngInitClipObj(&xcoClip);
1098 IntEngUpdateClipRegion(&xcoClip,
1099 prgnClip->rdh.nCount,
1100 prgnClip->Buffer,
1101 &prgnClip->rdh.rcBound);
1102
1103 /* Call the Eng or Drv function */
1104 bResult = IntEngBitBlt(&pdc->dclevel.pSurface->SurfObj,
1105 NULL,
1106 NULL,
1107 (CLIPOBJ *)&xcoClip,
1108 NULL,
1109 &prgnClip->rdh.rcBound,
1110 NULL,
1111 NULL,
1112 pbo,
1113 pptlBrush,
1114 rop4);
1115
1116 /* Cleanup */
1117 DC_vFinishBlit(pdc, NULL);
1118 REGION_Delete(prgnClip);
1119 IntEngFreeClipResources(&xcoClip);
1120
1121 /* Return the result */
1122 return bResult;
1123 }
1124
1125 BOOL
1126 IntGdiFillRgn(
1127 _In_ PDC pdc,
1128 _In_ PREGION prgn,
1129 _In_opt_ PBRUSH pbrFill)
1130 {
1131 PREGION prgnClip;
1132 XCLIPOBJ xcoClip;
1133 EBRUSHOBJ eboFill;
1134 BRUSHOBJ *pbo;
1135 BOOL bRet;
1136 DWORD rop2Fg;
1137 MIX mix;
1138 NT_ASSERT((pdc != NULL) && (prgn != NULL));
1139
1140 if (pdc->dclevel.pSurface == NULL)
1141 {
1142 return TRUE;
1143 }
1144
1145 prgnClip = IntSysCreateRectpRgn(0, 0, 0, 0);
1146 if (prgnClip == NULL)
1147 {
1148 return FALSE;
1149 }
1150
1151 /* Transform region into device coordinates */
1152 if (!REGION_LPTODP(pdc, prgnClip, prgn))
1153 {
1154 REGION_Delete(prgnClip);
1155 return FALSE;
1156 }
1157
1158 /* Intersect with the system or RAO region (these are (atm) without DC-origin) */
1159 if (pdc->prgnRao)
1160 IntGdiCombineRgn(prgnClip, prgnClip, pdc->prgnRao, RGN_AND);
1161 else
1162 IntGdiCombineRgn(prgnClip, prgnClip, pdc->prgnVis, RGN_AND);
1163
1164 /* Now account for the DC-origin */
1165 if (!REGION_bOffsetRgn(prgnClip, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y))
1166 {
1167 REGION_Delete(prgnClip);
1168 return FALSE;
1169 }
1170
1171 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
1172 {
1173 RECTL rcrgn;
1174 REGION_GetRgnBox(prgnClip, &rcrgn);
1175 IntUpdateBoundsRect(pdc, &rcrgn);
1176 }
1177
1178 IntEngInitClipObj(&xcoClip);
1179 IntEngUpdateClipRegion(&xcoClip,
1180 prgnClip->rdh.nCount,
1181 prgnClip->Buffer,
1182 &prgnClip->rdh.rcBound );
1183
1184 /* Get the FG rop and create a MIX based on the BK mode */
1185 rop2Fg = FIXUP_ROP2(pdc->pdcattr->jROP2);
1186 mix = rop2Fg | (pdc->pdcattr->jBkMode == OPAQUE ? rop2Fg : R2_NOP) << 8;
1187
1188 /* Prepare DC for blit */
1189 DC_vPrepareDCsForBlit(pdc, &prgnClip->rdh.rcBound, NULL, NULL);
1190
1191 /* Check if we have a fill brush */
1192 if (pbrFill != NULL)
1193 {
1194 /* Initialize the brush object */
1195 /// \todo Check parameters
1196 EBRUSHOBJ_vInit(&eboFill, pbrFill, pdc->dclevel.pSurface, 0x00FFFFFF, 0, NULL);
1197 pbo = &eboFill.BrushObject;
1198 }
1199 else
1200 {
1201 /* Update the fill brush if needed */
1202 if (pdc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
1203 DC_vUpdateFillBrush(pdc);
1204
1205 /* Use the DC brush object */
1206 pbo = &pdc->eboFill.BrushObject;
1207 }
1208
1209 /* Call the internal function */
1210 bRet = IntEngPaint(&pdc->dclevel.pSurface->SurfObj,
1211 (CLIPOBJ *)&xcoClip,
1212 pbo,
1213 &pdc->pdcattr->ptlBrushOrigin,
1214 mix);
1215
1216 DC_vFinishBlit(pdc, NULL);
1217 REGION_Delete(prgnClip);
1218 IntEngFreeClipResources(&xcoClip);
1219
1220 // Fill the region
1221 return bRet;
1222 }
1223
1224 BOOL
1225 FASTCALL
1226 IntGdiPaintRgn(
1227 _In_ PDC pdc,
1228 _In_ PREGION prgn)
1229 {
1230 return IntGdiFillRgn(pdc, prgn, NULL);
1231 }
1232
1233 BOOL
1234 APIENTRY
1235 NtGdiFillRgn(
1236 _In_ HDC hdc,
1237 _In_ HRGN hrgn,
1238 _In_ HBRUSH hbrush)
1239 {
1240 PDC pdc;
1241 PREGION prgn;
1242 PBRUSH pbrFill;
1243 BOOL bResult;
1244
1245 /* Lock the DC */
1246 pdc = DC_LockDc(hdc);
1247 if (pdc == NULL)
1248 {
1249 ERR("Failed to lock hdc %p\n", hdc);
1250 return FALSE;
1251 }
1252
1253 /* Check if the DC has no surface (empty mem or info DC) */
1254 if (pdc->dclevel.pSurface == NULL)
1255 {
1256 DC_UnlockDc(pdc);
1257 return TRUE;
1258 }
1259
1260 /* Lock the region */
1261 prgn = REGION_LockRgn(hrgn);
1262 if (prgn == NULL)
1263 {
1264 ERR("Failed to lock hrgn %p\n", hrgn);
1265 DC_UnlockDc(pdc);
1266 return FALSE;
1267 }
1268
1269 /* Lock the brush */
1270 pbrFill = BRUSH_ShareLockBrush(hbrush);
1271 if (pbrFill == NULL)
1272 {
1273 ERR("Failed to lock hbrush %p\n", hbrush);
1274 REGION_UnlockRgn(prgn);
1275 DC_UnlockDc(pdc);
1276 return FALSE;
1277 }
1278
1279 /* Call the internal function */
1280 bResult = IntGdiFillRgn(pdc, prgn, pbrFill);
1281
1282 /* Cleanup locks */
1283 BRUSH_ShareUnlockBrush(pbrFill);
1284 REGION_UnlockRgn(prgn);
1285 DC_UnlockDc(pdc);
1286
1287 return bResult;
1288 }
1289
1290 BOOL
1291 APIENTRY
1292 NtGdiFrameRgn(
1293 _In_ HDC hdc,
1294 _In_ HRGN hrgn,
1295 _In_ HBRUSH hbrush,
1296 _In_ INT xWidth,
1297 _In_ INT yHeight)
1298 {
1299 HRGN hrgnFrame;
1300 BOOL bResult;
1301
1302 hrgnFrame = GreCreateFrameRgn(hrgn, xWidth, yHeight);
1303 if (hrgnFrame == NULL)
1304 {
1305 return FALSE;
1306 }
1307
1308 bResult = NtGdiFillRgn(hdc, hrgnFrame, hbrush);
1309
1310 GreDeleteObject(hrgnFrame);
1311 return bResult;
1312 }
1313
1314 BOOL
1315 APIENTRY
1316 NtGdiInvertRgn(
1317 _In_ HDC hdc,
1318 _In_ HRGN hrgn)
1319 {
1320 BOOL bResult;
1321 PDC pdc;
1322 PREGION prgn;
1323
1324 /* Lock the DC */
1325 pdc = DC_LockDc(hdc);
1326 if (pdc == NULL)
1327 {
1328 EngSetLastError(ERROR_INVALID_HANDLE);
1329 return FALSE;
1330 }
1331
1332 /* Check if the DC has no surface (empty mem or info DC) */
1333 if (pdc->dclevel.pSurface == NULL)
1334 {
1335 /* Nothing to do, Windows returns TRUE! */
1336 DC_UnlockDc(pdc);
1337 return TRUE;
1338 }
1339
1340 /* Lock the region */
1341 prgn = REGION_LockRgn(hrgn);
1342 if (prgn == NULL)
1343 {
1344 DC_UnlockDc(pdc);
1345 return FALSE;
1346 }
1347
1348 /* Call the internal function */
1349 bResult = IntGdiBitBltRgn(pdc,
1350 prgn,
1351 NULL, // pbo
1352 NULL, // pptlBrush,
1353 ROP4_DSTINVERT);
1354
1355 /* Unlock the region and DC and return the result */
1356 REGION_UnlockRgn(prgn);
1357 DC_UnlockDc(pdc);
1358 return bResult;
1359 }
1360
1361 COLORREF
1362 APIENTRY
1363 NtGdiSetPixel(
1364 _In_ HDC hdc,
1365 _In_ INT x,
1366 _In_ INT y,
1367 _In_ COLORREF crColor)
1368 {
1369 PDC pdc;
1370 ULONG iOldColor, iSolidColor;
1371 BOOL bResult;
1372 PEBRUSHOBJ pebo;
1373 ULONG ulDirty;
1374 EXLATEOBJ exlo;
1375
1376 /* Lock the DC */
1377 pdc = DC_LockDc(hdc);
1378 if (!pdc)
1379 {
1380 EngSetLastError(ERROR_INVALID_HANDLE);
1381 return -1;
1382 }
1383
1384 /* Check if the DC has no surface (empty mem or info DC) */
1385 if (pdc->dclevel.pSurface == NULL)
1386 {
1387 /* Fail! */
1388 DC_UnlockDc(pdc);
1389 return -1;
1390 }
1391
1392 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
1393 {
1394 RECTL rcDst;
1395
1396 RECTL_vSetRect(&rcDst, x, y, x+1, y+1);
1397
1398 IntLPtoDP(pdc, (LPPOINT)&rcDst, 2);
1399
1400 rcDst.left += pdc->ptlDCOrig.x;
1401 rcDst.top += pdc->ptlDCOrig.y;
1402 rcDst.right += pdc->ptlDCOrig.x;
1403 rcDst.bottom += pdc->ptlDCOrig.y;
1404
1405 IntUpdateBoundsRect(pdc, &rcDst);
1406 }
1407
1408 /* Translate the color to the target format */
1409 iSolidColor = TranslateCOLORREF(pdc, crColor);
1410
1411 /* Use the DC's text brush, which is always a solid brush */
1412 pebo = &pdc->eboText;
1413
1414 /* Save the old solid color and set the one for the pixel */
1415 iOldColor = EBRUSHOBJ_iSetSolidColor(pebo, iSolidColor);
1416
1417 /* Save dirty flags and reset dirty text brush flag */
1418 ulDirty = pdc->pdcattr->ulDirty_;
1419 pdc->pdcattr->ulDirty_ &= ~DIRTY_TEXT;
1420
1421 /* Call the internal function */
1422 bResult = IntPatBlt(pdc, x, y, 1, 1, PATCOPY, pebo);
1423
1424 /* Restore old text brush color and dirty flags */
1425 EBRUSHOBJ_iSetSolidColor(pebo, iOldColor);
1426 pdc->pdcattr->ulDirty_ = ulDirty;
1427
1428 /// FIXME: we shouldn't dereference pSurface while the PDEV is not locked!
1429 /* Initialize an XLATEOBJ from the target surface to RGB */
1430 EXLATEOBJ_vInitialize(&exlo,
1431 pdc->dclevel.pSurface->ppal,
1432 &gpalRGB,
1433 0,
1434 pdc->pdcattr->crBackgroundClr,
1435 pdc->pdcattr->crForegroundClr);
1436
1437 /* Translate the color back to RGB */
1438 crColor = XLATEOBJ_iXlate(&exlo.xlo, iSolidColor);
1439
1440 /* Cleanup and return the target format color */
1441 EXLATEOBJ_vCleanup(&exlo);
1442
1443 /* Unlock the DC */
1444 DC_UnlockDc(pdc);
1445
1446 /* Return the new RGB color or -1 on failure */
1447 return bResult ? crColor : -1;
1448 }
1449
1450 COLORREF
1451 APIENTRY
1452 NtGdiGetPixel(
1453 _In_ HDC hdc,
1454 _In_ INT x,
1455 _In_ INT y)
1456 {
1457 PDC pdc;
1458 ULONG ulRGBColor = CLR_INVALID;
1459 POINTL ptlSrc;
1460 RECT rcDest;
1461 PSURFACE psurfSrc, psurfDest;
1462
1463 /* Lock the DC */
1464 pdc = DC_LockDc(hdc);
1465 if (!pdc)
1466 {
1467 EngSetLastError(ERROR_INVALID_HANDLE);
1468 return CLR_INVALID;
1469 }
1470
1471 /* Check if the DC has no surface (empty mem or info DC) */
1472 if (pdc->dclevel.pSurface == NULL)
1473 {
1474 /* Fail! */
1475 goto leave;
1476 }
1477
1478 /* Get the logical coordinates */
1479 ptlSrc.x = x;
1480 ptlSrc.y = y;
1481
1482 /* Translate coordinates to device coordinates */
1483 IntLPtoDP(pdc, &ptlSrc, 1);
1484 ptlSrc.x += pdc->ptlDCOrig.x;
1485 ptlSrc.y += pdc->ptlDCOrig.y;
1486
1487 rcDest.left = x;
1488 rcDest.top = y;
1489 rcDest.right = x + 1;
1490 rcDest.bottom = y + 1;
1491
1492 /* Prepare DC for blit */
1493 DC_vPrepareDCsForBlit(pdc, &rcDest, NULL, NULL);
1494
1495 /* Check if the pixel is outside the surface */
1496 psurfSrc = pdc->dclevel.pSurface;
1497 if ((ptlSrc.x >= psurfSrc->SurfObj.sizlBitmap.cx) ||
1498 (ptlSrc.y >= psurfSrc->SurfObj.sizlBitmap.cy) ||
1499 (ptlSrc.x < 0) ||
1500 (ptlSrc.y < 0))
1501 {
1502 /* Fail! */
1503 goto leave;
1504 }
1505
1506 /* Allocate a surface */
1507 psurfDest = SURFACE_AllocSurface(STYPE_BITMAP,
1508 1,
1509 1,
1510 BMF_32BPP,
1511 0,
1512 0,
1513 0,
1514 &ulRGBColor);
1515 if (psurfDest)
1516 {
1517 RECTL rclDest = {0, 0, 1, 1};
1518 EXLATEOBJ exlo;
1519
1520 /* Translate from the source palette to RGB color */
1521 EXLATEOBJ_vInitialize(&exlo,
1522 psurfSrc->ppal,
1523 &gpalRGB,
1524 0,
1525 RGB(0xff,0xff,0xff),
1526 RGB(0,0,0));
1527
1528 /* Call the copy bits function */
1529 EngCopyBits(&psurfDest->SurfObj,
1530 &psurfSrc->SurfObj,
1531 NULL,
1532 &exlo.xlo,
1533 &rclDest,
1534 &ptlSrc);
1535
1536 /* Cleanup the XLATEOBJ */
1537 EXLATEOBJ_vCleanup(&exlo);
1538
1539 /* Delete the surface */
1540 GDIOBJ_vDeleteObject(&psurfDest->BaseObject);
1541 }
1542
1543 leave:
1544
1545 /* Unlock the DC */
1546 DC_vFinishBlit(pdc, NULL);
1547 DC_UnlockDc(pdc);
1548
1549 /* Return the new RGB color or -1 on failure */
1550 return ulRGBColor;
1551 }
1552