VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Display/vrdp.c@ 25062

Last change on this file since 25062 was 20460, checked in by vboxsync, 16 years ago

Windows guest display driver: use correct foreground color in DrvRealizeBrush

  • Property svn:eol-style set to native
File size: 53.3 KB
Line 
1/** @file
2 *
3 * VirtualBox Windows NT/2000/XP guest video driver
4 *
5 * VRDP graphics orders pipeline.
6 */
7
8/*
9 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
20 * Clara, CA 95054 USA or visit http://www.sun.com if you need
21 * additional information or have any questions.
22 */
23
24#include "driver.h"
25#include "vrdpbmp.h"
26#include <VBox/VRDPOrders.h>
27
28#define VRDP_MAKE_OP(__c) (__c)
29
30typedef struct _VRDPBRUSH
31{
32 BOOL fPattern;
33
34 union {
35 struct {
36 uint32_t rgbFG;
37 uint32_t rgbBG;
38 uint8_t au8Pattern[8];
39 } pat;
40
41 struct {
42 uint16_t w;
43 uint16_t h;
44 uint32_t au32Bits[1];
45 /* Here bits continue. */
46 } bitmap;
47 } u;
48} VRDPBRUSH;
49
50#define VRDP_CLIP_OK 0
51#define VRDP_CLIP_NO_INTERSECTION 1
52#define VRDP_CLIP_TOO_MANY_RECTS 2
53
54#if 0
55#define dumpPCO(a, b) do {} while (0)
56#else
57void dumpPCO (RECTL *prclTrg, CLIPOBJ *pco)
58{
59 DISPDBG((1, " pco = %p Trg = %d-%d %d-%d\n", pco, prclTrg->left, prclTrg->right, prclTrg->top, prclTrg->bottom));
60
61 if (pco)
62 {
63 BOOL bMore;
64 CLIPRECTS cr;
65 RECTL* prclClip;
66 int cRects = 0;
67
68 DISPDBG((1, " pco = %d %d-%d %d-%d dc %d fc %d mode %d opt %d\n",
69 pco->iUniq,
70 pco->rclBounds.left, pco->rclBounds.right, pco->rclBounds.top, pco->rclBounds.bottom,
71 pco->iDComplexity, pco->iFComplexity, pco->iMode, pco->fjOptions));
72
73 CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
74
75 do
76 {
77 bMore = CLIPOBJ_bEnum(pco, sizeof(cr), (ULONG*)&cr);
78
79 for (prclClip = &cr.arcl[0]; cr.c != 0; cr.c--, prclClip++)
80 {
81 DISPDBG((1, " %d-%d %d-%d\n", prclClip->left, prclClip->right, prclClip->top, prclClip->bottom));
82 cRects++;
83 }
84 } while (bMore);
85
86 DISPDBG((1, " Total %d rects\n", cRects));
87 }
88}
89#endif
90
91static BOOL vrdpIsRectEmpty (const RECTL *prcl)
92{
93 return (prcl->left == prcl->right) || (prcl->top == prcl->bottom);
94}
95
96static void vrdpIntersectRects (RECTL *prectResult,
97 const RECTL *prect1,
98 const RECTL *prect2)
99{
100 /* Calculations are easier with left, right, top, bottom. */
101 int xLeft1 = prect1->left;
102 int xRight1 = prect1->right;
103
104 int xLeft2 = prect2->left;
105 int xRight2 = prect2->right;
106
107 int yTop1 = prect1->top;
108 int yBottom1 = prect1->bottom;
109
110 int yTop2 = prect2->top;
111 int yBottom2 = prect2->bottom;
112
113 int xLeftResult = max (xLeft1, xLeft2);
114 int xRightResult = min (xRight1, xRight2);
115
116 /* Initialize result to empty record. */
117 memset (prectResult, 0, sizeof (RECTL));
118
119 if (xLeftResult < xRightResult)
120 {
121 /* There is intersection by X. */
122
123 int yTopResult = max (yTop1, yTop2);
124 int yBottomResult = min (yBottom1, yBottom2);
125
126 if (yTopResult < yBottomResult)
127 {
128 /* There is intersection by Y. */
129
130 prectResult->left = xLeftResult;
131 prectResult->top = yTopResult;
132 prectResult->right = xRightResult;
133 prectResult->bottom = yBottomResult;
134 }
135 }
136
137 return;
138}
139
140static void vrdpOrderRect (RECTL *prcl)
141{
142 int tmp;
143
144 if (prcl->left > prcl->right)
145 {
146 DISPDBG((1, "vrdpOrderRect: Inverse X coordinates!!!\n"));
147
148 tmp = prcl->left;
149 prcl->left = prcl->right;
150 prcl->right = tmp;
151 }
152
153 if (prcl->top > prcl->bottom)
154 {
155 DISPDBG((1, "vrdpOrderRect: Inverse Y coordinates!!!\n"));
156
157 tmp = prcl->top;
158 prcl->top = prcl->bottom;
159 prcl->bottom = tmp;
160 }
161}
162
163
164void vrdpAdjustRect (SURFOBJ *pso, RECTL *prcl)
165{
166 int x;
167 int y;
168 int w;
169 int h;
170
171 DISPDBG((1, "vrdpAdjustRect: %d-%d %d-%d on %dx%d\n", prcl->left, prcl->right, prcl->top, prcl->bottom, pso->sizlBitmap.cx, pso->sizlBitmap.cy));
172
173 if (prcl->left <= prcl->right)
174 {
175 x = prcl->left;
176 w = prcl->right - prcl->left;
177 }
178 else
179 {
180 DISPDBG((1, "vrdpAdjustRect: Inverse X coordinates!!!\n"));
181 x = prcl->right;
182 w = prcl->left - prcl->right;
183 }
184
185 if (prcl->top <= prcl->bottom)
186 {
187 y = prcl->top;
188 h = prcl->bottom - prcl->top;
189 }
190 else
191 {
192 DISPDBG((1, "vrdpAdjustRect: Inverse Y coordinates!!!\n"));
193 y = prcl->bottom;
194 h = prcl->top - prcl->bottom;
195 }
196
197 VBVA_ASSERT(w >= 0 && h >= 0);
198
199 /* Correct negative x and y coordinates. */
200 if (x < 0)
201 {
202 x += w; /* Compute xRight which is also the new width. */
203
204 w = (x < 0)? 0: x;
205
206 x = 0;
207 }
208
209 if (y < 0)
210 {
211 y += h; /* Compute xBottom, which is also the new height. */
212
213 h = (y < 0)? 0: y;
214
215 y = 0;
216 }
217
218 /* Also check if coords are greater than the display resolution. */
219 if (x + w > pso->sizlBitmap.cx)
220 {
221 w = pso->sizlBitmap.cx > x? pso->sizlBitmap.cx - x: 0;
222 }
223
224 if (y + h > pso->sizlBitmap.cy)
225 {
226 h = pso->sizlBitmap.cy > y? pso->sizlBitmap.cy - y: 0;
227 }
228
229 prcl->left = x;
230 prcl->top = y;
231 prcl->right = x + w;
232 prcl->bottom = y + h;
233
234 DISPDBG((1, "vrdpAdjustRect: result %d-%d %d-%d\n", prcl->left, prcl->right, prcl->top, prcl->bottom));
235}
236
237static int vrdpGetIntersectingClipRects (VRDPCLIPRECTS *pClipRects, SURFOBJ *pso, RECTL *prcl, CLIPOBJ *pco, POINTL *pptlSrc)
238{
239 BOOL bTooManyRects = FALSE;
240
241 DISPDBG((1, "vrdpGetIntersectingClipRects: pso = %p, pptlSrc = %p\n", pso, pptlSrc));
242
243 pso = CONV_SURF(pso);
244
245 pClipRects->rclDstOrig = *prcl;
246 pClipRects->rclDst = *prcl;
247 pClipRects->rects.c = 0;
248
249 vrdpAdjustRect (pso, &pClipRects->rclDst);
250
251 if (pco && (pco->iDComplexity != DC_TRIVIAL))
252 {
253 ULONG iDirection = CD_ANY;
254
255 if (pptlSrc)
256 {
257 /* Operation is performed on the same (screen) surface and enumeration direction
258 * must take into account the position of source and target rectangles.
259 */
260 if (pptlSrc->x <= prcl->left)
261 {
262 if (pptlSrc->y <= prcl->top)
263 {
264 iDirection = CD_LEFTUP;
265 }
266 else
267 {
268 iDirection = CD_LEFTDOWN;
269 }
270 }
271 else
272 {
273 if (pptlSrc->y <= prcl->top)
274 {
275 iDirection = CD_RIGHTUP;
276 }
277 else
278 {
279 iDirection = CD_RIGHTDOWN;
280 }
281 }
282 }
283
284 /* Clip the target rect by entire clipping region. Obtain the effective target. */
285 vrdpIntersectRects (&pClipRects->rclDst, &pClipRects->rclDst, &pco->rclBounds);
286
287 /* Enumerate rectangles. Try to get all rectangles at once and if there is not
288 * enough space (too many rectangles) fail with the bTooManyRects condition.
289 */
290 CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, iDirection, 0);
291
292 bTooManyRects = CLIPOBJ_bEnum(pco, sizeof(pClipRects->rects), &pClipRects->rects.c);
293
294 if (!bTooManyRects)
295 {
296 RECTL *prclClipSrc = &pClipRects->rects.arcl[0];
297 RECTL *prclClipDst = prclClipSrc;
298
299 ULONG cRects = pClipRects->rects.c;
300
301 DISPDBG((1, "%d rects\n", cRects));
302
303 if (cRects > 0)
304 {
305 for (; cRects != 0; cRects--, prclClipSrc++)
306 {
307 vrdpIntersectRects (prclClipDst, prclClipSrc, &pClipRects->rclDst);
308
309 if (vrdpIsRectEmpty (prclClipDst))
310 {
311 pClipRects->rects.c--;
312 }
313 else
314 {
315 prclClipDst++;
316 }
317 }
318 }
319 else
320 {
321 pClipRects->rclDst.left = pClipRects->rclDst.right = 0;
322 }
323 }
324 }
325
326 if (vrdpIsRectEmpty (&pClipRects->rclDst))
327 {
328 return VRDP_CLIP_NO_INTERSECTION;
329 }
330
331 if (bTooManyRects)
332 {
333 pClipRects->rects.c = 0;
334
335 return VRDP_CLIP_TOO_MANY_RECTS;
336 }
337
338 return VRDP_CLIP_OK;
339}
340
341static uint32_t vrdpColor2RGB (SURFOBJ *pso, uint32_t color)
342{
343 uint32_t rgb = 0;
344
345 switch (pso->iBitmapFormat)
346 {
347 case BMF_16BPP:
348 {
349 uint8_t *d = (uint8_t *)&rgb;
350
351 *d++ = (BYTE)( color << 3); /* B */
352 *d++ = (BYTE)((color >> 5) << 2); /* G */
353 *d++ = (BYTE)((color >> 11) << 3); /* R */
354 } break;
355 case BMF_24BPP:
356 case BMF_32BPP:
357 {
358 rgb = color & 0xFFFFFF;
359 } break;
360 default:
361 DISPDBG((1, "vrdpColor2RGB: Unsupported bitmap format %d!!!\n", pso->iBitmapFormat));
362 }
363
364 return rgb;
365}
366
367__inline BOOL vrdpWriteHdr (PPDEV ppdev, uint32_t u32Op)
368{
369 return vboxWrite (ppdev, &u32Op, sizeof (u32Op));
370}
371
372static BOOL vrdpWriteBits (PPDEV ppdev, uint8_t *pu8Bits, int lDelta, int32_t x, int32_t y, uint32_t cWidth, uint32_t cHeight, int bytesPerPixel)
373{
374 BOOL bRc = FALSE;
375
376 VRDPDATABITS bits;
377
378 bits.cb = cHeight * cWidth * bytesPerPixel;
379 bits.x = (int16_t)x;
380 bits.y = (int16_t)y;
381 bits.cWidth = (uint16_t)cWidth;
382 bits.cHeight = (uint16_t)cHeight;
383 bits.cbPixel = (uint8_t)bytesPerPixel;
384
385 bRc = vboxWrite (ppdev, &bits, sizeof (bits));
386
387 if (bRc)
388 {
389 while (cHeight--)
390 {
391 bRc = vboxWrite (ppdev, pu8Bits, cWidth * bytesPerPixel);
392
393 if (!bRc)
394 {
395 break;
396 }
397
398 pu8Bits += lDelta;
399 }
400 }
401
402 return bRc;
403}
404
405void vrdpReportDirtyRect (PPDEV ppdev, RECTL *prcl)
406{
407 SURFOBJ *pso = ppdev->psoScreenBitmap;
408
409 /* This is a Bitmap Update Fallback operation. It takes bits from VRAM
410 * and inserts them in the pipeline. These bits are not cached.
411 */
412
413 uint8_t *pu8Bits;
414 int32_t lDelta;
415 uint32_t cWidth;
416 uint32_t cHeight;
417
418 BOOL bRc = FALSE;
419
420 int bytesPerPixel = format2BytesPerPixel(pso);
421
422 RECTL rclCopy = *prcl;
423
424 vrdpAdjustRect (pso, &rclCopy);
425
426 pu8Bits = (uint8_t *)pso->pvScan0 +
427 pso->lDelta * rclCopy.top +
428 bytesPerPixel * rclCopy.left;
429 lDelta = pso->lDelta;
430 cWidth = rclCopy.right - rclCopy.left;
431 cHeight = rclCopy.bottom - rclCopy.top;
432
433 if (cWidth == 0 || cHeight == 0)
434 {
435 return;
436 }
437
438 if (bytesPerPixel > 0)
439 {
440 bRc = vrdpWriteHdr (ppdev, VRDP_MAKE_OP(VRDP_ORDER_DIRTY_RECT));
441
442 if (bRc)
443 {
444 bRc = vrdpWriteBits (ppdev, pu8Bits, lDelta, rclCopy.left, rclCopy.top, cWidth, cHeight, bytesPerPixel);
445 }
446 }
447
448 if (!bRc)
449 {
450 DISPDBG((1, "vrdpReportDirtyRect failed!!! %d,%d %dx%d, bpp = %d\n",
451 rclCopy.left, rclCopy.top, cWidth, cHeight, bytesPerPixel));
452 }
453}
454
455static void vrdpReportDirtyPathBounds (PPDEV ppdev, CLIPOBJ *pco, PATHOBJ *ppo)
456{
457 RECTFX rcfxBounds;
458 RECTL rclBounds;
459
460 PATHOBJ_vGetBounds(ppo, &rcfxBounds);
461
462 rclBounds.left = FXTOLFLOOR(rcfxBounds.xLeft);
463 rclBounds.right = FXTOLCEILING(rcfxBounds.xRight);
464 rclBounds.top = FXTOLFLOOR(rcfxBounds.yTop);
465 rclBounds.bottom = FXTOLCEILING(rcfxBounds.yBottom);
466
467 vrdpIntersectRects (&rclBounds, &rclBounds, &pco->rclBounds);
468
469 vrdpReportDirtyRect (ppdev, &rclBounds);
470}
471
472static void vrdpReportDirtyPath (PPDEV ppdev, CLIPOBJ *pco, PATHOBJ *ppo)
473{
474 vrdpReportDirtyPathBounds (ppdev, pco, ppo);
475}
476
477static void vrdpReportDirtyClip (PPDEV ppdev, CLIPOBJ *pco, RECTL *prcl)
478{
479 if (prcl)
480 {
481 vrdpReportDirtyRect (ppdev, prcl);
482 }
483 else if (pco)
484 {
485 vrdpReportDirtyRect (ppdev, &pco->rclBounds);
486 }
487}
488
489static void vrdpReportDirtyRects (PPDEV ppdev, VRDPCLIPRECTS *pClipRects)
490{
491 /* Ignore rects, report entire area. */
492 vrdpReportDirtyRect (ppdev, &pClipRects->rclDst);
493}
494
495/*
496 * RDP orders reporting.
497 */
498static BOOL vrdpReportOrder (PPDEV ppdev,
499 const void *pOrder,
500 unsigned cbOrder,
501 unsigned code)
502{
503 BOOL bRc = vrdpWriteHdr (ppdev, VRDP_MAKE_OP(code));
504
505 if (bRc)
506 {
507 vboxWrite (ppdev, pOrder, cbOrder);
508 }
509
510 return bRc;
511}
512
513static BOOL vrdpReportBounds (PPDEV ppdev,
514 const RECTL *prcl)
515{
516 VRDPORDERBOUNDS bounds;
517
518 bounds.pt1.x = (int16_t)(prcl->left);
519 bounds.pt1.y = (int16_t)(prcl->top);
520 bounds.pt2.x = (int16_t)(prcl->right);
521 bounds.pt2.y = (int16_t)(prcl->bottom);
522
523 return vrdpReportOrder (ppdev, &bounds, sizeof (bounds), VRDP_ORDER_BOUNDS);
524}
525
526static BOOL vrdpReportRepeat (PPDEV ppdev,
527 const CLIPRECTS *pRects)
528{
529 BOOL bRc = TRUE;
530
531 if (pRects)
532 {
533 /* Start from index 1, because the first rect was already reported. */
534 unsigned i = 1;
535 const RECTL *prcl = &pRects->arcl[1];
536
537 for (; i < pRects->c; i++, prcl++)
538 {
539 VRDPORDERREPEAT repeat;
540
541 repeat.bounds.pt1.x = (int16_t)(prcl->left);
542 repeat.bounds.pt1.y = (int16_t)(prcl->top);
543 repeat.bounds.pt2.x = (int16_t)(prcl->right);
544 repeat.bounds.pt2.y = (int16_t)(prcl->bottom);
545
546 bRc = vrdpReportOrder (ppdev, &repeat, sizeof (repeat), VRDP_ORDER_REPEAT);
547
548 if (!bRc)
549 {
550 return bRc;
551 }
552 }
553 }
554
555 return bRc;
556}
557
558static BOOL vrdpIntersectRectWithBounds (RECTL *prclIntersect,
559 const RECTL *prcl,
560 const VRDPORDERBOUNDS *pBounds)
561{
562 if ( prcl->left < pBounds->pt2.x /* left < bounds_right */
563 && prcl->right > pBounds->pt1.x /* right < bounds_left */
564 && prcl->top < pBounds->pt2.y /* top < bounds_bottom */
565 && prcl->bottom > pBounds->pt1.y /* bottom < bounds_top */
566 )
567 {
568 /* There is intersection. */
569 prclIntersect->left = max(prcl->left, pBounds->pt1.x);
570 prclIntersect->right = min(prcl->right, pBounds->pt2.x);
571 prclIntersect->top = max(prcl->top, pBounds->pt1.y);
572 prclIntersect->bottom = min(prcl->bottom, pBounds->pt2.y);
573
574 VBVA_ASSERT(prclIntersect->left < prclIntersect->right);
575 VBVA_ASSERT(prclIntersect->top < prclIntersect->bottom);
576
577 return TRUE;
578 }
579
580 /* No intesection. */
581 return FALSE;
582}
583
584static BOOL vrdpGetIntersectingRects (CLIPRECTS *pRects,
585 const VRDPCLIPRECTS *pClipRects,
586 const VRDPORDERBOUNDS *pBounds)
587{
588 BOOL fReportOrder = TRUE;
589
590 pRects->c = 0; /* Number of clipping rects. */
591
592 if (pClipRects->rects.c == 0)
593 {
594 /* There were no clipping for the order. Therefore do nothing
595 * here and just return that order must be reported without
596 * clipping (rc = TRUE, pRects->c = 0).
597 */
598 /* Do nothing. */
599 }
600 else
601 {
602 /* Find which clipping rects intersect with the bounds. */
603 unsigned c = 0;
604 RECTL *prclIntersect = &pRects->arcl[0];
605
606 unsigned i = 0;
607 const RECTL *prcl = &pClipRects->rects.arcl[0];
608
609 for (; i < pClipRects->rects.c; i++, prcl++)
610 {
611 if (vrdpIntersectRectWithBounds (prclIntersect, prcl, pBounds))
612 {
613 c++;
614 prclIntersect++;
615 }
616 }
617
618 if (c == 0)
619 {
620 /* No of clip rects intersect with the bounds. */
621 fReportOrder = FALSE;
622 }
623 else
624 {
625 pRects->c = c;
626 }
627 }
628
629 return fReportOrder;
630}
631
632BOOL vrdpReportOrderGeneric (PPDEV ppdev,
633 const VRDPCLIPRECTS *pClipRects,
634 const void *pvOrder,
635 unsigned cbOrder,
636 unsigned code)
637{
638 BOOL bRc;
639
640 if (pClipRects && pClipRects->rects.c > 0)
641 {
642 bRc = vrdpReportBounds (ppdev, &pClipRects->rects.arcl[0]);
643
644 if (!bRc)
645 {
646 return bRc;
647 }
648 }
649
650 bRc = vrdpReportOrder (ppdev, pvOrder, cbOrder, code);
651
652 if (!bRc)
653 {
654 return bRc;
655 }
656
657 if (pClipRects && pClipRects->rects.c > 1)
658 {
659 bRc = vrdpReportRepeat (ppdev, &pClipRects->rects);
660 }
661
662 return bRc;
663}
664
665static void vrdpReportOrderGenericBounds (PPDEV ppdev,
666 const VRDPCLIPRECTS *pClipRects,
667 const VRDPORDERBOUNDS *pBounds,
668 const void *pvOrder,
669 unsigned cbOrder,
670 unsigned code)
671{
672 CLIPRECTS rects;
673
674 if (vrdpGetIntersectingRects (&rects, pClipRects, pBounds))
675 {
676 vrdpReportOrderGeneric (ppdev, pClipRects, pvOrder, cbOrder, code);
677 }
678}
679
680static void vrdpReportSolidRect (PPDEV ppdev,
681 const RECTL *prclTrg,
682 VRDPCLIPRECTS *pClipRects,
683 ULONG rgb)
684{
685 VRDPORDERSOLIDRECT order;
686
687 order.x = (int16_t)prclTrg->left;
688 order.y = (int16_t)prclTrg->top;
689 order.w = (uint16_t)(prclTrg->right - prclTrg->left);
690 order.h = (uint16_t)(prclTrg->bottom - prclTrg->top);
691 order.rgb = rgb;
692
693 vrdpReportOrderGeneric (ppdev, pClipRects, &order, sizeof (order), VRDP_ORDER_SOLIDRECT);
694}
695
696static void vrdpReportSolidBlt (PPDEV ppdev,
697 const RECTL *prclTrg,
698 VRDPCLIPRECTS *pClipRects,
699 ULONG rgb,
700 uint8_t rop3)
701{
702 VRDPORDERSOLIDBLT order;
703
704 order.x = (int16_t)prclTrg->left;
705 order.y = (int16_t)prclTrg->top;
706 order.w = (uint16_t)(prclTrg->right - prclTrg->left);
707 order.h = (uint16_t)(prclTrg->bottom - prclTrg->top);
708 order.rgb = rgb;
709 order.rop = rop3;
710
711 vrdpReportOrderGeneric (ppdev, pClipRects, &order, sizeof (order), VRDP_ORDER_SOLIDBLT);
712}
713
714static void vrdpReportPatBlt (PPDEV ppdev,
715 const RECTL *prclTrg,
716 VRDPCLIPRECTS *pClipRects,
717 VRDPBRUSH *pBrush,
718 POINTL *pptlBrush,
719 uint8_t rop3)
720{
721 VRDPORDERPATBLTBRUSH order;
722
723 int8_t xSrc = 0;
724 int8_t ySrc = 0;
725
726 if (pptlBrush)
727 {
728 int xDiff;
729 int yDiff;
730
731 DISPDBG((1, "Dst %d,%d Brush origin %d,%d\n", prclTrg->left, prclTrg->top, pptlBrush->x, pptlBrush->y));
732
733 xDiff = prclTrg->left - pptlBrush->x;
734 if (xDiff < 0)
735 {
736 xDiff = -xDiff;
737 }
738
739 yDiff = prclTrg->top - pptlBrush->y;
740 if (yDiff < 0)
741 {
742 yDiff = -yDiff;
743 }
744
745 xSrc = (int8_t)(xDiff % 8);
746 ySrc = (int8_t)(yDiff % 8);
747 }
748
749 order.x = (int16_t)prclTrg->left;
750 order.y = (int16_t)prclTrg->top;
751 order.w = (uint16_t)(prclTrg->right - prclTrg->left);
752 order.h = (uint16_t)(prclTrg->bottom - prclTrg->top);
753 order.xSrc = xSrc;
754 order.ySrc = ySrc;
755 order.rgbFG = pBrush->u.pat.rgbFG;
756 order.rgbBG = pBrush->u.pat.rgbBG;
757 order.rop = rop3;
758
759 memcpy (order.pattern, pBrush->u.pat.au8Pattern, sizeof (order.pattern));
760
761 vrdpReportOrderGeneric (ppdev, pClipRects, &order, sizeof (order), VRDP_ORDER_PATBLTBRUSH);
762}
763
764static void vrdpReportDstBlt (PPDEV ppdev,
765 const RECTL *prclTrg,
766 VRDPCLIPRECTS *pClipRects,
767 uint8_t rop3)
768{
769 VRDPORDERDSTBLT order;
770
771 order.x = (int16_t)prclTrg->left;
772 order.y = (int16_t)prclTrg->top;
773 order.w = (uint16_t)(prclTrg->right - prclTrg->left);
774 order.h = (uint16_t)(prclTrg->bottom - prclTrg->top);
775 order.rop = rop3;
776
777 vrdpReportOrderGeneric (ppdev, pClipRects, &order, sizeof (order), VRDP_ORDER_DSTBLT);
778}
779
780static void vrdpReportScreenBlt (PPDEV ppdev,
781 const RECTL *prclTrg,
782 VRDPCLIPRECTS *pClipRects,
783 POINTL *pptlSrc,
784 uint8_t rop3)
785{
786 VRDPORDERSCREENBLT order;
787
788 order.x = (int16_t)prclTrg->left;
789 order.y = (int16_t)prclTrg->top;
790 order.w = (uint16_t)(prclTrg->right - prclTrg->left);
791 order.h = (uint16_t)(prclTrg->bottom - prclTrg->top);
792 order.xSrc = (int16_t)pptlSrc->x;
793 order.ySrc = (int16_t)pptlSrc->y;
794 order.rop = rop3;
795
796 vrdpReportOrderGeneric (ppdev, pClipRects, &order, sizeof (order), VRDP_ORDER_SCREENBLT);
797}
798
799static void vrdpReportMemBltRect (PPDEV ppdev,
800 RECTL *prcl,
801 int xSrc,
802 int ySrc,
803 uint8_t rop3,
804 const VRDPBCHASH *phash)
805{
806 VRDPORDERMEMBLT order;
807
808 order.x = (int16_t)prcl->left;
809 order.y = (int16_t)prcl->top;
810 order.w = (uint16_t)(prcl->right - prcl->left);
811 order.h = (uint16_t)(prcl->bottom - prcl->top);
812 order.xSrc = (int16_t)xSrc;
813 order.ySrc = (int16_t)ySrc;
814 order.rop = rop3;
815
816 VBVA_ASSERT(sizeof (*phash) == sizeof (order.hash));
817 memcpy (order.hash, phash, sizeof (*phash));
818
819 vrdpReportOrder (ppdev, &order, sizeof (order), VRDP_ORDER_MEMBLT);
820}
821
822static void vrdpReportMemBlt (PPDEV ppdev,
823 VRDPCLIPRECTS *pClipRects,
824 POINTL *pptlSrc,
825 const uint8_t rop3,
826 const VRDPBCHASH *phash)
827{
828 if (pClipRects->rects.c == 0)
829 {
830 int xShift = pClipRects->rclDst.left - pClipRects->rclDstOrig.left;
831 int yShift = pClipRects->rclDst.top - pClipRects->rclDstOrig.top;
832
833 VBVA_ASSERT(xShift >= 0 && yShift >= 0);
834
835 vrdpReportMemBltRect (ppdev, &pClipRects->rclDst, pptlSrc->x + xShift, pptlSrc->y + yShift, rop3, phash);
836 }
837 else
838 {
839 ULONG i;
840 for (i = 0; i < pClipRects->rects.c; i++)
841 {
842 int xShift = pClipRects->rects.arcl[i].left - pClipRects->rclDstOrig.left;
843 int yShift = pClipRects->rects.arcl[i].top - pClipRects->rclDstOrig.top;
844
845 VBVA_ASSERT(xShift >= 0 && yShift >= 0);
846
847 vrdpReportMemBltRect (ppdev, &pClipRects->rects.arcl[i], pptlSrc->x + xShift, pptlSrc->y + yShift, rop3, phash);
848 }
849 }
850}
851
852static void vrdpReportCachedBitmap (PPDEV ppdev,
853 SURFOBJ *psoSrc,
854 const VRDPBCHASH *phash)
855{
856 BOOL bRc;
857
858 VRDPORDERCACHEDBITMAP order;
859
860 VBVA_ASSERT(sizeof (*phash) == sizeof (order.hash));
861 memcpy (order.hash, phash, sizeof (*phash));
862
863 bRc = vrdpReportOrder (ppdev, &order, sizeof (order), VRDP_ORDER_CACHED_BITMAP);
864
865 if (bRc)
866 {
867 int bytesPerPixel = format2BytesPerPixel(psoSrc);
868
869 uint8_t *pu8Bits = (uint8_t *)psoSrc->pvScan0;
870 int32_t lDelta = psoSrc->lDelta;
871 uint32_t cWidth = psoSrc->sizlBitmap.cx;
872 uint32_t cHeight = psoSrc->sizlBitmap.cy;
873
874 VBVA_ASSERT(cWidth != 0 && cHeight != 0 && bytesPerPixel != 0);
875
876 vrdpWriteBits (ppdev, pu8Bits, lDelta, 0, 0, cWidth, cHeight, bytesPerPixel);
877 }
878}
879
880static void vrdpReportDeletedBitmap (PPDEV ppdev,
881 const VRDPBCHASH *phash)
882{
883 VRDPORDERDELETEDBITMAP order;
884
885 VBVA_ASSERT(sizeof (*phash) == sizeof (order.hash));
886 memcpy (order.hash, phash, sizeof (*phash));
887
888 vrdpReportOrder (ppdev, &order, sizeof (order), VRDP_ORDER_DELETED_BITMAP);
889}
890
891
892/*
893 * VRDP driver functions.
894 */
895
896/* Whether the ROP4 operation requires MASK. */
897#define ROP4_NEED_MASK(__rop4) ( (uint8_t)((__rop4) >> 8) != (uint8_t)(__rop4) )
898
899/* Whether the ROP3 (lower byte of rop4) operation requires BRUSH. */
900#define ROP3_NEED_BRUSH(__rop3) (((((__rop3) >> 4) ^ (__rop3)) & 0x0F) != 0)
901
902/* Whether the ROP3 (lower byte of rop4) operation requires SOURCE. */
903#define ROP3_NEED_SRC(__rop3) (((((__rop3) >> 2) ^ (__rop3)) & 0x33) != 0)
904
905/* Whether the ROP3 (lower byte of rop4) operation requires DESTINATION. */
906#define ROP3_NEED_DST(__rop3) (((((__rop3) >> 1) ^ (__rop3)) & 0x55) != 0)
907
908void vrdpBitBlt (
909 SURFOBJ *psoTrg,
910 SURFOBJ *psoSrc,
911 SURFOBJ *psoMask,
912 CLIPOBJ *pco,
913 XLATEOBJ *pxlo,
914 RECTL *prclTrg,
915 POINTL *pptlSrc,
916 POINTL *pptlMask,
917 BRUSHOBJ *pbo,
918 POINTL *pptlBrush,
919 ROP4 rop4)
920{
921 PPDEV ppdev = (PPDEV)psoTrg->dhpdev;
922
923 /*
924 * BitBlt operation is supported by following RDP orders:
925 * RDP_ORDER_DESTBLT ROP on the screen bits (BLACKNESS, WHITENESS, DSTINVERT).
926 * RDP_ORDER_PATBLT ROP with screen bits and a brush.
927 * RDP_ORDER_SCREENBLT Screen to screen with ROP.
928 * RDP_ORDER_RECT Solid fill (SRCCOPY).
929 * RDP_ORDER_MEMBLT ROP with screen and cached offscreen bitmap.
930 * RDP_ORDER_TRIBLT ROP with screen, cached offscreen bitmap and a brush.
931 *
932 * Actual BitBlts must be mapped to these RDP operations.
933 * Anything that can not be mapped must be emulated with dirty rect.
934 *
935 */
936 VRDPCLIPRECTS clipRects;
937
938 int clipResult;
939
940 RECTL rclTrg = *prclTrg;
941 vrdpOrderRect (&rclTrg);
942
943 DISPDBG((1, "vrdpBitBlt\n"));
944
945 clipResult = vrdpGetIntersectingClipRects (&clipRects, psoTrg, &rclTrg, pco,
946 bIsScreenSurface (psoSrc)? pptlSrc: NULL);
947
948 if (clipResult == VRDP_CLIP_NO_INTERSECTION)
949 {
950 /* Do nothing. The Blt does not affect anything. */
951 DISPDBG((1, "VRDP::vrdpBitBlt: VRDP_CLIP_NO_INTERSECTION!!!\n"));
952 dumpPCO (&rclTrg, pco);
953 }
954 else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS)
955 {
956 /* A very complex clip. Better to emulate it. */
957 DISPDBG((1, "VRDP::vrdpBitBlt: VRDP_CLIP_TOO_MANY_RECTS!!!\n"));
958 dumpPCO (&rclTrg, pco);
959
960 vrdpReportDirtyRects (ppdev, &clipRects);
961 }
962 else if (ROP4_NEED_MASK (rop4))
963 {
964 /* Operation with mask is not supported. */
965 DISPDBG((1, "VRDP::vrdpBitBlt: Operation with mask is not supported.\n"));
966 vrdpReportDirtyRects (ppdev, &clipRects);
967 }
968 else if (ROP3_NEED_BRUSH(rop4))
969 {
970 DISPDBG((1, "VRDP::vrdpBitBlt: Operation requires brush.\n"));
971
972 /* Operation requires brush. */
973
974 if (ROP3_NEED_SRC(rop4))
975 {
976 /* @todo Tree way blt. RDP_ORDER_TRIBLT. */
977 DISPDBG((1, "VRDP::vrdpBitBlt: TRIBLT pbo->iSolidColor = 0x%08X.\n", pbo->iSolidColor));
978 vrdpReportDirtyRects (ppdev, &clipRects);
979 }
980 else
981 {
982 /* Only brush and destination. Check if the brush is solid. */
983 if (pbo->iSolidColor != 0xFFFFFFFF)
984 {
985 /* Solid brush. The iSolidColor is the target surface color. */
986 uint32_t rgb = vrdpColor2RGB (psoTrg, pbo->iSolidColor);
987
988 /* Mix with solid brush. RDP_ORDER_PATBLT. Or RDP_ORDER_RECT for rop4 = 0xF0F0. */
989 DISPDBG((1, "VRDP::vrdpBitBlt: Solid PATBLT color = %08X, rgb %08X.\n", pbo->iSolidColor, rgb));
990
991 if (rop4 == 0xF0F0)
992 {
993 vrdpReportSolidRect (ppdev, &rclTrg, &clipRects, rgb);
994 }
995 else
996 {
997 vrdpReportSolidBlt (ppdev, &rclTrg, &clipRects, rgb, (uint8_t)rop4);
998 }
999 }
1000 else
1001 {
1002 /* Non solid brush. RDP_ORDER_PATBLT. */
1003 DISPDBG((1, "VRDP::vrdpBitBlt: PATBLT pbo->pvRbrush = %p.\n", pbo->pvRbrush));
1004
1005 /* Realize brush. */
1006 if (!pbo->pvRbrush)
1007 {
1008 BRUSHOBJ_pvGetRbrush (pbo);
1009 }
1010
1011 if (pbo->pvRbrush)
1012 {
1013 /* Brush has been realized. */
1014 VRDPBRUSH *pBrush = (VRDPBRUSH *)pbo->pvRbrush;
1015
1016 if (pBrush->fPattern)
1017 {
1018 vrdpReportPatBlt (ppdev, &rclTrg, &clipRects, pBrush, pptlBrush, (uint8_t)rop4);
1019 }
1020 else
1021 {
1022 // @todo BITMAPCACHE followed by MEMBLT?
1023 vrdpReportDirtyRects (ppdev, &clipRects);
1024 }
1025 }
1026 else
1027 {
1028 /* Unsupported brush format. Fallback to dirty rects. */
1029 vrdpReportDirtyRects (ppdev, &clipRects);
1030 }
1031 }
1032 }
1033 }
1034 else
1035 {
1036 /* Operation does not require brush. */
1037 if (ROP3_NEED_SRC(rop4))
1038 {
1039 DISPDBG((1, "VRDP::vrdpBitBlt: MEMBLT or SCREENBLT.\n"));
1040
1041 /* MEMBLT or SCREENBLT. */
1042 if (bIsScreenSurface (psoSrc))
1043 {
1044 /* Screen to screen transfer. SCREENBLT. */
1045 DISPDBG((1, "VRDP::vrdpBitBlt: SCREENBLT.\n"));
1046 vrdpReportScreenBlt (ppdev, &rclTrg, &clipRects, pptlSrc, (uint8_t)rop4);
1047 }
1048 else
1049 {
1050 /* Offscreen bitmap to screen. MEMBLT. */
1051 VRDPBCHASH hash;
1052 VRDPBCHASH hashDeleted;
1053 int cacheResult;
1054
1055 DISPDBG((1, "VRDP::vrdpBitBlt: MEMBLT.\n"));
1056 if ( (psoSrc->fjBitmap & BMF_DONTCACHE) != 0
1057 || psoSrc->iUniq == 0
1058 /* Bitmaps with hdev == 0 seems to have different RGB layout for 16BPP modes.
1059 * Just do not cache these bitmaps and report the dirty display area instead.
1060 */
1061 || ( psoSrc->hdev == 0
1062 && !(psoSrc->iBitmapFormat == BMF_24BPP || psoSrc->iBitmapFormat == BMF_32BPP)
1063 )
1064 )
1065 {
1066 DISPDBG((1, "MEMBLT: non cachable bitmap.\n"));
1067 cacheResult = VRDPBMP_RC_NOT_CACHED;
1068 }
1069 else
1070 {
1071 DISPDBG((1, "VRDP::vrdpBitBlt: going to cache.\n"));
1072 cacheResult = vrdpbmpCacheSurface (&ppdev->cache, psoSrc, &hash, &hashDeleted);
1073 }
1074
1075 DISPDBG((1, "MEMBLT: cacheResult 0x%08X. trg %d,%d %dx%d src %dx%d from %d,%d\n",
1076 cacheResult,
1077 rclTrg.left, rclTrg.top,
1078 rclTrg.right - rclTrg.left,
1079 rclTrg.bottom - rclTrg.top,
1080 psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy,
1081 pptlSrc->x, pptlSrc->y));
1082
1083 if (cacheResult & VRDPBMP_RC_F_DELETED)
1084 {
1085 DISPDBG((1, "VRDPBMP_RC_F_DELETED\n"));
1086 vrdpReportDeletedBitmap (ppdev, &hashDeleted);
1087 cacheResult &= ~VRDPBMP_RC_F_DELETED;
1088 }
1089
1090 switch (cacheResult)
1091 {
1092 case VRDPBMP_RC_CACHED:
1093 vrdpReportCachedBitmap (ppdev, psoSrc, &hash);
1094 /* Continue and report MEMBLT order. */
1095
1096 case VRDPBMP_RC_ALREADY_CACHED:
1097 vrdpReportMemBlt (ppdev, &clipRects, pptlSrc, (uint8_t)rop4, &hash);
1098 DISPDBG((1, " %08X %08X %08X %08X\n",
1099 *(uint32_t *)&((uint8_t *)&hash)[0],
1100 *(uint32_t *)&((uint8_t *)&hash)[4],
1101 *(uint32_t *)&((uint8_t *)&hash)[8],
1102 *(uint32_t *)&((uint8_t *)&hash)[12]
1103 ));
1104 break;
1105
1106 default:
1107 /* The surface was not cached. Fallback to dirty rects. */
1108 DISPDBG((1, "MEMBLT: bitmap not cached.\n"));
1109 DISPDBG((1, " DHSURF dhsurf = %p\n", psoSrc->dhsurf));
1110 DISPDBG((1, " HSURF hsurf = %p\n", psoSrc->hsurf));
1111 DISPDBG((1, " DHPDEV dhpdev = %p\n", psoSrc->dhpdev));
1112 DISPDBG((1, " HDEV hdev = %p\n", psoSrc->hdev));
1113 DISPDBG((1, " SIZEL sizlBitmap = %dx%d\n", psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy));
1114 DISPDBG((1, " ULONG cjBits = %p\n", psoSrc->cjBits));
1115 DISPDBG((1, " PVOID pvBits = %p\n", psoSrc->pvBits));
1116 DISPDBG((1, " PVOID pvScan0 = %p\n", psoSrc->pvScan0));
1117 DISPDBG((1, " LONG lDelta = %p\n", psoSrc->lDelta));
1118 DISPDBG((1, " ULONG iUniq = %p\n", psoSrc->iUniq));
1119 DISPDBG((1, " ULONG iBitmapFormat = %p\n", psoSrc->iBitmapFormat));
1120 DISPDBG((1, " USHORT iType = %p\n", psoSrc->iType));
1121 DISPDBG((1, " USHORT fjBitmap = %p\n", psoSrc->fjBitmap));
1122 vrdpReportDirtyRects (ppdev, &clipRects);
1123 }
1124 }
1125 }
1126 else
1127 {
1128 /* No source and no brush, only dest affected. DESTBLT. */
1129 DISPDBG((1, "VRDP::vrdpBitBlt: DSTBLT with rop 0x%08X\n", rop4));
1130 vrdpReportDstBlt (ppdev, &rclTrg, &clipRects, (uint8_t)rop4);
1131 }
1132 }
1133}
1134
1135void vrdpTextOut(
1136 SURFOBJ *pso,
1137 STROBJ *pstro,
1138 FONTOBJ *pfo,
1139 CLIPOBJ *pco,
1140 RECTL *prclExtra, // Obsolete, always NULL
1141 RECTL *prclOpaque,
1142 BRUSHOBJ *pboFore,
1143 BRUSHOBJ *pboOpaque,
1144 POINTL *pptlOrg,
1145 MIX mix
1146 )
1147{
1148 PPDEV ppdev = (PPDEV)pso->dhpdev;
1149
1150 /*
1151 * TextOut operation is supported by RDP_ORDER_TEXT2/FONTCACHE.
1152 */
1153 VRDPCLIPRECTS clipRects;
1154 int clipResult;
1155
1156 RECTL rclArea = prclOpaque? *prclOpaque: pstro->rclBkGround;
1157
1158 clipResult = vrdpGetIntersectingClipRects (&clipRects, pso, &rclArea, pco, NULL);
1159
1160 if (clipResult == VRDP_CLIP_NO_INTERSECTION)
1161 {
1162 /* Do nothing. The operation does not affect anything. */
1163 DISPDBG((1, "VRDP::vrdpTextOut: VRDP_CLIP_NO_INTERSECTION!!!\n"));
1164 dumpPCO (&rclArea, pco);
1165 }
1166 else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS)
1167 {
1168 /* A very complex clip. Better to emulate it. */
1169 DISPDBG((1, "VRDP::vrdpTextOut: VRDP_CLIP_TOO_MANY_RECTS!!!\n"));
1170 dumpPCO (&rclArea, pco);
1171
1172 vrdpReportDirtyRects (ppdev, &clipRects);
1173 }
1174 else if ( pstro->pwszOrg == NULL
1175 || prclExtra != NULL
1176 || (pfo->flFontType & FO_TYPE_RASTER) == 0
1177 || pstro->cGlyphs > VRDP_TEXT_MAX_GLYPHS
1178 || (pboOpaque && pboOpaque->iSolidColor == 0xFFFFFFFF)
1179 || pfo->iUniq == 0
1180 )
1181 {
1182 /* Unknown/unsupported parameters. */
1183 DISPDBG((1, "VRDP::vrdpTextOut: unsupported: pstro->pwszOrg=%p, prclExtra=%p, pfo->flFontType & FO_TYPE_RASTER = 0x%08X, pstro->cGlyphs = %d, pboOpaque->iSolidColor %p, pfo->iUniq = %p\n",
1184 pstro->pwszOrg, prclExtra, pfo->flFontType & FO_TYPE_RASTER, pstro->cGlyphs, pboOpaque? pboOpaque->iSolidColor: 0, pfo->iUniq));
1185 vrdpReportDirtyRects (ppdev, &clipRects);
1186 }
1187 else
1188 {
1189#if 0
1190 /* Testing: report a red rectangle for the text area. */
1191 vrdpReportSolidRect (ppdev, &clipRects, 0x0000FF);
1192#else
1193 /* Try to report the text order. */
1194 ULONG ulForeRGB = pboFore? vrdpColor2RGB (pso, pboFore->iSolidColor): 0;
1195 ULONG ulBackRGB = pboOpaque? vrdpColor2RGB (pso, pboOpaque->iSolidColor): 0;
1196
1197 DISPDBG((1, "VRDP::vrdpTextOut: calling vboxReportText fg %x bg %x\n",
1198 ulForeRGB, ulBackRGB));
1199
1200 if (!vboxReportText (ppdev, &clipRects, pstro, pfo, prclOpaque, ulForeRGB, ulBackRGB))
1201 {
1202 vrdpReportDirtyRects (ppdev, &clipRects);
1203 }
1204#endif
1205 }
1206
1207 return;
1208}
1209
1210void vrdpLineTo(
1211 SURFOBJ *pso,
1212 CLIPOBJ *pco,
1213 BRUSHOBJ *pbo,
1214 LONG x1,
1215 LONG y1,
1216 LONG x2,
1217 LONG y2,
1218 RECTL *prclBounds,
1219 MIX mix
1220 )
1221{
1222 PPDEV ppdev = (PPDEV)pso->dhpdev;
1223
1224 /*
1225 * LineTo operation is supported by RDP_ORDER_LINE.
1226 */
1227 VRDPCLIPRECTS clipRects;
1228 int clipResult;
1229 RECTL rclBoundsOrdered = *prclBounds;
1230
1231 vrdpOrderRect (&rclBoundsOrdered);
1232
1233 clipResult = vrdpGetIntersectingClipRects (&clipRects, pso, &rclBoundsOrdered, pco, NULL);
1234
1235 if (clipResult == VRDP_CLIP_NO_INTERSECTION)
1236 {
1237 /* Do nothing. The Blt does not affect anything. */
1238 DISPDBG((1, "VRDP::vrdpLineTo: VRDP_CLIP_NO_INTERSECTION!!!\n"));
1239 dumpPCO (&rclBoundsOrdered, pco);
1240 }
1241 else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS)
1242 {
1243 /* A very complex clip. Better to emulate it. */
1244 DISPDBG((1, "VRDP::vrdpLineTo: VRDP_CLIP_TOO_MANY_RECTS!!!\n"));
1245 dumpPCO (&rclBoundsOrdered, pco);
1246
1247 vrdpReportDirtyRects (ppdev, &clipRects);
1248 }
1249 else if (pbo->iSolidColor == 0xFFFFFFFF)
1250 {
1251 /* Not solid brushes are not supported. */
1252 vrdpReportDirtyRects (ppdev, &clipRects);
1253 }
1254 else
1255 {
1256 VRDPORDERLINE order;
1257
1258 order.x1 = (int16_t)x1;
1259 order.y1 = (int16_t)y1;
1260 order.x2 = (int16_t)x2;
1261 order.y2 = (int16_t)y2;
1262
1263 order.xBounds1 = ~0;
1264 order.yBounds1 = ~0;
1265 order.xBounds2 = ~0;
1266 order.yBounds2 = ~0;
1267
1268 order.mix = (uint8_t)(mix & 0x1F);
1269 order.rgb = vrdpColor2RGB (pso, pbo->iSolidColor);
1270
1271 DISPDBG((1, "VRDP::vrdpLineTo: LINE %d,%d to %d,%d mix %02X rgb %08X bounds %d-%d %d-%d cliprects %d.\n",
1272 x1, y1, x2, y2, order.mix, order.rgb,
1273 prclBounds->left, prclBounds->right, prclBounds->top, prclBounds->bottom, clipRects.rects.c));
1274
1275 vrdpReportOrderGeneric (ppdev, &clipRects, &order, sizeof (order), VRDP_ORDER_LINE);
1276 }
1277}
1278
1279void vrdpStretchBlt(
1280 SURFOBJ *psoDest,
1281 SURFOBJ *psoSrc,
1282 SURFOBJ *psoMask,
1283 CLIPOBJ *pco,
1284 XLATEOBJ *pxlo,
1285 COLORADJUSTMENT *pca,
1286 POINTL *pptlHTOrg,
1287 RECTL *prclDest,
1288 RECTL *prclSrc,
1289 POINTL *pptlMask,
1290 ULONG iMode
1291 )
1292{
1293 PPDEV ppdev = (PPDEV)psoDest->dhpdev;
1294
1295 vrdpReportDirtyClip (ppdev, pco, prclDest);
1296}
1297
1298void vrdpCopyBits(
1299 SURFOBJ *psoDest,
1300 SURFOBJ *psoSrc,
1301 CLIPOBJ *pco,
1302 XLATEOBJ *pxlo,
1303 RECTL *prclDest,
1304 POINTL *pptlSrc
1305 )
1306{
1307 /* The copy bits is the same as bit blt with particular set of parameters. */
1308 vrdpBitBlt (psoDest, psoSrc, NULL, pco, pxlo, prclDest, pptlSrc, NULL, NULL, NULL, 0xCCCC);
1309}
1310
1311void vrdpPaint(
1312 SURFOBJ *pso,
1313 CLIPOBJ *pco,
1314 BRUSHOBJ *pbo,
1315 POINTL *pptlBrushOrg,
1316 MIX mix
1317 )
1318{
1319 PPDEV ppdev = (PPDEV)pso->dhpdev;
1320
1321 vrdpReportDirtyClip (ppdev, pco, NULL);
1322}
1323
1324void vrdpFillPath(
1325 SURFOBJ *pso,
1326 PATHOBJ *ppo,
1327 CLIPOBJ *pco,
1328 BRUSHOBJ *pbo,
1329 POINTL *pptlBrushOrg,
1330 MIX mix,
1331 FLONG flOptions
1332 )
1333{
1334 PPDEV ppdev = (PPDEV)pso->dhpdev;
1335
1336 vrdpReportDirtyPath (ppdev, pco, ppo);
1337}
1338
1339static void vrdpPointFX2Point (const POINTFIX *pptfx, VRDPORDERPOINT *ppt)
1340{
1341 ppt->x = (int16_t)FXTOLROUND(pptfx->x);
1342 ppt->y = (int16_t)FXTOLROUND(pptfx->y);
1343}
1344
1345static void vrdpPolyPointsAdd (VRDPORDERPOLYPOINTS *pPoints, const VRDPORDERPOINT *ppt)
1346{
1347 VBVA_ASSERT(pPoints->c < RT_ELEMENTS(pPoints->a));
1348
1349 pPoints->a[pPoints->c] = *ppt;
1350
1351 pPoints->c++;
1352}
1353
1354static void vrdpExtendOrderBounds (VRDPORDERBOUNDS *pBounds, const VRDPORDERPOINT *ppt)
1355{
1356 /* Bounds have inclusive pt1 and exclusive pt2. */
1357
1358 if (pBounds->pt1.x > ppt->x) /* Left. */
1359 {
1360 pBounds->pt1.x = ppt->x;
1361 }
1362 if (pBounds->pt1.y > ppt->y) /* Top. */
1363 {
1364 pBounds->pt1.y = ppt->y;
1365 }
1366 if (pBounds->pt2.x <= ppt->x) /* Right. */
1367 {
1368 pBounds->pt2.x = ppt->x + 1;
1369 }
1370 if (pBounds->pt2.y <= ppt->y) /* Bottom. */
1371 {
1372 pBounds->pt2.y = ppt->y + 1;
1373 }
1374}
1375
1376void vrdpStrokePath(
1377 SURFOBJ *pso,
1378 PATHOBJ *ppo,
1379 CLIPOBJ *pco,
1380 XFORMOBJ *pxo,
1381 BRUSHOBJ *pbo,
1382 POINTL *pptlBrushOrg,
1383 LINEATTRS *plineattrs,
1384 MIX mix
1385 )
1386{
1387 PPDEV ppdev = (PPDEV)pso->dhpdev;
1388
1389 /*
1390 * StrokePath operation is supported by RDP_ORDER_POLYGON/POLYLINE/ELLIPSE.
1391 */
1392 VRDPCLIPRECTS clipRects;
1393 int clipResult;
1394 RECTFX rcfxBounds;
1395 RECTL rclBoundsOrdered;
1396
1397 DISPDBG((1, "vrdpStrokePath: pso = %p, ppo = %p, pco = %p, pxo = %p, pbo = %p, pptlBrushOrg = %p, plineattrs = %p, mix = 0x%08X\n",
1398 pso, ppo, pco, pxo, pbo, pptlBrushOrg, plineattrs, mix));
1399
1400 DISPDBG((1, "vrdpStrokePath: ppo: fl = 0x%08X, cCurves = %d\n", ppo->fl, ppo->cCurves));
1401
1402 PATHOBJ_vGetBounds(ppo, &rcfxBounds);
1403
1404 rclBoundsOrdered.left = FXTOLFLOOR(rcfxBounds.xLeft);
1405 rclBoundsOrdered.right = FXTOLCEILING(rcfxBounds.xRight);
1406 rclBoundsOrdered.top = FXTOLFLOOR(rcfxBounds.yTop);
1407 rclBoundsOrdered.bottom = FXTOLCEILING(rcfxBounds.yBottom);
1408
1409 vrdpOrderRect (&rclBoundsOrdered);
1410
1411 DISPDBG((1, "vrdpStrokePath: ppo: bounds %x-%x, %x-%x, %d-%d %d-%d\n",
1412 rcfxBounds.xLeft, rcfxBounds.xRight, rcfxBounds.yTop, rcfxBounds.yBottom,
1413 rclBoundsOrdered.left, rclBoundsOrdered.right, rclBoundsOrdered.top, rclBoundsOrdered.bottom));
1414
1415 clipResult = vrdpGetIntersectingClipRects (&clipRects, pso, &rclBoundsOrdered, pco, NULL);
1416
1417 if (clipResult == VRDP_CLIP_NO_INTERSECTION)
1418 {
1419 /* Do nothing. The operation does not affect anything. */
1420 DISPDBG((1, "VRDP::vrdpStrokePath: VRDP_CLIP_NO_INTERSECTION!!!\n"));
1421 dumpPCO (&rclBoundsOrdered, pco);
1422 }
1423 else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS)
1424 {
1425 /* A very complex clip. Better to emulate it. */
1426 DISPDBG((1, "VRDP::vrdpStrokePath: VRDP_CLIP_TOO_MANY_RECTS!!!\n"));
1427 dumpPCO (&rclBoundsOrdered, pco);
1428
1429 vrdpReportDirtyRects (ppdev, &clipRects);
1430 }
1431 else if (pbo->iSolidColor == 0xFFFFFFFF)
1432 {
1433 /* Not solid brushes are not supported. */
1434 vrdpReportDirtyRects (ppdev, &clipRects);
1435 }
1436 else if (ppo->fl & PO_ELLIPSE)
1437 {
1438 if (vboxOrderSupported (ppdev, VRDP_ORDER_ELLIPSE))
1439 {
1440 VRDPORDERELLIPSE order;
1441
1442 order.pt1.x = (int16_t)FXTOLROUND(rcfxBounds.xLeft + 4);
1443 order.pt1.y = (int16_t)FXTOLROUND(rcfxBounds.yTop + 4);
1444 order.pt2.x = (int16_t)FXTOLROUND(rcfxBounds.xRight - 4);
1445 order.pt2.y = (int16_t)FXTOLROUND(rcfxBounds.yBottom - 4);
1446
1447 order.mix = (uint8_t)(mix & 0x1F);
1448 order.fillMode = 0;
1449 order.rgb = vrdpColor2RGB (pso, pbo->iSolidColor);
1450
1451 vrdpReportOrderGeneric (ppdev, &clipRects, &order, sizeof (order), VRDP_ORDER_ELLIPSE);
1452 }
1453 else
1454 {
1455 DISPDBG((1, "VRDP::vrdpStrokePath: ELLIPSE not supported\n"));
1456 vrdpReportDirtyRects (ppdev, &clipRects);
1457 }
1458 }
1459 else if ( (ppo->fl & PO_BEZIERS) == 0
1460 && (plineattrs->fl & LA_GEOMETRIC) == 0
1461 && plineattrs->pstyle == NULL)
1462 {
1463 unsigned i;
1464 PATHDATA pd;
1465 BOOL bMore;
1466 VRDPORDERPOLYLINE order;
1467 VRDPORDERPOINT ptStart;
1468 VRDPORDERBOUNDS bounds;
1469
1470 order.rgb = vrdpColor2RGB (pso, pbo->iSolidColor);
1471 order.mix = (uint8_t)(mix & 0x1F);
1472
1473 PATHOBJ_vEnumStart (ppo);
1474
1475 order.points.c = 0;
1476
1477 do {
1478 POINTFIX *pptfx;
1479 VRDPORDERPOINT pt;
1480
1481 bMore = PATHOBJ_bEnum (ppo, &pd);
1482
1483 DISPDBG((1, "vrdpStrokePath: pd: flags = 0x%08X, count = %d\n", pd.flags, pd.count));
1484
1485 pptfx = &pd.pptfx[0];
1486
1487 if (pd.flags & PD_BEGINSUBPATH)
1488 {
1489 /* Setup first point. Start a new order. */
1490 DISPDBG((1, "vrdpStrokePath: BEGINSUBPATH.\n"));
1491
1492 VBVA_ASSERT(order.points.c == 0);
1493
1494 vrdpPointFX2Point (pptfx, &ptStart);
1495 order.ptStart = ptStart;
1496 pt = ptStart;
1497
1498 bounds.pt1 = bounds.pt2 = ptStart;
1499
1500 pptfx++;
1501 i = 1;
1502 }
1503 else
1504 {
1505 DISPDBG((1, "vrdpStrokePath: Continue order.\n"));
1506
1507 i = 0;
1508 }
1509
1510 for (; i < pd.count; i++, pptfx++)
1511 {
1512 DISPDBG((1, "vrdpStrokePath: pd: %2d: %x,%x %d,%d\n",
1513 i, pptfx->x, pptfx->y, FXTOLROUND(pptfx->x), FXTOLROUND(pptfx->y)));
1514
1515 vrdpPointFX2Point (pptfx, &pt);
1516 vrdpPolyPointsAdd (&order.points, &pt);
1517 vrdpExtendOrderBounds (&bounds, &pt);
1518
1519 if (order.points.c == RT_ELEMENTS(order.points.a))
1520 {
1521 /* Flush the order and start a new order. */
1522 DISPDBG((1, "vrdpStrokePath: Report order, points overflow.\n"));
1523
1524 vrdpReportOrderGenericBounds (ppdev, &clipRects, &bounds, &order, sizeof (order), VRDP_ORDER_POLYLINE);
1525
1526 order.points.c = 0;
1527 order.ptStart = pt;
1528 bounds.pt1 = bounds.pt2 = pt;
1529 }
1530 }
1531
1532 if (pd.flags & PD_CLOSEFIGURE)
1533 {
1534 /* Encode the start point as the end point. */
1535 DISPDBG((1, "vrdpStrokePath: Report order, CLOSEFIGURE.\n"));
1536
1537 if ( ptStart.x != pt.x
1538 || ptStart.y != pt.y)
1539 {
1540 VBVA_ASSERT(order.points.c < RT_ELEMENTS(order.points.a));
1541
1542 vrdpPolyPointsAdd (&order.points, &ptStart);
1543 vrdpExtendOrderBounds (&bounds, &ptStart);
1544 }
1545 }
1546
1547 if (pd.flags & PD_ENDSUBPATH)
1548 {
1549 /* Finish the order. */
1550 DISPDBG((1, "vrdpStrokePath: Report order, ENDSUBPATH.\n"));
1551
1552 if (order.points.c > 0)
1553 {
1554 vrdpReportOrderGenericBounds (ppdev, &clipRects, &bounds, &order, sizeof (order), VRDP_ORDER_POLYLINE);
1555 }
1556
1557 order.points.c = 0;
1558 }
1559 } while (bMore);
1560 }
1561 else
1562 {
1563 /* Not supported. */
1564 DISPDBG((1, "VRDP::vrdpStrokePath: not supported: ppo->fl = %08X, plineattrs->fl = %08X, plineattrs->pstyle = %08X\n",
1565 ppo->fl, plineattrs->fl, plineattrs->pstyle));
1566
1567 vrdpReportDirtyRects (ppdev, &clipRects);
1568 }
1569
1570 return;
1571}
1572
1573void vrdpStrokeAndFillPath(
1574 SURFOBJ *pso,
1575 PATHOBJ *ppo,
1576 CLIPOBJ *pco,
1577 XFORMOBJ *pxo,
1578 BRUSHOBJ *pboStroke,
1579 LINEATTRS *plineattrs,
1580 BRUSHOBJ *pboFill,
1581 POINTL *pptlBrushOrg,
1582 MIX mixFill,
1583 FLONG flOptions
1584 )
1585{
1586 PPDEV ppdev = (PPDEV)pso->dhpdev;
1587
1588 vrdpReportDirtyPath (ppdev, pco, ppo);
1589}
1590
1591BOOL vrdpRealizeBrush(
1592 BRUSHOBJ *pbo,
1593 SURFOBJ *psoTarget,
1594 SURFOBJ *psoPattern,
1595 SURFOBJ *psoMask,
1596 XLATEOBJ *pxlo,
1597 ULONG iHatch
1598 )
1599{
1600 BOOL bRc = FALSE;
1601
1602 DISPDBG((1, "vrdpRealizeBrush: psoMask = %p, iHatch = %d\n", psoMask, iHatch));
1603
1604 if (psoPattern)
1605 {
1606 DISPDBG((1, " DHSURF dhsurf = %p\n", psoPattern->dhsurf));
1607 DISPDBG((1, " HSURF hsurf = %p\n", psoPattern->hsurf));
1608 DISPDBG((1, " DHPDEV dhpdev = %p\n", psoPattern->dhpdev));
1609 DISPDBG((1, " HDEV hdev = %p\n", psoPattern->hdev));
1610 DISPDBG((1, " SIZEL sizlBitmap = %dx%d\n", psoPattern->sizlBitmap.cx, psoPattern->sizlBitmap.cy));
1611 DISPDBG((1, " ULONG cjBits = %p\n", psoPattern->cjBits));
1612 DISPDBG((1, " PVOID pvBits = %p\n", psoPattern->pvBits));
1613 DISPDBG((1, " PVOID pvScan0 = %p\n", psoPattern->pvScan0));
1614 DISPDBG((1, " LONG lDelta = %p\n", psoPattern->lDelta));
1615 DISPDBG((1, " ULONG iUniq = %p\n", psoPattern->iUniq));
1616 DISPDBG((1, " ULONG iBitmapFormat = %p\n", psoPattern->iBitmapFormat));
1617 DISPDBG((1, " USHORT iType = %p\n", psoPattern->iType));
1618 DISPDBG((1, " USHORT fjBitmap = %p\n", psoPattern->fjBitmap));
1619 }
1620
1621 if (psoPattern
1622 && psoPattern->sizlBitmap.cx == 8
1623 && psoPattern->sizlBitmap.cy == 8
1624 && psoPattern->iBitmapFormat == 1
1625 )
1626 {
1627 uint32_t cbBrush = sizeof (VRDPBRUSH);
1628
1629 VRDPBRUSH *pBrush = (VRDPBRUSH *)BRUSHOBJ_pvAllocRbrush (pbo, cbBrush);
1630
1631 DISPDBG((1, "vrdpRealizeBrush: pattern pBrush = %p, size = %d\n", pBrush, cbBrush));
1632
1633 if (pBrush)
1634 {
1635 int i;
1636 uint8_t *pu8Bits = (uint8_t *)psoPattern->pvScan0;
1637
1638 for (i = 0; i < 8; i++)
1639 {
1640 pBrush->u.pat.au8Pattern[i] = *pu8Bits;
1641
1642 pu8Bits += psoPattern->lDelta;
1643 }
1644
1645 /* Obtain RGB values for the brush fore and background colors:
1646 * "should translate color zero through the XLATEOBJ to get the foreground color for the brush."
1647 */
1648 pBrush->u.pat.rgbFG = vrdpColor2RGB (psoTarget, pxlo->pulXlate[0]);
1649 pBrush->u.pat.rgbBG = vrdpColor2RGB (psoTarget, pxlo->pulXlate[1]);
1650
1651 pBrush->fPattern = TRUE;
1652
1653 bRc = TRUE;
1654 }
1655 }
1656#if 0
1657 else if (psoPattern)
1658 {
1659 /* Color brushes and brushes >8x8 are cached and MEMBLT order generated. */
1660 uint32_t cbBrush = sizeof (VRDPBRUSH) +
1661 psoTarget->sizlBitmap.cx * sizeof (uint32_t) * psoTarget->sizlBitmap.cy;
1662 ??? target
1663
1664 VRDPBRUSH *pBrush = (VRDPBRUSH *)BRUSHOBJ_pvAllocRbrush (pbo, cbBrush);
1665
1666 DISPDBG((1, "vrdpRealizeBrush: bitmap pBrush = %p, size = %d\n", pBrush, cbBrush));
1667
1668 if (pBrush)
1669 {
1670 /* Byte per pattern pixel. */
1671 uint32_t cbSrcBPP = format2BytesPerPixel(psoPattern);
1672
1673 /* Source bits scanline pointer. */
1674 uint8_t *pu8BitsSrcScanLine = (uint8_t *)psoPattern->pvScan0;
1675
1676 /* Target RGB pixel pointer. */
1677 uint32_t *pu32BitsDst = &pBrush->u.bitmap.au32Bits[0];
1678
1679 int y;
1680 for (y = 0; y < psoTarget->sizlBitmap.cy; y++, pu8BitsSrcScanLine += psoPattern->lDelta)
1681 {
1682 uint8_t *pu8BitsSrc = pu8BitsSrcScanLine;
1683
1684 int x;
1685
1686 for (x = 0; x < psoTarget->sizlBitmap.cx; x++, pu8BitsSrc += cbSrcBPP)
1687 {
1688 uint32_t color = 0;
1689
1690 memcpy (&color, pu8BitsSrc, cbSrcBPP);
1691
1692 if (pxlo)
1693 {
1694 color = XLATEOBJ_iXlate (pxlo, color);
1695 }
1696
1697 *pu32BitsDst++ = vrdpColor2RGB (psoTarget, color);
1698
1699 // DISPDBG((1, "%08X", pu32BitsDst[-1]));
1700 }
1701
1702 // DISPDBG((1, "\n"));
1703 }
1704
1705 pBrush->u.bitmap.w = (uint16_t)psoTarget->sizlBitmap.cx;
1706 pBrush->u.bitmap.h = (uint16_t)psoTarget->sizlBitmap.cy;
1707
1708 pBrush->fPattern = FALSE;
1709
1710 bRc = TRUE;
1711 }
1712 }
1713#endif /* 0 */
1714
1715 return bRc;
1716}
1717
1718void vrdpSaveScreenBits(
1719 SURFOBJ *pso,
1720 ULONG iMode,
1721 ULONG_PTR ident,
1722 RECTL *prcl
1723 )
1724{
1725 PPDEV ppdev = (PPDEV)pso->dhpdev;
1726
1727 switch (iMode)
1728 {
1729 case SS_SAVE:
1730 {
1731 VRDPORDERSAVESCREEN order;
1732
1733 order.pt1.x = (int16_t)prcl->left;
1734 order.pt1.y = (int16_t)prcl->top;
1735 order.pt2.x = (int16_t)prcl->right;
1736 order.pt2.y = (int16_t)prcl->bottom;
1737
1738 order.ident = (uint8_t)ident;
1739 order.restore = 0;
1740
1741 vrdpReportOrderGeneric (ppdev, NULL, &order, sizeof (order), VRDP_ORDER_SAVESCREEN);
1742 } break;
1743
1744 case SS_RESTORE:
1745 {
1746 VRDPORDERSAVESCREEN order;
1747
1748 order.pt1.x = (int16_t)prcl->left;
1749 order.pt1.y = (int16_t)prcl->top;
1750 order.pt2.x = (int16_t)prcl->right;
1751 order.pt2.y = (int16_t)prcl->bottom;
1752
1753 order.ident = (uint8_t)ident;
1754 order.restore = 1;
1755
1756 if (vrdpReportOrderGeneric (ppdev, NULL, &order, sizeof (order), VRDP_ORDER_SAVESCREEN))
1757 {
1758 uint8_t *pu8Bits;
1759 int32_t lDelta;
1760 uint32_t w;
1761 uint32_t h;
1762
1763 int cbPixel;
1764
1765 pso = CONV_SURF(pso);
1766
1767 cbPixel = format2BytesPerPixel(pso);
1768
1769 pu8Bits = (uint8_t *)pso->pvScan0 +
1770 pso->lDelta * prcl->top +
1771 cbPixel * prcl->left;
1772
1773 lDelta = pso->lDelta;
1774
1775 w = prcl->right - prcl->left;
1776 h = prcl->bottom - prcl->top;
1777
1778 vrdpWriteBits (ppdev, pu8Bits, lDelta, prcl->left, prcl->top, w, h, cbPixel);
1779 }
1780 } break;
1781
1782 default:
1783 DISPDBG((1, "vrdpSaveScreenBits Invalid mode %d!!!\n", iMode));
1784 }
1785}
1786
1787void vrdpReset (PPDEV ppdev)
1788{
1789 DISPDBG((1, "vrdpReset %p\n", ppdev));
1790
1791 vrdpbmpReset (&ppdev->cache);
1792
1793 return;
1794}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette