changeset 90541:b7130e76c2f9

Include window.h. (font_lispy_object): New function. (font_prepare_composition): Check LGLYPH_FORM (g) to detect the end of valid glyph. (font_close_object): Fix getting (struct font *). (font_at): New function. (Ffont_get): If FONT is a font-object, get entity from it. (Ffont_make_gstring): Initialize elements of glyphs with nil. (Ffont_fill_gstring): Use macro LGSTRING_XXX and LGLYPH_XXX. Fix range check. (Ffont_at): New function. (syms_of_font): Defsubr Sfont_at.
author Kenichi Handa <handa@m17n.org>
date Mon, 24 Jul 2006 04:42:53 +0000
parents a4c3599e9f9b
children 2be199f501f8
files src/font.c
diffstat 1 files changed, 114 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/src/font.c	Mon Jul 24 04:38:53 2006 +0000
+++ b/src/font.c	Mon Jul 24 04:42:53 2006 +0000
@@ -29,6 +29,7 @@
 #include "lisp.h"
 #include "buffer.h"
 #include "frame.h"
+#include "window.h"
 #include "dispextern.h"
 #include "charset.h"
 #include "character.h"
@@ -1416,6 +1417,23 @@
     }
 }
 
+static Lisp_Object
+font_lispy_object (font)
+     struct font *font;
+{
+  Lisp_Object objlist = AREF (font->entity, FONT_OBJLIST_INDEX);
+
+  for (; ! NILP (objlist); objlist = XCDR (objlist))
+    {
+      struct Lisp_Save_Value *p = XSAVE_VALUE (XCAR (objlist));
+
+      if (font == (struct font *) p->pointer)
+	break;
+    }
+  xassert (! NILP (objlist));
+  return XCAR (objlist);
+}
+
 
 /* OTF handler */
 
@@ -1843,7 +1861,7 @@
 /* GSTRING is a vector of this form:
 	[ [FONT-OBJECT LBEARING RBEARING WIDTH ASCENT DESCENT] GLYPH ... ]
    and GLYPH is a vector of this form:
-	[ FROM-IDX TO-IDX C CODE [ [X-OFF Y-OFF WIDTH WADJUST] | nil] ]
+	[ FROM-IDX TO-IDX C CODE WIDTH [ [X-OFF Y-OFF WADJUST] | nil] ]
    where
 	FROM-IDX and TO-IDX are used internally and should not be touched.
 	C is a character of the glyph.
@@ -1871,9 +1889,12 @@
   for (i = 0; i < len; i++)
     {
       Lisp_Object g = LGSTRING_GLYPH (gstring, i);
-      unsigned code = XINT (LGLYPH_CODE (g));
+      unsigned code;
       struct font_metrics metrics;
 
+      if (NILP (LGLYPH_FROM (g)))
+	break;
+      code = XINT (LGLYPH_CODE (g));
       font->driver->text_extents (font, &code, 1, &metrics);
       LGLYPH_SET_WIDTH (g, make_number (metrics.width));
       metrics.lbearing += LGLYPH_XOFF (g);
@@ -2316,30 +2337,30 @@
      FRAME_PTR f;
      Lisp_Object font_object;
 {
-  struct font *font;
-  Lisp_Object objlist = AREF (font->entity, FONT_OBJLIST_INDEX);
+  struct font *font = XSAVE_VALUE (font_object)->pointer;
+  Lisp_Object objlist;
   Lisp_Object tail, prev = Qnil;
 
+  XSAVE_VALUE (font_object)->integer--;
+  xassert (XSAVE_VALUE (font_object)->integer >= 0);
+  if (XSAVE_VALUE (font_object)->integer > 0)
+    return;
+
+  objlist = AREF (font->entity, FONT_OBJLIST_INDEX);
   for (prev = Qnil, tail = objlist; CONSP (tail);
        prev = tail, tail = XCDR (tail))
     if (EQ (font_object, XCAR (tail)))
       {
-	struct Lisp_Save_Value *p = XSAVE_VALUE (font_object);
-
-	xassert (p->integer > 0);
-	p->integer--;
-	if (p->integer == 0)
-	  {
-	    if (font->driver->close)
-	      font->driver->close (f, p->pointer);
-	    p->pointer = NULL;
-	    if (NILP (prev))
-	      ASET (font->entity, FONT_OBJLIST_INDEX, XCDR (objlist));
-	    else
-	      XSETCDR (prev, XCDR (objlist));
-	  }
-	break;
+	if (font->driver->close)
+	  font->driver->close (f, font);
+	XSAVE_VALUE (font_object)->pointer = NULL;
+	if (NILP (prev))
+	  ASET (font->entity, FONT_OBJLIST_INDEX, XCDR (objlist));
+	else
+	  XSETCDR (prev, XCDR (objlist));
+	return;
       }
+  abort ();
 }
 
 int
@@ -2678,6 +2699,36 @@
     }
 }
 
+Lisp_Object
+font_at (c, pos, face, w, object)
+     int c;
+     EMACS_INT pos;
+     struct face *face;
+     struct window *w;
+     Lisp_Object object;
+{
+  FRAME_PTR f;
+  int face_id;
+  int dummy;
+
+  f = XFRAME (w->frame);
+  if (! face)
+    {
+      if (STRINGP (object))
+	face_id = face_at_string_position (w, object, pos, 0, -1, -1, &dummy,
+					   DEFAULT_FACE_ID, 0);
+      else
+	face_id = face_at_buffer_position (w, pos, -1, -1, &dummy,
+					   pos + 100, 0);
+      face = FACE_FROM_ID (f, face_id);
+    }
+  face_id = FACE_FOR_CHAR (f, face, c, pos, object);
+  face = FACE_FROM_ID (f, face_id);
+  if (! face->font_info)
+    return Qnil;
+  return font_lispy_object ((struct font *) face->font_info);
+}
+
 
 /* Lisp API */
 
