+/* Sizing gutters is a pain so we try and help the user by determining
+ what height will accommodate all lines. This is useless on left and
+ right gutters as we always have a maximal number of lines. */
+static int
+calculate_gutter_size_from_display_lines (enum gutter_pos pos,
+ display_line_dynarr* ddla)
+{
+ int size = 0;
+ struct display_line *dl;
+
+ /* For top and bottom the calculation is easy. */
+ if (pos == TOP_GUTTER || pos == BOTTOM_GUTTER)
+ {
+ /* grab coordinates of last line */
+ if (Dynarr_length (ddla))
+ {
+ dl = Dynarr_atp (ddla, Dynarr_length (ddla) - 1);
+ size = (dl->ypos + dl->descent - dl->clip)
+ - (Dynarr_atp (ddla, 0)->ypos - Dynarr_atp (ddla, 0)->ascent);
+ }
+ }
+ /* For left and right we have to do some maths. */
+ else
+ {
+ int start_pos = 0, end_pos = 0, line;
+ for (line = 0; line < Dynarr_length (ddla); line++)
+ {
+ int block;
+ dl = Dynarr_atp (ddla, line);
+
+ for (block = 0; block < Dynarr_largest (dl->display_blocks); block++)
+ {
+ struct display_block *db = Dynarr_atp (dl->display_blocks, block);
+
+ if (db->type == TEXT)
+ {
+ start_pos = min (db->start_pos, start_pos);
+ end_pos = max (db->end_pos, end_pos);
+ }
+ }
+ }
+ size = end_pos - start_pos;
+ }
+
+ return size;
+}
+
+static Lisp_Object
+calculate_gutter_size (struct window *w, enum gutter_pos pos)
+{
+ struct frame* f = XFRAME (WINDOW_FRAME (w));
+ int count;
+ display_line_dynarr* ddla;
+ Lisp_Object ret = Qnil;
+
+ /* degenerate case */
+ if (NILP (RAW_WINDOW_GUTTER (w, pos))
+ ||
+ !FRAME_VISIBLE_P (f)
+ ||
+ NILP (w->buffer))
+ return Qnil;
+
+ /* Redisplay code that we use relies on GC not happening. Make it
+ so. */
+ count = specpdl_depth ();
+ record_unwind_protect (restore_gc_inhibit,
+ make_int (gc_currently_forbidden));
+ gc_currently_forbidden = 1;
+
+ ddla = Dynarr_new (display_line);
+ /* generate some display lines */
+ generate_displayable_area (w, WINDOW_GUTTER (w, pos),
+ FRAME_LEFT_BORDER_END (f),
+ FRAME_TOP_BORDER_END (f),
+ FRAME_RIGHT_BORDER_START (f)
+ - FRAME_LEFT_BORDER_END (f),
+ FRAME_BOTTOM_BORDER_START (f)
+ - FRAME_TOP_BORDER_END (f),
+ ddla, 0, 0);
+
+ /* Let GC happen again. */
+ unbind_to (count, Qnil);
+
+ ret = make_int (calculate_gutter_size_from_display_lines (pos, ddla));
+ free_display_lines (ddla);
+
+ return ret;
+}
+