2 * draw.c - drawing routines for the RFB X server. This is a set of
3 * wrappers around the standard MI/MFB/CFB drawing routines which work out
4 * to a fair approximation the region of the screen being modified by the
5 * drawing. If the RFB client is ready then the modified region of the screen
6 * is sent to the client, otherwise the modified region will simply grow with
7 * each drawing request until the client is ready.
11 * Copyright (C) 2002-2003 RealVNC Ltd.
12 * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
14 * This is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This software is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this software; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
32 Copyright (c) 1989 X Consortium
34 Permission is hereby granted, free of charge, to any person obtaining a copy
35 of this software and associated documentation files (the "Software"), to deal
36 in the Software without restriction, including without limitation the rights
37 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
38 copies of the Software, and to permit persons to whom the Software is
39 furnished to do so, subject to the following conditions:
41 The above copyright notice and this permission notice shall be included in
42 all copies or substantial portions of the Software.
44 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
45 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
46 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
47 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
48 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
49 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
51 Except as contained in this notice, the name of the X Consortium shall not be
52 used in advertising or otherwise to promote the sale, use or other dealings
53 in this Software without prior written authorization from the X Consortium.
57 #include "scrnintstr.h"
59 #include "windowstr.h"
60 #include "regionstr.h"
61 #include "dixfontstr.h"
65 extern WindowPtr *WindowTable; /* Why isn't this in a header file? */
67 int rfbDeferUpdateTime = 40; /* ms */
69 /* MAX_RECTS_PER_OP is the maximum number of rectangles we generate from
70 operations like Polylines and PolySegment. If the operation is more complex
71 than this, we simply use the bounding box. Ideally it would be a
72 command-line option, but that would involve an extra malloc each time, so we
74 #define MAX_RECTS_PER_OP 5
77 /****************************************************************************/
81 /****************************************************************************/
83 /* SLIGHTLY DIRTY HACK - use Composite Clip region calculated by mfb */
85 #define WINDOW_CLIP_REGION(_w, _gc) \
86 (((mfbPrivGCPtr)((_gc)->devPrivates[mfbGCPrivateIndex].ptr))->pCompositeClip)
88 #define TRC(x) if (rfbTrace) rfbLog x
90 /* ADD_TO_MODIFIED_REGION adds the given region to the modified region for each
93 #define ADD_TO_MODIFIED_REGION(pScreen,reg) \
96 for (cl = rfbClientHead; cl; cl = cl->next) { \
97 if (REGION_NUM_RECTS(&cl->modifiedRegion) > rfbMaxRects) { \
98 BoxRec boundingBox = *(REGION_EXTENTS((pScreen), \
99 &cl->modifiedRegion)); \
100 REGION_RESET((pScreen), &cl->modifiedRegion, &boundingBox); \
103 REGION_UNION((pScreen),&cl->modifiedRegion,&cl->modifiedRegion,reg);\
107 /* SCHEDULE_FB_UPDATE is used at the end of each drawing routine to schedule an
108 update to be sent to each client if there is one pending and the client is
111 #define SCHEDULE_FB_UPDATE(pScreen,prfb) \
112 if (!prfb->dontSendFramebufferUpdate) { \
113 rfbClientPtr cl, nextCl; \
114 for (cl = rfbClientHead; cl; cl = nextCl) { \
116 if (!cl->deferredUpdateScheduled && FB_UPDATE_PENDING(cl) && \
117 REGION_NOTEMPTY(pScreen,&cl->requestedRegion)) \
119 rfbScheduleDeferredUpdate(cl); \
124 /* function prototypes */
126 static void rfbCopyRegion(ScreenPtr pScreen, rfbClientPtr cl,
127 RegionPtr src, RegionPtr dst, int dx, int dy);
131 static void rfbValidateGC(GCPtr, unsigned long /*changes*/, DrawablePtr);
132 static void rfbChangeGC(GCPtr, unsigned long /*mask*/);
133 static void rfbCopyGC(GCPtr /*src*/, unsigned long /*mask*/, GCPtr /*dst*/);
134 static void rfbDestroyGC(GCPtr);
135 static void rfbChangeClip(GCPtr, int /*type*/, pointer /*pValue*/,
137 static void rfbDestroyClip(GCPtr);
138 static void rfbCopyClip(GCPtr /*dst*/, GCPtr /*src*/);
142 static void rfbFillSpans();
143 static void rfbSetSpans();
144 static void rfbPutImage();
145 static RegionPtr rfbCopyArea();
146 static RegionPtr rfbCopyPlane();
147 static void rfbPolyPoint();
148 static void rfbPolylines();
149 static void rfbPolySegment();
150 static void rfbPolyRectangle();
151 static void rfbPolyArc();
152 static void rfbFillPolygon();
153 static void rfbPolyFillRect();
154 static void rfbPolyFillArc();
155 static int rfbPolyText8();
156 static int rfbPolyText16();
157 static void rfbImageText8();
158 static void rfbImageText16();
159 static void rfbImageGlyphBlt();
160 static void rfbPolyGlyphBlt();
161 static void rfbPushPixels();
164 static GCFuncs rfbGCFuncs = {
175 static GCOps rfbGCOps = {
176 rfbFillSpans, rfbSetSpans, rfbPutImage,
177 rfbCopyArea, rfbCopyPlane, rfbPolyPoint,
178 rfbPolylines, rfbPolySegment, rfbPolyRectangle,
179 rfbPolyArc, rfbFillPolygon, rfbPolyFillRect,
180 rfbPolyFillArc, rfbPolyText8, rfbPolyText16,
181 rfbImageText8, rfbImageText16, rfbImageGlyphBlt,
182 rfbPolyGlyphBlt, rfbPushPixels
187 /****************************************************************************/
189 * Screen functions wrapper stuff
191 /****************************************************************************/
193 #define SCREEN_PROLOGUE(scrn, field) \
194 ScreenPtr pScreen = scrn; \
195 rfbScreenInfoPtr prfb = &rfbScreen; \
196 pScreen->field = prfb->field;
198 #define SCREEN_EPILOGUE(field, wrapper) \
199 pScreen->field = wrapper;
203 * CloseScreen wrapper -- unwrap everything, free the private data
204 * and call the wrapped CloseScreen function.
208 rfbCloseScreen (i, pScreen)
212 rfbScreenInfoPtr prfb = &rfbScreen;
214 pScreen->CloseScreen = prfb->CloseScreen;
215 pScreen->CreateGC = prfb->CreateGC;
216 pScreen->PaintWindowBackground = prfb->PaintWindowBackground;
217 pScreen->PaintWindowBorder = prfb->PaintWindowBorder;
218 pScreen->CopyWindow = prfb->CopyWindow;
219 pScreen->ClearToBackground = prfb->ClearToBackground;
220 pScreen->RestoreAreas = prfb->RestoreAreas;
222 TRC(("Unwrapped screen functions\n"));
224 return (*pScreen->CloseScreen) (i, pScreen);
228 * CreateGC - wrap the GC funcs (the GC ops will be wrapped when the GC
229 * func "ValidateGC" is called).
239 SCREEN_PROLOGUE(pGC->pScreen,CreateGC);
241 pGCPriv = (rfbGCPtr)pGC->devPrivates[rfbGCIndex].ptr;
243 ret = (*pScreen->CreateGC) (pGC);
245 TRC(("rfbCreateGC called\n"));
247 pGCPriv->wrapOps = NULL;
248 pGCPriv->wrapFuncs = pGC->funcs;
249 pGC->funcs = &rfbGCFuncs;
251 SCREEN_EPILOGUE(CreateGC,rfbCreateGC);
257 * PaintWindowBackground - the region being modified is just the given region.
261 rfbPaintWindowBackground (pWin, pRegion, what)
266 SCREEN_PROLOGUE(pWin->drawable.pScreen,PaintWindowBackground);
268 TRC(("rfbPaintWindowBackground called\n"));
270 ADD_TO_MODIFIED_REGION(pScreen,pRegion);
272 (*pScreen->PaintWindowBackground) (pWin, pRegion, what);
274 SCHEDULE_FB_UPDATE(pScreen, prfb);
276 SCREEN_EPILOGUE(PaintWindowBackground,rfbPaintWindowBackground);
280 * PaintWindowBorder - the region being modified is just the given region.
284 rfbPaintWindowBorder (pWin, pRegion, what)
289 SCREEN_PROLOGUE(pWin->drawable.pScreen,PaintWindowBorder);
291 TRC(("rfbPaintWindowBorder called\n"));
293 ADD_TO_MODIFIED_REGION(pScreen,pRegion);
295 (*pScreen->PaintWindowBorder) (pWin, pRegion, what);
297 SCHEDULE_FB_UPDATE(pScreen, prfb);
299 SCREEN_EPILOGUE(PaintWindowBorder,rfbPaintWindowBorder);
303 * CopyWindow - the region being modified is the translation of the old
304 * region, clipped to the border clip region of the window. Note that any
305 * parts of the window which have become newly-visible will not be affected by
306 * this call - a separate PaintWindowBackground/Border will be called to do
307 * that. If the client will accept CopyRect messages then use rfbCopyRegion to
308 * optimise the pending screen changes into a single "copy region" plus the
309 * ordinary modified region.
313 rfbCopyWindow (pWin, ptOldOrg, pOldRegion)
315 DDXPointRec ptOldOrg;
316 RegionPtr pOldRegion;
319 RegionRec srcRegion, dstRegion;
320 SCREEN_PROLOGUE(pWin->drawable.pScreen,CopyWindow);
322 TRC(("rfbCopyWindow called\n"));
324 REGION_INIT(pScreen,&dstRegion,NullBox,0);
325 REGION_COPY(pScreen,&dstRegion,pOldRegion);
326 REGION_TRANSLATE(pWin->drawable.pScreen, &dstRegion,
327 pWin->drawable.x - ptOldOrg.x,
328 pWin->drawable.y - ptOldOrg.y);
329 REGION_INTERSECT(pWin->drawable.pScreen, &dstRegion, &dstRegion,
332 for (cl = rfbClientHead; cl; cl = cl->next) {
333 if (cl->useCopyRect) {
334 REGION_INIT(pScreen,&srcRegion,NullBox,0);
335 REGION_COPY(pScreen,&srcRegion,pOldRegion);
337 rfbCopyRegion(pScreen, cl, &srcRegion, &dstRegion,
338 pWin->drawable.x - ptOldOrg.x,
339 pWin->drawable.y - ptOldOrg.y);
341 REGION_UNINIT(pSrc->pScreen, &srcRegion);
345 REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
350 REGION_UNINIT(pSrc->pScreen, &dstRegion);
352 (*pScreen->CopyWindow) (pWin, ptOldOrg, pOldRegion);
354 SCHEDULE_FB_UPDATE(pScreen, prfb);
356 SCREEN_EPILOGUE(CopyWindow,rfbCopyWindow);
360 * ClearToBackground - when generateExposures is false, the region being
361 * modified is the given rectangle (clipped to the "window clip region").
365 rfbClearToBackground (pWin, x, y, w, h, generateExposures)
368 Bool generateExposures;
372 SCREEN_PROLOGUE(pWin->drawable.pScreen,ClearToBackground);
374 TRC(("rfbClearToBackground called\n"));
376 if (!generateExposures) {
377 box.x1 = x + pWin->drawable.x;
378 box.y1 = y + pWin->drawable.y;
379 box.x2 = w ? (box.x1 + w) : (pWin->drawable.x + pWin->drawable.width);
380 box.y2 = h ? (box.y1 + h) : (pWin->drawable.y + pWin->drawable.height);
382 SAFE_REGION_INIT(pScreen, &tmpRegion, &box, 0);
384 REGION_INTERSECT(pScreen, &tmpRegion, &tmpRegion, &pWin->clipList);
386 ADD_TO_MODIFIED_REGION(pScreen, &tmpRegion);
388 REGION_UNINIT(pScreen, &tmpRegion);
391 (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures);
393 if (!generateExposures) {
394 SCHEDULE_FB_UPDATE(pScreen, prfb);
397 SCREEN_EPILOGUE(ClearToBackground,rfbClearToBackground);
401 * RestoreAreas - just be safe here - the region being modified is the whole
406 rfbRestoreAreas (pWin, prgnExposed)
408 RegionPtr prgnExposed;
411 SCREEN_PROLOGUE(pWin->drawable.pScreen,RestoreAreas);
413 TRC(("rfbRestoreAreas called\n"));
415 ADD_TO_MODIFIED_REGION(pScreen, prgnExposed);
417 result = (*pScreen->RestoreAreas) (pWin, prgnExposed);
419 SCHEDULE_FB_UPDATE(pScreen, prfb);
421 SCREEN_EPILOGUE(RestoreAreas,rfbRestoreAreas);
428 /****************************************************************************/
430 * GC funcs wrapper stuff
432 * We only really want to wrap the GC ops, but to do this we need to wrap
433 * ValidateGC and so all the other GC funcs must be wrapped as well.
435 /****************************************************************************/
437 #define GC_FUNC_PROLOGUE(pGC) \
438 rfbGCPtr pGCPriv = (rfbGCPtr) (pGC)->devPrivates[rfbGCIndex].ptr; \
439 (pGC)->funcs = pGCPriv->wrapFuncs; \
440 if (pGCPriv->wrapOps) \
441 (pGC)->ops = pGCPriv->wrapOps;
443 #define GC_FUNC_EPILOGUE(pGC) \
444 pGCPriv->wrapFuncs = (pGC)->funcs; \
445 (pGC)->funcs = &rfbGCFuncs; \
446 if (pGCPriv->wrapOps) { \
447 pGCPriv->wrapOps = (pGC)->ops; \
448 (pGC)->ops = &rfbGCOps; \
453 * ValidateGC - call the wrapped ValidateGC, then wrap the resulting GC ops if
454 * the drawing will be to a viewable window.
458 rfbValidateGC (pGC, changes, pDrawable)
460 unsigned long changes;
461 DrawablePtr pDrawable;
463 GC_FUNC_PROLOGUE(pGC);
465 TRC(("rfbValidateGC called\n"));
467 (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable);
469 pGCPriv->wrapOps = NULL;
470 if (pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr)pDrawable)->viewable)
472 WindowPtr pWin = (WindowPtr) pDrawable;
473 RegionPtr pRegion = &pWin->clipList;
475 if (pGC->subWindowMode == IncludeInferiors)
476 pRegion = &pWin->borderClip;
477 if (REGION_NOTEMPTY(pDrawable->pScreen, pRegion)) {
478 pGCPriv->wrapOps = pGC->ops;
479 TRC(("rfbValidateGC: wrapped GC ops\n"));
483 GC_FUNC_EPILOGUE(pGC);
487 * All other GC funcs simply unwrap the GC funcs and ops, call the wrapped
488 * function and then rewrap the funcs and ops.
492 rfbChangeGC (pGC, mask)
496 GC_FUNC_PROLOGUE(pGC);
497 (*pGC->funcs->ChangeGC) (pGC, mask);
498 GC_FUNC_EPILOGUE(pGC);
502 rfbCopyGC (pGCSrc, mask, pGCDst)
503 GCPtr pGCSrc, pGCDst;
506 GC_FUNC_PROLOGUE(pGCDst);
507 (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
508 GC_FUNC_EPILOGUE(pGCDst);
515 GC_FUNC_PROLOGUE(pGC);
516 (*pGC->funcs->DestroyGC) (pGC);
517 GC_FUNC_EPILOGUE(pGC);
521 rfbChangeClip (pGC, type, pvalue, nrects)
527 GC_FUNC_PROLOGUE(pGC);
528 (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
529 GC_FUNC_EPILOGUE(pGC);
536 GC_FUNC_PROLOGUE(pGC);
537 (* pGC->funcs->DestroyClip)(pGC);
538 GC_FUNC_EPILOGUE(pGC);
542 rfbCopyClip(pgcDst, pgcSrc)
543 GCPtr pgcDst, pgcSrc;
545 GC_FUNC_PROLOGUE(pgcDst);
546 (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
547 GC_FUNC_EPILOGUE(pgcDst);
551 /****************************************************************************/
553 * GC ops wrapper stuff
555 * Note that these routines will only have been wrapped for drawing to
556 * viewable windows so we don't need to check each time that the drawable
557 * is a viewable window.
559 /****************************************************************************/
561 #define GC_OP_PROLOGUE(pDrawable,pGC) \
562 rfbScreenInfoPtr prfb = &rfbScreen; \
563 rfbGCPtr pGCPrivate = (rfbGCPtr) (pGC)->devPrivates[rfbGCIndex].ptr; \
564 GCFuncs *oldFuncs = pGC->funcs; \
565 (pGC)->funcs = pGCPrivate->wrapFuncs; \
566 (pGC)->ops = pGCPrivate->wrapOps;
568 #define GC_OP_EPILOGUE(pGC) \
569 pGCPrivate->wrapOps = (pGC)->ops; \
570 (pGC)->funcs = oldFuncs; \
571 (pGC)->ops = &rfbGCOps;
575 * FillSpans - being very safe - the region being modified is the border clip
576 * region of the window.
580 rfbFillSpans(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted)
581 DrawablePtr pDrawable;
583 int nInit; /* number of spans to fill */
584 DDXPointPtr pptInit; /* pointer to list of start points */
585 int *pwidthInit; /* pointer to list of n widths */
588 GC_OP_PROLOGUE(pDrawable,pGC);
590 TRC(("rfbFillSpans called\n"));
592 ADD_TO_MODIFIED_REGION(pDrawable->pScreen,
593 &((WindowPtr)pDrawable)->borderClip);
595 (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit,pwidthInit,fSorted);
597 SCHEDULE_FB_UPDATE(pDrawable->pScreen, prfb);
603 * SetSpans - being very safe - the region being modified is the border clip
604 * region of the window.
608 rfbSetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted)
609 DrawablePtr pDrawable;
612 register DDXPointPtr ppt;
617 GC_OP_PROLOGUE(pDrawable,pGC);
619 TRC(("rfbSetSpans called\n"));
621 ADD_TO_MODIFIED_REGION(pDrawable->pScreen,
622 &((WindowPtr)pDrawable)->borderClip);
624 (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
626 SCHEDULE_FB_UPDATE(pDrawable->pScreen, prfb);
632 * PutImage - the region being modified is the rectangle of the
633 * PutImage (clipped to the window clip region).
637 rfbPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits)
638 DrawablePtr pDrawable;
651 GC_OP_PROLOGUE(pDrawable, pGC);
653 TRC(("rfbPutImage called\n"));
655 box.x1 = x + pDrawable->x;
656 box.y1 = y + pDrawable->y;
660 SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
662 REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
663 WINDOW_CLIP_REGION((WindowPtr)pDrawable,pGC));
665 ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
667 REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
669 (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h,
670 leftPad, format, pBits);
672 SCHEDULE_FB_UPDATE(pDrawable->pScreen, prfb);
678 * CopyArea - the region being modified is the destination rectangle (clipped
679 * to the window clip region).
680 * If the client will accept CopyRect messages then use rfbCopyRegion
681 * to optimise the pending screen changes into a single "copy region" plus
682 * the ordinary modified region.
686 rfbCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty)
699 RegionRec srcRegion, dstRegion;
701 GC_OP_PROLOGUE(pDst, pGC);
703 TRC(("rfbCopyArea called\n"));
705 box.x1 = dstx + pDst->x;
706 box.y1 = dsty + pDst->y;
710 SAFE_REGION_INIT(pDst->pScreen, &dstRegion, &box, 0);
711 REGION_INTERSECT(pDst->pScreen, &dstRegion, &dstRegion,
712 WINDOW_CLIP_REGION((WindowPtr)pDst,pGC));
714 if ((pSrc->type == DRAWABLE_WINDOW) && (pSrc->pScreen == pDst->pScreen)) {
715 box.x1 = srcx + pSrc->x;
716 box.y1 = srcy + pSrc->y;
720 for (cl = rfbClientHead; cl; cl = cl->next) {
721 if (cl->useCopyRect) {
722 SAFE_REGION_INIT(pSrc->pScreen, &srcRegion, &box, 0);
723 REGION_INTERSECT(pSrc->pScreen, &srcRegion, &srcRegion,
724 &((WindowPtr)pSrc)->clipList);
726 rfbCopyRegion(pSrc->pScreen, cl, &srcRegion, &dstRegion,
727 dstx + pDst->x - srcx - pSrc->x,
728 dsty + pDst->y - srcy - pSrc->y);
730 REGION_UNINIT(pSrc->pScreen, &srcRegion);
734 REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
741 ADD_TO_MODIFIED_REGION(pDst->pScreen, &dstRegion);
744 REGION_UNINIT(pDst->pScreen, &dstRegion);
746 rgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h,
749 SCHEDULE_FB_UPDATE(pDst->pScreen, prfb);
758 * CopyPlane - the region being modified is the destination rectangle (clipped
759 * to the window clip region).
763 rfbCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane)
778 GC_OP_PROLOGUE(pDst, pGC);
780 TRC(("rfbCopyPlane called\n"));
782 box.x1 = dstx + pDst->x;
783 box.y1 = dsty + pDst->y;
787 SAFE_REGION_INIT(pDst->pScreen, &tmpRegion, &box, 0);
789 REGION_INTERSECT(pDst->pScreen, &tmpRegion, &tmpRegion,
790 WINDOW_CLIP_REGION((WindowPtr)pDst,pGC));
792 ADD_TO_MODIFIED_REGION(pDst->pScreen, &tmpRegion);
794 REGION_UNINIT(pDst->pScreen, &tmpRegion);
796 rgn = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h,
799 SCHEDULE_FB_UPDATE(pDst->pScreen, prfb);
807 * PolyPoint - find the smallest rectangle which encloses the points drawn
812 rfbPolyPoint (pDrawable, pGC, mode, npt, pts)
813 DrawablePtr pDrawable;
815 int mode; /* Origin or Previous */
822 GC_OP_PROLOGUE(pDrawable, pGC);
824 TRC(("rfbPolyPoint called: %d points\n",npt));
827 int minX = pts[0].x, maxX = pts[0].x;
828 int minY = pts[0].y, maxY = pts[0].y;
830 if (mode == CoordModePrevious)
832 int x = pts[0].x, y = pts[0].y;
834 for (i = 1; i < npt; i++) {
837 if (x < minX) minX = x;
838 if (x > maxX) maxX = x;
839 if (y < minY) minY = y;
840 if (y > maxY) maxY = y;
845 for (i = 1; i < npt; i++) {
846 if (pts[i].x < minX) minX = pts[i].x;
847 if (pts[i].x > maxX) maxX = pts[i].x;
848 if (pts[i].y < minY) minY = pts[i].y;
849 if (pts[i].y > maxY) maxY = pts[i].y;
853 box.x1 = minX + pDrawable->x;
854 box.y1 = minY + pDrawable->y;
855 box.x2 = maxX + 1 + pDrawable->x;
856 box.y2 = maxY + 1 + pDrawable->y;
858 SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
860 REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
861 WINDOW_CLIP_REGION(((WindowPtr)pDrawable),pGC));
863 ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
865 REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
868 (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts);
871 SCHEDULE_FB_UPDATE(pDrawable->pScreen, prfb);
878 * PolyLines - take the union of bounding boxes around each line (and clip).
882 rfbPolylines (pDrawable, pGC, mode, npt, ppts)
883 DrawablePtr pDrawable;
890 xRectangle regRects[MAX_RECTS_PER_OP];
891 int i, extra, nregRects, lw;
892 int prevX, prevY, curX, curY;
893 int rectX1, rectY1, rectX2, rectY2;
894 int minX, minY, maxX, maxY;
895 GC_OP_PROLOGUE(pDrawable, pGC);
897 TRC(("rfbPolylines called: %d points\n",npt));
907 regRects[0].x = ppts[0].x - lw + pDrawable->x; /* being safe */
908 regRects[0].y = ppts[0].y - lw + pDrawable->y;
909 regRects[0].width = 2*lw;
910 regRects[0].height = 2*lw;
917 * mitered joins can project quite a way from
918 * the line end; the 11 degree miter limit limits
919 * this extension to lw / (2 * tan(11/2)), rounded up
920 * and converted to int yields 6 * lw
923 if (pGC->joinStyle == JoinMiter) {
929 prevX = ppts[0].x + pDrawable->x;
930 prevY = ppts[0].y + pDrawable->y;
934 for (i = 0; i < nregRects; i++) {
935 if (mode == CoordModeOrigin) {
936 curX = pDrawable->x + ppts[i+1].x;
937 curY = pDrawable->y + ppts[i+1].y;
939 curX = prevX + ppts[i+1].x;
940 curY = prevY + ppts[i+1].y;
944 rectX1 = curX - extra;
945 rectX2 = prevX + extra + 1;
947 rectX1 = prevX - extra;
948 rectX2 = curX + extra + 1;
952 rectY1 = curY - extra;
953 rectY2 = prevY + extra + 1;
955 rectY1 = prevY - extra;
956 rectY2 = curY + extra + 1;
959 if (nregRects <= MAX_RECTS_PER_OP) {
960 regRects[i].x = rectX1;
961 regRects[i].y = rectY1;
962 regRects[i].width = rectX2 - rectX1;
963 regRects[i].height = rectY2 - rectY1;
965 if (rectX1 < minX) minX = rectX1;
966 if (rectY1 < minY) minY = rectY1;
967 if (rectX2 > maxX) maxX = rectX2;
968 if (rectY2 > maxY) maxY = rectY2;
975 if (nregRects > MAX_RECTS_PER_OP) {
976 regRects[0].x = minX;
977 regRects[0].y = minY;
978 regRects[0].width = maxX - minX;
979 regRects[0].height = maxY - minY;
984 tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nregRects, regRects,
986 REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
987 WINDOW_CLIP_REGION((WindowPtr)pDrawable,pGC));
989 ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
991 REGION_DESTROY(pDrawable->pScreen, tmpRegion);
994 (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts);
997 SCHEDULE_FB_UPDATE(pDrawable->pScreen, prfb);
1000 GC_OP_EPILOGUE(pGC);
1004 * PolySegment - take the union of bounding boxes around each segment (and
1009 rfbPolySegment(pDrawable, pGC, nseg, segs)
1010 DrawablePtr pDrawable;
1015 RegionPtr tmpRegion;
1016 xRectangle regRects[MAX_RECTS_PER_OP];
1017 int i, extra, lw, nregRects;
1018 int rectX1, rectY1, rectX2, rectY2;
1019 int minX, minY, maxX, maxY;
1021 GC_OP_PROLOGUE(pDrawable, pGC);
1023 TRC(("rfbPolySegment called: %d segments\n",nseg));
1027 lw = pGC->lineWidth;
1030 minX = maxX = segs[0].x1;
1031 minY = maxY = segs[0].y1;
1033 for (i = 0; i < nseg; i++)
1035 if (segs[i].x1 > segs[i].x2) {
1036 rectX1 = pDrawable->x + segs[i].x2 - extra;
1037 rectX2 = pDrawable->x + segs[i].x1 + extra + 1;
1039 rectX1 = pDrawable->x + segs[i].x1 - extra;
1040 rectX2 = pDrawable->x + segs[i].x2 + extra + 1;
1043 if (segs[i].y1 > segs[i].y2) {
1044 rectY1 = pDrawable->y + segs[i].y2 - extra;
1045 rectY2 = pDrawable->y + segs[i].y1 + extra + 1;
1047 rectY1 = pDrawable->y + segs[i].y1 - extra;
1048 rectY2 = pDrawable->y + segs[i].y2 + extra + 1;
1051 if (nseg <= MAX_RECTS_PER_OP) {
1052 regRects[i].x = rectX1;
1053 regRects[i].y = rectY1;
1054 regRects[i].width = rectX2 - rectX1;
1055 regRects[i].height = rectY2 - rectY1;
1057 if (rectX1 < minX) minX = rectX1;
1058 if (rectY1 < minY) minY = rectY1;
1059 if (rectX2 > maxX) maxX = rectX2;
1060 if (rectY2 > maxY) maxY = rectY2;
1064 if (nseg > MAX_RECTS_PER_OP) {
1065 regRects[0].x = minX;
1066 regRects[0].y = minY;
1067 regRects[0].width = maxX - minX;
1068 regRects[0].height = maxY - minY;
1072 tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nregRects, regRects,
1074 REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
1075 WINDOW_CLIP_REGION((WindowPtr)pDrawable,pGC));
1077 ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
1079 REGION_DESTROY(pDrawable->pScreen, tmpRegion);
1082 (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs);
1085 SCHEDULE_FB_UPDATE(pDrawable->pScreen, prfb);
1088 GC_OP_EPILOGUE(pGC);
1092 * PolyRectangle (rectangle outlines) - take the union of bounding boxes
1093 * around each line (and clip).
1097 rfbPolyRectangle(pDrawable, pGC, nrects, rects)
1098 DrawablePtr pDrawable;
1103 int i, extra, lw, nregRects;
1104 int rectX1, rectY1, rectX2, rectY2;
1105 int minX, minY, maxX, maxY;
1106 RegionPtr tmpRegion;
1107 xRectangle regRects[MAX_RECTS_PER_OP*4];
1108 GC_OP_PROLOGUE(pDrawable, pGC);
1110 TRC(("rfbPolyRectangle called: %d rects\n",nrects));
1113 nregRects = nrects * 4;
1114 lw = pGC->lineWidth;
1117 minX = maxX = rects[0].x;
1118 minY = maxY = rects[0].y;
1120 for (i = 0; i < nrects; i++)
1122 if (nrects <= MAX_RECTS_PER_OP) {
1123 regRects[i*4].x = rects[i].x - extra + pDrawable->x;
1124 regRects[i*4].y = rects[i].y - extra + pDrawable->y;
1125 regRects[i*4].width = rects[i].width + 1 + 2 * extra;
1126 regRects[i*4].height = 1 + 2 * extra;
1128 regRects[i*4+1].x = rects[i].x - extra + pDrawable->x;
1129 regRects[i*4+1].y = rects[i].y - extra + pDrawable->y;
1130 regRects[i*4+1].width = 1 + 2 * extra;
1131 regRects[i*4+1].height = rects[i].height + 1 + 2 * extra;
1134 = rects[i].x + rects[i].width - extra + pDrawable->x;
1135 regRects[i*4+2].y = rects[i].y - extra + pDrawable->y;
1136 regRects[i*4+2].width = 1 + 2 * extra;
1137 regRects[i*4+2].height = rects[i].height + 1 + 2 * extra;
1139 regRects[i*4+3].x = rects[i].x - extra + pDrawable->x;
1141 = rects[i].y + rects[i].height - extra + pDrawable->y;
1142 regRects[i*4+3].width = rects[i].width + 1 + 2 * extra;
1143 regRects[i*4+3].height = 1 + 2 * extra;
1145 rectX1 = pDrawable->x + rects[i].x - extra;
1146 rectY1 = pDrawable->y + rects[i].y - extra;
1147 rectX2 = pDrawable->x + rects[i].x + rects[i].width + extra+1;
1148 rectY2 = pDrawable->y + rects[i].y + rects[i].height + extra+1;
1149 if (rectX1 < minX) minX = rectX1;
1150 if (rectY1 < minY) minY = rectY1;
1151 if (rectX2 > maxX) maxX = rectX2;
1152 if (rectY2 > maxY) maxY = rectY2;
1156 if (nrects > MAX_RECTS_PER_OP) {
1157 regRects[0].x = minX;
1158 regRects[0].y = minY;
1159 regRects[0].width = maxX - minX;
1160 regRects[0].height = maxY - minY;
1164 tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nregRects,
1166 REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
1167 WINDOW_CLIP_REGION((WindowPtr)pDrawable,pGC));
1169 ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
1171 REGION_DESTROY(pDrawable->pScreen, tmpRegion);
1174 (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects);
1177 SCHEDULE_FB_UPDATE(pDrawable->pScreen, prfb);
1180 GC_OP_EPILOGUE(pGC);
1184 * PolyArc - take the union of bounding boxes around each arc (and clip).
1185 * Bounding boxes assume each is a full circle / ellipse.
1189 rfbPolyArc(pDrawable, pGC, narcs, arcs)
1190 DrawablePtr pDrawable;
1195 int i, extra, lw, nregRects;
1196 int rectX1, rectY1, rectX2, rectY2;
1197 int minX, minY, maxX, maxY;
1198 RegionPtr tmpRegion;
1199 xRectangle regRects[MAX_RECTS_PER_OP];
1200 GC_OP_PROLOGUE(pDrawable, pGC);
1202 TRC(("rfbPolyArc called: %d arcs\n",narcs));
1206 lw = pGC->lineWidth;
1211 minX = maxX = arcs[0].x;
1212 minY = maxY = arcs[0].y;
1214 for (i = 0; i < narcs; i++)
1216 if (narcs <= MAX_RECTS_PER_OP) {
1217 regRects[i].x = arcs[i].x - extra + pDrawable->x;
1218 regRects[i].y = arcs[i].y - extra + pDrawable->y;
1219 regRects[i].width = arcs[i].width + lw;
1220 regRects[i].height = arcs[i].height + lw;
1222 rectX1 = pDrawable->x + arcs[i].x - extra;
1223 rectY1 = pDrawable->y + arcs[i].y - extra;
1224 rectX2 = pDrawable->x + arcs[i].x + arcs[i].width + lw;
1225 rectY2 = pDrawable->y + arcs[i].y + arcs[i].height + lw;
1226 if (rectX1 < minX) minX = rectX1;
1227 if (rectY1 < minY) minY = rectY1;
1228 if (rectX2 > maxX) maxX = rectX2;
1229 if (rectY2 > maxY) maxY = rectY2;
1233 if (narcs > MAX_RECTS_PER_OP) {
1234 regRects[0].x = minX;
1235 regRects[0].y = minY;
1236 regRects[0].width = maxX - minX;
1237 regRects[0].height = maxY - minY;
1241 tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nregRects, regRects,
1243 REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
1244 WINDOW_CLIP_REGION((WindowPtr)pDrawable,pGC));
1246 ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
1248 REGION_DESTROY(pDrawable->pScreen, tmpRegion);
1251 (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs);
1254 SCHEDULE_FB_UPDATE(pDrawable->pScreen, prfb);
1257 GC_OP_EPILOGUE(pGC);
1261 * FillPolygon - take bounding box around polygon (and clip).
1265 rfbFillPolygon(pDrawable, pGC, shape, mode, count, pts)
1266 register DrawablePtr pDrawable;
1273 RegionRec tmpRegion;
1275 GC_OP_PROLOGUE(pDrawable, pGC);
1277 TRC(("rfbFillPolygon called\n"));
1280 int minX = pts[0].x, maxX = pts[0].x;
1281 int minY = pts[0].y, maxY = pts[0].y;
1283 if (mode == CoordModePrevious)
1285 int x = pts[0].x, y = pts[0].y;
1287 for (i = 1; i < count; i++) {
1290 if (x < minX) minX = x;
1291 if (x > maxX) maxX = x;
1292 if (y < minY) minY = y;
1293 if (y > maxY) maxY = y;
1298 for (i = 1; i < count; i++) {
1299 if (pts[i].x < minX) minX = pts[i].x;
1300 if (pts[i].x > maxX) maxX = pts[i].x;
1301 if (pts[i].y < minY) minY = pts[i].y;
1302 if (pts[i].y > maxY) maxY = pts[i].y;
1306 box.x1 = minX + pDrawable->x;
1307 box.y1 = minY + pDrawable->y;
1308 box.x2 = maxX + 1 + pDrawable->x;
1309 box.y2 = maxY + 1 + pDrawable->y;
1311 SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
1313 REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
1314 WINDOW_CLIP_REGION(((WindowPtr)pDrawable),pGC));
1316 ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
1318 REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
1321 (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts);
1324 SCHEDULE_FB_UPDATE(pDrawable->pScreen, prfb);
1327 GC_OP_EPILOGUE(pGC);
1331 * PolyFillRect - take the union of the given rectangles (and clip).
1335 rfbPolyFillRect(pDrawable, pGC, nrects, rects)
1336 DrawablePtr pDrawable;
1341 RegionPtr tmpRegion;
1342 xRectangle regRects[MAX_RECTS_PER_OP];
1344 int rectX1, rectY1, rectX2, rectY2;
1345 int minX, minY, maxX, maxY;
1346 GC_OP_PROLOGUE(pDrawable, pGC);
1348 TRC(("rfbPolyFillRect called: %d rects\n",nrects));
1353 minX = maxX = rects[0].x;
1354 minY = maxY = rects[0].y;
1356 for (i = 0; i < nrects; i++) {
1357 if (nrects <= MAX_RECTS_PER_OP) {
1358 regRects[i].x = rects[i].x + pDrawable->x;
1359 regRects[i].y = rects[i].y + pDrawable->y;
1360 regRects[i].width = rects[i].width;
1361 regRects[i].height = rects[i].height;
1363 rectX1 = pDrawable->x + rects[i].x;
1364 rectY1 = pDrawable->y + rects[i].y;
1365 rectX2 = pDrawable->x + rects[i].x + rects[i].width;
1366 rectY2 = pDrawable->y + rects[i].y + rects[i].height;
1367 if (rectX1 < minX) minX = rectX1;
1368 if (rectY1 < minY) minY = rectY1;
1369 if (rectX2 > maxX) maxX = rectX2;
1370 if (rectY2 > maxY) maxY = rectY2;
1374 if (nrects > MAX_RECTS_PER_OP) {
1375 regRects[0].x = minX;
1376 regRects[0].y = minY;
1377 regRects[0].width = maxX - minX;
1378 regRects[0].height = maxY - minY;
1382 tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nregRects, regRects,
1384 REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
1385 WINDOW_CLIP_REGION((WindowPtr)pDrawable,pGC));
1387 ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
1389 REGION_DESTROY(pDrawable->pScreen, tmpRegion);
1392 (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects);
1395 SCHEDULE_FB_UPDATE(pDrawable->pScreen, prfb);
1398 GC_OP_EPILOGUE(pGC);
1402 * PolyFillArc - take the union of bounding boxes around each arc (and clip).
1403 * Bounding boxes assume each is a full circle / ellipse.
1407 rfbPolyFillArc(pDrawable, pGC, narcs, arcs)
1408 DrawablePtr pDrawable;
1413 int i, extra, lw, nregRects;
1414 int rectX1, rectY1, rectX2, rectY2;
1415 int minX, minY, maxX, maxY;
1416 RegionPtr tmpRegion;
1417 xRectangle regRects[MAX_RECTS_PER_OP];
1418 GC_OP_PROLOGUE(pDrawable, pGC);
1420 TRC(("rfbPolyFillArc called: %d arcs\n",narcs));
1424 lw = pGC->lineWidth;
1429 minX = maxX = arcs[0].x;
1430 minY = maxY = arcs[0].y;
1432 for (i = 0; i < narcs; i++)
1434 if (narcs <= MAX_RECTS_PER_OP) {
1435 regRects[i].x = arcs[i].x - extra + pDrawable->x;
1436 regRects[i].y = arcs[i].y - extra + pDrawable->y;
1437 regRects[i].width = arcs[i].width + lw;
1438 regRects[i].height = arcs[i].height + lw;
1440 rectX1 = pDrawable->x + arcs[i].x - extra;
1441 rectY1 = pDrawable->y + arcs[i].y - extra;
1442 rectX2 = pDrawable->x + arcs[i].x + arcs[i].width + lw;
1443 rectY2 = pDrawable->y + arcs[i].y + arcs[i].height + lw;
1444 if (rectX1 < minX) minX = rectX1;
1445 if (rectY1 < minY) minY = rectY1;
1446 if (rectX2 > maxX) maxX = rectX2;
1447 if (rectY2 > maxY) maxY = rectY2;
1451 if (narcs > MAX_RECTS_PER_OP) {
1452 regRects[0].x = minX;
1453 regRects[0].y = minY;
1454 regRects[0].width = maxX - minX;
1455 regRects[0].height = maxY - minY;
1459 tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nregRects, regRects,
1461 REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
1462 WINDOW_CLIP_REGION((WindowPtr)pDrawable,pGC));
1464 ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
1466 REGION_DESTROY(pDrawable->pScreen, tmpRegion);
1469 (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs);
1472 SCHEDULE_FB_UPDATE(pDrawable->pScreen, prfb);
1475 GC_OP_EPILOGUE(pGC);
1479 * Get a rough bounding box around n characters of the given font.
1482 static void GetTextBoundingBox(pDrawable, font, x, y, n, pbox)
1483 DrawablePtr pDrawable;
1488 int maxAscent, maxDescent, maxCharWidth;
1490 if (FONTASCENT(font) > FONTMAXBOUNDS(font,ascent))
1491 maxAscent = FONTASCENT(font);
1493 maxAscent = FONTMAXBOUNDS(font,ascent);
1495 if (FONTDESCENT(font) > FONTMAXBOUNDS(font,descent))
1496 maxDescent = FONTDESCENT(font);
1498 maxDescent = FONTMAXBOUNDS(font,descent);
1500 if (FONTMAXBOUNDS(font,rightSideBearing) > FONTMAXBOUNDS(font,characterWidth))
1501 maxCharWidth = FONTMAXBOUNDS(font,rightSideBearing);
1503 maxCharWidth = FONTMAXBOUNDS(font,characterWidth);
1505 pbox->x1 = pDrawable->x + x;
1506 pbox->y1 = pDrawable->y + y - maxAscent;
1507 pbox->x2 = pbox->x1 + maxCharWidth * n;
1508 pbox->y2 = pbox->y1 + maxAscent + maxDescent;
1510 if (FONTMINBOUNDS(font,leftSideBearing) < 0) {
1511 pbox->x1 += FONTMINBOUNDS(font,leftSideBearing);
1517 * PolyText8 - use rough bounding box.
1521 rfbPolyText8(pDrawable, pGC, x, y, count, chars)
1522 DrawablePtr pDrawable;
1529 RegionRec tmpRegion;
1531 GC_OP_PROLOGUE(pDrawable, pGC);
1533 TRC(("rfbPolyText8 called '%.*s'\n",count,chars));
1536 GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box);
1538 SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
1540 REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
1541 WINDOW_CLIP_REGION(((WindowPtr)pDrawable),pGC));
1543 ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
1545 REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
1548 ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
1551 SCHEDULE_FB_UPDATE(pDrawable->pScreen, prfb);
1554 GC_OP_EPILOGUE(pGC);
1559 * PolyText16 - use rough bounding box.
1563 rfbPolyText16(pDrawable, pGC, x, y, count, chars)
1564 DrawablePtr pDrawable;
1568 unsigned short *chars;
1571 RegionRec tmpRegion;
1573 GC_OP_PROLOGUE(pDrawable, pGC);
1575 TRC(("rfbPolyText16 called\n"));
1578 GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box);
1580 SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
1582 REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
1583 WINDOW_CLIP_REGION(((WindowPtr)pDrawable),pGC));
1585 ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
1587 REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
1590 ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
1593 SCHEDULE_FB_UPDATE(pDrawable->pScreen, prfb);
1596 GC_OP_EPILOGUE(pGC);
1601 * ImageText8 - use rough bounding box.
1605 rfbImageText8(pDrawable, pGC, x, y, count, chars)
1606 DrawablePtr pDrawable;
1612 RegionRec tmpRegion;
1614 GC_OP_PROLOGUE(pDrawable, pGC);
1616 TRC(("rfbImageText8 called '%.*s'\n",count,chars));
1619 GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box);
1621 SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
1623 REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
1624 WINDOW_CLIP_REGION(((WindowPtr)pDrawable),pGC));
1626 ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
1628 REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
1631 (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
1634 SCHEDULE_FB_UPDATE(pDrawable->pScreen, prfb);
1637 GC_OP_EPILOGUE(pGC);
1641 * ImageText16 - use rough bounding box.
1645 rfbImageText16(pDrawable, pGC, x, y, count, chars)
1646 DrawablePtr pDrawable;
1650 unsigned short *chars;
1652 RegionRec tmpRegion;
1654 GC_OP_PROLOGUE(pDrawable, pGC);
1656 TRC(("rfbImageText16 called\n"));
1659 GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box);
1661 SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
1663 REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
1664 WINDOW_CLIP_REGION(((WindowPtr)pDrawable),pGC));
1666 ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
1668 REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
1671 (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
1674 SCHEDULE_FB_UPDATE(pDrawable->pScreen, prfb);
1677 GC_OP_EPILOGUE(pGC);
1681 * ImageGlyphBlt - use rough bounding box.
1685 rfbImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)
1686 DrawablePtr pDrawable;
1689 unsigned int nglyph;
1690 CharInfoPtr *ppci; /* array of character info */
1691 pointer pglyphBase; /* start of array of glyphs */
1693 RegionRec tmpRegion;
1695 GC_OP_PROLOGUE(pDrawable, pGC);
1697 TRC(("rfbImageGlyphBlt called\n"));
1700 GetTextBoundingBox(pDrawable, pGC->font, x, y, nglyph, &box);
1702 SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
1704 REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
1705 WINDOW_CLIP_REGION(((WindowPtr)pDrawable),pGC));
1707 ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
1709 REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
1712 (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase);
1715 SCHEDULE_FB_UPDATE(pDrawable->pScreen, prfb);
1718 GC_OP_EPILOGUE(pGC);
1722 * PolyGlyphBlt - use rough bounding box.
1726 rfbPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)
1727 DrawablePtr pDrawable;
1730 unsigned int nglyph;
1731 CharInfoPtr *ppci; /* array of character info */
1732 pointer pglyphBase; /* start of array of glyphs */
1734 RegionRec tmpRegion;
1736 GC_OP_PROLOGUE(pDrawable, pGC);
1738 TRC(("rfbPolyGlyphBlt called\n"));
1741 GetTextBoundingBox(pDrawable, pGC->font, x, y, nglyph, &box);
1743 SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
1745 REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
1746 WINDOW_CLIP_REGION(((WindowPtr)pDrawable),pGC));
1748 ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
1750 REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
1753 (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
1756 SCHEDULE_FB_UPDATE(pDrawable->pScreen, prfb);
1759 GC_OP_EPILOGUE(pGC);
1763 * PushPixels - be fairly safe - region modified is intersection of the given
1764 * rectangle with the window clip region.
1768 rfbPushPixels(pGC, pBitMap, pDrawable, w, h, x, y)
1771 DrawablePtr pDrawable;
1774 RegionRec tmpRegion;
1776 GC_OP_PROLOGUE(pDrawable, pGC);
1778 TRC(("rfbPushPixels called\n"));
1780 box.x1 = x + pDrawable->x;
1781 box.y1 = y + pDrawable->y;
1782 box.x2 = box.x1 + w;
1783 box.y2 = box.y1 + h;
1785 SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
1787 REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
1788 WINDOW_CLIP_REGION(((WindowPtr)pDrawable),pGC));
1790 ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
1792 REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
1794 (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y);
1796 SCHEDULE_FB_UPDATE(pDrawable->pScreen, prfb);
1798 GC_OP_EPILOGUE(pGC);
1803 /****************************************************************************/
1807 /****************************************************************************/
1810 * rfbCopyRegion. Args are src and dst regions plus a translation (dx,dy).
1811 * Takes these args together with the existing modified region and possibly an
1812 * existing copy region and translation. Produces a combined modified region
1813 * plus copy region and translation. Note that the copy region is the
1814 * destination of the copy.
1816 * First we trim parts of src which are invalid (ie in the modified region).
1817 * Then we see if there is any overlap between the src and the existing copy
1818 * region. If not then the two copies cannot be combined, so we choose
1819 * whichever is bigger to form the basis of a new copy, while the other copy is
1820 * just done the hard way by being added to the modified region. So if the
1821 * existing copy is bigger then we simply add the destination of the new copy
1822 * to the modified region and we're done. If the new copy is bigger, we add
1823 * the old copy region to the modified region and behave as though there is no
1824 * existing copy region.
1826 * At this stage we now know that either the two copies can be combined, or
1827 * that there is no existing copy. We temporarily add both the existing copy
1828 * region and dst to the modified region (this is the entire area of the screen
1829 * affected in any way). Finally we calculate the new copy region, and remove
1830 * it from the modified region.
1833 * 1. The src region is modified by this routine.
1834 * 2. When the copy region is empty, copyDX and copyDY MUST be set to zero.
1838 rfbCopyRegion(pScreen, cl, src, dst, dx, dy)
1847 /* src = src - modifiedRegion */
1849 REGION_SUBTRACT(pScreen, src, src, &cl->modifiedRegion);
1851 if (REGION_NOTEMPTY(pScreen, &cl->copyRegion)) {
1853 REGION_INIT(pScreen, &tmp, NullBox, 0);
1854 REGION_INTERSECT(pScreen, &tmp, src, &cl->copyRegion);
1856 if (REGION_NOTEMPTY(pScreen, &tmp)) {
1858 /* if src and copyRegion overlap:
1859 src = src intersect copyRegion */
1861 REGION_COPY(pScreen, src, &tmp);
1865 /* if no overlap, find bigger region */
1867 int newArea = (((REGION_EXTENTS(pScreen,src))->x2
1868 - (REGION_EXTENTS(pScreen,src))->x1)
1869 * ((REGION_EXTENTS(pScreen,src))->y2
1870 - (REGION_EXTENTS(pScreen,src))->y1));
1872 int oldArea = (((REGION_EXTENTS(pScreen,&cl->copyRegion))->x2
1873 - (REGION_EXTENTS(pScreen,&cl->copyRegion))->x1)
1874 * ((REGION_EXTENTS(pScreen,&cl->copyRegion))->y2
1875 - (REGION_EXTENTS(pScreen,&cl->copyRegion))->y1));
1877 if (oldArea > newArea) {
1879 /* existing copy is bigger:
1880 modifiedRegion = modifiedRegion union dst
1881 copyRegion = copyRegion - dst
1884 REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
1886 REGION_SUBTRACT(pScreen, &cl->copyRegion, &cl->copyRegion,
1888 if (!REGION_NOTEMPTY(pScreen, &cl->copyRegion)) {
1895 /* new copy is bigger:
1896 modifiedRegion = modifiedRegion union copyRegion
1897 copyRegion = empty */
1899 REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
1901 REGION_EMPTY(pScreen, &cl->copyRegion);
1902 cl->copyDX = cl->copyDY = 0;
1907 /* modifiedRegion = modifiedRegion union dst union copyRegion */
1909 REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, dst);
1910 REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
1913 /* copyRegion = T(src) intersect dst */
1915 REGION_TRANSLATE(pScreen, src, dx, dy);
1916 REGION_INTERSECT(pScreen, &cl->copyRegion, src, dst);
1918 /* modifiedRegion = modifiedRegion - copyRegion */
1920 REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
1923 /* combine new translation T with existing translation */
1925 if (REGION_NOTEMPTY(pScreen, &cl->copyRegion)) {
1936 * rfbDeferredUpdateCallback() is called when a client's deferredUpdateTimer
1941 rfbDeferredUpdateCallback(OsTimerPtr timer, CARD32 now, pointer arg)
1943 rfbClientPtr cl = (rfbClientPtr)arg;
1945 rfbSendFramebufferUpdate(cl);
1947 cl->deferredUpdateScheduled = FALSE;
1953 * rfbScheduleDeferredUpdate() is called from the SCHEDULE_FB_UPDATE macro
1954 * to schedule an update.
1958 rfbScheduleDeferredUpdate(rfbClientPtr cl)
1960 if (rfbDeferUpdateTime != 0) {
1961 cl->deferredUpdateTimer = TimerSet(cl->deferredUpdateTimer, 0,
1963 rfbDeferredUpdateCallback, cl);
1964 cl->deferredUpdateScheduled = TRUE;
1966 rfbSendFramebufferUpdate(cl);
1972 * PrintRegion is useful for debugging.
1977 PrintRegion(pScreen,reg)
1981 int nrects = REGION_NUM_RECTS(reg);
1984 rfbLog("Region num rects %d extents %d,%d %d,%d\n",nrects,
1985 (REGION_EXTENTS(pScreen,reg))->x1,
1986 (REGION_EXTENTS(pScreen,reg))->y1,
1987 (REGION_EXTENTS(pScreen,reg))->x2,
1988 (REGION_EXTENTS(pScreen,reg))->y2);
1990 for (i = 0; i < nrects; i++) {
1991 rfbLog(" rect %d,%d %dx%d\n",
1992 REGION_RECTS(reg)[i].x1,
1993 REGION_RECTS(reg)[i].y1,
1994 REGION_RECTS(reg)[i].x2-REGION_RECTS(reg)[i].x1,
1995 REGION_RECTS(reg)[i].y2-REGION_RECTS(reg)[i].y1);