patch 8.1.1751: when redrawing popups plines_win() may be called often

Problem:    When redrawing popups plines_win() may be called often.
Solution:   Pass a cache to mouse_comp_pos().
diff --git a/src/beval.c b/src/beval.c
index 3dd9b67..69e667d 100644
--- a/src/beval.c
+++ b/src/beval.c
@@ -43,7 +43,7 @@
     {
 	// Found a window and the cursor is in the text.  Now find the line
 	// number.
-	if (!mouse_comp_pos(wp, &row, &col, &lnum))
+	if (!mouse_comp_pos(wp, &row, &col, &lnum, NULL))
 	{
 	    // Not past end of the file.
 	    lbuf = ml_get_buf(wp->w_buffer, lnum, FALSE);
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 73efa79..685e2f1 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -4738,7 +4738,7 @@
 		win = mouse_find_win(&row, &col, FIND_POPUP);
 		if (win == NULL)
 		    return;
-		(void)mouse_comp_pos(win, &row, &col, &lnum);
+		(void)mouse_comp_pos(win, &row, &col, &lnum, NULL);
 # ifdef FEAT_TEXT_PROP
 		if (WIN_IS_POPUP(win))
 		    winnr = 0;
diff --git a/src/popupwin.c b/src/popupwin.c
index a303582..d0f6156 100644
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -2593,6 +2593,10 @@
     // Only check which lines are to be updated if not already
     // updating all lines.
     if (mask == popup_mask_next)
+    {
+	int	    *plines_cache = ALLOC_CLEAR_MULT(int, Rows);
+	win_T	    *prev_wp = NULL;
+
 	for (line = 0; line < screen_Rows; ++line)
 	{
 	    int	    col_done = 0;
@@ -2625,13 +2629,19 @@
 			wp = mouse_find_win(&line_cp, &col_cp, IGNORE_POPUP);
 			if (wp != NULL)
 			{
+			    if (wp != prev_wp)
+			    {
+				vim_memset(plines_cache, 0, sizeof(int) * Rows);
+				prev_wp = wp;
+			    }
+
 			    if (line_cp >= wp->w_height)
 				// In (or below) status line
 				wp->w_redr_status = TRUE;
 			    // compute the position in the buffer line from the
 			    // position on the screen
 			    else if (mouse_comp_pos(wp, &line_cp, &col_cp,
-									&lnum))
+							  &lnum, plines_cache))
 				// past bottom
 				wp->w_redr_status = TRUE;
 			    else
@@ -2645,6 +2655,9 @@
 		}
 	    }
 	}
+
+	vim_free(plines_cache);
+    }
 }
 
 /*
diff --git a/src/proto/ui.pro b/src/proto/ui.pro
index 7b28a32..472da36 100644
--- a/src/proto/ui.pro
+++ b/src/proto/ui.pro
@@ -64,7 +64,7 @@
 int clip_x11_owner_exists(Clipboard_T *cbd);
 void yank_cut_buffer0(Display *dpy, Clipboard_T *cbd);
 int jump_to_mouse(int flags, int *inclusive, int which_button);
-int mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump);
+int mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump, int *plines_cache);
 win_T *mouse_find_win(int *rowp, int *colp, mouse_find_T popup);
 int get_fpos_of_mouse(pos_T *mpos);
 int vcol2col(win_T *wp, linenr_T lnum, int vcol);
diff --git a/src/ui.c b/src/ui.c
index 1e6c146..5d04e1b 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -3381,7 +3381,7 @@
 #endif
 
     /* compute the position in the buffer line from the posn on the screen */
-    if (mouse_comp_pos(curwin, &row, &col, &curwin->w_cursor.lnum))
+    if (mouse_comp_pos(curwin, &row, &col, &curwin->w_cursor.lnum, NULL))
 	mouse_past_bottom = TRUE;
 
     /* Start Visual mode before coladvance(), for when 'sel' != "old" */
@@ -3429,8 +3429,12 @@
 #if defined(FEAT_MOUSE) || defined(FEAT_TEXT_PROP) || defined(PROTO)
 
 /*
- * Compute the position in the buffer line from the posn on the screen in
+ * Compute the buffer line position from the screen position "rowp" / "colp" in
  * window "win".
+ * "plines_cache" can be NULL (no cache) or an array with "win->w_height"
+ * entries that caches the plines_win() result from a previous call.  Entry is
+ * zero if not computed yet.  There must be no text or setting changes since
+ * the entry is put in the cache.
  * Returns TRUE if the position is below the last line.
  */
     int
@@ -3438,7 +3442,8 @@
     win_T	*win,
     int		*rowp,
     int		*colp,
-    linenr_T	*lnump)
+    linenr_T	*lnump,
+    int		*plines_cache)
 {
     int		col = *colp;
     int		row = *rowp;
@@ -3456,23 +3461,32 @@
 
     while (row > 0)
     {
-#ifdef FEAT_DIFF
-	/* Don't include filler lines in "count" */
-	if (win->w_p_diff
-# ifdef FEAT_FOLDING
-		&& !hasFoldingWin(win, lnum, NULL, NULL, TRUE, NULL)
-# endif
-		)
-	{
-	    if (lnum == win->w_topline)
-		row -= win->w_topfill;
-	    else
-		row -= diff_check_fill(win, lnum);
-	    count = plines_win_nofill(win, lnum, TRUE);
-	}
+	int cache_idx = lnum - win->w_topline;
+
+	if (plines_cache != NULL && plines_cache[cache_idx] > 0)
+	    count = plines_cache[cache_idx];
 	else
+	{
+#ifdef FEAT_DIFF
+	    /* Don't include filler lines in "count" */
+	    if (win->w_p_diff
+# ifdef FEAT_FOLDING
+		    && !hasFoldingWin(win, lnum, NULL, NULL, TRUE, NULL)
+# endif
+		    )
+	    {
+		if (lnum == win->w_topline)
+		    row -= win->w_topfill;
+		else
+		    row -= diff_check_fill(win, lnum);
+		count = plines_win_nofill(win, lnum, TRUE);
+	    }
+	    else
 #endif
-	    count = plines_win(win, lnum, TRUE);
+		count = plines_win(win, lnum, TRUE);
+	    if (plines_cache != NULL)
+		plines_cache[cache_idx] = count;
+	}
 	if (count > row)
 	    break;	/* Position is in this buffer line. */
 #ifdef FEAT_FOLDING
@@ -3626,7 +3640,7 @@
 	return IN_UNKNOWN;
 
     /* compute the position in the buffer line from the posn on the screen */
-    if (mouse_comp_pos(curwin, &row, &col, &mpos->lnum))
+    if (mouse_comp_pos(curwin, &row, &col, &mpos->lnum, NULL))
 	return IN_STATUS_LINE; /* past bottom */
 
     mpos->col = vcol2col(wp, mpos->lnum, col);
diff --git a/src/version.c b/src/version.c
index 5c75078..5104f6a 100644
--- a/src/version.c
+++ b/src/version.c
@@ -778,6 +778,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1751,
+/**/
     1750,
 /**/
     1749,