Initial git import
[sxemacs] / src / ui / redisplay-output.c
1 /* Synchronize redisplay structures and output changes.
2    Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
3    Copyright (C) 1995, 1996 Ben Wing.
4    Copyright (C) 1996 Chuck Thompson.
5    Copyright (C) 1999, 2002 Andy Piper.
6
7 This file is part of SXEmacs
8
9 SXEmacs is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 SXEmacs is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
21
22
23 /* Synched up with: Not in FSF. */
24
25 /* This file has been Mule-ized. */
26
27 /* Author: Chuck Thompson */
28
29 /* Heavily hacked for modularity, gutter and subwindow support by Andy
30    Piper. */
31
32 #include <config.h>
33 #include "lisp.h"
34
35 #include "buffer.h"
36 #include "window.h"
37 #include "frame.h"
38 #include "device.h"
39 #include "glyphs.h"
40 #include "redisplay.h"
41 #include "faces.h"
42 #include "gutter.h"
43
44 static int compare_runes(struct window *w, struct rune *crb, struct rune *drb);
45 static void redraw_cursor_in_window(struct window *w, int run_end_begin_glyphs);
46 static void redisplay_output_display_block(struct window *w,
47                                            struct display_line *dl, int block,
48                                            int start, int end, int start_pixpos,
49                                            int cursor_start, int cursor_width,
50                                            int cursor_height);
51 static void redisplay_normalize_display_box(struct display_box *dest,
52                                             struct display_glyph_area *src);
53 static int redisplay_display_boxes_in_window_p(struct window *w,
54                                                struct display_box *db,
55                                                struct display_glyph_area *dga);
56 static void redisplay_clear_clipped_region(Lisp_Object locale,
57                                            face_index findex,
58                                            struct display_box *dest,
59                                            struct display_glyph_area *glyphsrc,
60                                            int fullheight_p, Lisp_Object);
61
62 /*****************************************************************************
63  sync_rune_structs
64
65  Synchronize the given rune blocks.
66  ****************************************************************************/
67 static void
68 sync_rune_structs(struct window *w, rune_dynarr * cra, rune_dynarr * dra)
69 {
70         int rune_elt;
71         int max_move = ((Dynarr_length(dra) > Dynarr_largest(cra))
72                         ? Dynarr_largest(cra)
73                         : Dynarr_length(dra));
74
75         if (max_move) {
76                 /* #### Doing this directly breaks the encapsulation.  But, the
77                    running time of this function has a measurable impact on
78                    redisplay performance so avoiding all excess overhead is a
79                    good thing.  Is all of this true? */
80                 memcpy(cra->base, dra->base, sizeof(struct rune) * max_move);
81                 Dynarr_set_size(cra, max_move);
82         } else
83                 Dynarr_reset(cra);
84
85         for (rune_elt = max_move; rune_elt < Dynarr_length(dra); rune_elt++) {
86                 struct rune rb, *crb;
87                 struct rune *drb = Dynarr_atp(dra, rune_elt);
88
89                 crb = &rb;
90                 memcpy(crb, drb, sizeof(struct rune));
91                 Dynarr_add(cra, *crb);
92         }
93 }
94
95 /*****************************************************************************
96  sync_display_line_structs
97
98  For the given LINE in window W, make the current display line equal
99  the desired display line.
100  ****************************************************************************/
101 void
102 sync_display_line_structs(struct window *w, int line, int do_blocks,
103                           display_line_dynarr * cdla,
104                           display_line_dynarr * ddla)
105 {
106         int cdla_len = Dynarr_length(cdla);
107
108         struct display_line dl, *clp, *dlp;
109         int db_elt;
110
111         dlp = Dynarr_atp(ddla, line);
112         if (line >= Dynarr_largest(cdla)) {
113                 clp = &dl;
114                 clp->display_blocks = Dynarr_new(display_block);
115         } else {
116                 clp = Dynarr_atp(cdla, line);
117                 if (clp->display_blocks)
118                         Dynarr_reset(clp->display_blocks);
119                 if (clp->left_glyphs) {
120                         Dynarr_free(clp->left_glyphs);
121                         clp->left_glyphs = 0;
122                 }
123                 if (clp->right_glyphs) {
124                         Dynarr_free(clp->right_glyphs);
125                         clp->right_glyphs = 0;
126                 }
127         }
128         {
129                 display_block_dynarr *tdb = clp->display_blocks;
130
131                 memcpy(clp, dlp, sizeof(struct display_line));
132                 clp->display_blocks = tdb;
133                 clp->left_glyphs = 0;
134                 clp->right_glyphs = 0;
135         }
136
137         if (!do_blocks && line >= cdla_len) {
138                 Dynarr_add(cdla, *clp);
139                 return;
140         }
141
142         for (db_elt = 0; db_elt < Dynarr_length(dlp->display_blocks); db_elt++) {
143                 struct display_block db, *cdb;
144                 struct display_block *ddb =
145                     Dynarr_atp(dlp->display_blocks, db_elt);
146
147                 if (db_elt >= Dynarr_largest(clp->display_blocks)) {
148                         cdb = &db;
149                         memcpy(cdb, ddb, sizeof(struct display_block));
150                         cdb->runes = Dynarr_new(rune);
151                         Dynarr_add(clp->display_blocks, *cdb);
152                 } else {
153                         rune_dynarr *tr;
154
155                         cdb = Dynarr_atp(clp->display_blocks, db_elt);
156                         tr = cdb->runes;
157                         memcpy(cdb, ddb, sizeof(struct display_block));
158                         cdb->runes = tr;
159                         Dynarr_increment(clp->display_blocks);
160                 }
161
162                 sync_rune_structs(w, cdb->runes, ddb->runes);
163         }
164
165         if (line >= cdla_len)
166                 Dynarr_add(cdla, *clp);
167 }
168
169 /*****************************************************************************
170  compare_runes
171
172  Compare two runes to see if each of their fields is equal.  If so,
173  return true otherwise return false.
174  ****************************************************************************/
175 static int compare_runes(struct window *w, struct rune *crb, struct rune *drb)
176 {
177         /* Do not compare the values of bufpos and endpos.  They do not
178            affect the display characteristics. */
179
180         /* Note: (hanoi 6) spends 95% of its time in redisplay, and about
181            30% here. Not using bitfields for rune.type alone gives a redisplay
182            speed up of 10%.
183
184            #### In profile arcs run of a normal Gnus session this function
185            is run 6.76 million times, only to return 1 in 6.73 million of
186            those.
187
188            In addition a quick look GCC sparc assembly shows that GCC is not
189            doing a good job here.
190            1. The function is not inlined (too complicated?)
191            2. It seems to be reloading the crb and drb variables all the
192            time.
193            3. It doesn't seem to notice that the second half of these if's
194            are really a switch statement.
195
196            So I (JV) conjecture
197
198            #### It would really be worth it to arrange for this function to
199            be (almost) a single call to memcmp. */
200
201         if (crb->xpos != drb->xpos)
202                 return 0;
203         else if (crb->width != drb->width)
204                 return 0;
205         else if (crb->cursor_type != drb->cursor_type)
206                 return 0;
207         else if (crb->type != drb->type)
208                 return 0;
209         else if (crb->type == RUNE_CHAR &&
210                  (crb->object.chr.ch != drb->object.chr.ch))
211                 return 0;
212         else if (crb->type == RUNE_HLINE &&
213                  (crb->object.hline.thickness != drb->object.hline.thickness ||
214                   crb->object.hline.yoffset != drb->object.hline.yoffset))
215                 return 0;
216         else if (crb->type == RUNE_DGLYPH &&
217                  (!EQ(crb->object.dglyph.glyph, drb->object.dglyph.glyph) ||
218                   !EQ(crb->object.dglyph.extent, drb->object.dglyph.extent) ||
219                   crb->object.dglyph.xoffset != drb->object.dglyph.xoffset ||
220                   crb->object.dglyph.yoffset != drb->object.dglyph.yoffset ||
221                   crb->object.dglyph.ascent != drb->object.dglyph.ascent ||
222                   crb->object.dglyph.descent != drb->object.dglyph.descent))
223                 return 0;
224         /* Only check dirtiness if we know something has changed. */
225         else if (crb->type == RUNE_DGLYPH &&
226                  (XGLYPH_DIRTYP(crb->object.dglyph.glyph) ||
227                   crb->findex != drb->findex)) {
228                 /* We need some way of telling redisplay_output_layout () that the
229                    only reason we are outputting it is because something has
230                    changed internally. That way we can optimize whether we need
231                    to clear the layout first and also only output the components
232                    that have changed. The image_instance dirty flag and
233                    display_hash are no good to us because these will invariably
234                    have been set anyway if the layout has changed. So it looks
235                    like we need yet another change flag that we can set here and
236                    then clear in redisplay_output_layout (). */
237                 Lisp_Object window, image;
238                 Lisp_Image_Instance *ii;
239                 XSETWINDOW(window, w);
240                 image = glyph_image_instance(crb->object.dglyph.glyph,
241                                              window, ERROR_ME_NOT, 1);
242
243                 if (!IMAGE_INSTANCEP(image))
244                         return 0;
245                 ii = XIMAGE_INSTANCE(image);
246
247                 if (TEXT_IMAGE_INSTANCEP(image) &&
248                     (crb->findex != drb->findex ||
249                      WINDOW_FACE_CACHEL_DIRTY(w, drb->findex)))
250                         return 0;
251
252                 /* It is quite common for the two glyphs to be EQ since in many
253                    cases they will actually be the same object. This does not
254                    mean, however, that nothing has changed. We therefore need to
255                    check the current hash of the glyph against the last recorded
256                    display hash and the pending display items. See
257                    update_subwindow (). */
258                 if (image_instance_changed(image) ||
259                     crb->findex != drb->findex ||
260                     WINDOW_FACE_CACHEL_DIRTY(w, drb->findex)) {
261                         /* Now we are going to re-output the glyph, but since
262                            this is for some internal reason not related to geometry
263                            changes, send a hint to the output routines that they can
264                            take some short cuts. This is most useful for
265                            layouts. This flag should get reset by the output
266                            routines.
267
268                            #### It is possible for us to get here when the
269                            face_cachel is dirty. I do not know what the implications
270                            of this are. */
271                         IMAGE_INSTANCE_OPTIMIZE_OUTPUT(ii) = 1;
272                         return 0;
273                 } else
274                         return 1;
275         }
276         /* We now do this last so that glyph checks can do their own thing
277            for face changes. Face changes quite often happen when we are
278            trying to output something in the gutter, this would normally
279            lead to a lot of flashing. The indices can quite often be
280            different and yet the faces are the same, we do not want to
281            re-output in this instance. */
282         else if (crb->findex != drb->findex ||
283                  WINDOW_FACE_CACHEL_DIRTY(w, drb->findex))
284                 return 0;
285         else
286                 return 1;
287 }
288
289 /*****************************************************************************
290  get_next_display_block
291
292  Return the next display starting at or overlapping START_POS.  Return
293  the start of the next region in NEXT_START.
294  ****************************************************************************/
295 int
296 get_next_display_block(layout_bounds bounds, display_block_dynarr * dba,
297                        int start_pos, int *next_start)
298 {
299         int next_display_block = NO_BLOCK;
300         int priority = -1;
301         int block;
302
303         /* If we don't find a display block covering or starting at
304            start_pos, then we return the starting point of the next display
305            block or the next division boundary, whichever is closer to
306            start_pos. */
307         if (next_start) {
308                 if (start_pos >= bounds.left_out && start_pos < bounds.left_in)
309                         *next_start = bounds.left_in;
310                 else if (start_pos < bounds.left_white)
311                         *next_start = bounds.left_white;
312                 else if (start_pos < bounds.right_white)
313                         *next_start = bounds.right_white;
314                 else if (start_pos < bounds.right_in)
315                         *next_start = bounds.right_in;
316                 else if (start_pos <= bounds.right_out)
317                         *next_start = bounds.right_out;
318                 else
319                         abort();
320         }
321
322         for (block = 0; block < Dynarr_length(dba); block++) {
323                 struct display_block *db = Dynarr_atp(dba, block);
324
325                 if (db->start_pos <= start_pos && db->end_pos > start_pos) {
326                         if ((int)db->type > priority) {
327                                 priority = db->type;
328                                 next_display_block = block;
329                                 if (next_start)
330                                         *next_start = db->end_pos;
331                         }
332                 } else if (next_start && db->start_pos > start_pos) {
333                         if (db->start_pos < *next_start)
334                                 *next_start = db->start_pos;
335                 }
336         }
337
338         return next_display_block;
339 }
340
341 /*****************************************************************************
342  get_cursor_size_and_location
343
344  Return the information defining the pixel location of the cursor.
345  ****************************************************************************/
346 static void
347 get_cursor_size_and_location(struct window *w, struct display_block *db,
348                              int cursor_location,
349                              int *cursor_start, int *cursor_width,
350                              int *cursor_height)
351 {
352         struct rune *rb;
353         Lisp_Object window;
354         int defheight, defwidth;
355
356         if (Dynarr_length(db->runes) <= cursor_location)
357                 abort();
358
359         XSETWINDOW(window, w);
360
361         rb = Dynarr_atp(db->runes, cursor_location);
362         *cursor_start = rb->xpos;
363
364         default_face_height_and_width(window, &defheight, &defwidth);
365         *cursor_height = defheight;
366
367         if (rb->type == RUNE_BLANK)
368                 *cursor_width = defwidth;
369         else
370                 *cursor_width = rb->width;
371 }
372
373 /*****************************************************************************
374  compare_display_blocks
375
376  Given two display blocks, output only those areas where they differ.
377  ****************************************************************************/
378 static int
379 compare_display_blocks(struct window *w, struct display_line *cdl,
380                        struct display_line *ddl, int c_block, int d_block,
381                        int start_pixpos, int cursor_start, int cursor_width,
382                        int cursor_height)
383 {
384         struct frame *f = XFRAME(w->frame);
385         struct display_block *cdb, *ddb;
386         int start_pos;
387         int stop_pos;
388         int force = 0;
389         int block_end;
390
391         cdb = Dynarr_atp(cdl->display_blocks, c_block);
392         ddb = Dynarr_atp(ddl->display_blocks, d_block);
393
394         assert(cdb->type == ddb->type);
395
396         start_pos = -1;
397         stop_pos = min(Dynarr_length(cdb->runes), Dynarr_length(ddb->runes));
398
399         block_end = (!Dynarr_length(ddb->runes)
400                      ? 0
401                      : (Dynarr_atp(ddb->runes, Dynarr_length(ddb->runes) - 1)->
402                         xpos + Dynarr_atp(ddb->runes,
403                                           Dynarr_length(ddb->runes) -
404                                           1)->width));
405
406         /* If the new block type is not text and the cursor status is
407            changing and it overlaps the position of this block then force a
408            full redraw of the block in order to make sure that the cursor is
409            updated properly. */
410         if (ddb->type != TEXT
411 #if 0
412             /* I'm not sure exactly what this code wants to do, but it's
413              * not right--it doesn't update when cursor_elt changes from, e.g.,
414              * 0 to 8, and the new or old cursor loc overlaps this block.
415              * I've replaced it with the more conservative test below.
416              * -dkindred@cs.cmu.edu 23-Mar-1997 */
417             && ((cdl->cursor_elt == -1 && ddl->cursor_elt != -1)
418                 || (cdl->cursor_elt != -1 && ddl->cursor_elt == -1))
419             && (ddl->cursor_elt == -1 ||
420                 (cursor_start
421                  && cursor_width
422                  && (cursor_start + cursor_width) >= start_pixpos
423                  && cursor_start <= block_end))
424 #else
425             && (cdl->cursor_elt != ddl->cursor_elt)
426 #endif
427             )
428                 force = 1;
429
430         if (f->windows_structure_changed ||
431             /* #### Why is this so? We have face cachels so that we don't
432                have to recalculate all the display blocks when faces
433                change. I have fixed this for glyphs and am inclined to think
434                that faces should "Just Work", but I'm not feeling brave
435                today. Maybe its because the face cachels represent merged
436                faces rather than simply instantiations in a particular
437                domain. */
438             f->faces_changed ||
439             cdl->ypos != ddl->ypos ||
440             cdl->ascent != ddl->ascent ||
441             cdl->descent != ddl->descent || cdl->clip != ddl->clip || force) {
442                 start_pos = 0;
443                 force = 1;
444         } else {
445                 int elt = 0;
446
447                 while (start_pos < 0 && elt < stop_pos) {
448                         if (!compare_runes(w, Dynarr_atp(cdb->runes, elt),
449                                            Dynarr_atp(ddb->runes, elt))) {
450                                 start_pos = elt;
451                         } else {
452                                 elt++;
453                         }
454                 }
455
456                 /* If nothing has changed in the area where the blocks overlap, but
457                    there are new blocks in the desired block, then adjust the start
458                    point accordingly. */
459                 if (elt == stop_pos && stop_pos < Dynarr_length(ddb->runes))
460                         start_pos = stop_pos;
461         }
462
463         if (start_pos >= 0) {
464                 if ((Dynarr_length(ddb->runes) != Dynarr_length(cdb->runes))
465                     || force) {
466                         stop_pos = Dynarr_length(ddb->runes);
467                 } else {
468                         /* If the lines have the same number of runes and we are not
469                            forcing a full redraw because the display line has
470                            changed position then we try and optimize how much of the
471                            line we actually redraw by scanning backwards from the
472                            end for the first changed rune.  This optimization is
473                            almost always triggered by face changes. */
474
475                         int elt = Dynarr_length(ddb->runes) - 1;
476
477                         while (elt > start_pos) {
478                                 if (!compare_runes
479                                     (w, Dynarr_atp(cdb->runes, elt),
480                                      Dynarr_atp(ddb->runes, elt)))
481                                         break;
482                                 else
483                                         elt--;
484                         }
485                         stop_pos = elt + 1;
486                 }
487
488                 redisplay_output_display_block(w, ddl, d_block, start_pos,
489                                                stop_pos, start_pixpos,
490                                                cursor_start, cursor_width,
491                                                cursor_height);
492                 return 1;
493         }
494
495         return 0;
496 }
497
498 /*****************************************************************************
499  clear_left_border
500
501  Clear the lefthand outside border.
502  ****************************************************************************/
503 static void clear_left_border(struct window *w, int y, int height)
504 {
505         struct frame *f = XFRAME(w->frame);
506         Lisp_Object window;
507
508         XSETWINDOW(window, w);
509         redisplay_clear_region(window, DEFAULT_INDEX,
510                                FRAME_LEFT_BORDER_START(f), y,
511                                FRAME_BORDER_WIDTH(f), height);
512 }
513
514 /*****************************************************************************
515  clear_right_border
516
517  Clear the righthand outside border.
518  ****************************************************************************/
519 static void clear_right_border(struct window *w, int y, int height)
520 {
521         struct frame *f = XFRAME(w->frame);
522         Lisp_Object window;
523
524         XSETWINDOW(window, w);
525         redisplay_clear_region(window, DEFAULT_INDEX,
526                                FRAME_RIGHT_BORDER_START(f),
527                                y, FRAME_BORDER_WIDTH(f), height);
528 }
529
530 /*****************************************************************************
531  output_display_line
532
533  Ensure that the contents of the given display line is correct
534  on-screen.  The force_ parameters are used by redisplay_move_cursor
535  to correctly update cursor locations and only cursor locations.
536  ****************************************************************************/
537 void
538 output_display_line(struct window *w, display_line_dynarr * cdla,
539                     display_line_dynarr * ddla, int line, int force_start,
540                     int force_end)
541 {
542         struct frame *f = XFRAME(w->frame);
543         struct buffer *b = XBUFFER(w->buffer);
544         struct buffer *old_b = window_display_buffer(w);
545         struct display_line *cdl, *ddl;
546         display_block_dynarr *cdba, *ddba;
547         int start_pixpos, end_pixpos;
548         int cursor_start, cursor_width, cursor_height;
549
550         int force = (force_start >= 0 || force_end >= 0);
551         int clear_border = 0;
552         int must_sync = 0;
553
554         if (cdla && line < Dynarr_length(cdla)) {
555                 cdl = Dynarr_atp(cdla, line);
556                 cdba = cdl->display_blocks;
557         } else {
558                 cdl = NULL;
559                 cdba = NULL;
560         }
561
562         ddl = Dynarr_atp(ddla, line);   /* assert line < Dynarr_length (ddla) */
563         ddba = ddl->display_blocks;
564
565         if (force_start >= 0 && force_start >= ddl->bounds.left_out)
566                 start_pixpos = force_start;
567         else
568                 start_pixpos = ddl->bounds.left_out;
569
570         if (force_end >= 0 && force_end < ddl->bounds.right_out)
571                 end_pixpos = force_end;
572         else
573                 end_pixpos = ddl->bounds.right_out;
574
575         /* Get the cursor parameters. */
576         if (ddl->cursor_elt != -1) {
577                 struct display_block *db;
578
579                 /* If the lines cursor parameter is not -1 then it indicates
580                    which rune in the TEXT block contains the cursor.  This means
581                    that there must be at least one display block.  The TEXT
582                    block, if present, must always be the first display block. */
583                 assert(Dynarr_length(ddba) != 0);
584
585                 db = Dynarr_atp(ddba, 0);
586                 assert(db->type == TEXT);
587
588                 get_cursor_size_and_location(w, db, ddl->cursor_elt,
589                                              &cursor_start, &cursor_width,
590                                              &cursor_height);
591         } else {
592                 cursor_start = cursor_width = cursor_height = 0;
593         }
594
595         /* The modeline should only have a single block and it had better be
596            a TEXT block. */
597         if (ddl->modeline) {
598                 /* The shadow thickness check is necessary if only the sign of
599                    the size changed. */
600                 if (cdba && !w->shadow_thickness_changed) {
601                         must_sync |= compare_display_blocks(w, cdl, ddl, 0, 0,
602                                                             start_pixpos, 0, 0,
603                                                             0);
604                 } else {
605                         redisplay_output_display_block(w, ddl, 0, 0, -1,
606                                                        start_pixpos, 0, 0, 0);
607                         must_sync = 1;
608                 }
609
610                 if (must_sync)
611                         clear_border = 1;
612         }
613
614         while (!ddl->modeline && start_pixpos < end_pixpos) {
615                 int block;
616                 int next_start_pixpos = 0;
617
618                 block = get_next_display_block(ddl->bounds, ddba, start_pixpos,
619                                                &next_start_pixpos);
620
621                 /* If we didn't find a block then we should blank the area
622                    between start_pos and next_start if necessary. */
623                 if (block == NO_BLOCK) {
624                         /* We only erase those areas which were actually previously
625                            covered by a display block unless the window structure
626                            changed.  In that case we clear all areas since the current
627                            structures may actually represent a different buffer. */
628                         while (start_pixpos < next_start_pixpos) {
629                                 int block_end = 0;
630                                 int old_block = 0;
631
632                                 if (cdba)
633                                         old_block =
634                                             get_next_display_block(ddl->bounds,
635                                                                    cdba,
636                                                                    start_pixpos,
637                                                                    &block_end);
638                                 else {
639                                         old_block = NO_BLOCK;
640                                         block_end = next_start_pixpos;
641                                 }
642
643                                 if (!cdba || old_block != NO_BLOCK || b != old_b
644                                     || f->windows_structure_changed
645                                     || f->faces_changed || force || (cdl
646                                                                      && (cdl->
647                                                                          ypos !=
648                                                                          ddl->
649                                                                          ypos
650                                                                          ||
651                                                                          cdl->
652                                                                          ascent
653                                                                          !=
654                                                                          ddl->
655                                                                          ascent
656                                                                          ||
657                                                                          cdl->
658                                                                          descent
659                                                                          !=
660                                                                          ddl->
661                                                                          descent
662                                                                          ||
663                                                                          cdl->
664                                                                          top_clip
665                                                                          !=
666                                                                          ddl->
667                                                                          top_clip
668                                                                          ||
669                                                                          cdl->
670                                                                          clip !=
671                                                                          ddl->
672                                                                          clip)))
673                                 {
674                                         int x, y, width, height;
675                                         face_index findex;
676
677                                         must_sync = 1;
678                                         x = start_pixpos;
679                                         y = DISPLAY_LINE_YPOS(ddl);
680                                         width =
681                                             min(next_start_pixpos,
682                                                 block_end) - x;
683                                         height = DISPLAY_LINE_HEIGHT(ddl);
684
685                                         if (x < ddl->bounds.left_in) {
686                                                 findex =
687                                                     ddl->
688                                                     left_margin_findex ? ddl->
689                                                     left_margin_findex :
690                                                     get_builtin_face_cache_index
691                                                     (w, Vleft_margin_face);
692                                         } else if (x < ddl->bounds.right_in) {
693                                                 /* no check here because DEFAULT_INDEX == 0 anyway */
694                                                 findex = ddl->default_findex;
695                                         } else if (x < ddl->bounds.right_out) {
696                                                 findex =
697                                                     ddl->
698                                                     right_margin_findex ? ddl->
699                                                     right_margin_findex :
700                                                     get_builtin_face_cache_index
701                                                     (w, Vright_margin_face);
702                                         } else
703                                                 findex = (face_index) - 1;
704
705                                         if (findex != (face_index) - 1) {
706                                                 Lisp_Object window;
707
708                                                 XSETWINDOW(window, w);
709
710                                                 /* Clear the empty area. */
711                                                 redisplay_clear_region(window,
712                                                                        findex,
713                                                                        x, y,
714                                                                        width,
715                                                                        height);
716
717                                                 /* Mark that we should clear the border.  This is
718                                                    necessary because italic fonts may leave
719                                                    droppings in the border. */
720                                                 clear_border = 1;
721                                         }
722                                 }
723
724                                 start_pixpos =
725                                     min(next_start_pixpos, block_end);
726                         }
727                 } else {
728                         struct display_block *cdb, *ddb;
729                         int block_end = 0;
730                         int old_block = 0;
731
732                         if (cdba)
733                                 old_block =
734                                     get_next_display_block(ddl->bounds, cdba,
735                                                            start_pixpos,
736                                                            &block_end);
737                         else
738                                 old_block = NO_BLOCK;
739
740                         ddb = Dynarr_atp(ddba, block);
741                         cdb =
742                             (old_block !=
743                              NO_BLOCK ? Dynarr_atp(cdba, old_block) : 0);
744
745                         /* If there was formerly no block over the current
746                            region or if it was a block of a different type, then
747                            output the entire ddb.  Otherwise, compare cdb and
748                            ddb and output only the changed region. */
749                         if (!force && cdb && ddb->type == cdb->type
750                             /* If there was no buffer being display before the
751                                compare anyway as we might be outputting a gutter. */
752                             && (b == old_b || !old_b)) {
753                                 must_sync |=
754                                     compare_display_blocks(w, cdl, ddl,
755                                                            old_block, block,
756                                                            start_pixpos,
757                                                            cursor_start,
758                                                            cursor_width,
759                                                            cursor_height);
760                         } else {
761                                 int elt;
762                                 int first_elt = 0;
763                                 int last_elt = -1;
764
765                                 for (elt = 0; elt < Dynarr_length(ddb->runes);
766                                      elt++) {
767                                         struct rune *rb =
768                                             Dynarr_atp(ddb->runes, elt);
769
770                                         if (start_pixpos >= rb->xpos
771                                             && start_pixpos <
772                                             rb->xpos + rb->width)
773                                                 first_elt = elt;
774
775                                         if (end_pixpos > rb->xpos
776                                             && end_pixpos <=
777                                             rb->xpos + rb->width) {
778                                                 last_elt = elt + 1;
779                                                 if (last_elt >
780                                                     Dynarr_length(ddb->runes))
781                                                         last_elt =
782                                                             Dynarr_length(ddb->
783                                                                           runes);
784                                                 break;
785                                         }
786                                 }
787
788                                 must_sync = 1;
789                                 redisplay_output_display_block(w, ddl, block,
790                                                                first_elt,
791                                                                last_elt,
792                                                                start_pixpos,
793                                                                cursor_start,
794                                                                cursor_width,
795                                                                cursor_height);
796                         }
797
798                         start_pixpos = next_start_pixpos;
799                 }
800         }
801
802         /* Clear the internal border if we are next to it and the window
803            structure or frame size has changed or if something caused
804            clear_border to be tripped.  */
805         /* #### Doing this on f->clear sucks but is necessary because of
806            window-local background values. */
807         if (f->windows_structure_changed || f->faces_changed || clear_border
808             || f->clear) {
809                 int y = DISPLAY_LINE_YPOS(ddl);
810                 int height = DISPLAY_LINE_HEIGHT(ddl);
811
812                 /* If we are in the gutter then we musn't clear the borders. */
813                 if (y >= WINDOW_TEXT_TOP(w)
814                     && (y + height) <= WINDOW_TEXT_BOTTOM(w)) {
815                         if (ddl->modeline) {
816                                 y -= MODELINE_SHADOW_THICKNESS(w);
817                                 height += (2 * MODELINE_SHADOW_THICKNESS(w));
818                         }
819
820                         if (window_is_leftmost(w))
821                                 clear_left_border(w, y, height);
822                         if (window_is_rightmost(w))
823                                 clear_right_border(w, y, height);
824                 }
825         }
826
827         if (cdla)
828                 sync_display_line_structs(w, line, must_sync, cdla, ddla);
829 }
830
831 /*****************************************************************************
832  redisplay_move_cursor
833
834  For the given window W, move the cursor to NEW_POINT.  Returns a
835  boolean indicating success or failure.
836  ****************************************************************************/
837
838 #define ADJ_BUFPOS (rb->bufpos + dl->offset)
839 #define ADJ_ENDPOS (rb->endpos + dl->offset)
840
841 int redisplay_move_cursor(struct window *w, Bufpos new_point, int no_output_end)
842 {
843         struct frame *f = XFRAME(w->frame);
844         struct device *d = XDEVICE(f->device);
845
846         display_line_dynarr *cla = window_display_lines(w, CURRENT_DISP);
847         struct display_line *dl;
848         struct display_block *db;
849         struct rune *rb;
850         int x = w->last_point_x[CURRENT_DISP];
851         int y = w->last_point_y[CURRENT_DISP];
852
853         /*
854          * Bail if cursor_in_echo_area is non-zero and we're fiddling with
855          * the cursor in a non-active minibuffer window, since that is a
856          * special case that is handled elsewhere and this function need
857          * not handle it.  Return 1 so the caller will assume we
858          * succeeded.
859          */
860         if (cursor_in_echo_area && MINI_WINDOW_P(w) &&
861             w != XWINDOW(FRAME_SELECTED_WINDOW(f)))
862                 return 1;
863
864         if (y < 0 || y >= Dynarr_length(cla))
865                 return 0;
866
867         dl = Dynarr_atp(cla, y);
868         db = get_display_block_from_line(dl, TEXT);
869
870         if (x < 0 || x >= Dynarr_length(db->runes))
871                 return 0;
872
873         rb = Dynarr_atp(db->runes, x);
874
875         if (rb->cursor_type == CURSOR_OFF)
876                 return 0;
877         else if (ADJ_BUFPOS == new_point
878                  || (ADJ_ENDPOS && (new_point >= ADJ_BUFPOS)
879                      && (new_point <= ADJ_ENDPOS))) {
880                 w->last_point_x[CURRENT_DISP] = x;
881                 w->last_point_y[CURRENT_DISP] = y;
882                 Fset_marker(w->last_point[CURRENT_DISP], make_int(ADJ_BUFPOS),
883                             w->buffer);
884                 dl->cursor_elt = x;
885                 return 1;
886         } else {
887                 {
888                         MAYBE_DEVMETH(d, frame_output_begin, (f));
889                         MAYBE_DEVMETH(d, window_output_begin, (w));
890                 }
891                 rb->cursor_type = CURSOR_OFF;
892                 dl->cursor_elt = -1;
893                 output_display_line(w, 0, cla, y, rb->xpos,
894                                     rb->xpos + rb->width);
895         }
896
897         w->last_point_x[CURRENT_DISP] = -1;
898         w->last_point_y[CURRENT_DISP] = -1;
899         Fset_marker(w->last_point[CURRENT_DISP], Qnil, w->buffer);
900
901         /* If this isn't the selected frame, then erasing the old cursor is
902            all we actually had to do. */
903         if (w != XWINDOW(FRAME_SELECTED_WINDOW(device_selected_frame(d)))) {
904                 if (!no_output_end) {
905                         MAYBE_DEVMETH(d, window_output_end, (w));
906                         MAYBE_DEVMETH(d, frame_output_end, (f));
907                 }
908
909                 return 1;
910         }
911
912         /* This should only occur in the minibuffer. */
913         if (new_point == 0) {
914                 w->last_point_x[CURRENT_DISP] = 0;
915                 w->last_point_y[CURRENT_DISP] = y;
916                 Fset_marker(w->last_point[CURRENT_DISP], Qzero, w->buffer);
917
918                 rb = Dynarr_atp(db->runes, 0);
919                 rb->cursor_type = CURSOR_ON;
920                 dl->cursor_elt = 0;
921
922                 output_display_line(w, 0, cla, y, rb->xpos,
923                                     rb->xpos + rb->width);
924
925                 if (!no_output_end) {
926                         MAYBE_DEVMETH(d, window_output_end, (w));
927                         MAYBE_DEVMETH(d, frame_output_end, (f));
928                 }
929                 return 1;
930         } else {
931                 int cur_rb = 0;
932                 int first = 0;
933                 int cur_dl, up;
934
935                 if (ADJ_BUFPOS < new_point) {
936                         up = 1;
937                         cur_rb = x + 1;
938                         cur_dl = y;
939                 } else {        /* (rb->bufpos + dl->offset) > new_point */
940
941                         up = 0;
942
943                         if (!x) {
944                                 cur_dl = y - 1;
945                                 first = 0;
946                         } else {
947                                 cur_rb = x - 1;
948                                 cur_dl = y;
949                                 first = 1;
950                         }
951                 }
952
953                 while (up ? (cur_dl < Dynarr_length(cla)) : (cur_dl >= 0)) {
954                         dl = Dynarr_atp(cla, cur_dl);
955                         db = get_display_block_from_line(dl, TEXT);
956
957                         if (!up && !first)
958                                 cur_rb = Dynarr_length(db->runes) - 1;
959
960                         while ((!scroll_on_clipped_lines || !dl->clip) &&
961                                (up ? (cur_rb < Dynarr_length(db->runes))
962                                 : (cur_rb >= 0))) {
963                                 rb = Dynarr_atp(db->runes, cur_rb);
964
965                                 if (rb->cursor_type != IGNORE_CURSOR
966                                     && rb->cursor_type != NO_CURSOR &&
967                                     (ADJ_BUFPOS == new_point
968                                      || (ADJ_ENDPOS && (new_point >= ADJ_BUFPOS)
969                                          && (new_point <= ADJ_BUFPOS)))) {
970                                         rb->cursor_type = CURSOR_ON;
971                                         dl->cursor_elt = cur_rb;
972
973                                         output_display_line(w, 0, cla, cur_dl,
974                                                             rb->xpos,
975                                                             rb->xpos +
976                                                             rb->width);
977
978                                         w->last_point_x[CURRENT_DISP] = cur_rb;
979                                         w->last_point_y[CURRENT_DISP] = cur_dl;
980                                         Fset_marker(w->last_point[CURRENT_DISP],
981                                                     make_int(ADJ_BUFPOS),
982                                                     w->buffer);
983
984                                         if (!no_output_end) {
985                                                 MAYBE_DEVMETH(d,
986                                                               window_output_end,
987                                                               (w));
988                                                 MAYBE_DEVMETH(d,
989                                                               frame_output_end,
990                                                               (f));
991                                         }
992                                         return 1;
993                                 }
994
995                                 (up ? cur_rb++ : cur_rb--);
996                         }
997
998                         (up ? (cur_rb = 0) : (first = 0));
999                         (up ? cur_dl++ : cur_dl--);
1000                 }
1001         }
1002
1003         if (!no_output_end) {
1004                 MAYBE_DEVMETH(d, window_output_end, (w));
1005                 MAYBE_DEVMETH(d, frame_output_end, (f));
1006         }
1007         return 0;
1008 }
1009
1010 #undef ADJ_BUFPOS
1011 #undef ADJ_ENDPOS
1012
1013 /*****************************************************************************
1014  redraw_cursor_in_window
1015
1016  For the given window W, redraw the cursor if it is contained within
1017  the window.
1018  ****************************************************************************/
1019 static void redraw_cursor_in_window(struct window *w, int run_end_begin_meths)
1020 {
1021         struct frame *f = XFRAME(w->frame);
1022         struct device *d = XDEVICE(f->device);
1023
1024         display_line_dynarr *dla = window_display_lines(w, CURRENT_DISP);
1025         struct display_line *dl;
1026         struct display_block *db;
1027         struct rune *rb;
1028
1029         int x = w->last_point_x[CURRENT_DISP];
1030         int y = w->last_point_y[CURRENT_DISP];
1031
1032         if (cursor_in_echo_area && MINI_WINDOW_P(w) &&
1033             !echo_area_active(f) && minibuf_level == 0) {
1034                 MAYBE_DEVMETH(d, set_final_cursor_coords, (f, w->pixel_top, 0));
1035         }
1036
1037         if (y < 0 || y >= Dynarr_length(dla))
1038                 return;
1039
1040         if (MINI_WINDOW_P(w) && f != device_selected_frame(d) &&
1041             !is_surrogate_for_selected_frame(f))
1042                 return;
1043
1044         dl = Dynarr_atp(dla, y);
1045         db = get_display_block_from_line(dl, TEXT);
1046
1047         if (x < 0 || x >= Dynarr_length(db->runes))
1048                 return;
1049
1050         rb = Dynarr_atp(db->runes, x);
1051
1052         /* Don't call the output routine if the block isn't actually the
1053            cursor. */
1054         if (rb->cursor_type == CURSOR_ON) {
1055                 MAYBE_DEVMETH(d, set_final_cursor_coords,
1056                               (f, dl->ypos - 1, rb->xpos));
1057
1058                 if (run_end_begin_meths) {
1059                         MAYBE_DEVMETH(d, frame_output_begin, (f));
1060                         MAYBE_DEVMETH(d, window_output_begin, (w));
1061                 }
1062
1063                 output_display_line(w, 0, dla, y, rb->xpos,
1064                                     rb->xpos + rb->width);
1065
1066                 if (run_end_begin_meths) {
1067                         MAYBE_DEVMETH(d, window_output_end, (w));
1068                         MAYBE_DEVMETH(d, frame_output_end, (f));
1069                 }
1070         }
1071 }
1072
1073 /*****************************************************************************
1074  redisplay_redraw_cursor
1075
1076  For the given frame F, redraw the cursor on the selected window.
1077  This is used to update the cursor after focus changes.
1078  ****************************************************************************/
1079 void redisplay_redraw_cursor(struct frame *f, int run_end_begin_meths)
1080 {
1081         Lisp_Object window;
1082
1083         if (!cursor_in_echo_area)
1084                 window = FRAME_SELECTED_WINDOW(f);
1085         else if (FRAME_HAS_MINIBUF_P(f))
1086                 window = FRAME_MINIBUF_WINDOW(f);
1087         else
1088                 return;
1089
1090         redraw_cursor_in_window(XWINDOW(window), run_end_begin_meths);
1091 }
1092
1093 /****************************************************************************
1094  redisplay_output_display_block
1095
1096  Given a display line, a block number for that start line, output all
1097  runes between start and end in the specified display block.
1098  ****************************************************************************/
1099 static void
1100 redisplay_output_display_block(struct window *w, struct display_line *dl,
1101                                int block, int start, int end, int start_pixpos,
1102                                int cursor_start, int cursor_width,
1103                                int cursor_height)
1104 {
1105         struct frame *f = XFRAME(w->frame);
1106         struct device *d = XDEVICE(f->device);
1107         /* Temporarily disabled until generalization is done. */
1108 #if 0
1109         struct display_block *db = Dynarr_atp(dl->display_blocks, block);
1110         rune_dynarr *rba = db->runes;
1111         struct rune *rb;
1112         int xpos, width;
1113         rb = Dynarr_atp(rba, start);
1114
1115         if (!rb)
1116                 /* Nothing to do so don't do anything. */
1117                 return;
1118
1119         xpos = max(start_pixpos, rb->xpos);
1120
1121         if (end < 0)
1122                 end = Dynarr_length(rba);
1123
1124         rb = Dynarr_atp(rba, end - 1);
1125         width = rb->xpos + rb->width - xpos;
1126 #endif
1127         /* now actually output the block. */
1128         DEVMETH(d, output_display_block, (w, dl, block, start,
1129                                           end, start_pixpos,
1130                                           cursor_start, cursor_width,
1131                                           cursor_height));
1132 }
1133
1134 /****************************************************************************
1135  redisplay_unmap_subwindows
1136
1137  Remove subwindows from the area in the box defined by the given
1138  parameters.
1139  ****************************************************************************/
1140 static void
1141 redisplay_unmap_subwindows(struct frame *f, int x, int y, int width, int height,
1142                            Lisp_Object ignored_window)
1143 {
1144         Lisp_Object rest;
1145
1146         LIST_LOOP(rest, XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f))) {
1147                 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(XCAR(rest));
1148                 if (IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(ii)
1149                     && IMAGE_INSTANCE_DISPLAY_X(ii)
1150                     + IMAGE_INSTANCE_DISPLAY_WIDTH(ii) > (unsigned)x
1151                     && IMAGE_INSTANCE_DISPLAY_X(ii) < (unsigned)(x + width)
1152                     && IMAGE_INSTANCE_DISPLAY_Y(ii)
1153                     + IMAGE_INSTANCE_DISPLAY_HEIGHT(ii) > (unsigned)y
1154                     && IMAGE_INSTANCE_DISPLAY_Y(ii) < (unsigned)(y + height)
1155                     && !EQ(XCAR(rest), ignored_window)) {
1156                         unmap_subwindow(XCAR(rest));
1157                 }
1158         }
1159 }
1160
1161 /****************************************************************************
1162  redisplay_unmap_subwindows_maybe
1163
1164  Potentially subwindows from the area in the box defined by the given
1165  parameters.
1166  ****************************************************************************/
1167 void redisplay_unmap_subwindows_maybe(struct frame *f, int x, int y, int width,
1168                                       int height)
1169 {
1170         if (!NILP(XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f)))) {
1171                 redisplay_unmap_subwindows(f, x, y, width, height, Qnil);
1172         }
1173 }
1174
1175 static void redisplay_unmap_subwindows_except_us(struct frame *f, int x, int y,
1176                                                  int width, int height,
1177                                                  Lisp_Object subwindow)
1178 {
1179         if (!NILP(XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f)))) {
1180                 redisplay_unmap_subwindows(f, x, y, width, height, subwindow);
1181         }
1182 }
1183
1184 /****************************************************************************
1185  redisplay_output_subwindow
1186
1187  output a subwindow.  This code borrows heavily from the pixmap stuff,
1188  although is much simpler not needing to account for partial
1189  pixmaps, backgrounds etc.
1190  ****************************************************************************/
1191 void
1192 redisplay_output_subwindow(struct window *w,
1193                            Lisp_Object image_instance,
1194                            struct display_box *db,
1195                            struct display_glyph_area *dga, face_index findex,
1196                            int cursor_start, int cursor_width,
1197                            int cursor_height)
1198 {
1199         Lisp_Image_Instance *p = XIMAGE_INSTANCE(image_instance);
1200         Lisp_Object window;
1201         struct display_glyph_area sdga;
1202
1203         dga->height = IMAGE_INSTANCE_HEIGHT(p);
1204         dga->width = IMAGE_INSTANCE_WIDTH(p);
1205
1206         /* The first thing we are going to do is update the display
1207            characteristics of the subwindow. This also clears the dirty
1208            flags as a side effect. */
1209         redisplay_subwindow(image_instance);
1210
1211         /* This makes the glyph area fit into the display area. */
1212         if (!redisplay_normalize_glyph_area(db, dga))
1213                 return;
1214
1215         XSETWINDOW(window, w);
1216
1217         /* Clear the area the subwindow is going into. */
1218         redisplay_clear_clipped_region(window, findex,
1219                                        db, dga, 0, image_instance);
1220
1221         /* This shrinks the display box to exactly enclose the glyph
1222            area. */
1223         redisplay_normalize_display_box(db, dga);
1224
1225         /* if we can't view the whole window we can't view any of it. We
1226            have to be careful here since we may be being asked to display
1227            part of a subwindow, the rest of which is on-screen as well. We
1228            need to allow this case and map the entire subwindow. We also
1229            need to be careful since the subwindow could be outside the
1230            window in the gutter or modeline - we also need to allow these
1231            cases. */
1232         sdga.xoffset = -dga->xoffset;
1233         sdga.yoffset = -dga->yoffset;
1234         sdga.height = IMAGE_INSTANCE_HEIGHT(p);
1235         sdga.width = IMAGE_INSTANCE_WIDTH(p);
1236
1237         if (redisplay_display_boxes_in_window_p(w, db, &sdga) == 0 ||
1238             /* We only want to do full subwindow display for windows that
1239                are completely in the gutter, otherwise we must clip to be
1240                safe. */
1241             display_boxes_in_gutter_p(XFRAME(w->frame), db, &sdga) <= 0) {
1242                 map_subwindow(image_instance, db->xpos, db->ypos, dga);
1243         } else {
1244                 sdga.xoffset = sdga.yoffset = 0;
1245                 map_subwindow(image_instance, db->xpos - dga->xoffset,
1246                               db->ypos - dga->yoffset, &sdga);
1247         }
1248 }
1249
1250 /****************************************************************************
1251  redisplay_output_layout
1252
1253  Output a widget hierarchy. This can safely call itself recursively.
1254
1255  The complexity of outputting layouts is deciding whether to do it or
1256  not. Consider a layout enclosing some text, the text changes and is
1257  marked as dirty, but the enclosing layout has not been marked as
1258  dirty so no updates occur and the text will potentially be truncated.
1259  Alternatively we hold a back pointer in the image instance to the
1260  parent and mark the parent as dirty. But the layout code assumes that
1261  if the layout is dirty then the whole layout should be redisplayed,
1262  so we then get lots of flashing even though only the text has changed
1263  size. Of course if the text shrinks in size then we do actually need
1264  to redisplay the layout to repaint the exposed area. So what happens
1265  if we make a non-structural change like changing color? Either we
1266  redisplay everything, or we redisplay nothing. These are exactly the
1267  issues lwlib has to grapple with. We really need to know what has
1268  actually changed and make a layout decision based on that. We also
1269  really need to know what has changed so that we can only make the
1270  necessary changes in update_subwindow.  This has all now been
1271  implemented, Viva la revolution!
1272  ****************************************************************************/
1273 void
1274 redisplay_output_layout(Lisp_Object domain,
1275                         Lisp_Object image_instance,
1276                         struct display_box *db, struct display_glyph_area *dga,
1277                         face_index findex, int cursor_start, int cursor_width,
1278                         int cursor_height)
1279 {
1280         Lisp_Image_Instance *p = XIMAGE_INSTANCE(image_instance);
1281         Lisp_Object rest, window = DOMAIN_WINDOW(domain);
1282         Emchar_dynarr *buf = NULL;
1283         struct window *w = XWINDOW(window);
1284         struct device *d = DOMAIN_XDEVICE(domain);
1285         int layout_height, layout_width;
1286
1287         layout_height = glyph_height(image_instance, domain);
1288         layout_width = glyph_width(image_instance, domain);
1289
1290         dga->height = layout_height;
1291         dga->width = layout_width;
1292 #ifdef DEBUG_WIDGET_OUTPUT
1293         printf("outputing layout glyph %p\n", p);
1294 #endif
1295         /* This makes the glyph area fit into the display area. */
1296         if (!redisplay_normalize_glyph_area(db, dga))
1297                 return;
1298
1299         /* Highly dodgy optimization. We want to only output the whole
1300            layout if we really have to. */
1301         if (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT(p)
1302             || IMAGE_INSTANCE_LAYOUT_CHANGED(p)
1303             || IMAGE_INSTANCE_WIDGET_FACE_CHANGED(p)
1304             || IMAGE_INSTANCE_SIZE_CHANGED(p)
1305             || IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(p)) {
1306                 /* First clear the area we are drawing into. This is the easiest
1307                    thing to do since we have many gaps that we have to make sure are
1308                    filled in. */
1309                 redisplay_clear_clipped_region(window, findex, db, dga, 1,
1310                                                Qnil);
1311
1312                 /* Output a border if required */
1313                 if (!NILP(IMAGE_INSTANCE_LAYOUT_BORDER(p))) {
1314                         int edges = 0;
1315                         enum edge_style style;
1316                         int ypos = db->ypos;
1317                         int xpos = db->xpos;
1318                         int height = dga->height;
1319                         int width = dga->width;
1320
1321                         /* The bevel_area routines always draw in from the specified
1322                            area so there is no need to adjust the displayed area to
1323                            make sure that the lines are visible. */
1324                         if (dga->xoffset >= 0)
1325                                 edges |= EDGE_LEFT;
1326                         if (dga->width - dga->xoffset == layout_width)
1327                                 edges |= EDGE_RIGHT;
1328                         if (dga->yoffset >= 0)
1329                                 edges |= EDGE_TOP;
1330                         if (dga->height - dga->yoffset == layout_height)
1331                                 edges |= EDGE_BOTTOM;
1332
1333                         if (EQ(IMAGE_INSTANCE_LAYOUT_BORDER(p), Qetched_in))
1334                                 style = EDGE_ETCHED_IN;
1335                         else if (EQ
1336                                  (IMAGE_INSTANCE_LAYOUT_BORDER(p), Qetched_out))
1337                                 style = EDGE_ETCHED_OUT;
1338                         else if (EQ(IMAGE_INSTANCE_LAYOUT_BORDER(p), Qbevel_in))
1339                                 style = EDGE_BEVEL_IN;
1340                         else if (INTP(IMAGE_INSTANCE_LAYOUT_BORDER(p))) {
1341                                 style = EDGE_ETCHED_IN;
1342                                 if (edges & EDGE_TOP) {
1343                                         ypos +=
1344                                             XINT(IMAGE_INSTANCE_LAYOUT_BORDER
1345                                                  (p));
1346                                         height -=
1347                                             XINT(IMAGE_INSTANCE_LAYOUT_BORDER
1348                                                  (p));
1349                                 }
1350                         } else
1351                                 style = EDGE_BEVEL_OUT;
1352
1353                         MAYBE_DEVMETH(d, bevel_area,
1354                                       (w, findex, xpos, ypos, width, height,
1355                                        DEFAULT_WIDGET_SHADOW_WIDTH, edges,
1356                                        style));
1357                 }
1358         }
1359
1360         /* This shrinks the display box to exactly enclose the glyph
1361            area. */
1362         redisplay_normalize_display_box(db, dga);
1363         buf = Dynarr_new(Emchar);
1364         /* Flip through the widgets in the layout displaying as necessary */
1365         LIST_LOOP(rest, IMAGE_INSTANCE_LAYOUT_CHILDREN(p)) {
1366                 Lisp_Object child =
1367                     glyph_image_instance(XCAR(rest), image_instance,
1368                                          ERROR_ME_NOT, 1);
1369
1370                 struct display_box cdb;
1371                 /* For losing HP-UX */
1372                 cdb.xpos = db->xpos;
1373                 cdb.ypos = db->ypos;
1374                 cdb.width = db->width;
1375                 cdb.height = db->height;
1376
1377                 /* First determine if the image is visible at all */
1378                 if (IMAGE_INSTANCEP(child)) {
1379                         Lisp_Image_Instance *childii = XIMAGE_INSTANCE(child);
1380
1381                         /* The enclosing layout offsets are +ve at this point */
1382                         struct display_glyph_area cdga;
1383                         cdga.xoffset =
1384                             IMAGE_INSTANCE_XOFFSET(childii) - dga->xoffset;
1385                         cdga.yoffset =
1386                             IMAGE_INSTANCE_YOFFSET(childii) - dga->yoffset;
1387                         cdga.width = glyph_width(child, image_instance);
1388                         cdga.height = glyph_height(child, image_instance);
1389
1390                         IMAGE_INSTANCE_OPTIMIZE_OUTPUT(childii) =
1391                             IMAGE_INSTANCE_OPTIMIZE_OUTPUT(p);
1392
1393                         /* Although normalization is done by the output routines
1394                            we have to do it here so that they don't try and
1395                            clear all of db. This is true below also. */
1396                         if (redisplay_normalize_glyph_area(&cdb, &cdga)) {
1397                                 redisplay_normalize_display_box(&cdb, &cdga);
1398                                 /* Since the display boxes will now be totally
1399                                    in the window if they are visible at all we
1400                                    can now check this easily. */
1401                                 if (cdb.xpos < db->xpos || cdb.ypos < db->ypos
1402                                     || cdb.xpos + cdb.width >
1403                                     db->xpos + db->width
1404                                     || cdb.ypos + cdb.height >
1405                                     db->ypos + db->height)
1406                                         continue;
1407                                 /* We have to invert the offset here as
1408                                    normalization will have made them positive
1409                                    which the output routines will treat as a
1410                                    truly +ve offset. */
1411                                 cdga.xoffset = -cdga.xoffset;
1412                                 cdga.yoffset = -cdga.yoffset;
1413
1414                                 switch (IMAGE_INSTANCE_TYPE(childii)) {
1415                                 case IMAGE_TEXT: {
1416                                         /* #### This is well hacked and
1417                                            could use some generalisation. */
1418                                         if (redisplay_normalize_glyph_area(
1419                                                     &cdb, &cdga) &&
1420                                             (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT
1421                                              (childii) ||
1422                                              IMAGE_INSTANCE_DIRTYP(childii))) {
1423                                                 /* this is fake */
1424                                                 struct display_line dl;
1425                                                 Lisp_Object string =
1426                                                         IMAGE_INSTANCE_TEXT_STRING
1427                                                         (childii);
1428                                                 unsigned char
1429                                                         charsets
1430                                                         [NUM_LEADING_BYTES];
1431                                                 struct face_cachel
1432                                                         *cachel =
1433                                                         WINDOW_FACE_CACHEL
1434                                                         (w, findex);
1435
1436                                                 find_charsets_in_bufbyte_string
1437                                                         (charsets,
1438                                                          XSTRING_DATA
1439                                                          (string),
1440                                                          XSTRING_LENGTH
1441                                                          (string));
1442                                                 ensure_face_cachel_complete
1443                                                         (cachel, window,
1444                                                          charsets);
1445
1446                                                 convert_bufbyte_string_into_emchar_dynarr
1447                                                         (XSTRING_DATA
1448                                                          (string),
1449                                                          XSTRING_LENGTH
1450                                                          (string), buf);
1451
1452                                                 redisplay_normalize_display_box
1453                                                         (&cdb, &cdga);
1454                                                 /* Offsets are now +ve again so
1455                                                    be careful when fixing up the
1456                                                    display line. */
1457                                                 xzero(dl);
1458                                                 /* Munge boxes into display
1459                                                    lines. */
1460                                                 dl.ypos =
1461                                                         (cdb.ypos -
1462                                                          cdga.yoffset)
1463                                                         +
1464                                                         glyph_ascent(child,
1465                                                                      image_instance);
1466                                                 dl.ascent =
1467                                                         glyph_ascent(child,
1468                                                                      image_instance);
1469                                                 dl.descent =
1470                                                         glyph_descent(child,
1471                                                                       image_instance);
1472                                                 dl.top_clip =
1473                                                         cdga.yoffset;
1474                                                 dl.clip =
1475                                                         (dl.ypos +
1476                                                          dl.descent) -
1477                                                         (cdb.ypos +
1478                                                          cdb.height);
1479                                                 /* output_string doesn't
1480                                                    understand offsets in the
1481                                                    same way as other routines -
1482                                                    we have to add the offset to
1483                                                    the width so that we output
1484                                                    the full string. */
1485                                                 MAYBE_DEVMETH(d,
1486                                                               output_string,
1487                                                               (w, &dl,
1488                                                                buf,
1489                                                                cdb.xpos,
1490                                                                cdga.
1491                                                                xoffset,
1492                                                                cdb.xpos,
1493                                                                cdga.
1494                                                                width +
1495                                                                cdga.
1496                                                                xoffset,
1497                                                                findex,
1498                                                                0, 0, 0,
1499                                                                0));
1500                                                 Dynarr_reset(buf);
1501                                         }
1502                                 }
1503                                         break;
1504
1505                                 case IMAGE_MONO_PIXMAP:
1506                                 case IMAGE_COLOR_PIXMAP:
1507                                         if (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT
1508                                             (childii)
1509                                             || IMAGE_INSTANCE_DIRTYP(childii))
1510                                                 redisplay_output_pixmap(w,
1511                                                                         child,
1512                                                                         &cdb,
1513                                                                         &cdga,
1514                                                                         findex,
1515                                                                         0, 0, 0,
1516                                                                         0);
1517                                         break;
1518
1519                                 case IMAGE_WIDGET:
1520                                         if (EQ
1521                                             (IMAGE_INSTANCE_WIDGET_TYPE
1522                                              (childii), Qlayout)) {
1523                                                 redisplay_output_layout
1524                                                     (image_instance, child,
1525                                                      &cdb, &cdga, findex, 0, 0,
1526                                                      0);
1527                                                 break;
1528                                         }
1529                                 case IMAGE_SUBWINDOW:
1530                                         if (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT
1531                                             (childii)
1532                                             || IMAGE_INSTANCE_DIRTYP(childii))
1533                                                 redisplay_output_subwindow(w,
1534                                                                            child,
1535                                                                            &cdb,
1536                                                                            &cdga,
1537                                                                            findex,
1538                                                                            0, 0,
1539                                                                            0);
1540                                         break;
1541
1542                                 case IMAGE_NOTHING:
1543                                         /* nothing is as nothing does */
1544                                         break;
1545
1546                                 case IMAGE_UNKNOWN:
1547                                 case IMAGE_POINTER:
1548                                 default:
1549                                         abort();
1550                                 }
1551                         }
1552                         IMAGE_INSTANCE_OPTIMIZE_OUTPUT(childii) = 0;
1553                 }
1554         }
1555
1556         /* Update any display properties. I'm not sure whether this actually
1557            does anything for layouts except clear the changed flags. */
1558         redisplay_subwindow(image_instance);
1559
1560         Dynarr_free(buf);
1561 }
1562
1563 /****************************************************************************
1564  redisplay_output_pixmap
1565
1566  output a pixmap.
1567  ****************************************************************************/
1568 void
1569 redisplay_output_pixmap(struct window *w,
1570                         Lisp_Object image_instance,
1571                         struct display_box *db, struct display_glyph_area *dga,
1572                         face_index findex, int cursor_start, int cursor_width,
1573                         int cursor_height, int offset_bitmap)
1574 {
1575         struct frame *f = XFRAME(w->frame);
1576         struct device *d = XDEVICE(f->device);
1577         Lisp_Image_Instance *p = XIMAGE_INSTANCE(image_instance);
1578         Lisp_Object window;
1579         XSETWINDOW(window, w);
1580
1581         dga->height = IMAGE_INSTANCE_PIXMAP_HEIGHT(p);
1582         dga->width = IMAGE_INSTANCE_PIXMAP_WIDTH(p);
1583
1584 #ifdef DEBUG_REDISPLAY
1585         printf("redisplay_output_pixmap(request) \
1586 [%dx%d@%d+%d] in [%dx%d@%d+%d]\n", db->width, db->height, db->xpos, db->ypos, dga->width, dga->height, dga->xoffset, dga->yoffset);
1587 #endif
1588
1589         /* This makes the glyph area fit into the display area. */
1590         if (!redisplay_normalize_glyph_area(db, dga))
1591                 return;
1592
1593 #ifdef DEBUG_REDISPLAY
1594         printf("redisplay_output_pixmap(normalized) \
1595 [%dx%d@%d+%d] in [%dx%d@%d+%d]\n", db->width, db->height, db->xpos, db->ypos, dga->width, dga->height, dga->xoffset, dga->yoffset);
1596 #endif
1597
1598         /* Clear the area the pixmap is going into.  The pixmap itself will
1599            always take care of the full width.  We don't want to clear where
1600            it is going to go in order to avoid flicker.  So, all we have to
1601            take care of is any area above or below the pixmap. If the pixmap
1602            has a mask in which case we have to clear the whole damn thing
1603            since we can't yet clear just the area not included in the
1604            mask. */
1605         if (!offset_bitmap) {
1606                 redisplay_clear_clipped_region(window, findex,
1607                                                db, dga,
1608                                                (IMAGE_INSTANCE_PIXMAP_MASK(p) !=
1609                                                 0), Qnil);
1610
1611                 /* This shrinks the display box to exactly enclose the glyph
1612                    area. */
1613                 redisplay_normalize_display_box(db, dga);
1614         }
1615         assert(db->xpos >= 0 && db->ypos >= 0);
1616
1617         MAYBE_DEVMETH(d, output_pixmap, (w, image_instance,
1618                                          db, dga,
1619                                          findex, cursor_start,
1620                                          cursor_width, cursor_height,
1621                                          offset_bitmap));
1622 }
1623
1624 /****************************************************************************
1625  redisplay_clear_region
1626
1627  Clear the area in the box defined by the given parameters using the
1628  given face. This has been generalised so that subwindows can be
1629  coped with effectively.
1630  ****************************************************************************/
1631 void
1632 redisplay_clear_region(Lisp_Object locale, face_index findex, int x, int y,
1633                        int width, int height)
1634 {
1635         struct window *w = NULL;
1636         struct frame *f = NULL;
1637         struct device *d;
1638         Lisp_Object background_pixmap = Qunbound;
1639         Lisp_Object fcolor = Qnil, bcolor = Qnil;
1640
1641         if (!width || !height)
1642                 return;
1643
1644         if (WINDOWP(locale)) {
1645                 w = XWINDOW(locale);
1646                 f = XFRAME(w->frame);
1647         } else if (FRAMEP(locale)) {
1648                 w = NULL;
1649                 f = XFRAME(locale);
1650         } else
1651                 abort();
1652
1653         d = XDEVICE(f->device);
1654
1655         /* if we have subwindows in the region we have to unmap them */
1656         redisplay_unmap_subwindows_maybe(f, x, y, width, height);
1657
1658         /* #### This isn't quite right for when this function is called
1659            from the toolbar code. */
1660
1661         /* Don't use a backing pixmap in the border area */
1662         if (x >= FRAME_LEFT_BORDER_END(f)
1663             && x < FRAME_RIGHT_BORDER_START(f)
1664             && y >= FRAME_TOP_BORDER_END(f)
1665             && y < FRAME_BOTTOM_BORDER_START(f)) {
1666                 Lisp_Object temp;
1667
1668                 if (w) {
1669                         temp = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP(w, findex);
1670
1671                         if (IMAGE_INSTANCEP(temp)
1672                             &&
1673                             IMAGE_INSTANCE_PIXMAP_TYPE_P(XIMAGE_INSTANCE(temp)))
1674                         {
1675                                 /* #### maybe we could implement such that a string
1676                                    can be a background pixmap? */
1677                                 background_pixmap = temp;
1678                         }
1679                 } else {
1680                         temp = FACE_BACKGROUND_PIXMAP(Vdefault_face, locale);
1681
1682                         if (IMAGE_INSTANCEP(temp)
1683                             &&
1684                             IMAGE_INSTANCE_PIXMAP_TYPE_P(XIMAGE_INSTANCE(temp)))
1685                         {
1686                                 background_pixmap = temp;
1687                         }
1688                 }
1689         }
1690
1691         if (!UNBOUNDP(background_pixmap) &&
1692             XIMAGE_INSTANCE_PIXMAP_DEPTH(background_pixmap) == 0) {
1693                 if (w) {
1694                         fcolor = WINDOW_FACE_CACHEL_FOREGROUND(w, findex);
1695                         bcolor = WINDOW_FACE_CACHEL_BACKGROUND(w, findex);
1696                 } else {
1697                         fcolor = FACE_FOREGROUND(Vdefault_face, locale);
1698                         bcolor = FACE_BACKGROUND(Vdefault_face, locale);
1699                 }
1700         } else {
1701                 fcolor = (w ?
1702                           WINDOW_FACE_CACHEL_BACKGROUND(w, findex) :
1703                           FACE_BACKGROUND(Vdefault_face, locale));
1704
1705         }
1706
1707         if (UNBOUNDP(background_pixmap))
1708                 background_pixmap = Qnil;
1709
1710         DEVMETH(d, clear_region,
1711                 (locale, d, f, findex, x, y, width, height, fcolor, bcolor,
1712                  background_pixmap));
1713 }
1714
1715 /****************************************************************************
1716  redisplay_clear_clipped_region
1717
1718  Clear the area in the dest display_box not covered by the src
1719  display_glyph_area using the given face. This is a common occurrence
1720  for images shorter than the display line. Clipping can be played
1721  around with by altering these. glyphsrc should be normalized.
1722  ****************************************************************************/
1723 static void
1724 redisplay_clear_clipped_region(Lisp_Object window, face_index findex,
1725                                struct display_box *dest,
1726                                struct display_glyph_area *glyphsrc,
1727                                int fullheight_p, Lisp_Object ignored_subwindow)
1728 {
1729         /* assume dest->xpos >= 0 */
1730         int clear_x;
1731         struct frame *f = XFRAME(XWINDOW(window)->frame);
1732
1733         if (glyphsrc->xoffset > 0) {
1734                 clear_x = dest->xpos + glyphsrc->xoffset;
1735         } else {
1736                 clear_x = dest->xpos;
1737         }
1738
1739         /* If we need the whole height cleared then just do it. */
1740         if (fullheight_p) {
1741                 redisplay_clear_region(window, findex, clear_x, dest->ypos,
1742                                        glyphsrc->width, dest->height);
1743         } else {
1744                 int yoffset = (glyphsrc->yoffset > 0 ? glyphsrc->yoffset : 0);
1745
1746                 /* We need to make sure that subwindows are unmapped from the
1747                    whole area. */
1748                 redisplay_unmap_subwindows_except_us(f, clear_x, dest->ypos,
1749                                                      glyphsrc->width,
1750                                                      dest->height,
1751                                                      ignored_subwindow);
1752                 /* first the top box */
1753                 if (yoffset > 0) {
1754                         redisplay_clear_region(window, findex, clear_x,
1755                                                dest->ypos, glyphsrc->width,
1756                                                yoffset);
1757
1758                 }
1759                 /* Then the bottom box */
1760                 if (yoffset + glyphsrc->height < dest->height) {
1761                         redisplay_clear_region(window, findex, clear_x,
1762                                                dest->ypos + yoffset +
1763                                                glyphsrc->height,
1764                                                glyphsrc->width,
1765                                                dest->height - (yoffset +
1766                                                                glyphsrc->
1767                                                                height));
1768
1769                 }
1770         }
1771 }
1772
1773 /*****************************************************************************
1774  redisplay_normalize_glyph_area
1775  redisplay_normalize_display_box
1776
1777  Calculate the visible box for displaying glyphsrc in dest.
1778
1779  display_box and display_glyph_area are used to represent an area to
1780  displayed and where to display it. Using these two structures all
1781  combinations of clipping and position can be accommodated.
1782
1783  dest - display_box
1784
1785         xpos - absolute horizontal position of area.
1786
1787         ypos - absolute vertical position of area.
1788
1789   glyphsrc - display_glyph_area
1790
1791         xoffset - horizontal offset of the glyph, +ve means display
1792         the glyph with the x position offset by xoffset, -ve means
1793         display starting xoffset into the glyph.
1794
1795         yoffset - vertical offset of the glyph, +ve means display the
1796         glyph with y position offset by yoffset, -ve means display
1797         starting xoffset into the glyph.
1798
1799  ****************************************************************************/
1800 int
1801 redisplay_normalize_glyph_area(struct display_box *dest,
1802                                struct display_glyph_area *glyphsrc)
1803 {
1804         if (dest->xpos + glyphsrc->xoffset > dest->xpos + dest->width
1805             ||
1806             dest->ypos + glyphsrc->yoffset > dest->ypos + dest->height
1807             ||
1808             -glyphsrc->xoffset >= glyphsrc->width
1809             || -glyphsrc->yoffset >= glyphsrc->height ||
1810             /* #### Not sure why this wasn't coped with before but normalizing
1811                to zero width or height is definitely wrong. */
1812             (dest->xpos + glyphsrc->xoffset + glyphsrc->width >
1813              dest->xpos + dest->width && dest->width - glyphsrc->xoffset <= 0)
1814             || (dest->ypos + glyphsrc->yoffset + glyphsrc->height >
1815                 dest->ypos + dest->height
1816                 && dest->height - glyphsrc->yoffset <= 0)) {
1817                 /* It's all clipped out */
1818                 return 0;
1819         }
1820
1821         /* Horizontal offsets. This works because xoffset can be -ve as well
1822            as +ve.  When we enter this function the glyphsrc width and
1823            height are set to the actual glyph width and height irrespective
1824            of how much can be displayed. We are trying to clip both the
1825            offset into the image and the rightmost bounding box. Its
1826            possible for the glyph width to be much larger than the area we
1827            are displaying into (e.g. a large glyph in a small frame). */
1828         if (dest->xpos + glyphsrc->xoffset + glyphsrc->width >
1829             dest->xpos + dest->width) {
1830                 /* glyphsrc offset is +ve we are trying to display offset from the
1831                    origin (the bounding box contains some space and then the
1832                    glyph). At most the width we want to display is dest->width -
1833                    glyphsrc->xoffset. */
1834                 if (glyphsrc->xoffset > 0)
1835                         glyphsrc->width = dest->width - glyphsrc->xoffset;
1836                 /* glyphsrc offset is -ve we are trying to display hard up
1837                    against the dest corner inset into the glyphsrc by
1838                    xoffset. */
1839                 else if (glyphsrc->xoffset < 0) {
1840                         glyphsrc->width += glyphsrc->xoffset;
1841                         glyphsrc->width = min(glyphsrc->width, dest->width);
1842                 } else
1843                         glyphsrc->width = dest->width;
1844         }
1845
1846         else if (glyphsrc->xoffset < 0)
1847                 glyphsrc->width += glyphsrc->xoffset;
1848
1849         /* Vertical offsets. This works because yoffset can be -ve as well as +ve */
1850         if (dest->ypos + glyphsrc->yoffset + glyphsrc->height >
1851             dest->ypos + dest->height) {
1852                 if ((glyphsrc->yoffset > 0)
1853                     && (dest->height > glyphsrc->yoffset))
1854                         glyphsrc->height = dest->height - glyphsrc->yoffset;
1855                 else if (glyphsrc->yoffset < 0) {
1856                         glyphsrc->height += glyphsrc->yoffset;
1857                         glyphsrc->height = min(glyphsrc->height, dest->height);
1858                 } else
1859                         glyphsrc->height = dest->height;
1860         }
1861
1862         else if (glyphsrc->yoffset < 0)
1863                 glyphsrc->height += glyphsrc->yoffset;
1864
1865         return 1;
1866 }
1867
1868 static void
1869 redisplay_normalize_display_box(struct display_box *dest,
1870                                 struct display_glyph_area *glyphsrc)
1871 {
1872         /* Adjust the destination area. At the end of this the destination
1873            area will exactly enclose the glyph area. The only remaining
1874            adjustment will be offsets into the glyph area. */
1875
1876         /* Horizontal adjustment. */
1877         if (glyphsrc->xoffset > 0) {
1878                 dest->xpos += glyphsrc->xoffset;
1879                 dest->width -= glyphsrc->xoffset;
1880                 glyphsrc->xoffset = 0;
1881         } else
1882                 glyphsrc->xoffset = -glyphsrc->xoffset;
1883
1884         if (glyphsrc->width < dest->width)
1885                 dest->width = glyphsrc->width;
1886
1887         /* Vertical adjustment. */
1888         if (glyphsrc->yoffset > 0) {
1889                 dest->ypos += glyphsrc->yoffset;
1890                 dest->height -= glyphsrc->yoffset;
1891                 glyphsrc->yoffset = 0;
1892         } else
1893                 glyphsrc->yoffset = -glyphsrc->yoffset;
1894
1895         if (glyphsrc->height < dest->height)
1896                 dest->height = glyphsrc->height;
1897 }
1898
1899 /*****************************************************************************
1900  redisplay_display_boxes_in_window_p
1901
1902  Determine whether the required display_glyph_area is completely inside
1903  the window. -1 means the display_box is not in the window. 1 means the
1904  display_box and the display_glyph_area are in the window. 0 means
1905  the display_box is in the window but the display_glyph_area is not.
1906  ****************************************************************************/
1907 static int
1908 redisplay_display_boxes_in_window_p(struct window *w,
1909                                     struct display_box *db,
1910                                     struct display_glyph_area *dga)
1911 {
1912         int left = WINDOW_TEXT_LEFT(w);
1913         int right = WINDOW_TEXT_RIGHT(w);
1914         int top = WINDOW_TEXT_TOP(w);
1915         int bottom = WINDOW_TEXT_BOTTOM(w);
1916
1917         if (db->xpos < left || db->ypos < top
1918             || db->xpos + db->width > right || db->ypos + db->height > bottom)
1919                 /* We are not displaying in a window at all */
1920                 return -1;
1921
1922         if (db->xpos + dga->xoffset >= left
1923             &&
1924             db->ypos + dga->yoffset >= top
1925             &&
1926             db->xpos + dga->xoffset + dga->width <= right
1927             && db->ypos + dga->yoffset + dga->height <= bottom)
1928                 return 1;
1929
1930         return 0;
1931 }
1932
1933 /*****************************************************************************
1934  redisplay_calculate_display_boxes
1935
1936  Convert from rune/display_line co-ordinates to display_box
1937  co-ordinates.
1938  ****************************************************************************/
1939 int
1940 redisplay_calculate_display_boxes(struct display_line *dl, int xpos,
1941                                   int xoffset, int yoffset, int start_pixpos,
1942                                   int width, struct display_box *dest,
1943                                   struct display_glyph_area *src)
1944 {
1945         dest->xpos = xpos;
1946         dest->ypos = DISPLAY_LINE_YPOS(dl);
1947         dest->width = width;
1948         dest->height = DISPLAY_LINE_HEIGHT(dl);
1949
1950         src->xoffset = -xoffset;
1951         src->width = 0;
1952         src->height = 0;
1953
1954         src->yoffset = -dl->top_clip + yoffset;
1955
1956         if (start_pixpos >= 0 && start_pixpos > xpos) {
1957                 /* Oops, we're asking for a start outside of the displayable
1958                    area. */
1959                 if (start_pixpos > xpos + width)
1960                         return 0;
1961                 dest->xpos = start_pixpos;
1962                 dest->width -= (start_pixpos - xpos);
1963                 /* Offsets are -ve when we want to clip pixels off the displayed
1964                    glyph. */
1965                 src->xoffset -= (start_pixpos - xpos);
1966         }
1967
1968         return 1;
1969 }
1970
1971 /*****************************************************************************
1972  redisplay_clear_top_of_window
1973
1974  If window is topmost, clear the internal border above it.
1975  ****************************************************************************/
1976 void redisplay_clear_top_of_window(struct window *w)
1977 {
1978         Lisp_Object window;
1979         XSETWINDOW(window, w);
1980
1981         if (!NILP(Fwindow_highest_p(window))) {
1982                 struct frame *f = XFRAME(w->frame);
1983                 int x, y, width, height;
1984
1985                 x = w->pixel_left;
1986                 width = w->pixel_width;
1987
1988                 if (window_is_leftmost(w)) {
1989                         x -= FRAME_BORDER_WIDTH(f);
1990                         width += FRAME_BORDER_WIDTH(f);
1991                 }
1992                 if (window_is_rightmost(w))
1993                         width += FRAME_BORDER_WIDTH(f);
1994
1995                 y = FRAME_TOP_BORDER_START(f) - 1;
1996                 height = FRAME_BORDER_HEIGHT(f) + 1;
1997
1998                 redisplay_clear_region(window, DEFAULT_INDEX, x, y, width,
1999                                        height);
2000         }
2001 }
2002
2003 /*****************************************************************************
2004  redisplay_clear_to_window_end
2005
2006  Clear the area between ypos1 and ypos2.  Each margin area and the
2007  text area is handled separately since they may each have their own
2008  background color.
2009  ****************************************************************************/
2010 void redisplay_clear_to_window_end(struct window *w, int ypos1, int ypos2)
2011 {
2012         struct frame *f = XFRAME(w->frame);
2013         struct device *d = XDEVICE(f->device);
2014
2015         if (HAS_DEVMETH_P(d, clear_to_window_end))
2016                 DEVMETH(d, clear_to_window_end, (w, ypos1, ypos2));
2017         else {
2018                 int height = ypos2 - ypos1;
2019
2020                 if (height) {
2021                         Lisp_Object window;
2022                         int bflag = 0;  /* (window_needs_vertical_divider (w) ? 0 : 1); */
2023                         layout_bounds bounds;
2024
2025                         bounds = calculate_display_line_boundaries(w, bflag);
2026                         XSETWINDOW(window, w);
2027
2028                         if (window_is_leftmost(w))
2029                                 redisplay_clear_region(window, DEFAULT_INDEX,
2030                                                        FRAME_LEFT_BORDER_START
2031                                                        (f), ypos1,
2032                                                        FRAME_BORDER_WIDTH(f),
2033                                                        height);
2034
2035                         if (bounds.left_in - bounds.left_out > 0)
2036                                 redisplay_clear_region(window,
2037                                                        get_builtin_face_cache_index
2038                                                        (w, Vleft_margin_face),
2039                                                        bounds.left_out, ypos1,
2040                                                        bounds.left_in -
2041                                                        bounds.left_out, height);
2042
2043                         if (bounds.right_in - bounds.left_in > 0)
2044                                 redisplay_clear_region(window,
2045                                                        DEFAULT_INDEX,
2046                                                        bounds.left_in, ypos1,
2047                                                        bounds.right_in -
2048                                                        bounds.left_in, height);
2049
2050                         if (bounds.right_out - bounds.right_in > 0)
2051                                 redisplay_clear_region(window,
2052                                                        get_builtin_face_cache_index
2053                                                        (w, Vright_margin_face),
2054                                                        bounds.right_in, ypos1,
2055                                                        bounds.right_out -
2056                                                        bounds.right_in, height);
2057
2058                         if (window_is_rightmost(w))
2059                                 redisplay_clear_region(window, DEFAULT_INDEX,
2060                                                        FRAME_RIGHT_BORDER_START
2061                                                        (f), ypos1,
2062                                                        FRAME_BORDER_WIDTH(f),
2063                                                        height);
2064                 }
2065         }
2066 }
2067
2068 /*****************************************************************************
2069  redisplay_clear_bottom_of_window
2070
2071  Clear window from right below the last display line to right above
2072  the modeline.  The calling function can limit the area actually
2073  erased by setting min_start and/or max_end to positive values.
2074  ****************************************************************************/
2075 void
2076 redisplay_clear_bottom_of_window(struct window *w, display_line_dynarr * ddla,
2077                                  int min_start, int max_end)
2078 {
2079         struct frame *f = XFRAME(w->frame);
2080         int ypos1, ypos2;
2081         int ddla_len = Dynarr_length(ddla);
2082
2083         ypos2 = WINDOW_TEXT_BOTTOM(w);
2084 #ifdef HAVE_SCROLLBARS
2085         /* This adjustment is to catch the intersection of any scrollbars. */
2086         if (f->windows_structure_changed && NILP(w->scrollbar_on_top_p))
2087                 ypos2 += window_scrollbar_height(w);
2088 #endif
2089
2090         if (ddla_len) {
2091                 if (ddla_len == 1 && Dynarr_atp(ddla, 0)->modeline) {
2092                         ypos1 = WINDOW_TEXT_TOP(w);
2093 #ifdef HAVE_SCROLLBARS
2094                         /* This adjustment is to catch the intersection of any scrollbars. */
2095                         if (f->windows_structure_changed
2096                             && !NILP(w->scrollbar_on_top_p))
2097                                 ypos1 -= window_scrollbar_height(w);
2098 #endif
2099                 } else {
2100                         struct display_line *dl =
2101                             Dynarr_atp(ddla, ddla_len - 1);
2102                         ypos1 = dl->ypos + dl->descent - dl->clip;
2103                 }
2104         } else
2105                 ypos1 = WINDOW_TEXT_TOP(w);
2106
2107         /* #### See if this can be made conditional on the frame
2108            changing size. */
2109         if (MINI_WINDOW_P(w))
2110                 ypos2 += FRAME_BORDER_HEIGHT(f);
2111
2112         if (min_start >= 0 && ypos1 < min_start)
2113                 ypos1 = min_start;
2114         if (max_end >= 0 && ypos2 > max_end)
2115                 ypos2 = max_end;
2116
2117         if (ypos2 <= ypos1)
2118                 return;
2119
2120         redisplay_clear_to_window_end(w, ypos1, ypos2);
2121 }
2122
2123 /*****************************************************************************
2124  redisplay_update_line
2125
2126  This is used during incremental updates to update a single line and
2127  correct the offsets on all lines below it.  At the moment
2128  update_values is false if we are only updating the modeline.
2129  ****************************************************************************/
2130 void
2131 redisplay_update_line(struct window *w, int first_line, int last_line,
2132                       int update_values)
2133 {
2134         struct frame *f = XFRAME(w->frame);
2135         struct device *d = XDEVICE(f->device);
2136
2137         display_line_dynarr *cdla = window_display_lines(w, CURRENT_DISP);
2138         display_line_dynarr *ddla = window_display_lines(w, DESIRED_DISP);
2139
2140         MAYBE_DEVMETH(d, window_output_begin, (w));
2141
2142         while (first_line <= last_line) {
2143                 Charcount old_len = (Dynarr_atp(cdla, first_line)->end_bufpos -
2144                                      Dynarr_atp(cdla, first_line)->bufpos);
2145                 Charcount new_len = (Dynarr_atp(ddla, first_line)->end_bufpos -
2146                                      Dynarr_atp(ddla, first_line)->bufpos);
2147
2148                 assert(Dynarr_length(cdla) == Dynarr_length(ddla));
2149
2150                 /* Output the changes. */
2151                 output_display_line(w, cdla, ddla, first_line, -1, -1);
2152
2153                 /* Update the offsets. */
2154                 if (update_values) {
2155                         int cur_line = first_line + 1;
2156                         while (cur_line < Dynarr_length(cdla)) {
2157                                 Dynarr_atp(cdla, cur_line)->offset +=
2158                                     (new_len - old_len);
2159                                 Dynarr_atp(ddla, cur_line)->offset +=
2160                                     (new_len - old_len);
2161                                 cur_line++;
2162                         }
2163                 }
2164
2165                 /* Update the window_end_pos and other settings. */
2166                 if (update_values) {
2167                         w->window_end_pos[CURRENT_DISP] -= (new_len - old_len);
2168
2169                         if (Dynarr_atp(ddla, first_line)->cursor_elt != -1) {
2170                                 w->last_point_x[CURRENT_DISP] =
2171                                     w->last_point_x[DESIRED_DISP];
2172                                 w->last_point_y[CURRENT_DISP] =
2173                                     w->last_point_y[DESIRED_DISP];
2174                         }
2175                 }
2176
2177                 first_line++;
2178         }
2179
2180         /* Update the window max line length.  We have to scan the entire
2181            set of display lines otherwise we might not detect if the max is
2182            supposed to shrink. */
2183         if (update_values) {
2184                 int line = 0;
2185
2186                 w->max_line_len = 0;
2187                 while (line < Dynarr_length(ddla)) {
2188                         struct display_line *dl = Dynarr_atp(ddla, line);
2189
2190                         if (!dl->modeline)
2191                                 w->max_line_len =
2192                                     max(dl->num_chars, w->max_line_len);
2193
2194                         line++;
2195                 }
2196         }
2197
2198         w->last_modified[CURRENT_DISP] = w->last_modified[DESIRED_DISP];
2199         w->last_facechange[CURRENT_DISP] = w->last_facechange[DESIRED_DISP];
2200         Fset_marker(w->last_point[CURRENT_DISP],
2201                     Fmarker_position(w->last_point[DESIRED_DISP]), w->buffer);
2202         Fset_marker(w->last_start[CURRENT_DISP],
2203                     Fmarker_position(w->last_start[DESIRED_DISP]), w->buffer);
2204
2205         /* We don't bother updating the vertical scrollbars here.  This
2206            gives us a performance increase while having minimal loss of
2207            quality to the scrollbar slider size and position since when this
2208            function is called we know that the changes to the buffer were
2209            very localized.  We have to update the horizontal scrollbars,
2210            though, because this routine could cause a change which has a
2211            larger impact on their sizing. */
2212         /* #### See if we can get away with only calling this if
2213            max_line_len is greater than the window_char_width. */
2214         /* #### BILL!!! Should we do this for GTK as well? */
2215 #if defined(HAVE_SCROLLBARS) && defined(HAVE_X_WINDOWS)
2216         {
2217                 extern int stupid_vertical_scrollbar_drag_hack;
2218
2219                 update_window_scrollbars(w, NULL, 1,
2220                                          stupid_vertical_scrollbar_drag_hack);
2221                 stupid_vertical_scrollbar_drag_hack = 1;
2222         }
2223 #endif
2224
2225         redisplay_redraw_cursor(f, 0);
2226         MAYBE_DEVMETH(d, window_output_end, (w));
2227 }
2228
2229 /*****************************************************************************
2230  redisplay_output_window
2231
2232  For the given window W, ensure that the current display lines are
2233  equal to the desired display lines, outputing changes as necessary.
2234
2235  #### Fuck me.  This just isn't going to cut it for tty's.  The output
2236  decisions for them must be based on the contents of the entire frame
2237  because that is how the available output capabilities think.  The
2238  solution is relatively simple.  Create redisplay_output_frame.  This
2239  will basically merge all of the separate window display structs into
2240  a single one for the frame.  This combination structure will be able
2241  to be passed to the same output_display_line which works for windows
2242  on X frames and the right things will happen.  It just takes time to
2243  do.
2244  ****************************************************************************/
2245 void redisplay_output_window(struct window *w)
2246 {
2247         struct frame *f = XFRAME(w->frame);
2248         struct device *d = XDEVICE(f->device);
2249
2250         display_line_dynarr *cdla = window_display_lines(w, CURRENT_DISP);
2251         display_line_dynarr *ddla = window_display_lines(w, DESIRED_DISP);
2252
2253         int cdla_len = Dynarr_length(cdla);
2254         int ddla_len = Dynarr_length(ddla);
2255
2256         int line;
2257         int need_to_clear_bottom = 0;
2258         int need_to_clear_start = -1;
2259         int need_to_clear_end = -1;
2260
2261         /* Backgrounds may have changed or windows may have gone away
2262            leaving dividers lying around. */
2263         if (f->faces_changed
2264             || f->windows_structure_changed || w->shadow_thickness_changed)
2265                 need_to_clear_bottom = 1;
2266
2267         /* The first thing we do is determine if we are going to need to
2268            clear the bottom of the window.  We only need to do this if the
2269            bottom of the current display lines is below the bottom of the
2270            desired display lines.  Note that the number of lines is
2271            irrelevant.  Only the position matters.  We also clear to the
2272            bottom of the window if the modeline has shifted position. */
2273         /* #### We can't blindly not clear the bottom if f->clear is true
2274            since there might be a window-local background.  However, for
2275            those cases where there isn't, clearing the end of the window in
2276            this case sucks. */
2277         if (!need_to_clear_bottom) {
2278                 struct display_line *cdl, *ddl;
2279
2280                 /* If the modeline has changed position or size, clear the bottom
2281                    of the window. */
2282                 if (!need_to_clear_bottom) {
2283                         cdl = ddl = 0;
2284
2285                         if (cdla_len)
2286                                 cdl = Dynarr_atp(cdla, 0);
2287                         if (ddla_len)
2288                                 ddl = Dynarr_atp(ddla, 0);
2289
2290                         if (!cdl || !ddl)
2291                                 need_to_clear_bottom = 1;
2292                         else if ((!cdl->modeline && ddl->modeline)
2293                                  || (cdl->modeline && !ddl->modeline))
2294                                 need_to_clear_bottom = 1;
2295                         else if (cdl->ypos != ddl->ypos ||
2296                                  cdl->ascent != ddl->ascent ||
2297                                  cdl->descent != ddl->descent ||
2298                                  cdl->clip != ddl->clip)
2299                                 need_to_clear_bottom = 1;
2300
2301                         /* #### This kludge is to make sure the modeline shadows get
2302                            redrawn if the modeline position shifts. */
2303                         if (need_to_clear_bottom)
2304                                 w->shadow_thickness_changed = 1;
2305                 }
2306
2307                 if (!need_to_clear_bottom) {
2308                         cdl = ddl = 0;
2309
2310                         if (cdla_len)
2311                                 cdl = Dynarr_atp(cdla, cdla_len - 1);
2312                         if (ddla_len)
2313                                 ddl = Dynarr_atp(ddla, ddla_len - 1);
2314
2315                         if (!cdl || !ddl)
2316                                 need_to_clear_bottom = 1;
2317                         else {
2318                                 int cdl_bottom, ddl_bottom;
2319
2320                                 cdl_bottom = cdl->ypos + cdl->descent;
2321                                 ddl_bottom = ddl->ypos + ddl->descent;
2322
2323                                 if (cdl_bottom > ddl_bottom) {
2324                                         need_to_clear_bottom = 1;
2325                                         need_to_clear_start = ddl_bottom;
2326                                         need_to_clear_end = cdl_bottom;
2327                                 }
2328                         }
2329                 }
2330         }
2331
2332         /* Perform any output initialization. */
2333         MAYBE_DEVMETH(d, window_output_begin, (w));
2334
2335         /* If the window's structure has changed clear the internal border
2336            above it if it is topmost (the function will check). */
2337         if (f->windows_structure_changed || f->faces_changed)
2338                 redisplay_clear_top_of_window(w);
2339
2340         /* Output each line. */
2341         for (line = 0; line < Dynarr_length(ddla); line++) {
2342                 output_display_line(w, cdla, ddla, line, -1, -1);
2343         }
2344
2345         /* If the number of display lines has shrunk, adjust. */
2346         if (cdla_len > ddla_len) {
2347                 Dynarr_length(cdla) = ddla_len;
2348         }
2349
2350         /* Output a vertical divider between windows, if necessary. */
2351         if (window_needs_vertical_divider(w)
2352             && (f->windows_structure_changed || f->clear)) {
2353                 MAYBE_DEVMETH(d, output_vertical_divider,
2354                               (w, f->windows_structure_changed));
2355         }
2356
2357         /* Clear the rest of the window, if necessary. */
2358         if (need_to_clear_bottom) {
2359                 redisplay_clear_bottom_of_window(w, ddla, need_to_clear_start,
2360                                                  need_to_clear_end);
2361         }
2362
2363         w->window_end_pos[CURRENT_DISP] = w->window_end_pos[DESIRED_DISP];
2364         Fset_marker(w->start[CURRENT_DISP],
2365                     make_int(marker_position(w->start[DESIRED_DISP])),
2366                     w->buffer);
2367         Fset_marker(w->pointm[CURRENT_DISP],
2368                     make_int(marker_position(w->pointm[DESIRED_DISP])),
2369                     w->buffer);
2370         w->last_modified[CURRENT_DISP] = w->last_modified[DESIRED_DISP];
2371         w->last_facechange[CURRENT_DISP] = w->last_facechange[DESIRED_DISP];
2372         Fset_marker(w->last_start[CURRENT_DISP],
2373                     Fmarker_position(w->last_start[DESIRED_DISP]), w->buffer);
2374         Fset_marker(w->last_point[CURRENT_DISP],
2375                     Fmarker_position(w->last_point[DESIRED_DISP]), w->buffer);
2376         w->last_point_x[CURRENT_DISP] = w->last_point_x[DESIRED_DISP];
2377         w->last_point_y[CURRENT_DISP] = w->last_point_y[DESIRED_DISP];
2378         w->shadow_thickness_changed = 0;
2379
2380         set_window_display_buffer(w, XBUFFER(w->buffer));
2381         find_window_mirror(w)->truncate_win = window_truncation_on(w);
2382
2383         /* Overkill on invalidating the cache.  It is very bad for it to not
2384            get invalidated when it should be. */
2385         INVALIDATE_DEVICE_PIXEL_TO_GLYPH_CACHE(d);
2386
2387         redisplay_redraw_cursor(f, 0);
2388         MAYBE_DEVMETH(d, window_output_end, (w));
2389
2390 #ifdef HAVE_SCROLLBARS
2391         update_window_scrollbars(w, NULL, !MINI_WINDOW_P(w), 0);
2392 #endif
2393 }
2394
2395 /*****************************************************************************
2396  bevel_modeline
2397
2398  Draw a 3d border around the modeline on window W.
2399  ****************************************************************************/
2400 void bevel_modeline(struct window *w, struct display_line *dl)
2401 {
2402         struct frame *f = XFRAME(w->frame);
2403         struct device *d = XDEVICE(f->device);
2404         int x, y, width, height;
2405         int shadow_thickness = MODELINE_SHADOW_THICKNESS(w);
2406         enum edge_style style;
2407
2408         x = WINDOW_MODELINE_LEFT(w);
2409         width = WINDOW_MODELINE_RIGHT(w) - x;
2410         y = dl->ypos - dl->ascent - shadow_thickness;
2411         height = dl->ascent + dl->descent + 2 * shadow_thickness;
2412
2413         if (XINT(w->modeline_shadow_thickness) < 0) {
2414                 style = EDGE_BEVEL_IN;
2415         } else {
2416                 style = EDGE_BEVEL_OUT;
2417         }
2418
2419         MAYBE_DEVMETH(d, bevel_area,
2420                       (w, MODELINE_INDEX, x, y, width, height, shadow_thickness,
2421                        EDGE_ALL, style));
2422 }