static int test_empty_rectangle(void) { REGION16 region, intersection; int retCode = -1; int i; RECTANGLE_16 emptyRectangles[3] = { { 0, 0, 0, 0}, { 10, 10, 10, 11}, { 10, 10, 11, 10} }; RECTANGLE_16 firstRect = { 0, 0, 100, 100 }; RECTANGLE_16 anotherRect = { 100, 100, 200, 200 }; RECTANGLE_16 expected_inter_extents = { 0, 0, 0, 0 }; region16_init(®ion); region16_init(&intersection); /* Check for empty rectangles */ for (i = 0; i < 3; i++) { if (!rectangle_is_empty(&emptyRectangles[i])) goto out; } /* Check for non-empty rectangles */ if (rectangle_is_empty(&firstRect)) goto out; /* Intersect 2 non-intersect rectangle, result should be empty */ if (!region16_union_rect(®ion, ®ion, &firstRect)) goto out; if (!region16_intersect_rect(®ion, ®ion, &anotherRect)) goto out; if (!compareRectangles(region16_extents(®ion), &expected_inter_extents, 1)) goto out; if (!region16_is_empty(®ion)) goto out; if (!rectangle_is_empty(region16_extents(&intersection))) goto out; retCode = 0; out: region16_uninit(&intersection); region16_uninit(®ion); return retCode; }
BOOL region16_intersects_rect(const REGION16 *src, const RECTANGLE_16 *arg2) { const RECTANGLE_16 *rect, *endPtr, *srcExtents; int nbRects; assert(src); assert(src->data); rect = region16_rects(src, &nbRects); if (!nbRects) return FALSE; srcExtents = region16_extents(src); if (nbRects == 1) return rectangles_intersects(srcExtents, arg2); if (!rectangles_intersects(srcExtents, arg2)) return FALSE; endPtr = rect + nbRects; for (endPtr = rect + nbRects; (rect < endPtr) && (arg2->bottom > rect->top); rect++) { if (rectangles_intersects(rect, arg2)) return TRUE; } return FALSE; }
int gdi_OutputUpdate(rdpGdi* gdi) { int nDstStep; BYTE* pDstData; int nXDst, nYDst; int nXSrc, nYSrc; int nWidth, nHeight; gdiGfxSurface* surface; RECTANGLE_16 surfaceRect; const RECTANGLE_16* extents; rdpUpdate* update = gdi->context->update; if (!gdi->graphicsReset) return 1; pDstData = gdi->primary_buffer; nDstStep = gdi->bytesPerPixel * gdi->width; surface = (gdiGfxSurface*) gdi->gfx->GetSurfaceData(gdi->gfx, gdi->outputSurfaceId); if (!surface) return -1; surfaceRect.left = 0; surfaceRect.top = 0; surfaceRect.right = gdi->width; surfaceRect.bottom = gdi->height; region16_intersect_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), &surfaceRect); if (!region16_is_empty(&(gdi->invalidRegion))) { extents = region16_extents(&(gdi->invalidRegion)); nXDst = extents->left; nYDst = extents->top; nXSrc = extents->left; nYSrc = extents->top; nWidth = extents->right - extents->left; nHeight = extents->bottom - extents->top; update->BeginPaint(gdi->context); freerdp_image_copy(pDstData, gdi->format, nDstStep, nXDst, nYDst, nWidth, nHeight, surface->data, surface->format, surface->scanline, nXSrc, nYSrc, NULL); gdi_InvalidateRegion(gdi->primary->hdc, nXDst, nYDst, nWidth, nHeight); update->EndPaint(gdi->context); } region16_clear(&(gdi->invalidRegion)); return 1; }
int gdi_OutputUpdate(rdpGdi* gdi, gdiGfxSurface* surface) { int nDstStep; BYTE* pDstData; int nXDst, nYDst; int nXSrc, nYSrc; UINT16 width, height; UINT32 surfaceX, surfaceY; RECTANGLE_16 surfaceRect; const RECTANGLE_16* extents; rdpUpdate* update = gdi->context->update; pDstData = gdi->primary_buffer; nDstStep = gdi->bytesPerPixel * gdi->width; surfaceX = surface->outputOriginX; surfaceY = surface->outputOriginY; surfaceRect.left = 0; surfaceRect.top = 0; surfaceRect.right = surface->width; surfaceRect.bottom = surface->height; region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect); if (!region16_is_empty(&(surface->invalidRegion))) { extents = region16_extents(&(surface->invalidRegion)); nXSrc = extents->left; nYSrc = extents->top; nXDst = surfaceX + extents->left; nYDst = surfaceY + extents->top; width = extents->right - extents->left; height = extents->bottom - extents->top; update->BeginPaint(gdi->context); freerdp_image_copy(pDstData, gdi->format, nDstStep, nXDst, nYDst, width, height, surface->data, surface->format, surface->scanline, nXSrc, nYSrc, NULL); gdi_InvalidateRegion(gdi->primary->hdc, nXDst, nYDst, width, height); update->EndPaint(gdi->context); } region16_clear(&(surface->invalidRegion)); return 1; }
int xf_OutputUpdate(xfContext* xfc) { UINT16 width, height; xfGfxSurface* surface; RECTANGLE_16 surfaceRect; const RECTANGLE_16* extents; if (!xfc->graphicsReset) return 1; surface = (xfGfxSurface*) xfc->gfx->GetSurfaceData(xfc->gfx, xfc->outputSurfaceId); if (!surface) return -1; surfaceRect.left = 0; surfaceRect.top = 0; surfaceRect.right = xfc->width; surfaceRect.bottom = xfc->height; region16_intersect_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &surfaceRect); XSetClipMask(xfc->display, xfc->gc, None); XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFillStyle(xfc->display, xfc->gc, FillSolid); if (!region16_is_empty(&(xfc->invalidRegion))) { extents = region16_extents(&(xfc->invalidRegion)); width = extents->right - extents->left; height = extents->bottom - extents->top; if (width > xfc->width) width = xfc->width; if (height > xfc->height) height = xfc->height; XPutImage(xfc->display, xfc->drawable, xfc->gc, surface->image, extents->left, extents->top, extents->left, extents->top, width, height); } region16_clear(&(xfc->invalidRegion)); XSetClipMask(xfc->display, xfc->gc, None); XSync(xfc->display, True); return 1; }
void xf_rail_invalidate_region(xfContext* xfc, REGION16* invalidRegion) { int index; int count; RECTANGLE_16 updateRect; RECTANGLE_16 windowRect; ULONG_PTR* pKeys = NULL; xfAppWindow* appWindow; const RECTANGLE_16* extents; REGION16 windowInvalidRegion; region16_init(&windowInvalidRegion); count = HashTable_GetKeys(xfc->railWindows, &pKeys); for (index = 0; index < count; index++) { appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, (void*) pKeys[index]); if (appWindow) { windowRect.left = MAX(appWindow->x, 0); windowRect.top = MAX(appWindow->y, 0); windowRect.right = MAX(appWindow->x + appWindow->width, 0); windowRect.bottom = MAX(appWindow->y + appWindow->height, 0); region16_clear(&windowInvalidRegion); region16_intersect_rect(&windowInvalidRegion, invalidRegion, &windowRect); if (!region16_is_empty(&windowInvalidRegion)) { extents = region16_extents(&windowInvalidRegion); updateRect.left = extents->left - appWindow->x; updateRect.top = extents->top - appWindow->y; updateRect.right = extents->right - appWindow->x; updateRect.bottom = extents->bottom - appWindow->y; if (appWindow) { xf_UpdateWindowArea(xfc, appWindow, updateRect.left, updateRect.top, updateRect.right - updateRect.left, updateRect.bottom - updateRect.top); } } } } region16_uninit(&windowInvalidRegion); }
BOOL wf_sw_end_paint(wfContext* wfc) { int i; rdpGdi* gdi; int ninvalid; RECT updateRect; HGDI_RGN cinvalid; REGION16 invalidRegion; RECTANGLE_16 invalidRect; const RECTANGLE_16* extents; rdpContext* context = (rdpContext*) wfc; gdi = context->gdi; ninvalid = gdi->primary->hdc->hwnd->ninvalid; cinvalid = gdi->primary->hdc->hwnd->cinvalid; if (ninvalid < 1) return TRUE; region16_init(&invalidRegion); for (i = 0; i < ninvalid; i++) { invalidRect.left = cinvalid[i].x; invalidRect.top = cinvalid[i].y; invalidRect.right = cinvalid[i].x + cinvalid[i].w; invalidRect.bottom = cinvalid[i].y + cinvalid[i].h; region16_union_rect(&invalidRegion, &invalidRegion, &invalidRect); } if (!region16_is_empty(&invalidRegion)) { extents = region16_extents(&invalidRegion); updateRect.left = extents->left; updateRect.top = extents->top; updateRect.right = extents->right; updateRect.bottom = extents->bottom; InvalidateRect(wfc->hwnd, &updateRect, FALSE); if (wfc->rail) wf_rail_invalidate_region(wfc, &invalidRegion); } region16_uninit(&invalidRegion); return TRUE; }
void wf_rail_invalidate_region(wfContext* wfc, REGION16* invalidRegion) { int index; int count; RECT updateRect; RECTANGLE_16 windowRect; ULONG_PTR* pKeys = NULL; wfRailWindow* railWindow; const RECTANGLE_16* extents; REGION16 windowInvalidRegion; region16_init(&windowInvalidRegion); count = HashTable_GetKeys(wfc->railWindows, &pKeys); for (index = 0; index < count; index++) { railWindow = (wfRailWindow*) HashTable_GetItemValue(wfc->railWindows, (void*) pKeys[index]); if (railWindow) { windowRect.left = railWindow->x; windowRect.top = railWindow->y; windowRect.right = railWindow->x + railWindow->width; windowRect.bottom = railWindow->y + railWindow->height; region16_clear(&windowInvalidRegion); region16_intersect_rect(&windowInvalidRegion, invalidRegion, &windowRect); if (!region16_is_empty(&windowInvalidRegion)) { extents = region16_extents(&windowInvalidRegion); updateRect.left = extents->left - railWindow->x; updateRect.top = extents->top - railWindow->y; updateRect.right = extents->right - railWindow->x; updateRect.bottom = extents->bottom - railWindow->y; InvalidateRect(railWindow->hWnd, &updateRect, FALSE); } } } region16_uninit(&windowInvalidRegion); }
static int test_norbert_case() { REGION16 region, intersection; int retCode = -1; const RECTANGLE_16 *rects; int nbRects, i; RECTANGLE_16 inRectangles[5] = { {1680, 0, 1920, 242}, { 294, 242, 971, 776}, {1680, 242, 1920, 776}, {1680, 776, 1920, 1036}, { 2, 1040, 53, 1078} }; RECTANGLE_16 screenRect = { 0, 0, 1920, 1080 }; RECTANGLE_16 expected_inter_extents = { 0, 0, 1920, 1078 }; region16_init(®ion); region16_init(&intersection); for (i = 0; i < 5; i++) { if (!region16_union_rect(®ion, ®ion, &inRectangles[i])) goto out; } if (!region16_intersect_rect(&intersection, ®ion, &screenRect)) goto out; rects = region16_rects(&intersection, &nbRects); if (!rects || nbRects != 5 || !compareRectangles(rects, inRectangles, nbRects)) goto out; if (!compareRectangles(region16_extents(&intersection), &expected_inter_extents, 1) ) goto out; retCode = 0; out: region16_uninit(&intersection); region16_uninit(®ion); return retCode; }
static UINT gdi_OutputUpdate(rdpGdi* gdi, gdiGfxSurface* surface) { UINT32 nXDst, nYDst; UINT32 nXSrc, nYSrc; UINT16 width, height; UINT32 surfaceX, surfaceY; RECTANGLE_16 surfaceRect; const RECTANGLE_16* extents; rdpUpdate* update = gdi->context->update; surfaceX = surface->outputOriginX; surfaceY = surface->outputOriginY; surfaceRect.left = 0; surfaceRect.top = 0; surfaceRect.right = surface->width; surfaceRect.bottom = surface->height; region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect); if (!region16_is_empty(&(surface->invalidRegion))) { extents = region16_extents(&(surface->invalidRegion)); nXSrc = extents->left; nYSrc = extents->top; nXDst = surfaceX + extents->left; nYDst = surfaceY + extents->top; width = extents->right - extents->left; height = extents->bottom - extents->top; update->BeginPaint(gdi->context); if (!freerdp_image_copy(gdi->primary_buffer, gdi->primary->hdc->format, gdi->stride, nXDst, nYDst, width, height, surface->data, surface->format, surface->scanline, nXSrc, nYSrc, NULL, FREERDP_FLIP_NONE)) return CHANNEL_RC_NULL_DATA; gdi_InvalidateRegion(gdi->primary->hdc, nXDst, nYDst, width, height); update->EndPaint(gdi->context); } region16_clear(&(surface->invalidRegion)); return CHANNEL_RC_OK; }
static int test_norbert_case(void) { REGION16 region, intersection; int retCode = -1; const RECTANGLE_16* rects; UINT32 nbRects, i; RECTANGLE_16 inRectangles[5] = { {1680, 0, 1920, 242}, { 294, 242, 971, 776}, {1680, 242, 1920, 776}, {1680, 776, 1920, 1036}, { 2, 1040, 53, 1078} }; RECTANGLE_16 screenRect = { 0, 0, 1920, 1080 }; RECTANGLE_16 expected_inter_extents = { 2, 0, 1920, 1078 }; region16_init(®ion); region16_init(&intersection); /* * Consider following as a screen with resolution 1920*1080 * | | | | | | | * | |2 |53 |294 |971 |1680 | * | | | | | | | * 0 +=+======================================+======+ * | | | | * | | R[0]| * 242 | +-----------+ +------+ * | | | | | | * | | | | | * | | R[1]| | R[2]| * 776 | | +-----------+ +------+ * | | | * | | R[3]| * 1036 | | +------+ * 1040 | +----+ * | |R[4]| Union of R[0-4]| * 1078 | +----+ - - - - - - - -+ * 1080 | * * * The result is union of R[0] - R[4]. * After intersected with the full screen rect, the * result should keep the same. */ for (i = 0; i < 5; i++) { if (!region16_union_rect(®ion, ®ion, &inRectangles[i])) goto out; } if (!compareRectangles(region16_extents(®ion), &expected_inter_extents, 1)) goto out; if (!region16_intersect_rect(&intersection, ®ion, &screenRect)) goto out; rects = region16_rects(&intersection, &nbRects); if (!rects || nbRects != 5 || !compareRectangles(rects, inRectangles, nbRects)) goto out; if (!compareRectangles(region16_extents(&intersection), &expected_inter_extents, 1)) goto out; retCode = 0; out: region16_uninit(&intersection); region16_uninit(®ion); return retCode; }
static int xf_OutputUpdate(xfContext* xfc, xfGfxSurface* surface) { UINT16 width, height; UINT32 surfaceX, surfaceY; RECTANGLE_16 surfaceRect; const RECTANGLE_16* extents; surfaceX = surface->outputOriginX; surfaceY = surface->outputOriginY; surfaceRect.left = surfaceX; surfaceRect.top = surfaceY; surfaceRect.right = surfaceX + surface->width; surfaceRect.bottom = surfaceY + surface->height; XSetClipMask(xfc->display, xfc->gc, None); XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFillStyle(xfc->display, xfc->gc, FillSolid); if (!region16_is_empty(&surface->invalidRegion)) { extents = region16_extents(&surface->invalidRegion); width = extents->right - extents->left; height = extents->bottom - extents->top; if (width > surface->width) width = surface->width; if (height > surface->height) height = surface->height; if (surface->stage) { freerdp_image_copy(surface->stage, xfc->format, surface->stageStep, 0, 0, surface->width, surface->height, surface->data, surface->format, surface->scanline, 0, 0, NULL); } #ifdef WITH_XRENDER if (xfc->settings->SmartSizing || xfc->settings->MultiTouchGestures) { XPutImage(xfc->display, xfc->primary, xfc->gc, surface->image, extents->left, extents->top, extents->left + surfaceX, extents->top + surfaceY, width, height); xf_draw_screen(xfc, extents->left, extents->top, width, height); } else #endif { XPutImage(xfc->display, xfc->drawable, xfc->gc, surface->image, extents->left, extents->top, extents->left + surfaceX, extents->top + surfaceY, width, height); } } region16_clear(&surface->invalidRegion); XSetClipMask(xfc->display, xfc->gc, None); XSync(xfc->display, False); return 1; }
RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects, int numRects, BYTE* data, int width, int height, int scanline) { int i, maxNbTiles, maxTilesX, maxTilesY; int xIdx, yIdx, regionNbRects; int gridRelX, gridRelY, ax, ay, bytesPerPixel; RFX_TILE* tile; RFX_RECT* rfxRect; RFX_MESSAGE* message = NULL; PTP_WORK* workObject = NULL; RFX_TILE_COMPOSE_WORK_PARAM *workParam = NULL; BOOL success = FALSE; REGION16 rectsRegion, tilesRegion; RECTANGLE_16 currentTileRect; const RECTANGLE_16 *regionRect; const RECTANGLE_16 *extents; assert(data); assert(rects); assert(numRects > 0); assert(width > 0); assert(height > 0); assert(scanline > 0); if (!(message = (RFX_MESSAGE*)calloc(1, sizeof(RFX_MESSAGE)))) return NULL; region16_init(&tilesRegion); region16_init(&rectsRegion); if (context->state == RFX_STATE_SEND_HEADERS) rfx_update_context_properties(context); message->frameIdx = context->frameIdx++; if (!context->numQuant) { if (!(context->quants = (UINT32*) malloc(sizeof(rfx_default_quantization_values)))) goto skip_encoding_loop; CopyMemory(context->quants, &rfx_default_quantization_values, sizeof(rfx_default_quantization_values)); context->numQuant = 1; context->quantIdxY = 0; context->quantIdxCb = 0; context->quantIdxCr = 0; } message->numQuant = context->numQuant; message->quantVals = context->quants; bytesPerPixel = (context->bits_per_pixel / 8); if (!computeRegion(rects, numRects, &rectsRegion, width, height)) goto skip_encoding_loop; extents = region16_extents(&rectsRegion); assert(extents->right - extents->left > 0); assert(extents->bottom - extents->top > 0); maxTilesX = 1 + TILE_NO(extents->right - 1) - TILE_NO(extents->left); maxTilesY = 1 + TILE_NO(extents->bottom - 1) - TILE_NO(extents->top); maxNbTiles = maxTilesX * maxTilesY; if (!(message->tiles = calloc(maxNbTiles, sizeof(RFX_TILE*)))) goto skip_encoding_loop; if (!setupWorkers(context, maxNbTiles)) goto skip_encoding_loop; if (context->priv->UseThreads) { workObject = context->priv->workObjects; workParam = context->priv->tileWorkParams; } regionRect = region16_rects(&rectsRegion, ®ionNbRects); if (!(message->rects = calloc(regionNbRects, sizeof(RFX_RECT)))) goto skip_encoding_loop; message->numRects = regionNbRects; for (i = 0, rfxRect = message->rects; i < regionNbRects; i++, regionRect++, rfxRect++) { int startTileX = regionRect->left / 64; int endTileX = (regionRect->right - 1) / 64; int startTileY = regionRect->top / 64; int endTileY = (regionRect->bottom - 1) / 64; rfxRect->x = regionRect->left; rfxRect->y = regionRect->top; rfxRect->width = (regionRect->right - regionRect->left); rfxRect->height = (regionRect->bottom - regionRect->top); for (yIdx = startTileY, gridRelY = startTileY * 64; yIdx <= endTileY; yIdx++, gridRelY += 64 ) { int tileHeight = 64; if ((yIdx == endTileY) && (gridRelY + 64 > height)) tileHeight = height - gridRelY; currentTileRect.top = gridRelY; currentTileRect.bottom = gridRelY + tileHeight; for (xIdx = startTileX, gridRelX = startTileX * 64; xIdx <= endTileX; xIdx++, gridRelX += 64) { int tileWidth = 64; if ((xIdx == endTileX) && (gridRelX + 64 > width)) tileWidth = width - gridRelX; currentTileRect.left = gridRelX; currentTileRect.right = gridRelX + tileWidth; /* checks if this tile is already treated */ if (region16_intersects_rect(&tilesRegion, ¤tTileRect)) continue; if (!(tile = (RFX_TILE*) ObjectPool_Take(context->priv->TilePool))) goto skip_encoding_loop; tile->xIdx = xIdx; tile->yIdx = yIdx; tile->x = gridRelX; tile->y = gridRelY; tile->scanline = scanline; tile->width = tileWidth; tile->height = tileHeight; ax = gridRelX; ay = gridRelY; if (tile->data && tile->allocated) { free(tile->data); tile->allocated = FALSE; } tile->data = &data[(ay * scanline) + (ax * bytesPerPixel)]; tile->quantIdxY = context->quantIdxY; tile->quantIdxCb = context->quantIdxCb; tile->quantIdxCr = context->quantIdxCr; tile->YLen = tile->CbLen = tile->CrLen = 0; if (!(tile->YCbCrData = (BYTE *)BufferPool_Take(context->priv->BufferPool, -1))) goto skip_encoding_loop; tile->YData = (BYTE*) &(tile->YCbCrData[((8192 + 32) * 0) + 16]); tile->CbData = (BYTE*) &(tile->YCbCrData[((8192 + 32) * 1) + 16]); tile->CrData = (BYTE*) &(tile->YCbCrData[((8192 + 32) * 2) + 16]); message->tiles[message->numTiles] = tile; message->numTiles++; if (context->priv->UseThreads) { workParam->context = context; workParam->tile = tile; if (!(*workObject = CreateThreadpoolWork( (PTP_WORK_CALLBACK)rfx_compose_message_tile_work_callback, (void*) workParam, &context->priv->ThreadPoolEnv))) { goto skip_encoding_loop; } SubmitThreadpoolWork(*workObject); workObject++; workParam++; } else { rfx_encode_rgb(context, tile); } if (!region16_union_rect(&tilesRegion, &tilesRegion, ¤tTileRect)) goto skip_encoding_loop; } /* xIdx */ } /* yIdx */ } /* rects */ success = TRUE; skip_encoding_loop: if (success && message->numTiles != maxNbTiles) { void* pmem = realloc((void*) message->tiles, sizeof(RFX_TILE*) * message->numTiles); if (pmem) message->tiles = (RFX_TILE**) pmem; else success = FALSE; } /* when using threads ensure all computations are done */ message->tilesDataSize = 0; workObject = context->priv->workObjects; for (i = 0; i < message->numTiles; i++) { tile = message->tiles[i]; if (context->priv->UseThreads) { if (*workObject) { WaitForThreadpoolWorkCallbacks(*workObject, FALSE); CloseThreadpoolWork(*workObject); } workObject++; } message->tilesDataSize += rfx_tile_length(tile); } region16_uninit(&tilesRegion); region16_uninit(&rectsRegion); if (success) return message; WLog_ERR(TAG, "%s: failed", __FUNCTION__); message->freeRects = TRUE; rfx_message_free(context, message); return NULL; }
BOOL region16_intersect_rect(REGION16 *dst, const REGION16 *src, const RECTANGLE_16 *rect) { REGION16_DATA *newItems; const RECTANGLE_16 *srcPtr, *endPtr, *srcExtents; RECTANGLE_16 *dstPtr; int nbRects, usedRects; RECTANGLE_16 common, newExtents; assert(src); assert(src->data); srcPtr = region16_rects(src, &nbRects); if (!nbRects) { region16_clear(dst); return TRUE; } srcExtents = region16_extents(src); if (nbRects == 1) { BOOL intersects = rectangles_intersection(srcExtents, rect, &common); region16_clear(dst); if (intersects) return region16_union_rect(dst, dst, &common); return TRUE; } newItems = allocateRegion(nbRects); if (!newItems) return FALSE; dstPtr = (RECTANGLE_16*) (&newItems[1]); usedRects = 0; ZeroMemory(&newExtents, sizeof(newExtents)); /* accumulate intersecting rectangles, the final region16_simplify_bands() will * do all the bad job to recreate correct rectangles */ for (endPtr = srcPtr + nbRects; (srcPtr < endPtr) && (rect->bottom > srcPtr->top); srcPtr++) { if (rectangles_intersection(srcPtr, rect, &common)) { *dstPtr = common; usedRects++; dstPtr++; newExtents.top = MIN(common.top, newExtents.top); newExtents.left = MIN(common.left, newExtents.left); newExtents.bottom = MAX(common.bottom, newExtents.bottom); newExtents.right = MAX(common.right, newExtents.right); } } newItems->nbRects = usedRects; newItems->size = sizeof(REGION16_DATA) + (usedRects * sizeof(RECTANGLE_16)); if (dst->data->size) free(dst->data); dst->data = realloc(newItems, newItems->size); if (!dst->data) { free(newItems); return FALSE; } dst->extents = newExtents; return region16_simplify_bands(dst); }
BOOL region16_union_rect(REGION16 *dst, const REGION16 *src, const RECTANGLE_16 *rect) { const RECTANGLE_16* srcExtents; RECTANGLE_16* dstExtents; const RECTANGLE_16 *currentBand, *endSrcRect, *nextBand; REGION16_DATA* newItems = NULL; RECTANGLE_16* dstRect = NULL; int usedRects, srcNbRects; UINT16 topInterBand; assert(src); assert(src->data); assert(dst); srcExtents = region16_extents(src); dstExtents = region16_extents_noconst(dst); if (!region16_n_rects(src)) { /* source is empty, so the union is rect */ dst->extents = *rect; dst->data = allocateRegion(1); if (!dst->data) return FALSE; dstRect = region16_rects_noconst(dst); dstRect->top = rect->top; dstRect->left = rect->left; dstRect->right = rect->right; dstRect->bottom = rect->bottom; return TRUE; } newItems = allocateRegion((1 + region16_n_rects(src)) * 4); if (!newItems) return FALSE; dstRect = (RECTANGLE_16*) (&newItems[1]); usedRects = 0; /* adds the piece of rect that is on the top of src */ if (rect->top < srcExtents->top) { dstRect->top = rect->top; dstRect->left = rect->left; dstRect->right = rect->right; dstRect->bottom = srcExtents->top; usedRects++; dstRect++; } /* treat possibly overlapping region */ currentBand = region16_rects(src, &srcNbRects); endSrcRect = currentBand + srcNbRects; while (currentBand < endSrcRect) { if ((currentBand->bottom <= rect->top) || (rect->bottom <= currentBand->top) || rectangle_contained_in_band(currentBand, endSrcRect, rect)) { /* no overlap between rect and the band, rect is totally below or totally above * the current band, or rect is already covered by an item of the band. * let's copy all the rectangles from this band +----+ | | rect (case 1) +----+ ================= band of srcRect ================= +----+ | | rect (case 2) +----+ */ region16_copy_band_with_union(dstRect, currentBand, endSrcRect, currentBand->top, currentBand->bottom, NULL, &usedRects, &nextBand, &dstRect); topInterBand = rect->top; } else { /* rect overlaps the band: | | | | ====^=================| |==| |=========================== band | top split | | | | v | 1 | | 2 | ^ | | | | +----+ +----+ | merge zone | | | | | | | 4 | v +----+ | | | | +----+ ^ | | | 3 | | bottom split | | | | ====v=========================| |==| |=================== | | | | possible cases: 1) no top split, merge zone then a bottom split. The band will be splitted in two 2) not band split, only the merge zone, band merged with rect but not splitted 3) a top split, the merge zone and no bottom split. The band will be split in two 4) a top split, the merge zone and also a bottom split. The band will be splitted in 3, but the coalesce algorithm may merge the created bands */ UINT16 mergeTop = currentBand->top; UINT16 mergeBottom = currentBand->bottom; /* test if we need a top split, case 3 and 4 */ if (rect->top > currentBand->top) { region16_copy_band_with_union(dstRect, currentBand, endSrcRect, currentBand->top, rect->top, NULL, &usedRects, &nextBand, &dstRect); mergeTop = rect->top; } /* do the merge zone (all cases) */ if (rect->bottom < currentBand->bottom) mergeBottom = rect->bottom; region16_copy_band_with_union(dstRect, currentBand, endSrcRect, mergeTop, mergeBottom, rect, &usedRects, &nextBand, &dstRect); /* test if we need a bottom split, case 1 and 4 */ if (rect->bottom < currentBand->bottom) { region16_copy_band_with_union(dstRect, currentBand, endSrcRect, mergeBottom, currentBand->bottom, NULL, &usedRects, &nextBand, &dstRect); } topInterBand = currentBand->bottom; } /* test if a piece of rect should be inserted as a new band between * the current band and the next one. band n and n+1 shouldn't touch. * * ============================================================== * band n * +------+ +------+ * ===========| rect |====================| |=============== * | | +------+ | | * +------+ | rect | | rect | * +------+ | | * =======================================| |================ * +------+ band n+1 * =============================================================== * */ if ((nextBand < endSrcRect) && (nextBand->top != currentBand->bottom) && (rect->bottom > currentBand->bottom) && (rect->top < nextBand->top)) { dstRect->right = rect->right; dstRect->left = rect->left; dstRect->top = topInterBand; dstRect->bottom = MIN(nextBand->top, rect->bottom); dstRect++; usedRects++; } currentBand = nextBand; } /* adds the piece of rect that is below src */ if (srcExtents->bottom < rect->bottom) { dstRect->top = MAX(srcExtents->bottom, rect->top); dstRect->left = rect->left; dstRect->right = rect->right; dstRect->bottom = rect->bottom; usedRects++; dstRect++; } if ((src == dst) && (src->data->size)) free(src->data); dstExtents->top = MIN(rect->top, srcExtents->top); dstExtents->left = MIN(rect->left, srcExtents->left); dstExtents->bottom = MAX(rect->bottom, srcExtents->bottom); dstExtents->right = MAX(rect->right, srcExtents->right); newItems->size = sizeof(REGION16_DATA) + (usedRects * sizeof(RECTANGLE_16)); dst->data = realloc(newItems, newItems->size); if (!dst->data) { free(newItems); return FALSE; } dst->data->nbRects = usedRects; return region16_simplify_bands(dst); }
int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem) { int count; int status; int x, y; int width, height; XImage* image; rdpShadowScreen* screen; rdpShadowServer* server; rdpShadowSurface* surface; RECTANGLE_16 invalidRect; RECTANGLE_16 surfaceRect; const RECTANGLE_16 *extents; server = subsystem->server; surface = server->surface; screen = server->screen; count = ArrayList_Count(server->clients); if (count < 1) return 1; if ((count == 1) && subsystem->suppressOutput) return 1; surfaceRect.left = 0; surfaceRect.top = 0; surfaceRect.right = surface->width; surfaceRect.bottom = surface->height; XLockDisplay(subsystem->display); if (subsystem->use_xshm) { image = subsystem->fb_image; XCopyArea(subsystem->display, subsystem->root_window, subsystem->fb_pixmap, subsystem->xshm_gc, 0, 0, subsystem->width, subsystem->height, 0, 0); status = shadow_capture_compare(surface->data, surface->scanline, surface->width, surface->height, (BYTE*) &(image->data[surface->width * 4]), image->bytes_per_line, &invalidRect); } else { image = XGetImage(subsystem->display, subsystem->root_window, surface->x, surface->y, surface->width, surface->height, AllPlanes, ZPixmap); status = shadow_capture_compare(surface->data, surface->scanline, surface->width, surface->height, (BYTE*) image->data, image->bytes_per_line, &invalidRect); } XSync(subsystem->display, False); XUnlockDisplay(subsystem->display); region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect); region16_intersect_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &surfaceRect); if (!region16_is_empty(&(subsystem->invalidRegion))) { extents = region16_extents(&(subsystem->invalidRegion)); x = extents->left; y = extents->top; width = extents->right - extents->left; height = extents->bottom - extents->top; freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, x, y, width, height, (BYTE*) image->data, PIXEL_FORMAT_XRGB32, image->bytes_per_line, x, y, NULL); //x11_shadow_blend_cursor(subsystem); count = ArrayList_Count(server->clients); InitializeSynchronizationBarrier(&(subsystem->barrier), count + 1, -1); SetEvent(subsystem->updateEvent); EnterSynchronizationBarrier(&(subsystem->barrier), 0); DeleteSynchronizationBarrier(&(subsystem->barrier)); if (count == 1) { rdpShadowClient* client; client = (rdpShadowClient*) ArrayList_GetItem(server->clients, 0); if (client) { subsystem->captureFrameRate = client->encoder->fps; } } ResetEvent(subsystem->updateEvent); region16_clear(&(subsystem->invalidRegion)); } if (!subsystem->use_xshm) XDestroyImage(image); return 1; }
int freerds_message_server_queue_pack(rdsBackendConnector* connector) { RDS_RECT rect; int ChainedMode; REGION16 region; wLinkedList* list; RECTANGLE_16 rect16; RDS_MSG_COMMON* node; rdsConnection* connection; const RECTANGLE_16* extents; ChainedMode = 0; connection = connector->connection; list = connector->ServerList; region16_init(®ion); LinkedList_Enumerator_Reset(list); while (LinkedList_Enumerator_MoveNext(list)) { node = (RDS_MSG_COMMON*) LinkedList_Enumerator_Current(list); if ((!ChainedMode) && (node->msgFlags & RDS_MSG_FLAG_RECT)) { rect16.left = node->rect.x; rect16.top = node->rect.y; rect16.right = node->rect.x + node->rect.width; rect16.bottom = node->rect.y + node->rect.height; region16_union_rect(®ion, ®ion, &rect16); } else { MessageQueue_Post(connector->ServerQueue, (void*) connector, node->type, (void*) node, NULL); } } LinkedList_Clear(list); if (!ChainedMode) { extents = region16_extents(®ion); rect.x = extents->left; rect.y = extents->top; rect.width = extents->right - extents->left; rect.height = extents->bottom - extents->top; freerds_message_server_align_rect(connector, &rect); if (connector->framebuffer.fbAttached && (rect.width * rect.height)) { RDS_MSG_COMMON* msg; RDS_MSG_PAINT_RECT paintRect; paintRect.type = RDS_SERVER_PAINT_RECT; paintRect.nXSrc = 0; paintRect.nYSrc = 0; paintRect.bitmapData = NULL; paintRect.bitmapDataLength = 0; paintRect.framebuffer = &(connector->framebuffer); paintRect.fbSegmentId = connector->framebuffer.fbSegmentId; paintRect.nLeftRect = rect.x; paintRect.nTopRect = rect.y; paintRect.nWidth = rect.width; paintRect.nHeight = rect.height; msg = freerds_server_message_copy((RDS_MSG_COMMON*) &paintRect); MessageQueue_Post(connector->ServerQueue, (void*) connector, msg->type, (void*) msg, NULL); } } region16_uninit(®ion); return 0; }
int shadow_client_send_surface_update(rdpShadowClient* client) { int status = -1; int nXSrc, nYSrc; int nWidth, nHeight; rdpContext* context; rdpSettings* settings; rdpShadowServer* server; rdpShadowSurface* surface; rdpShadowEncoder* encoder; REGION16 invalidRegion; RECTANGLE_16 surfaceRect; const RECTANGLE_16* extents; context = (rdpContext*) client; settings = context->settings; server = client->server; encoder = client->encoder; surface = client->inLobby ? server->lobby : server->surface; EnterCriticalSection(&(client->lock)); region16_init(&invalidRegion); region16_copy(&invalidRegion, &(client->invalidRegion)); region16_clear(&(client->invalidRegion)); LeaveCriticalSection(&(client->lock)); surfaceRect.left = 0; surfaceRect.top = 0; surfaceRect.right = surface->width; surfaceRect.bottom = surface->height; region16_intersect_rect(&invalidRegion, &invalidRegion, &surfaceRect); if (server->shareSubRect) { region16_intersect_rect(&invalidRegion, &invalidRegion, &(server->subRect)); } if (region16_is_empty(&invalidRegion)) { region16_uninit(&invalidRegion); return 1; } extents = region16_extents(&invalidRegion); nXSrc = extents->left - 0; nYSrc = extents->top - 0; nWidth = extents->right - extents->left; nHeight = extents->bottom - extents->top; //WLog_INFO(TAG, "shadow_client_send_surface_update: x: %d y: %d width: %d height: %d right: %d bottom: %d", // nXSrc, nYSrc, nWidth, nHeight, nXSrc + nWidth, nYSrc + nHeight); if (settings->RemoteFxCodec || settings->NSCodec) { status = shadow_client_send_surface_bits(client, surface, nXSrc, nYSrc, nWidth, nHeight); } else { status = shadow_client_send_bitmap_update(client, surface, nXSrc, nYSrc, nWidth, nHeight); } region16_uninit(&invalidRegion); return status; }
int win_shadow_surface_copy(winShadowSubsystem* subsystem) { int x, y; int width; int height; int count; int status = 1; int nDstStep = 0; BYTE* pDstData = NULL; rdpShadowServer* server; rdpShadowSurface* surface; RECTANGLE_16 surfaceRect; RECTANGLE_16 invalidRect; const RECTANGLE_16* extents; server = subsystem->server; surface = server->surface; if (ArrayList_Count(server->clients) < 1) { region16_clear(&(subsystem->invalidRegion)); return 1; } surfaceRect.left = surface->x; surfaceRect.top = surface->y; surfaceRect.right = surface->x + surface->width; surfaceRect.bottom = surface->y + surface->height; region16_intersect_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &surfaceRect); if (region16_is_empty(&(subsystem->invalidRegion))) return 1; extents = region16_extents(&(subsystem->invalidRegion)); CopyMemory(&invalidRect, extents, sizeof(RECTANGLE_16)); shadow_capture_align_clip_rect(&invalidRect, &surfaceRect); x = invalidRect.left; y = invalidRect.top; width = invalidRect.right - invalidRect.left; height = invalidRect.bottom - invalidRect.top; if (0) { x = 0; y = 0; width = surface->width; height = surface->height; } WLog_INFO(TAG, "SurfaceCopy x: %d y: %d width: %d height: %d right: %d bottom: %d", x, y, width, height, x + width, y + height); #if defined(WITH_WDS_API) { rdpGdi* gdi; shwContext* shw; rdpContext* context; shw = subsystem->shw; context = (rdpContext*) shw; gdi = context->gdi; pDstData = gdi->primary_buffer; nDstStep = gdi->width * 4; } #elif defined(WITH_DXGI_1_2) status = win_shadow_dxgi_fetch_frame_data(subsystem, &pDstData, &nDstStep, x, y, width, height); #endif if (status <= 0) return status; freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, x - surface->x, y - surface->y, width, height, pDstData, PIXEL_FORMAT_XRGB32, nDstStep, 0, 0, NULL); ArrayList_Lock(server->clients); count = ArrayList_Count(server->clients); shadow_multiclient_publish_and_wait(subsystem->updateEvent); ArrayList_Unlock(server->clients); region16_clear(&(subsystem->invalidRegion)); return 1; }
int xf_OutputUpdate(xfContext* xfc) { UINT16 width, height; xfGfxSurface* surface; RECTANGLE_16 surfaceRect; const RECTANGLE_16* extents; if (!xfc->graphicsReset) return 1; surface = (xfGfxSurface*) xfc->gfx->GetSurfaceData(xfc->gfx, xfc->outputSurfaceId); if (!surface) return -1; surfaceRect.left = 0; surfaceRect.top = 0; surfaceRect.right = xfc->width; surfaceRect.bottom = xfc->height; region16_intersect_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &surfaceRect); XSetClipMask(xfc->display, xfc->gc, None); XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFillStyle(xfc->display, xfc->gc, FillSolid); if (!region16_is_empty(&(xfc->invalidRegion))) { extents = region16_extents(&(xfc->invalidRegion)); width = extents->right - extents->left; height = extents->bottom - extents->top; if (width > xfc->width) width = xfc->width; if (height > xfc->height) height = xfc->height; if (surface->stage) { freerdp_image_copy(surface->stage, xfc->format, surface->stageStep, 0, 0, surface->width, surface->height, surface->data, surface->format, surface->scanline, 0, 0, NULL); } #ifdef WITH_XRENDER if (xfc->settings->SmartSizing || xfc->settings->MultiTouchGestures) { XPutImage(xfc->display, xfc->primary, xfc->gc, surface->image, extents->left, extents->top, extents->left, extents->top, width, height); xf_draw_screen(xfc, extents->left, extents->top, width, height); } else #endif { XPutImage(xfc->display, xfc->drawable, xfc->gc, surface->image, extents->left, extents->top, extents->left, extents->top, width, height); } } region16_clear(&(xfc->invalidRegion)); XSetClipMask(xfc->display, xfc->gc, None); XSync(xfc->display, True); return 1; }
int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem) { int count; int status; int x, y; int width, height; XImage* image; rdpShadowScreen* screen; rdpShadowServer* server; rdpShadowSurface* surface; RECTANGLE_16 invalidRect; RECTANGLE_16 surfaceRect; const RECTANGLE_16 *extents; server = subsystem->server; surface = server->surface; screen = server->screen; count = ArrayList_Count(server->clients); if (count < 1) return 1; surfaceRect.left = 0; surfaceRect.top = 0; surfaceRect.right = surface->width; surfaceRect.bottom = surface->height; XLockDisplay(subsystem->display); /* * Ignore BadMatch error during image capture. The screen size may be * changed outside. We will resize to correct resolution at next frame */ XSetErrorHandler(x11_shadow_error_handler_for_capture); if (subsystem->use_xshm) { image = subsystem->fb_image; XCopyArea(subsystem->display, subsystem->root_window, subsystem->fb_pixmap, subsystem->xshm_gc, 0, 0, subsystem->width, subsystem->height, 0, 0); status = shadow_capture_compare(surface->data, surface->scanline, surface->width, surface->height, (BYTE*) &(image->data[surface->width * 4]), image->bytes_per_line, &invalidRect); } else { image = XGetImage(subsystem->display, subsystem->root_window, surface->x, surface->y, surface->width, surface->height, AllPlanes, ZPixmap); if (!image) { /* * BadMatch error happened. The size may have been changed again. * Give up this frame and we will resize again in next frame */ goto fail_capture; } status = shadow_capture_compare(surface->data, surface->scanline, surface->width, surface->height, (BYTE*) image->data, image->bytes_per_line, &invalidRect); } /* Restore the default error handler */ XSetErrorHandler(NULL); XSync(subsystem->display, False); XUnlockDisplay(subsystem->display); region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect); region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect); if (!region16_is_empty(&(surface->invalidRegion))) { extents = region16_extents(&(surface->invalidRegion)); x = extents->left; y = extents->top; width = extents->right - extents->left; height = extents->bottom - extents->top; freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, x, y, width, height, (BYTE*) image->data, PIXEL_FORMAT_XRGB32, image->bytes_per_line, x, y, NULL); //x11_shadow_blend_cursor(subsystem); count = ArrayList_Count(server->clients); shadow_subsystem_frame_update((rdpShadowSubsystem *)subsystem); if (count == 1) { rdpShadowClient* client; client = (rdpShadowClient*) ArrayList_GetItem(server->clients, 0); if (client) { subsystem->captureFrameRate = shadow_encoder_preferred_fps(client->encoder); } } region16_clear(&(surface->invalidRegion)); } if (!subsystem->use_xshm) XDestroyImage(image); return 1; fail_capture: XSetErrorHandler(NULL); XSync(subsystem->display, False); XUnlockDisplay(subsystem->display); return 0; }
/** * Function description * * @return TRUE on success (or nothing need to be updated) */ static BOOL shadow_client_send_surface_update(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus) { BOOL ret = TRUE; int nXSrc, nYSrc; int nWidth, nHeight; rdpContext* context; rdpSettings* settings; rdpShadowServer* server; rdpShadowSurface* surface; rdpShadowEncoder* encoder; REGION16 invalidRegion; RECTANGLE_16 surfaceRect; const RECTANGLE_16* extents; BYTE* pSrcData; int nSrcStep; int index; int numRects = 0; const RECTANGLE_16* rects; context = (rdpContext*) client; settings = context->settings; server = client->server; encoder = client->encoder; surface = client->inLobby ? server->lobby : server->surface; EnterCriticalSection(&(client->lock)); region16_init(&invalidRegion); region16_copy(&invalidRegion, &(client->invalidRegion)); region16_clear(&(client->invalidRegion)); LeaveCriticalSection(&(client->lock)); rects = region16_rects(&(surface->invalidRegion), &numRects); for (index = 0; index < numRects; index++) { region16_union_rect(&invalidRegion, &invalidRegion, &rects[index]); } surfaceRect.left = 0; surfaceRect.top = 0; surfaceRect.right = surface->width; surfaceRect.bottom = surface->height; region16_intersect_rect(&invalidRegion, &invalidRegion, &surfaceRect); if (server->shareSubRect) { region16_intersect_rect(&invalidRegion, &invalidRegion, &(server->subRect)); } if (region16_is_empty(&invalidRegion)) { /* No image region need to be updated. Success */ goto out; } extents = region16_extents(&invalidRegion); nXSrc = extents->left; nYSrc = extents->top; nWidth = extents->right - extents->left; nHeight = extents->bottom - extents->top; pSrcData = surface->data; nSrcStep = surface->scanline; /* Move to new pSrcData / nXSrc / nYSrc according to sub rect */ if (server->shareSubRect) { int subX, subY; subX = server->subRect.left; subY = server->subRect.top; nXSrc -= subX; nYSrc -= subY; pSrcData = &pSrcData[(subY * nSrcStep) + (subX * 4)]; } //WLog_INFO(TAG, "shadow_client_send_surface_update: x: %d y: %d width: %d height: %d right: %d bottom: %d", // nXSrc, nYSrc, nWidth, nHeight, nXSrc + nWidth, nYSrc + nHeight); if (settings->SupportGraphicsPipeline && settings->GfxH264 && pStatus->gfxOpened) { /* GFX/h264 always full screen encoded */ nWidth = settings->DesktopWidth; nHeight = settings->DesktopHeight; /* Create primary surface if have not */ if (!pStatus->gfxSurfaceCreated) { /* Only init surface when we have h264 supported */ if (!(ret = shadow_client_rdpgfx_reset_graphic(client))) goto out; if (!(ret = shadow_client_rdpgfx_new_surface(client))) goto out; pStatus->gfxSurfaceCreated = TRUE; } ret = shadow_client_send_surface_gfx(client, pSrcData, nSrcStep, 0, 0, nWidth, nHeight); } else if (settings->RemoteFxCodec || settings->NSCodec) { ret = shadow_client_send_surface_bits(client, pSrcData, nSrcStep, nXSrc, nYSrc, nWidth, nHeight); } else { ret = shadow_client_send_bitmap_update(client, pSrcData, nSrcStep, nXSrc, nYSrc, nWidth, nHeight); } out: region16_uninit(&invalidRegion); return ret; }