VirtualBox

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

Last change on this file since 29883 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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