XEmacs 21.2.32 "Kastor & Polydeukes".
[chise/xemacs-chise.git.1] / src / redisplay-output.c
index 16a27f2..b89f50f 100644 (file)
@@ -101,7 +101,7 @@ sync_rune_structs (struct window *w, rune_dynarr *cra, rune_dynarr *dra)
  For the given LINE in window W, make the current display line equal
  the desired display line.
  ****************************************************************************/
-static void
+void
 sync_display_line_structs (struct window *w, int line, int do_blocks,
                           display_line_dynarr *cdla,
                           display_line_dynarr *ddla)
@@ -211,10 +211,7 @@ compare_runes (struct window *w, struct rune *crb, struct rune *drb)
      #### It would really be worth it to arrange for this function to
      be (almost) a single call to memcmp. */
 
-  if ((crb->findex != drb->findex) ||
-      (WINDOW_FACE_CACHEL_DIRTY (w, drb->findex)))
-    return 0;
-  else if (crb->xpos != drb->xpos)
+  if (crb->xpos != drb->xpos)
     return 0;
   else if (crb->width != drb->width)
     return 0;
@@ -236,17 +233,67 @@ compare_runes (struct window *w, struct rune *crb, struct rune *drb)
     return 0;
   /* Only check dirtiness if we know something has changed. */
   else if (crb->type == RUNE_DGLYPH &&
-          XFRAME (w->frame)->glyphs_changed)
+          ((XFRAME (w->frame)->glyphs_changed &&
+            XGLYPH_DIRTYP (crb->object.dglyph.glyph)) || 
+           crb->findex != drb->findex))
     {
-      glyph_index gindex = get_glyph_cachel_index (w, drb->object.dglyph.glyph);
-      /* Although doing the cachel lookup for every comparison is
-        very expensive.we have to do it to make sure the cache is
-        up-to-date. */
-      if (GLYPH_CACHEL_DIRTYP (w, gindex))
+      /* We need some way of telling redisplay_output_layout () that the
+         only reason we are outputting it is because something has
+         changed internally. That way we can optimize whether we need
+         to clear the layout first and also only output the components
+         that have changed. The image_instance dirty flag and
+         display_hash are no good to us because these will invariably
+         have been set anyway if the layout has changed. So it looks
+         like we need yet another change flag that we can set here and
+         then clear in redisplay_output_layout (). */
+      Lisp_Object window, image;
+      Lisp_Image_Instance* ii;
+      XSETWINDOW (window, w);
+      image = glyph_image_instance (crb->object.dglyph.glyph,
+                                   window, ERROR_ME_NOT, 1);
+      ii = XIMAGE_INSTANCE (image);
+
+      if (TEXT_IMAGE_INSTANCEP (image) && 
+         (crb->findex != drb->findex || 
+          WINDOW_FACE_CACHEL_DIRTY (w, drb->findex)))
        return 0;
+
+      /* It is quite common of the two glyphs to be EQ since in many
+        cases they will actually be the same object. This does not
+        mean, however, that nothing has changed. We therefore need to
+        check the current hash of the glyph against the last recorded
+        display hash. See update_subwindow (). */
+      if (IMAGE_INSTANCE_DISPLAY_HASH (ii) == 0 ||
+         IMAGE_INSTANCE_DISPLAY_HASH (ii) != 
+         internal_hash (image, IMAGE_INSTANCE_HASH_DEPTH) ||
+         crb->findex != drb->findex || 
+         WINDOW_FACE_CACHEL_DIRTY (w, drb->findex))
+       {
+         /* We now now we are going to re-output the glyph, but since
+            this is for some internal reason not related to geometry
+            changes, send a hint to the output routines that they can
+            take some short cuts. This is most useful for
+            layouts. This flag should get reset by the output
+            routines. 
+
+            #### It is possible for us to get here when the
+            face_cachel is dirty. I do not know what the implications
+            of this are.*/
+         IMAGE_INSTANCE_OPTIMIZE_OUTPUT (ii) = 1;
+         return 0;
+       }
       else
        return 1;
     }
+  /* We now do this last so that glyph checks can do their own thing
+     for face changes. Face changes quite often happen when we are
+     trying to output something in the gutter, this would normally
+     lead to a lot of flashing. The indices can quite often be
+     different and yet the faces are the same, we do not want to
+     re-output in this instance. */
+  else  if (crb->findex != drb->findex ||
+           WINDOW_FACE_CACHEL_DIRTY (w, drb->findex))
+    return 0;
   else
     return 1;
 }
