Bool rfbSendCursorPos(rfbClientPtr cl) { rfbFramebufferUpdateRectHeader rect; if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) { if (!rfbSendUpdateBuf(cl)) return FALSE; } cl->clientCursorLocation = currentCursorLoc(); rect.encoding = Swap32IfLE(rfbEncodingPointerPos); rect.r.x = Swap16IfLE((CARD16)cl->clientCursorLocation.x); rect.r.y = Swap16IfLE((CARD16)cl->clientCursorLocation.y); rect.r.w = 0; rect.r.h = 0; memcpy(&cl->updateBuf[cl->ublen], (char *)&rect, sz_rfbFramebufferUpdateRectHeader); cl->ublen += sz_rfbFramebufferUpdateRectHeader; cl->rfbRectanglesSent[rfbStatsCursorPosition]++; cl->rfbBytesSent[rfbStatsCursorPosition] += sz_rfbFramebufferUpdateRectHeader; if (!rfbSendUpdateBuf(cl)) return FALSE; return TRUE; }
Bool rfbSendRectEncodingHextile(rfbClientPtr cl, int x, int y, int w, int h) { rfbFramebufferUpdateRectHeader rect; if (ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) { if (!rfbSendUpdateBuf(cl)) return FALSE; } rect.r.x = Swap16IfLE(x); rect.r.y = Swap16IfLE(y); rect.r.w = Swap16IfLE(w); rect.r.h = Swap16IfLE(h); rect.encoding = Swap32IfLE(rfbEncodingHextile); memcpy(&updateBuf[ublen], (char *)&rect, sz_rfbFramebufferUpdateRectHeader); ublen += sz_rfbFramebufferUpdateRectHeader; cl->rfbRectanglesSent[rfbEncodingHextile]++; cl->rfbBytesSent[rfbEncodingHextile] += sz_rfbFramebufferUpdateRectHeader; switch (cl->format.bitsPerPixel) { case 8: return sendHextiles8(cl, x, y, w, h); case 16: return sendHextiles16(cl, x, y, w, h); case 32: return sendHextiles32(cl, x, y, w, h); } rfbLog("rfbSendRectEncodingHextile: bpp %d?\n", cl->format.bitsPerPixel); return FALSE; }
rfbBool rfbSendRectEncodingZRLE(rfbClientPtr cl, int x, int y, int w, int h) { zrleOutStream* zos; rfbFramebufferUpdateRectHeader rect; rfbZRLEHeader hdr; int i; if (cl->preferredEncoding == rfbEncodingZYWRLE) { if (cl->tightQualityLevel < 0) { cl->zywrleLevel = 1; } else if (cl->tightQualityLevel < 3) { cl->zywrleLevel = 3; } else if (cl->tightQualityLevel < 6) { cl->zywrleLevel = 2; } else { cl->zywrleLevel = 1; } } else cl->zywrleLevel = 0; if (!cl->zrleData) cl->zrleData = zrleOutStreamNew(); zos = cl->zrleData; zos->in.ptr = zos->in.start; zos->out.ptr = zos->out.start; switch (cl->format.bitsPerPixel) { case 8: zrleEncode8NE(x, y, w, h, zos, zrleBeforeBuf, cl); break; case 16: if (cl->format.greenMax > 0x1F) { if (cl->format.bigEndian) zrleEncode16BE(x, y, w, h, zos, zrleBeforeBuf, cl); else zrleEncode16LE(x, y, w, h, zos, zrleBeforeBuf, cl); } else { if (cl->format.bigEndian) zrleEncode15BE(x, y, w, h, zos, zrleBeforeBuf, cl); else zrleEncode15LE(x, y, w, h, zos, zrleBeforeBuf, cl); } break; case 32: { rfbBool fitsInLS3Bytes = ((cl->format.redMax << cl->format.redShift) < (1<<24) && (cl->format.greenMax << cl->format.greenShift) < (1<<24) && (cl->format.blueMax << cl->format.blueShift) < (1<<24)); rfbBool fitsInMS3Bytes = (cl->format.redShift > 7 && cl->format.greenShift > 7 && cl->format.blueShift > 7); if ((fitsInLS3Bytes && !cl->format.bigEndian) || (fitsInMS3Bytes && cl->format.bigEndian)) { if (cl->format.bigEndian) zrleEncode24ABE(x, y, w, h, zos, zrleBeforeBuf, cl); else zrleEncode24ALE(x, y, w, h, zos, zrleBeforeBuf, cl); } else if ((fitsInLS3Bytes && cl->format.bigEndian) || (fitsInMS3Bytes && !cl->format.bigEndian)) { if (cl->format.bigEndian) zrleEncode24BBE(x, y, w, h, zos, zrleBeforeBuf, cl); else zrleEncode24BLE(x, y, w, h, zos, zrleBeforeBuf, cl); } else { if (cl->format.bigEndian) zrleEncode32BE(x, y, w, h, zos, zrleBeforeBuf, cl); else zrleEncode32LE(x, y, w, h, zos, zrleBeforeBuf, cl); } } break; } rfbStatRecordEncodingSent(cl, rfbEncodingZRLE, sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader + ZRLE_BUFFER_LENGTH(&zos->out), + w * (cl->format.bitsPerPixel / 8) * h); if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader > UPDATE_BUF_SIZE) { if (!rfbSendUpdateBuf(cl)) return FALSE; } rect.r.x = Swap16IfLE(x); rect.r.y = Swap16IfLE(y); rect.r.w = Swap16IfLE(w); rect.r.h = Swap16IfLE(h); rect.encoding = Swap32IfLE(cl->preferredEncoding); memcpy(cl->updateBuf+cl->ublen, (char *)&rect, sz_rfbFramebufferUpdateRectHeader); cl->ublen += sz_rfbFramebufferUpdateRectHeader; hdr.length = Swap32IfLE(ZRLE_BUFFER_LENGTH(&zos->out)); memcpy(cl->updateBuf+cl->ublen, (char *)&hdr, sz_rfbZRLEHeader); cl->ublen += sz_rfbZRLEHeader; /* copy into updateBuf and send from there. Maybe should send directly? */ for (i = 0; i < ZRLE_BUFFER_LENGTH(&zos->out);) { int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen; if (i + bytesToCopy > ZRLE_BUFFER_LENGTH(&zos->out)) { bytesToCopy = ZRLE_BUFFER_LENGTH(&zos->out) - i; } memcpy(cl->updateBuf+cl->ublen, (uint8_t*)zos->out.start + i, bytesToCopy); cl->ublen += bytesToCopy; i += bytesToCopy; if (cl->ublen == UPDATE_BUF_SIZE) { if (!rfbSendUpdateBuf(cl)) return FALSE; } } return TRUE; }
rfbBool rfbSendCursorShape(rfbClientPtr cl) { rfbCursorPtr pCursor; rfbFramebufferUpdateRectHeader rect; rfbXCursorColors colors; int saved_ublen; int bitmapRowBytes, maskBytes, dataBytes; int i, j; uint8_t *bitmapData; uint8_t bitmapByte; /* TODO: scale the cursor data to the correct size */ pCursor = cl->screen->getCursorPtr(cl); /*if(!pCursor) return TRUE;*/ if (cl->useRichCursorEncoding) { if(pCursor && !pCursor->richSource) rfbMakeRichCursorFromXCursor(cl->screen,pCursor); rect.encoding = Swap32IfLE(rfbEncodingRichCursor); } else { if(pCursor && !pCursor->source) rfbMakeXCursorFromRichCursor(cl->screen,pCursor); rect.encoding = Swap32IfLE(rfbEncodingXCursor); } /* If there is no cursor, send update with empty cursor data. */ if ( pCursor && pCursor->width == 1 && pCursor->height == 1 && pCursor->mask[0] == 0 ) { pCursor = NULL; } if (pCursor == NULL) { if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE ) { if (!rfbSendUpdateBuf(cl)) return FALSE; } rect.r.x = rect.r.y = 0; rect.r.w = rect.r.h = 0; memcpy(&cl->updateBuf[cl->ublen], (char *)&rect, sz_rfbFramebufferUpdateRectHeader); cl->ublen += sz_rfbFramebufferUpdateRectHeader; if (!rfbSendUpdateBuf(cl)) return FALSE; return TRUE; } /* Calculate data sizes. */ bitmapRowBytes = (pCursor->width + 7) / 8; maskBytes = bitmapRowBytes * pCursor->height; dataBytes = (cl->useRichCursorEncoding) ? (pCursor->width * pCursor->height * (cl->format.bitsPerPixel / 8)) : maskBytes; /* Send buffer contents if needed. */ if ( cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) { if (!rfbSendUpdateBuf(cl)) return FALSE; } if ( cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) { return FALSE; /* FIXME. */ } saved_ublen = cl->ublen; /* Prepare rectangle header. */ rect.r.x = Swap16IfLE(pCursor->xhot); rect.r.y = Swap16IfLE(pCursor->yhot); rect.r.w = Swap16IfLE(pCursor->width); rect.r.h = Swap16IfLE(pCursor->height); memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader); cl->ublen += sz_rfbFramebufferUpdateRectHeader; /* Prepare actual cursor data (depends on encoding used). */ if (!cl->useRichCursorEncoding) { /* XCursor encoding. */ colors.foreRed = (char)(pCursor->foreRed >> 8); colors.foreGreen = (char)(pCursor->foreGreen >> 8); colors.foreBlue = (char)(pCursor->foreBlue >> 8); colors.backRed = (char)(pCursor->backRed >> 8); colors.backGreen = (char)(pCursor->backGreen >> 8); colors.backBlue = (char)(pCursor->backBlue >> 8); memcpy(&cl->updateBuf[cl->ublen], (char *)&colors, sz_rfbXCursorColors); cl->ublen += sz_rfbXCursorColors; bitmapData = (uint8_t *)pCursor->source; for (i = 0; i < pCursor->height; i++) { for (j = 0; j < bitmapRowBytes; j++) { bitmapByte = bitmapData[i * bitmapRowBytes + j]; cl->updateBuf[cl->ublen++] = (char)bitmapByte; } } }
rfbBool rfbSendRectEncodingRRE(rfbClientPtr cl, int x, int y, int w, int h) { rfbFramebufferUpdateRectHeader rect; rfbRREHeader hdr; int nSubrects; int i; char *fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y) + (x * (cl->scaledScreen->bitsPerPixel / 8))); int maxRawSize = (cl->scaledScreen->width * cl->scaledScreen->height * (cl->format.bitsPerPixel / 8)); if (cl->beforeEncBufSize < maxRawSize) { cl->beforeEncBufSize = maxRawSize; if (cl->beforeEncBuf == NULL) cl->beforeEncBuf = (char *)malloc(cl->beforeEncBufSize); else cl->beforeEncBuf = (char *)realloc(cl->beforeEncBuf, cl->beforeEncBufSize); } if (cl->afterEncBufSize < maxRawSize) { cl->afterEncBufSize = maxRawSize; if (cl->afterEncBuf == NULL) cl->afterEncBuf = (char *)malloc(cl->afterEncBufSize); else cl->afterEncBuf = (char *)realloc(cl->afterEncBuf, cl->afterEncBufSize); } (*cl->translateFn)(cl->translateLookupTable, &(cl->screen->serverFormat), &cl->format, fbptr, cl->beforeEncBuf, cl->scaledScreen->paddedWidthInBytes, w, h); switch (cl->format.bitsPerPixel) { case 8: nSubrects = subrectEncode8(cl, (uint8_t *)cl->beforeEncBuf, w, h); break; case 16: nSubrects = subrectEncode16(cl, (uint16_t *)cl->beforeEncBuf, w, h); break; case 32: nSubrects = subrectEncode32(cl, (uint32_t *)cl->beforeEncBuf, w, h); break; default: rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel); return FALSE; } if (nSubrects < 0) { /* RRE encoding was too large, use raw */ return rfbSendRectEncodingRaw(cl, x, y, w, h); } rfbStatRecordEncodingSent(cl, rfbEncodingRRE, sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader + cl->afterEncBufLen, sz_rfbFramebufferUpdateRectHeader + w * h * (cl->format.bitsPerPixel / 8)); if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader > UPDATE_BUF_SIZE) { if (!rfbSendUpdateBuf(cl)) return FALSE; } rect.r.x = Swap16IfLE(x); rect.r.y = Swap16IfLE(y); rect.r.w = Swap16IfLE(w); rect.r.h = Swap16IfLE(h); rect.encoding = Swap32IfLE(rfbEncodingRRE); memcpy(&cl->updateBuf[cl->ublen], (char *)&rect, sz_rfbFramebufferUpdateRectHeader); cl->ublen += sz_rfbFramebufferUpdateRectHeader; hdr.nSubrects = Swap32IfLE(nSubrects); memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbRREHeader); cl->ublen += sz_rfbRREHeader; for (i = 0; i < cl->afterEncBufLen;) { int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen; if (i + bytesToCopy > cl->afterEncBufLen) { bytesToCopy = cl->afterEncBufLen - i; } memcpy(&cl->updateBuf[cl->ublen], &cl->afterEncBuf[i], bytesToCopy); cl->ublen += bytesToCopy; i += bytesToCopy; if (cl->ublen == UPDATE_BUF_SIZE) { if (!rfbSendUpdateBuf(cl)) return FALSE; } } return TRUE; }
Bool rfbSendRichCursorUpdate(rfbClientPtr cl) { rfbFramebufferUpdateRectHeader rect; rfbPixelFormat cursorFormat; unsigned char *cursorData; int bufferMaskOffset; int cursorSize; // Size of cursor data from size int cursorRowBytes; int cursorDataSize; // Size to be sent to client int cursorMaskSize; // Mask Size to be sent to client int cursorDepth; int cursorBitsPerComponent; BOOL cursorIsDifferentFormat = FALSE; CGError err; CGSConnectionRef connection = getConnection(); int components; // Cursor Components CGPoint hotspot; CGRect cursorRect; //rfbLog("Sending Cursor To Client"); //GetCursorInfo(); if (!connection) { if (!maxFailsRemaining) cl->useRichCursorEncoding = FALSE; return FALSE; } if (CGSGetGlobalCursorDataSize(connection, &cursorDataSize) != kCGErrorSuccess) { rfbLog("Error obtaining cursor data - cursor not sent\n"); return FALSE; } cursorData = (unsigned char*)malloc(sizeof(unsigned char) * cursorDataSize); err = CGSGetGlobalCursorData(connection, cursorData, &cursorDataSize, &cursorRowBytes, &cursorRect, &hotspot, &cursorDepth, &components, &cursorBitsPerComponent); //CGSReleaseConnection(connection); if (err != kCGErrorSuccess) { rfbLog("Error obtaining cursor data - cursor not sent\n"); return FALSE; } if (cursorRect.size.height > 128 || cursorRect.size.width > 128) { // Wow That's one big cursor! We don't handle cursors this big // (they are probably cursors with lots of states and that doesn't work so good for VNC. // For now just ignore them cl->currentCursorSeed = CGSCurrentCursorSeed(); return FALSE; } // For This We Don't send location just the cursor shape (and Hot Spot) cursorFormat.depth = (cursorDepth == 32 ? 24 : cursorDepth); cursorFormat.bitsPerPixel = cursorDepth; cursorFormat.bigEndian = TRUE; cursorFormat.trueColour = TRUE; cursorFormat.redMax = cursorFormat.greenMax = cursorFormat.blueMax = (unsigned short) ((1<<cursorBitsPerComponent) - 1); cursorFormat.bigEndian = !littleEndian; cursorFormat.redShift = (unsigned char) (cursorBitsPerComponent * 2); cursorFormat.greenShift = (unsigned char) (cursorBitsPerComponent * 1); cursorFormat.blueShift = (unsigned char) (cursorBitsPerComponent * 0); //GetCursorInfo(); //PrintPixelFormat(&cursorFormat); cursorIsDifferentFormat = !(PF_EQ(cursorFormat,rfbServerFormat)); cursorSize = (cursorRect.size.width * cursorRect.size.height * (cl->format.bitsPerPixel / 8)); cursorMaskSize = floor((cursorRect.size.width+7)/8) * cursorRect.size.height; // Make Sure we have space on the buffer (otherwise push the data out now) if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + cursorSize + cursorMaskSize > UPDATE_BUF_SIZE) { if (!rfbSendUpdateBuf(cl)) return FALSE; } // Send The Header rect.r.x = Swap16IfLE((short) hotspot.x); rect.r.y = Swap16IfLE((short) hotspot.y); rect.r.w = Swap16IfLE((short) cursorRect.size.width); rect.r.h = Swap16IfLE((short) cursorRect.size.height); rect.encoding = Swap32IfLE(rfbEncodingRichCursor); memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader); cl->ublen += sz_rfbFramebufferUpdateRectHeader; // Apple Cursors can use a full Alpha channel. // Since we can only send a bit mask - to get closer we will compose the full color with a white // This requires us to jump ahead to write in the update buffer bufferMaskOffset = cl->ublen + cursorSize; // For starters we'll set mask to OFF (transparent) everywhere) memset(&cl->updateBuf[bufferMaskOffset], 0, cursorMaskSize); // This algorithm assumes the Alpha channel is the first component { unsigned char *cursorRowData = cursorData; unsigned char *cursorColumnData = cursorData; unsigned int cursorBytesPerPixel = (cursorDepth/8); unsigned char mask = 0; unsigned int alphaShift = (8 - cursorBitsPerComponent); unsigned char fullOn = (0xFF) >> alphaShift; unsigned char alphaThreshold = (0x60) >> alphaShift; // Only include the pixel if it's coverage is greater than this int dataX, dataY, componentIndex; for (dataY = 0; dataY < cursorRect.size.height; dataY++) { cursorColumnData = cursorRowData; for (dataX = 0; dataX < cursorRect.size.width; dataX++) { if (littleEndian) mask = (unsigned char)(*(cursorColumnData+(cursorBytesPerPixel-1))) >> alphaShift; else mask = (unsigned char)(*cursorColumnData) >> alphaShift; if (mask > alphaThreshold) { // Write the Bit For The Mask to be ON (opaque) cl->updateBuf[bufferMaskOffset+(dataX/8)] |= (0x0080 >> (dataX % 8)); // Composite Alpha into the cursors other channels - only for 32 bit if (cursorDepth == 32 && mask != fullOn) { for (componentIndex = 0; componentIndex < components; componentIndex++) { *cursorColumnData = (unsigned char) (fullOn - mask + ((*cursorColumnData * mask)/fullOn)) & 0xFF; cursorColumnData++; } } else cursorColumnData += cursorBytesPerPixel; } else cursorColumnData += cursorBytesPerPixel; }
rfbBool rfbSendRectEncodingZRLE(rfbClientPtr cl, int x, int y, int w, int h) { zrleOutStream* zos; rfbFramebufferUpdateRectHeader rect; rfbZRLEHeader hdr; int i; if (!cl->zrleData) cl->zrleData = zrleOutStreamNew(); zos = cl->zrleData; zos->in.ptr = zos->in.start; zos->out.ptr = zos->out.start; switch (cl->format.bitsPerPixel) { case 8: zrleEncode8( x, y, w, h, zos, zrleBeforeBuf, cl); break; case 16: zrleEncode16(x, y, w, h, zos, zrleBeforeBuf, cl); break; case 32: { rfbBool fitsInLS3Bytes = ((cl->format.redMax << cl->format.redShift) < (1<<24) && (cl->format.greenMax << cl->format.greenShift) < (1<<24) && (cl->format.blueMax << cl->format.blueShift) < (1<<24)); rfbBool fitsInMS3Bytes = (cl->format.redShift > 7 && cl->format.greenShift > 7 && cl->format.blueShift > 7); if ((fitsInLS3Bytes && !cl->format.bigEndian) || (fitsInMS3Bytes && cl->format.bigEndian)) { zrleEncode24A(x, y, w, h, zos, zrleBeforeBuf, cl); } else if ((fitsInLS3Bytes && cl->format.bigEndian) || (fitsInMS3Bytes && !cl->format.bigEndian)) { zrleEncode24B(x, y, w, h, zos, zrleBeforeBuf, cl); } else { zrleEncode32(x, y, w, h, zos, zrleBeforeBuf, cl); } } break; } cl->rfbRectanglesSent[rfbEncodingZRLE]++; cl->rfbBytesSent[rfbEncodingZRLE] += (sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader + ZRLE_BUFFER_LENGTH(&zos->out)); if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader > UPDATE_BUF_SIZE) { if (!rfbSendUpdateBuf(cl)) return FALSE; } rect.r.x = Swap16IfLE(x); rect.r.y = Swap16IfLE(y); rect.r.w = Swap16IfLE(w); rect.r.h = Swap16IfLE(h); rect.encoding = Swap32IfLE(rfbEncodingZRLE); memcpy(cl->updateBuf+cl->ublen, (char *)&rect, sz_rfbFramebufferUpdateRectHeader); cl->ublen += sz_rfbFramebufferUpdateRectHeader; hdr.length = Swap32IfLE(ZRLE_BUFFER_LENGTH(&zos->out)); memcpy(cl->updateBuf+cl->ublen, (char *)&hdr, sz_rfbZRLEHeader); cl->ublen += sz_rfbZRLEHeader; /* copy into updateBuf and send from there. Maybe should send directly? */ for (i = 0; i < ZRLE_BUFFER_LENGTH(&zos->out);) { int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen; if (i + bytesToCopy > ZRLE_BUFFER_LENGTH(&zos->out)) { bytesToCopy = ZRLE_BUFFER_LENGTH(&zos->out) - i; } memcpy(cl->updateBuf+cl->ublen, (uint8_t*)zos->out.start + i, bytesToCopy); cl->ublen += bytesToCopy; i += bytesToCopy; if (cl->ublen == UPDATE_BUF_SIZE) { if (!rfbSendUpdateBuf(cl)) return FALSE; } } return TRUE; }
static rfbBool rfbSendOneRectEncodingUltra(rfbClientPtr cl, int x, int y, int w, int h) { rfbFramebufferUpdateRectHeader rect; rfbZlibHeader hdr; int deflateResult; int i; char *fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y) + (x * (cl->scaledScreen->bitsPerPixel / 8))); int maxRawSize; lzo_uint maxCompSize; maxRawSize = (w * h * (cl->format.bitsPerPixel / 8)); if (cl->beforeEncBufSize < maxRawSize) { cl->beforeEncBufSize = maxRawSize; if (cl->beforeEncBuf == NULL) cl->beforeEncBuf = (char *)MemAlloc(cl->beforeEncBufSize); else cl->beforeEncBuf = (char *)MemRealloc(cl->beforeEncBuf, cl->beforeEncBufSize); } /* * lzo requires output buffer to be slightly larger than the input * buffer, in the worst case. */ maxCompSize = (maxRawSize + maxRawSize / 16 + 64 + 3); if (cl->afterEncBufSize < (int)maxCompSize) { cl->afterEncBufSize = maxCompSize; if (cl->afterEncBuf == NULL) cl->afterEncBuf = (char *)MemAlloc(cl->afterEncBufSize); else cl->afterEncBuf = (char *)MemRealloc(cl->afterEncBuf, cl->afterEncBufSize); } /* * Convert pixel data to client format. */ (*cl->translateFn)(cl->translateLookupTable, &cl->screen->serverFormat, &cl->format, fbptr, cl->beforeEncBuf, cl->scaledScreen->paddedWidthInBytes, w, h); if ( cl->compStreamInitedLZO == FALSE ) { cl->compStreamInitedLZO = TRUE; /* Work-memory needed for compression. Allocate memory in units * of `lzo_align_t' (instead of `char') to make sure it is properly aligned. */ cl->lzoWrkMem = MemAlloc(sizeof(lzo_align_t) * (((LZO1X_1_MEM_COMPRESS) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t))); } /* Perform the compression here. */ deflateResult = lzo1x_1_compress((unsigned char *)cl->beforeEncBuf, (lzo_uint)(w * h * (cl->format.bitsPerPixel / 8)), (unsigned char *)cl->afterEncBuf, &maxCompSize, cl->lzoWrkMem); /* maxCompSize now contains the compressed size */ /* Find the total size of the resulting compressed data. */ cl->afterEncBufLen = maxCompSize; if ( deflateResult != LZO_E_OK ) { ///rfbErr("lzo deflation error: %d\n", deflateResult); return FALSE; } /* Update statics */ ///rfbStatRecordEncodingSent(cl, rfbEncodingUltra, sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader + cl->afterEncBufLen, maxRawSize); if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader > UPDATE_BUF_SIZE) { if (!rfbSendUpdateBuf(cl)) return FALSE; } rect.r.x = Swap16IfLE(x); rect.r.y = Swap16IfLE(y); rect.r.w = Swap16IfLE(w); rect.r.h = Swap16IfLE(h); rect.encoding = Swap32IfLE(rfbEncodingUltra); memcpy(&cl->updateBuf[cl->ublen], (char *)&rect, sz_rfbFramebufferUpdateRectHeader); cl->ublen += sz_rfbFramebufferUpdateRectHeader; hdr.nBytes = Swap32IfLE(cl->afterEncBufLen); memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbZlibHeader); cl->ublen += sz_rfbZlibHeader; /* We might want to try sending the data directly... */ for (i = 0; i < cl->afterEncBufLen;) { int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen; if (i + bytesToCopy > cl->afterEncBufLen) { bytesToCopy = cl->afterEncBufLen - i; } memcpy(&cl->updateBuf[cl->ublen], &cl->afterEncBuf[i], bytesToCopy); cl->ublen += bytesToCopy; i += bytesToCopy; if (cl->ublen == UPDATE_BUF_SIZE) { if (!rfbSendUpdateBuf(cl)) return FALSE; } } return TRUE; }
rfbBool rfbSendRectEncodingUltra(rfbClientPtr cl, int x, int y, int w, int h) { int maxLines; int linesRemaining; rfbRectangle partialRect; partialRect.x = x; partialRect.y = y; partialRect.w = w; partialRect.h = h; /* Determine maximum pixel/scan lines allowed per rectangle. */ maxLines = ( ULTRA_MAX_SIZE(w) / w ); /* Initialize number of scan lines left to do. */ linesRemaining = h; /* Loop until all work is done. */ while ( linesRemaining > 0 ) { int linesToComp; if ( maxLines < linesRemaining ) linesToComp = maxLines; else linesToComp = linesRemaining; partialRect.h = linesToComp; /* Encode (compress) and send the next rectangle. */ if ( ! rfbSendOneRectEncodingUltra( cl, partialRect.x, partialRect.y, partialRect.w, partialRect.h )) { return FALSE; } /* Technically, flushing the buffer here is not extrememly * efficient. However, this improves the overall throughput * of the system over very slow networks. By flushing * the buffer with every maximum size lzo rectangle, we * improve the pipelining usage of the server CPU, network, * and viewer CPU components. Insuring that these components * are working in parallel actually improves the performance * seen by the user. * Since, lzo is most useful for slow networks, this flush * is appropriate for the desired behavior of the lzo encoding. */ if (( cl->ublen > 0 ) && ( linesToComp == maxLines )) { if (!rfbSendUpdateBuf(cl)) { return FALSE; } } /* Update remaining and incremental rectangle location. */ linesRemaining -= linesToComp; partialRect.y += linesToComp; } return TRUE; }