]> git.eshelyaron.com Git - emacs.git/commitdiff
Initial partial support for mouse highlight in bidi-reordered text.
authorEli Zaretskii <eliz@gnu.org>
Sat, 21 Aug 2010 15:24:15 +0000 (18:24 +0300)
committerEli Zaretskii <eliz@gnu.org>
Sat, 21 Aug 2010 15:24:15 +0000 (18:24 +0300)
 xdisp.c (mouse_face_from_buffer_pos): Support mouse highlight in
 bidi-reordered L2R lines.  Continued lines are not yet supported.

src/ChangeLog
src/xdisp.c

index 403a588df4cb9dbf890b031fe87ef36e27001dc3..242018c406159fadd4c763d7043fd41c233432dd 100644 (file)
@@ -1,5 +1,8 @@
 2010-08-21  Eli Zaretskii  <eliz@gnu.org>
 
+       * xdisp.c (mouse_face_from_buffer_pos): Support mouse highlight in
+       bidi-reordered L2R lines.  Continued lines are not yet supported.
+
        * dispnew.c (buffer_posn_from_coords): Fix off-by-one error in
        mirroring pixel positions.
 
index c80e1f35df37bfde7c4d959494ac98cffc3ab92c..7fcbab718b1d7dc10e4246f5f6496c130a7731d6 100644 (file)
@@ -23839,7 +23839,7 @@ mouse_face_from_buffer_pos (Lisp_Object window,
   struct glyph_row *first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
   struct glyph_row *row;
   struct glyph *glyph, *end;
-  EMACS_INT ignore;
+  EMACS_INT ignore, pos;
   int x;
 
   xassert (NILP (display_string) || STRINGP (display_string));
@@ -23847,7 +23847,9 @@ mouse_face_from_buffer_pos (Lisp_Object window,
   xassert (NILP (after_string) || STRINGP (after_string));
 
   /* Find the first highlighted glyph.  */
-  if (start_charpos < MATRIX_ROW_START_CHARPOS (first))
+  if (start_charpos < MATRIX_ROW_START_CHARPOS (first)
+      && (NILP (XBUFFER (w->buffer)->bidi_display_reordering)
+         || row_containing_pos (w, start_charpos, first, NULL, 0) == NULL))
     {
       dpyinfo->mouse_face_beg_col = 0;
       dpyinfo->mouse_face_beg_row = MATRIX_ROW_VPOS (first, w->current_matrix);
@@ -23856,6 +23858,10 @@ mouse_face_from_buffer_pos (Lisp_Object window,
     }
   else
     {
+      /* FIXME: this assumes that START_CHARPOS is in beg_row.  This
+        is false for reordered lines that are continued.  Need to
+        compute beg_row and end_row separately from beg_col and
+        end_col.  */
       row = row_containing_pos (w, start_charpos, first, NULL, 0);
       if (row == NULL)
        row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
@@ -23880,33 +23886,72 @@ mouse_face_from_buffer_pos (Lisp_Object window,
            }
        }
 
-      glyph = row->glyphs[TEXT_AREA];
-      end = glyph + row->used[TEXT_AREA];
-      x = row->x;
       dpyinfo->mouse_face_beg_y = row->y;
       dpyinfo->mouse_face_beg_row = MATRIX_ROW_VPOS (row, w->current_matrix);
 
-      /* Skip truncation glyphs at the start of the glyph row.  */
-      if (row->displays_text_p)
-       for (; glyph < end
-              && INTEGERP (glyph->object)
-              && glyph->charpos < 0;
-            ++glyph)
-         x += glyph->pixel_width;
-
-      /* Scan the glyph row, stopping before BEFORE_STRING or
-        DISPLAY_STRING or START_CHARPOS.  */
-      for (; glyph < end
-            && !INTEGERP (glyph->object)
-            && !EQ (glyph->object, before_string)
-            && !EQ (glyph->object, display_string)
-            && !(BUFFERP (glyph->object)
-                 && glyph->charpos >= start_charpos);
-          ++glyph)
-       x += glyph->pixel_width;
+      /* For a bidi-reordered row, the positions of BEFORE_STRING,
+        AFTER_STRING, DISPLAY_STRING, START_CHARPOS, and END_CHARPOS
+        could be anywhere in the row and in any order.  The strategy
+        below is to find the leftmost and the rightmost glyph that
+        belongs to either of these 3 strings, or whose position is
+        between START_CHARPOS and END_CHARPOS, and highlight all the
+        glyphs between those two.  This may cover more than just the
+        text between START_CHARPOS and END_CHARPOS if the range of
+        characters strides the the bidi level boundary, e.g. if the
+        beginning is in R2L text while the end is in L2R text or vice
+        versa.  */
+      if (!row->reversed_p)
+       {
+         /* This row is in a left to right paragraph.  Scan it left
+            to right.  */
+         glyph = row->glyphs[TEXT_AREA];
+         end = glyph + row->used[TEXT_AREA];
+         x = row->x;
+
+         /* Skip truncation glyphs at the start of the glyph row.  */
+         if (row->displays_text_p)
+           for (; glyph < end
+                  && INTEGERP (glyph->object)
+                  && glyph->charpos < 0;
+                ++glyph)
+             x += glyph->pixel_width;
 
-      dpyinfo->mouse_face_beg_x = x;
-      dpyinfo->mouse_face_beg_col = glyph - row->glyphs[TEXT_AREA];
+      /* Scan the glyph row, looking for BEFORE_STRING, AFTER_STRING,
+        or DISPLAY_STRING, and the first glyph whose position is
+        between START_CHARPOS and END_CHARPOS.  */
+         for (; glyph < end
+                && !INTEGERP (glyph->object)
+                && !EQ (glyph->object, display_string)
+                && !(BUFFERP (glyph->object)
+                     && (glyph->charpos >= start_charpos
+                         && glyph->charpos < end_charpos));
+              ++glyph)
+           {
+             /* BEFORE_STRING or AFTER_STRING are only relevant if
+                they are present at buffer positions between
+                START_CHARPOS and END_CHARPOS.  */
+             if (EQ (glyph->object, before_string))
+               {
+                 pos = string_buffer_position (w, before_string,
+                                               start_charpos);
+                 if (pos && pos >= start_charpos && pos < end_charpos)
+                   break;
+               }
+             else if (EQ (glyph->object, after_string))
+               {
+                 pos = string_buffer_position (w, after_string, end_charpos);
+                 if (pos && pos >= start_charpos && pos < end_charpos)
+                   break;
+               }
+             x += glyph->pixel_width;
+           }
+         dpyinfo->mouse_face_beg_x = x;
+         dpyinfo->mouse_face_beg_col = glyph - row->glyphs[TEXT_AREA];
+       }
+      else
+       {
+         /* FIXME! */
+       }
     }
 
   /* Find the last highlighted glyph.  */
@@ -23931,60 +23976,54 @@ mouse_face_from_buffer_pos (Lisp_Object window,
        row = next;
     }
 
-  glyph = row->glyphs[TEXT_AREA];
-  end = glyph + row->used[TEXT_AREA];
-  x = row->x;
   dpyinfo->mouse_face_end_y = row->y;
   dpyinfo->mouse_face_end_row = MATRIX_ROW_VPOS (row, w->current_matrix);
 
-  /* Skip truncation glyphs at the start of the row.  */
-  if (row->displays_text_p)
-    for (; glyph < end
-          && INTEGERP (glyph->object)
-          && glyph->charpos < 0;
-        ++glyph)
-      x += glyph->pixel_width;
-
-  /* Scan the glyph row, stopping at END_CHARPOS or when we encounter
-     AFTER_STRING.  */
-  for (; glyph < end
-        && !INTEGERP (glyph->object)
-        && !EQ (glyph->object, after_string)
-        && !(BUFFERP (glyph->object) && glyph->charpos >= end_charpos);
-       ++glyph)
-    x += glyph->pixel_width;
-
-  /* If we found AFTER_STRING, consume it and stop.  */
-  if (EQ (glyph->object, after_string))
+  if (!row->reversed_p)
     {
-      for (; EQ (glyph->object, after_string) && glyph < end; ++glyph)
+      /* Skip truncation and continuation glyphs near the end of the
+        row, and also blanks and stretch glyphs inserted by
+        extend_face_to_end_of_line.  */
+      while (end > glyph
+            && INTEGERP ((end - 1)->object)
+            && (end - 1)->charpos <= 0)
+       --end;
+      /* Scan the rest of the glyph row from the end, looking for the
+        first glyph that comes from BEFORE_STRING, AFTER_STRING, or
+        DISPLAY_STRING, or whose position is between START_CHARPOS
+        and END_CHARPOS */
+      for (--end;
+            end > glyph
+            && !INTEGERP (end->object)
+            && !EQ (end->object, display_string)
+            && !(BUFFERP (end->object)
+                 && (end->charpos >= start_charpos
+                     && end->charpos < end_charpos));
+          --end)
+       {
+         /* BEFORE_STRING or AFTER_STRING are only relevant if
+            they are present at buffer positions between
+            START_CHARPOS and END_CHARPOS.  */
+         if (EQ (end->object, before_string))
+           {
+             pos = string_buffer_position (w, before_string, start_charpos);
+             if (pos && pos >= start_charpos && pos < end_charpos)
+               break;
+           }
+         else if (EQ (end->object, after_string))
+           {
+             pos = string_buffer_position (w, after_string, end_charpos);
+             if (pos && pos >= start_charpos && pos < end_charpos)
+               break;
+           }
+       }
+      /* Find the X coordinate of the last glyph to be highlighted.  */
+      for (; glyph <= end; ++glyph)
        x += glyph->pixel_width;
     }
   else
     {
-      /* If there's no after-string, we must check if we overshot,
-        which might be the case if we stopped after a string glyph.
-        That glyph may belong to a before-string or display-string
-        associated with the end position, which must not be
-        highlighted.  */
-      Lisp_Object prev_object;
-      EMACS_INT pos;
-
-      while (glyph > row->glyphs[TEXT_AREA])
-       {
-         prev_object = (glyph - 1)->object;
-         if (!STRINGP (prev_object) || EQ (prev_object, display_string))
-           break;
-
-         pos = string_buffer_position (w, prev_object, end_charpos);
-         if (pos && pos < end_charpos)
-           break;
-
-         for (; glyph > row->glyphs[TEXT_AREA]
-                && EQ ((glyph - 1)->object, prev_object);
-              --glyph)
-           x -= (glyph - 1)->pixel_width;
-       }
+      /* FIXME! */
     }
 
   dpyinfo->mouse_face_end_x = x;