@@ -1067,6 +1114,8 @@ redisplay_output_display_block (struct window *w, struct display_line *dl, int b
 {
   struct frame *f = XFRAME (w->frame);
   struct device *d = XDEVICE (f->device);
+  /* Temporarily disabled until generalization is done. */
+#if 0
   struct display_block *db = Dynarr_atp (dl->display_blocks, block);
   rune_dynarr *rba = db->runes;
   struct rune *rb;
@@ -1084,6 +1133,7 @@ redisplay_output_display_block (struct window *w, struct display_line *dl, int b
 
   rb  = Dynarr_atp (rba, end - 1);
   width = rb->xpos + rb->width - xpos;
+#endif
   /* now actually output the block. */
   DEVMETH (d, output_display_block, (w, dl, block, start,
                                     end, start_pixpos,
@@ -1157,12 +1207,17 @@ redisplay_output_subwindow (struct window *w,
                            face_index findex, int cursor_start, int cursor_width,
                            int cursor_height)
 {
-  struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
+  Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
   Lisp_Object window;
   struct display_glyph_area sdga;
 
-  dga->height = IMAGE_INSTANCE_SUBWINDOW_HEIGHT (p);
-  dga->width = IMAGE_INSTANCE_SUBWINDOW_WIDTH (p);
+  dga->height = IMAGE_INSTANCE_HEIGHT (p);
+  dga->width = IMAGE_INSTANCE_WIDTH (p);
+
+  /* The first thing we are going to do is update the display
+     characteristics of the subwindow. This also clears the dirty
+     flags as a side effect. */
+  update_subwindow (image_instance);
 
   /* This makes the glyph area fit into the display area. */
   if (!redisplay_normalize_glyph_area (db, dga))
@@ -1187,8 +1242,8 @@ redisplay_output_subwindow (struct window *w,
      cases.*/
   sdga.xoffset = -dga->xoffset;
   sdga.yoffset = -dga->yoffset;
-  sdga.height = IMAGE_INSTANCE_SUBWINDOW_HEIGHT (p);
-  sdga.width = IMAGE_INSTANCE_SUBWINDOW_WIDTH (p);
+  sdga.height = IMAGE_INSTANCE_HEIGHT (p);
+  sdga.width = IMAGE_INSTANCE_WIDTH (p);
 
   if (redisplay_display_boxes_in_window_p (w, db, &sdga) < 0)
     {
@@ -1206,6 +1261,24 @@ redisplay_output_subwindow (struct window *w,
  redisplay_output_layout
 
  Output a widget hierarchy. This can safely call itself recursively.
+
+ The complexity of outputting layouts is deciding whether to do it or
+ not. Consider a layout enclosing some text, the text changes and is
+ marked as dirty, but the enclosing layout has not been marked as
+ dirty so no updates occur and the text will potentially be truncated.
+ Alternatively we hold a back pointer in the image instance to the
+ parent and mark the parent as dirty. But the layout code assumes that
+ if the layout is dirty then the whole layout should be redisplayed,
+ so we then get lots of flashing even though only the text has changed
+ size. Of course if the text shrinks in size then we do actually need
+ to redisplay the layout to repaint the exposed area. So what happens
+ if we make a non-structural change like changing color? Either we
+ redisplay everything, or we redisplay nothing. These are exactly the
+ issues lwlib has to grapple with. We really need to know what has
+ actually changed and make a layout decision based on that. We also
+ really need to know what has changed so that we can only make the
+ neccessary changes in update_subwindow.  This has all now been
+ implemented, Viva la revolution!
  ****************************************************************************/
 void
 redisplay_output_layout (struct window *w,
@@ -1214,28 +1287,17 @@ redisplay_output_layout (struct window *w,
                         face_index findex, int cursor_start, int cursor_width,
                         int cursor_height)
 {
-  struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
+  Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
   Lisp_Object window, rest;
   Emchar_dynarr *buf = Dynarr_new (Emchar);
   struct frame *f = XFRAME (w->frame);
   struct device *d = XDEVICE (f->device);
   int layout_height, layout_width;
-  /* We bogusly don't take f->extents_changed and f->glyphs_changed
-     into account. This is because if we do we always redisplay the
-     entire layout. So far I have seen no ill effects to we'll see. */
-  int frame_really_changed = (f->buffers_changed ||
-                             f->clip_changed ||
-                             f->faces_changed    ||
-                             f->frame_changed    ||
-                             f->modeline_changed ||
-                             f->subwindows_changed ||
-                             f->windows_changed ||
-                             f->windows_structure_changed);
 
   XSETWINDOW (window, w);
 
-  layout_height = glyph_height (image_instance, Qnil, findex, window);
-  layout_width = glyph_width (image_instance, Qnil, findex, window);
+  layout_height = glyph_height (image_instance, window);
+  layout_width = glyph_width (image_instance, window);
 
   dga->height = layout_height;
   dga->width = layout_width;
@@ -1246,7 +1308,11 @@ redisplay_output_layout (struct window *w,
 
   /* Highly dodgy optimization. We want to only output the whole
      layout if we really have to. */
-  if (frame_really_changed || IMAGE_INSTANCE_DIRTYP (p))
+  if (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT (p)
+      || IMAGE_INSTANCE_LAYOUT_CHANGED (p)
+      || IMAGE_INSTANCE_WIDGET_FACE_CHANGED (p)
+      || IMAGE_INSTANCE_SIZE_CHANGED (p)
+      || IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (p))
     {
       /* First clear the area we are drawing into. This is the easiest
         thing to do since we have many gaps that we have to make sure are
@@ -1314,13 +1380,17 @@ redisplay_output_layout (struct window *w,
       /* First determine if the image is visible at all */
       if (IMAGE_INSTANCEP (child))
        {
-         struct Lisp_Image_Instance* childii = XIMAGE_INSTANCE (child);
+         Lisp_Image_Instance* childii = XIMAGE_INSTANCE (child);
+
          /* The enclosing layout offsets are +ve at this point */
          struct display_glyph_area cdga;
          cdga.xoffset  = IMAGE_INSTANCE_XOFFSET (childii) - dga->xoffset;
          cdga.yoffset = IMAGE_INSTANCE_YOFFSET (childii) - dga->yoffset;
-         cdga.width = glyph_width (child, Qnil, findex, window);
-         cdga.height = glyph_height (child, Qnil, findex, window);
+         cdga.width = glyph_width (child, window);
+         cdga.height = glyph_height (child, window);
+
+         IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) = 
+           IMAGE_INSTANCE_OPTIMIZE_OUTPUT (p);
 
          /* Although normalization is done by the output routines
             we have to do it here so that they don't try and
@@ -1348,7 +1418,8 @@ redisplay_output_layout (struct window *w,
                       generalisation.*/
                    if (redisplay_normalize_glyph_area (&cdb, &cdga)
                        &&
-                       (frame_really_changed || IMAGE_INSTANCE_DIRTYP (childii)))
+                       (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) ||
+                        IMAGE_INSTANCE_DIRTYP (childii)))
                      {
                        struct display_line dl; /* this is fake */
                        Lisp_Object string =
@@ -1362,9 +1433,9 @@ redisplay_output_layout (struct window *w,
                        xzero (dl);
                        /* Munge boxes into display lines. */
                        dl.ypos = (cdb.ypos - cdga.yoffset)
-                         + glyph_ascent (child, Qnil, findex, window);
-                       dl.ascent = glyph_ascent (child, Qnil, findex, window);
-                       dl.descent = glyph_descent (child, Qnil, findex, window);
+                         + glyph_ascent (child, window);
+                       dl.ascent = glyph_ascent (child, window);
+                       dl.descent = glyph_descent (child, window);
                        dl.top_clip = cdga.yoffset;
                        dl.clip = (dl.ypos + dl.descent) - (cdb.ypos + cdb.height);
                        /* output_string doesn't understand offsets in
@@ -1382,14 +1453,16 @@ redisplay_output_layout (struct window *w,
 
                case IMAGE_MONO_PIXMAP:
                case IMAGE_COLOR_PIXMAP:
-                 if (frame_really_changed || IMAGE_INSTANCE_DIRTYP (childii))
+                 if (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii)
+                     || IMAGE_INSTANCE_DIRTYP (childii))
                    redisplay_output_pixmap (w, child, &cdb, &cdga, findex,
                                             0, 0, 0, 0);
                  break;
 
                case IMAGE_WIDGET:
                case IMAGE_SUBWINDOW:
-                 if (frame_really_changed || IMAGE_INSTANCE_DIRTYP (childii))
+                 if (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) ||
+                     IMAGE_INSTANCE_DIRTYP (childii))
                    redisplay_output_subwindow (w, child, &cdb, &cdga, findex,
                                                0, 0, 0);
                  break;
@@ -1408,8 +1481,14 @@ redisplay_output_layout (struct window *w,
                  abort ();
                }
            }
+         IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) = 0;
        }
     }
+  
+  /* Update any display properties. I'm not sure whether this actually
+     does anything for layouts except clear the changed flags. */
+  update_subwindow (image_instance);
+
   Dynarr_free (buf);
 }
 
@@ -1428,7 +1507,7 @@ redisplay_output_pixmap (struct window *w,
 {
   struct frame *f = XFRAME (w->frame);
   struct device *d = XDEVICE (f->device);
-  struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
+  Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
   Lisp_Object window;
   XSETWINDOW (window, w);