diff options
author | Jan D <jan.h.d@swipnet.se> | 2015-02-11 16:14:35 +0100 |
---|---|---|
committer | Jan D <jan.h.d@swipnet.se> | 2015-02-11 16:14:35 +0100 |
commit | dddcc0e78452f2186c132823a33a174d2596ba33 (patch) | |
tree | 8369d54925d9ea4b60ecf6a53c6a321dffd194f9 /src/ftcrfont.c | |
parent | 061c7e2b5a5a5854b2b85f2ace5b1d9222dd7f11 (diff) | |
download | emacs-dddcc0e78452f2186c132823a33a174d2596ba33.tar.gz |
Add cairo drawing.
* configure.ac (with-cairo): New option.
(USE_CAIRO): Default to yes for Gtk+ 3. Add code to test for cairo,
set CAIRO_CFLAGS, CAIRO_LIBS. Add ftcrfonto to FONT_OBJ if cairo.
Output "Does Emacs use cairo?".
* lisp/version.el (emacs-version): Add cairo version.
* src/Makefile.in (CAIRO_CFLAGS, CAIRO_LIBS): New variables.
(FONT_OBJ): Add comment about ftcrfont.
(ALL_CFLAGS): Add CAIRO_CFLAGS.
(LIBES): Add CAIRO_LIBS.
* src/dispextern.h (struct image): Add cr_data for cairo.
(x_cr_init_fringe): Declare.
* src/font.c (syms_of_font): Call syms_of_ftcrfont for cairo.
* src/font.h (ftcrfont_driver, syms_of_ftcrfont): Declare
* src/fringe.c (x_cr_init_fringe): New function name that shares code
with w32_init_fringe.
* src/ftcrfont.c: New font driver for cairo, based on the ftfont driver.
* src/ftfont.c (ftfont_info_size); New global variable.
(ftfont_open2): New extern function almost the same as old ftfont_open,
but takes the font_object as argument.
(ftfont_open): Build font object and call ftfont_open2.
* src/ftfont.h (ftfont_open2, ftfont_info_size): Declare.
* src/gtkutil.c (xg_clear_under_internal_border)
(xg_update_scrollbar_pos, xg_update_horizontal_scrollbar_pos): Only
queue_draw if not cairo. Change args to x_clear_area.
(xg_get_font): Use Qftcr when using cairo, Qxft otherwise.
(xg_page_setup_dialog, xg_get_page_setup, draw_page)
(xg_print_frames_dialog): New functions for printing.
* src/gtkutil.h (xg_page_setup_dialog, xg_get_page_setup)
(xg_print_frames_dialog): Declare.
* src/image.c: Add defined (USE_CAIRO) for PNG.
Add !defined USE_CAIRO for W32 PNG code.
(x_clear_image): If cairo, destroy the surface in cr_data.
(png_load): Add new cairo compatible implementation.
(lookup_image_type): Add defined (USE_CAIRO) for define png_type.
* src/xfns.c: New section Printing.
(x-export-frames, x-page-setup-dialog, x-get-page-setup)
(x-print-frames-dialog): New printing functions.
(Fx_create_frame, x_create_tip_frame): Register ftcrfont if
cairo.
(syms_of_xfns): Defsym Qorientation, Qtop_margin, Qbottom_margin,
Qportrait, Qlandscape, Qreverse_portrait, Qreverse_landscape).
(syms_of_xfns): Provide cairo and defvar cairo-version-string.
defsubr Sx_page_setup_dialog, Sx_get_page_setup, Sx_print_frames_dialog.
* src/xterm.c (x_clear_area1, x_prepare_for_xlibdraw)
(x_set_clip_rectangles, x_reset_clip_rectangles, x_fill_rectangle)
(x_draw_rectangle, x_fill_trapezoid_for_relief, x_clear_window)
(x_gc_get_ext_data, x_extension_initialize, x_cr_accumulate_data):
Declare.
(FRAME_CR_CONTEXT, FRAME_CR_SURFACE): New macros.
(max_fringe_bmp, fringe_bmp): New variables.
(x_gc_get_ext_data, x_extension_initialize)
(x_cr_destroy_surface, x_begin_cr_clip, x_end_cr_clip)
(x_set_cr_source_with_gc_foreground)
(x_set_cr_source_with_gc_background, x_cr_define_fringe_bitmap)
(x_cr_destroy_fringe_bitmap, x_cr_draw_image, x_cr_draw_frame)
(x_cr_accumulate_data, x_cr_destroy, x_cr_export_frames)
(x_prepare_for_xlibdraw, x_set_clip_rectangles)
(x_reset_clip_rectangles, x_fill_rectangle, x_draw_rectangle)
(x_clear_window, x_fill_trapezoid_for_relief): New functions.
(x_update_begin): Create cairo surface if needed.
(x_draw_vertical_window_border): Call x_fill_rectangle for cairo.
(x_update_end): Paint cairo drawing surface to xlib surface.
(x_clear_under_internal_border, x_after_update_window_line): Adjust
arguments to x_clear_area.
(x_draw_fringe_bitmap): Call x_fill_rectangle. Get GC values and
call x_cr_draw_image for cairo. Call x_reset_clip_rectangles instead
of XSetClipMask.
(x_set_glyph_string_clipping)
(x_set_glyph_string_clipping_exactly): Use x_set_clip_rectangles
instead of XSetClipRectangles.
(x_clear_glyph_string_rect, x_draw_glyph_string_background): Use
x_fill_rectangle instead of XFillRectangle.
(x_draw_glyph_string_foreground)
(x_draw_composite_glyph_string_foreground)
(x_draw_glyphless_glyph_string_foreground): Use x_draw_rectangle instead
of XDrawRectangle.
(x_draw_relief_rect): Add code for USE_CAIRO.
Call x_reset_clip_rectangles instead of XSetClipMask.
(x_draw_box_rect): x_set_clip_rectangles instead of XSetClipRectangles,
x_fill_rectangle instead of XFillRectangle, x_reset_clip_rectangles
instead of XSetClipMask.
(x_draw_image_foreground, x_draw_image_foreground_1):
x_draw_rectangle instead of XDrawRectangle.
(x_draw_glyph_string_bg_rect): x_fill_rectangle instead of
XFillRectangle.
(x_draw_image_glyph_string): If img has cr_data, use it as
a cairo surface.
(x_draw_stretch_glyph_string): x_set_clip_rectangles instead of
XSetClipRectangles, x_fill_rectangle instead of XFillRectangle.
(x_draw_glyph_string): x_fill_rectangle instead of XFillRectangle.,
x_reset_clip_rectangles instead of XSetClipMask.
(x_shift_glyphs_for_insert): Call x_prepare_for_xlibdraw.
(x_clear_area1): New function that calls XClearArea.
(x_clear_area): Takes frame as parameter, calls x_clear_area1 for
non-cairo.
(x_clear_frame): x_clear_window instead of XClearWindow.
(x_scroll_run): Set frame garbaged if cairo.
(XTmouse_position): Initialize *part to 0.
(x_scroll_bar_create): Adjust arguments to x_clear_area.
(x_scroll_bar_set_handle): x_clear_area1 instead of x_clear_area,
x_fill_rectangle instead of XFillRectangle.
(XTset_vertical_scroll_bar, XTset_horizontal_scroll_bar): Adjust
arguments to x_clear_area.
(x_scroll_bar_expose): x_draw_rectangle instead of XDrawRectangle.
(handle_one_xevent): Adjust arguments to x_clear_area.
Destroy cairo surface for frame if ConfigureNotify.
(x_clip_to_row): x_set_clip_rectangles instead of XSetClipRectangles.
(x_draw_hollow_cursor): x_draw_rectangle instead of XDrawRectangle,
x_reset_clip_rectangles instead of XSetClipMask.
(x_draw_bar_cursor): x_fill_rectangle instead of XFillRectangle,
x_reset_clip_rectangles instead of XSetClipMask.
(x_clear_frame_area): Adjust arguments to x_clear_area.
(x_free_frame_resources): Call x_prepare_for_xlibdraw.
(x_term_init): Call x_extension_initialize if cairo.
(x_redisplay_interface): Add x_cr_define_fringe_bitmap,
x_cr_destroy_fringe_bitmap for cairo.
(x_initialize): Call x_cr_init_fringe for cairo.
* src/xterm.h: Add include of cairo header files.
(x_bitmap_record): Add img if cairo.
(x_gc_ext_data): New struct for cairo.
(x_display_info): Add ext_codes for cairo.
(x_output): Add cr_context and cr_surface for cairo.
(x_clear_area): Change arguments from Display*/Window to frame pointer.
(x_query_color, x_begin_cr_clip, x_end_cr_clip)
(x_set_cr_source_with_gc_foreground, x_set_cr_source_with_gc_background)
(x_cr_draw_frame, x_cr_export_frames): Declare.
Diffstat (limited to 'src/ftcrfont.c')
-rw-r--r-- | src/ftcrfont.c | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/src/ftcrfont.c b/src/ftcrfont.c new file mode 100644 index 00000000000..d60c1202b9d --- /dev/null +++ b/src/ftcrfont.c @@ -0,0 +1,314 @@ +/* ftcrfont.c -- FreeType font driver on cairo. + Copyright (C) 2015 Free Software Foundation, Inc. + +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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>. */ + + +#include <config.h> +#include <stdio.h> +#include <cairo-ft.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" +#include "ftfont.h" + +/* FTCR font driver. */ + +/* The actual structure for ftcr font that can be casted to struct + font. */ + +struct ftcrfont_info +{ + struct font font; + /* The following six members must be here in this order to be + compatible with struct ftfont_info (in ftfont.c). */ +#ifdef HAVE_LIBOTF + bool maybe_otf; /* Flag to tell if this may be OTF or not. */ + OTF *otf; +#endif /* HAVE_LIBOTF */ + FT_Size ft_size; + int index; + FT_Matrix matrix; + + cairo_font_face_t *cr_font_face; + /* To prevent cairo from cluttering the activated FT_Size maintained + in ftfont.c, we activate this special FT_Size before drawing. */ + FT_Size ft_size_draw; + /* Font metrics cache. */ + struct font_metrics **metrics; + short metrics_nrows; +}; + +#define METRICS_NCOLS_PER_ROW (128) + +enum metrics_status + { + METRICS_INVALID = -1, /* metrics entry is invalid */ + }; + +#define METRICS_STATUS(metrics) ((metrics)->ascent + (metrics)->descent) +#define METRICS_SET_STATUS(metrics, status) \ + ((metrics)->ascent = 0, (metrics)->descent = (status)) + +/* Prototypes for helper function. */ +static int ftcrfont_glyph_extents (struct font *, unsigned, + struct font_metrics *); + +/* Prototypes for font-driver methods. */ +static Lisp_Object ftcrfont_list (struct frame*, Lisp_Object); +static Lisp_Object ftcrfont_match (struct frame*, Lisp_Object); +static Lisp_Object ftcrfont_open (struct frame*, Lisp_Object, int); +static void ftcrfont_close (struct font *); +static void ftcrfont_text_extents (struct font *, unsigned *, int, + struct font_metrics *); +static int ftcrfont_draw (struct glyph_string *, int, int, int, int, bool); + +struct font_driver ftcrfont_driver; + +static int +ftcrfont_glyph_extents (struct font *font, + unsigned glyph, + struct font_metrics *metrics) +{ + struct ftcrfont_info *ftcrfont_info = (struct ftcrfont_info *) font; + int row, col; + struct font_metrics *cache; + + row = glyph / METRICS_NCOLS_PER_ROW; + col = glyph % METRICS_NCOLS_PER_ROW; + if (row >= ftcrfont_info->metrics_nrows) + { + ftcrfont_info->metrics = + xrealloc (ftcrfont_info->metrics, + sizeof (struct font_metrics *) * (row + 1)); + bzero (ftcrfont_info->metrics + ftcrfont_info->metrics_nrows, + (sizeof (struct font_metrics *) + * (row + 1 - ftcrfont_info->metrics_nrows))); + ftcrfont_info->metrics_nrows = row + 1; + } + if (ftcrfont_info->metrics[row] == NULL) + { + struct font_metrics *new; + int i; + + new = xmalloc (sizeof (struct font_metrics) * METRICS_NCOLS_PER_ROW); + for (i = 0; i < METRICS_NCOLS_PER_ROW; i++) + METRICS_SET_STATUS (new + i, METRICS_INVALID); + ftcrfont_info->metrics[row] = new; + } + cache = ftcrfont_info->metrics[row] + col; + + if (METRICS_STATUS (cache) == METRICS_INVALID) + ftfont_driver.text_extents (font, &glyph, 1, cache); + + if (metrics) + *metrics = *cache; + + return cache->width; +} + +static Lisp_Object +ftcrfont_list (struct frame *f, Lisp_Object spec) +{ + Lisp_Object list = ftfont_driver.list (f, spec), tail; + + for (tail = list; CONSP (tail); tail = XCDR (tail)) + ASET (XCAR (tail), FONT_TYPE_INDEX, Qftcr); + return list; +} + +static Lisp_Object +ftcrfont_match (struct frame *f, Lisp_Object spec) +{ + Lisp_Object entity = ftfont_driver.match (f, spec); + + if (VECTORP (entity)) + ASET (entity, FONT_TYPE_INDEX, Qftcr); + return entity; +} + +extern FT_Face ftfont_get_ft_face (Lisp_Object); + +static Lisp_Object +ftcrfont_open (struct frame *f, Lisp_Object entity, int pixel_size) +{ + Lisp_Object font_object; + struct font *font; + struct ftcrfont_info *ftcrfont_info; + FT_Face ft_face; + FT_UInt size; + + block_input (); + size = XINT (AREF (entity, FONT_SIZE_INDEX)); + if (size == 0) + size = pixel_size; + font_object = font_build_object (VECSIZE (struct ftcrfont_info), + Qftcr, entity, size); + font_object = ftfont_open2 (f, entity, pixel_size, font_object); + if (NILP (font_object)) return Qnil; + + font = XFONT_OBJECT (font_object); + font->driver = &ftcrfont_driver; + ftcrfont_info = (struct ftcrfont_info *) font; + ft_face = ftcrfont_info->ft_size->face; + FT_New_Size (ft_face, &ftcrfont_info->ft_size_draw); + FT_Activate_Size (ftcrfont_info->ft_size_draw); + FT_Set_Pixel_Sizes (ft_face, 0, font->pixel_size); + ftcrfont_info->cr_font_face = + cairo_ft_font_face_create_for_ft_face (ft_face, 0); + ftcrfont_info->metrics = NULL; + ftcrfont_info->metrics_nrows = 0; + unblock_input (); + + return font_object; +} + +static void +ftcrfont_close (struct font *font) +{ + struct ftcrfont_info *ftcrfont_info = (struct ftcrfont_info *) font; + int i; + + block_input (); + for (i = 0; i < ftcrfont_info->metrics_nrows; i++) + if (ftcrfont_info->metrics[i]) + xfree (ftcrfont_info->metrics[i]); + if (ftcrfont_info->metrics) + xfree (ftcrfont_info->metrics); + FT_Done_Size (ftcrfont_info->ft_size_draw); + cairo_font_face_destroy (ftcrfont_info->cr_font_face); + unblock_input (); + + ftfont_driver.close (font); +} + +static void +ftcrfont_text_extents (struct font *font, + unsigned *code, + int nglyphs, + struct font_metrics *metrics) +{ + int width, i; + + block_input (); + width = ftcrfont_glyph_extents (font, code[0], metrics); + for (i = 1; i < nglyphs; i++) + { + struct font_metrics m; + int w = ftcrfont_glyph_extents (font, code[i], metrics ? &m : NULL); + + if (metrics) + { + if (width + m.lbearing < metrics->lbearing) + metrics->lbearing = width + m.lbearing; + if (width + m.rbearing > metrics->rbearing) + metrics->rbearing = width + m.rbearing; + if (m.ascent > metrics->ascent) + metrics->ascent = m.ascent; + if (m.descent > metrics->descent) + metrics->descent = m.descent; + } + width += w; + } + unblock_input (); + + if (metrics) + metrics->width = width; +} + +static int +ftcrfont_draw (struct glyph_string *s, + int from, int to, int x, int y, bool with_background) +{ + struct frame *f = s->f; + struct face *face = s->face; + struct ftcrfont_info *ftcrfont_info = (struct ftcrfont_info *) s->font; + cairo_t *cr; + cairo_glyph_t *glyphs; + cairo_surface_t *surface; + int len = to - from; + int i; + + block_input (); + + cr = x_begin_cr_clip (f, s->gc); + + if (with_background) + { + x_set_cr_source_with_gc_background (f, s->gc); + cairo_rectangle (cr, x, y - FONT_BASE (face->font), + s->width, FONT_HEIGHT (face->font)); + cairo_fill (cr); + } + + glyphs = alloca (sizeof (cairo_glyph_t) * len); + for (i = 0; i < len; i++) + { + unsigned code = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8) + | XCHAR2B_BYTE2 (s->char2b + from + i)); + + glyphs[i].index = code; + glyphs[i].x = x; + glyphs[i].y = y; + x += (s->padding_p ? 1 : ftcrfont_glyph_extents (s->font, code, NULL)); + } + + x_set_cr_source_with_gc_foreground (f, s->gc); + cairo_set_font_face (cr, ftcrfont_info->cr_font_face); + cairo_set_font_size (cr, s->font->pixel_size); + /* cairo_set_font_matrix */ + /* cairo_set_font_options */ + + FT_Activate_Size (ftcrfont_info->ft_size_draw); + cairo_show_glyphs (cr, glyphs, len); + surface = cairo_get_target (cr); + if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_XLIB) + cairo_surface_flush (surface); + + x_end_cr_clip (f); + + unblock_input (); + + return len; +} + + + +void +syms_of_ftcrfont (void) +{ + if (ftfont_info_size != offsetof (struct ftcrfont_info, cr_font_face)) + abort (); + + DEFSYM (Qftcr, "ftcr"); + + ftcrfont_driver = ftfont_driver; + ftcrfont_driver.type = Qftcr; + ftcrfont_driver.list = ftcrfont_list; + ftcrfont_driver.match = ftcrfont_match; + ftcrfont_driver.open = ftcrfont_open; + ftcrfont_driver.close = ftcrfont_close; + ftcrfont_driver.text_extents = ftcrfont_text_extents; + ftcrfont_driver.draw = ftcrfont_draw; + register_font_driver (&ftcrfont_driver, NULL); +} |