mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-27 07:37:33 +00:00
New file.
This commit is contained in:
parent
4ed925c668
commit
c2f5bfd68d
2571
src/font.c
Normal file
2571
src/font.c
Normal file
File diff suppressed because it is too large
Load Diff
479
src/font.h
Normal file
479
src/font.h
Normal file
@ -0,0 +1,479 @@
|
||||
/* font.h -- Interface definition for font handling.
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
Copyright (C) 2006
|
||||
National Institute of Advanced Industrial Science and Technology (AIST)
|
||||
Registration Number H13PRO009
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#ifndef EMACS_FONT_H
|
||||
#define EMACS_FONT_H
|
||||
|
||||
#include "ccl.h"
|
||||
|
||||
/* We have three types of Lisp objects related to font.
|
||||
|
||||
FONT-SPEC
|
||||
|
||||
Vector (length FONT_SPEC_MAX) of font properties. Some
|
||||
properties can be left unspecified (i.e. nil). Emacs asks
|
||||
font-drivers to find a font by FONT-SPEC. A fontset entry
|
||||
specifies requisite properties whereas a face specifies just
|
||||
preferable properties. This object is fully modifiable by
|
||||
Lisp.
|
||||
|
||||
FONT-ENTITY
|
||||
|
||||
Vector (length FONT_ENTITY_MAX) of fully specified font
|
||||
properties that a font-driver returns upon a request of
|
||||
FONT-SPEC.
|
||||
|
||||
Note: Only the method `list' of a font-driver can create this
|
||||
object, and should never be modified by Lisp. In that sense,
|
||||
it may be cleaner to implement it as a Lisp object of a new
|
||||
type (e.g. struct Lisp_Font).
|
||||
|
||||
FONT-OBJECT
|
||||
|
||||
Lisp object of type Lisp_Misc_Save_Value encapsulating a
|
||||
pointer to "struct font". This corresponds to an opened font.
|
||||
|
||||
Note: The note for FONT-ENTITY also applies to this.
|
||||
*/
|
||||
|
||||
|
||||
struct font_driver;
|
||||
struct font;
|
||||
|
||||
/* An enumerator for each font property. This is used as an index to
|
||||
the vector of FONT-SPEC and FONT-ENTITY.
|
||||
|
||||
Note: The order is important and should not be changed. */
|
||||
|
||||
enum font_property_index
|
||||
{
|
||||
/* FONT-TYPE is a symbol indicating a font backend; currently `x',
|
||||
`xft', `ftx', `freetype' are available. For windows, we need
|
||||
`bdf' and `windows'. For Mac OS X, we need `atm'. */
|
||||
FONT_TYPE_INDEX,
|
||||
|
||||
/* FONT-FOUNDRY is a foundry name (symbol). */
|
||||
FONT_FOUNDRY_INDEX,
|
||||
|
||||
/* FONT-FAMILY is a family name (symbol). */
|
||||
FONT_FAMILY_INDEX,
|
||||
|
||||
/* FONT-ADSTYLE is an additional style name (symbol). */
|
||||
FONT_ADSTYLE_INDEX,
|
||||
|
||||
/* FONT-REGISTRY is a combination of a charset-registry and
|
||||
charset0encoding name (symbol). */
|
||||
FONT_REGISTRY_INDEX,
|
||||
|
||||
/* FONT-WEIGHT is a numeric value of weight (e.g. medium, bold) of
|
||||
the font. The value is what defined by FC_WEIGHT_* in
|
||||
fontconfig. */
|
||||
FONT_WEIGHT_INDEX,
|
||||
|
||||
/* FONT-SLANT is a numeric value of slant (e.g. r, i, o) of the
|
||||
font. The value is what defined by FC_SLANT_* in
|
||||
fontconfig plus 100. */
|
||||
FONT_SLANT_INDEX,
|
||||
|
||||
/* FONT-WIDTH is a numeric value of setwidth (e.g. normal,
|
||||
condensed) of the font. The value is what defined by
|
||||
FC_WIDTH_* in fontconfig. */
|
||||
FONT_WIDTH_INDEX,
|
||||
|
||||
/* FONT-SIZE is a size of the font. If integer, it is a pixel
|
||||
size. For a font-spec, the value can be float specifying a
|
||||
point size. For a font-entity, the value can be zero meaning
|
||||
that the font is scalable. */
|
||||
FONT_SIZE_INDEX,
|
||||
|
||||
/* In a font-spec, the value is an alist of extra information of a
|
||||
font such as name, OpenType features, and language coverage.
|
||||
In a font-entity, the value is an extra infomation for
|
||||
identifying a font (font-driver dependent). */
|
||||
FONT_EXTRA_INDEX, /* alist alist */
|
||||
|
||||
/* This value is the length of font-spec vector. */
|
||||
FONT_SPEC_MAX,
|
||||
|
||||
/* The followings are used only for a font-entity. */
|
||||
|
||||
/* Frame on which the font is found. The value is nil if the font
|
||||
can be opend on any frame. */
|
||||
FONT_FRAME_INDEX = FONT_SPEC_MAX,
|
||||
|
||||
/* List of font-objects opened from the font-entity. */
|
||||
FONT_OBJLIST_INDEX,
|
||||
|
||||
/* This value is the length of font-entity vector. */
|
||||
FONT_ENTITY_MAX
|
||||
};
|
||||
|
||||
extern Lisp_Object QCotf, QClanguage, QCscript;
|
||||
|
||||
extern Lisp_Object null_string;
|
||||
extern Lisp_Object null_vector;
|
||||
|
||||
/* Structure for an opened font. We can safely cast this structure to
|
||||
"struft font_info". */
|
||||
|
||||
struct font
|
||||
{
|
||||
struct font_info font;
|
||||
|
||||
/* From which font-entity the font is opened. */
|
||||
Lisp_Object entity;
|
||||
|
||||
/* By which pixel size the font is opened. */
|
||||
int pixel_size;
|
||||
|
||||
/* Font-driver for the font. */
|
||||
struct font_driver *driver;
|
||||
|
||||
/* File name of the font, or NULL if the font is not associated with
|
||||
a file. */
|
||||
char *file_name;
|
||||
|
||||
/* Charset to encode a character code into a glyph code of the
|
||||
font. */
|
||||
int encoding_charset;
|
||||
|
||||
/* Charset to check if a character code is supported by the font.
|
||||
-1 means that the contents of the font must be looked up to
|
||||
determine it.
|
||||
*/
|
||||
int repertory_charet;
|
||||
|
||||
/* Minimum glyph width (in pixels). */
|
||||
int min_width;
|
||||
|
||||
/* Ascent and descent of the font (in pixels). */
|
||||
int ascent, descent;
|
||||
|
||||
/* There will be more to this structure, but they are private to a
|
||||
font-driver. */
|
||||
};
|
||||
|
||||
struct font_metrics
|
||||
{
|
||||
short lbearing, rbearing, width, ascent, descent;
|
||||
};
|
||||
|
||||
struct font_bitmap
|
||||
{
|
||||
int rows;
|
||||
int width;
|
||||
int pitch;
|
||||
unsigned char *buffer;
|
||||
int left;
|
||||
int top;
|
||||
int advance;
|
||||
void *extra;
|
||||
};
|
||||
|
||||
/* Predicates to check various font-related objects. */
|
||||
|
||||
#define FONTP(x) \
|
||||
(VECTORP (x) && (ASIZE (x) == FONT_SPEC_MAX || ASIZE (x) == FONT_ENTITY_MAX))
|
||||
#define FONT_SPEC_P(x) \
|
||||
(VECTORP (x) && ASIZE (x) == FONT_SPEC_MAX)
|
||||
#define FONT_ENTITY_P(x) \
|
||||
(VECTORP (x) && ASIZE (x) == FONT_ENTITY_MAX)
|
||||
#define FONT_OBJECT_P(x) \
|
||||
(XTYPE (x) == Lisp_Misc && XMISCTYPE (x) == Lisp_Misc_Save_Value)
|
||||
|
||||
|
||||
/* Check macros for various font-related objects. */
|
||||
|
||||
#define CHECK_FONT(x) \
|
||||
do { if (! FONTP (x)) x = wrong_type_argument (Qfont, x); } while (0)
|
||||
#define CHECK_FONT_SPEC(x) \
|
||||
do { if (! FONT_SPEC_P (x)) x = wrong_type_argument (Qfont, x); } while (0)
|
||||
#define CHECK_FONT_ENTITY(x) \
|
||||
do { if (! FONT_ENTITY_P (x)) x = wrong_type_argument (Qfont, x); } while (0)
|
||||
#define CHECK_FONT_OBJECT(x) \
|
||||
do { if (! FONT_OBJECT_P (x)) x = wrong_type_argument (Qfont, x); } while (0)
|
||||
|
||||
#define CHECK_FONT_GET_OBJECT(x, font) \
|
||||
do { \
|
||||
if (! FONT_OBJECT_P (x)) x = wrong_type_argument (Qfont, x); \
|
||||
if (! XSAVE_VALUE (x)->pointer) error ("Font already closed"); \
|
||||
font = XSAVE_VALUE (x)->pointer; \
|
||||
} while (0)
|
||||
|
||||
struct face;
|
||||
struct composition;
|
||||
|
||||
/* Macros for lispy glyph-string. */
|
||||
#define LGSTRING_FONT(lgs) AREF (AREF ((lgs), 0), 0)
|
||||
#define LGSTRING_LBEARING(lgs) AREF (AREF ((lgs), 0), 1)
|
||||
#define LGSTRING_RBEARING(lgs) AREF (AREF ((lgs), 0), 2)
|
||||
#define LGSTRING_WIDTH(lgs) AREF (AREF ((lgs), 0), 3)
|
||||
#define LGSTRING_ASCENT(lgs) AREF (AREF ((lgs), 0), 4)
|
||||
#define LGSTRING_DESCENT(lgs) AREF (AREF ((lgs), 0), 5)
|
||||
#define LGSTRING_SET_FONT(lgs, val) ASET (AREF ((lgs), 0), 0, (val))
|
||||
#define LGSTRING_SET_LBEARING(lgs, val) ASET (AREF ((lgs), 0), 1, (val))
|
||||
#define LGSTRING_SET_RBEARING(lgs, val) ASET (AREF ((lgs), 0), 2, (val))
|
||||
#define LGSTRING_SET_WIDTH(lgs, val) ASET (AREF ((lgs), 0), 3, (val))
|
||||
#define LGSTRING_SET_ASCENT(lgs, val) ASET (AREF ((lgs), 0), 4, (val))
|
||||
#define LGSTRING_SET_DESCENT(lgs, val) ASET (AREF ((lgs), 0), 5, (val))
|
||||
|
||||
#define LGSTRING_LENGTH(lgs) (ASIZE ((lgs)) - 1)
|
||||
#define LGSTRING_GLYPH(lgs, idx) AREF ((lgs), (idx) + 1)
|
||||
|
||||
#define LGLYPH_CHAR(g) AREF ((g), 2)
|
||||
#define LGLYPH_CODE(g) AREF ((g), 3)
|
||||
#define LGLYPH_XOFF(g) AREF ((g), 4)
|
||||
#define LGLYPH_YOFF(g) AREF ((g), 5)
|
||||
#define LGLYPH_WIDTH(g) AREF ((g), 6)
|
||||
#define LGLYPH_WADJUST(g) AREF ((g), 7)
|
||||
#define LGLYPH_SET_CHAR(g, val) ASET ((g), 2, (val))
|
||||
#define LGLYPH_SET_CODE(g, val) ASET ((g), 3, (val))
|
||||
#define LGLYPH_SET_XOFF(g, val) ASET ((g), 4, (val))
|
||||
#define LGLYPH_SET_YOFF(g, val) ASET ((g), 5, (val))
|
||||
#define LGLYPH_SET_WIDTH(g, val) ASET ((g), 6, (val))
|
||||
#define LGLYPH_SET_WADJUST(g, val) ASET ((g), 7, (val))
|
||||
|
||||
#define FONT_INVALID_CODE 0xFFFFFFFF
|
||||
|
||||
struct font_driver
|
||||
{
|
||||
/* Symbol indicating the type of the font-driver. */
|
||||
Lisp_Object type;
|
||||
|
||||
/* Return a cache of font-entities on FRAME. The cache must be a
|
||||
cons whose cdr part is the actual cache area. */
|
||||
Lisp_Object (*get_cache) P_ ((Lisp_Object frame));
|
||||
|
||||
/* Parse font name NAME, store the font properties in SPEC, and
|
||||
return 0. If the font-driver can't parse NAME, return -1. */
|
||||
int (*parse_name) P_ ((FRAME_PTR f, char *name, Lisp_Object spec));
|
||||
|
||||
/* List fonts matching with FONT_SPEC on FRAME. The value is a
|
||||
vector of font-entities. This is the sole API that allocates
|
||||
font-entities. */
|
||||
Lisp_Object (*list) P_ ((Lisp_Object frame, Lisp_Object font_spec));
|
||||
|
||||
/* List available families. The value is a list of family names
|
||||
(symbols). The method can be NULL if the driver doesn't support
|
||||
this facility. */
|
||||
Lisp_Object (*list_family) P_ ((Lisp_Object frame));
|
||||
|
||||
/* Free FONT_EXTRA_INDEX field of FONT_ENTITY. This method can be
|
||||
NULL if FONT_EXTRA_INDEX of FONT_ENTITY is a normal Lisp object
|
||||
(i.e. not Lisp_Save_Value). */
|
||||
void (*free_entity) P_ ((Lisp_Object font_entity));
|
||||
|
||||
/* Open a font specified by FONT_ENTITY on frame F. If the font is
|
||||
scalable, open it with PIXEL_SIZE. */
|
||||
struct font *(*open) P_ ((FRAME_PTR f, Lisp_Object font_entity,
|
||||
int pixel_size));
|
||||
|
||||
/* Close FONT on frame F. */
|
||||
void (*close) P_ ((FRAME_PTR f, struct font *font));
|
||||
|
||||
/* Prepare FACE for displaying characters by FONT on frame F. If
|
||||
successful, return 0. Otherwise, return -1. This method can be
|
||||
NULL if there's nothing to do. */
|
||||
int (*prepare_face) P_ ((FRAME_PTR f, struct face *face));
|
||||
|
||||
/* Done FACE for displaying characters by FACE->font on frame F.
|
||||
This method can be NULL if there's nothing to do. */
|
||||
void (*done_face) P_ ((FRAME_PTR f, struct face *face));
|
||||
|
||||
/* If FONT_ENTITY has a glyph for character C, return 1. If not,
|
||||
return 0. If a font must be opened to check it, return -1. This
|
||||
method can be NULL if the driver always requires a font to be
|
||||
opened for this check. In that case, we must open a font and use
|
||||
`encode_char' method. */
|
||||
int (*has_char) P_ ((Lisp_Object entity, int c));
|
||||
|
||||
/* Return a glyph code of FONT for characer C. If FONT doesn't have
|
||||
such a glyph, return FONT_INVALID_CODE. */
|
||||
unsigned (*encode_char) P_ ((struct font *font, int c));
|
||||
|
||||
/* Perform the size computation of glyphs of FONT and fillin members
|
||||
of METRICS. The glyphs are specified by their glyph codes in
|
||||
CODE (length NGLYPHS). */
|
||||
int (*text_extents) P_ ((struct font *font,
|
||||
unsigned *code, int nglyphs,
|
||||
struct font_metrics *metrics));
|
||||
|
||||
/* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
|
||||
position of frame F with S->FACE and S->GC. If WITH_BACKGROUND
|
||||
is nonzero, fill the background in advance. It is assured that
|
||||
WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
|
||||
int (*draw) P_ ((struct glyph_string *s, int from, int to,
|
||||
int x, int y, int with_background));
|
||||
|
||||
/* Store bitmap data for glyph-code CODE of FONT in BITMAP. This
|
||||
method can be NULL if the driver doesn't support this facility.
|
||||
It is intended that this method is callled from the other
|
||||
font-driver for actual drawing. */
|
||||
int (*get_bitmap) P_ ((struct font *font, unsigned code,
|
||||
struct font_bitmap *bitmap,
|
||||
int bits_per_pixel));
|
||||
|
||||
/* Free bitmap data in BITMAP. This method can be NULL if no data
|
||||
have to be freed. */
|
||||
void (*free_bitmap) P_ ((struct font *font, struct font_bitmap *bitmap));
|
||||
|
||||
/* Return an outline data for glyph-code CODE of FONT. The format
|
||||
of the outline data depends on the font-driver. This method can
|
||||
be NULL if the driver doesn't support this facility. */
|
||||
void *(*get_outline) P_ ((struct font *font, unsigned code));
|
||||
|
||||
/* Free OUTLINE (that is obtained by the above method). */
|
||||
void (*free_outline) P_ ((struct font *font, void *outline));
|
||||
|
||||
/* Get coordinates of the INDEXth anchor point of the glyph whose
|
||||
code is CODE. Store the coordinates in *X and *Y. Return 0 if
|
||||
the operations was successfull. Otherwise return -1. This
|
||||
method can be NULL if the driver doesn't support this
|
||||
facility. */
|
||||
int (*anchor_point) P_ ((struct font *font, unsigned code, int index,
|
||||
int *x, int *y));
|
||||
|
||||
/* Return a list describing which scripts/languages FONT
|
||||
supports by which GSUB/GPOS features of OpenType tables. */
|
||||
Lisp_Object (*otf_capability) P_ ((struct font *font));
|
||||
|
||||
/* Drive FONT's OTF GSUB features according to GSUB_SPEC.
|
||||
|
||||
GSUB_SPEC is in this format (all elements are symbols):
|
||||
(SCRIPT LANGSYS GSUB-FEATURE ...)
|
||||
If one of GSUB-FEATURE is nil, apply all gsub features except for
|
||||
already applied and listed later. For instance, if the font has
|
||||
GSUB features nukt, haln, rphf, blwf, and half,
|
||||
(deva nil nukt haln nil rphf)
|
||||
applies nukt and haln in this order, then applies blwf and half
|
||||
in the order apearing in the font. The features are of the
|
||||
default langsys of `deva' script.
|
||||
|
||||
This method applies the specified features to the codes in the
|
||||
elements of GSTRING-IN (between FROMth and TOth). The output
|
||||
codes are stored in GSTRING-OUT at the IDXth element and the
|
||||
following elements.
|
||||
|
||||
Return the number of output codes. If none of the features are
|
||||
applicable to the input data, return 0. If GSTRING-OUT is too
|
||||
short, return -1. */
|
||||
int (*otf_gsub) P_ ((struct font *font, Lisp_Object gsub_spec,
|
||||
Lisp_Object gstring_in, int from, int to,
|
||||
Lisp_Object gstring_out, int idx));
|
||||
|
||||
/* Drive FONT's OTF GPOS features according to GPOS_SPEC.
|
||||
|
||||
GPOS_SPEC is in this format (all elements are symbols):
|
||||
(SCRIPT LANGSYS GPOS-FEATURE ...)
|
||||
The meaning is the same as GSUB_SPEC above.
|
||||
|
||||
This method applies the specified features to the codes in the
|
||||
elements of GSTRING (between FROMth and TOth). The resulting
|
||||
positioning information (x-offset and y-offset) is stored in the
|
||||
slots of the elements.
|
||||
|
||||
Return 1 if at least one glyph has nonzero x-offset or y-offset.
|
||||
Otherwise return 0. */
|
||||
int (*otf_gpos) P_ ((struct font *font, Lisp_Object gpos_spec,
|
||||
Lisp_Object gstring, int from, int to));
|
||||
};
|
||||
|
||||
|
||||
struct font_driver_list
|
||||
{
|
||||
struct font_driver *driver;
|
||||
struct font_driver_list *next;
|
||||
};
|
||||
|
||||
extern int enable_font_backend;
|
||||
|
||||
EXFUN (Ffont_spec, MANY);
|
||||
|
||||
extern Lisp_Object font_symbolic_weight P_ ((Lisp_Object font));
|
||||
extern Lisp_Object font_symbolic_slant P_ ((Lisp_Object font));
|
||||
extern Lisp_Object font_symbolic_width P_ ((Lisp_Object font));
|
||||
|
||||
extern Lisp_Object font_find_object P_ ((struct font *font));
|
||||
extern char *font_get_name P_ ((Lisp_Object));
|
||||
extern Lisp_Object font_get_frame P_ ((Lisp_Object font));
|
||||
extern int font_has_char P_ ((FRAME_PTR, Lisp_Object, int));
|
||||
extern unsigned font_encode_char P_ ((Lisp_Object, int));
|
||||
|
||||
extern int font_set_lface_from_name P_ ((FRAME_PTR f,
|
||||
Lisp_Object lface,
|
||||
Lisp_Object fontname,
|
||||
int force_p, int may_fail_p));
|
||||
extern Lisp_Object font_find_for_lface P_ ((FRAME_PTR f, Lisp_Object *lface,
|
||||
Lisp_Object spec));
|
||||
extern Lisp_Object font_open_for_lface P_ ((FRAME_PTR f, Lisp_Object *lface,
|
||||
Lisp_Object entity));
|
||||
extern void font_load_for_face P_ ((FRAME_PTR f, struct face *face));
|
||||
extern void font_prepare_for_face P_ ((FRAME_PTR f, struct face *face));
|
||||
extern Lisp_Object font_open_by_name P_ ((FRAME_PTR f, char *name));
|
||||
|
||||
extern Lisp_Object intern_downcase P_ ((char *str, int len));
|
||||
extern void font_update_sort_order P_ ((int *order));
|
||||
|
||||
extern void font_parse_old_font_spec P_ ((Lisp_Object, Lisp_Object,
|
||||
Lisp_Object, Lisp_Object));
|
||||
|
||||
|
||||
extern int font_parse_xlfd P_ ((char *name, Lisp_Object font, int merge));
|
||||
extern int font_unparse_xlfd P_ ((Lisp_Object font, int pixel_size,
|
||||
char *name, int bytes));
|
||||
extern void register_font_driver P_ ((struct font_driver *driver, FRAME_PTR f));
|
||||
extern void free_font_driver_list P_ ((FRAME_PTR f));
|
||||
|
||||
extern struct font *font_prepare_composition P_ ((struct composition *cmp));
|
||||
|
||||
|
||||
#ifdef HAVE_LIBOTF
|
||||
/* This can be used as `otf_capability' method of a font-driver. */
|
||||
extern Lisp_Object font_otf_capability P_ ((struct font *font));
|
||||
/* This can be used as `otf_gsub' method of a font-driver. */
|
||||
extern int font_otf_gsub P_ ((struct font *font, Lisp_Object gsub_spec,
|
||||
Lisp_Object gstring_in, int from, int to,
|
||||
Lisp_Object gstring_out, int idx));
|
||||
/* This can be used as `otf_gpos' method of a font-driver. */
|
||||
extern int font_otf_gpos P_ ((struct font *font, Lisp_Object gpos_spec,
|
||||
Lisp_Object gstring, int from, int to));
|
||||
#endif /* HAVE_LIBOTF */
|
||||
|
||||
#ifdef HAVE_FREETYPE
|
||||
extern struct font_driver ftfont_driver;
|
||||
#endif /* HAVE_FREETYPE */
|
||||
#ifdef HAVE_X_WINDOWS
|
||||
extern struct font_driver xfont_driver;
|
||||
extern struct font_driver ftxfont_driver;
|
||||
#ifdef HAVE_XFT
|
||||
extern struct font_driver xftfont_driver;
|
||||
#endif /* HAVE_XFT */
|
||||
#endif /* HAVE_X_WINDOWS */
|
||||
#ifdef WINDOWSNT
|
||||
extern struct font_driver w32font_driver;
|
||||
#endif /* WINDOWSNT */
|
||||
#ifdef MAC_OS
|
||||
extern struct font_driver atmfont_driver;
|
||||
#endif /* MAC_OS */
|
||||
|
||||
#endif /* not EMACS_FONT_H */
|
731
src/ftfont.c
Normal file
731
src/ftfont.c
Normal file
@ -0,0 +1,731 @@
|
||||
/* ftfont.c -- FreeType font driver.
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
Copyright (C) 2006
|
||||
National Institute of Advanced Industrial Science and Technology (AIST)
|
||||
Registration Number H13PRO009
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_SIZES_H
|
||||
#include <fontconfig/fontconfig.h>
|
||||
#include <fontconfig/fcfreetype.h>
|
||||
|
||||
#include "lisp.h"
|
||||
#include "dispextern.h"
|
||||
#include "frame.h"
|
||||
#include "blockinput.h"
|
||||
#include "character.h"
|
||||
#include "charset.h"
|
||||
#include "coding.h"
|
||||
#include "fontset.h"
|
||||
#include "font.h"
|
||||
|
||||
Lisp_Object Qfreetype;
|
||||
|
||||
static int fc_initialized;
|
||||
static FT_Library ft_library;
|
||||
|
||||
static Lisp_Object freetype_font_cache;
|
||||
|
||||
static Lisp_Object Qiso8859_1, Qiso10646_1, Qunicode_bmp;
|
||||
|
||||
static FcCharSet *cs_iso8859_1;
|
||||
|
||||
/* The actual structure for FreeType font that can be casted to struct
|
||||
font. */
|
||||
|
||||
struct ftfont_info
|
||||
{
|
||||
struct font font;
|
||||
FT_Size ft_size;
|
||||
};
|
||||
|
||||
static int
|
||||
ftfont_build_basic_charsets ()
|
||||
{
|
||||
FcChar32 c;
|
||||
|
||||
cs_iso8859_1 = FcCharSetCreate ();
|
||||
if (! cs_iso8859_1)
|
||||
return -1;
|
||||
for (c = ' '; c < 127; c++)
|
||||
if (! FcCharSetAddChar (cs_iso8859_1, c))
|
||||
return -1;
|
||||
for (c = 192; c < 256; c++)
|
||||
if (! FcCharSetAddChar (cs_iso8859_1, c))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Lisp_Object ftfont_get_cache P_ ((Lisp_Object));
|
||||
static int ftfont_parse_name P_ ((FRAME_PTR, char *, Lisp_Object));
|
||||
static Lisp_Object ftfont_list P_ ((Lisp_Object, Lisp_Object));
|
||||
static Lisp_Object ftfont_list_family P_ ((Lisp_Object));
|
||||
static void ftfont_free_entity P_ ((Lisp_Object));
|
||||
static struct font *ftfont_open P_ ((FRAME_PTR, Lisp_Object, int));
|
||||
static void ftfont_close P_ ((FRAME_PTR, struct font *));
|
||||
static int ftfont_has_char P_ ((Lisp_Object, int));
|
||||
static unsigned ftfont_encode_char P_ ((struct font *, int));
|
||||
static int ftfont_text_extents P_ ((struct font *, unsigned *, int,
|
||||
struct font_metrics *));
|
||||
static int ftfont_get_bitmap P_ ((struct font *, unsigned,
|
||||
struct font_bitmap *, int));
|
||||
static int ftfont_anchor_point P_ ((struct font *, unsigned, int,
|
||||
int *, int *));
|
||||
|
||||
struct font_driver ftfont_driver =
|
||||
{
|
||||
(Lisp_Object) NULL, /* Qfreetype */
|
||||
ftfont_get_cache,
|
||||
ftfont_parse_name,
|
||||
ftfont_list,
|
||||
ftfont_list_family,
|
||||
ftfont_free_entity,
|
||||
ftfont_open,
|
||||
ftfont_close,
|
||||
/* We can't draw a text without device dependent functions. */
|
||||
NULL,
|
||||
NULL,
|
||||
ftfont_has_char,
|
||||
ftfont_encode_char,
|
||||
ftfont_text_extents,
|
||||
/* We can't draw a text without device dependent functions. */
|
||||
NULL,
|
||||
ftfont_get_bitmap,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
ftfont_anchor_point,
|
||||
#ifdef HAVE_LIBOTF
|
||||
font_otf_capability,
|
||||
font_otf_gsub,
|
||||
font_otf_gpos
|
||||
#else
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
#endif /* HAVE_LIBOTF */
|
||||
};
|
||||
|
||||
#define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
|
||||
|
||||
extern Lisp_Object QCname;
|
||||
|
||||
static Lisp_Object
|
||||
ftfont_get_cache (frame)
|
||||
Lisp_Object frame;
|
||||
{
|
||||
if (NILP (freetype_font_cache))
|
||||
freetype_font_cache = Fcons (Qt, Qnil);
|
||||
return freetype_font_cache;
|
||||
}
|
||||
|
||||
static int
|
||||
ftfont_parse_name (f, name, spec)
|
||||
FRAME_PTR f;
|
||||
char *name;
|
||||
Lisp_Object spec;
|
||||
{
|
||||
FcPattern *p;
|
||||
FcChar8 *str;
|
||||
int numeric;
|
||||
double dbl;
|
||||
|
||||
if (name[0] == '-' || strchr (name, '*'))
|
||||
/* It seems that NAME is XLFD. */
|
||||
return -1;
|
||||
p = FcNameParse ((FcChar8 *) name);
|
||||
if (! p)
|
||||
return -1;
|
||||
if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch)
|
||||
ASET (spec, FONT_FOUNDRY_INDEX,
|
||||
intern_downcase ((char *) str, strlen ((char *) str)));
|
||||
if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch)
|
||||
ASET (spec, FONT_FAMILY_INDEX,
|
||||
intern_downcase ((char *) str, strlen ((char *) str)));
|
||||
if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
|
||||
ASET (spec, FONT_WEIGHT_INDEX, make_number (numeric));
|
||||
if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
|
||||
ASET (spec, FONT_SLANT_INDEX, make_number (numeric + 100));
|
||||
if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
|
||||
ASET (spec, FONT_WIDTH_INDEX, make_number (numeric));
|
||||
if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
|
||||
ASET (spec, FONT_SIZE_INDEX, make_number (dbl));
|
||||
else if (FcPatternGetDouble (p, FC_SIZE, 0, &dbl) == FcResultMatch)
|
||||
ASET (spec, FONT_SIZE_INDEX, make_float (dbl));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Lisp_Object
|
||||
ftfont_list (frame, spec)
|
||||
Lisp_Object frame, spec;
|
||||
{
|
||||
Lisp_Object val, tmp, extra, font_name;
|
||||
int i;
|
||||
FcPattern *pattern = NULL;
|
||||
FcCharSet *charset = NULL;
|
||||
FcLangSet *langset = NULL;
|
||||
FcFontSet *fontset = NULL;
|
||||
FcObjectSet *objset = NULL;
|
||||
Lisp_Object registry = Qnil;
|
||||
|
||||
val = null_vector;
|
||||
|
||||
if (! fc_initialized)
|
||||
{
|
||||
FcInit ();
|
||||
fc_initialized = 1;
|
||||
}
|
||||
|
||||
if (! NILP (AREF (spec, FONT_ADSTYLE_INDEX)))
|
||||
return val;
|
||||
if (! NILP (AREF (spec, FONT_REGISTRY_INDEX)))
|
||||
{
|
||||
registry = AREF (spec, FONT_REGISTRY_INDEX);
|
||||
if (EQ (registry, Qiso8859_1))
|
||||
{
|
||||
if (! cs_iso8859_1
|
||||
&& ftfont_build_basic_charsets () < 0)
|
||||
goto err;
|
||||
charset = cs_iso8859_1;
|
||||
registry = Qnil;
|
||||
}
|
||||
}
|
||||
|
||||
extra = AREF (spec, FONT_EXTRA_INDEX);
|
||||
font_name = Qnil;
|
||||
if (CONSP (extra))
|
||||
{
|
||||
tmp = Fassq (QCotf, extra);
|
||||
if (! NILP (tmp))
|
||||
return val;
|
||||
tmp = Fassq (QClanguage, extra);
|
||||
if (CONSP (tmp))
|
||||
{
|
||||
langset = FcLangSetCreate ();
|
||||
if (! langset)
|
||||
goto err;
|
||||
tmp = XCDR (tmp);
|
||||
if (SYMBOLP (tmp))
|
||||
{
|
||||
if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (tmp)))
|
||||
goto err;
|
||||
}
|
||||
else
|
||||
while (CONSP (tmp))
|
||||
{
|
||||
if (SYMBOLP (XCAR (tmp))
|
||||
&& ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (tmp))))
|
||||
goto err;
|
||||
tmp = XCDR (tmp);
|
||||
}
|
||||
}
|
||||
tmp = Fassq (QCname, extra);
|
||||
if (CONSP (tmp))
|
||||
font_name = XCDR (tmp);
|
||||
tmp = Fassq (QCscript, extra);
|
||||
if (CONSP (tmp) && ! charset)
|
||||
{
|
||||
Lisp_Object script = XCDR (tmp);
|
||||
Lisp_Object chars = assq_no_quit (script,
|
||||
Vscript_representative_chars);
|
||||
|
||||
if (CONSP (chars))
|
||||
{
|
||||
charset = FcCharSetCreate ();
|
||||
if (! charset)
|
||||
goto err;
|
||||
for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
|
||||
if (CHARACTERP (XCAR (chars))
|
||||
&& ! FcCharSetAddChar (charset, XUINT (XCAR (chars))))
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! NILP (registry) && ! charset)
|
||||
goto finish;
|
||||
|
||||
if (STRINGP (font_name))
|
||||
{
|
||||
if (! isalpha (SDATA (font_name)[0]))
|
||||
goto finish;
|
||||
pattern = FcNameParse (SDATA (font_name));
|
||||
if (! pattern)
|
||||
goto err;
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern = FcPatternCreate ();
|
||||
if (! pattern)
|
||||
goto err;
|
||||
|
||||
tmp = AREF (spec, FONT_FOUNDRY_INDEX);
|
||||
if (SYMBOLP (tmp) && ! NILP (tmp)
|
||||
&& ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
|
||||
goto err;
|
||||
tmp = AREF (spec, FONT_FAMILY_INDEX);
|
||||
if (SYMBOLP (tmp) && ! NILP (tmp)
|
||||
&& ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
|
||||
goto err;
|
||||
tmp = AREF (spec, FONT_WEIGHT_INDEX);
|
||||
if (INTEGERP (tmp)
|
||||
&& ! FcPatternAddInteger (pattern, FC_WEIGHT, XINT (tmp)))
|
||||
goto err;
|
||||
tmp = AREF (spec, FONT_SLANT_INDEX);
|
||||
if (INTEGERP (tmp)
|
||||
&& XINT (tmp) >= 100
|
||||
&& ! FcPatternAddInteger (pattern, FC_SLANT, XINT (tmp) - 100))
|
||||
goto err;
|
||||
tmp = AREF (spec, FONT_WIDTH_INDEX);
|
||||
if (INTEGERP (tmp)
|
||||
&& ! FcPatternAddInteger (pattern, FC_WIDTH, XINT (tmp)))
|
||||
goto err;
|
||||
if (! FcPatternAddBool (pattern, FC_SCALABLE, FcTrue))
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (charset
|
||||
&& ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
|
||||
goto err;
|
||||
if (langset
|
||||
&& ! FcPatternAddLangSet (pattern, FC_LANG, langset))
|
||||
goto err;
|
||||
objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
|
||||
FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING,
|
||||
FC_CHARSET, FC_FILE, NULL);
|
||||
if (! objset)
|
||||
goto err;
|
||||
|
||||
BLOCK_INPUT;
|
||||
fontset = FcFontList (NULL, pattern, objset);
|
||||
UNBLOCK_INPUT;
|
||||
if (! fontset)
|
||||
goto err;
|
||||
val = Qnil;
|
||||
for (i = 0; i < fontset->nfont; i++)
|
||||
{
|
||||
FcPattern *p = fontset->fonts[i];
|
||||
FcChar8 *str, *file;
|
||||
|
||||
if (FcPatternGetString (p, FC_FILE, 0, &file) == FcResultMatch
|
||||
&& FcPatternGetCharSet (p, FC_CHARSET, 0, &charset) == FcResultMatch)
|
||||
{
|
||||
Lisp_Object entity = Fmake_vector (make_number (FONT_ENTITY_MAX),
|
||||
null_string);
|
||||
int numeric;
|
||||
double dbl;
|
||||
FcPattern *p0;
|
||||
|
||||
ASET (entity, FONT_TYPE_INDEX, Qfreetype);
|
||||
ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
|
||||
ASET (entity, FONT_FRAME_INDEX, frame);
|
||||
ASET (entity, FONT_OBJLIST_INDEX, Qnil);
|
||||
|
||||
if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch)
|
||||
ASET (entity, FONT_FOUNDRY_INDEX,
|
||||
intern_downcase ((char *) str, strlen ((char *) str)));
|
||||
if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch)
|
||||
ASET (entity, FONT_FAMILY_INDEX,
|
||||
intern_downcase ((char *) str, strlen ((char *) str)));
|
||||
if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
|
||||
ASET (entity, FONT_WEIGHT_INDEX, make_number (numeric));
|
||||
if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
|
||||
ASET (entity, FONT_SLANT_INDEX, make_number (numeric + 100));
|
||||
if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
|
||||
ASET (entity, FONT_WIDTH_INDEX, make_number (numeric));
|
||||
if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
|
||||
ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
|
||||
else
|
||||
ASET (entity, FONT_SIZE_INDEX, make_number (0));
|
||||
|
||||
if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) != FcResultMatch)
|
||||
numeric = FC_MONO;
|
||||
p0 = FcPatternCreate ();
|
||||
if (! p0
|
||||
|| FcPatternAddString (p0, FC_FILE, file) == FcFalse
|
||||
|| FcPatternAddCharSet (p0, FC_CHARSET, charset) == FcFalse
|
||||
|| FcPatternAddInteger (p0, FC_SPACING, numeric) == FcFalse)
|
||||
break;
|
||||
ASET (entity, FONT_EXTRA_INDEX, make_save_value (p0, 0));
|
||||
|
||||
val = Fcons (entity, val);
|
||||
}
|
||||
}
|
||||
val = Fvconcat (1, &val);
|
||||
goto finish;
|
||||
|
||||
err:
|
||||
/* We come here because of unexpected error in fontconfig API call
|
||||
(usually insufficiency memory). */
|
||||
val = Qnil;
|
||||
|
||||
finish:
|
||||
if (charset && charset != cs_iso8859_1) FcCharSetDestroy (charset);
|
||||
if (objset) FcObjectSetDestroy (objset);
|
||||
if (fontset) FcFontSetDestroy (fontset);
|
||||
if (langset) FcLangSetDestroy (langset);
|
||||
if (pattern) FcPatternDestroy (pattern);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static Lisp_Object
|
||||
ftfont_list_family (frame)
|
||||
Lisp_Object frame;
|
||||
{
|
||||
Lisp_Object list;
|
||||
FcPattern *pattern = NULL;
|
||||
FcFontSet *fontset = NULL;
|
||||
FcObjectSet *objset = NULL;
|
||||
int i;
|
||||
|
||||
if (! fc_initialized)
|
||||
{
|
||||
FcInit ();
|
||||
fc_initialized = 1;
|
||||
}
|
||||
|
||||
pattern = FcPatternCreate ();
|
||||
if (! pattern)
|
||||
goto finish;
|
||||
objset = FcObjectSetBuild (FC_FAMILY);
|
||||
if (! objset)
|
||||
goto finish;
|
||||
fontset = FcFontList (NULL, pattern, objset);
|
||||
if (! fontset)
|
||||
goto finish;
|
||||
|
||||
list = Qnil;
|
||||
for (i = 0; i < fontset->nfont; i++)
|
||||
{
|
||||
FcPattern *pat = fontset->fonts[i];
|
||||
FcChar8 *str;
|
||||
|
||||
if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
|
||||
list = Fcons (intern_downcase ((char *) str, strlen ((char *) str)),
|
||||
list);
|
||||
}
|
||||
|
||||
finish:
|
||||
if (objset) FcObjectSetDestroy (objset);
|
||||
if (fontset) FcFontSetDestroy (fontset);
|
||||
if (pattern) FcPatternDestroy (pattern);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ftfont_free_entity (entity)
|
||||
Lisp_Object entity;
|
||||
{
|
||||
Lisp_Object val = AREF (entity, FONT_EXTRA_INDEX);
|
||||
FcPattern *pattern = XSAVE_VALUE (val)->pointer;
|
||||
|
||||
FcPatternDestroy (pattern);
|
||||
}
|
||||
|
||||
static struct font *
|
||||
ftfont_open (f, entity, pixel_size)
|
||||
FRAME_PTR f;
|
||||
Lisp_Object entity;
|
||||
int pixel_size;
|
||||
{
|
||||
struct ftfont_info *ftfont_info;
|
||||
struct font *font;
|
||||
FT_Face ft_face;
|
||||
FT_Size ft_size;
|
||||
FT_UInt size;
|
||||
Lisp_Object val;
|
||||
FcPattern *pattern;
|
||||
FcChar8 *file;
|
||||
int spacing;
|
||||
|
||||
val = AREF (entity, FONT_EXTRA_INDEX);
|
||||
if (XTYPE (val) != Lisp_Misc
|
||||
|| XMISCTYPE (val) != Lisp_Misc_Save_Value)
|
||||
return NULL;
|
||||
pattern = XSAVE_VALUE (val)->pointer;
|
||||
if (XSAVE_VALUE (val)->integer == 0)
|
||||
{
|
||||
/* We have not yet created FT_Face for this font. */
|
||||
if (! ft_library
|
||||
&& FT_Init_FreeType (&ft_library) != 0)
|
||||
return NULL;
|
||||
if (FcPatternGetString (pattern, FC_FILE, 0, &file) != FcResultMatch)
|
||||
return NULL;
|
||||
if (FT_New_Face (ft_library, (char *) file, 0, &ft_face) != 0)
|
||||
return NULL;
|
||||
FcPatternAddFTFace (pattern, FC_FT_FACE, ft_face);
|
||||
ft_size = ft_face->size;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &ft_face)
|
||||
!= FcResultMatch)
|
||||
return NULL;
|
||||
if (FT_New_Size (ft_face, &ft_size) != 0)
|
||||
return NULL;
|
||||
if (FT_Activate_Size (ft_size) != 0)
|
||||
{
|
||||
FT_Done_Size (ft_size);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
size = XINT (AREF (entity, FONT_SIZE_INDEX));
|
||||
if (size == 0)
|
||||
size = pixel_size;
|
||||
if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
|
||||
{
|
||||
if (XSAVE_VALUE (val)->integer == 0)
|
||||
FT_Done_Face (ft_face);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ftfont_info = malloc (sizeof (struct ftfont_info));
|
||||
if (! ftfont_info)
|
||||
return NULL;
|
||||
ftfont_info->ft_size = ft_size;
|
||||
|
||||
font = (struct font *) ftfont_info;
|
||||
font->entity = entity;
|
||||
font->pixel_size = size;
|
||||
font->driver = &ftfont_driver;
|
||||
font->font.name = font->font.full_name = NULL;
|
||||
font->file_name = (char *) file;
|
||||
font->font.size = ft_face->size->metrics.max_advance >> 6;
|
||||
font->ascent = ft_face->size->metrics.ascender >> 6;
|
||||
font->descent = - ft_face->size->metrics.descender >> 6;
|
||||
font->font.height = ft_face->size->metrics.height >> 6;
|
||||
if (FcPatternGetInteger (pattern, FC_SPACING, 0, &spacing) != FcResultMatch
|
||||
|| spacing != FC_PROPORTIONAL)
|
||||
font->font.average_width = font->font.space_width = font->font.size;
|
||||
else
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 32; i < 127; i++)
|
||||
{
|
||||
if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) != 0)
|
||||
break;
|
||||
if (i == 32)
|
||||
font->font.space_width = ft_face->glyph->metrics.horiAdvance >> 6;
|
||||
font->font.average_width += ft_face->glyph->metrics.horiAdvance >> 6;
|
||||
}
|
||||
if (i == 127)
|
||||
{
|
||||
/* The font contains all ASCII printable characters. */
|
||||
font->font.average_width /= 95;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i == 32)
|
||||
font->font.space_width = font->font.size;
|
||||
font->font.average_width = font->font.size;
|
||||
}
|
||||
}
|
||||
|
||||
font->font.baseline_offset = 0;
|
||||
font->font.relative_compose = 0;
|
||||
font->font.default_ascent = 0;
|
||||
font->font.vertical_centering = 0;
|
||||
|
||||
(XSAVE_VALUE (val)->integer)++;
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
static void
|
||||
ftfont_close (f, font)
|
||||
FRAME_PTR f;
|
||||
struct font *font;
|
||||
{
|
||||
struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
|
||||
Lisp_Object entity = font->entity;
|
||||
Lisp_Object val = AREF (entity, FONT_EXTRA_INDEX);
|
||||
|
||||
(XSAVE_VALUE (val)->integer)--;
|
||||
if (XSAVE_VALUE (val)->integer == 0)
|
||||
FT_Done_Face (ftfont_info->ft_size->face);
|
||||
else
|
||||
FT_Done_Size (ftfont_info->ft_size);
|
||||
|
||||
free (font);
|
||||
}
|
||||
|
||||
static int
|
||||
ftfont_has_char (entity, c)
|
||||
Lisp_Object entity;
|
||||
int c;
|
||||
{
|
||||
Lisp_Object val;
|
||||
FcPattern *pattern;
|
||||
FcCharSet *charset;
|
||||
|
||||
val = AREF (entity, FONT_EXTRA_INDEX);
|
||||
pattern = XSAVE_VALUE (val)->pointer;
|
||||
FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset);
|
||||
|
||||
return (FcCharSetHasChar (charset, (FcChar32) c) == FcTrue);
|
||||
}
|
||||
|
||||
static unsigned
|
||||
ftfont_encode_char (font, c)
|
||||
struct font *font;
|
||||
int c;
|
||||
{
|
||||
struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
|
||||
FT_Face ft_face = ftfont_info->ft_size->face;
|
||||
FT_ULong charcode = c;
|
||||
FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
|
||||
|
||||
return (code > 0 ? code : 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
static int
|
||||
ftfont_text_extents (font, code, nglyphs, metrics)
|
||||
struct font *font;
|
||||
unsigned *code;
|
||||
int nglyphs;
|
||||
struct font_metrics *metrics;
|
||||
{
|
||||
struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
|
||||
FT_Face ft_face = ftfont_info->ft_size->face;
|
||||
int width = 0;
|
||||
int i;
|
||||
|
||||
if (ftfont_info->ft_size != ft_face->size)
|
||||
FT_Activate_Size (ftfont_info->ft_size);
|
||||
if (metrics)
|
||||
bzero (metrics, sizeof (struct font_metrics));
|
||||
for (i = 0; i < nglyphs; i++)
|
||||
{
|
||||
if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
|
||||
{
|
||||
FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
|
||||
|
||||
if (metrics)
|
||||
{
|
||||
if (metrics->lbearing > width + (m->horiBearingX >> 6))
|
||||
metrics->lbearing = width + (m->horiBearingX >> 6);
|
||||
if (metrics->rbearing
|
||||
< width + ((m->horiBearingX + m->width) >> 6))
|
||||
metrics->rbearing
|
||||
= width + ((m->horiBearingX + m->width) >> 6);
|
||||
if (metrics->ascent < (m->horiBearingY >> 6))
|
||||
metrics->ascent = m->horiBearingY >> 6;
|
||||
if (metrics->descent > ((m->horiBearingY + m->height) >> 6))
|
||||
metrics->descent = (m->horiBearingY + m->height) >> 6;
|
||||
}
|
||||
width += m->horiAdvance >> 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
width += font->font.space_width;
|
||||
}
|
||||
}
|
||||
if (metrics)
|
||||
metrics->width = width;
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
static int
|
||||
ftfont_get_bitmap (font, code, bitmap, bits_per_pixel)
|
||||
struct font *font;
|
||||
unsigned code;
|
||||
struct font_bitmap *bitmap;
|
||||
int bits_per_pixel;
|
||||
{
|
||||
struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
|
||||
FT_Face ft_face = ftfont_info->ft_size->face;
|
||||
FT_Int32 load_flags = FT_LOAD_RENDER;
|
||||
|
||||
if (ftfont_info->ft_size != ft_face->size)
|
||||
FT_Activate_Size (ftfont_info->ft_size);
|
||||
if (bits_per_pixel == 1)
|
||||
{
|
||||
#ifdef FT_LOAD_TARGET_MONO
|
||||
load_flags |= FT_LOAD_TARGET_MONO;
|
||||
#else
|
||||
load_flags |= FT_LOAD_MONOCHROME;
|
||||
#endif
|
||||
}
|
||||
else if (bits_per_pixel != 8)
|
||||
/* We don't support such a rendering. */
|
||||
return -1;
|
||||
|
||||
if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
|
||||
return -1;
|
||||
bitmap->rows = ft_face->glyph->bitmap.rows;
|
||||
bitmap->width = ft_face->glyph->bitmap.width;
|
||||
bitmap->pitch = ft_face->glyph->bitmap.pitch;
|
||||
bitmap->buffer = ft_face->glyph->bitmap.buffer;
|
||||
bitmap->left = ft_face->glyph->bitmap_left;
|
||||
bitmap->top = ft_face->glyph->bitmap_top;
|
||||
bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
|
||||
bitmap->extra = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ftfont_anchor_point (font, code, index, x, y)
|
||||
struct font *font;
|
||||
unsigned code;
|
||||
int index;
|
||||
int *x, *y;
|
||||
{
|
||||
struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
|
||||
FT_Face ft_face = ftfont_info->ft_size->face;
|
||||
|
||||
if (ftfont_info->ft_size != ft_face->size)
|
||||
FT_Activate_Size (ftfont_info->ft_size);
|
||||
if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
|
||||
return -1;
|
||||
if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
|
||||
return -1;
|
||||
if (index >= ft_face->glyph->outline.n_points)
|
||||
return -1;
|
||||
*x = ft_face->glyph->outline.points[index].x;
|
||||
*y = ft_face->glyph->outline.points[index].y;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
syms_of_ftfont ()
|
||||
{
|
||||
staticpro (&freetype_font_cache);
|
||||
freetype_font_cache = Qnil;
|
||||
|
||||
DEFSYM (Qfreetype, "freetype");
|
||||
DEFSYM (Qiso8859_1, "iso8859-1");
|
||||
DEFSYM (Qiso10646_1, "iso10646-1");
|
||||
DEFSYM (Qunicode_bmp, "unicode-bmp");
|
||||
|
||||
ftfont_driver.type = Qfreetype;
|
||||
register_font_driver (&ftfont_driver, NULL);
|
||||
}
|
346
src/ftxfont.c
Normal file
346
src/ftxfont.c
Normal file
@ -0,0 +1,346 @@
|
||||
/* ftxfont.c -- FreeType font driver on X (without using XFT).
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
Copyright (C) 2006
|
||||
National Institute of Advanced Industrial Science and Technology (AIST)
|
||||
Registration Number H13PRO009
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include "lisp.h"
|
||||
#include "dispextern.h"
|
||||
#include "xterm.h"
|
||||
#include "frame.h"
|
||||
#include "blockinput.h"
|
||||
#include "character.h"
|
||||
#include "charset.h"
|
||||
#include "fontset.h"
|
||||
#include "font.h"
|
||||
|
||||
/* FTX font driver. */
|
||||
|
||||
static Lisp_Object Qftx;
|
||||
|
||||
/* Prototypes for helper function. */
|
||||
static int ftxfont_draw_bitmap P_ ((FRAME_PTR, GC *, struct font *, unsigned,
|
||||
int, int, XPoint *, int, int *n));
|
||||
static void ftxfont_draw_backgrond P_ ((FRAME_PTR, struct font *, GC,
|
||||
int, int, int));
|
||||
|
||||
static int
|
||||
ftxfont_draw_bitmap (f, gc, font, code, x, y, p, size, n)
|
||||
FRAME_PTR f;
|
||||
GC *gc;
|
||||
struct font *font;
|
||||
unsigned code;
|
||||
int x, y;
|
||||
XPoint *p;
|
||||
int size, *n;
|
||||
{
|
||||
struct font_bitmap bitmap;
|
||||
unsigned char *b;
|
||||
int i, j;
|
||||
|
||||
if (ftfont_driver.get_bitmap (font, code, &bitmap, 1) < 0)
|
||||
return 0;
|
||||
for (i = 0, b = bitmap.buffer; i < bitmap.rows;
|
||||
i++, b += bitmap.pitch)
|
||||
{
|
||||
if (size > 0x100)
|
||||
{
|
||||
for (j = 0; j < bitmap.width; j++)
|
||||
if (b[j / 8] & (1 << (7 - (j % 8))))
|
||||
{
|
||||
p[n[0]].x = x + bitmap.left + j;
|
||||
p[n[0]].y = y - bitmap.top + i;
|
||||
if (++n[0] == 0x400)
|
||||
{
|
||||
XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
|
||||
gc[0], p, size, CoordModeOrigin);
|
||||
n[0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (j = 0; j < bitmap.width; j++)
|
||||
{
|
||||
int idx = (b[j] >> 5) - 1;
|
||||
|
||||
if (idx >= 0)
|
||||
{
|
||||
XPoint *pp = p + size * idx;
|
||||
|
||||
pp[n[idx]].x = x + bitmap.left + j;
|
||||
pp[n[idx]].y = y - bitmap.top + i;
|
||||
if (++(n[idx]) == 0x100)
|
||||
{
|
||||
XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
|
||||
gc[idx], pp, size, CoordModeOrigin);
|
||||
n[idx] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ftfont_driver.free_bitmap)
|
||||
ftfont_driver.free_bitmap (font, &bitmap);
|
||||
|
||||
return bitmap.advance;
|
||||
}
|
||||
|
||||
static void
|
||||
ftxfont_draw_backgrond (f, font, gc, x, y, width)
|
||||
FRAME_PTR f;
|
||||
struct font *font;
|
||||
GC gc;
|
||||
int x, y, width;
|
||||
{
|
||||
XGCValues xgcv;
|
||||
|
||||
XGetGCValues (FRAME_X_DISPLAY (f), gc,
|
||||
GCForeground | GCBackground, &xgcv);
|
||||
XSetForeground (FRAME_X_DISPLAY (f), gc, xgcv.background);
|
||||
XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
|
||||
x, y - font->ascent, width, font->font.height);
|
||||
XSetForeground (FRAME_X_DISPLAY (f), gc, xgcv.foreground);
|
||||
}
|
||||
|
||||
/* Prototypes for font-driver methods. */
|
||||
static Lisp_Object ftxfont_list P_ ((Lisp_Object, Lisp_Object));
|
||||
static struct font *ftxfont_open P_ ((FRAME_PTR, Lisp_Object, int));
|
||||
static void ftxfont_close P_ ((FRAME_PTR, struct font *));
|
||||
static int ftxfont_prepare_face (FRAME_PTR, struct face *);
|
||||
static void ftxfont_done_face (FRAME_PTR, struct face *);
|
||||
|
||||
static int ftxfont_draw P_ ((struct glyph_string *, int, int, int, int, int));
|
||||
|
||||
struct font_driver ftxfont_driver;
|
||||
|
||||
static Lisp_Object
|
||||
ftxfont_list (frame, spec)
|
||||
Lisp_Object frame;
|
||||
Lisp_Object spec;
|
||||
{
|
||||
Lisp_Object val = ftfont_driver.list (frame, spec);
|
||||
|
||||
if (! NILP (val))
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ASIZE (val); i++)
|
||||
ASET (AREF (val, i), FONT_TYPE_INDEX, Qftx);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static struct font *
|
||||
ftxfont_open (f, entity, pixel_size)
|
||||
FRAME_PTR f;
|
||||
Lisp_Object entity;
|
||||
int pixel_size;
|
||||
{
|
||||
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
|
||||
struct font *font;
|
||||
XFontStruct *xfont = malloc (sizeof (XFontStruct));
|
||||
|
||||
if (! xfont)
|
||||
return NULL;
|
||||
font = ftfont_driver.open (f, entity, pixel_size);
|
||||
if (! font)
|
||||
{
|
||||
free (xfont);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xfont->fid = FRAME_FONT (f)->fid;
|
||||
xfont->ascent = font->ascent;
|
||||
xfont->descent = font->descent;
|
||||
xfont->max_bounds.width = font->font.size;
|
||||
xfont->min_bounds.width = font->min_width;
|
||||
font->font.font = xfont;
|
||||
font->driver = &ftxfont_driver;
|
||||
|
||||
dpyinfo->n_fonts++;
|
||||
|
||||
/* Set global flag fonts_changed_p to non-zero if the font loaded
|
||||
has a character with a smaller width than any other character
|
||||
before, or if the font loaded has a smaller height than any other
|
||||
font loaded before. If this happens, it will make a glyph matrix
|
||||
reallocation necessary. */
|
||||
if (dpyinfo->n_fonts == 1)
|
||||
{
|
||||
dpyinfo->smallest_font_height = font->font.height;
|
||||
dpyinfo->smallest_char_width = font->min_width;
|
||||
fonts_changed_p = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dpyinfo->smallest_font_height > font->font.height)
|
||||
dpyinfo->smallest_font_height = font->font.height, fonts_changed_p |= 1;
|
||||
if (dpyinfo->smallest_char_width > font->min_width)
|
||||
dpyinfo->smallest_char_width = font->min_width, fonts_changed_p |= 1;
|
||||
}
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
static void
|
||||
ftxfont_close (f, font)
|
||||
FRAME_PTR f;
|
||||
struct font *font;
|
||||
{
|
||||
ftfont_driver.close (f, font);
|
||||
FRAME_X_DISPLAY_INFO (f)->n_fonts--;
|
||||
}
|
||||
|
||||
static int
|
||||
ftxfont_prepare_face (f, face)
|
||||
FRAME_PTR f;
|
||||
struct face *face;
|
||||
{
|
||||
GC gc[6];
|
||||
XColor colors[3];
|
||||
XGCValues xgcv;
|
||||
unsigned long mask = GCForeground | GCBackground | GCGraphicsExposures;
|
||||
int i;
|
||||
|
||||
face->extra = NULL;
|
||||
|
||||
/* Here, we create 6 more GCs to simulate anti-aliasing. */
|
||||
BLOCK_INPUT;
|
||||
XGetGCValues (FRAME_X_DISPLAY (f), face->gc, mask, &xgcv);
|
||||
colors[0].pixel = face->foreground;
|
||||
colors[1].pixel = face->background;
|
||||
XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, 2);
|
||||
for (i = 1; i < 7; i++)
|
||||
{
|
||||
colors[2].red = (colors[0].red * i + colors[1].red * (7 - i)) / 7;
|
||||
colors[2].green = (colors[0].green * i + colors[1].green * (7 - i)) / 7;
|
||||
colors[2].blue = (colors[0].blue * i + colors[1].blue * (7 - i)) / 7;
|
||||
if (! x_alloc_nearest_color (f, FRAME_X_COLORMAP (f), &colors[2]))
|
||||
break;
|
||||
xgcv.foreground = colors[2].pixel;
|
||||
gc[i - 1] = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
|
||||
mask, &xgcv);
|
||||
}
|
||||
UNBLOCK_INPUT;
|
||||
|
||||
if (i < 7)
|
||||
return -1;
|
||||
face->extra = malloc (sizeof (GC) * 7);
|
||||
if (! face->extra)
|
||||
return -1;
|
||||
for (i = 0; i < 6; i++)
|
||||
((GC *) face->extra)[i] = gc[i];
|
||||
((GC *) face->extra)[i] = face->gc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ftxfont_done_face (f, face)
|
||||
FRAME_PTR f;
|
||||
struct face *face;
|
||||
{
|
||||
if (face->extra)
|
||||
{
|
||||
int i;
|
||||
|
||||
BLOCK_INPUT;
|
||||
for (i = 0; i < 7; i++)
|
||||
XFreeGC (FRAME_X_DISPLAY (f), ((GC *) face->extra)[i]);
|
||||
UNBLOCK_INPUT;
|
||||
free (face->extra);
|
||||
face->extra = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ftxfont_draw (s, from, to, x, y, with_background)
|
||||
struct glyph_string *s;
|
||||
int from, to, x, y, with_background;
|
||||
{
|
||||
FRAME_PTR f = s->f;
|
||||
struct face *face = s->face;
|
||||
struct font *font = (struct font *) face->font;
|
||||
XPoint p[0x700];
|
||||
int n[7];
|
||||
unsigned *code;
|
||||
int len = to - from;
|
||||
int i;
|
||||
|
||||
n[0] = n[1] = n[2] = n[3] = n[4] = n[5] = n[6] = 0;
|
||||
|
||||
BLOCK_INPUT;
|
||||
|
||||
if (with_background)
|
||||
ftxfont_draw_backgrond (f, font, s->gc, x, y, s->width);
|
||||
code = alloca (sizeof (unsigned) * len);
|
||||
for (i = 0; i < len; i++)
|
||||
code[i] = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8)
|
||||
| XCHAR2B_BYTE2 (s->char2b + from + i));
|
||||
|
||||
if (! face->extra)
|
||||
{
|
||||
for (i = 0; i < len; i++)
|
||||
x += ftxfont_draw_bitmap (f, &face->gc, font, code[i], x, y,
|
||||
p, 0x700, n);
|
||||
if (n[0] > 0)
|
||||
XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
|
||||
face->gc, p, n[0], CoordModeOrigin);
|
||||
}
|
||||
else
|
||||
{
|
||||
GC *gc = face->extra;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
x += ftxfont_draw_bitmap (f, &face->gc, font, code[i], x, y,
|
||||
p, 0x100, n);
|
||||
for (i = 0; i < 7; i++)
|
||||
if (n[i] > 0)
|
||||
XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
|
||||
gc[i], p + 0x100 * i, n[i], CoordModeOrigin);
|
||||
}
|
||||
|
||||
UNBLOCK_INPUT;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
syms_of_ftxfont ()
|
||||
{
|
||||
DEFSYM (Qftx, "ftx");
|
||||
|
||||
ftxfont_driver = ftfont_driver;
|
||||
ftxfont_driver.type = Qftx;
|
||||
ftxfont_driver.list = ftxfont_list;
|
||||
ftxfont_driver.open = ftxfont_open;
|
||||
ftxfont_driver.close = ftxfont_close;
|
||||
ftxfont_driver.prepare_face = ftxfont_prepare_face;
|
||||
ftxfont_driver.done_face = ftxfont_done_face;
|
||||
ftxfont_driver.draw = ftxfont_draw;
|
||||
|
||||
register_font_driver (&ftxfont_driver, NULL);
|
||||
}
|
868
src/xfont.c
Normal file
868
src/xfont.c
Normal file
@ -0,0 +1,868 @@
|
||||
/* xfont.c -- X core font driver.
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
Copyright (C) 2006
|
||||
National Institute of Advanced Industrial Science and Technology (AIST)
|
||||
Registration Number H13PRO009
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include "lisp.h"
|
||||
#include "dispextern.h"
|
||||
#include "xterm.h"
|
||||
#include "frame.h"
|
||||
#include "blockinput.h"
|
||||
#include "character.h"
|
||||
#include "charset.h"
|
||||
#include "fontset.h"
|
||||
#include "font.h"
|
||||
|
||||
|
||||
/* X core font driver. */
|
||||
|
||||
Lisp_Object Qx;
|
||||
|
||||
/* Alist of font registry symbol and the corresponding charsets
|
||||
information. The information is retrieved from
|
||||
Vfont_encoding_alist on demand.
|
||||
|
||||
Eash element has the form:
|
||||
(REGISTRY . (ENCODING-CHARSET-ID . REPERTORY-CHARSET-ID))
|
||||
or
|
||||
(REGISTRY . nil)
|
||||
|
||||
In the former form, ENCODING-CHARSET-ID is an ID of a charset that
|
||||
encodes a character code to a glyph code of a font, and
|
||||
REPERTORY-CHARSET-ID is an ID of a charset that tells if a
|
||||
character is supported by a font.
|
||||
|
||||
The latter form means that the information for REGISTRY couldn't be
|
||||
retrieved. */
|
||||
static Lisp_Object x_font_charset_alist;
|
||||
|
||||
/* Prototypes of support functions. */
|
||||
extern void x_clear_errors P_ ((Display *));
|
||||
|
||||
static char *xfont_query_font P_ ((Display *, char *, Lisp_Object));
|
||||
static XCharStruct *xfont_get_pcm P_ ((XFontStruct *, XChar2b *));
|
||||
static int xfont_registry_charsets P_ ((Lisp_Object, struct charset **,
|
||||
struct charset **));
|
||||
|
||||
static char *
|
||||
xfont_query_font (display, name, spec)
|
||||
Display *display;
|
||||
char *name;
|
||||
Lisp_Object spec;
|
||||
{
|
||||
XFontStruct *font;
|
||||
|
||||
BLOCK_INPUT;
|
||||
x_catch_errors (display);
|
||||
font = XLoadQueryFont (display, name);
|
||||
name = NULL;
|
||||
if (x_had_errors_p (display))
|
||||
{
|
||||
/* This error is perhaps due to insufficient memory on X
|
||||
server. Let's just ignore it. */
|
||||
x_clear_errors (display);
|
||||
}
|
||||
else if (font)
|
||||
{
|
||||
unsigned long value;
|
||||
|
||||
if (XGetFontProperty (font, XA_FONT, &value))
|
||||
{
|
||||
char *n = (char *) XGetAtomName (display, (Atom) value);
|
||||
|
||||
if (font_parse_xlfd (n, spec, 0) >= 0)
|
||||
name = n;
|
||||
else
|
||||
XFree (n);
|
||||
}
|
||||
XFreeFont (display, font);
|
||||
}
|
||||
x_uncatch_errors ();
|
||||
UNBLOCK_INPUT;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/* Get metrics of character CHAR2B in XFONT. Value is null if CHAR2B
|
||||
is not contained in the font. */
|
||||
|
||||
static XCharStruct *
|
||||
xfont_get_pcm (xfont, char2b)
|
||||
XFontStruct *xfont;
|
||||
XChar2b *char2b;
|
||||
{
|
||||
/* The result metric information. */
|
||||
XCharStruct *pcm = NULL;
|
||||
|
||||
xassert (xfont && char2b);
|
||||
|
||||
if (xfont->per_char != NULL)
|
||||
{
|
||||
if (xfont->min_byte1 == 0 && xfont->max_byte1 == 0)
|
||||
{
|
||||
/* min_char_or_byte2 specifies the linear character index
|
||||
corresponding to the first element of the per_char array,
|
||||
max_char_or_byte2 is the index of the last character. A
|
||||
character with non-zero CHAR2B->byte1 is not in the font.
|
||||
A character with byte2 less than min_char_or_byte2 or
|
||||
greater max_char_or_byte2 is not in the font. */
|
||||
if (char2b->byte1 == 0
|
||||
&& char2b->byte2 >= xfont->min_char_or_byte2
|
||||
&& char2b->byte2 <= xfont->max_char_or_byte2)
|
||||
pcm = xfont->per_char + char2b->byte2 - xfont->min_char_or_byte2;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If either min_byte1 or max_byte1 are nonzero, both
|
||||
min_char_or_byte2 and max_char_or_byte2 are less than
|
||||
256, and the 2-byte character index values corresponding
|
||||
to the per_char array element N (counting from 0) are:
|
||||
|
||||
byte1 = N/D + min_byte1
|
||||
byte2 = N\D + min_char_or_byte2
|
||||
|
||||
where:
|
||||
|
||||
D = max_char_or_byte2 - min_char_or_byte2 + 1
|
||||
/ = integer division
|
||||
\ = integer modulus */
|
||||
if (char2b->byte1 >= xfont->min_byte1
|
||||
&& char2b->byte1 <= xfont->max_byte1
|
||||
&& char2b->byte2 >= xfont->min_char_or_byte2
|
||||
&& char2b->byte2 <= xfont->max_char_or_byte2)
|
||||
pcm = (xfont->per_char
|
||||
+ ((xfont->max_char_or_byte2 - xfont->min_char_or_byte2 + 1)
|
||||
* (char2b->byte1 - xfont->min_byte1))
|
||||
+ (char2b->byte2 - xfont->min_char_or_byte2));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the per_char pointer is null, all glyphs between the first
|
||||
and last character indexes inclusive have the same
|
||||
information, as given by both min_bounds and max_bounds. */
|
||||
if (char2b->byte2 >= xfont->min_char_or_byte2
|
||||
&& char2b->byte2 <= xfont->max_char_or_byte2)
|
||||
pcm = &xfont->max_bounds;
|
||||
}
|
||||
|
||||
return ((pcm == NULL
|
||||
|| (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
|
||||
? NULL : pcm);
|
||||
}
|
||||
|
||||
extern Lisp_Object find_font_encoding P_ ((Lisp_Object));
|
||||
|
||||
/* Return encoding charset and repertory charset for REGISTRY in
|
||||
ENCODING and REPERTORY correspondingly. If correct information for
|
||||
REGISTRY is available, return 0. Otherwise return -1. */
|
||||
|
||||
static int
|
||||
xfont_registry_charsets (registry, encoding, repertory)
|
||||
Lisp_Object registry;
|
||||
struct charset **encoding, **repertory;
|
||||
{
|
||||
Lisp_Object val;
|
||||
int encoding_id, repertory_id;
|
||||
|
||||
val = assq_no_quit (registry, x_font_charset_alist);
|
||||
if (! NILP (val))
|
||||
{
|
||||
val = XCDR (val);
|
||||
if (NILP (val))
|
||||
return -1;
|
||||
encoding_id = XINT (XCAR (val));
|
||||
repertory_id = XINT (XCDR (val));
|
||||
}
|
||||
else
|
||||
{
|
||||
val = find_font_encoding (SYMBOL_NAME (registry));
|
||||
if (SYMBOLP (val) && CHARSETP (val))
|
||||
{
|
||||
encoding_id = repertory_id = XINT (CHARSET_SYMBOL_ID (val));
|
||||
}
|
||||
else if (CONSP (val))
|
||||
{
|
||||
if (! CHARSETP (XCAR (val)))
|
||||
goto invalid_entry;
|
||||
encoding_id = XINT (CHARSET_SYMBOL_ID (XCAR (val)));
|
||||
if (NILP (XCDR (val)))
|
||||
repertory_id = -1;
|
||||
else
|
||||
{
|
||||
if (! CHARSETP (XCDR (val)))
|
||||
goto invalid_entry;
|
||||
repertory_id = XINT (CHARSET_SYMBOL_ID (XCDR (val)));
|
||||
}
|
||||
}
|
||||
else
|
||||
goto invalid_entry;
|
||||
val = Fcons (make_number (encoding_id), make_number (repertory_id));
|
||||
x_font_charset_alist
|
||||
= nconc2 (x_font_charset_alist, Fcons (Fcons (registry, val), Qnil));
|
||||
}
|
||||
|
||||
if (encoding)
|
||||
*encoding = CHARSET_FROM_ID (encoding_id);
|
||||
if (repertory)
|
||||
*repertory = repertory_id >= 0 ? CHARSET_FROM_ID (repertory_id) : NULL;
|
||||
return 0;
|
||||
|
||||
invalid_entry:
|
||||
x_font_charset_alist
|
||||
= nconc2 (x_font_charset_alist, Fcons (Fcons (registry, Qnil), Qnil));
|
||||
return -1;
|
||||
}
|
||||
|
||||
static Lisp_Object xfont_get_cache P_ ((Lisp_Object));
|
||||
static int xfont_parse_name P_ ((FRAME_PTR, char *, Lisp_Object));
|
||||
static Lisp_Object xfont_list P_ ((Lisp_Object, Lisp_Object));
|
||||
static Lisp_Object xfont_list_family P_ ((Lisp_Object));
|
||||
static struct font *xfont_open P_ ((FRAME_PTR, Lisp_Object, int));
|
||||
static void xfont_close P_ ((FRAME_PTR, struct font *));
|
||||
static int xfont_prepare_face P_ ((FRAME_PTR, struct face *));
|
||||
#if 0
|
||||
static void xfont_done_face P_ ((FRAME_PTR, struct face *));
|
||||
#endif
|
||||
static int xfont_has_char P_ ((Lisp_Object, int));
|
||||
static unsigned xfont_encode_char P_ ((struct font *, int));
|
||||
static int xfont_text_extents P_ ((struct font *, unsigned *, int,
|
||||
struct font_metrics *));
|
||||
static int xfont_draw P_ ((struct glyph_string *, int, int, int, int, int));
|
||||
|
||||
struct font_driver xfont_driver =
|
||||
{
|
||||
(Lisp_Object) NULL, /* Qx */
|
||||
xfont_get_cache,
|
||||
xfont_parse_name,
|
||||
xfont_list,
|
||||
xfont_list_family,
|
||||
NULL,
|
||||
xfont_open,
|
||||
xfont_close,
|
||||
xfont_prepare_face,
|
||||
NULL /*xfont_done_face*/,
|
||||
xfont_has_char,
|
||||
xfont_encode_char,
|
||||
xfont_text_extents,
|
||||
xfont_draw,
|
||||
};
|
||||
|
||||
extern Lisp_Object QCname;
|
||||
|
||||
static Lisp_Object
|
||||
xfont_get_cache (frame)
|
||||
Lisp_Object frame;
|
||||
{
|
||||
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (frame));
|
||||
|
||||
return (dpyinfo->name_list_element);
|
||||
}
|
||||
|
||||
static int
|
||||
xfont_parse_name (f, name, spec)
|
||||
FRAME_PTR f;
|
||||
char *name;
|
||||
Lisp_Object spec;
|
||||
{
|
||||
if (font_parse_xlfd (name, spec, 0) >= 0)
|
||||
return 0;
|
||||
name = xfont_query_font (FRAME_X_DISPLAY (f), name, spec);
|
||||
if (name)
|
||||
{
|
||||
XFree (name);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern Lisp_Object Vface_alternative_font_registry_alist;
|
||||
|
||||
static Lisp_Object
|
||||
xfont_list (frame, spec)
|
||||
Lisp_Object frame, spec;
|
||||
{
|
||||
FRAME_PTR f = XFRAME (frame);
|
||||
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
|
||||
Lisp_Object *vec, val, extra, font_name, entity;
|
||||
char name[256], **names;
|
||||
int i, idx, limit, num_fonts;
|
||||
int error_occurred = 0;
|
||||
USE_SAFE_ALLOCA;
|
||||
|
||||
extra = AREF (spec, FONT_EXTRA_INDEX);
|
||||
font_name = Qnil;
|
||||
if (CONSP (extra))
|
||||
{
|
||||
val = Fassq (QCotf, extra);
|
||||
if (! NILP (val))
|
||||
return null_vector;
|
||||
val = Fassq (QCname, extra);
|
||||
if (CONSP (val))
|
||||
font_name = XCDR (val);
|
||||
}
|
||||
|
||||
if (! STRINGP (font_name)
|
||||
&& font_unparse_xlfd (spec, 0, name, 256) < 0)
|
||||
return null_vector;
|
||||
|
||||
BLOCK_INPUT;
|
||||
x_catch_errors (dpyinfo->display);
|
||||
|
||||
if (STRINGP (font_name))
|
||||
{
|
||||
XFontStruct *font = XLoadQueryFont (dpyinfo->display,
|
||||
(char *) SDATA (font_name));
|
||||
unsigned long value;
|
||||
|
||||
num_fonts = 0;
|
||||
if (x_had_errors_p (dpyinfo->display))
|
||||
{
|
||||
/* This error is perhaps due to insufficient memory on X
|
||||
server. Let's just ignore it. */
|
||||
font = NULL;
|
||||
error_occurred = 1;
|
||||
x_clear_errors (dpyinfo->display);
|
||||
}
|
||||
if (font)
|
||||
{
|
||||
if (XGetFontProperty (font, XA_FONT, &value))
|
||||
{
|
||||
char *n = (char *) XGetAtomName (dpyinfo->display, (Atom) value);
|
||||
int len = strlen (n);
|
||||
char *tmp;
|
||||
|
||||
/* If DXPC (a Differential X Protocol Compressor)
|
||||
Ver.3.7 is running, XGetAtomName will return null
|
||||
string. We must avoid such a name. */
|
||||
if (len > 0)
|
||||
{
|
||||
num_fonts = 1;
|
||||
names = (char **) alloca (sizeof (char *));
|
||||
/* Some systems only allow alloca assigned to a
|
||||
simple var. */
|
||||
tmp = (char *) alloca (len + 1); names[0] = tmp;
|
||||
bcopy (n, names[0], len + 1);
|
||||
}
|
||||
XFree (n);
|
||||
}
|
||||
XFreeFont (dpyinfo->display, font);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Lisp_Object registry = AREF (spec, FONT_REGISTRY_INDEX);
|
||||
Lisp_Object alter = Qnil;
|
||||
char *r = NULL;
|
||||
|
||||
if (! NILP (registry))
|
||||
alter = Fassoc_string (SYMBOL_NAME (registry),
|
||||
Vface_alternative_font_registry_alist);
|
||||
while (1)
|
||||
{
|
||||
for (limit = 512, num_fonts = 0; ; limit *= 2)
|
||||
{
|
||||
names = XListFonts (dpyinfo->display, name, limit, &num_fonts);
|
||||
if (x_had_errors_p (dpyinfo->display))
|
||||
{
|
||||
/* This error is perhaps due to insufficient memory
|
||||
on X server. Let's just ignore it. */
|
||||
x_clear_errors (dpyinfo->display);
|
||||
error_occurred = 1;
|
||||
num_fonts = 0;
|
||||
break;
|
||||
}
|
||||
if (num_fonts < limit)
|
||||
break;
|
||||
XFreeFontNames (names);
|
||||
}
|
||||
if (num_fonts > 0
|
||||
|| NILP (alter))
|
||||
break;
|
||||
|
||||
/* Setup for trying alternatives. */
|
||||
if (! r
|
||||
&& ! (r = strstr (name, (char *) SDATA (SYMBOL_NAME (registry)))))
|
||||
abort ();
|
||||
while (1)
|
||||
{
|
||||
registry = Qnil;
|
||||
alter = XCDR (alter);
|
||||
if (NILP (alter))
|
||||
break;
|
||||
registry = XCAR (alter);
|
||||
if ((r - name) + SBYTES (registry) < 255)
|
||||
break;
|
||||
}
|
||||
if (NILP (registry))
|
||||
break;
|
||||
bcopy (SDATA (registry), r, SBYTES (registry));
|
||||
}
|
||||
}
|
||||
|
||||
x_uncatch_errors ();
|
||||
UNBLOCK_INPUT;
|
||||
|
||||
if (error_occurred)
|
||||
return Qnil;
|
||||
if (num_fonts == 0)
|
||||
return null_vector;
|
||||
|
||||
entity = Fmake_vector (make_number (FONT_ENTITY_MAX), Qnil);
|
||||
ASET (entity, FONT_TYPE_INDEX, Qx);
|
||||
ASET (entity, FONT_FRAME_INDEX, frame);
|
||||
|
||||
SAFE_ALLOCA_LISP (vec, num_fonts);
|
||||
for (i = idx = 0; i < num_fonts; i++)
|
||||
{
|
||||
if (font_parse_xlfd (names[i], entity, 0) > 0)
|
||||
vec[idx++] = Fcopy_sequence (entity);
|
||||
}
|
||||
if (! STRINGP (font_name))
|
||||
{
|
||||
BLOCK_INPUT;
|
||||
XFreeFontNames (names);
|
||||
UNBLOCK_INPUT;
|
||||
}
|
||||
val = Fvector (idx, vec);
|
||||
SAFE_FREE ();
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int
|
||||
memq_no_quit (elt, list)
|
||||
Lisp_Object elt, list;
|
||||
{
|
||||
while (CONSP (list) && ! EQ (XCAR (list), elt))
|
||||
list = XCDR (list);
|
||||
return (CONSP (list));
|
||||
}
|
||||
|
||||
static Lisp_Object
|
||||
xfont_list_family (frame)
|
||||
{
|
||||
FRAME_PTR f = XFRAME (frame);
|
||||
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
|
||||
char **names;
|
||||
int num_fonts, i;
|
||||
Lisp_Object list;
|
||||
char *last_family;
|
||||
int last_len;
|
||||
|
||||
BLOCK_INPUT;
|
||||
x_catch_errors (dpyinfo->display);
|
||||
names = XListFonts (dpyinfo->display, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*",
|
||||
0x8000, &num_fonts);
|
||||
if (x_had_errors_p (dpyinfo->display))
|
||||
{
|
||||
/* This error is perhaps due to insufficient memory on X server.
|
||||
Let's just ignore it. */
|
||||
x_clear_errors (dpyinfo->display);
|
||||
num_fonts = 0;
|
||||
}
|
||||
|
||||
list = Qnil;
|
||||
for (i = 0, last_len = 0; i < num_fonts; i++)
|
||||
{
|
||||
char *p0 = names[i], *p1;
|
||||
Lisp_Object family;
|
||||
|
||||
p0++; /* skip the leading '-' */
|
||||
while (*p0 && *p0 != '-') p0++; /* skip foundry */
|
||||
if (! *p0)
|
||||
continue;
|
||||
p1 = ++p0;
|
||||
while (*p1 && *p1 != '-') p1++; /* find the end of family */
|
||||
if (! *p1 || p1 == p0)
|
||||
continue;
|
||||
if (last_len == p1 - p0
|
||||
&& bcmp (last_family, p0, last_len) == 0)
|
||||
continue;
|
||||
last_len = p1 - p0;
|
||||
last_family = p0;
|
||||
family = intern_downcase (p0, last_len);
|
||||
if (! memq_no_quit (family, list))
|
||||
list = Fcons (family, list);
|
||||
}
|
||||
|
||||
XFreeFontNames (names);
|
||||
x_uncatch_errors ();
|
||||
UNBLOCK_INPUT;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static struct font *
|
||||
xfont_open (f, entity, pixel_size)
|
||||
FRAME_PTR f;
|
||||
Lisp_Object entity;
|
||||
int pixel_size;
|
||||
{
|
||||
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
|
||||
Display *display = dpyinfo->display;
|
||||
char name[256];
|
||||
int len;
|
||||
unsigned long value;
|
||||
Lisp_Object registry;
|
||||
struct charset *encoding, *repertory;
|
||||
struct font *font;
|
||||
XFontStruct *xfont;
|
||||
|
||||
/* At first, check if we know how to encode characters for this
|
||||
font. */
|
||||
registry = AREF (entity, FONT_REGISTRY_INDEX);
|
||||
if (xfont_registry_charsets (registry, &encoding, &repertory) < 0)
|
||||
return NULL;
|
||||
|
||||
if (XINT (AREF (entity, FONT_SIZE_INDEX)) != 0)
|
||||
pixel_size = XINT (AREF (entity, FONT_SIZE_INDEX));
|
||||
len = font_unparse_xlfd (entity, pixel_size, name, 256);
|
||||
if (len <= 0)
|
||||
return NULL;
|
||||
|
||||
BLOCK_INPUT;
|
||||
x_catch_errors (display);
|
||||
xfont = XLoadQueryFont (display, name);
|
||||
if (x_had_errors_p (display))
|
||||
{
|
||||
/* This error is perhaps due to insufficient memory on X server.
|
||||
Let's just ignore it. */
|
||||
x_clear_errors (display);
|
||||
xfont = NULL;
|
||||
}
|
||||
x_uncatch_errors ();
|
||||
UNBLOCK_INPUT;
|
||||
|
||||
if (! xfont)
|
||||
return NULL;
|
||||
font = malloc (sizeof (struct font));
|
||||
font->font.font = xfont;
|
||||
font->entity = entity;
|
||||
font->pixel_size = pixel_size;
|
||||
font->driver = &xfont_driver;
|
||||
font->font.name = malloc (len + 1);
|
||||
if (! font->font.name)
|
||||
{
|
||||
XFreeFont (display, xfont);
|
||||
free (font);
|
||||
return NULL;
|
||||
}
|
||||
bcopy (name, font->font.name, len + 1);
|
||||
font->font.charset = encoding->id;
|
||||
font->encoding_charset = encoding->id;
|
||||
font->repertory_charet = repertory ? repertory->id : -1;
|
||||
font->ascent = xfont->ascent;
|
||||
font->descent = xfont->descent;
|
||||
|
||||
if (xfont->min_bounds.width == xfont->max_bounds.width)
|
||||
{
|
||||
/* Fixed width font. */
|
||||
font->font.average_width = font->font.space_width
|
||||
= xfont->min_bounds.width;
|
||||
}
|
||||
else
|
||||
{
|
||||
XChar2b char2b;
|
||||
XCharStruct *pcm;
|
||||
|
||||
char2b.byte1 = 0x00, char2b.byte2 = 0x20;
|
||||
pcm = xfont_get_pcm (xfont, &char2b);
|
||||
if (pcm)
|
||||
font->font.space_width = pcm->width;
|
||||
else
|
||||
font->font.space_width = xfont->max_bounds.width;
|
||||
|
||||
font->font.average_width
|
||||
= (XGetFontProperty (xfont, dpyinfo->Xatom_AVERAGE_WIDTH, &value)
|
||||
? (long) value / 10 : 0);
|
||||
if (font->font.average_width < 0)
|
||||
font->font.average_width = - font->font.average_width;
|
||||
if (font->font.average_width == 0)
|
||||
{
|
||||
if (pcm)
|
||||
{
|
||||
int width = pcm->width;
|
||||
for (char2b.byte2 = 33; char2b.byte2 <= 126; char2b.byte2++)
|
||||
if ((pcm = xfont_get_pcm (xfont, &char2b)) != NULL)
|
||||
width += pcm->width;
|
||||
font->font.average_width = width / 95;
|
||||
}
|
||||
else
|
||||
font->font.average_width = xfont->max_bounds.width;
|
||||
}
|
||||
}
|
||||
font->min_width = xfont->min_bounds.width;
|
||||
if (font->min_width <= 0)
|
||||
font->min_width = font->font.space_width;
|
||||
|
||||
BLOCK_INPUT;
|
||||
/* Try to get the full name of FONT. Put it in FULL_NAME. */
|
||||
if (XGetFontProperty (xfont, XA_FONT, &value))
|
||||
{
|
||||
char *full_name = NULL, *p0, *p;
|
||||
int dashes = 0;
|
||||
|
||||
p0 = p = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);;
|
||||
/* Count the number of dashes in the "full name".
|
||||
If it is too few, this isn't really the font's full name,
|
||||
so don't use it.
|
||||
In X11R4, the fonts did not come with their canonical names
|
||||
stored in them. */
|
||||
while (*p)
|
||||
{
|
||||
if (*p == '-')
|
||||
dashes++;
|
||||
p++;
|
||||
}
|
||||
|
||||
if (dashes >= 13)
|
||||
{
|
||||
full_name = (char *) malloc (p - p0 + 1);
|
||||
if (full_name)
|
||||
bcopy (p0, full_name, p - p0 + 1);
|
||||
}
|
||||
XFree (p0);
|
||||
|
||||
if (full_name)
|
||||
font->font.full_name = full_name;
|
||||
else
|
||||
font->font.full_name = font->font.name;
|
||||
}
|
||||
font->file_name = NULL;
|
||||
|
||||
font->font.size = xfont->max_bounds.width;
|
||||
font->font.height = xfont->ascent + xfont->descent;
|
||||
font->font.baseline_offset
|
||||
= (XGetFontProperty (xfont, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
|
||||
? (long) value : 0);
|
||||
font->font.relative_compose
|
||||
= (XGetFontProperty (xfont, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
|
||||
? (long) value : 0);
|
||||
font->font.default_ascent
|
||||
= (XGetFontProperty (xfont, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
|
||||
? (long) value : 0);
|
||||
font->font.vertical_centering
|
||||
= (STRINGP (Vvertical_centering_font_regexp)
|
||||
&& (fast_c_string_match_ignore_case
|
||||
(Vvertical_centering_font_regexp, font->font.full_name) >= 0));
|
||||
|
||||
UNBLOCK_INPUT;
|
||||
|
||||
dpyinfo->n_fonts++;
|
||||
|
||||
/* Set global flag fonts_changed_p to non-zero if the font loaded
|
||||
has a character with a smaller width than any other character
|
||||
before, or if the font loaded has a smaller height than any other
|
||||
font loaded before. If this happens, it will make a glyph matrix
|
||||
reallocation necessary. */
|
||||
if (dpyinfo->n_fonts == 1)
|
||||
{
|
||||
dpyinfo->smallest_font_height = font->font.height;
|
||||
dpyinfo->smallest_char_width = font->min_width;
|
||||
fonts_changed_p = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dpyinfo->smallest_font_height > font->font.height)
|
||||
dpyinfo->smallest_font_height = font->font.height, fonts_changed_p |= 1;
|
||||
if (dpyinfo->smallest_char_width > font->min_width)
|
||||
dpyinfo->smallest_char_width = font->min_width, fonts_changed_p |= 1;
|
||||
}
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
static void
|
||||
xfont_close (f, font)
|
||||
FRAME_PTR f;
|
||||
struct font *font;
|
||||
{
|
||||
BLOCK_INPUT;
|
||||
XFreeFont (FRAME_X_DISPLAY (f), font->font.font);
|
||||
UNBLOCK_INPUT;
|
||||
|
||||
if (font->font.name != font->font.full_name)
|
||||
free (font->font.full_name);
|
||||
free (font->font.name);
|
||||
free (font);
|
||||
FRAME_X_DISPLAY_INFO (f)->n_fonts--;
|
||||
}
|
||||
|
||||
static int
|
||||
xfont_prepare_face (f, face)
|
||||
FRAME_PTR f;
|
||||
struct face *face;
|
||||
{
|
||||
BLOCK_INPUT;
|
||||
XSetFont (FRAME_X_DISPLAY (f), face->gc, face->font->fid);
|
||||
UNBLOCK_INPUT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
xfont_done_face (f, face)
|
||||
FRAME_PTR f;
|
||||
struct face *face;
|
||||
{
|
||||
if (face->extra)
|
||||
{
|
||||
BLOCK_INPUT;
|
||||
XFreeGC (FRAME_X_DISPLAY (f), (GC) face->extra);
|
||||
UNBLOCK_INPUT;
|
||||
face->extra = NULL;
|
||||
}
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
static int
|
||||
xfont_has_char (entity, c)
|
||||
Lisp_Object entity;
|
||||
int c;
|
||||
{
|
||||
Lisp_Object registry = AREF (entity, FONT_REGISTRY_INDEX);
|
||||
struct charset *repertory;
|
||||
|
||||
if (xfont_registry_charsets (registry, NULL, &repertory) < 0)
|
||||
return -1;
|
||||
if (! repertory)
|
||||
return -1;
|
||||
return (ENCODE_CHAR (repertory, c) != CHARSET_INVALID_CODE (repertory));
|
||||
}
|
||||
|
||||
static unsigned
|
||||
xfont_encode_char (font, c)
|
||||
struct font *font;
|
||||
int c;
|
||||
{
|
||||
struct charset *charset;
|
||||
unsigned code;
|
||||
XChar2b char2b;
|
||||
|
||||
charset = CHARSET_FROM_ID (font->encoding_charset);
|
||||
code = ENCODE_CHAR (charset, c);
|
||||
if (code == CHARSET_INVALID_CODE (charset))
|
||||
return 0xFFFFFFFF;
|
||||
if (font->repertory_charet >= 0)
|
||||
{
|
||||
charset = CHARSET_FROM_ID (font->repertory_charet);
|
||||
return (ENCODE_CHAR (charset, c) != CHARSET_INVALID_CODE (charset)
|
||||
? code : 0xFFFFFFFF);
|
||||
}
|
||||
char2b.byte1 = code >> 16;
|
||||
char2b.byte2 = code & 0xFFFF;
|
||||
return (xfont_get_pcm (font->font.font, &char2b) ? code : 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
static int
|
||||
xfont_text_extents (font, code, nglyphs, metrics)
|
||||
struct font *font;
|
||||
unsigned *code;
|
||||
int nglyphs;
|
||||
struct font_metrics *metrics;
|
||||
{
|
||||
int width = 0;
|
||||
int i, x;
|
||||
|
||||
if (metrics)
|
||||
bzero (metrics, sizeof (struct font_metrics));
|
||||
for (i = 0, x = 0; i < nglyphs; i++)
|
||||
{
|
||||
XChar2b char2b;
|
||||
static XCharStruct *pcm;
|
||||
|
||||
if (code[i] >= 0x10000)
|
||||
continue;
|
||||
char2b.byte1 = code[i] >> 8, char2b.byte2 = code[i] & 0xFF;
|
||||
pcm = xfont_get_pcm (font->font.font, &char2b);
|
||||
if (! pcm)
|
||||
continue;
|
||||
if (metrics->lbearing > width + pcm->lbearing)
|
||||
metrics->lbearing = width + pcm->lbearing;
|
||||
if (metrics->rbearing < width + pcm->rbearing)
|
||||
metrics->rbearing = width + pcm->rbearing;
|
||||
if (metrics->ascent < pcm->ascent)
|
||||
metrics->ascent = pcm->ascent;
|
||||
if (metrics->descent < pcm->descent)
|
||||
metrics->descent = pcm->descent;
|
||||
width += pcm->width;
|
||||
}
|
||||
if (metrics)
|
||||
metrics->width = width;
|
||||
return width;
|
||||
}
|
||||
|
||||
static int
|
||||
xfont_draw (s, from, to, x, y, with_background)
|
||||
struct glyph_string *s;
|
||||
int from, to, x, y, with_background;
|
||||
{
|
||||
XFontStruct *xfont = s->face->font;
|
||||
int len = to - from;
|
||||
|
||||
if (xfont->min_byte1 == 0 && xfont->max_byte1 == 0)
|
||||
{
|
||||
char *str;
|
||||
int i;
|
||||
USE_SAFE_ALLOCA;
|
||||
|
||||
SAFE_ALLOCA (str, char *, len);
|
||||
for (i = 0; i < len ; i++)
|
||||
str[i] = XCHAR2B_BYTE2 (s->char2b + from + i);
|
||||
if (with_background > 0)
|
||||
XDrawImageString (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
|
||||
s->gc, x, y, str, len);
|
||||
else
|
||||
XDrawString (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
|
||||
s->gc, x, y, str, len);
|
||||
SAFE_FREE ();
|
||||
return s->nchars;
|
||||
}
|
||||
|
||||
if (with_background > 0)
|
||||
XDrawImageString16 (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
|
||||
s->gc, x, y, s->char2b + from, len);
|
||||
else
|
||||
XDrawString16 (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
|
||||
s->gc, x, y, s->char2b + from, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
syms_of_xfont ()
|
||||
{
|
||||
staticpro (&x_font_charset_alist);
|
||||
x_font_charset_alist = Qnil;
|
||||
|
||||
DEFSYM (Qx, "x");
|
||||
xfont_driver.type = Qx;
|
||||
register_font_driver (&xfont_driver, NULL);
|
||||
}
|
552
src/xftfont.c
Normal file
552
src/xftfont.c
Normal file
@ -0,0 +1,552 @@
|
||||
/* xftfont.c -- XFT font driver.
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
Copyright (C) 2006
|
||||
National Institute of Advanced Industrial Science and Technology (AIST)
|
||||
Registration Number H13PRO009
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xft/Xft.h>
|
||||
|
||||
#include "lisp.h"
|
||||
#include "dispextern.h"
|
||||
#include "xterm.h"
|
||||
#include "frame.h"
|
||||
#include "blockinput.h"
|
||||
#include "character.h"
|
||||
#include "charset.h"
|
||||
#include "fontset.h"
|
||||
#include "font.h"
|
||||
|
||||
/* Xft font driver. */
|
||||
|
||||
static Lisp_Object Qxft;
|
||||
|
||||
/* The actual structure for Xft font that can be casted to struct
|
||||
font. */
|
||||
|
||||
struct xftfont_info
|
||||
{
|
||||
struct font font;
|
||||
Display *display;
|
||||
int screen;
|
||||
XftFont *xftfont;
|
||||
FT_Face ft_face;
|
||||
};
|
||||
|
||||
/* Structure pointed by (struct face *)->extra */
|
||||
struct xftface_info
|
||||
{
|
||||
XftColor xft_fg;
|
||||
XftColor xft_bg;
|
||||
XftDraw *xft_draw;
|
||||
};
|
||||
|
||||
static void xftfont_get_colors P_ ((FRAME_PTR, struct face *, GC gc,
|
||||
struct xftface_info *,
|
||||
XftColor *fg, XftColor *bg));
|
||||
static Font xftfont_default_fid P_ ((FRAME_PTR));
|
||||
|
||||
|
||||
/* Setup colors pointed by FG and BG for GC. If XFTFACE_INFO is not
|
||||
NULL, reuse the colors in it if possible. BG may be NULL. */
|
||||
static void
|
||||
xftfont_get_colors (f, face, gc, xftface_info, fg, bg)
|
||||
FRAME_PTR f;
|
||||
struct face *face;
|
||||
GC gc;
|
||||
struct xftface_info *xftface_info;
|
||||
XftColor *fg, *bg;
|
||||
{
|
||||
if (xftface_info && face->gc == gc)
|
||||
{
|
||||
*fg = xftface_info->xft_fg;
|
||||
if (bg)
|
||||
*bg = xftface_info->xft_bg;
|
||||
}
|
||||
else
|
||||
{
|
||||
XGCValues xgcv;
|
||||
int fg_done = 0, bg_done = 0;
|
||||
|
||||
BLOCK_INPUT;
|
||||
XGetGCValues (FRAME_X_DISPLAY (f), gc,
|
||||
GCForeground | GCBackground, &xgcv);
|
||||
if (xftface_info)
|
||||
{
|
||||
if (xgcv.foreground == face->foreground)
|
||||
*fg = xftface_info->xft_fg, fg_done = 1;
|
||||
else if (xgcv.foreground == face->background)
|
||||
*fg = xftface_info->xft_bg, fg_done = 1;
|
||||
if (! bg)
|
||||
bg_done = 1;
|
||||
else if (xgcv.background == face->background)
|
||||
*bg = xftface_info->xft_bg, bg_done = 1;
|
||||
else if (xgcv.background == face->foreground)
|
||||
*bg = xftface_info->xft_fg, bg_done = 1;
|
||||
}
|
||||
|
||||
if (fg_done + bg_done < 2)
|
||||
{
|
||||
XColor colors[2];
|
||||
|
||||
colors[0].pixel = fg->pixel = xgcv.foreground;
|
||||
if (bg)
|
||||
colors[1].pixel = bg->pixel = xgcv.background;
|
||||
XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors,
|
||||
bg ? 2 : 1);
|
||||
fg->color.alpha = 0xFFFF;
|
||||
fg->color.red = colors[0].red;
|
||||
fg->color.green = colors[0].green;
|
||||
fg->color.blue = colors[0].blue;
|
||||
if (bg)
|
||||
{
|
||||
bg->color.alpha = 0xFFFF;
|
||||
bg->color.red = colors[1].red;
|
||||
bg->color.green = colors[1].green;
|
||||
bg->color.blue = colors[1].blue;
|
||||
}
|
||||
}
|
||||
UNBLOCK_INPUT;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the default Font ID on frame F. */
|
||||
|
||||
static Font
|
||||
xftfont_default_fid (f)
|
||||
FRAME_PTR f;
|
||||
{
|
||||
static int fid_known;
|
||||
static Font fid;
|
||||
|
||||
if (! fid_known)
|
||||
{
|
||||
fid = XLoadFont (FRAME_X_DISPLAY (f), "fixed");
|
||||
if (! fid)
|
||||
{
|
||||
fid = XLoadFont (FRAME_X_DISPLAY (f), "*");
|
||||
if (! fid)
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
return fid;
|
||||
}
|
||||
|
||||
|
||||
static Lisp_Object xftfont_list P_ ((Lisp_Object, Lisp_Object));
|
||||
static struct font *xftfont_open P_ ((FRAME_PTR, Lisp_Object, int));
|
||||
static void xftfont_close P_ ((FRAME_PTR, struct font *));
|
||||
static int xftfont_prepare_face P_ ((FRAME_PTR, struct face *));
|
||||
static void xftfont_done_face P_ ((FRAME_PTR, struct face *));
|
||||
static unsigned xftfont_encode_char P_ ((struct font *, int));
|
||||
static int xftfont_text_extents P_ ((struct font *, unsigned *, int,
|
||||
struct font_metrics *));
|
||||
static int xftfont_draw P_ ((struct glyph_string *, int, int, int, int, int));
|
||||
|
||||
static int xftfont_anchor_point P_ ((struct font *, unsigned, int,
|
||||
int *, int *));
|
||||
|
||||
struct font_driver xftfont_driver;
|
||||
|
||||
static Lisp_Object
|
||||
xftfont_list (frame, spec)
|
||||
Lisp_Object frame;
|
||||
Lisp_Object spec;
|
||||
{
|
||||
Lisp_Object val = ftfont_driver.list (frame, spec);
|
||||
|
||||
if (! NILP (val))
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ASIZE (val); i++)
|
||||
ASET (AREF (val, i), FONT_TYPE_INDEX, Qxft);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static FcChar8 ascii_printable[95];
|
||||
|
||||
static struct font *
|
||||
xftfont_open (f, entity, pixel_size)
|
||||
FRAME_PTR f;
|
||||
Lisp_Object entity;
|
||||
int pixel_size;
|
||||
{
|
||||
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
|
||||
Display *display = FRAME_X_DISPLAY (f);
|
||||
Lisp_Object val;
|
||||
FcPattern *pattern, *pat;
|
||||
FcChar8 *file;
|
||||
XFontStruct *xfont;
|
||||
struct xftfont_info *xftfont_info;
|
||||
struct font *font;
|
||||
double size = 0;
|
||||
XftFont *xftfont;
|
||||
int spacing;
|
||||
|
||||
val = AREF (entity, FONT_EXTRA_INDEX);
|
||||
if (XTYPE (val) != Lisp_Misc
|
||||
|| XMISCTYPE (val) != Lisp_Misc_Save_Value)
|
||||
return NULL;
|
||||
pattern = XSAVE_VALUE (val)->pointer;
|
||||
if (FcPatternGetString (pattern, FC_FILE, 0, &file) != FcResultMatch)
|
||||
return NULL;
|
||||
|
||||
size = XINT (AREF (entity, FONT_SIZE_INDEX));
|
||||
if (size == 0)
|
||||
size = pixel_size;
|
||||
pat = FcPatternCreate ();
|
||||
FcPatternAddString (pat, FC_FILE, file);
|
||||
FcPatternAddDouble (pat, FC_PIXEL_SIZE, pixel_size);
|
||||
FcPatternAddBool (pat, FC_ANTIALIAS, FcTrue);
|
||||
xftfont = XftFontOpenPattern (display, pat);
|
||||
/* We should not destroy PAT here because it is kept in XFTFONT and
|
||||
destroyed automatically when XFTFONT is closed. */
|
||||
if (! xftfont)
|
||||
return NULL;
|
||||
|
||||
xftfont_info = malloc (sizeof (struct xftfont_info));
|
||||
if (! xftfont_info)
|
||||
{
|
||||
XftFontClose (display, xftfont);
|
||||
return NULL;
|
||||
}
|
||||
xfont = malloc (sizeof (XFontStruct));
|
||||
if (! xftfont_info)
|
||||
{
|
||||
XftFontClose (display, xftfont);
|
||||
free (xftfont_info);
|
||||
return NULL;
|
||||
}
|
||||
xftfont_info->display = display;
|
||||
xftfont_info->screen = FRAME_X_SCREEN_NUMBER (f);
|
||||
xftfont_info->xftfont = xftfont;
|
||||
xftfont_info->ft_face = XftLockFace (xftfont);
|
||||
|
||||
font = (struct font *) xftfont_info;
|
||||
font->entity = entity;
|
||||
font->pixel_size = size;
|
||||
font->driver = &xftfont_driver;
|
||||
font->font.name = font->font.full_name = NULL;
|
||||
font->file_name = (char *) file;
|
||||
font->font.size = xftfont->max_advance_width;
|
||||
font->ascent = xftfont->ascent;
|
||||
font->descent = xftfont->descent;
|
||||
font->font.height = xftfont->ascent + xftfont->descent;
|
||||
|
||||
if (FcPatternGetInteger (xftfont->pattern, FC_SPACING, 0, &spacing)
|
||||
!= FcResultMatch)
|
||||
spacing = FC_PROPORTIONAL;
|
||||
if (spacing != FC_PROPORTIONAL)
|
||||
font->font.average_width = font->font.space_width
|
||||
= xftfont->max_advance_width;
|
||||
else
|
||||
{
|
||||
XGlyphInfo extents;
|
||||
|
||||
if (! ascii_printable[0])
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 95; i++)
|
||||
ascii_printable[i] = ' ' + i;
|
||||
}
|
||||
XftTextExtents8 (display, xftfont, ascii_printable, 1, &extents);
|
||||
font->font.space_width = extents.xOff;
|
||||
if (font->font.space_width <= 0)
|
||||
/* dirty workaround */
|
||||
font->font.space_width = pixel_size;
|
||||
XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
|
||||
font->font.average_width = (font->font.space_width + extents.xOff) / 95;
|
||||
}
|
||||
|
||||
/* Unfortunately Xft doesn't provide a way to get minimum char
|
||||
width. So, we use space_width instead. */
|
||||
font->min_width = font->font.space_width;
|
||||
|
||||
font->font.baseline_offset = 0;
|
||||
font->font.relative_compose = 0;
|
||||
font->font.default_ascent = 0;
|
||||
font->font.vertical_centering = 0;
|
||||
|
||||
/* Setup pseudo XFontStruct */
|
||||
xfont->fid = xftfont_default_fid (f);
|
||||
xfont->ascent = xftfont->ascent;
|
||||
xfont->descent = xftfont->descent;
|
||||
xfont->max_bounds.descent = xftfont->descent;
|
||||
xfont->max_bounds.width = xftfont->max_advance_width;
|
||||
xfont->min_bounds.width = font->font.space_width;
|
||||
font->font.font = xfont;
|
||||
|
||||
dpyinfo->n_fonts++;
|
||||
|
||||
/* Set global flag fonts_changed_p to non-zero if the font loaded
|
||||
has a character with a smaller width than any other character
|
||||
before, or if the font loaded has a smaller height than any other
|
||||
font loaded before. If this happens, it will make a glyph matrix
|
||||
reallocation necessary. */
|
||||
if (dpyinfo->n_fonts == 1)
|
||||
{
|
||||
dpyinfo->smallest_font_height = font->font.height;
|
||||
dpyinfo->smallest_char_width = font->min_width;
|
||||
fonts_changed_p = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dpyinfo->smallest_font_height > font->font.height)
|
||||
dpyinfo->smallest_font_height = font->font.height,
|
||||
fonts_changed_p |= 1;
|
||||
if (dpyinfo->smallest_char_width > font->min_width)
|
||||
dpyinfo->smallest_char_width = font->min_width,
|
||||
fonts_changed_p |= 1;
|
||||
}
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
static void
|
||||
xftfont_close (f, font)
|
||||
FRAME_PTR f;
|
||||
struct font *font;
|
||||
{
|
||||
struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
|
||||
|
||||
XftUnlockFace (xftfont_info->xftfont);
|
||||
XftFontClose (xftfont_info->display, xftfont_info->xftfont);
|
||||
free (font);
|
||||
FRAME_X_DISPLAY_INFO (f)->n_fonts--;
|
||||
}
|
||||
|
||||
struct xftdraw_list
|
||||
{
|
||||
XftDraw *xftdraw;
|
||||
struct xftdraw_list *next;
|
||||
};
|
||||
|
||||
static struct xftdraw_list *xftdraw_list;
|
||||
|
||||
static void
|
||||
register_xftdraw (xftdraw)
|
||||
XftDraw *xftdraw;
|
||||
{
|
||||
struct xftdraw_list *list = malloc (sizeof (struct xftdraw_list));
|
||||
|
||||
list->xftdraw = xftdraw;
|
||||
list->next = xftdraw_list;
|
||||
xftdraw_list = list;
|
||||
}
|
||||
|
||||
static void
|
||||
check_xftdraw (xftdraw)
|
||||
XftDraw *xftdraw;
|
||||
{
|
||||
struct xftdraw_list *list, *prev;
|
||||
|
||||
for (list = xftdraw_list, prev = NULL; list; prev = list, list = list->next)
|
||||
{
|
||||
if (list->xftdraw == xftdraw)
|
||||
{
|
||||
if (! prev)
|
||||
{
|
||||
list = xftdraw_list->next;
|
||||
free (xftdraw_list);
|
||||
xftdraw_list = list;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev->next = list->next;
|
||||
free (list);
|
||||
list = prev;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
abort ();
|
||||
}
|
||||
|
||||
static int
|
||||
xftfont_prepare_face (f, face)
|
||||
FRAME_PTR f;
|
||||
struct face *face;
|
||||
{
|
||||
struct xftface_info *xftface_info = malloc (sizeof (struct xftface_info));
|
||||
|
||||
if (! xftface_info)
|
||||
return -1;
|
||||
|
||||
BLOCK_INPUT;
|
||||
xftface_info->xft_draw = XftDrawCreate (FRAME_X_DISPLAY (f),
|
||||
FRAME_X_WINDOW (f),
|
||||
FRAME_X_VISUAL (f),
|
||||
FRAME_X_COLORMAP (f));
|
||||
register_xftdraw (xftface_info->xft_draw);
|
||||
|
||||
xftfont_get_colors (f, face, face->gc, NULL,
|
||||
&xftface_info->xft_fg, &xftface_info->xft_bg);
|
||||
UNBLOCK_INPUT;
|
||||
|
||||
face->extra = xftface_info;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
xftfont_done_face (f, face)
|
||||
FRAME_PTR f;
|
||||
struct face *face;
|
||||
{
|
||||
struct xftface_info *xftface_info = (struct xftface_info *) face->extra;
|
||||
|
||||
if (xftface_info)
|
||||
{
|
||||
BLOCK_INPUT;
|
||||
check_xftdraw (xftface_info->xft_draw);
|
||||
XftDrawDestroy (xftface_info->xft_draw);
|
||||
UNBLOCK_INPUT;
|
||||
free (xftface_info);
|
||||
face->extra = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned
|
||||
xftfont_encode_char (font, c)
|
||||
struct font *font;
|
||||
int c;
|
||||
{
|
||||
struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
|
||||
unsigned code = XftCharIndex (xftfont_info->display, xftfont_info->xftfont,
|
||||
(FcChar32) c);
|
||||
|
||||
return (code ? code : 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
static int
|
||||
xftfont_text_extents (font, code, nglyphs, metrics)
|
||||
struct font *font;
|
||||
unsigned *code;
|
||||
int nglyphs;
|
||||
struct font_metrics *metrics;
|
||||
{
|
||||
struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
|
||||
XGlyphInfo extents;
|
||||
|
||||
BLOCK_INPUT;
|
||||
XftGlyphExtents (xftfont_info->display, xftfont_info->xftfont, code, nglyphs,
|
||||
&extents);
|
||||
UNBLOCK_INPUT;
|
||||
if (metrics)
|
||||
{
|
||||
metrics->lbearing = - extents.x;
|
||||
metrics->rbearing = - extents.x + extents.width;
|
||||
metrics->width = extents.xOff;
|
||||
metrics->ascent = extents.y;
|
||||
metrics->descent = extents.y - extents.height;
|
||||
}
|
||||
return extents.xOff;
|
||||
}
|
||||
|
||||
static int
|
||||
xftfont_draw (s, from, to, x, y, with_background)
|
||||
struct glyph_string *s;
|
||||
int from, to, x, y, with_background;
|
||||
{
|
||||
FRAME_PTR f = s->f;
|
||||
struct face *face = s->face;
|
||||
struct xftfont_info *xftfont_info = (struct xftfont_info *) face->font_info;
|
||||
struct xftface_info *xftface_info = (struct xftface_info *) face->extra;
|
||||
FT_UInt *code;
|
||||
XftColor fg, bg;
|
||||
XRectangle r;
|
||||
int len = to - from;
|
||||
int i;
|
||||
|
||||
xftfont_get_colors (f, face, s->gc, xftface_info,
|
||||
&fg, s->width ? &bg : NULL);
|
||||
BLOCK_INPUT;
|
||||
if (s->clip_width)
|
||||
{
|
||||
r.x = s->clip_x, r.width = s->clip_width;
|
||||
r.y = s->clip_y, r.height = s->clip_height;
|
||||
XftDrawSetClipRectangles (xftface_info->xft_draw, 0, 0, &r, 1);
|
||||
}
|
||||
if (with_background)
|
||||
{
|
||||
struct font *font = (struct font *) face->font_info;
|
||||
|
||||
XftDrawRect (xftface_info->xft_draw, &bg,
|
||||
x, y - face->font->ascent, s->width, font->font.height);
|
||||
}
|
||||
code = alloca (sizeof (FT_UInt) * len);
|
||||
for (i = 0; i < len; i++)
|
||||
code[i] = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8)
|
||||
| XCHAR2B_BYTE2 (s->char2b + from + i));
|
||||
|
||||
XftDrawGlyphs (xftface_info->xft_draw, &fg, xftfont_info->xftfont,
|
||||
x, y, code, len);
|
||||
if (s->clip_width)
|
||||
XftDrawSetClip (xftface_info->xft_draw, NULL);
|
||||
UNBLOCK_INPUT;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
xftfont_anchor_point (font, code, index, x, y)
|
||||
struct font *font;
|
||||
unsigned code;
|
||||
int index;
|
||||
int *x, *y;
|
||||
{
|
||||
struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
|
||||
FT_Face ft_face = xftfont_info->ft_face;
|
||||
|
||||
if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
|
||||
return -1;
|
||||
if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
|
||||
return -1;
|
||||
if (index >= ft_face->glyph->outline.n_points)
|
||||
return -1;
|
||||
*x = ft_face->glyph->outline.points[index].x;
|
||||
*y = ft_face->glyph->outline.points[index].y;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
syms_of_xftfont ()
|
||||
{
|
||||
DEFSYM (Qxft, "xft");
|
||||
|
||||
xftfont_driver = ftfont_driver;
|
||||
xftfont_driver.type = Qxft;
|
||||
xftfont_driver.get_cache = xfont_driver.get_cache;
|
||||
xftfont_driver.list = xftfont_list;
|
||||
xftfont_driver.open = xftfont_open;
|
||||
xftfont_driver.close = xftfont_close;
|
||||
xftfont_driver.prepare_face = xftfont_prepare_face;
|
||||
xftfont_driver.done_face = xftfont_done_face;
|
||||
xftfont_driver.encode_char = xftfont_encode_char;
|
||||
xftfont_driver.text_extents = xftfont_text_extents;
|
||||
xftfont_driver.draw = xftfont_draw;
|
||||
xftfont_driver.anchor_point = xftfont_anchor_point;
|
||||
|
||||
register_font_driver (&xftfont_driver, NULL);
|
||||
}
|
Loading…
Reference in New Issue
Block a user