1/*
2   Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
3   All rights reserved.
4
5This file is part of x11vnc.
6
7x11vnc is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or (at
10your option) any later version.
11
12x11vnc is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with x11vnc; if not, write to the Free Software
19Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
20or see <http://www.gnu.org/licenses/>.
21
22In addition, as a special exception, Karl J. Runge
23gives permission to link the code of its release of x11vnc with the
24OpenSSL project's "OpenSSL" library (or with modified versions of it
25that use the same license as the "OpenSSL" library), and distribute
26the linked executables.  You must obey the GNU General Public License
27in all respects for all of the code used other than "OpenSSL".  If you
28modify this file, you may extend this exception to your version of the
29file, but you are not obligated to do so.  If you do not wish to do
30so, delete this exception statement from your version.
31*/
32
33/* -- scan.c -- */
34
35#include "x11vnc.h"
36#include "xinerama.h"
37#include "xwrappers.h"
38#include "xdamage.h"
39#include "xrandr.h"
40#include "win_utils.h"
41#include "8to24.h"
42#include "screen.h"
43#include "pointer.h"
44#include "cleanup.h"
45#include "unixpw.h"
46#include "screen.h"
47#include "macosx.h"
48#include "userinput.h"
49
50/*
51 * routines for scanning and reading the X11 display for changes, and
52 * for doing all the tile work (shm, etc).
53 */
54void initialize_tiles(void);
55void free_tiles(void);
56void shm_delete(XShmSegmentInfo *shm);
57void shm_clean(XShmSegmentInfo *shm, XImage *xim);
58void initialize_polling_images(void);
59void scale_rect(double factor_x, double factor_y, int blend, int interpolate, int Bpp,
60    char *src_fb, int src_bytes_per_line, char *dst_fb, int dst_bytes_per_line,
61    int Nx, int Ny, int nx, int ny, int X1, int Y1, int X2, int Y2, int mark);
62void scale_and_mark_rect(int X1, int Y1, int X2, int Y2, int mark);
63void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force);
64int copy_screen(void);
65int copy_snap(void);
66void nap_sleep(int ms, int split);
67void set_offset(void);
68int scan_for_updates(int count_only);
69void rotate_curs(char *dst_0, char *src_0, int Dx, int Dy, int Bpp);
70void rotate_coords(int x, int y, int *xo, int *yo, int dxi, int dyi);
71void rotate_coords_inverse(int x, int y, int *xo, int *yo, int dxi, int dyi);
72
73static void set_fs_factor(int max);
74static char *flip_ximage_byte_order(XImage *xim);
75static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h,
76    char *name);
77static void create_tile_hint(int x, int y, int tw, int th, hint_t *hint);
78static void extend_tile_hint(int x, int y, int tw, int th, hint_t *hint);
79static void save_hint(hint_t hint, int loc);
80static void hint_updates(void);
81static void mark_hint(hint_t hint);
82static int copy_tiles(int tx, int ty, int nt);
83static int copy_all_tiles(void);
84static int copy_all_tile_runs(void);
85static int copy_tiles_backward_pass(void);
86static int copy_tiles_additional_pass(void);
87static int gap_try(int x, int y, int *run, int *saw, int along_x);
88static int fill_tile_gaps(void);
89static int island_try(int x, int y, int u, int v, int *run);
90static int grow_islands(void);
91static void blackout_regions(void);
92static void nap_set(int tile_cnt);
93static void nap_check(int tile_cnt);
94static void ping_clients(int tile_cnt);
95static int blackout_line_skip(int n, int x, int y, int rescan,
96    int *tile_count);
97static int blackout_line_cmpskip(int n, int x, int y, char *dst, char *src,
98    int w, int pixelsize);
99static int scan_display(int ystart, int rescan);
100
101
102/* array to hold the hints: */
103static hint_t *hint_list;
104
105/* nap state */
106int nap_ok = 0;
107static int nap_diff_count = 0;
108
109static int scan_count = 0;	/* indicates which scan pattern we are on  */
110static int scan_in_progress = 0;
111
112
113typedef struct tile_change_region {
114	/* start and end lines, along y, of the changed area inside a tile. */
115	unsigned short first_line, last_line;
116	short first_x, last_x;
117	/* info about differences along edges. */
118	unsigned short left_diff, right_diff;
119	unsigned short top_diff,  bot_diff;
120} region_t;
121
122/* array to hold the tiles region_t-s. */
123static region_t *tile_region;
124
125
126
127
128/*
129 * setup tile numbers and allocate the tile and hint arrays:
130 */
131void initialize_tiles(void) {
132
133	ntiles_x = (dpy_x - 1)/tile_x + 1;
134	ntiles_y = (dpy_y - 1)/tile_y + 1;
135	ntiles = ntiles_x * ntiles_y;
136
137	tile_has_diff = (unsigned char *)
138		calloc((size_t) (ntiles * sizeof(unsigned char)), 1);
139	tile_has_xdamage_diff = (unsigned char *)
140		calloc((size_t) (ntiles * sizeof(unsigned char)), 1);
141	tile_row_has_xdamage_diff = (unsigned char *)
142		calloc((size_t) (ntiles_y * sizeof(unsigned char)), 1);
143	tile_tried    = (unsigned char *)
144		calloc((size_t) (ntiles * sizeof(unsigned char)), 1);
145	tile_copied   = (unsigned char *)
146		calloc((size_t) (ntiles * sizeof(unsigned char)), 1);
147	tile_blackout    = (tile_blackout_t *)
148		calloc((size_t) (ntiles * sizeof(tile_blackout_t)), 1);
149	tile_region = (region_t *) calloc((size_t) (ntiles * sizeof(region_t)), 1);
150
151	tile_row = (XImage **)
152		calloc((size_t) ((ntiles_x + 1) * sizeof(XImage *)), 1);
153	tile_row_shm = (XShmSegmentInfo *)
154		calloc((size_t) ((ntiles_x + 1) * sizeof(XShmSegmentInfo)), 1);
155
156	/* there will never be more hints than tiles: */
157	hint_list = (hint_t *) calloc((size_t) (ntiles * sizeof(hint_t)), 1);
158}
159
160void free_tiles(void) {
161	if (tile_has_diff) {
162		free(tile_has_diff);
163		tile_has_diff = NULL;
164	}
165	if (tile_has_xdamage_diff) {
166		free(tile_has_xdamage_diff);
167		tile_has_xdamage_diff = NULL;
168	}
169	if (tile_row_has_xdamage_diff) {
170		free(tile_row_has_xdamage_diff);
171		tile_row_has_xdamage_diff = NULL;
172	}
173	if (tile_tried) {
174		free(tile_tried);
175		tile_tried = NULL;
176	}
177	if (tile_copied) {
178		free(tile_copied);
179		tile_copied = NULL;
180	}
181	if (tile_blackout) {
182		free(tile_blackout);
183		tile_blackout = NULL;
184	}
185	if (tile_region) {
186		free(tile_region);
187		tile_region = NULL;
188	}
189	if (tile_row) {
190		free(tile_row);
191		tile_row = NULL;
192	}
193	if (tile_row_shm) {
194		free(tile_row_shm);
195		tile_row_shm = NULL;
196	}
197	if (hint_list) {
198		free(hint_list);
199		hint_list = NULL;
200	}
201}
202
203/*
204 * silly function to factor dpy_y until fullscreen shm is not bigger than max.
205 * should always work unless dpy_y is a large prime or something... under
206 * failure fs_factor remains 0 and no fullscreen updates will be tried.
207 */
208static int fs_factor = 0;
209
210static void set_fs_factor(int max) {
211	int f, fac = 1, n = dpy_y;
212
213	fs_factor = 0;
214	if ((bpp/8) * dpy_x * dpy_y <= max)  {
215		fs_factor = 1;
216		return;
217	}
218	for (f=2; f <= 101; f++) {
219		while (n % f == 0) {
220			n = n / f;
221			fac = fac * f;
222			if ( (bpp/8) * dpy_x * (dpy_y/fac) <= max )  {
223				fs_factor = fac;
224				return;
225			}
226		}
227	}
228}
229
230static char *flip_ximage_byte_order(XImage *xim) {
231	char *order;
232	if (xim->byte_order == LSBFirst) {
233		order = "MSBFirst";
234		xim->byte_order = MSBFirst;
235		xim->bitmap_bit_order = MSBFirst;
236	} else {
237		order = "LSBFirst";
238		xim->byte_order = LSBFirst;
239		xim->bitmap_bit_order = LSBFirst;
240	}
241	return order;
242}
243
244/*
245 * set up an XShm image, or if not using shm just create the XImage.
246 */
247static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h,
248    char *name) {
249
250	XImage *xim;
251	static int reported_flip = 0;
252	int db = 0;
253
254	shm->shmid = -1;
255	shm->shmaddr = (char *) -1;
256	*ximg_ptr = NULL;
257
258	if (nofb) {
259		return 1;
260	}
261
262	X_LOCK;
263
264	if (! using_shm || xform24to32 || raw_fb) {
265		/* we only need the XImage created */
266		xim = XCreateImage_wr(dpy, default_visual, depth, ZPixmap,
267		    0, NULL, w, h, raw_fb ? 32 : BitmapPad(dpy), 0);
268
269		X_UNLOCK;
270
271		if (xim == NULL) {
272			rfbErr("XCreateImage(%s) failed.\n", name);
273			if (quiet) {
274				fprintf(stderr, "XCreateImage(%s) failed.\n",
275				    name);
276			}
277			return 0;
278		}
279		if (db) fprintf(stderr, "shm_create simple %d %d\t%p %s\n", w, h, (void *)xim, name);
280		xim->data = (char *) malloc(xim->bytes_per_line * xim->height);
281		if (xim->data == NULL) {
282			rfbErr("XCreateImage(%s) data malloc failed.\n", name);
283			if (quiet) {
284				fprintf(stderr, "XCreateImage(%s) data malloc"
285				    " failed.\n", name);
286			}
287			return 0;
288		}
289		if (flip_byte_order) {
290			char *order = flip_ximage_byte_order(xim);
291			if (! reported_flip && ! quiet) {
292				rfbLog("Changing XImage byte order"
293				    " to %s\n", order);
294				reported_flip = 1;
295			}
296		}
297
298		*ximg_ptr = xim;
299		return 1;
300	}
301
302	if (! dpy) {
303		X_UNLOCK;
304		return 0;
305	}
306
307	xim = XShmCreateImage_wr(dpy, default_visual, depth, ZPixmap, NULL,
308	    shm, w, h);
309
310	if (xim == NULL) {
311		rfbErr("XShmCreateImage(%s) failed.\n", name);
312		if (quiet) {
313			fprintf(stderr, "XShmCreateImage(%s) failed.\n", name);
314		}
315		X_UNLOCK;
316		return 0;
317	}
318
319	*ximg_ptr = xim;
320
321#if LIBVNCSERVER_HAVE_XSHM
322	shm->shmid = shmget(IPC_PRIVATE,
323	    xim->bytes_per_line * xim->height, IPC_CREAT | 0777);
324
325	if (shm->shmid == -1) {
326		rfbErr("shmget(%s) failed.\n", name);
327		rfbLogPerror("shmget");
328
329		XDestroyImage(xim);
330		*ximg_ptr = NULL;
331
332		X_UNLOCK;
333		return 0;
334	}
335
336	shm->shmaddr = xim->data = (char *) shmat(shm->shmid, 0, 0);
337
338	if (shm->shmaddr == (char *)-1) {
339		rfbErr("shmat(%s) failed.\n", name);
340		rfbLogPerror("shmat");
341
342		XDestroyImage(xim);
343		*ximg_ptr = NULL;
344
345		shmctl(shm->shmid, IPC_RMID, 0);
346		shm->shmid = -1;
347
348		X_UNLOCK;
349		return 0;
350	}
351
352	shm->readOnly = False;
353
354	if (! XShmAttach_wr(dpy, shm)) {
355		rfbErr("XShmAttach(%s) failed.\n", name);
356		XDestroyImage(xim);
357		*ximg_ptr = NULL;
358
359		shmdt(shm->shmaddr);
360		shm->shmaddr = (char *) -1;
361
362		shmctl(shm->shmid, IPC_RMID, 0);
363		shm->shmid = -1;
364
365		X_UNLOCK;
366		return 0;
367	}
368#endif
369
370	X_UNLOCK;
371	return 1;
372}
373
374void shm_delete(XShmSegmentInfo *shm) {
375#if LIBVNCSERVER_HAVE_XSHM
376	if (getenv("X11VNC_SHM_DEBUG")) fprintf(stderr, "shm_delete:    %p\n", (void *) shm);
377	if (shm != NULL && shm->shmaddr != (char *) -1) {
378		shmdt(shm->shmaddr);
379	}
380	if (shm != NULL && shm->shmid != -1) {
381		shmctl(shm->shmid, IPC_RMID, 0);
382	}
383	if (shm != NULL) {
384		shm->shmaddr = (char *) -1;
385		shm->shmid = -1;
386	}
387#else
388	if (!shm) {}
389#endif
390}
391
392void shm_clean(XShmSegmentInfo *shm, XImage *xim) {
393	int db = 0;
394
395	if (db) fprintf(stderr, "shm_clean: called:  %p\n", (void *)xim);
396	X_LOCK;
397#if LIBVNCSERVER_HAVE_XSHM
398	if (shm != NULL && shm->shmid != -1 && dpy) {
399		if (db) fprintf(stderr, "shm_clean: XShmDetach_wr\n");
400		XShmDetach_wr(dpy, shm);
401	}
402#endif
403	if (xim != NULL) {
404		if (! raw_fb_back_to_X) {	/* raw_fb hack */
405			if (xim->bitmap_unit != -1) {
406				if (db) fprintf(stderr, "shm_clean: XDestroyImage  %p\n", (void *)xim);
407				XDestroyImage(xim);
408			} else {
409				if (xim->data) {
410					if (db) fprintf(stderr, "shm_clean: free xim->data  %p %p\n", (void *)xim, (void *)(xim->data));
411					free(xim->data);
412					xim->data = NULL;
413				}
414			}
415		}
416		xim = NULL;
417	}
418	X_UNLOCK;
419
420	shm_delete(shm);
421}
422
423void initialize_polling_images(void) {
424	int i, MB = 1024 * 1024;
425
426	/* set all shm areas to "none" before trying to create any */
427	scanline_shm.shmid	= -1;
428	scanline_shm.shmaddr	= (char *) -1;
429	scanline		= NULL;
430	fullscreen_shm.shmid	= -1;
431	fullscreen_shm.shmaddr	= (char *) -1;
432	fullscreen		= NULL;
433	snaprect_shm.shmid	= -1;
434	snaprect_shm.shmaddr	= (char *) -1;
435	snaprect		= NULL;
436	for (i=1; i<=ntiles_x; i++) {
437		tile_row_shm[i].shmid	= -1;
438		tile_row_shm[i].shmaddr	= (char *) -1;
439		tile_row[i]		= NULL;
440	}
441
442	/* the scanline (e.g. 1280x1) shared memory area image: */
443
444	if (! shm_create(&scanline_shm, &scanline, dpy_x, 1, "scanline")) {
445		clean_up_exit(1);
446	}
447
448	/*
449	 * the fullscreen (e.g. 1280x1024/fs_factor) shared memory area image:
450	 * (we cut down the size of the shm area to try avoid and shm segment
451	 * limits, e.g. the default 1MB on Solaris)
452	 */
453	if (UT.sysname && strstr(UT.sysname, "Linux")) {
454		set_fs_factor(10 * MB);
455	} else {
456		set_fs_factor(1 * MB);
457	}
458	if (fs_frac >= 1.0) {
459		fs_frac = 1.1;
460		fs_factor = 0;
461	}
462	if (! fs_factor) {
463		rfbLog("warning: fullscreen updates are disabled.\n");
464	} else {
465		if (! shm_create(&fullscreen_shm, &fullscreen, dpy_x,
466		    dpy_y/fs_factor, "fullscreen")) {
467			clean_up_exit(1);
468		}
469	}
470	if (use_snapfb) {
471		if (! fs_factor) {
472			rfbLog("warning: disabling -snapfb mode.\n");
473			use_snapfb = 0;
474		} else if (! shm_create(&snaprect_shm, &snaprect, dpy_x,
475		    dpy_y/fs_factor, "snaprect")) {
476			clean_up_exit(1);
477		}
478	}
479
480	/*
481	 * for copy_tiles we need a lot of shared memory areas, one for
482	 * each possible run length of changed tiles.  32 for 1024x768
483	 * and 40 for 1280x1024, etc.
484	 */
485
486	tile_shm_count = 0;
487	for (i=1; i<=ntiles_x; i++) {
488		if (! shm_create(&tile_row_shm[i], &tile_row[i], tile_x * i,
489		    tile_y, "tile_row")) {
490			if (i == 1) {
491				clean_up_exit(1);
492			}
493			rfbLog("shm: Error creating shared memory tile-row for"
494			    " len=%d,\n", i);
495			rfbLog("shm: reverting to -onetile mode. If this"
496			    " problem persists\n");
497			rfbLog("shm: try using the -onetile or -noshm options"
498			    " to limit\n");
499			rfbLog("shm: shared memory usage, or run ipcrm(1)"
500			    " to manually\n");
501			rfbLog("shm: delete unattached shm segments.\n");
502			single_copytile_count = i;
503			single_copytile = 1;
504		}
505		tile_shm_count++;
506		if (single_copytile && i >= 1) {
507			/* only need 1x1 tiles */
508			break;
509		}
510	}
511	if (verbose) {
512		if (using_shm && ! xform24to32) {
513			rfbLog("created %d tile_row shm polling images.\n",
514			    tile_shm_count);
515		} else {
516			rfbLog("created %d tile_row polling images.\n",
517			    tile_shm_count);
518		}
519	}
520}
521
522/*
523 * A hint is a rectangular region built from 1 or more adjacent tiles
524 * glued together.  Ultimately, this information in a single hint is sent
525 * to libvncserver rather than sending each tile separately.
526 */
527static void create_tile_hint(int x, int y, int tw, int th, hint_t *hint) {
528	int w = dpy_x - x;
529	int h = dpy_y - y;
530
531	if (w > tw) {
532		w = tw;
533	}
534	if (h > th) {
535		h = th;
536	}
537
538	hint->x = x;
539	hint->y = y;
540	hint->w = w;
541	hint->h = h;
542}
543
544static void extend_tile_hint(int x, int y, int tw, int th, hint_t *hint) {
545	int w = dpy_x - x;
546	int h = dpy_y - y;
547
548	if (w > tw) {
549		w = tw;
550	}
551	if (h > th) {
552		h = th;
553	}
554
555	if (hint->x > x) {			/* extend to the left */
556		hint->w += hint->x - x;
557		hint->x = x;
558	}
559	if (hint->y > y) {			/* extend upward */
560		hint->h += hint->y - y;
561		hint->y = y;
562	}
563
564	if (hint->x + hint->w < x + w) {	/* extend to the right */
565		hint->w = x + w - hint->x;
566	}
567	if (hint->y + hint->h < y + h) {	/* extend downward */
568		hint->h = y + h - hint->y;
569	}
570}
571
572static void save_hint(hint_t hint, int loc) {
573	/* simply copy it to the global array for later use. */
574	hint_list[loc].x = hint.x;
575	hint_list[loc].y = hint.y;
576	hint_list[loc].w = hint.w;
577	hint_list[loc].h = hint.h;
578}
579
580/*
581 * Glue together horizontal "runs" of adjacent changed tiles into one big
582 * rectangle change "hint" to be passed to the vnc machinery.
583 */
584static void hint_updates(void) {
585	hint_t hint;
586	int x, y, i, n, ty, th, tx, tw;
587	int hint_count = 0, in_run = 0;
588
589	hint.x = hint.y = hint.w = hint.h = 0;
590
591	for (y=0; y < ntiles_y; y++) {
592		for (x=0; x < ntiles_x; x++) {
593			n = x + y * ntiles_x;
594
595			if (tile_has_diff[n]) {
596				ty = tile_region[n].first_line;
597				th = tile_region[n].last_line - ty + 1;
598
599				tx = tile_region[n].first_x;
600				tw = tile_region[n].last_x - tx + 1;
601				if (tx < 0) {
602					tx = 0;
603					tw = tile_x;
604				}
605
606				if (! in_run) {
607					create_tile_hint( x * tile_x + tx,
608					    y * tile_y + ty, tw, th, &hint);
609					in_run = 1;
610				} else {
611					extend_tile_hint( x * tile_x + tx,
612					    y * tile_y + ty, tw, th, &hint);
613				}
614			} else {
615				if (in_run) {
616					/* end of a row run of altered tiles: */
617					save_hint(hint, hint_count++);
618					in_run = 0;
619				}
620			}
621		}
622		if (in_run) {	/* save the last row run */
623			save_hint(hint, hint_count++);
624			in_run = 0;
625		}
626	}
627
628	for (i=0; i < hint_count; i++) {
629		/* pass update info to vnc: */
630		mark_hint(hint_list[i]);
631	}
632}
633
634/*
635 * kludge, simple ceil+floor for non-negative doubles:
636 */
637#define CEIL(x)  ( (double) ((int) (x)) == (x) ? \
638	(double) ((int) (x)) : (double) ((int) (x) + 1) )
639#define FLOOR(x) ( (double) ((int) (x)) )
640
641/*
642 * Scaling:
643 *
644 * For shrinking, a destination (scaled) pixel will correspond to more
645 * than one source (i.e. main fb) pixel.  Think of an x-y plane made with
646 * graph paper.  Each unit square in the graph paper (i.e. collection of
647 * points (x,y) such that N < x < N+1 and M < y < M+1, N and M integers)
648 * corresponds to one pixel in the unscaled fb.  There is a solid
649 * color filling the inside of such a square.  A scaled pixel has width
650 * 1/scale_fac, e.g. for "-scale 3/4" the width of the scaled pixel
651 * is 1.333.  The area of this scaled pixel is 1.333 * 1.333 (so it
652 * obviously overlaps more than one source pixel, each which have area 1).
653 *
654 * We take the weight an unscaled pixel (source) contributes to a
655 * scaled pixel (destination) as simply proportional to the overlap area
656 * between the two pixels.  One can then think of the value of the scaled
657 * pixel as an integral over the portion of the graph paper it covers.
658 * The thing being integrated is the color value of the unscaled source.
659 * That color value is constant over a graph paper square (source pixel),
660 * and changes discontinuously from one unit square to the next.
661 *
662
663Here is an example for -scale 3/4, the solid lines are the source pixels
664(graph paper unit squares), while the dotted lines denote the scaled
665pixels (destination pixels):
666
667            0         1 4/3     2     8/3 3         4=12/3
668            |---------|--.------|------.--|---------|.
669            |         |  .      |      .  |         |.
670            |    A    |  . B    |      .  |         |.
671            |         |  .      |      .  |         |.
672            |         |  .      |      .  |         |.
673          1 |---------|--.------|------.--|---------|.
674         4/3|.........|.........|.........|.........|.
675            |         |  .      |      .  |         |.
676            |    C    |  . D    |      .  |         |.
677            |         |  .      |      .  |         |.
678          2 |---------|--.------|------.--|---------|.
679            |         |  .      |      .  |         |.
680            |         |  .      |      .  |         |.
681         8/3|.........|.........|.........|.........|.
682            |         |  .      |      .  |         |.
683          3 |---------|--.------|------.--|---------|.
684
685So we see the first scaled pixel (0 < x < 4/3 and 0 < y < 4/3) mostly
686overlaps with unscaled source pixel "A".  The integration (averaging)
687weights for this scaled pixel are:
688
689			A	 1
690			B	1/3
691			C	1/3
692			D	1/9
693
694 *
695 * The Red, Green, and Blue color values must be averaged over separately
696 * otherwise you can get a complete mess (except in solid regions),
697 * because high order bits are averaged differently from the low order bits.
698 *
699 * So the algorithm is roughly:
700 *
701 *   - Given as input a rectangle in the unscaled source fb with changes,
702 *     find the rectangle of pixels this affects in the scaled destination fb.
703 *
704 *   - For each of the affected scaled (dest) pixels, determine all of the
705 *     unscaled (source) pixels it overlaps with.
706 *
707 *   - Average those unscaled source values together, weighted by the area
708 *     overlap with the destination pixel.  Average R, G, B separately.
709 *
710 *   - Take this average value and convert to a valid pixel value if
711 *     necessary (e.g. rounding, shifting), and then insert it into the
712 *     destination framebuffer as the pixel value.
713 *
714 *   - On to the next destination pixel...
715 *
716 * ========================================================================
717 *
718 * For expanding, e.g. -scale 1.1 (which we don't think people will do
719 * very often... or at least so we hope, the framebuffer can become huge)
720 * the situation is reversed and the destination pixel is smaller than a
721 * "graph paper" unit square (source pixel).  Some destination pixels
722 * will be completely within a single unscaled source pixel.
723 *
724 * What we do here is a simple 4 point interpolation scheme:
725 *
726 * Let P00 be the source pixel closest to the destination pixel but with
727 * x and y values less than or equal to those of the destination pixel.
728 * (for simplicity, think of the upper left corner of a pixel defining the
729 * x,y location of the pixel, the center would work just as well).  So it
730 * is the source pixel immediately to the upper left of the destination
731 * pixel.  Let P10 be the source pixel one to the right of P00.  Let P01
732 * be one down from P00.  And let P11 be one down and one to the right
733 * of P00.  They form a 2x2 square we will interpolate inside of.
734 *
735 * Let V00, V10, V01, and V11 be the color values of those 4 source
736 * pixels.  Let dx be the displacement along x the destination pixel is
737 * from P00.  Note: 0 <= dx < 1 by definition of P00.  Similarly let
738 * dy be the displacement along y.  The weighted average for the
739 * interpolation is:
740 *
741 * 	V_ave = V00 * (1 - dx) * (1 - dy)
742 * 	      + V10 *      dx  * (1 - dy)
743 * 	      + V01 * (1 - dx) *      dy
744 * 	      + V11 *      dx  *      dy
745 *
746 * Note that the weights (1-dx)*(1-dy) + dx*(1-dy) + (1-dx)*dy + dx*dy
747 * automatically add up to 1.  It is also nice that all the weights are
748 * positive (unsigned char stays unsigned char).  The above formula can
749 * be motivated by doing two 1D interpolations along x:
750 *
751 * 	VA = V00 * (1 - dx) + V10 * dx
752 * 	VB = V01 * (1 - dx) + V11 * dx
753 *
754 * and then interpolating VA and VB along y:
755 *
756 * 	V_ave = VA * (1 - dy) + VB * dy
757 *
758 *                      VA
759 *           v   |<-dx->|
760 *           -- V00 ------ V10
761 *           dy  |          |
762 *           --  |      o...|...    "o" denotes the position of the desired
763 *           ^   |      .   |  .    destination pixel relative to the P00
764 *               |      .   |  .    source pixel.
765 *              V10 ----.- V11 .
766 *                      ........
767 *                      |
768 *                      VB
769 *
770 *
771 * Of course R, G, B averages are done separately as in the shrinking
772 * case.  This gives reasonable results, and the implementation for
773 * shrinking can simply be used with different choices for weights for
774 * the loop over the 4 pixels.
775 */
776
777void scale_rect(double factor_x, double factor_y, int blend, int interpolate, int Bpp,
778    char *src_fb, int src_bytes_per_line, char *dst_fb, int dst_bytes_per_line,
779    int Nx, int Ny, int nx, int ny, int X1, int Y1, int X2, int Y2, int mark) {
780/*
781 * Notation:
782 * "i" an x pixel index in the destination (scaled) framebuffer
783 * "j" a  y pixel index in the destination (scaled) framebuffer
784 * "I" an x pixel index in the source (un-scaled, i.e. main) framebuffer
785 * "J" a  y pixel index in the source (un-scaled, i.e. main) framebuffer
786 *
787 *  Similarly for nx, ny, Nx, Ny, etc.  Lowercase: dest, Uppercase: source.
788 */
789	int i, j, i1, i2, j1, j2;	/* indices for scaled fb (dest) */
790	int I, J, I1, I2, J1, J2;	/* indices for main fb   (source) */
791
792	double w, wx, wy, wtot;	/* pixel weights */
793
794	double x1, y1, x2, y2;	/* x-y coords for destination pixels edges */
795	double dx, dy;		/* size of destination pixel */
796	double ddx=0, ddy=0;	/* for interpolation expansion */
797
798	char *src, *dest;	/* pointers to the two framebuffers */
799
800
801	unsigned short us = 0;
802	unsigned char  uc = 0;
803	unsigned int   ui = 0;
804
805	int use_noblend_shortcut = 1;
806	int shrink;		/* whether shrinking or expanding */
807	static int constant_weights = -1, mag_int = -1;
808	static int last_Nx = -1, last_Ny = -1, cnt = 0;
809	static double last_factor = -1.0;
810	int b, k;
811	double pixave[4];	/* for averaging pixel values */
812
813	if (factor_x <= 1.0 && factor_y <= 1.0) {
814		shrink = 1;
815	} else {
816		shrink = 0;
817	}
818
819	/*
820	 * N.B. width and height (real numbers) of a scaled pixel.
821	 * both are > 1   (e.g. 1.333 for -scale 3/4)
822	 * they should also be equal but we don't assume it.
823	 *
824	 * This new way is probably the best we can do, take the inverse
825	 * of the scaling factor to double precision.
826	 */
827	dx = 1.0/factor_x;
828	dy = 1.0/factor_y;
829
830	/*
831	 * There is some speedup if the pixel weights are constant, so
832	 * let's special case these.
833	 *
834	 * If scale = 1/n and n divides Nx and Ny, the pixel weights
835	 * are constant (e.g. 1/2 => equal on 2x2 square).
836	 */
837	if (factor_x != last_factor || Nx != last_Nx || Ny != last_Ny) {
838		constant_weights = -1;
839		mag_int = -1;
840		last_Nx = Nx;
841		last_Ny = Ny;
842		last_factor = factor_x;
843	}
844	if (constant_weights < 0 && factor_x != factor_y) {
845		constant_weights = 0;
846		mag_int = 0;
847
848	} else if (constant_weights < 0) {
849		int n = 0;
850
851		constant_weights = 0;
852		mag_int = 0;
853
854		for (i = 2; i<=128; i++) {
855			double test = ((double) 1)/ i;
856			double diff, eps = 1.0e-7;
857			diff = factor_x - test;
858			if (-eps < diff && diff < eps) {
859				n = i;
860				break;
861			}
862		}
863		if (! blend || ! shrink || interpolate) {
864			;
865		} else if (n != 0) {
866			if (Nx % n == 0 && Ny % n == 0) {
867				static int didmsg = 0;
868				if (mark && ! didmsg) {
869					didmsg = 1;
870					rfbLog("scale_and_mark_rect: using "
871					    "constant pixel weight speedup "
872					    "for 1/%d\n", n);
873				}
874				constant_weights = 1;
875			}
876		}
877
878		n = 0;
879		for (i = 2; i<=32; i++) {
880			double test = (double) i;
881			double diff, eps = 1.0e-7;
882			diff = factor_x - test;
883			if (-eps < diff && diff < eps) {
884				n = i;
885				break;
886			}
887		}
888		if (! blend && factor_x > 1.0 && n) {
889			mag_int = n;
890		}
891	}
892
893	if (mark && factor_x > 1.0 && blend) {
894		/*
895		 * kludge: correct for interpolating blurring leaking
896		 * up or left 1 destination pixel.
897		 */
898		if (X1 > 0) X1--;
899		if (Y1 > 0) Y1--;
900	}
901
902	/*
903	 * find the extent of the change the input rectangle induces in
904	 * the scaled framebuffer.
905	 */
906
907	/* Left edges: find largest i such that i * dx <= X1  */
908	i1 = FLOOR(X1/dx);
909
910	/* Right edges: find smallest i such that (i+1) * dx >= X2+1  */
911	i2 = CEIL( (X2+1)/dx ) - 1;
912
913	/* To be safe, correct any overflows: */
914	i1 = nfix(i1, nx);
915	i2 = nfix(i2, nx) + 1;	/* add 1 to make a rectangle upper boundary */
916
917	/* Repeat above for y direction: */
918	j1 = FLOOR(Y1/dy);
919	j2 = CEIL( (Y2+1)/dy ) - 1;
920
921	j1 = nfix(j1, ny);
922	j2 = nfix(j2, ny) + 1;
923
924	/*
925	 * special case integer magnification with no blending.
926	 * vision impaired magnification usage is interested in this case.
927	 */
928	if (mark && ! blend && mag_int && Bpp != 3) {
929		int jmin, jmax, imin, imax;
930
931		/* outer loop over *source* pixels */
932		for (J=Y1; J < Y2; J++) {
933		    jmin = J * mag_int;
934		    jmax = jmin + mag_int;
935		    for (I=X1; I < X2; I++) {
936			/* extract value */
937			src = src_fb + J*src_bytes_per_line + I*Bpp;
938			if (Bpp == 4) {
939				ui = *((unsigned int *)src);
940			} else if (Bpp == 2) {
941				us = *((unsigned short *)src);
942			} else if (Bpp == 1) {
943				uc = *((unsigned char *)src);
944			}
945			imin = I * mag_int;
946			imax = imin + mag_int;
947			/* inner loop over *dest* pixels */
948			for (j=jmin; j<jmax; j++) {
949			    dest = dst_fb + j*dst_bytes_per_line + imin*Bpp;
950			    for (i=imin; i<imax; i++) {
951				if (Bpp == 4) {
952					*((unsigned int *)dest) = ui;
953				} else if (Bpp == 2) {
954					*((unsigned short *)dest) = us;
955				} else if (Bpp == 1) {
956					*((unsigned char *)dest) = uc;
957				}
958				dest += Bpp;
959			    }
960			}
961		    }
962		}
963		goto markit;
964	}
965
966	/* set these all to 1.0 to begin with */
967	wx = 1.0;
968	wy = 1.0;
969	w  = 1.0;
970
971	/*
972	 * Loop over destination pixels in scaled fb:
973	 */
974	for (j=j1; j<j2; j++) {
975		y1 =  j * dy;	/* top edge */
976		if (y1 > Ny - 1) {
977			/* can go over with dy = 1/scale_fac */
978			y1 = Ny - 1;
979		}
980		y2 = y1 + dy;	/* bottom edge */
981
982		/* Find main fb indices covered by this dest pixel: */
983		J1 = (int) FLOOR(y1);
984		J1 = nfix(J1, Ny);
985
986		if (shrink && ! interpolate) {
987			J2 = (int) CEIL(y2) - 1;
988			J2 = nfix(J2, Ny);
989		} else {
990			J2 = J1 + 1;	/* simple interpolation */
991			ddy = y1 - J1;
992		}
993
994		/* destination char* pointer: */
995		dest = dst_fb + j*dst_bytes_per_line + i1*Bpp;
996
997		for (i=i1; i<i2; i++) {
998
999			x1 =  i * dx;	/* left edge */
1000			if (x1 > Nx - 1) {
1001				/* can go over with dx = 1/scale_fac */
1002				x1 = Nx - 1;
1003			}
1004			x2 = x1 + dx;	/* right edge */
1005
1006			cnt++;
1007
1008			/* Find main fb indices covered by this dest pixel: */
1009			I1 = (int) FLOOR(x1);
1010			if (I1 >= Nx) I1 = Nx - 1;
1011
1012			if (! blend && use_noblend_shortcut) {
1013				/*
1014				 * The noblend case involves no weights,
1015				 * and 1 pixel, so just copy the value
1016				 * directly.
1017				 */
1018				src = src_fb + J1*src_bytes_per_line + I1*Bpp;
1019				if (Bpp == 4) {
1020					*((unsigned int *)dest)
1021					    = *((unsigned int *)src);
1022				} else if (Bpp == 2) {
1023					*((unsigned short *)dest)
1024					    = *((unsigned short *)src);
1025				} else if (Bpp == 1) {
1026					*(dest) = *(src);
1027				} else if (Bpp == 3) {
1028					/* rare case */
1029					for (k=0; k<=2; k++) {
1030						*(dest+k) = *(src+k);
1031					}
1032				}
1033				dest += Bpp;
1034				continue;
1035			}
1036
1037			if (shrink && ! interpolate) {
1038				I2 = (int) CEIL(x2) - 1;
1039				if (I2 >= Nx) I2 = Nx - 1;
1040			} else {
1041				I2 = I1 + 1;	/* simple interpolation */
1042				ddx = x1 - I1;
1043			}
1044
1045			/* Zero out accumulators for next pixel average: */
1046			for (b=0; b<4; b++) {
1047				pixave[b] = 0.0; /* for RGB weighted sums */
1048			}
1049
1050			/*
1051			 * wtot is for accumulating the total weight.
1052			 * It should always sum to 1/(scale_fac * scale_fac).
1053			 */
1054			wtot = 0.0;
1055
1056			/*
1057			 * Loop over source pixels covered by this dest pixel.
1058			 *
1059			 * These "extra" loops over "J" and "I" make
1060			 * the cache/cacheline performance unclear.
1061			 * For example, will the data brought in from
1062			 * src for j, i, and J=0 still be in the cache
1063			 * after the J > 0 data have been accessed and
1064			 * we are at j, i+1, J=0?  The stride in J is
1065			 * main_bytes_per_line, and so ~4 KB.
1066			 *
1067			 * Typical case when shrinking are 2x2 loop, so
1068			 * just two lines to worry about.
1069			 */
1070			for (J=J1; J<=J2; J++) {
1071			    /* see comments for I, x1, x2, etc. below */
1072			    if (constant_weights) {
1073				;
1074			    } else if (! blend) {
1075				if (J != J1) {
1076					continue;
1077				}
1078				wy = 1.0;
1079
1080				/* interpolation scheme: */
1081			    } else if (! shrink || interpolate) {
1082				if (J >= Ny) {
1083					continue;
1084				} else if (J == J1) {
1085					wy = 1.0 - ddy;
1086				} else if (J != J1) {
1087					wy = ddy;
1088				}
1089
1090				/* integration scheme: */
1091			    } else if (J < y1) {
1092				wy = J+1 - y1;
1093			    } else if (J+1 > y2) {
1094				wy = y2 - J;
1095			    } else {
1096				wy = 1.0;
1097			    }
1098
1099			    src = src_fb + J*src_bytes_per_line + I1*Bpp;
1100
1101			    for (I=I1; I<=I2; I++) {
1102
1103				/* Work out the weight: */
1104
1105				if (constant_weights) {
1106					;
1107				} else if (! blend) {
1108					/*
1109					 * Ugh, PseudoColor colormap is
1110					 * bad news, to avoid random
1111					 * colors just take the first
1112					 * pixel.  Or user may have
1113					 * specified :nb to fraction.
1114					 * The :fb will force blending
1115					 * for this case.
1116					 */
1117					if (I != I1) {
1118						continue;
1119					}
1120					wx = 1.0;
1121
1122					/* interpolation scheme: */
1123				} else if (! shrink || interpolate) {
1124					if (I >= Nx) {
1125						continue;	/* off edge */
1126					} else if (I == I1) {
1127						wx = 1.0 - ddx;
1128					} else if (I != I1) {
1129						wx = ddx;
1130					}
1131
1132					/* integration scheme: */
1133				} else if (I < x1) {
1134					/*
1135					 * source left edge (I) to the
1136					 * left of dest left edge (x1):
1137					 * fractional weight
1138					 */
1139					wx = I+1 - x1;
1140				} else if (I+1 > x2) {
1141					/*
1142					 * source right edge (I+1) to the
1143					 * right of dest right edge (x2):
1144					 * fractional weight
1145					 */
1146					wx = x2 - I;
1147				} else {
1148					/*
1149					 * source edges (I and I+1) completely
1150					 * inside dest edges (x1 and x2):
1151					 * full weight
1152					 */
1153					wx = 1.0;
1154				}
1155
1156				w = wx * wy;
1157				wtot += w;
1158
1159				/*
1160				 * We average the unsigned char value
1161				 * instead of char value: otherwise
1162				 * the minimum (char 0) is right next
1163				 * to the maximum (char -1)!  This way
1164				 * they are spread between 0 and 255.
1165				 */
1166				if (Bpp == 4) {
1167					/* unroll the loops, can give 20% */
1168					pixave[0] += w * ((unsigned char) *(src  ));
1169					pixave[1] += w * ((unsigned char) *(src+1));
1170					pixave[2] += w * ((unsigned char) *(src+2));
1171					pixave[3] += w * ((unsigned char) *(src+3));
1172				} else if (Bpp == 2) {
1173					/*
1174					 * 16bpp: trickier with green
1175					 * split over two bytes, so we
1176					 * use the masks:
1177					 */
1178					us = *((unsigned short *) src);
1179					pixave[0] += w*(us & main_red_mask);
1180					pixave[1] += w*(us & main_green_mask);
1181					pixave[2] += w*(us & main_blue_mask);
1182				} else if (Bpp == 1) {
1183					pixave[0] += w *
1184					    ((unsigned char) *(src));
1185				} else {
1186					for (b=0; b<Bpp; b++) {
1187						pixave[b] += w *
1188						    ((unsigned char) *(src+b));
1189					}
1190				}
1191				src += Bpp;
1192			    }
1193			}
1194
1195			if (wtot <= 0.0) {
1196				wtot = 1.0;
1197			}
1198			wtot = 1.0/wtot;	/* normalization factor */
1199
1200			/* place weighted average pixel in the scaled fb: */
1201			if (Bpp == 4) {
1202				*(dest  ) = (char) (wtot * pixave[0]);
1203				*(dest+1) = (char) (wtot * pixave[1]);
1204				*(dest+2) = (char) (wtot * pixave[2]);
1205				*(dest+3) = (char) (wtot * pixave[3]);
1206			} else if (Bpp == 2) {
1207				/* 16bpp / 565 case: */
1208				pixave[0] *= wtot;
1209				pixave[1] *= wtot;
1210				pixave[2] *= wtot;
1211				us =  (main_red_mask   & (int) pixave[0])
1212				    | (main_green_mask & (int) pixave[1])
1213				    | (main_blue_mask  & (int) pixave[2]);
1214				*( (unsigned short *) dest ) = us;
1215			} else if (Bpp == 1) {
1216				*(dest) = (char) (wtot * pixave[0]);
1217			} else {
1218				for (b=0; b<Bpp; b++) {
1219					*(dest+b) = (char) (wtot * pixave[b]);
1220				}
1221			}
1222			dest += Bpp;
1223		}
1224	}
1225	markit:
1226	if (mark) {
1227		mark_rect_as_modified(i1, j1, i2, j2, 1);
1228	}
1229}
1230
1231/*
1232 Framebuffers data flow:
1233
1234 General case:
1235                --------       --------       --------        --------
1236    -----      |8to24_fb|     |main_fb |     |snap_fb |      | X      |
1237   |rfbfb| <== |        | <== |        | <== |        | <==  | Server |
1238    -----       --------       --------       --------        --------
1239   (to vnc)    (optional)    (usu = rfbfb)   (optional)      (read only)
1240
1241 8to24_fb mode will create side fbs: poll24_fb and poll8_fb for
1242 bookkeepping the different regions (merged into 8to24_fb).
1243
1244 Normal case:
1245    --------        --------
1246   |main_fb |      | X      |
1247   |= rfb_fb| <==  | Server |
1248    --------        --------
1249
1250 Scaling case:
1251                --------        --------
1252    -----      |main_fb |      | X      |
1253   |rfbfb| <== |        | <==  | Server |
1254    -----       --------        --------
1255
1256 Webcam/video case:
1257    --------        --------        --------
1258   |main_fb |      |snap_fb |      | Video  |
1259   |        | <==  |        | <==  | device |
1260    --------        --------        --------
1261
1262If we ever do a -rr rotation/reflection tran, it probably should
1263be done after any scaling (need a rr_fb for intermediate results)
1264
1265-rr option:		transformation:
1266
1267	none		x -> x;
1268			y -> y;
1269
1270	x		x -> w - x - 1;
1271			y -> y;
1272
1273	y		x -> x;
1274			x -> h - y - 1;
1275
1276	xy		x -> w - x - 1;
1277			y -> h - y - 1;
1278
1279	+90		x -> h - y - 1;
1280			y -> x;
1281
1282	+90x		x -> y;
1283			y -> x;
1284
1285	+90y		x -> h - y - 1;
1286			y -> w - x - 1;
1287
1288	-90		x -> y;
1289			y -> w - x - 1;
1290
1291some aliases:
1292
1293	xy:	yx, +180, -180, 180
1294	+90:	90
1295	+90x:	90x
1296	+90y:	90y
1297	-90:	+270, 270
1298 */
1299
1300void scale_and_mark_rect(int X1, int Y1, int X2, int Y2, int mark) {
1301	char *dst_fb, *src_fb = main_fb;
1302	int dst_bpl, Bpp = bpp/8, fac = 1;
1303
1304	if (!screen || !rfb_fb || !main_fb) {
1305		return;
1306	}
1307	if (! screen->serverFormat.trueColour) {
1308		/*
1309		 * PseudoColor colormap... blending leads to random colors.
1310		 * User can override with ":fb"
1311		 */
1312		if (scaling_blend == 1) {
1313			/* :fb option sets it to 2 */
1314			if (default_visual->class == StaticGray) {
1315				/*
1316				 * StaticGray can be blended OK, otherwise
1317				 * user can disable with :nb
1318				 */
1319				;
1320			} else {
1321				scaling_blend = 0;
1322			}
1323		}
1324	}
1325
1326	if (cmap8to24 && cmap8to24_fb) {
1327		src_fb = cmap8to24_fb;
1328		if (scaling) {
1329			if (depth <= 8) {
1330				fac = 4;
1331			} else if (depth <= 16) {
1332				fac = 2;
1333			}
1334		}
1335	}
1336	dst_fb = rfb_fb;
1337	dst_bpl = rfb_bytes_per_line;
1338
1339	scale_rect(scale_fac_x, scale_fac_y, scaling_blend, scaling_interpolate, fac * Bpp,
1340	    src_fb, fac * main_bytes_per_line, dst_fb, dst_bpl, dpy_x, dpy_y,
1341	    scaled_x, scaled_y, X1, Y1, X2, Y2, mark);
1342}
1343
1344void rotate_coords(int x, int y, int *xo, int *yo, int dxi, int dyi) {
1345	int xi = x, yi = y;
1346	int Dx, Dy;
1347
1348	if (dxi >= 0) {
1349		Dx = dxi;
1350		Dy = dyi;
1351	} else if (scaling) {
1352		Dx = scaled_x;
1353		Dy = scaled_y;
1354	} else {
1355		Dx = dpy_x;
1356		Dy = dpy_y;
1357	}
1358
1359	/* ncache?? */
1360
1361	if (rotating == ROTATE_NONE) {
1362		*xo = xi;
1363		*yo = yi;
1364	} else if (rotating == ROTATE_X) {
1365		*xo = Dx - xi - 1;
1366		*yo = yi;
1367	} else if (rotating == ROTATE_Y) {
1368		*xo = xi;
1369		*yo = Dy - yi - 1;
1370	} else if (rotating == ROTATE_XY) {
1371		*xo = Dx - xi - 1;
1372		*yo = Dy - yi - 1;
1373	} else if (rotating == ROTATE_90) {
1374		*xo = Dy - yi - 1;
1375		*yo = xi;
1376	} else if (rotating == ROTATE_90X) {
1377		*xo = yi;
1378		*yo = xi;
1379	} else if (rotating == ROTATE_90Y) {
1380		*xo = Dy - yi - 1;
1381		*yo = Dx - xi - 1;
1382	} else if (rotating == ROTATE_270) {
1383		*xo = yi;
1384		*yo = Dx - xi - 1;
1385	}
1386}
1387
1388void rotate_coords_inverse(int x, int y, int *xo, int *yo, int dxi, int dyi) {
1389	int xi = x, yi = y;
1390
1391	int Dx, Dy;
1392
1393	if (dxi >= 0) {
1394		Dx = dxi;
1395		Dy = dyi;
1396	} else if (scaling) {
1397		Dx = scaled_x;
1398		Dy = scaled_y;
1399	} else {
1400		Dx = dpy_x;
1401		Dy = dpy_y;
1402	}
1403	if (! rotating_same) {
1404		int t = Dx;
1405		Dx = Dy;
1406		Dy = t;
1407	}
1408
1409	if (rotating == ROTATE_NONE) {
1410		*xo = xi;
1411		*yo = yi;
1412	} else if (rotating == ROTATE_X) {
1413		*xo = Dx - xi - 1;
1414		*yo = yi;
1415	} else if (rotating == ROTATE_Y) {
1416		*xo = xi;
1417		*yo = Dy - yi - 1;
1418	} else if (rotating == ROTATE_XY) {
1419		*xo = Dx - xi - 1;
1420		*yo = Dy - yi - 1;
1421	} else if (rotating == ROTATE_90) {
1422		*xo = yi;
1423		*yo = Dx - xi - 1;
1424	} else if (rotating == ROTATE_90X) {
1425		*xo = yi;
1426		*yo = xi;
1427	} else if (rotating == ROTATE_90Y) {
1428		*xo = Dy - yi - 1;
1429		*yo = Dx - xi - 1;
1430	} else if (rotating == ROTATE_270) {
1431		*xo = Dy - yi - 1;
1432		*yo = xi;
1433	}
1434}
1435
1436	/* unroll the Bpp loop to be used in each case: */
1437#define ROT_COPY \
1438	src = src_0 + fbl*y  + Bpp*x;  \
1439	dst = dst_0 + rbl*yn + Bpp*xn; \
1440	if (Bpp == 1) { \
1441		*(dst) = *(src);	 \
1442	} else if (Bpp == 2) { \
1443		*(dst+0) = *(src+0);	 \
1444		*(dst+1) = *(src+1);	 \
1445	} else if (Bpp == 3) { \
1446		*(dst+0) = *(src+0);	 \
1447		*(dst+1) = *(src+1);	 \
1448		*(dst+2) = *(src+2);	 \
1449	} else if (Bpp == 4) { \
1450		*(dst+0) = *(src+0);	 \
1451		*(dst+1) = *(src+1);	 \
1452		*(dst+2) = *(src+2);	 \
1453		*(dst+3) = *(src+3);	 \
1454	}
1455
1456void rotate_fb(int x1, int y1, int x2, int y2) {
1457	int x, y, xn, yn, r_x1, r_y1, r_x2, r_y2, Bpp = bpp/8;
1458	int fbl = rfb_bytes_per_line;
1459	int rbl = rot_bytes_per_line;
1460	int Dx, Dy;
1461	char *src, *dst;
1462	char *src_0 = rfb_fb;
1463	char *dst_0 = rot_fb;
1464
1465	if (! rotating || ! rot_fb) {
1466		return;
1467	}
1468
1469	if (scaling) {
1470		Dx = scaled_x;
1471		Dy = scaled_y;
1472	} else {
1473		Dx = dpy_x;
1474		Dy = dpy_y;
1475	}
1476	rotate_coords(x1, y1, &r_x1, &r_y1, -1, -1);
1477	rotate_coords(x2, y2, &r_x2, &r_y2, -1, -1);
1478
1479	dst = rot_fb;
1480
1481	if (rotating == ROTATE_X) {
1482		for (y = y1; y < y2; y++)  {
1483			for (x = x1; x < x2; x++)  {
1484				xn = Dx - x - 1;
1485				yn = y;
1486				ROT_COPY
1487			}
1488		}
1489	} else if (rotating == ROTATE_Y) {
1490		for (y = y1; y < y2; y++)  {
1491			for (x = x1; x < x2; x++)  {
1492				xn = x;
1493				yn = Dy - y - 1;
1494				ROT_COPY
1495			}
1496		}
1497	} else if (rotating == ROTATE_XY) {
1498		for (y = y1; y < y2; y++)  {
1499			for (x = x1; x < x2; x++)  {
1500				xn = Dx - x - 1;
1501				yn = Dy - y - 1;
1502				ROT_COPY
1503			}
1504		}
1505	} else if (rotating == ROTATE_90) {
1506		for (y = y1; y < y2; y++)  {
1507			for (x = x1; x < x2; x++)  {
1508				xn = Dy - y - 1;
1509				yn = x;
1510				ROT_COPY
1511			}
1512		}
1513	} else if (rotating == ROTATE_90X) {
1514		for (y = y1; y < y2; y++)  {
1515			for (x = x1; x < x2; x++)  {
1516				xn = y;
1517				yn = x;
1518				ROT_COPY
1519			}
1520		}
1521	} else if (rotating == ROTATE_90Y) {
1522		for (y = y1; y < y2; y++)  {
1523			for (x = x1; x < x2; x++)  {
1524				xn = Dy - y - 1;
1525				yn = Dx - x - 1;
1526				ROT_COPY
1527			}
1528		}
1529	} else if (rotating == ROTATE_270) {
1530		for (y = y1; y < y2; y++)  {
1531			for (x = x1; x < x2; x++)  {
1532				xn = y;
1533				yn = Dx - x - 1;
1534				ROT_COPY
1535			}
1536		}
1537	}
1538}
1539
1540void rotate_curs(char *dst_0, char *src_0, int Dx, int Dy, int Bpp) {
1541	int x, y, xn, yn;
1542	char *src, *dst;
1543	int fbl, rbl;
1544
1545	if (! rotating) {
1546		return;
1547	}
1548
1549	fbl = Dx * Bpp;
1550	if (rotating_same) {
1551		rbl = Dx * Bpp;
1552	} else {
1553		rbl = Dy * Bpp;
1554	}
1555
1556	if (rotating == ROTATE_X) {
1557		for (y = 0; y < Dy; y++)  {
1558			for (x = 0; x < Dx; x++)  {
1559				xn = Dx - x - 1;
1560				yn = y;
1561				ROT_COPY
1562if (0) fprintf(stderr, "rcurs: %d %d  %d %d\n", x, y, xn, yn);
1563			}
1564		}
1565	} else if (rotating == ROTATE_Y) {
1566		for (y = 0; y < Dy; y++)  {
1567			for (x = 0; x < Dx; x++)  {
1568				xn = x;
1569				yn = Dy - y - 1;
1570				ROT_COPY
1571			}
1572		}
1573	} else if (rotating == ROTATE_XY) {
1574		for (y = 0; y < Dy; y++)  {
1575			for (x = 0; x < Dx; x++)  {
1576				xn = Dx - x - 1;
1577				yn = Dy - y - 1;
1578				ROT_COPY
1579			}
1580		}
1581	} else if (rotating == ROTATE_90) {
1582		for (y = 0; y < Dy; y++)  {
1583			for (x = 0; x < Dx; x++)  {
1584				xn = Dy - y - 1;
1585				yn = x;
1586				ROT_COPY
1587			}
1588		}
1589	} else if (rotating == ROTATE_90X) {
1590		for (y = 0; y < Dy; y++)  {
1591			for (x = 0; x < Dx; x++)  {
1592				xn = y;
1593				yn = x;
1594				ROT_COPY
1595			}
1596		}
1597	} else if (rotating == ROTATE_90Y) {
1598		for (y = 0; y < Dy; y++)  {
1599			for (x = 0; x < Dx; x++)  {
1600				xn = Dy - y - 1;
1601				yn = Dx - x - 1;
1602				ROT_COPY
1603			}
1604		}
1605	} else if (rotating == ROTATE_270) {
1606		for (y = 0; y < Dy; y++)  {
1607			for (x = 0; x < Dx; x++)  {
1608				xn = y;
1609				yn = Dx - x - 1;
1610				ROT_COPY
1611			}
1612		}
1613	}
1614}
1615
1616void mark_wrapper(int x1, int y1, int x2, int y2) {
1617	int t, r_x1 = x1, r_y1 = y1, r_x2 = x2, r_y2 = y2;
1618
1619	if (rotating) {
1620		/* well we hope rot_fb will always be the last one... */
1621		rotate_coords(x1, y1, &r_x1, &r_y1, -1, -1);
1622		rotate_coords(x2, y2, &r_x2, &r_y2, -1, -1);
1623		rotate_fb(x1, y1, x2, y2);
1624		if (r_x1 > r_x2) {
1625			t = r_x1;
1626			r_x1 = r_x2;
1627			r_x2 = t;
1628		}
1629		if (r_y1 > r_y2) {
1630			t = r_y1;
1631			r_y1 = r_y2;
1632			r_y2 = t;
1633		}
1634		/* painting errors  */
1635		r_x1--;
1636		r_x2++;
1637		r_y1--;
1638		r_y2++;
1639	}
1640	rfbMarkRectAsModified(screen, r_x1, r_y1, r_x2, r_y2);
1641}
1642
1643void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force) {
1644
1645	if (damage_time != 0) {
1646		/*
1647		 * This is not XDAMAGE, rather a hack for testing
1648		 * where we allow the framebuffer to be corrupted for
1649		 * damage_delay seconds.
1650		 */
1651		int debug = 0;
1652		if (time(NULL) > damage_time + damage_delay) {
1653			if (! quiet) {
1654				rfbLog("damaging turned off.\n");
1655			}
1656			damage_time = 0;
1657			damage_delay = 0;
1658		} else {
1659			if (debug) {
1660				rfbLog("damaging viewer fb by not marking "
1661				    "rect: %d,%d,%d,%d\n", x1, y1, x2, y2);
1662			}
1663			return;
1664		}
1665	}
1666
1667
1668	if (rfb_fb == main_fb || force) {
1669		mark_wrapper(x1, y1, x2, y2);
1670		return;
1671	}
1672
1673	if (cmap8to24) {
1674		bpp8to24(x1, y1, x2, y2);
1675	}
1676
1677	if (scaling) {
1678		scale_and_mark_rect(x1, y1, x2, y2, 1);
1679	} else {
1680		mark_wrapper(x1, y1, x2, y2);
1681	}
1682}
1683
1684/*
1685 * Notifies libvncserver of a changed hint rectangle.
1686 */
1687static void mark_hint(hint_t hint) {
1688	int x = hint.x;
1689	int y = hint.y;
1690	int w = hint.w;
1691	int h = hint.h;
1692
1693	mark_rect_as_modified(x, y, x + w, y + h, 0);
1694}
1695
1696/*
1697 * copy_tiles() gives a slight improvement over copy_tile() since
1698 * adjacent runs of tiles are done all at once there is some savings
1699 * due to contiguous memory access.  Not a great speedup, but in some
1700 * cases it can be up to 2X.  Even more on a SunRay or ShadowFB where
1701 * no graphics hardware is involved in the read.  Generally, graphics
1702 * devices are optimized for write, not read, so we are limited by the
1703 * read bandwidth, sometimes only 5 MB/sec on otherwise fast hardware.
1704 */
1705static int *first_line = NULL, *last_line = NULL;
1706static unsigned short *left_diff = NULL, *right_diff = NULL;
1707
1708static int copy_tiles(int tx, int ty, int nt) {
1709	int x, y, line;
1710	int size_x, size_y, width1, width2;
1711	int off, len, n, dw, dx, t;
1712	int w1, w2, dx1, dx2;	/* tmps for normal and short tiles */
1713	int pixelsize = bpp/8;
1714	int first_min, last_max;
1715	int first_x = -1, last_x = -1;
1716	static int prev_ntiles_x = -1;
1717
1718	char *src, *dst, *s_src, *s_dst, *m_src, *m_dst;
1719	char *h_src, *h_dst;
1720	if (unixpw_in_progress) return 0;
1721
1722	if (ntiles_x != prev_ntiles_x && first_line != NULL) {
1723		free(first_line);	first_line = NULL;
1724		free(last_line);	last_line = NULL;
1725		free(left_diff);	left_diff = NULL;
1726		free(right_diff);	right_diff = NULL;
1727	}
1728
1729	if (first_line == NULL) {
1730		/* allocate arrays first time in. */
1731		int n = ntiles_x + 1;
1732		rfbLog("copy_tiles: allocating first_line at size %d\n", n);
1733		first_line = (int *) malloc((size_t) (n * sizeof(int)));
1734		last_line  = (int *) malloc((size_t) (n * sizeof(int)));
1735		left_diff  = (unsigned short *)
1736			malloc((size_t) (n * sizeof(unsigned short)));
1737		right_diff = (unsigned short *)
1738			malloc((size_t) (n * sizeof(unsigned short)));
1739	}
1740	prev_ntiles_x = ntiles_x;
1741
1742	x = tx * tile_x;
1743	y = ty * tile_y;
1744
1745	size_x = dpy_x - x;
1746	if ( size_x > tile_x * nt ) {
1747		size_x = tile_x * nt;
1748		width1 = tile_x;
1749		width2 = tile_x;
1750	} else {
1751		/* short tile */
1752		width1 = tile_x;	/* internal tile */
1753		width2 = size_x - (nt - 1) * tile_x;	/* right hand tile */
1754	}
1755
1756	size_y = dpy_y - y;
1757	if ( size_y > tile_y ) {
1758		size_y = tile_y;
1759	}
1760
1761	n = tx + ty * ntiles_x;		/* number of the first tile */
1762
1763	if (blackouts && tile_blackout[n].cover == 2) {
1764		/*
1765		 * If there are blackouts and this tile is completely covered
1766		 * no need to poll screen or do anything else..
1767		 * n.b. we are in single copy_tile mode: nt=1
1768		 */
1769		tile_has_diff[n] = 0;
1770		return(0);
1771	}
1772
1773	X_LOCK;
1774	XRANDR_SET_TRAP_RET(-1, "copy_tile-set");
1775	/* read in the whole tile run at once: */
1776	copy_image(tile_row[nt], x, y, size_x, size_y);
1777	XRANDR_CHK_TRAP_RET(-1, "copy_tile-chk");
1778
1779
1780	X_UNLOCK;
1781
1782	if (blackouts && tile_blackout[n].cover == 1) {
1783		/*
1784		 * If there are blackouts and this tile is partially covered
1785		 * we should re-black-out the portion.
1786		 * n.b. we are in single copy_tile mode: nt=1
1787		 */
1788		int x1, x2, y1, y2, b;
1789		int w, s, fill = 0;
1790
1791		for (b=0; b < tile_blackout[n].count; b++) {
1792			char *b_dst = tile_row[nt]->data;
1793
1794			x1 = tile_blackout[n].bo[b].x1 - x;
1795			y1 = tile_blackout[n].bo[b].y1 - y;
1796			x2 = tile_blackout[n].bo[b].x2 - x;
1797			y2 = tile_blackout[n].bo[b].y2 - y;
1798
1799			w = (x2 - x1) * pixelsize;
1800			s = x1 * pixelsize;
1801
1802			for (line = 0; line < size_y; line++) {
1803				if (y1 <= line && line < y2) {
1804					memset(b_dst + s, fill, (size_t) w);
1805				}
1806				b_dst += tile_row[nt]->bytes_per_line;
1807			}
1808		}
1809	}
1810
1811	src = tile_row[nt]->data;
1812	dst = main_fb + y * main_bytes_per_line + x * pixelsize;
1813
1814	s_src = src;
1815	s_dst = dst;
1816
1817	for (t=1; t <= nt; t++) {
1818		first_line[t] = -1;
1819	}
1820
1821	/* find the first line with difference: */
1822	w1 = width1 * pixelsize;
1823	w2 = width2 * pixelsize;
1824
1825	/* foreach line: */
1826	for (line = 0; line < size_y; line++) {
1827		/* foreach horizontal tile: */
1828		for (t=1; t <= nt; t++) {
1829			if (first_line[t] != -1) {
1830				continue;
1831			}
1832
1833			off = (t-1) * w1;
1834			if (t == nt) {
1835				len = w2;	/* possible short tile */
1836			} else {
1837				len = w1;
1838			}
1839
1840			if (memcmp(s_dst + off, s_src + off, len)) {
1841				first_line[t] = line;
1842			}
1843		}
1844		s_src += tile_row[nt]->bytes_per_line;
1845		s_dst += main_bytes_per_line;
1846	}
1847
1848	/* see if there were any differences for any tile: */
1849	first_min = -1;
1850	for (t=1; t <= nt; t++) {
1851		tile_tried[n+(t-1)] = 1;
1852		if (first_line[t] != -1) {
1853			if (first_min == -1 || first_line[t] < first_min) {
1854				first_min = first_line[t];
1855			}
1856		}
1857	}
1858	if (first_min == -1) {
1859		/* no tile has a difference, note this and get out: */
1860		for (t=1; t <= nt; t++) {
1861			tile_has_diff[n+(t-1)] = 0;
1862		}
1863		return(0);
1864	} else {
1865		/*
1866		 * at least one tile has a difference.  make sure info
1867		 * is recorded (e.g. sometimes we guess tiles and they
1868		 * came in with tile_has_diff 0)
1869		 */
1870		for (t=1; t <= nt; t++) {
1871			if (first_line[t] == -1) {
1872				tile_has_diff[n+(t-1)] = 0;
1873			} else {
1874				tile_has_diff[n+(t-1)] = 1;
1875			}
1876		}
1877	}
1878
1879	m_src = src + (tile_row[nt]->bytes_per_line * size_y);
1880	m_dst = dst + (main_bytes_per_line * size_y);
1881
1882	for (t=1; t <= nt; t++) {
1883		last_line[t] = first_line[t];
1884	}
1885
1886	/* find the last line with difference: */
1887	w1 = width1 * pixelsize;
1888	w2 = width2 * pixelsize;
1889
1890	/* foreach line: */
1891	for (line = size_y - 1; line > first_min; line--) {
1892
1893		m_src -= tile_row[nt]->bytes_per_line;
1894		m_dst -= main_bytes_per_line;
1895
1896		/* foreach tile: */
1897		for (t=1; t <= nt; t++) {
1898			if (first_line[t] == -1
1899			    || last_line[t] != first_line[t]) {
1900				/* tile has no changes or already done */
1901				continue;
1902			}
1903
1904			off = (t-1) * w1;
1905			if (t == nt) {
1906				len = w2;	/* possible short tile */
1907			} else {
1908				len = w1;
1909			}
1910			if (memcmp(m_dst + off, m_src + off, len)) {
1911				last_line[t] = line;
1912			}
1913		}
1914	}
1915
1916	/*
1917	 * determine the farthest down last changed line
1918	 * will be used below to limit our memcpy() to the framebuffer.
1919	 */
1920	last_max = -1;
1921	for (t=1; t <= nt; t++) {
1922		if (first_line[t] == -1) {
1923			continue;
1924		}
1925		if (last_max == -1 || last_line[t] > last_max) {
1926			last_max = last_line[t];
1927		}
1928	}
1929
1930	/* look for differences on left and right hand edges: */
1931	for (t=1; t <= nt; t++) {
1932		left_diff[t] = 0;
1933		right_diff[t] = 0;
1934	}
1935
1936	h_src = src;
1937	h_dst = dst;
1938
1939	w1 = width1 * pixelsize;
1940	w2 = width2 * pixelsize;
1941
1942	dx1 = (width1 - tile_fuzz) * pixelsize;
1943	dx2 = (width2 - tile_fuzz) * pixelsize;
1944	dw = tile_fuzz * pixelsize;
1945
1946	/* foreach line: */
1947	for (line = 0; line < size_y; line++) {
1948		/* foreach tile: */
1949		for (t=1; t <= nt; t++) {
1950			if (first_line[t] == -1) {
1951				/* tile has no changes at all */
1952				continue;
1953			}
1954
1955			off = (t-1) * w1;
1956			if (t == nt) {
1957				dx = dx2;	/* possible short tile */
1958				if (dx <= 0) {
1959					break;
1960				}
1961			} else {
1962				dx = dx1;
1963			}
1964
1965			if (! left_diff[t] && memcmp(h_dst + off,
1966			    h_src + off, dw)) {
1967				left_diff[t] = 1;
1968			}
1969			if (! right_diff[t] && memcmp(h_dst + off + dx,
1970			    h_src + off + dx, dw) ) {
1971				right_diff[t] = 1;
1972			}
1973		}
1974		h_src += tile_row[nt]->bytes_per_line;
1975		h_dst += main_bytes_per_line;
1976	}
1977
1978	/* now finally copy the difference to the rfb framebuffer: */
1979	s_src = src + tile_row[nt]->bytes_per_line * first_min;
1980	s_dst = dst + main_bytes_per_line * first_min;
1981
1982	for (line = first_min; line <= last_max; line++) {
1983		/* for I/O speed we do not do this tile by tile */
1984		memcpy(s_dst, s_src, size_x * pixelsize);
1985		if (nt == 1) {
1986			/*
1987			 * optimization for tall skinny lines, e.g. wm
1988			 * frame. try to find first_x and last_x to limit
1989			 * the size of the hint.  could help for a slow
1990			 * link.  Unfortunately we spent a lot of time
1991			 * reading in the many tiles.
1992			 *
1993			 * BTW, we like to think the above memcpy leaves
1994			 * the data we use below in the cache... (but
1995			 * it could be two 128 byte segments at 32bpp)
1996			 * so this inner loop is not as bad as it seems.
1997			 */
1998			int k, kx;
1999			kx = pixelsize;
2000			for (k=0; k<size_x; k++) {
2001				if (memcmp(s_dst + k*kx, s_src + k*kx, kx))  {
2002					if (first_x == -1 || k < first_x) {
2003						first_x = k;
2004					}
2005					if (last_x == -1 || k > last_x) {
2006						last_x = k;
2007					}
2008				}
2009			}
2010		}
2011		s_src += tile_row[nt]->bytes_per_line;
2012		s_dst += main_bytes_per_line;
2013	}
2014
2015	/* record all the info in the region array for this tile: */
2016	for (t=1; t <= nt; t++) {
2017		int s = t - 1;
2018
2019		if (first_line[t] == -1) {
2020			/* tile unchanged */
2021			continue;
2022		}
2023		tile_region[n+s].first_line = first_line[t];
2024		tile_region[n+s].last_line  = last_line[t];
2025
2026		tile_region[n+s].first_x = first_x;
2027		tile_region[n+s].last_x  = last_x;
2028
2029		tile_region[n+s].top_diff = 0;
2030		tile_region[n+s].bot_diff = 0;
2031		if ( first_line[t] < tile_fuzz ) {
2032			tile_region[n+s].top_diff = 1;
2033		}
2034		if ( last_line[t] > (size_y - 1) - tile_fuzz ) {
2035			tile_region[n+s].bot_diff = 1;
2036		}
2037
2038		tile_region[n+s].left_diff  = left_diff[t];
2039		tile_region[n+s].right_diff = right_diff[t];
2040
2041		tile_copied[n+s] = 1;
2042	}
2043
2044	return(1);
2045}
2046
2047/*
2048 * The copy_tile() call in the loop below copies the changed tile into
2049 * the rfb framebuffer.  Note that copy_tile() sets the tile_region
2050 * struct to have info about the y-range of the changed region and also
2051 * whether the tile edges contain diffs (within distance tile_fuzz).
2052 *
2053 * We use this tile_region info to try to guess if the downward and right
2054 * tiles will have diffs.  These tiles will be checked later in the loop
2055 * (since y+1 > y and x+1 > x).
2056 *
2057 * See copy_tiles_backward_pass() for analogous checking upward and
2058 * left tiles.
2059 */
2060static int copy_all_tiles(void) {
2061	int x, y, n, m;
2062	int diffs = 0, ct;
2063
2064	if (unixpw_in_progress) return 0;
2065
2066	for (y=0; y < ntiles_y; y++) {
2067		for (x=0; x < ntiles_x; x++) {
2068			n = x + y * ntiles_x;
2069
2070			if (tile_has_diff[n]) {
2071				ct = copy_tiles(x, y, 1);
2072				if (ct < 0) return ct;	/* fatal */
2073			}
2074			if (! tile_has_diff[n]) {
2075				/*
2076				 * n.b. copy_tiles() may have detected
2077				 * no change and reset tile_has_diff to 0.
2078				 */
2079				continue;
2080			}
2081			diffs++;
2082
2083			/* neighboring tile downward: */
2084			if ( (y+1) < ntiles_y && tile_region[n].bot_diff) {
2085				m = x + (y+1) * ntiles_x;
2086				if (! tile_has_diff[m]) {
2087					tile_has_diff[m] = 2;
2088				}
2089			}
2090			/* neighboring tile to right: */
2091			if ( (x+1) < ntiles_x && tile_region[n].right_diff) {
2092				m = (x+1) + y * ntiles_x;
2093				if (! tile_has_diff[m]) {
2094					tile_has_diff[m] = 2;
2095				}
2096			}
2097		}
2098	}
2099	return diffs;
2100}
2101
2102/*
2103 * Routine analogous to copy_all_tiles() above, but for horizontal runs
2104 * of adjacent changed tiles.
2105 */
2106static int copy_all_tile_runs(void) {
2107	int x, y, n, m, i;
2108	int diffs = 0, ct;
2109	int in_run = 0, run = 0;
2110	int ntave = 0, ntcnt = 0;
2111
2112	if (unixpw_in_progress) return 0;
2113
2114	for (y=0; y < ntiles_y; y++) {
2115		for (x=0; x < ntiles_x + 1; x++) {
2116			n = x + y * ntiles_x;
2117
2118			if (x != ntiles_x && tile_has_diff[n]) {
2119				in_run = 1;
2120				run++;
2121			} else {
2122				if (! in_run) {
2123					in_run = 0;
2124					run = 0;
2125					continue;
2126				}
2127				ct = copy_tiles(x - run, y, run);
2128				if (ct < 0) return ct;	/* fatal */
2129
2130				ntcnt++;
2131				ntave += run;
2132				diffs += run;
2133
2134				/* neighboring tile downward: */
2135				for (i=1; i <= run; i++) {
2136					if ((y+1) < ntiles_y
2137					    && tile_region[n-i].bot_diff) {
2138						m = (x-i) + (y+1) * ntiles_x;
2139						if (! tile_has_diff[m]) {
2140							tile_has_diff[m] = 2;
2141						}
2142					}
2143				}
2144
2145				/* neighboring tile to right: */
2146				if (((x-1)+1) < ntiles_x
2147				    && tile_region[n-1].right_diff) {
2148					m = ((x-1)+1) + y * ntiles_x;
2149					if (! tile_has_diff[m]) {
2150						tile_has_diff[m] = 2;
2151					}
2152
2153					/* note that this starts a new run */
2154					in_run = 1;
2155					run = 1;
2156				} else {
2157					in_run = 0;
2158					run = 0;
2159				}
2160			}
2161		}
2162		/*
2163		 * Could some activity go here, to emulate threaded
2164		 * behavior by servicing some libvncserver tasks?
2165		 */
2166	}
2167	return diffs;
2168}
2169
2170/*
2171 * Here starts a bunch of heuristics to guess/detect changed tiles.
2172 * They are:
2173 *   copy_tiles_backward_pass, fill_tile_gaps/gap_try, grow_islands/island_try
2174 */
2175
2176/*
2177 * Try to predict whether the upward and/or leftward tile has been modified.
2178 * copy_all_tiles() has already done downward and rightward tiles.
2179 */
2180static int copy_tiles_backward_pass(void) {
2181	int x, y, n, m;
2182	int diffs = 0, ct;
2183
2184	if (unixpw_in_progress) return 0;
2185
2186	for (y = ntiles_y - 1; y >= 0; y--) {
2187	    for (x = ntiles_x - 1; x >= 0; x--) {
2188		n = x + y * ntiles_x;		/* number of this tile */
2189
2190		if (! tile_has_diff[n]) {
2191			continue;
2192		}
2193
2194		m = x + (y-1) * ntiles_x;	/* neighboring tile upward */
2195
2196		if (y >= 1 && ! tile_has_diff[m] && tile_region[n].top_diff) {
2197			if (! tile_tried[m]) {
2198				tile_has_diff[m] = 2;
2199				ct = copy_tiles(x, y-1, 1);
2200				if (ct < 0) return ct;	/* fatal */
2201			}
2202		}
2203
2204		m = (x-1) + y * ntiles_x;	/* neighboring tile to left */
2205
2206		if (x >= 1 && ! tile_has_diff[m] && tile_region[n].left_diff) {
2207			if (! tile_tried[m]) {
2208				tile_has_diff[m] = 2;
2209				ct = copy_tiles(x-1, y, 1);
2210				if (ct < 0) return ct;	/* fatal */
2211			}
2212		}
2213	    }
2214	}
2215	for (n=0; n < ntiles; n++) {
2216		if (tile_has_diff[n]) {
2217			diffs++;
2218		}
2219	}
2220	return diffs;
2221}
2222
2223static int copy_tiles_additional_pass(void) {
2224	int x, y, n;
2225	int diffs = 0, ct;
2226
2227	if (unixpw_in_progress) return 0;
2228
2229	for (y=0; y < ntiles_y; y++) {
2230		for (x=0; x < ntiles_x; x++) {
2231			n = x + y * ntiles_x;		/* number of this tile */
2232
2233			if (! tile_has_diff[n]) {
2234				continue;
2235			}
2236			if (tile_copied[n]) {
2237				continue;
2238			}
2239
2240			ct = copy_tiles(x, y, 1);
2241			if (ct < 0) return ct;	/* fatal */
2242		}
2243	}
2244	for (n=0; n < ntiles; n++) {
2245		if (tile_has_diff[n]) {
2246			diffs++;
2247		}
2248	}
2249	return diffs;
2250}
2251
2252static int gap_try(int x, int y, int *run, int *saw, int along_x) {
2253	int n, m, i, xt, yt, ct;
2254
2255	n = x + y * ntiles_x;
2256
2257	if (! tile_has_diff[n]) {
2258		if (*saw) {
2259			(*run)++;	/* extend the gap run. */
2260		}
2261		return 0;
2262	}
2263	if (! *saw || *run == 0 || *run > gaps_fill) {
2264		*run = 0;		/* unacceptable run. */
2265		*saw = 1;
2266		return 0;
2267	}
2268
2269	for (i=1; i <= *run; i++) {	/* iterate thru the run. */
2270		if (along_x) {
2271			xt = x - i;
2272			yt = y;
2273		} else {
2274			xt = x;
2275			yt = y - i;
2276		}
2277
2278		m = xt + yt * ntiles_x;
2279		if (tile_tried[m]) {	/* do not repeat tiles */
2280			continue;
2281		}
2282
2283		ct = copy_tiles(xt, yt, 1);
2284		if (ct < 0) return ct;	/* fatal */
2285	}
2286	*run = 0;
2287	*saw = 1;
2288	return 1;
2289}
2290
2291/*
2292 * Look for small gaps of unchanged tiles that may actually contain changes.
2293 * E.g. when paging up and down in a web broswer or terminal there can
2294 * be a distracting delayed filling in of such gaps.  gaps_fill is the
2295 * tweak parameter that sets the width of the gaps that are checked.
2296 *
2297 * BTW, grow_islands() is actually pretty successful at doing this too...
2298 */
2299static int fill_tile_gaps(void) {
2300	int x, y, run, saw;
2301	int n, diffs = 0, ct;
2302
2303	/* horizontal: */
2304	for (y=0; y < ntiles_y; y++) {
2305		run = 0;
2306		saw = 0;
2307		for (x=0; x < ntiles_x; x++) {
2308			ct = gap_try(x, y, &run, &saw, 1);
2309			if (ct < 0) return ct;	/* fatal */
2310		}
2311	}
2312
2313	/* vertical: */
2314	for (x=0; x < ntiles_x; x++) {
2315		run = 0;
2316		saw = 0;
2317		for (y=0; y < ntiles_y; y++) {
2318			ct = gap_try(x, y, &run, &saw, 0);
2319			if (ct < 0) return ct;	/* fatal */
2320		}
2321	}
2322
2323	for (n=0; n < ntiles; n++) {
2324		if (tile_has_diff[n]) {
2325			diffs++;
2326		}
2327	}
2328	return diffs;
2329}
2330
2331static int island_try(int x, int y, int u, int v, int *run) {
2332	int n, m, ct;
2333
2334	n = x + y * ntiles_x;
2335	m = u + v * ntiles_x;
2336
2337	if (tile_has_diff[n]) {
2338		(*run)++;
2339	} else {
2340		*run = 0;
2341	}
2342
2343	if (tile_has_diff[n] && ! tile_has_diff[m]) {
2344		/* found a discontinuity */
2345
2346		if (tile_tried[m]) {
2347			return 0;
2348		} else if (*run < grow_fill) {
2349			return 0;
2350		}
2351
2352		ct = copy_tiles(u, v, 1);
2353		if (ct < 0) return ct;	/* fatal */
2354	}
2355	return 1;
2356}
2357
2358/*
2359 * Scan looking for discontinuities in tile_has_diff[].  Try to extend
2360 * the boundary of the discontinuity (i.e. make the island larger).
2361 * Vertical scans are skipped since they do not seem to yield much...
2362 */
2363static int grow_islands(void) {
2364	int x, y, n, run;
2365	int diffs = 0, ct;
2366
2367	/*
2368	 * n.b. the way we scan here should keep an extension going,
2369	 * and so also fill in gaps effectively...
2370	 */
2371
2372	/* left to right: */
2373	for (y=0; y < ntiles_y; y++) {
2374		run = 0;
2375		for (x=0; x <= ntiles_x - 2; x++) {
2376			ct = island_try(x, y, x+1, y, &run);
2377			if (ct < 0) return ct;	/* fatal */
2378		}
2379	}
2380	/* right to left: */
2381	for (y=0; y < ntiles_y; y++) {
2382		run = 0;
2383		for (x = ntiles_x - 1; x >= 1; x--) {
2384			ct = island_try(x, y, x-1, y, &run);
2385			if (ct < 0) return ct;	/* fatal */
2386		}
2387	}
2388	for (n=0; n < ntiles; n++) {
2389		if (tile_has_diff[n]) {
2390			diffs++;
2391		}
2392	}
2393	return diffs;
2394}
2395
2396/*
2397 * Fill the framebuffer with zeros for each blackout region
2398 */
2399static void blackout_regions(void) {
2400	int i;
2401	for (i=0; i < blackouts; i++) {
2402		zero_fb(blackr[i].x1, blackr[i].y1, blackr[i].x2, blackr[i].y2);
2403	}
2404}
2405
2406/*
2407 * copy the whole X screen to the rfb framebuffer.  For a large enough
2408 * number of changed tiles, this is faster than tiles scheme at retrieving
2409 * the info from the X server.  Bandwidth to client and compression time
2410 * are other issues...  use -fs 1.0 to disable.
2411 */
2412int copy_screen(void) {
2413	char *fbp;
2414	int i, y, block_size;
2415
2416	if (! fs_factor) {
2417		return 0;
2418	}
2419	if (debug_tiles) fprintf(stderr, "copy_screen\n");
2420
2421	if (unixpw_in_progress) return 0;
2422
2423
2424	if (! main_fb) {
2425		return 0;
2426	}
2427
2428	block_size = ((dpy_y/fs_factor) * main_bytes_per_line);
2429
2430	fbp = main_fb;
2431	y = 0;
2432
2433	X_LOCK;
2434
2435	/* screen may be too big for 1 shm area, so broken into fs_factor */
2436	for (i=0; i < fs_factor; i++) {
2437		XRANDR_SET_TRAP_RET(-1, "copy_screen-set");
2438		copy_image(fullscreen, 0, y, 0, 0);
2439		XRANDR_CHK_TRAP_RET(-1, "copy_screen-chk");
2440
2441		memcpy(fbp, fullscreen->data, (size_t) block_size);
2442
2443		y += dpy_y / fs_factor;
2444		fbp += block_size;
2445	}
2446
2447	X_UNLOCK;
2448
2449	if (blackouts) {
2450		blackout_regions();
2451	}
2452
2453	mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0);
2454	return 0;
2455}
2456
2457#include <rfb/default8x16.h>
2458
2459/*
2460 * Color values from the vcsadump program.
2461 * void dumpcss(FILE *fp, char *attribs_used)
2462 * char *colormap[] = {
2463 *    "#000000", "#0000AA", "#00AA00", "#00AAAA", "#AA0000", "#AA00AA", "#AA5500", "#AAAAAA",
2464 *    "#555555", "#5555AA", "#55FF55", "#55FFFF", "#FF5555", "#FF55FF", "#FFFF00", "#FFFFFF" };
2465 */
2466
2467static unsigned char console_cmap[16*3]={
2468/*  0 */	0x00, 0x00, 0x00,
2469/*  1 */	0x00, 0x00, 0xAA,
2470/*  2 */	0x00, 0xAA, 0x00,
2471/*  3 */	0x00, 0xAA, 0xAA,
2472/*  4 */	0xAA, 0x00, 0x00,
2473/*  5 */	0xAA, 0x00, 0xAA,
2474/*  6 */	0xAA, 0x55, 0x00,
2475/*  7 */	0xAA, 0xAA, 0xAA,
2476/*  8 */	0x55, 0x55, 0x55,
2477/*  9 */	0x55, 0x55, 0xAA,
2478/* 10 */	0x55, 0xFF, 0x55,
2479/* 11 */	0x55, 0xFF, 0xFF,
2480/* 12 */	0xFF, 0x55, 0x55,
2481/* 13 */	0xFF, 0x55, 0xFF,
2482/* 14 */	0xFF, 0xFF, 0x00,
2483/* 15 */	0xFF, 0xFF, 0xFF
2484};
2485
2486static void snap_vcsa_rawfb(void) {
2487	int n;
2488	char *dst;
2489	char buf[32];
2490	int i, len, del;
2491	unsigned char rows, cols, xpos, ypos;
2492	static int prev_rows = -1, prev_cols = -1;
2493	static unsigned char prev_xpos = -1, prev_ypos = -1;
2494	static char *vcsabuf  = NULL;
2495	static char *vcsabuf0 = NULL;
2496	static unsigned int color_tab[16];
2497	static int Cw = 8, Ch = 16;
2498	static int db = -1, first = 1;
2499	int created = 0;
2500	rfbScreenInfo s;
2501	rfbScreenInfoPtr fake_screen = &s;
2502	int Bpp = raw_fb_native_bpp / 8;
2503
2504	if (db < 0) {
2505		if (getenv("X11VNC_DEBUG_VCSA")) {
2506			db = atoi(getenv("X11VNC_DEBUG_VCSA"));
2507		} else {
2508			db = 0;
2509		}
2510	}
2511
2512	if (first) {
2513		unsigned int rm = raw_fb_native_red_mask;
2514		unsigned int gm = raw_fb_native_green_mask;
2515		unsigned int bm = raw_fb_native_blue_mask;
2516		unsigned int rs = raw_fb_native_red_shift;
2517		unsigned int gs = raw_fb_native_green_shift;
2518		unsigned int bs = raw_fb_native_blue_shift;
2519		unsigned int rx = raw_fb_native_red_max;
2520		unsigned int gx = raw_fb_native_green_max;
2521		unsigned int bx = raw_fb_native_blue_max;
2522
2523		for (i=0; i < 16; i++) {
2524			int r = console_cmap[3*i+0];
2525			int g = console_cmap[3*i+1];
2526			int b = console_cmap[3*i+2];
2527			r = rx * r / 255;
2528			g = gx * g / 255;
2529			b = bx * b / 255;
2530			color_tab[i] = (r << rs) | (g << gs) | (b << bs);
2531			if (db) fprintf(stderr, "cmap[%02d] 0x%08x  %04d %04d %04d\n", i, color_tab[i], r, g, b);
2532			if (i != 0 && getenv("RAWFB_VCSA_BW")) {
2533				color_tab[i] = rm | gm | bm;
2534			}
2535		}
2536	}
2537	first = 0;
2538
2539	lseek(raw_fb_fd, 0, SEEK_SET);
2540	len = 4;
2541	del = 0;
2542	memset(buf, 0, sizeof(buf));
2543	while (len > 0) {
2544		n = read(raw_fb_fd, buf + del, len);
2545		if (n > 0) {
2546			del += n;
2547			len -= n;
2548		} else if (n == 0) {
2549			break;
2550		} else if (errno != EINTR && errno != EAGAIN) {
2551			break;
2552		}
2553	}
2554
2555	rows = (unsigned char) buf[0];
2556	cols = (unsigned char) buf[1];
2557	xpos = (unsigned char) buf[2];
2558	ypos = (unsigned char) buf[3];
2559
2560	if (db) fprintf(stderr, "rows=%d cols=%d xpos=%d ypos=%d Bpp=%d\n", rows, cols, xpos, ypos, Bpp);
2561	if (rows == 0 || cols == 0) {
2562		usleep(100 * 1000);
2563		return;
2564	}
2565
2566	if (vcsabuf == NULL || prev_rows != rows || prev_cols != cols) {
2567		if (vcsabuf) {
2568			free(vcsabuf);
2569			free(vcsabuf0);
2570		}
2571		vcsabuf  = (char *) calloc(2 * rows * cols, 1);
2572		vcsabuf0 = (char *) calloc(2 * rows * cols, 1);
2573		created = 1;
2574
2575		if (prev_rows != -1 && prev_cols != -1) {
2576			do_new_fb(1);
2577		}
2578
2579		prev_rows = rows;
2580		prev_cols = cols;
2581	}
2582
2583	if (!rfbEndianTest) {
2584		unsigned char tc = rows;
2585		rows = cols;
2586		cols = tc;
2587
2588		tc = xpos;
2589		xpos = ypos;
2590		ypos = tc;
2591	}
2592
2593	len = 2 * rows * cols;
2594	del = 0;
2595	memset(vcsabuf, 0, len);
2596	while (len > 0) {
2597		n = read(raw_fb_fd, vcsabuf + del, len);
2598		if (n > 0) {
2599			del += n;
2600			len -= n;
2601		} else if (n == 0) {
2602			break;
2603		} else if (errno != EINTR && errno != EAGAIN) {
2604			break;
2605		}
2606	}
2607
2608	fake_screen->frameBuffer = snap->data;
2609	fake_screen->paddedWidthInBytes = snap->bytes_per_line;
2610	fake_screen->serverFormat.bitsPerPixel = raw_fb_native_bpp;
2611	fake_screen->width = snap->width;
2612	fake_screen->height = snap->height;
2613
2614	for (i=0; i < rows * cols; i++) {
2615		int ix, iy, x, y, w, h;
2616		unsigned char chr = 0;
2617		unsigned char attr;
2618		unsigned int fore, back;
2619		unsigned short *usp;
2620		unsigned int *uip;
2621		chr  = (unsigned char) vcsabuf[2*i];
2622		attr = vcsabuf[2*i+1];
2623
2624		iy = i / cols;
2625		ix = i - iy * cols;
2626
2627		if (ix == prev_xpos && iy == prev_ypos) {
2628			;
2629		} else if (ix == xpos && iy == ypos) {
2630			;
2631		} else if (!created && chr == vcsabuf0[2*i] && attr == vcsabuf0[2*i+1]) {
2632			continue;
2633		}
2634
2635		if (!rfbEndianTest) {
2636			unsigned char tc = chr;
2637			chr = attr;
2638			attr = tc;
2639		}
2640
2641		y = iy * Ch;
2642		x = ix * Cw;
2643		dst = snap->data + y * snap->bytes_per_line + x * Bpp;
2644
2645		fore = color_tab[attr & 0xf];
2646		back = color_tab[(attr >> 4) & 0x7];
2647
2648		if (ix == xpos && iy == ypos) {
2649			unsigned int ti = fore;
2650			fore = back;
2651			back = ti;
2652		}
2653
2654		for (h = 0; h < Ch; h++) {
2655			if (Bpp == 1) {
2656				memset(dst, back, Cw);
2657			} else if (Bpp == 2) {
2658				for (w = 0; w < Cw; w++) {
2659					usp = (unsigned short *) (dst + w*Bpp);
2660					*usp = (unsigned short) back;
2661				}
2662			} else if (Bpp == 4) {
2663				for (w = 0; w < Cw; w++) {
2664					uip = (unsigned int *) (dst + w*Bpp);
2665					*uip = (unsigned int) back;
2666				}
2667			}
2668			dst += snap->bytes_per_line;
2669		}
2670		rfbDrawChar(fake_screen, &default8x16Font, x, y + Ch, chr, fore);
2671	}
2672	memcpy(vcsabuf0, vcsabuf, 2 * rows * cols);
2673	prev_xpos = xpos;
2674	prev_ypos = ypos;
2675}
2676
2677static void snap_all_rawfb(void) {
2678	int pixelsize = bpp/8;
2679	int n, sz;
2680	char *dst;
2681	static char *unclipped_dst = NULL;
2682	static int unclipped_len = 0;
2683
2684	dst = snap->data;
2685
2686	if (xform24to32 && bpp == 32) {
2687		pixelsize = 3;
2688	}
2689	sz = dpy_y * snap->bytes_per_line;
2690
2691	if (wdpy_x > dpy_x || wdpy_y > dpy_y) {
2692		sz = wdpy_x * wdpy_y * pixelsize;
2693		if (sz > unclipped_len || unclipped_dst == NULL) {
2694			if (unclipped_dst) {
2695				free(unclipped_dst);
2696			}
2697			unclipped_dst = (char *) malloc(sz+4);
2698			unclipped_len = sz;
2699		}
2700		dst = unclipped_dst;
2701	}
2702
2703	if (! raw_fb_seek) {
2704		memcpy(dst, raw_fb_addr + raw_fb_offset, sz);
2705
2706	} else {
2707		int len = sz, del = 0;
2708		off_t off = (off_t) raw_fb_offset;
2709
2710		lseek(raw_fb_fd, off, SEEK_SET);
2711		while (len > 0) {
2712			n = read(raw_fb_fd, dst + del, len);
2713			if (n > 0) {
2714				del += n;
2715				len -= n;
2716			} else if (n == 0) {
2717				break;
2718			} else if (errno != EINTR && errno != EAGAIN) {
2719				break;
2720			}
2721		}
2722	}
2723
2724	if (dst == unclipped_dst) {
2725		char *src;
2726		int h;
2727		int x = off_x + coff_x;
2728		int y = off_y + coff_y;
2729
2730		src = unclipped_dst + y * wdpy_x * pixelsize +
2731		    x * pixelsize;
2732		dst = snap->data;
2733
2734		for (h = 0; h < dpy_y; h++) {
2735			memcpy(dst, src, dpy_x * pixelsize);
2736			src += wdpy_x * pixelsize;
2737			dst += snap->bytes_per_line;
2738		}
2739	}
2740}
2741
2742int copy_snap(void) {
2743	int db = 1;
2744	char *fbp;
2745	int i, y, block_size;
2746	double dt;
2747	static int first = 1, snapcnt = 0;
2748
2749	if (raw_fb_str) {
2750		int read_all_at_once = 1;
2751		double start = dnow();
2752		if (rawfb_reset < 0) {
2753			if (getenv("SNAPFB_RAWFB_RESET")) {
2754				rawfb_reset = 1;
2755			} else {
2756				rawfb_reset = 0;
2757			}
2758		}
2759		if (snap_fb == NULL || snap == NULL) {
2760			rfbLog("copy_snap: rawfb mode and null snap fb\n");
2761			clean_up_exit(1);
2762		}
2763		if (rawfb_reset) {
2764			initialize_raw_fb(1);
2765		}
2766		if (raw_fb_bytes_per_line != snap->bytes_per_line) {
2767			read_all_at_once = 0;
2768		}
2769		if (raw_fb_full_str && strstr(raw_fb_full_str, "/dev/vcsa")) {
2770			snap_vcsa_rawfb();
2771		} else if (read_all_at_once) {
2772			snap_all_rawfb();
2773		} else {
2774			/* this goes line by line, XXX not working for video */
2775			copy_raw_fb(snap, 0, 0, dpy_x, dpy_y);
2776		}
2777if (db && snapcnt++ < 5) rfbLog("rawfb copy_snap took: %.5f secs\n", dnow() - start);
2778
2779		return 0;
2780	}
2781
2782	if (! fs_factor) {
2783		return 0;
2784	}
2785
2786
2787	if (! snap_fb || ! snap || ! snaprect) {
2788		return 0;
2789	}
2790	block_size = ((dpy_y/fs_factor) * snap->bytes_per_line);
2791
2792	fbp = snap_fb;
2793	y = 0;
2794
2795
2796	dtime0(&dt);
2797	X_LOCK;
2798
2799	/* screen may be too big for 1 shm area, so broken into fs_factor */
2800	for (i=0; i < fs_factor; i++) {
2801		XRANDR_SET_TRAP_RET(-1, "copy_snap-set");
2802		copy_image(snaprect, 0, y, 0, 0);
2803		XRANDR_CHK_TRAP_RET(-1, "copy_snap-chk");
2804
2805		memcpy(fbp, snaprect->data, (size_t) block_size);
2806
2807		y += dpy_y / fs_factor;
2808		fbp += block_size;
2809	}
2810
2811	X_UNLOCK;
2812
2813	dt = dtime(&dt);
2814	if (first) {
2815		rfbLog("copy_snap: time for -snapfb snapshot: %.3f sec\n", dt);
2816		first = 0;
2817	}
2818
2819	return 0;
2820}
2821
2822
2823/*
2824 * debugging: print out a picture of the tiles.
2825 */
2826static void print_tiles(void) {
2827	/* hack for viewing tile diffs on the screen. */
2828	static char *prev = NULL;
2829	int n, x, y, ms = 1500;
2830
2831	ms = 1;
2832
2833	if (! prev) {
2834		prev = (char *) malloc((size_t) ntiles);
2835		for (n=0; n < ntiles; n++) {
2836			prev[n] = 0;
2837		}
2838	}
2839	fprintf(stderr, "   ");
2840	for (x=0; x < ntiles_x; x++) {
2841		fprintf(stderr, "%1d", x % 10);
2842	}
2843	fprintf(stderr, "\n");
2844	n = 0;
2845	for (y=0; y < ntiles_y; y++) {
2846		fprintf(stderr, "%2d ", y);
2847		for (x=0; x < ntiles_x; x++) {
2848			if (tile_has_diff[n]) {
2849				fprintf(stderr, "X");
2850			} else if (prev[n]) {
2851				fprintf(stderr, "o");
2852			} else {
2853				fprintf(stderr, ".");
2854			}
2855			n++;
2856		}
2857		fprintf(stderr, "\n");
2858	}
2859	for (n=0; n < ntiles; n++) {
2860		prev[n] = tile_has_diff[n];
2861	}
2862	usleep(ms * 1000);
2863}
2864
2865/*
2866 * Utilities for managing the "naps" to cut down on amount of polling.
2867 */
2868static void nap_set(int tile_cnt) {
2869	int nap_in = nap_ok;
2870	time_t now = time(NULL);
2871
2872	if (scan_count == 0) {
2873		/* roll up check for all NSCAN scans */
2874		nap_ok = 0;
2875		if (naptile && nap_diff_count < 2 * NSCAN * naptile) {
2876			/* "2" is a fudge to permit a bit of bg drawing */
2877			nap_ok = 1;
2878		}
2879		nap_diff_count = 0;
2880	}
2881	if (nap_ok && ! nap_in && use_xdamage) {
2882		if (XD_skip > 0.8 * XD_tot) 	{
2883			/* X DAMAGE is keeping load low, so skip nap */
2884			nap_ok = 0;
2885		}
2886	}
2887	if (! nap_ok && client_count) {
2888		if(now > last_fb_bytes_sent + no_fbu_blank) {
2889			if (debug_tiles > 1) {
2890				fprintf(stderr, "nap_set: nap_ok=1: now: %d last: %d\n",
2891				    (int) now, (int) last_fb_bytes_sent);
2892			}
2893			nap_ok = 1;
2894		}
2895	}
2896
2897	if (show_cursor) {
2898		/* kludge for the up to 4 tiles the mouse patch could occupy */
2899		if ( tile_cnt > 4) {
2900			last_event = now;
2901		}
2902	} else if (tile_cnt != 0) {
2903		last_event = now;
2904	}
2905}
2906
2907/*
2908 * split up a long nap to improve the wakeup time
2909 */
2910void nap_sleep(int ms, int split) {
2911	int i, input = got_user_input;
2912	int gd = got_local_pointer_input;
2913
2914	for (i=0; i<split; i++) {
2915		usleep(ms * 1000 / split);
2916		if (! use_threads && i != split - 1) {
2917			rfbPE(-1);
2918		}
2919		if (input != got_user_input) {
2920			break;
2921		}
2922		if (gd != got_local_pointer_input) {
2923			break;
2924		}
2925	}
2926}
2927
2928static char *get_load(void) {
2929	static char tmp[64];
2930	static int count = 0;
2931
2932	if (count++ % 5 == 0) {
2933		struct stat sb;
2934		memset(tmp, 0, sizeof(tmp));
2935		if (stat("/proc/loadavg", &sb) == 0) {
2936			int d = open("/proc/loadavg", O_RDONLY);
2937			if (d >= 0) {
2938				read(d, tmp, 60);
2939				close(d);
2940			}
2941		}
2942		if (tmp[0] == '\0') {
2943			strcat(tmp, "unknown");
2944		}
2945	}
2946	return tmp;
2947}
2948
2949/*
2950 * see if we should take a nap of some sort between polls
2951 */
2952static void nap_check(int tile_cnt) {
2953	time_t now;
2954
2955	nap_diff_count += tile_cnt;
2956
2957	if (! take_naps) {
2958		return;
2959	}
2960
2961	now = time(NULL);
2962
2963	if (screen_blank > 0) {
2964		int dt_ev, dt_fbu;
2965		static int ms = 0;
2966		if (ms == 0) {
2967			ms = 2000;
2968			if (getenv("X11VNC_SB_FACTOR")) {
2969				ms = ms * atof(getenv("X11VNC_SB_FACTOR"));
2970			}
2971			if (ms <= 0) {
2972				ms = 2000;
2973			}
2974		}
2975
2976		/* if no activity, pause here for a second or so. */
2977		dt_ev  = (int) (now - last_event);
2978		dt_fbu = (int) (now - last_fb_bytes_sent);
2979		if (dt_fbu > screen_blank) {
2980			/* sleep longer for no fb requests */
2981			if (debug_tiles > 1) {
2982				fprintf(stderr, "screen blank sleep1: %d ms / 16, load: %s\n", 2 * ms, get_load());
2983			}
2984			nap_sleep(2 * ms, 16);
2985			return;
2986		}
2987		if (dt_ev > screen_blank) {
2988			if (debug_tiles > 1) {
2989				fprintf(stderr, "screen blank sleep2: %d ms / 8, load: %s\n", ms, get_load());
2990			}
2991			nap_sleep(ms, 8);
2992			return;
2993		}
2994	}
2995	if (naptile && nap_ok && tile_cnt < naptile) {
2996		int ms = napfac * waitms;
2997		ms = ms > napmax ? napmax : ms;
2998		if (now - last_input <= 3) {
2999			nap_ok = 0;
3000		} else if (now - last_local_input <= 3) {
3001			nap_ok = 0;
3002		} else {
3003			if (debug_tiles > 1) {
3004				fprintf(stderr, "nap_check sleep: %d ms / 1, load: %s\n", ms, get_load());
3005			}
3006			nap_sleep(ms, 1);
3007		}
3008	}
3009}
3010
3011/*
3012 * This is called to avoid a ~20 second timeout in libvncserver.
3013 * May no longer be needed.
3014 */
3015static void ping_clients(int tile_cnt) {
3016	static time_t last_send = 0;
3017	time_t now = time(NULL);
3018
3019	if (rfbMaxClientWait < 20000) {
3020		rfbMaxClientWait = 20000;
3021		rfbLog("reset rfbMaxClientWait to %d msec.\n",
3022		    rfbMaxClientWait);
3023	}
3024	if (tile_cnt > 0) {
3025		last_send = now;
3026	} else if (tile_cnt < 0) {
3027		/* negative tile_cnt is -ping case */
3028		if (now >= last_send - tile_cnt) {
3029			mark_rect_as_modified(0, 0, 1, 1, 1);
3030			last_send = now;
3031		}
3032	} else if (now - last_send > 5) {
3033		/* Send small heartbeat to client */
3034		mark_rect_as_modified(0, 0, 1, 1, 1);
3035		last_send = now;
3036	}
3037}
3038
3039/*
3040 * scan_display() wants to know if this tile can be skipped due to
3041 * blackout regions: (no data compare is done, just a quick geometric test)
3042 */
3043static int blackout_line_skip(int n, int x, int y, int rescan,
3044    int *tile_count) {
3045
3046	if (tile_blackout[n].cover == 2) {
3047		tile_has_diff[n] = 0;
3048		return 1;	/* skip it */
3049
3050	} else if (tile_blackout[n].cover == 1) {
3051		int w, x1, y1, x2, y2, b, hit = 0;
3052		if (x + NSCAN > dpy_x) {
3053			w = dpy_x - x;
3054		} else {
3055			w = NSCAN;
3056		}
3057
3058		for (b=0; b < tile_blackout[n].count; b++) {
3059
3060			/* n.b. these coords are in full display space: */
3061			x1 = tile_blackout[n].bo[b].x1;
3062			x2 = tile_blackout[n].bo[b].x2;
3063			y1 = tile_blackout[n].bo[b].y1;
3064			y2 = tile_blackout[n].bo[b].y2;
3065
3066			if (x2 - x1 < w) {
3067				/* need to cover full width */
3068				continue;
3069			}
3070			if (y1 <= y && y < y2) {
3071				hit = 1;
3072				break;
3073			}
3074		}
3075		if (hit) {
3076			if (! rescan) {
3077				tile_has_diff[n] = 0;
3078			} else {
3079				*tile_count += tile_has_diff[n];
3080			}
3081			return 1;	/* skip */
3082		}
3083	}
3084	return 0;	/* do not skip */
3085}
3086
3087static int blackout_line_cmpskip(int n, int x, int y, char *dst, char *src,
3088    int w, int pixelsize) {
3089
3090	int i, x1, y1, x2, y2, b, hit = 0;
3091	int beg = -1, end = -1;
3092
3093	if (tile_blackout[n].cover == 0) {
3094		return 0;	/* 0 means do not skip it. */
3095	} else if (tile_blackout[n].cover == 2) {
3096		return 1;	/* 1 means skip it. */
3097	}
3098
3099	/* tile has partial coverage: */
3100
3101	for (i=0; i < w * pixelsize; i++)  {
3102		if (*(dst+i) != *(src+i)) {
3103			beg = i/pixelsize;	/* beginning difference */
3104			break;
3105		}
3106	}
3107	for (i = w * pixelsize - 1; i >= 0; i--)  {
3108		if (*(dst+i) != *(src+i)) {
3109			end = i/pixelsize;	/* ending difference */
3110			break;
3111		}
3112	}
3113	if (beg < 0 || end < 0) {
3114		/* problem finding range... */
3115		return 0;
3116	}
3117
3118	/* loop over blackout rectangles: */
3119	for (b=0; b < tile_blackout[n].count; b++) {
3120
3121		/* y in full display space: */
3122		y1 = tile_blackout[n].bo[b].y1;
3123		y2 = tile_blackout[n].bo[b].y2;
3124
3125		/* x relative to tile origin: */
3126		x1 = tile_blackout[n].bo[b].x1 - x;
3127		x2 = tile_blackout[n].bo[b].x2 - x;
3128
3129		if (y1 > y || y >= y2) {
3130			continue;
3131		}
3132		if (x1 <= beg && end <= x2) {
3133			hit = 1;
3134			break;
3135		}
3136	}
3137	if (hit) {
3138		return 1;
3139	} else {
3140		return 0;
3141	}
3142}
3143
3144/*
3145 * For the subwin case follows the window if it is moved.
3146 */
3147void set_offset(void) {
3148	Window w;
3149	if (! subwin) {
3150		return;
3151	}
3152	X_LOCK;
3153	xtranslate(window, rootwin, 0, 0, &off_x, &off_y, &w, 0);
3154	X_UNLOCK;
3155}
3156
3157static int xd_samples = 0, xd_misses = 0, xd_do_check = 0;
3158
3159/*
3160 * Loop over 1-pixel tall horizontal scanlines looking for changes.
3161 * Record the changes in tile_has_diff[].  Scanlines in the loop are
3162 * equally spaced along y by NSCAN pixels, but have a slightly random
3163 * starting offset ystart ( < NSCAN ) from scanlines[].
3164 */
3165
3166static int scan_display(int ystart, int rescan) {
3167	char *src, *dst;
3168	int pixelsize = bpp/8;
3169	int x, y, w, n;
3170	int tile_count = 0;
3171	int nodiffs = 0, diff_hint;
3172	int xd_check = 0, xd_freq = 1;
3173	static int xd_tck = 0;
3174
3175	y = ystart;
3176
3177	g_now = dnow();
3178
3179	if (! main_fb) {
3180		rfbLog("scan_display: no main_fb!\n");
3181		return 0;
3182	}
3183
3184	X_LOCK;
3185
3186	while (y < dpy_y) {
3187
3188		if (use_xdamage) {
3189			XD_tot++;
3190			xd_check = 0;
3191			if (xdamage_hint_skip(y)) {
3192				if (xd_do_check && dpy && use_xdamage == 1) {
3193					xd_tck++;
3194					xd_tck = xd_tck % xd_freq;
3195					if (xd_tck == 0) {
3196						xd_check = 1;
3197						xd_samples++;
3198					}
3199				}
3200				if (!xd_check) {
3201					XD_skip++;
3202					y += NSCAN;
3203					continue;
3204				}
3205			} else {
3206				if (xd_do_check && 0) {
3207					fprintf(stderr, "ns y=%d\n", y);
3208				}
3209			}
3210		}
3211
3212		/* grab the horizontal scanline from the display: */
3213
3214#ifndef NO_NCACHE
3215/* XXX Y test */
3216if (ncache > 0) {
3217	int gotone = 0;
3218	if (macosx_console) {
3219		if (macosx_checkevent(NULL)) {
3220			gotone = 1;
3221		}
3222	} else {
3223#if !NO_X11
3224		XEvent ev;
3225		if (raw_fb_str) {
3226			;
3227		} else if (XEventsQueued(dpy, QueuedAlready) == 0) {
3228			;	/* XXX Y resp */
3229		} else if (XCheckTypedEvent(dpy, MapNotify, &ev)) {
3230			gotone = 1;
3231		} else if (XCheckTypedEvent(dpy, UnmapNotify, &ev)) {
3232			gotone = 2;
3233		} else if (XCheckTypedEvent(dpy, CreateNotify, &ev)) {
3234			gotone = 3;
3235		} else if (XCheckTypedEvent(dpy, ConfigureNotify, &ev)) {
3236			gotone = 4;
3237		} else if (XCheckTypedEvent(dpy, VisibilityNotify, &ev)) {
3238			gotone = 5;
3239		}
3240		if (gotone) {
3241			XPutBackEvent(dpy, &ev);
3242		}
3243#endif
3244	}
3245	if (gotone) {
3246		static int nomsg = 1;
3247		if (nomsg) {
3248			if (dnowx() > 20) {
3249				nomsg = 0;
3250			}
3251		} else {
3252if (ncdb) fprintf(stderr, "\n*** SCAN_DISPLAY CHECK_NCACHE/%d *** %d rescan=%d\n", gotone, y, rescan);
3253		}
3254		X_UNLOCK;
3255		check_ncache(0, 1);
3256		X_LOCK;
3257	}
3258}
3259#endif
3260
3261		XRANDR_SET_TRAP_RET(-1, "scan_display-set");
3262		copy_image(scanline, 0, y, 0, 0);
3263		XRANDR_CHK_TRAP_RET(-1, "scan_display-chk");
3264
3265		/* for better memory i/o try the whole line at once */
3266		src = scanline->data;
3267		dst = main_fb + y * main_bytes_per_line;
3268
3269		if (! memcmp(dst, src, main_bytes_per_line)) {
3270			/* no changes anywhere in scan line */
3271			nodiffs = 1;
3272			if (! rescan) {
3273				y += NSCAN;
3274				continue;
3275			}
3276		}
3277		if (xd_check) {
3278			xd_misses++;
3279		}
3280
3281		x = 0;
3282		while (x < dpy_x) {
3283			n = (x/tile_x) + (y/tile_y) * ntiles_x;
3284			diff_hint = 0;
3285
3286			if (blackouts) {
3287				if (blackout_line_skip(n, x, y, rescan,
3288				    &tile_count)) {
3289					x += NSCAN;
3290					continue;
3291				}
3292			}
3293
3294			if (rescan) {
3295				if (nodiffs || tile_has_diff[n]) {
3296					tile_count += tile_has_diff[n];
3297					x += NSCAN;
3298					continue;
3299				}
3300			} else if (xdamage_tile_count &&
3301			    tile_has_xdamage_diff[n]) {
3302				tile_has_xdamage_diff[n] = 2;
3303				diff_hint = 1;
3304			}
3305
3306			/* set ptrs to correspond to the x offset: */
3307			src = scanline->data + x * pixelsize;
3308			dst = main_fb + y * main_bytes_per_line + x * pixelsize;
3309
3310			/* compute the width of data to be compared: */
3311			if (x + NSCAN > dpy_x) {
3312				w = dpy_x - x;
3313			} else {
3314				w = NSCAN;
3315			}
3316
3317			if (diff_hint || memcmp(dst, src, w * pixelsize)) {
3318				/* found a difference, record it: */
3319				if (! blackouts) {
3320					tile_has_diff[n] = 1;
3321					tile_count++;
3322				} else {
3323					if (blackout_line_cmpskip(n, x, y,
3324					    dst, src, w, pixelsize)) {
3325						tile_has_diff[n] = 0;
3326					} else {
3327						tile_has_diff[n] = 1;
3328						tile_count++;
3329					}
3330				}
3331			}
3332			x += NSCAN;
3333		}
3334		y += NSCAN;
3335	}
3336
3337	X_UNLOCK;
3338
3339	return tile_count;
3340}
3341
3342
3343int scanlines[NSCAN] = {
3344	 0, 16,  8, 24,  4, 20, 12, 28,
3345	10, 26, 18,  2, 22,  6, 30, 14,
3346	 1, 17,  9, 25,  7, 23, 15, 31,
3347	19,  3, 27, 11, 29, 13,  5, 21
3348};
3349
3350/*
3351 * toplevel for the scanning, rescanning, and applying the heuristics.
3352 * returns number of changed tiles.
3353 */
3354int scan_for_updates(int count_only) {
3355	int i, tile_count, tile_diffs;
3356	int old_copy_tile;
3357	double frac1 = 0.1;   /* tweak parameter to try a 2nd scan_display() */
3358	double frac2 = 0.35;  /* or 3rd */
3359	double frac3 = 0.02;  /* do scan_display() again after copy_tiles() */
3360	static double last_poll = 0.0;
3361	double dtmp = 0.0;
3362
3363	if (unixpw_in_progress) return 0;
3364
3365	if (slow_fb > 0.0) {
3366		double now = dnow();
3367		if (now < last_poll + slow_fb) {
3368			return 0;
3369		}
3370		last_poll = now;
3371	}
3372
3373	for (i=0; i < ntiles; i++) {
3374		tile_has_diff[i] = 0;
3375		tile_has_xdamage_diff[i] = 0;
3376		tile_tried[i] = 0;
3377		tile_copied[i] = 0;
3378	}
3379	for (i=0; i < ntiles_y; i++) {
3380		/* could be useful, currently not used */
3381		tile_row_has_xdamage_diff[i] = 0;
3382	}
3383	xdamage_tile_count = 0;
3384
3385	/*
3386	 * n.b. this program has only been tested so far with
3387	 * tile_x = tile_y = NSCAN = 32!
3388	 */
3389
3390	if (!count_only) {
3391		scan_count++;
3392		scan_count %= NSCAN;
3393
3394		/* some periodic maintenance */
3395		if (subwin && scan_count % 4 == 0) {
3396			set_offset();	/* follow the subwindow */
3397		}
3398		if (indexed_color && scan_count % 4 == 0) {
3399			/* check for changed colormap */
3400			set_colormap(0);
3401		}
3402		if (cmap8to24 && scan_count % 1 == 0) {
3403			check_for_multivis();
3404		}
3405#ifdef MACOSX
3406		if (macosx_console) {
3407			macosx_event_loop();
3408		}
3409#endif
3410		if (use_xdamage) {
3411			/* first pass collecting DAMAGE events: */
3412#ifdef MACOSX
3413			if (macosx_console) {
3414				collect_non_X_xdamage(-1, -1, -1, -1, 0);
3415			} else
3416#endif
3417			{
3418				if (rawfb_vnc_reflect) {
3419					collect_non_X_xdamage(-1, -1, -1, -1, 0);
3420				} else {
3421					collect_xdamage(scan_count, 0);
3422				}
3423			}
3424		}
3425	}
3426
3427#define SCAN_FATAL(x) \
3428	if (x < 0) { \
3429		scan_in_progress = 0; \
3430		fb_copy_in_progress = 0; \
3431		return 0; \
3432	}
3433
3434	/* scan with the initial y to the jitter value from scanlines: */
3435	scan_in_progress = 1;
3436	tile_count = scan_display(scanlines[scan_count], 0);
3437	SCAN_FATAL(tile_count);
3438
3439	/*
3440	 * we do the XDAMAGE here too since after scan_display()
3441	 * there is a better chance we have received the events from
3442	 * the X server (otherwise the DAMAGE events will be processed
3443	 * in the *next* call, usually too late and wasteful since
3444	 * the unchanged tiles are read in again).
3445	 */
3446	if (use_xdamage) {
3447#ifdef MACOSX
3448		if (macosx_console) {
3449			;
3450		} else
3451#endif
3452		{
3453			if (rawfb_vnc_reflect) {
3454				;
3455			} else {
3456				collect_xdamage(scan_count, 1);
3457			}
3458		}
3459	}
3460	if (count_only) {
3461		scan_in_progress = 0;
3462		fb_copy_in_progress = 0;
3463		return tile_count;
3464	}
3465
3466	if (xdamage_tile_count) {
3467		/* pick up "known" damaged tiles we missed in scan_display() */
3468		for (i=0; i < ntiles; i++) {
3469			if (tile_has_diff[i]) {
3470				continue;
3471			}
3472			if (tile_has_xdamage_diff[i]) {
3473				tile_has_diff[i] = 1;
3474				if (tile_has_xdamage_diff[i] == 1) {
3475					tile_has_xdamage_diff[i] = 2;
3476					tile_count++;
3477				}
3478			}
3479		}
3480	}
3481	if (dpy && use_xdamage == 1) {
3482		static time_t last_xd_check = 0;
3483		if (time(NULL) > last_xd_check + 2) {
3484			int cp = (scan_count + 3) % NSCAN;
3485			xd_do_check = 1;
3486			tile_count = scan_display(scanlines[cp], 0);
3487			xd_do_check = 0;
3488			SCAN_FATAL(tile_count);
3489			last_xd_check = time(NULL);
3490			if (xd_samples > 200) {
3491				static int bad = 0;
3492				if (xd_misses > (20 * xd_samples) / 100) {
3493					rfbLog("XDAMAGE is not working well... misses: %d/%d\n", xd_misses, xd_samples);
3494					rfbLog("Maybe an OpenGL app like Beryl or Compiz is the problem?\n");
3495					rfbLog("Use x11vnc -noxdamage or disable the Beryl/Compiz app.\n");
3496					rfbLog("To disable this check and warning specify -xdamage twice.\n");
3497					if (++bad >= 10) {
3498						rfbLog("XDAMAGE appears broken (OpenGL app?), turning it off.\n");
3499						use_xdamage = 0;
3500						initialize_xdamage();
3501						destroy_xdamage_if_needed();
3502					}
3503				}
3504				xd_samples = 0;
3505				xd_misses = 0;
3506			}
3507		}
3508	}
3509
3510	nap_set(tile_count);
3511
3512	if (fs_factor && frac1 >= fs_frac) {
3513		/* make frac1 < fs_frac if fullscreen updates are enabled */
3514		frac1 = fs_frac/2.0;
3515	}
3516
3517	if (tile_count > frac1 * ntiles) {
3518		/*
3519		 * many tiles have changed, so try a rescan (since it should
3520		 * be short compared to the many upcoming copy_tiles() calls)
3521		 */
3522
3523		/* this check is done to skip the extra scan_display() call */
3524		if (! fs_factor || tile_count <= fs_frac * ntiles) {
3525			int cp, tile_count_old = tile_count;
3526
3527			/* choose a different y shift for the 2nd scan: */
3528			cp = (NSCAN - scan_count) % NSCAN;
3529
3530			tile_count = scan_display(scanlines[cp], 1);
3531			SCAN_FATAL(tile_count);
3532
3533			if (tile_count >= (1 + frac2) * tile_count_old) {
3534				/* on a roll... do a 3rd scan */
3535				cp = (NSCAN - scan_count + 7) % NSCAN;
3536				tile_count = scan_display(scanlines[cp], 1);
3537				SCAN_FATAL(tile_count);
3538			}
3539		}
3540		scan_in_progress = 0;
3541
3542		/*
3543		 * At some number of changed tiles it is better to just
3544		 * copy the full screen at once.  I.e. time = c1 + m * r1
3545		 * where m is number of tiles, r1 is the copy_tiles()
3546		 * time, and c1 is the scan_display() time: for some m
3547		 * it crosses the full screen update time.
3548		 *
3549		 * We try to predict that crossover with the fs_frac
3550		 * fudge factor... seems to be about 1/2 the total number
3551		 * of tiles.  n.b. this ignores network bandwidth,
3552		 * compression time etc...
3553		 *
3554		 * Use -fs 1.0 to disable on slow links.
3555		 */
3556		if (fs_factor && tile_count > fs_frac * ntiles) {
3557			int cs;
3558			fb_copy_in_progress = 1;
3559			cs = copy_screen();
3560			fb_copy_in_progress = 0;
3561			SCAN_FATAL(cs);
3562			if (use_threads && pointer_mode != 1) {
3563				pointer_event(-1, 0, 0, NULL);
3564			}
3565			nap_check(tile_count);
3566			return tile_count;
3567		}
3568	}
3569	scan_in_progress = 0;
3570
3571	/* copy all tiles with differences from display to rfb framebuffer: */
3572	fb_copy_in_progress = 1;
3573
3574	if (single_copytile || tile_shm_count < ntiles_x) {
3575		/*
3576		 * Old way, copy I/O one tile at a time.
3577		 */
3578		old_copy_tile = 1;
3579	} else {
3580		/*
3581		 * New way, does runs of horizontal tiles at once.
3582		 * Note that below, for simplicity, the extra tile finding
3583		 * (e.g. copy_tiles_backward_pass) is done the old way.
3584		 */
3585		old_copy_tile = 0;
3586	}
3587
3588	if (unixpw_in_progress) return 0;
3589
3590/* XXX Y */
3591if (0 && tile_count > 20) print_tiles();
3592#if 0
3593dtmp = dnow();
3594#else
3595dtmp = 0.0;
3596#endif
3597
3598	if (old_copy_tile) {
3599		tile_diffs = copy_all_tiles();
3600	} else {
3601		tile_diffs = copy_all_tile_runs();
3602	}
3603	SCAN_FATAL(tile_diffs);
3604
3605#if 0
3606if (tile_count) fprintf(stderr, "XX copytile: %.4f  tile_count: %d\n", dnow() - dtmp, tile_count);
3607#endif
3608
3609	/*
3610	 * This backward pass for upward and left tiles complements what
3611	 * was done in copy_all_tiles() for downward and right tiles.
3612	 */
3613	tile_diffs = copy_tiles_backward_pass();
3614	SCAN_FATAL(tile_diffs);
3615
3616	if (tile_diffs > frac3 * ntiles) {
3617		/*
3618		 * we spent a lot of time in those copy_tiles, run
3619		 * another scan, maybe more of the screen changed.
3620		 */
3621		int cp = (NSCAN - scan_count + 13) % NSCAN;
3622
3623		scan_in_progress = 1;
3624		tile_count = scan_display(scanlines[cp], 1);
3625		SCAN_FATAL(tile_count);
3626		scan_in_progress = 0;
3627
3628		tile_diffs = copy_tiles_additional_pass();
3629		SCAN_FATAL(tile_diffs);
3630	}
3631
3632	/* Given enough tile diffs, try the islands: */
3633	if (grow_fill && tile_diffs > 4) {
3634		tile_diffs = grow_islands();
3635	}
3636	SCAN_FATAL(tile_diffs);
3637
3638	/* Given enough tile diffs, try the gaps: */
3639	if (gaps_fill && tile_diffs > 4) {
3640		tile_diffs = fill_tile_gaps();
3641	}
3642	SCAN_FATAL(tile_diffs);
3643
3644	fb_copy_in_progress = 0;
3645	if (use_threads && pointer_mode != 1) {
3646		/*
3647		 * tell the pointer handler it can process any queued
3648		 * pointer events:
3649		 */
3650		pointer_event(-1, 0, 0, NULL);
3651	}
3652
3653	if (blackouts) {
3654		/* ignore any diffs in completely covered tiles */
3655		int x, y, n;
3656		for (y=0; y < ntiles_y; y++) {
3657			for (x=0; x < ntiles_x; x++) {
3658				n = x + y * ntiles_x;
3659				if (tile_blackout[n].cover == 2) {
3660					tile_has_diff[n] = 0;
3661				}
3662			}
3663		}
3664	}
3665
3666	hint_updates();	/* use x0rfbserver hints algorithm */
3667
3668	/* Work around threaded rfbProcessClientMessage() calls timeouts */
3669	if (use_threads) {
3670		ping_clients(tile_diffs);
3671	} else if (saw_ultra_chat || saw_ultra_file) {
3672		ping_clients(-1);
3673	} else if (use_openssl && !tile_diffs) {
3674		ping_clients(0);
3675	}
3676	/* -ping option: */
3677	if (ping_interval) {
3678		int td = ping_interval > 0 ? ping_interval : -ping_interval;
3679		ping_clients(-td);
3680	}
3681
3682
3683	nap_check(tile_diffs);
3684	return tile_diffs;
3685}
3686
3687
3688