#if __ORCAC__ #pragma lint -1 #pragma noroot segment "VNCview GS"; #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "vncsession.h" #include "vncview.h" #include "vncdisplay.h" #include "colortables.h" #include "readtcp.h" #include "raw.h" /* Data on state of raw rectangle drawing routines */ static unsigned int lineBytes; /* Number of bytes in a line of GS pixels */ static unsigned long pixels; static unsigned int drawingLine; /* Line to be drawn while displaying */ static BOOLEAN extraByteAdvance; static unsigned linesAvailable; /* Bytes to skip before or after doing raw drawing */ static unsigned long preSkip, postSkip; /* Buffer to hold all SHR pixel data from one update (defined in tables.asm). * Must be big enough: at least (WIN_WIDTH_640/4 + 1) * WIN_HEIGHT. */ #define DESTBUF_SIZE 0x8001 extern unsigned char destBuf[]; static unsigned char *destPtr; unsigned char * rawDecode640(unsigned startOffset, unsigned endOffset, unsigned char *lineDataPtr); unsigned char * rawDecode320(unsigned startOffset, unsigned endOffset, unsigned char *lineDataPtr); /* Ends drawing of a raw rectangle when it is complete or aborted * because the rectangle is not visible. */ static void StopRawDrawing (void) { NextRect(); /* Prepare for next rect */ } #pragma optimize 95 /* To work around an ORCA/C optimizer bug */ /* Draw one or more lines from a raw rectangle */ void RawDraw (void) { static unsigned char *lineDataPtr; unsigned int i; /* Loop indices */ unsigned char *initialLineDataPtr; unsigned char *finalDestPtr; static EventRecord unusedEventRec; /* For use with GetContentOrigin() */ Origin contentOrigin; SetPort(vncWindow); /* Drawing in VNC window */ #if 0 /* Check if what we're drawing is visible, and skip any invisible part * by skipping some lines or completely aborting drawing the rectangle. */ if (checkBounds) { Rect drawingRect; contentOrigin.l = GetContentOrigin(vncWindow); drawingRect.h1 = rectX - contentOrigin.pt.h; drawingRect.h2 = rectX - contentOrigin.pt.h + rectWidth; drawingRect.v1 = rectY - contentOrigin.pt.v + drawingLine; drawingRect.v2 = rectY - contentOrigin.pt.v + rectHeight; if (!RectInRgn(&drawingRect, GetVisHandle())) { StopRawDrawing(); return; } else if (rectY + drawingLine < contentOrigin.pt.v) { unsigned linesToSkip = contentOrigin.pt.v - rectY - drawingLine; preSkip = linesToSkip * rectWidth; destPtr += (unsigned long)lineBytes * linesToSkip; drawingLine = contentOrigin.pt.v - rectY; if (drawingLine >= rectHeight) { /* Sanity check */ StopRawDrawing(); return; } } else if (rectY + rectHeight - 1 > contentOrigin.pt.v + winHeight) rectHeight = contentOrigin.pt.v + winHeight - rectY + 1; checkBounds = FALSE; } #endif do { /* We short-circuit back to here if there are no events pending */ unsigned inPixelsA, inPixelsB, outPixels; if (linesAvailable == 0) { linesAvailable = DoReadMultipleTCP(rectWidth, rectHeight - drawingLine); if (linesAvailable) { lineDataPtr = readBufferPtr; } else { return; } } finalDestPtr = destPtr + lineBytes - 1; if (hRez == 640) { initialLineDataPtr = lineDataPtr; lineDataPtr = rawDecode640(destPtr-destBuf, finalDestPtr-destBuf, lineDataPtr); destPtr = finalDestPtr; *destPtr = pixTransTbl[*(lineDataPtr++)] & 0xC0; for (i = lineDataPtr - initialLineDataPtr; i < rectWidth; i++) switch (i & 0x03) { case 0x01: /* pixels 1, 5, 9, ... */ *destPtr += pixTransTbl[*(lineDataPtr++)] & 0x30; break; case 0x02: /* pixels 2, 6, 10, ... */ *destPtr += pixTransTbl[*(lineDataPtr++)] & 0x0C; break; case 0x03: /* pixels 3, 7, 11, ... */ *destPtr += pixTransTbl[*(lineDataPtr++)] & 0x03; } destPtr++; } else { /* 320 mode */ lineDataPtr = rawDecode320(destPtr-destBuf, finalDestPtr-destBuf, lineDataPtr); destPtr = finalDestPtr; /* Final byte to produce */ *destPtr = pixTransTbl[*(lineDataPtr++)] & 0xF0; if (extraByteAdvance) destPtr++; /* Not ending on byte boundary - update index */ else *(destPtr++) += pixTransTbl[*(lineDataPtr++)] & 0x0F; } drawingLine++; if (pixels > 613 && !(drawingLine & 0x03)) { /* Draw every 4th line */ srcRect.v2 = drawingLine; contentOrigin.l = GetContentOrigin(vncWindow); PPToPort(&srcLocInfo, &srcRect, rectX - contentOrigin.pt.h, rectY + srcRect.v1 - contentOrigin.pt.v, modeCopy); srcRect.v1 = drawingLine; } /* Check whether we're done with this rectangle */ if (drawingLine >= rectHeight) { /* Draw final rect, if necessary */ if (drawingLine > srcRect.v1) { srcRect.v2 = drawingLine; contentOrigin.l = GetContentOrigin(vncWindow); PPToPort(&srcLocInfo, &srcRect, rectX - contentOrigin.pt.h, rectY + srcRect.v1 - contentOrigin.pt.v, modeCopy); } StopRawDrawing(); return; } linesAvailable--; /* Check if there are actually any events that need to be processed. * If not, save time by not going through the whole event loop, but * instead processing the minimum necessary periodic tasks and then * going straight to the next line of data. */ if (!(drawingLine & 15)) { if (EventAvail(0xFFFF, &unusedEventRec)) return; SystemTask(); /* Let periodic Desk Accesories do their things */ } TCPIPPoll(); /* Let Marinetti keep processing data */ } while (1); } #pragma optimize -1 /* Process rectangle data in raw encoding and write it to screen. */ void DoRawRect (void) { pixels = (unsigned long) rectWidth * rectHeight; if (hRez == 640) { if (rectWidth & 0x03) { /* Width not an exact multiple of 4 */ lineBytes = rectWidth/4 + 1; } else { /* Width is a multiple of 4 */ lineBytes = rectWidth/4; } } else { /* 320 mode */ if (rectWidth & 0x01) { /* Width not an exact multiple of 2 */ lineBytes = rectWidth/2 + 1; extraByteAdvance = TRUE; } else { /* Width is a multiple of 2 */ lineBytes = rectWidth/2; extraByteAdvance = FALSE; } } /* If we get an oversized update, ignore it and ask for another one. * Shouldn't normally happen, except possibly if there are outstanding * update requests for multiple screen regions due to scrolling. */ if (lineBytes * rectHeight >= DESTBUF_SIZE) { Origin contentOrigin; contentOrigin.l = GetContentOrigin(vncWindow); SendFBUpdateRequest(FALSE, contentOrigin.pt.h, contentOrigin.pt.v, winWidth, winHeight); skipBytes = pixels; StopRawDrawing(); return; } destPtr = destBuf; srcLocInfo.ptrToPixImage = destPtr; srcLocInfo.width = lineBytes; srcLocInfo.boundsRect.v2 = rectHeight; /* Since the lines are rounded up to integral numbers of bytes, this * padding must be accounted for here. */ if (hRez == 640) { switch (rectWidth & 0x03) { case 0x00: srcLocInfo.boundsRect.h2 = rectWidth; break; case 0x01: srcLocInfo.boundsRect.h2 = rectWidth+3; break; case 0x02: srcLocInfo.boundsRect.h2 = rectWidth+2; break; case 0x03: srcLocInfo.boundsRect.h2 = rectWidth+1; } } else { switch (rectWidth & 0x01) { case 0x00: srcLocInfo.boundsRect.h2 = rectWidth; break; case 0x01: srcLocInfo.boundsRect.h2 = rectWidth+1; } } /* Don't include padding in the area we will actually copy over */ srcRect.h2 = rectWidth; srcRect.v1 = 0; displayInProgress = TRUE; drawingLine = 0; /* Drawing first line of rect */ linesAvailable = 0; /* No line data read yet */ checkBounds = TRUE; /* Flag to check bounds when drawing 1st line */ }