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