/** @file * * VirtualBox Windows NT/2000/XP guest video driver * * VRDP graphics orders pipeline. */ /* * Copyright (C) 2006-2007 innotek GmbH * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ #include "driver.h" #include "vrdpbmp.h" #include #define VRDP_MAKE_OP(__c) (__c) typedef struct _VRDPBRUSH { BOOL fPattern; union { struct { uint32_t rgbFG; uint32_t rgbBG; uint8_t au8Pattern[8]; } pat; struct { uint16_t w; uint16_t h; uint32_t au32Bits[1]; /* Here bits continue. */ } bitmap; } u; } VRDPBRUSH; #define VRDP_CLIP_OK 0 #define VRDP_CLIP_NO_INTERSECTION 1 #define VRDP_CLIP_TOO_MANY_RECTS 2 #if 0 #define dumpPCO(a, b) do {} while (0) #else void dumpPCO (RECTL *prclTrg, CLIPOBJ *pco) { DISPDBG((1, " pco = %p Trg = %d-%d %d-%d\n", pco, prclTrg->left, prclTrg->right, prclTrg->top, prclTrg->bottom)); if (pco) { BOOL bMore; CLIPRECTS cr; RECTL* prclClip; int cRects = 0; DISPDBG((1, " pco = %d %d-%d %d-%d dc %d fc %d mode %d opt %d\n", pco->iUniq, pco->rclBounds.left, pco->rclBounds.right, pco->rclBounds.top, pco->rclBounds.bottom, pco->iDComplexity, pco->iFComplexity, pco->iMode, pco->fjOptions)); CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0); do { bMore = CLIPOBJ_bEnum(pco, sizeof(cr), (ULONG*)&cr); for (prclClip = &cr.arcl[0]; cr.c != 0; cr.c--, prclClip++) { DISPDBG((1, " %d-%d %d-%d\n", prclClip->left, prclClip->right, prclClip->top, prclClip->bottom)); cRects++; } } while (bMore); DISPDBG((1, " Total %d rects\n", cRects)); } } #endif static BOOL vrdpIsRectEmpty (const RECTL *prcl) { return (prcl->left == prcl->right) || (prcl->top == prcl->bottom); } static void vrdpIntersectRects (RECTL *prectResult, const RECTL *prect1, const RECTL *prect2) { /* Calculations are easier with left, right, top, bottom. */ int xLeft1 = prect1->left; int xRight1 = prect1->right; int xLeft2 = prect2->left; int xRight2 = prect2->right; int yTop1 = prect1->top; int yBottom1 = prect1->bottom; int yTop2 = prect2->top; int yBottom2 = prect2->bottom; int xLeftResult = max (xLeft1, xLeft2); int xRightResult = min (xRight1, xRight2); /* Initialize result to empty record. */ memset (prectResult, 0, sizeof (RECTL)); if (xLeftResult < xRightResult) { /* There is intersection by X. */ int yTopResult = max (yTop1, yTop2); int yBottomResult = min (yBottom1, yBottom2); if (yTopResult < yBottomResult) { /* There is intersection by Y. */ prectResult->left = xLeftResult; prectResult->top = yTopResult; prectResult->right = xRightResult; prectResult->bottom = yBottomResult; } } return; } static void vrdpOrderRect (RECTL *prcl) { int tmp; if (prcl->left > prcl->right) { DISPDBG((1, "vrdpOrderRect: Inverse X coordinates!!!\n")); tmp = prcl->left; prcl->left = prcl->right; prcl->right = tmp; } if (prcl->top > prcl->bottom) { DISPDBG((1, "vrdpOrderRect: Inverse Y coordinates!!!\n")); tmp = prcl->top; prcl->top = prcl->bottom; prcl->bottom = tmp; } } void vrdpAdjustRect (SURFOBJ *pso, RECTL *prcl) { int x; int y; int w; int h; 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)); if (prcl->left <= prcl->right) { x = prcl->left; w = prcl->right - prcl->left; } else { DISPDBG((1, "vrdpAdjustRect: Inverse X coordinates!!!\n")); x = prcl->right; w = prcl->left - prcl->right; } if (prcl->top <= prcl->bottom) { y = prcl->top; h = prcl->bottom - prcl->top; } else { DISPDBG((1, "vrdpAdjustRect: Inverse Y coordinates!!!\n")); y = prcl->bottom; h = prcl->top - prcl->bottom; } VBVA_ASSERT(w >= 0 && h >= 0); /* Correct negative x and y coordinates. */ if (x < 0) { x += w; /* Compute xRight which is also the new width. */ w = (x < 0)? 0: x; x = 0; } if (y < 0) { y += h; /* Compute xBottom, which is also the new height. */ h = (y < 0)? 0: y; y = 0; } /* Also check if coords are greater than the display resolution. */ if (x + w > pso->sizlBitmap.cx) { w = pso->sizlBitmap.cx > x? pso->sizlBitmap.cx - x: 0; } if (y + h > pso->sizlBitmap.cy) { h = pso->sizlBitmap.cy > y? pso->sizlBitmap.cy - y: 0; } prcl->left = x; prcl->top = y; prcl->right = x + w; prcl->bottom = y + h; DISPDBG((1, "vrdpAdjustRect: result %d-%d %d-%d\n", prcl->left, prcl->right, prcl->top, prcl->bottom)); } static int vrdpGetIntersectingClipRects (VRDPCLIPRECTS *pClipRects, SURFOBJ *pso, RECTL *prcl, CLIPOBJ *pco, POINTL *pptlSrc) { BOOL bTooManyRects = FALSE; DISPDBG((1, "vrdpGetIntersectingClipRects: pso = %p, pptlSrc = %p\n", pso, pptlSrc)); pso = CONV_SURF(pso); pClipRects->rclDstOrig = *prcl; pClipRects->rclDst = *prcl; pClipRects->rects.c = 0; vrdpAdjustRect (pso, &pClipRects->rclDst); if (pco && (pco->iDComplexity != DC_TRIVIAL)) { ULONG iDirection = CD_ANY; if (pptlSrc) { /* Operation is performed on the same (screen) surface and enumeration direction * must take into account the position of source and target rectangles. */ if (pptlSrc->x <= prcl->left) { if (pptlSrc->y <= prcl->top) { iDirection = CD_LEFTUP; } else { iDirection = CD_LEFTDOWN; } } else { if (pptlSrc->y <= prcl->top) { iDirection = CD_RIGHTUP; } else { iDirection = CD_RIGHTDOWN; } } } /* Clip the target rect by entire clipping region. Obtain the effective target. */ vrdpIntersectRects (&pClipRects->rclDst, &pClipRects->rclDst, &pco->rclBounds); /* Enumerate rectangles. Try to get all rectangles at once and if there is not * enough space (too many rectangles) fail with the bTooManyRects condition. */ CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, iDirection, 0); bTooManyRects = CLIPOBJ_bEnum(pco, sizeof(pClipRects->rects), &pClipRects->rects.c); if (!bTooManyRects) { RECTL *prclClipSrc = &pClipRects->rects.arcl[0]; RECTL *prclClipDst = prclClipSrc; ULONG cRects = pClipRects->rects.c; DISPDBG((1, "%d rects\n", cRects)); if (cRects > 0) { for (; cRects != 0; cRects--, prclClipSrc++) { vrdpIntersectRects (prclClipDst, prclClipSrc, &pClipRects->rclDst); if (vrdpIsRectEmpty (prclClipDst)) { pClipRects->rects.c--; } else { prclClipDst++; } } } else { pClipRects->rclDst.left = pClipRects->rclDst.right = 0; } } } if (vrdpIsRectEmpty (&pClipRects->rclDst)) { return VRDP_CLIP_NO_INTERSECTION; } if (bTooManyRects) { pClipRects->rects.c = 0; return VRDP_CLIP_TOO_MANY_RECTS; } return VRDP_CLIP_OK; } static uint32_t vrdpColor2RGB (SURFOBJ *pso, uint32_t color) { uint32_t rgb = 0; switch (pso->iBitmapFormat) { case BMF_16BPP: { uint8_t *d = (uint8_t *)&rgb; *d++ = (BYTE)( color << 3); /* B */ *d++ = (BYTE)((color >> 5) << 2); /* G */ *d++ = (BYTE)((color >> 11) << 3); /* R */ } break; case BMF_24BPP: case BMF_32BPP: { rgb = color & 0xFFFFFF; } break; default: DISPDBG((1, "vrdpColor2RGB: Unsupported bitmap format %d!!!\n", pso->iBitmapFormat)); } return rgb; } __inline BOOL vrdpWriteHdr (PPDEV ppdev, uint32_t u32Op) { return vboxWrite (ppdev, &u32Op, sizeof (u32Op)); } static BOOL vrdpWriteBits (PPDEV ppdev, uint8_t *pu8Bits, int lDelta, int32_t x, int32_t y, uint32_t cWidth, uint32_t cHeight, int bytesPerPixel) { BOOL bRc = FALSE; VRDPDATABITS bits; bits.cb = cHeight * cWidth * bytesPerPixel; bits.x = (int16_t)x; bits.y = (int16_t)y; bits.cWidth = (uint16_t)cWidth; bits.cHeight = (uint16_t)cHeight; bits.cbPixel = (uint8_t)bytesPerPixel; bRc = vboxWrite (ppdev, &bits, sizeof (bits)); if (bRc) { while (cHeight--) { bRc = vboxWrite (ppdev, pu8Bits, cWidth * bytesPerPixel); if (!bRc) { break; } pu8Bits += lDelta; } } return bRc; } void vrdpReportDirtyRect (PPDEV ppdev, RECTL *prcl) { SURFOBJ *pso = ppdev->psoScreenBitmap; /* This is a Bitmap Update Fallback operation. It takes bits from VRAM * and inserts them in the pipeline. These bits are not cached. */ uint8_t *pu8Bits; int32_t lDelta; uint32_t cWidth; uint32_t cHeight; BOOL bRc = FALSE; int bytesPerPixel = format2BytesPerPixel(pso); RECTL rclCopy = *prcl; vrdpAdjustRect (pso, &rclCopy); pu8Bits = (uint8_t *)pso->pvScan0 + pso->lDelta * rclCopy.top + bytesPerPixel * rclCopy.left; lDelta = pso->lDelta; cWidth = rclCopy.right - rclCopy.left; cHeight = rclCopy.bottom - rclCopy.top; if (cWidth == 0 || cHeight == 0) { return; } if (bytesPerPixel > 0) { bRc = vrdpWriteHdr (ppdev, VRDP_MAKE_OP(VRDP_ORDER_DIRTY_RECT)); if (bRc) { bRc = vrdpWriteBits (ppdev, pu8Bits, lDelta, rclCopy.left, rclCopy.top, cWidth, cHeight, bytesPerPixel); } } if (!bRc) { DISPDBG((1, "vrdpReportDirtyRect failed!!! %d,%d %dx%d, bpp = %d\n", rclCopy.left, rclCopy.top, cWidth, cHeight, bytesPerPixel)); } } static void vrdpReportDirtyPathBounds (PPDEV ppdev, CLIPOBJ *pco, PATHOBJ *ppo) { RECTFX rcfxBounds; RECTL rclBounds; PATHOBJ_vGetBounds(ppo, &rcfxBounds); rclBounds.left = FXTOLFLOOR(rcfxBounds.xLeft); rclBounds.right = FXTOLCEILING(rcfxBounds.xRight); rclBounds.top = FXTOLFLOOR(rcfxBounds.yTop); rclBounds.bottom = FXTOLCEILING(rcfxBounds.yBottom); vrdpIntersectRects (&rclBounds, &rclBounds, &pco->rclBounds); vrdpReportDirtyRect (ppdev, &rclBounds); } static void vrdpReportDirtyPath (PPDEV ppdev, CLIPOBJ *pco, PATHOBJ *ppo) { vrdpReportDirtyPathBounds (ppdev, pco, ppo); } static void vrdpReportDirtyClip (PPDEV ppdev, CLIPOBJ *pco, RECTL *prcl) { if (prcl) { vrdpReportDirtyRect (ppdev, prcl); } else if (pco) { vrdpReportDirtyRect (ppdev, &pco->rclBounds); } } static void vrdpReportDirtyRects (PPDEV ppdev, VRDPCLIPRECTS *pClipRects) { /* Ignore rects, report entire area. */ vrdpReportDirtyRect (ppdev, &pClipRects->rclDst); } /* * RDP orders reporting. */ static BOOL vrdpReportOrder (PPDEV ppdev, const void *pOrder, unsigned cbOrder, unsigned code) { BOOL bRc = vrdpWriteHdr (ppdev, VRDP_MAKE_OP(code)); if (bRc) { vboxWrite (ppdev, pOrder, cbOrder); } return bRc; } static BOOL vrdpReportBounds (PPDEV ppdev, const RECTL *prcl) { VRDPORDERBOUNDS bounds; bounds.pt1.x = (int16_t)(prcl->left); bounds.pt1.y = (int16_t)(prcl->top); bounds.pt2.x = (int16_t)(prcl->right); bounds.pt2.y = (int16_t)(prcl->bottom); return vrdpReportOrder (ppdev, &bounds, sizeof (bounds), VRDP_ORDER_BOUNDS); } static BOOL vrdpReportRepeat (PPDEV ppdev, const CLIPRECTS *pRects) { BOOL bRc = TRUE; if (pRects) { /* Start from index 1, because the first rect was already reported. */ unsigned i = 1; const RECTL *prcl = &pRects->arcl[1]; for (; i < pRects->c; i++, prcl++) { VRDPORDERREPEAT repeat; repeat.bounds.pt1.x = (int16_t)(prcl->left); repeat.bounds.pt1.y = (int16_t)(prcl->top); repeat.bounds.pt2.x = (int16_t)(prcl->right); repeat.bounds.pt2.y = (int16_t)(prcl->bottom); bRc = vrdpReportOrder (ppdev, &repeat, sizeof (repeat), VRDP_ORDER_REPEAT); if (!bRc) { return bRc; } } } return bRc; } static BOOL vrdpIntersectRectWithBounds (RECTL *prclIntersect, const RECTL *prcl, const VRDPORDERBOUNDS *pBounds) { if ( prcl->left < pBounds->pt2.x /* left < bounds_right */ && prcl->right > pBounds->pt1.x /* right < bounds_left */ && prcl->top < pBounds->pt2.y /* top < bounds_bottom */ && prcl->bottom > pBounds->pt1.y /* bottom < bounds_top */ ) { /* There is intersection. */ prclIntersect->left = max(prcl->left, pBounds->pt1.x); prclIntersect->right = min(prcl->right, pBounds->pt2.x); prclIntersect->top = max(prcl->top, pBounds->pt1.y); prclIntersect->bottom = min(prcl->bottom, pBounds->pt2.y); VBVA_ASSERT(prclIntersect->left < prclIntersect->right); VBVA_ASSERT(prclIntersect->top < prclIntersect->bottom); return TRUE; } /* No intesection. */ return FALSE; } static BOOL vrdpGetIntersectingRects (CLIPRECTS *pRects, const VRDPCLIPRECTS *pClipRects, const VRDPORDERBOUNDS *pBounds) { BOOL fReportOrder = TRUE; pRects->c = 0; /* Number of clipping rects. */ if (pClipRects->rects.c == 0) { /* There were no clipping for the order. Therefore do nothing * here and just return that order must be reported without * clipping (rc = TRUE, pRects->c = 0). */ /* Do nothing. */ } else { /* Find which clipping rects intersect with the bounds. */ unsigned c = 0; RECTL *prclIntersect = &pRects->arcl[0]; unsigned i = 0; const RECTL *prcl = &pClipRects->rects.arcl[0]; for (; i < pClipRects->rects.c; i++, prcl++) { if (vrdpIntersectRectWithBounds (prclIntersect, prcl, pBounds)) { c++; prclIntersect++; } } if (c == 0) { /* No of clip rects intersect with the bounds. */ fReportOrder = FALSE; } else { pRects->c = c; } } return fReportOrder; } BOOL vrdpReportOrderGeneric (PPDEV ppdev, const VRDPCLIPRECTS *pClipRects, const void *pvOrder, unsigned cbOrder, unsigned code) { BOOL bRc; if (pClipRects && pClipRects->rects.c > 0) { bRc = vrdpReportBounds (ppdev, &pClipRects->rects.arcl[0]); if (!bRc) { return bRc; } } bRc = vrdpReportOrder (ppdev, pvOrder, cbOrder, code); if (!bRc) { return bRc; } if (pClipRects && pClipRects->rects.c > 1) { bRc = vrdpReportRepeat (ppdev, &pClipRects->rects); } return bRc; } static void vrdpReportOrderGenericBounds (PPDEV ppdev, const VRDPCLIPRECTS *pClipRects, const VRDPORDERBOUNDS *pBounds, const void *pvOrder, unsigned cbOrder, unsigned code) { CLIPRECTS rects; if (vrdpGetIntersectingRects (&rects, pClipRects, pBounds)) { vrdpReportOrderGeneric (ppdev, pClipRects, pvOrder, cbOrder, code); } } static void vrdpReportSolidRect (PPDEV ppdev, const RECTL *prclTrg, VRDPCLIPRECTS *pClipRects, ULONG rgb) { VRDPORDERSOLIDRECT order; order.x = (int16_t)prclTrg->left; order.y = (int16_t)prclTrg->top; order.w = (uint16_t)(prclTrg->right - prclTrg->left); order.h = (uint16_t)(prclTrg->bottom - prclTrg->top); order.rgb = rgb; vrdpReportOrderGeneric (ppdev, pClipRects, &order, sizeof (order), VRDP_ORDER_SOLIDRECT); } static void vrdpReportSolidBlt (PPDEV ppdev, const RECTL *prclTrg, VRDPCLIPRECTS *pClipRects, ULONG rgb, uint8_t rop3) { VRDPORDERSOLIDBLT order; order.x = (int16_t)prclTrg->left; order.y = (int16_t)prclTrg->top; order.w = (uint16_t)(prclTrg->right - prclTrg->left); order.h = (uint16_t)(prclTrg->bottom - prclTrg->top); order.rgb = rgb; order.rop = rop3; vrdpReportOrderGeneric (ppdev, pClipRects, &order, sizeof (order), VRDP_ORDER_SOLIDBLT); } static void vrdpReportPatBlt (PPDEV ppdev, const RECTL *prclTrg, VRDPCLIPRECTS *pClipRects, VRDPBRUSH *pBrush, POINTL *pptlBrush, uint8_t rop3) { VRDPORDERPATBLTBRUSH order; int8_t xSrc = 0; int8_t ySrc = 0; if (pptlBrush) { int xDiff; int yDiff; DISPDBG((1, "Dst %d,%d Brush origin %d,%d\n", prclTrg->left, prclTrg->top, pptlBrush->x, pptlBrush->y)); xDiff = prclTrg->left - pptlBrush->x; if (xDiff < 0) { xDiff = -xDiff; } yDiff = prclTrg->top - pptlBrush->y; if (yDiff < 0) { yDiff = -yDiff; } xSrc = (int8_t)(xDiff % 8); ySrc = (int8_t)(yDiff % 8); } order.x = (int16_t)prclTrg->left; order.y = (int16_t)prclTrg->top; order.w = (uint16_t)(prclTrg->right - prclTrg->left); order.h = (uint16_t)(prclTrg->bottom - prclTrg->top); order.xSrc = xSrc; order.ySrc = ySrc; order.rgbFG = pBrush->u.pat.rgbFG; order.rgbBG = pBrush->u.pat.rgbBG; order.rop = rop3; memcpy (order.pattern, pBrush->u.pat.au8Pattern, sizeof (order.pattern)); vrdpReportOrderGeneric (ppdev, pClipRects, &order, sizeof (order), VRDP_ORDER_PATBLTBRUSH); } static void vrdpReportDstBlt (PPDEV ppdev, const RECTL *prclTrg, VRDPCLIPRECTS *pClipRects, uint8_t rop3) { VRDPORDERDSTBLT order; order.x = (int16_t)prclTrg->left; order.y = (int16_t)prclTrg->top; order.w = (uint16_t)(prclTrg->right - prclTrg->left); order.h = (uint16_t)(prclTrg->bottom - prclTrg->top); order.rop = rop3; vrdpReportOrderGeneric (ppdev, pClipRects, &order, sizeof (order), VRDP_ORDER_DSTBLT); } static void vrdpReportScreenBlt (PPDEV ppdev, const RECTL *prclTrg, VRDPCLIPRECTS *pClipRects, POINTL *pptlSrc, uint8_t rop3) { VRDPORDERSCREENBLT order; order.x = (int16_t)prclTrg->left; order.y = (int16_t)prclTrg->top; order.w = (uint16_t)(prclTrg->right - prclTrg->left); order.h = (uint16_t)(prclTrg->bottom - prclTrg->top); order.xSrc = (int16_t)pptlSrc->x; order.ySrc = (int16_t)pptlSrc->y; order.rop = rop3; vrdpReportOrderGeneric (ppdev, pClipRects, &order, sizeof (order), VRDP_ORDER_SCREENBLT); } static void vrdpReportMemBltRect (PPDEV ppdev, RECTL *prcl, int xSrc, int ySrc, uint8_t rop3, const VRDPBCHASH *phash) { VRDPORDERMEMBLT order; order.x = (int16_t)prcl->left; order.y = (int16_t)prcl->top; order.w = (uint16_t)(prcl->right - prcl->left); order.h = (uint16_t)(prcl->bottom - prcl->top); order.xSrc = (int16_t)xSrc; order.ySrc = (int16_t)ySrc; order.rop = rop3; VBVA_ASSERT(sizeof (*phash) == sizeof (order.hash)); memcpy (order.hash, phash, sizeof (*phash)); vrdpReportOrder (ppdev, &order, sizeof (order), VRDP_ORDER_MEMBLT); } static void vrdpReportMemBlt (PPDEV ppdev, VRDPCLIPRECTS *pClipRects, POINTL *pptlSrc, const uint8_t rop3, const VRDPBCHASH *phash) { if (pClipRects->rects.c == 0) { int xShift = pClipRects->rclDst.left - pClipRects->rclDstOrig.left; int yShift = pClipRects->rclDst.top - pClipRects->rclDstOrig.top; VBVA_ASSERT(xShift >= 0 && yShift >= 0); vrdpReportMemBltRect (ppdev, &pClipRects->rclDst, pptlSrc->x + xShift, pptlSrc->y + yShift, rop3, phash); } else { ULONG i; for (i = 0; i < pClipRects->rects.c; i++) { int xShift = pClipRects->rects.arcl[i].left - pClipRects->rclDstOrig.left; int yShift = pClipRects->rects.arcl[i].top - pClipRects->rclDstOrig.top; VBVA_ASSERT(xShift >= 0 && yShift >= 0); vrdpReportMemBltRect (ppdev, &pClipRects->rects.arcl[i], pptlSrc->x + xShift, pptlSrc->y + yShift, rop3, phash); } } } static void vrdpReportCachedBitmap (PPDEV ppdev, SURFOBJ *psoSrc, const VRDPBCHASH *phash) { BOOL bRc; VRDPORDERCACHEDBITMAP order; VBVA_ASSERT(sizeof (*phash) == sizeof (order.hash)); memcpy (order.hash, phash, sizeof (*phash)); bRc = vrdpReportOrder (ppdev, &order, sizeof (order), VRDP_ORDER_CACHED_BITMAP); if (bRc) { int bytesPerPixel = format2BytesPerPixel(psoSrc); uint8_t *pu8Bits = (uint8_t *)psoSrc->pvScan0; int32_t lDelta = psoSrc->lDelta; uint32_t cWidth = psoSrc->sizlBitmap.cx; uint32_t cHeight = psoSrc->sizlBitmap.cy; VBVA_ASSERT(cWidth != 0 && cHeight != 0 && bytesPerPixel != 0); vrdpWriteBits (ppdev, pu8Bits, lDelta, 0, 0, cWidth, cHeight, bytesPerPixel); } } static void vrdpReportDeletedBitmap (PPDEV ppdev, const VRDPBCHASH *phash) { VRDPORDERDELETEDBITMAP order; VBVA_ASSERT(sizeof (*phash) == sizeof (order.hash)); memcpy (order.hash, phash, sizeof (*phash)); vrdpReportOrder (ppdev, &order, sizeof (order), VRDP_ORDER_DELETED_BITMAP); } /* * VRDP driver functions. */ /* Whether the ROP4 operation requires MASK. */ #define ROP4_NEED_MASK(__rop4) ( (uint8_t)((__rop4) >> 8) != (uint8_t)(__rop4) ) /* Whether the ROP3 (lower byte of rop4) operation requires BRUSH. */ #define ROP3_NEED_BRUSH(__rop3) (((((__rop3) >> 4) ^ (__rop3)) & 0x0F) != 0) /* Whether the ROP3 (lower byte of rop4) operation requires SOURCE. */ #define ROP3_NEED_SRC(__rop3) (((((__rop3) >> 2) ^ (__rop3)) & 0x33) != 0) /* Whether the ROP3 (lower byte of rop4) operation requires DESTINATION. */ #define ROP3_NEED_DST(__rop3) (((((__rop3) >> 1) ^ (__rop3)) & 0x55) != 0) void vrdpBitBlt ( SURFOBJ *psoTrg, SURFOBJ *psoSrc, SURFOBJ *psoMask, CLIPOBJ *pco, XLATEOBJ *pxlo, RECTL *prclTrg, POINTL *pptlSrc, POINTL *pptlMask, BRUSHOBJ *pbo, POINTL *pptlBrush, ROP4 rop4) { PPDEV ppdev = (PPDEV)psoTrg->dhpdev; /* * BitBlt operation is supported by following RDP orders: * RDP_ORDER_DESTBLT ROP on the screen bits (BLACKNESS, WHITENESS, DSTINVERT). * RDP_ORDER_PATBLT ROP with screen bits and a brush. * RDP_ORDER_SCREENBLT Screen to screen with ROP. * RDP_ORDER_RECT Solid fill (SRCCOPY). * RDP_ORDER_MEMBLT ROP with screen and cached offscreen bitmap. * RDP_ORDER_TRIBLT ROP with screen, cached offscreen bitmap and a brush. * * Actual BitBlts must be mapped to these RDP operations. * Anything that can not be mapped must be emulated with dirty rect. * */ VRDPCLIPRECTS clipRects; int clipResult; RECTL rclTrg = *prclTrg; vrdpOrderRect (&rclTrg); DISPDBG((1, "vrdpBitBlt\n")); clipResult = vrdpGetIntersectingClipRects (&clipRects, psoTrg, &rclTrg, pco, bIsScreenSurface (psoSrc)? pptlSrc: NULL); if (clipResult == VRDP_CLIP_NO_INTERSECTION) { /* Do nothing. The Blt does not affect anything. */ DISPDBG((1, "VRDP::vrdpBitBlt: VRDP_CLIP_NO_INTERSECTION!!!\n")); dumpPCO (&rclTrg, pco); } else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS) { /* A very complex clip. Better to emulate it. */ DISPDBG((1, "VRDP::vrdpBitBlt: VRDP_CLIP_TOO_MANY_RECTS!!!\n")); dumpPCO (&rclTrg, pco); vrdpReportDirtyRects (ppdev, &clipRects); } else if (ROP4_NEED_MASK (rop4)) { /* Operation with mask is not supported. */ DISPDBG((1, "VRDP::vrdpBitBlt: Operation with mask is not supported.\n")); vrdpReportDirtyRects (ppdev, &clipRects); } else if (ROP3_NEED_BRUSH(rop4)) { DISPDBG((1, "VRDP::vrdpBitBlt: Operation requires brush.\n")); /* Operation requires brush. */ if (ROP3_NEED_SRC(rop4)) { /* @todo Tree way blt. RDP_ORDER_TRIBLT. */ DISPDBG((1, "VRDP::vrdpBitBlt: TRIBLT pbo->iSolidColor = 0x%08X.\n", pbo->iSolidColor)); vrdpReportDirtyRects (ppdev, &clipRects); } else { /* Only brush and destination. Check if the brush is solid. */ if (pbo->iSolidColor != 0xFFFFFFFF) { /* Solid brush. The iSolidColor is the target surface color. */ uint32_t rgb = vrdpColor2RGB (psoTrg, pbo->iSolidColor); /* Mix with solid brush. RDP_ORDER_PATBLT. Or RDP_ORDER_RECT for rop4 = 0xF0F0. */ DISPDBG((1, "VRDP::vrdpBitBlt: Solid PATBLT color = %08X, rgb %08X.\n", pbo->iSolidColor, rgb)); if (rop4 == 0xF0F0) { vrdpReportSolidRect (ppdev, &rclTrg, &clipRects, rgb); } else { vrdpReportSolidBlt (ppdev, &rclTrg, &clipRects, rgb, (uint8_t)rop4); } } else { /* Non solid brush. RDP_ORDER_PATBLT. */ DISPDBG((1, "VRDP::vrdpBitBlt: PATBLT pbo->pvRbrush = %p.\n", pbo->pvRbrush)); /* Realize brush. */ if (!pbo->pvRbrush) { BRUSHOBJ_pvGetRbrush (pbo); } if (pbo->pvRbrush) { /* Brush has been realized. */ VRDPBRUSH *pBrush = (VRDPBRUSH *)pbo->pvRbrush; if (pBrush->fPattern) { vrdpReportPatBlt (ppdev, &rclTrg, &clipRects, pBrush, pptlBrush, (uint8_t)rop4); } else { // @todo BITMAPCACHE followed by MEMBLT? vrdpReportDirtyRects (ppdev, &clipRects); } } else { /* Unsupported brush format. Fallback to dirty rects. */ vrdpReportDirtyRects (ppdev, &clipRects); } } } } else { /* Operation does not require brush. */ if (ROP3_NEED_SRC(rop4)) { DISPDBG((1, "VRDP::vrdpBitBlt: MEMBLT or SCREENBLT.\n")); /* MEMBLT or SCREENBLT. */ if (bIsScreenSurface (psoSrc)) { /* Screen to screen transfer. SCREENBLT. */ DISPDBG((1, "VRDP::vrdpBitBlt: SCREENBLT.\n")); vrdpReportScreenBlt (ppdev, &rclTrg, &clipRects, pptlSrc, (uint8_t)rop4); } else { /* Offscreen bitmap to screen. MEMBLT. */ VRDPBCHASH hash; VRDPBCHASH hashDeleted; int cacheResult; DISPDBG((1, "VRDP::vrdpBitBlt: MEMBLT.\n")); if ( (psoSrc->fjBitmap & BMF_DONTCACHE) != 0 || psoSrc->iUniq == 0 /* Bitmaps with hdev == 0 seems to have different RGB layout for 16BPP modes. * Just do not cache these bitmaps and report the dirty display area instead. */ || ( psoSrc->hdev == 0 && !(psoSrc->iBitmapFormat == BMF_24BPP || psoSrc->iBitmapFormat == BMF_32BPP) ) ) { DISPDBG((1, "MEMBLT: non cachable bitmap.\n")); cacheResult = VRDPBMP_RC_NOT_CACHED; } else { DISPDBG((1, "VRDP::vrdpBitBlt: going to cache.\n")); cacheResult = vrdpbmpCacheSurface (&ppdev->cache, psoSrc, &hash, &hashDeleted); } DISPDBG((1, "MEMBLT: cacheResult 0x%08X. trg %d,%d %dx%d src %dx%d from %d,%d\n", cacheResult, rclTrg.left, rclTrg.top, rclTrg.right - rclTrg.left, rclTrg.bottom - rclTrg.top, psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy, pptlSrc->x, pptlSrc->y)); if (cacheResult & VRDPBMP_RC_F_DELETED) { DISPDBG((1, "VRDPBMP_RC_F_DELETED\n")); vrdpReportDeletedBitmap (ppdev, &hashDeleted); cacheResult &= ~VRDPBMP_RC_F_DELETED; } switch (cacheResult) { case VRDPBMP_RC_CACHED: vrdpReportCachedBitmap (ppdev, psoSrc, &hash); /* Continue and report MEMBLT order. */ case VRDPBMP_RC_ALREADY_CACHED: vrdpReportMemBlt (ppdev, &clipRects, pptlSrc, (uint8_t)rop4, &hash); DISPDBG((1, " %08X %08X %08X %08X\n", *(uint32_t *)&((uint8_t *)&hash)[0], *(uint32_t *)&((uint8_t *)&hash)[4], *(uint32_t *)&((uint8_t *)&hash)[8], *(uint32_t *)&((uint8_t *)&hash)[12] )); break; default: /* The surface was not cached. Fallback to dirty rects. */ DISPDBG((1, "MEMBLT: bitmap not cached.\n")); DISPDBG((1, " DHSURF dhsurf = %p\n", psoSrc->dhsurf)); DISPDBG((1, " HSURF hsurf = %p\n", psoSrc->hsurf)); DISPDBG((1, " DHPDEV dhpdev = %p\n", psoSrc->dhpdev)); DISPDBG((1, " HDEV hdev = %p\n", psoSrc->hdev)); DISPDBG((1, " SIZEL sizlBitmap = %dx%d\n", psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy)); DISPDBG((1, " ULONG cjBits = %p\n", psoSrc->cjBits)); DISPDBG((1, " PVOID pvBits = %p\n", psoSrc->pvBits)); DISPDBG((1, " PVOID pvScan0 = %p\n", psoSrc->pvScan0)); DISPDBG((1, " LONG lDelta = %p\n", psoSrc->lDelta)); DISPDBG((1, " ULONG iUniq = %p\n", psoSrc->iUniq)); DISPDBG((1, " ULONG iBitmapFormat = %p\n", psoSrc->iBitmapFormat)); DISPDBG((1, " USHORT iType = %p\n", psoSrc->iType)); DISPDBG((1, " USHORT fjBitmap = %p\n", psoSrc->fjBitmap)); vrdpReportDirtyRects (ppdev, &clipRects); } } } else { /* No source and no brush, only dest affected. DESTBLT. */ DISPDBG((1, "VRDP::vrdpBitBlt: DSTBLT with rop 0x%08X\n", rop4)); vrdpReportDstBlt (ppdev, &rclTrg, &clipRects, (uint8_t)rop4); } } } void vrdpTextOut( SURFOBJ *pso, STROBJ *pstro, FONTOBJ *pfo, CLIPOBJ *pco, RECTL *prclExtra, // Obsolete, always NULL RECTL *prclOpaque, BRUSHOBJ *pboFore, BRUSHOBJ *pboOpaque, POINTL *pptlOrg, MIX mix ) { PPDEV ppdev = (PPDEV)pso->dhpdev; /* * TextOut operation is supported by RDP_ORDER_TEXT2/FONTCACHE. */ VRDPCLIPRECTS clipRects; int clipResult; RECTL rclArea = prclOpaque? *prclOpaque: pstro->rclBkGround; clipResult = vrdpGetIntersectingClipRects (&clipRects, pso, &rclArea, pco, NULL); if (clipResult == VRDP_CLIP_NO_INTERSECTION) { /* Do nothing. The operation does not affect anything. */ DISPDBG((1, "VRDP::vrdpTextOut: VRDP_CLIP_NO_INTERSECTION!!!\n")); dumpPCO (&rclArea, pco); } else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS) { /* A very complex clip. Better to emulate it. */ DISPDBG((1, "VRDP::vrdpTextOut: VRDP_CLIP_TOO_MANY_RECTS!!!\n")); dumpPCO (&rclArea, pco); vrdpReportDirtyRects (ppdev, &clipRects); } else if ( pstro->pwszOrg == NULL || prclExtra != NULL || (pfo->flFontType & FO_TYPE_RASTER) == 0 || pstro->cGlyphs > VRDP_TEXT_MAX_GLYPHS || (pboOpaque && pboOpaque->iSolidColor == 0xFFFFFFFF) || pfo->iUniq == 0 ) { /* Unknown/unsupported parameters. */ 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", pstro->pwszOrg, prclExtra, pfo->flFontType & FO_TYPE_RASTER, pstro->cGlyphs, pboOpaque? pboOpaque->iSolidColor: 0, pfo->iUniq)); vrdpReportDirtyRects (ppdev, &clipRects); } else { #if 0 /* Testing: report a red rectangle for the text area. */ vrdpReportSolidRect (ppdev, &clipRects, 0x0000FF); #else /* Try to report the text order. */ ULONG ulForeRGB = pboFore? vrdpColor2RGB (pso, pboFore->iSolidColor): 0; ULONG ulBackRGB = pboOpaque? vrdpColor2RGB (pso, pboOpaque->iSolidColor): 0; DISPDBG((1, "VRDP::vrdpTextOut: calling vboxReportText fg %x bg %x\n", ulForeRGB, ulBackRGB)); if (!vboxReportText (ppdev, &clipRects, pstro, pfo, prclOpaque, ulForeRGB, ulBackRGB)) { vrdpReportDirtyRects (ppdev, &clipRects); } #endif } return; } void vrdpLineTo( SURFOBJ *pso, CLIPOBJ *pco, BRUSHOBJ *pbo, LONG x1, LONG y1, LONG x2, LONG y2, RECTL *prclBounds, MIX mix ) { PPDEV ppdev = (PPDEV)pso->dhpdev; /* * LineTo operation is supported by RDP_ORDER_LINE. */ VRDPCLIPRECTS clipRects; int clipResult; RECTL rclBoundsOrdered = *prclBounds; vrdpOrderRect (&rclBoundsOrdered); clipResult = vrdpGetIntersectingClipRects (&clipRects, pso, &rclBoundsOrdered, pco, NULL); if (clipResult == VRDP_CLIP_NO_INTERSECTION) { /* Do nothing. The Blt does not affect anything. */ DISPDBG((1, "VRDP::vrdpLineTo: VRDP_CLIP_NO_INTERSECTION!!!\n")); dumpPCO (&rclBoundsOrdered, pco); } else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS) { /* A very complex clip. Better to emulate it. */ DISPDBG((1, "VRDP::vrdpLineTo: VRDP_CLIP_TOO_MANY_RECTS!!!\n")); dumpPCO (&rclBoundsOrdered, pco); vrdpReportDirtyRects (ppdev, &clipRects); } else if (pbo->iSolidColor == 0xFFFFFFFF) { /* Not solid brushes are not supported. */ vrdpReportDirtyRects (ppdev, &clipRects); } else { VRDPORDERLINE order; order.x1 = (int16_t)x1; order.y1 = (int16_t)y1; order.x2 = (int16_t)x2; order.y2 = (int16_t)y2; order.xBounds1 = ~0; order.yBounds1 = ~0; order.xBounds2 = ~0; order.yBounds2 = ~0; order.mix = (uint8_t)(mix & 0x1F); order.rgb = vrdpColor2RGB (pso, pbo->iSolidColor); DISPDBG((1, "VRDP::vrdpLineTo: LINE %d,%d to %d,%d mix %02X rgb %08X bounds %d-%d %d-%d cliprects %d.\n", x1, y1, x2, y2, order.mix, order.rgb, prclBounds->left, prclBounds->right, prclBounds->top, prclBounds->bottom, clipRects.rects.c)); vrdpReportOrderGeneric (ppdev, &clipRects, &order, sizeof (order), VRDP_ORDER_LINE); } } void vrdpStretchBlt( SURFOBJ *psoDest, SURFOBJ *psoSrc, SURFOBJ *psoMask, CLIPOBJ *pco, XLATEOBJ *pxlo, COLORADJUSTMENT *pca, POINTL *pptlHTOrg, RECTL *prclDest, RECTL *prclSrc, POINTL *pptlMask, ULONG iMode ) { PPDEV ppdev = (PPDEV)psoDest->dhpdev; vrdpReportDirtyClip (ppdev, pco, prclDest); } void vrdpCopyBits( SURFOBJ *psoDest, SURFOBJ *psoSrc, CLIPOBJ *pco, XLATEOBJ *pxlo, RECTL *prclDest, POINTL *pptlSrc ) { /* The copy bits is the same as bit blt with particular set of parameters. */ vrdpBitBlt (psoDest, psoSrc, NULL, pco, pxlo, prclDest, pptlSrc, NULL, NULL, NULL, 0xCCCC); } void vrdpPaint( SURFOBJ *pso, CLIPOBJ *pco, BRUSHOBJ *pbo, POINTL *pptlBrushOrg, MIX mix ) { PPDEV ppdev = (PPDEV)pso->dhpdev; vrdpReportDirtyClip (ppdev, pco, NULL); } void vrdpFillPath( SURFOBJ *pso, PATHOBJ *ppo, CLIPOBJ *pco, BRUSHOBJ *pbo, POINTL *pptlBrushOrg, MIX mix, FLONG flOptions ) { PPDEV ppdev = (PPDEV)pso->dhpdev; vrdpReportDirtyPath (ppdev, pco, ppo); } static void vrdpPointFX2Point (const POINTFIX *pptfx, VRDPORDERPOINT *ppt) { ppt->x = (int16_t)FXTOLROUND(pptfx->x); ppt->y = (int16_t)FXTOLROUND(pptfx->y); } static void vrdpPolyPointsAdd (VRDPORDERPOLYPOINTS *pPoints, const VRDPORDERPOINT *ppt) { VBVA_ASSERT(pPoints->c < ELEMENTS(pPoints->a)); pPoints->a[pPoints->c] = *ppt; pPoints->c++; } static void vrdpExtendOrderBounds (VRDPORDERBOUNDS *pBounds, const VRDPORDERPOINT *ppt) { /* Bounds have inclusive pt1 and exclusive pt2. */ if (pBounds->pt1.x > ppt->x) /* Left. */ { pBounds->pt1.x = ppt->x; } if (pBounds->pt1.y > ppt->y) /* Top. */ { pBounds->pt1.y = ppt->y; } if (pBounds->pt2.x <= ppt->x) /* Right. */ { pBounds->pt2.x = ppt->x + 1; } if (pBounds->pt2.y <= ppt->y) /* Bottom. */ { pBounds->pt2.y = ppt->y + 1; } } void vrdpStrokePath( SURFOBJ *pso, PATHOBJ *ppo, CLIPOBJ *pco, XFORMOBJ *pxo, BRUSHOBJ *pbo, POINTL *pptlBrushOrg, LINEATTRS *plineattrs, MIX mix ) { PPDEV ppdev = (PPDEV)pso->dhpdev; /* * StrokePath operation is supported by RDP_ORDER_POLYGON/POLYLINE/ELLIPSE. */ VRDPCLIPRECTS clipRects; int clipResult; RECTFX rcfxBounds; RECTL rclBoundsOrdered; DISPDBG((1, "vrdpStrokePath: pso = %p, ppo = %p, pco = %p, pxo = %p, pbo = %p, pptlBrushOrg = %p, plineattrs = %p, mix = 0x%08X\n", pso, ppo, pco, pxo, pbo, pptlBrushOrg, plineattrs, mix)); DISPDBG((1, "vrdpStrokePath: ppo: fl = 0x%08X, cCurves = %d\n", ppo->fl, ppo->cCurves)); PATHOBJ_vGetBounds(ppo, &rcfxBounds); rclBoundsOrdered.left = FXTOLFLOOR(rcfxBounds.xLeft); rclBoundsOrdered.right = FXTOLCEILING(rcfxBounds.xRight); rclBoundsOrdered.top = FXTOLFLOOR(rcfxBounds.yTop); rclBoundsOrdered.bottom = FXTOLCEILING(rcfxBounds.yBottom); vrdpOrderRect (&rclBoundsOrdered); DISPDBG((1, "vrdpStrokePath: ppo: bounds %x-%x, %x-%x, %d-%d %d-%d\n", rcfxBounds.xLeft, rcfxBounds.xRight, rcfxBounds.yTop, rcfxBounds.yBottom, rclBoundsOrdered.left, rclBoundsOrdered.right, rclBoundsOrdered.top, rclBoundsOrdered.bottom)); clipResult = vrdpGetIntersectingClipRects (&clipRects, pso, &rclBoundsOrdered, pco, NULL); if (clipResult == VRDP_CLIP_NO_INTERSECTION) { /* Do nothing. The operation does not affect anything. */ DISPDBG((1, "VRDP::vrdpStrokePath: VRDP_CLIP_NO_INTERSECTION!!!\n")); dumpPCO (&rclBoundsOrdered, pco); } else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS) { /* A very complex clip. Better to emulate it. */ DISPDBG((1, "VRDP::vrdpStrokePath: VRDP_CLIP_TOO_MANY_RECTS!!!\n")); dumpPCO (&rclBoundsOrdered, pco); vrdpReportDirtyRects (ppdev, &clipRects); } else if (pbo->iSolidColor == 0xFFFFFFFF) { /* Not solid brushes are not supported. */ vrdpReportDirtyRects (ppdev, &clipRects); } else if (ppo->fl & PO_ELLIPSE) { if (vboxOrderSupported (ppdev, VRDP_ORDER_ELLIPSE)) { VRDPORDERELLIPSE order; order.pt1.x = (int16_t)FXTOLROUND(rcfxBounds.xLeft + 4); order.pt1.y = (int16_t)FXTOLROUND(rcfxBounds.yTop + 4); order.pt2.x = (int16_t)FXTOLROUND(rcfxBounds.xRight - 4); order.pt2.y = (int16_t)FXTOLROUND(rcfxBounds.yBottom - 4); order.mix = (uint8_t)(mix & 0x1F); order.fillMode = 0; order.rgb = vrdpColor2RGB (pso, pbo->iSolidColor); vrdpReportOrderGeneric (ppdev, &clipRects, &order, sizeof (order), VRDP_ORDER_ELLIPSE); } else { DISPDBG((1, "VRDP::vrdpStrokePath: ELLIPSE not supported\n")); vrdpReportDirtyRects (ppdev, &clipRects); } } else if ( (ppo->fl & PO_BEZIERS) == 0 && (plineattrs->fl & LA_GEOMETRIC) == 0 && plineattrs->pstyle == NULL) { unsigned i; PATHDATA pd; BOOL bMore; VRDPORDERPOLYLINE order; VRDPORDERPOINT ptStart; VRDPORDERBOUNDS bounds; order.rgb = vrdpColor2RGB (pso, pbo->iSolidColor); order.mix = (uint8_t)(mix & 0x1F); PATHOBJ_vEnumStart (ppo); order.points.c = 0; do { POINTFIX *pptfx; VRDPORDERPOINT pt; bMore = PATHOBJ_bEnum (ppo, &pd); DISPDBG((1, "vrdpStrokePath: pd: flags = 0x%08X, count = %d\n", pd.flags, pd.count)); pptfx = &pd.pptfx[0]; if (pd.flags & PD_BEGINSUBPATH) { /* Setup first point. Start a new order. */ DISPDBG((1, "vrdpStrokePath: BEGINSUBPATH.\n")); VBVA_ASSERT(order.points.c == 0); vrdpPointFX2Point (pptfx, &ptStart); order.ptStart = ptStart; pt = ptStart; bounds.pt1 = bounds.pt2 = ptStart; pptfx++; i = 1; } else { DISPDBG((1, "vrdpStrokePath: Continue order.\n")); i = 0; } for (; i < pd.count; i++, pptfx++) { DISPDBG((1, "vrdpStrokePath: pd: %2d: %x,%x %d,%d\n", i, pptfx->x, pptfx->y, FXTOLROUND(pptfx->x), FXTOLROUND(pptfx->y))); vrdpPointFX2Point (pptfx, &pt); vrdpPolyPointsAdd (&order.points, &pt); vrdpExtendOrderBounds (&bounds, &pt); if (order.points.c == ELEMENTS(order.points.a)) { /* Flush the order and start a new order. */ DISPDBG((1, "vrdpStrokePath: Report order, points overflow.\n")); vrdpReportOrderGenericBounds (ppdev, &clipRects, &bounds, &order, sizeof (order), VRDP_ORDER_POLYLINE); order.points.c = 0; order.ptStart = pt; bounds.pt1 = bounds.pt2 = pt; } } if (pd.flags & PD_CLOSEFIGURE) { /* Encode the start point as the end point. */ DISPDBG((1, "vrdpStrokePath: Report order, CLOSEFIGURE.\n")); if ( ptStart.x != pt.x || ptStart.y != pt.y) { VBVA_ASSERT(order.points.c < ELEMENTS(order.points.a)); vrdpPolyPointsAdd (&order.points, &ptStart); vrdpExtendOrderBounds (&bounds, &ptStart); } } if (pd.flags & PD_ENDSUBPATH) { /* Finish the order. */ DISPDBG((1, "vrdpStrokePath: Report order, ENDSUBPATH.\n")); if (order.points.c > 0) { vrdpReportOrderGenericBounds (ppdev, &clipRects, &bounds, &order, sizeof (order), VRDP_ORDER_POLYLINE); } order.points.c = 0; } } while (bMore); } else { /* Not supported. */ DISPDBG((1, "VRDP::vrdpStrokePath: not supported: ppo->fl = %08X, plineattrs->fl = %08X, plineattrs->pstyle = %08X\n", ppo->fl, plineattrs->fl, plineattrs->pstyle)); vrdpReportDirtyRects (ppdev, &clipRects); } return; } BOOL vrdpRealizeBrush( BRUSHOBJ *pbo, SURFOBJ *psoTarget, SURFOBJ *psoPattern, SURFOBJ *psoMask, XLATEOBJ *pxlo, ULONG iHatch ) { BOOL bRc = FALSE; DISPDBG((1, "vrdpRealizeBrush: psoMask = %p, iHatch = %d\n", psoMask, iHatch)); if (psoPattern) { DISPDBG((1, " DHSURF dhsurf = %p\n", psoPattern->dhsurf)); DISPDBG((1, " HSURF hsurf = %p\n", psoPattern->hsurf)); DISPDBG((1, " DHPDEV dhpdev = %p\n", psoPattern->dhpdev)); DISPDBG((1, " HDEV hdev = %p\n", psoPattern->hdev)); DISPDBG((1, " SIZEL sizlBitmap = %dx%d\n", psoPattern->sizlBitmap.cx, psoPattern->sizlBitmap.cy)); DISPDBG((1, " ULONG cjBits = %p\n", psoPattern->cjBits)); DISPDBG((1, " PVOID pvBits = %p\n", psoPattern->pvBits)); DISPDBG((1, " PVOID pvScan0 = %p\n", psoPattern->pvScan0)); DISPDBG((1, " LONG lDelta = %p\n", psoPattern->lDelta)); DISPDBG((1, " ULONG iUniq = %p\n", psoPattern->iUniq)); DISPDBG((1, " ULONG iBitmapFormat = %p\n", psoPattern->iBitmapFormat)); DISPDBG((1, " USHORT iType = %p\n", psoPattern->iType)); DISPDBG((1, " USHORT fjBitmap = %p\n", psoPattern->fjBitmap)); } if (psoPattern && psoPattern->sizlBitmap.cx == 8 && psoPattern->sizlBitmap.cy == 8 && psoPattern->iBitmapFormat == 1 ) { uint32_t cbBrush = sizeof (VRDPBRUSH); VRDPBRUSH *pBrush = (VRDPBRUSH *)BRUSHOBJ_pvAllocRbrush (pbo, cbBrush); DISPDBG((1, "vrdpRealizeBrush: pattern pBrush = %p, size = %d\n", pBrush, cbBrush)); if (pBrush) { int i; uint8_t *pu8Bits = (uint8_t *)psoPattern->pvScan0; for (i = 0; i < 8; i++) { pBrush->u.pat.au8Pattern[i] = *pu8Bits; pu8Bits += psoPattern->lDelta; } /* Obtain RGB values for the brush fore and background colors. */ pBrush->u.pat.rgbFG = vrdpColor2RGB (psoTarget, pxlo->pulXlate[1]); pBrush->u.pat.rgbBG = vrdpColor2RGB (psoTarget, pxlo->pulXlate[0]); pBrush->fPattern = TRUE; bRc = TRUE; } } #if 0 else if (psoPattern) { /* Color brushes and brushes >8x8 are cached and MEMBLT order generated. */ uint32_t cbBrush = sizeof (VRDPBRUSH) + psoTarget->sizlBitmap.cx * sizeof (uint32_t) * psoTarget->sizlBitmap.cy; ??? target VRDPBRUSH *pBrush = (VRDPBRUSH *)BRUSHOBJ_pvAllocRbrush (pbo, cbBrush); DISPDBG((1, "vrdpRealizeBrush: bitmap pBrush = %p, size = %d\n", pBrush, cbBrush)); if (pBrush) { /* Byte per pattern pixel. */ uint32_t cbSrcBPP = format2BytesPerPixel(psoPattern); /* Source bits scanline pointer. */ uint8_t *pu8BitsSrcScanLine = (uint8_t *)psoPattern->pvScan0; /* Target RGB pixel pointer. */ uint32_t *pu32BitsDst = &pBrush->u.bitmap.au32Bits[0]; int y; for (y = 0; y < psoTarget->sizlBitmap.cy; y++, pu8BitsSrcScanLine += psoPattern->lDelta) { uint8_t *pu8BitsSrc = pu8BitsSrcScanLine; int x; for (x = 0; x < psoTarget->sizlBitmap.cx; x++, pu8BitsSrc += cbSrcBPP) { uint32_t color = 0; memcpy (&color, pu8BitsSrc, cbSrcBPP); if (pxlo) { color = XLATEOBJ_iXlate (pxlo, color); } *pu32BitsDst++ = vrdpColor2RGB (psoTarget, color); // DISPDBG((1, "%08X", pu32BitsDst[-1])); } // DISPDBG((1, "\n")); } pBrush->u.bitmap.w = (uint16_t)psoTarget->sizlBitmap.cx; pBrush->u.bitmap.h = (uint16_t)psoTarget->sizlBitmap.cy; pBrush->fPattern = FALSE; bRc = TRUE; } } #endif /* 0 */ return bRc; } void vrdpSaveScreenBits( SURFOBJ *pso, ULONG iMode, ULONG_PTR ident, RECTL *prcl ) { PPDEV ppdev = (PPDEV)pso->dhpdev; switch (iMode) { case SS_SAVE: { VRDPORDERSAVESCREEN order; order.pt1.x = (int16_t)prcl->left; order.pt1.y = (int16_t)prcl->top; order.pt2.x = (int16_t)prcl->right; order.pt2.y = (int16_t)prcl->bottom; order.ident = (uint8_t)ident; order.restore = 0; vrdpReportOrderGeneric (ppdev, NULL, &order, sizeof (order), VRDP_ORDER_SAVESCREEN); } break; case SS_RESTORE: { VRDPORDERSAVESCREEN order; order.pt1.x = (int16_t)prcl->left; order.pt1.y = (int16_t)prcl->top; order.pt2.x = (int16_t)prcl->right; order.pt2.y = (int16_t)prcl->bottom; order.ident = (uint8_t)ident; order.restore = 1; if (vrdpReportOrderGeneric (ppdev, NULL, &order, sizeof (order), VRDP_ORDER_SAVESCREEN)) { uint8_t *pu8Bits; int32_t lDelta; uint32_t w; uint32_t h; int cbPixel; pso = CONV_SURF(pso); cbPixel = format2BytesPerPixel(pso); pu8Bits = (uint8_t *)pso->pvScan0 + pso->lDelta * prcl->top + cbPixel * prcl->left; lDelta = pso->lDelta; w = prcl->right - prcl->left; h = prcl->bottom - prcl->top; vrdpWriteBits (ppdev, pu8Bits, lDelta, prcl->left, prcl->top, w, h, cbPixel); } } break; default: DISPDBG((1, "vrdpSaveScreenBits Invalid mode %d!!!\n", iMode)); } } void vrdpReset (PPDEV ppdev) { DISPDBG((1, "vrdpReset %p\n", ppdev)); vrdpbmpReset (&ppdev->cache); return; }