@@ -2732,7 +2783,10 @@
 {
   enum font_property_index idx;
 
-  CHECK_FONT (font);
+  if (FONT_OBJECT_P (font))
+    font = ((struct font *) XSAVE_VALUE (font)->pointer)->entity;
+  else
+    CHECK_FONT (font);
   idx = get_font_prop_index (prop, 0);
   if (idx < FONT_EXTRA_INDEX)
     return AREF (font, idx);
@@ -2998,7 +3052,7 @@
   ASET (g, 0, font_object);
   ASET (gstring, 0, g);
   for (i = 1; i < len; i++)
-    ASET (gstring, i, Fmake_vector (make_number (8), make_number (0)));
+    ASET (gstring, i, Fmake_vector (make_number (8), Qnil));
   return gstring;
 }
 
@@ -3017,7 +3071,7 @@
 
   CHECK_VECTOR (gstring);
   if (NILP (font_object))
-    font_object = Faref (Faref (gstring, make_number (0)), make_number (0));
+    font_object = LGSTRING_FONT (gstring);
   CHECK_FONT_GET_OBJECT (font_object, font);
 
   if (STRINGP (object))
@@ -3028,7 +3082,7 @@
       CHECK_NATNUM (end);
       if (XINT (start) > XINT (end)
 	  || XINT (end) > ASIZE (object)
-	  || XINT (end) - XINT (start) >= XINT (Flength (gstring)))
+	  || XINT (end) - XINT (start) > LGSTRING_LENGTH (gstring))
 	args_out_of_range (start, end);
 
       len = XINT (end) - XINT (start);
@@ -3041,8 +3095,8 @@
 	  code = font->driver->encode_char (font, c);
 	  if (code > MOST_POSITIVE_FIXNUM)
 	    error ("Glyph code 0x%X is too large", code);
-	  ASET (g, 0, make_number (i));
-	  ASET (g, 1, make_number (i + 1));
+	  LGLYPH_SET_FROM (g, make_number (i));
+	  LGLYPH_SET_TO (g, make_number (i + 1));
 	  LGLYPH_SET_CHAR (g, make_number (c));
 	  LGLYPH_SET_CODE (g, make_number (code));
 	}
@@ -3054,7 +3108,7 @@
       if (! NILP (object))
 	Fset_buffer (object);
       validate_region (&start, &end);
-      if (XINT (end) - XINT (start) > len)
+      if (XINT (end) - XINT (start) > LGSTRING_LENGTH (gstring))
 	args_out_of_range (start, end);
       len = XINT (end) - XINT (start);
       pos = XINT (start);
@@ -3067,12 +3121,18 @@
 	  code = font->driver->encode_char (font, c);
 	  if (code > MOST_POSITIVE_FIXNUM)
 	    error ("Glyph code 0x%X is too large", code);
-	  ASET (g, 0, make_number (i));
-	  ASET (g, 1, make_number (i + 1));
+	  LGLYPH_SET_FROM (g, make_number (i));
+	  LGLYPH_SET_TO (g, make_number (i + 1));
 	  LGLYPH_SET_CHAR (g, make_number (c));
 	  LGLYPH_SET_CODE (g, make_number (code));
 	}
     }
+  for (i = LGSTRING_LENGTH (gstring) - 1; i >= len; i--)
+    {
+      Lisp_Object g = LGSTRING_GLYPH (gstring, i);
+
+      LGLYPH_SET_FROM (g, Qnil);
+    }
   return Qnil;
 }
 
@@ -3199,6 +3259,31 @@
   return (font_match_p (spec, font) ? Qt : Qnil);
 }
 
+DEFUN ("font-at", Ffont_at, Sfont_at, 1, 2, 0,
+       doc: /* Return a font-object for displaying a character at POSISTION.
+Optional second arg WINDOW, if non-nil, is a window displaying
+the current buffer.  It defaults to the currently selected window.  */)
+     (position, window)
+     Lisp_Object position, window;
+{
+  struct window *w;
+  EMACS_INT pos, pos_byte;
+  int c;
+
+  CHECK_NUMBER_COERCE_MARKER (position);
+  pos = XINT (position);
+  if (pos < BEGV || pos >= ZV)
+    args_out_of_range_3 (position, make_number (BEGV), make_number (ZV));
+  pos_byte = CHAR_TO_BYTE (pos);
+  c = FETCH_CHAR (pos_byte);
+  if (NILP (window))
+    window = selected_window;
+  CHECK_LIVE_WINDOW (window);
+  w = XWINDOW (selected_window);
+
+  return font_at (c, pos, NULL, w, Qnil);
+}
+
 #if 0
 DEFUN ("draw-string", Fdraw_string, Sdraw_string, 2, 2, 0,
        doc: /*  Draw STRING by FONT-OBJECT on the top left corner of the current frame.
@@ -3323,6 +3408,7 @@
   defsubr (&Squery_font);
   defsubr (&Sget_font_glyphs);
   defsubr (&Sfont_match_p);
+  defsubr (&Sfont_at);
 #if 0
   defsubr (&Sdraw_string);
 #endif