diff options
-rw-r--r-- | ChangeLog | 19 | ||||
-rw-r--r-- | configure.in | 68 | ||||
-rw-r--r-- | src/Makefile.am | 44 | ||||
-rw-r--r-- | src/vte.c | 23 | ||||
-rw-r--r-- | src/vteapp.c | 10 | ||||
-rw-r--r-- | src/vtedraw.c | 44 | ||||
-rw-r--r-- | src/vtedraw.h | 12 | ||||
-rw-r--r-- | src/vtefc.c | 13 | ||||
-rw-r--r-- | src/vteft2.c | 338 | ||||
-rw-r--r-- | src/vteft2.h | 35 | ||||
-rw-r--r-- | src/vtegl.c | 414 | ||||
-rw-r--r-- | src/vtegl.h | 35 | ||||
-rw-r--r-- | src/vteglyph.c | 728 | ||||
-rw-r--r-- | src/vteglyph.h | 86 | ||||
-rw-r--r-- | src/vtepango.c | 42 | ||||
-rw-r--r-- | src/vtepangox.c | 466 | ||||
-rw-r--r-- | src/vtepangox.h | 35 | ||||
-rw-r--r-- | src/vtergb.c | 260 | ||||
-rw-r--r-- | src/vtergb.h | 52 | ||||
-rw-r--r-- | src/vteskel.c | 35 | ||||
-rw-r--r-- | src/vtexft.c | 39 | ||||
-rw-r--r-- | vte.pc.in | 2 | ||||
-rw-r--r-- | vte.spec | 6 |
23 files changed, 2681 insertions, 125 deletions
@@ -1,3 +1,22 @@ +2003-04-09 nalin + * configure.in: add specific checks for PangoX and glX. + * src/vteft2.c, src/vteft2.h: add drawing method using freetype and + GdkRGB. + * src/vteglyph.c, src/vteglyph.h: add. + * src/vtepangox.c, src/vtepangox.h: add drawing method using PangoX. + * src/vtergb.c, src/vtergb.h: add. + * src/vtegl.c, src/vtegl.h: add placeholder drawing method using + freetype and glX. + * src/Makefile.am: add newly-added source files to libvte.la target. + * src/vtedraw.c, src/vtedraw.h: add get_visual and get_colormap + methods so that drawing methods can override the default visual and + colormap. Rename get_text_base() to get_text_ascent(), which is more + correct. Remove scroll(), which would just wrap gdk_window_scroll(). + * src/vte.c: fix logic for choosing alternate render methods when + VTE_USE_XFT is "0". + * src/vteapp.c: add -- option to stop parsing options with getopt. + * src/vtefc.c: fix incorrect DPI read due to type mismatch (#109513). + 2003-03-31 Laurent Dhima <laurenti@alblinux.net> * configure.in: Added "sq" to ALL_LINGUAS. diff --git a/configure.in b/configure.in index 42cda0a..52f9937 100644 --- a/configure.in +++ b/configure.in @@ -17,23 +17,64 @@ AM_GLIB_GNU_GETTEXT # X_PRE_LIBS and X_EXTRA_LIBS to add even more libraries, and add -lX11 to # the list of libraries for grins. AC_PATH_XTRA -HAVE_XFT=no -X_LIBS="$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS" -PKG_CHECK_MODULES(GOBJECT,[glib-2.0 gobject-2.0]) +X_LIBS= +if test $with_x = yes ; then + X_LIBS="$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS" +fi + savelibs="$LIBS" LIBS="$X_LIBS $LIBS" +PKG_CHECK_MODULES(GLIB,glib-2.0) +PKG_CHECK_MODULES(GOBJECT,[glib-2.0 gobject-2.0]) +PKG_CHECK_MODULES(GTK,[glib-2.0 gobject-2.0 gtk+-2.0]) + # Require GTK+ 2.0 and fontconfig. -wantedmodules="glib-2.0 gobject-2.0 gdk-pixbuf-2.0 gtk+-2.0 fontconfig" -# Use Xft2 if Pango has Xft2 support. -if pkg-config --exists pangoxft '>=' 1.1.0 ; then - AC_DEFINE(HAVE_XFT2,1,[Whether we have Xft2]) - wantedmodules="$wantedmodules xft" -else - AC_MSG_WARN([Xft2 not detected]) +wantedmodules="glib-2.0 gobject-2.0 gtk+-2.0 fontconfig" + +# Use Xft2 if Pango has Xft2 support and it isn't disabled. +AC_ARG_WITH(xft2,[ --with-xft2 enable drawing using Xft2],with_xft2=$withval,with_xft2=yes) +if test $with_xft2 = yes ; then + if pkg-config --exists pangoxft '>=' 1.1.0 ; then + AC_DEFINE(HAVE_XFT2,1,[Whether we have Xft2]) + wantedmodules="$wantedmodules pangoxft >= 1.1.0 xft >= 2.0" + else + AC_MSG_WARN([Xft2 not detected]) + fi +fi + +# Use PangoX if we have it and it isn't disabled. +AC_ARG_WITH(pangox,[ --with-pangox enable drawing using PangoX],with_pangox=$withval,with_pangox=yes) +if test $with_pangox = yes ; then + if pkg-config --exists pangox ; then + AC_DEFINE(HAVE_PANGOX,1,[Whether we have PangoX]) + wantedmodules="$wantedmodules pangox" + else + AC_MSG_WARN([PangoX not detected]) + fi fi + +# Use glX if we have it and it isn't disabled. +AC_ARG_WITH(glX,[ --with-glX enable drawing using glX],with_glx=$withval,with_glx=yes) +if test $with_glx = yes ; then + have_gl=0 + have_libgl=0 + AC_CHECK_HEADERS(GL/glx.h) + if test $ac_cv_header_GL_glx_h = yes ; then + AC_CHECK_FUNC(glXQueryExtension,[have_gl=1],AC_CHECK_LIB(GL,glXQueryExtension,[have_gl=1;have_libgl=1])) + fi + if test $have_gl = 1 ; then + AC_DEFINE(HAVE_GL,1,[Whether we have GL and glX.]) + fi + if test $have_libgl = 1 ; then + LIBS="-lGLU -lGL $LIBS" + fi +fi + # Search for the required modules. PKG_CHECK_MODULES(VTE,[$wantedmodules]) +NEEDEDPACKAGES="$wantedmodules" +AC_SUBST(NEEDEDPACKAGES) # Require Freetype2. We use our local copy of the macro because packages of # freetype's development files don't always include the proper macro. @@ -53,24 +94,28 @@ AC_CHECK_DECLS(FT_RENDER_MODE_MONO,,,[ #include FT_FREETYPE_H #endif ]) + AC_CHECK_DECLS(FT_LOAD_NO_HINTING,,,[ #ifdef HAVE_FT2BUILD_H #include <ft2build.h> #include FT_FREETYPE_H #endif ]) + AC_CHECK_DECLS(FT_RENDER_MODE_LIGHT,,,[ #ifdef HAVE_FT2BUILD_H #include <ft2build.h> #include FT_FREETYPE_H #endif ]) + AC_CHECK_DECLS(FT_RENDER_MODE_NORMAL,,,[ #ifdef HAVE_FT2BUILD_H #include <ft2build.h> #include FT_FREETYPE_H #endif ]) + CFLAGS="$savecflags" CPPFLAGS="$savecppflags" @@ -84,6 +129,7 @@ AC_EGREP_CPP(glibc, #endif ], AC_DEFINE(_GNU_SOURCE,1,[Use all features.])) + AC_DEFINE(G_DISABLE_DEPRECATED,1,[Disable deprecated GLib features.]) AC_DEFINE(GDK_DISABLE_DEPRECATED,1,[Disable deprecated GDK features.]) AC_DEFINE(GDK_PIXBUF_DISABLE_DEPRECATED,1,[Disable deprecated gdk-pixbuf features.]) @@ -110,7 +156,7 @@ fi if test x$have_socketpair = x1 ; then AC_DEFINE(HAVE_SOCKETPAIR,1,[Define if you have the socketpair function.]) fi - +AC_CHECK_FUNC(floor,,AC_CHECK_LIB(m,floor,LIBS=["$LIBS -lm"])) # Look for ncurses or curses or termcap. AC_CHECK_HEADER(ncurses.h,[AC_CHECK_HEADER(term.h,[AC_CHECK_LIB(ncurses,tgetent,[LIBS="-lncurses $LIBS";AC_DEFINE(HAVE_NCURSES,1,[Define if you have ncurses.h and libncurses])])])]) diff --git a/src/Makefile.am b/src/Makefile.am index cc3d060..d9b1f8e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -60,8 +60,18 @@ libvte_la_SOURCES = \ vtedraw.h \ vtefc.c \ vtefc.h \ + vteft2.c \ + vteft2.h \ + vtegl.c \ + vtegl.h \ + vteglyph.c \ + vteglyph.h \ vtepango.c \ vtepango.h \ + vtepangox.c \ + vtepangox.h \ + vtergb.c \ + vtergb.h \ vteskel.c \ vteskel.h \ vtexft.c \ @@ -98,7 +108,7 @@ else REFLECT_ZVT = endif -interpret_CFLAGS = @CFLAGS@ @GOBJECT_CFLAGS@ @VTE_CFLAGS@ -DINTERPRET_MAIN +interpret_CFLAGS = @CFLAGS@ @GTK_CFLAGS@ -DINTERPRET_MAIN interpret_SOURCES = \ buffer.c \ buffer.h \ @@ -119,7 +129,7 @@ interpret_SOURCES = \ interpret.c interpret_LDADD = @LDFLAGS@ @GOBJECT_LIBS@ -iso2022_CFLAGS = @CFLAGS@ @GOBJECT_CFLAGS@ @VTE_CFLAGS@ -DISO2022_MAIN +iso2022_CFLAGS = @CFLAGS@ @GTK_CFLAGS@ -DISO2022_MAIN iso2022_SOURCES = \ debug.c \ debug.h \ @@ -146,22 +156,22 @@ utf8echo_SOURCES = \ utf8echo.c utf8echo_LDADD = @LDFLAGS@ @LIBS@ @GOBJECT_LIBS@ -nativeecho_CFLAGS = @CFLAGS@ @GOBJECT_CFLAGS@ -DNATIVEECHO_MAIN +nativeecho_CFLAGS = @CFLAGS@ @GLIB_CFLAGS@ -DNATIVEECHO_MAIN nativeecho_SOURCES = \ nativeecho.c nativeecho_LDADD = @LDFLAGS@ @LIBS@ -ring_CFLAGS = @CFLAGS@ @GOBJECT_CFLAGS@ -DRING_MAIN +ring_CFLAGS = @CFLAGS@ @GLIB_CFLAGS@ -DRING_MAIN ring_SOURCES = \ debug.c \ debug.h \ ring.c \ ring.h -ring_LDADD = @LDFLAGS@ @LIBS@ @GOBJECT_LIBS@ +ring_LDADD = @LDFLAGS@ @LIBS@ @GLIB_LIBS@ slowcat_SOURCES = \ slowcat.c -slowcat_LDADD = @LDFLAGS@ @LIBS@ @GOBJECT_LIBS@ +slowcat_LDADD = @LDFLAGS@ @LIBS@ @GLIB_LIBS@ table_CFLAGS = @CFLAGS@ @GOBJECT_CFLAGS@ -DTABLE_MAIN table_SOURCES = \ @@ -189,23 +199,23 @@ trie_SOURCES = \ trie.h trie_LDADD = @LDFLAGS@ @LIBS@ @GOBJECT_LIBS@ -termcap_CFLAGS = @CFLAGS@ @GOBJECT_CFLAGS@ -DTERMCAP_MAIN +termcap_CFLAGS = @CFLAGS@ @GLIB_CFLAGS@ -DTERMCAP_MAIN termcap_SOURCES = \ debug.c \ debug.h \ termcap.c \ termcap.h -termcap_LDADD = @LDFLAGS@ @LIBS@ @GOBJECT_LIBS@ +termcap_LDADD = @LDFLAGS@ @LIBS@ @GLIB_LIBS@ -pty_CFLAGS = @CFLAGS@ @GOBJECT_CFLAGS@ -DPTY_MAIN +pty_CFLAGS = @CFLAGS@ @GLIB_CFLAGS@ -DPTY_MAIN pty_SOURCES = \ debug.c \ debug.h \ pty.c \ pty.h -pty_LDADD = @LDFLAGS@ @LIBS@ @GOBJECT_LIBS@ +pty_LDADD = @LDFLAGS@ @LIBS@ @GLIB_LIBS@ -reaper_CFLAGS = @CFLAGS@ @GOBJECT_CFLAGS@ @VTE_CFLAGS@ -DREAPER_MAIN +reaper_CFLAGS = @CFLAGS@ @GTK_CFLAGS@ -DREAPER_MAIN reaper_SOURCES = \ debug.c \ debug.h \ @@ -215,19 +225,19 @@ reaper_SOURCES = \ reaper.h reaper_LDADD = @LDFLAGS@ @LIBS@ @GOBJECT_LIBS@ -buffer_CFLAGS = @CFLAGS@ @GOBJECT_CFLAGS@ -DBUFFER_MAIN +buffer_CFLAGS = @CFLAGS@ @GLIB_CFLAGS@ -DBUFFER_MAIN buffer_SOURCES = buffer.c -buffer_LDADD = @LDFLAGS@ @GOBJECT_LIBS@ +buffer_LDADD = @LDFLAGS@ @GLIB_LIBS@ dumpkeys_SOURCES = dumpkeys.c -dumpkeys_LDADD = @LDFLAGS@ @LIBS@ @GOBJECT_LIBS@ +dumpkeys_LDADD = @LDFLAGS@ @LIBS@ @GLIB_LIBS@ mev_SOURCES = mev.c -mev_LDADD = @LDFLAGS@ @LIBS@ @GOBJECT_LIBS@ +mev_LDADD = @LDFLAGS@ @LIBS@ @GLIB_LIBS@ ssfe_SOURCES = ssfe.c ssfe_LDADD = @LDFLAGS@ @OTHERLIBS@ -xticker_CFLAGS = @CFLAGS@ @GOBJECT_CFLAGS@ +xticker_CFLAGS = @CFLAGS@ @GLIB_CFLAGS@ xticker_SOURCES = xticker.c -xticker_LDADD = @LIBS@ @GOBJECT_LIBS@ +xticker_LDADD = @LIBS@ @GLIB_LIBS@ @@ -10856,9 +10856,9 @@ vte_terminal_open_font(VteTerminal *terminal) vte_terminal_apply_metrics(terminal, _vte_draw_get_text_width(draw), _vte_draw_get_text_height(draw), - _vte_draw_get_text_base(draw), + _vte_draw_get_text_ascent(draw), _vte_draw_get_text_height(draw) - - _vte_draw_get_text_base(draw)); + _vte_draw_get_text_ascent(draw)); break; #ifdef HAVE_XFT2 case VteRenderXft2: @@ -11585,13 +11585,14 @@ vte_terminal_init(VteTerminal *terminal, gpointer *klass) render_max = VteRenderXft1; } } - if ((render_max >= VteRenderXft1) && + if ((render_max == VteRenderXft1) && (getenv("VTE_USE_XFT") != NULL)) { if (atol(getenv("VTE_USE_XFT")) == 0) { render_max = VteRenderPango; } } - if ((render_max >= VteRenderXft1) && + if (((render_max == VteRenderXft2) || + (render_max == VteRenderXft1)) && (getenv("GDK_USE_XFT") != NULL)) { if (atol(getenv("GDK_USE_XFT")) == 0) { render_max = VteRenderPango; @@ -11851,12 +11852,6 @@ static void vte_terminal_unrealize(GtkWidget *widget) { VteTerminal *terminal; - Display *display; - GdkColormap *gcolormap; - Colormap colormap; - GdkVisual *gvisual; - Visual *visual; - int i; #ifdef VTE_DEBUG if (_vte_debug_on(VTE_DEBUG_LIFECYCLE)) { @@ -12277,8 +12272,8 @@ vte_terminal_realize(GtkWidget *widget) attributes.width = widget->allocation.width; attributes.height = widget->allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; - attributes.visual = gtk_widget_get_visual(widget); - attributes.colormap = gtk_widget_get_colormap(widget); + attributes.visual = _vte_draw_get_visual(terminal->pvt->draw); + attributes.colormap = _vte_draw_get_colormap(terminal->pvt->draw); attributes.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK | GDK_VISIBILITY_NOTIFY_MASK | @@ -12291,8 +12286,8 @@ vte_terminal_realize(GtkWidget *widget) attributes.cursor = terminal->pvt->mouse_default_cursor; attributes_mask = GDK_WA_X | GDK_WA_Y | - GDK_WA_VISUAL | - GDK_WA_COLORMAP | + (attributes.visual ? GDK_WA_VISUAL : 0) | + (attributes.colormap ? GDK_WA_COLORMAP : 0) | GDK_WA_CURSOR; widget->window = gdk_window_new(gtk_widget_get_parent_window(widget), &attributes, diff --git a/src/vteapp.c b/src/vteapp.c index 3899c63..481161e 100644 --- a/src/vteapp.c +++ b/src/vteapp.c @@ -434,8 +434,10 @@ main(int argc, char **argv) } argv2[i] = NULL; g_assert(i < (g_list_length(args) + 2)); + /* Parse some command-line options. */ - while ((opt = getopt(argc, argv, "B:CDT2abc:df:ghn:st:w:")) != -1) { + while ((opt = getopt(argc, argv, "B:CDT2abc:df:ghn:st:w:-")) != -1) { + gboolean bail = FALSE; switch (opt) { case 'B': background = optarg; @@ -485,12 +487,18 @@ main(int argc, char **argv) case 'w': working_directory = optarg; break; + case '-': + bail = TRUE; + break; case 'h': default: g_print(usage, argv[0]); exit(1); break; } + if (bail) { + break; + } } gtk_init(&argc, &argv); diff --git a/src/vtedraw.c b/src/vtedraw.c index 44c643d..61887b2 100644 --- a/src/vtedraw.c +++ b/src/vtedraw.c @@ -27,17 +27,27 @@ #include <gtk/gtk.h> #include "debug.h" #include "vtedraw.h" +#include "vteft2.h" +#include "vtegl.h" #include "vtepango.h" +#include "vtepangox.h" #include "vteskel.h" #include "vtexft.h" struct _vte_draw_impl *_vte_draw_impls[] = { &_vte_draw_skel, +#ifdef HAVE_GL + /* &_vte_draw_gl, */ +#endif #ifdef HAVE_XFT2 &_vte_draw_xft, #endif + &_vte_draw_ft2, &_vte_draw_pango, +#ifdef HAVE_PANGOX + &_vte_draw_pango_x, +#endif }; struct _vte_draw * @@ -98,6 +108,22 @@ _vte_draw_free(struct _vte_draw *draw) g_free(draw); } +GdkVisual * +_vte_draw_get_visual(struct _vte_draw *draw) +{ + g_return_val_if_fail(draw->impl != NULL, NULL); + g_return_val_if_fail(draw->impl->get_visual != NULL, NULL); + return draw->impl->get_visual(draw); +} + +GdkColormap * +_vte_draw_get_colormap(struct _vte_draw *draw) +{ + g_return_val_if_fail(draw->impl != NULL, NULL); + g_return_val_if_fail(draw->impl->get_colormap != NULL, NULL); + return draw->impl->get_colormap(draw); +} + void _vte_draw_start(struct _vte_draw *draw) { @@ -169,11 +195,11 @@ _vte_draw_get_text_height(struct _vte_draw *draw) } int -_vte_draw_get_text_base(struct _vte_draw *draw) +_vte_draw_get_text_ascent(struct _vte_draw *draw) { g_return_val_if_fail(draw->impl != NULL, 1); - g_return_val_if_fail(draw->impl->get_text_base != NULL, 1); - return draw->impl->get_text_base(draw); + g_return_val_if_fail(draw->impl->get_text_ascent != NULL, 1); + return draw->impl->get_text_ascent(draw); } void @@ -184,8 +210,7 @@ _vte_draw_text(struct _vte_draw *draw, g_return_if_fail(draw->started == TRUE); g_return_if_fail(draw->impl != NULL); g_return_if_fail(draw->impl->draw_text != NULL); - draw->impl->draw_text(draw, requests, n_requests, - color, alpha); + draw->impl->draw_text(draw, requests, n_requests, color, alpha); } void @@ -210,15 +235,6 @@ _vte_draw_draw_rectangle(struct _vte_draw *draw, draw->impl->draw_rectangle(draw, x, y, width, height, color, alpha); } -gboolean -_vte_draw_scroll(struct _vte_draw *draw, gint dx, gint dy) -{ - g_return_val_if_fail(draw->started == TRUE, FALSE); - g_return_val_if_fail(draw->impl != NULL, FALSE); - g_return_val_if_fail(draw->impl->scroll != NULL, FALSE); - return draw->impl->scroll(draw, dx, dy); -} - void _vte_draw_set_scroll(struct _vte_draw *draw, gint x, gint y) { diff --git a/src/vtedraw.h b/src/vtedraw.h index 27fa47b..25311cf 100644 --- a/src/vtedraw.h +++ b/src/vtedraw.h @@ -47,6 +47,8 @@ struct _vte_draw_impl { gboolean (*check)(struct _vte_draw *draw, GtkWidget *widget); void (*create)(struct _vte_draw *draw, GtkWidget *widget); void (*destroy)(struct _vte_draw *draw); + GdkVisual* (*get_visual)(struct _vte_draw *draw); + GdkColormap* (*get_colormap)(struct _vte_draw *draw); void (*start)(struct _vte_draw *draw); void (*end)(struct _vte_draw *draw); void (*set_background_color)(struct _vte_draw *, GdkColor *); @@ -55,7 +57,7 @@ struct _vte_draw_impl { void (*set_text_font)(struct _vte_draw *, const PangoFontDescription *); int (*get_text_width)(struct _vte_draw *); int (*get_text_height)(struct _vte_draw *); - int (*get_text_base)(struct _vte_draw *); + int (*get_text_ascent)(struct _vte_draw *); void (*draw_text)(struct _vte_draw *, struct _vte_draw_text_request *, gsize, GdkColor *, guchar); @@ -65,20 +67,21 @@ struct _vte_draw_impl { void (*fill_rectangle)(struct _vte_draw *, gint, gint, gint, gint, GdkColor *, guchar); - gboolean (*scroll)(struct _vte_draw *, gint, gint); void (*set_scroll)(struct _vte_draw *, gint, gint); }; struct _vte_draw { GtkWidget *widget; gboolean started; - gint width, height, base; + gint width, height, ascent; struct _vte_draw_impl *impl; gpointer impl_data; }; struct _vte_draw *_vte_draw_new(GtkWidget *widget); void _vte_draw_free(struct _vte_draw *draw); +GdkVisual *_vte_draw_get_visual(struct _vte_draw *draw); +GdkColormap *_vte_draw_get_colormap(struct _vte_draw *draw); void _vte_draw_start(struct _vte_draw *draw); void _vte_draw_end(struct _vte_draw *draw); @@ -91,7 +94,7 @@ void _vte_draw_set_text_font(struct _vte_draw *draw, const PangoFontDescription *fontdesc); int _vte_draw_get_text_width(struct _vte_draw *draw); int _vte_draw_get_text_height(struct _vte_draw *draw); -int _vte_draw_get_text_base(struct _vte_draw *draw); +int _vte_draw_get_text_ascent(struct _vte_draw *draw); void _vte_draw_text(struct _vte_draw *draw, struct _vte_draw_text_request *requests, gsize n_requests, GdkColor *color, guchar alpha); @@ -102,7 +105,6 @@ void _vte_draw_fill_rectangle(struct _vte_draw *draw, void _vte_draw_draw_rectangle(struct _vte_draw *draw, gint x, gint y, gint width, gint height, GdkColor *color, guchar alpha); -gboolean _vte_draw_scroll(struct _vte_draw *draw, gint dx, gint dy); void _vte_draw_set_scroll(struct _vte_draw *draw, gint x, gint y); G_END_DECLS diff --git a/src/vtefc.c b/src/vtefc.c index 3d1d40d..6b0be99 100644 --- a/src/vtefc.c +++ b/src/vtefc.c @@ -17,6 +17,7 @@ */ #include "../config.h" +#include <stdio.h> #include <string.h> #include <gtk/gtk.h> #include <pango/pango.h> @@ -82,8 +83,8 @@ _vte_fc_transcribe_from_pango_font_description(FcPattern *pattern, /* Set the font size for the pattern, or use a sensible default. */ if (pango_mask & PANGO_FONT_MASK_SIZE) { - size = (double) pango_font_description_get_size(font_desc); - size /= (double) PANGO_SCALE; + size = pango_font_description_get_size(font_desc); + size /= PANGO_SCALE; } FcPatternAddDouble(pattern, FC_SIZE, size); @@ -114,14 +115,16 @@ static void _vte_fc_defaults_from_gtk(FcPattern *pattern) { GtkSettings *settings; + GdkScreen *screen; GObjectClass *klass; - int i, antialias = -1, hinting = -1; - double d, dpi = -1; + int i, antialias = -1, hinting = -1, dpi = -1; + double d; char *rgba = NULL, *hintstyle = NULL; FcResult result; /* Add any defaults configured for GTK+. */ - settings = gtk_settings_get_for_screen(gdk_screen_get_default()); + screen = gdk_screen_get_default(); + settings = gtk_settings_get_for_screen(screen); if (settings == NULL) { return; } diff --git a/src/vteft2.c b/src/vteft2.c new file mode 100644 index 0000000..b598527 --- /dev/null +++ b/src/vteft2.c @@ -0,0 +1,338 @@ +/* + * Copyright (C) 2003 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "../config.h" + +#include <sys/param.h> +#include <string.h> +#include <gtk/gtk.h> +#include <glib.h> +#include <fontconfig/fontconfig.h> +#include "debug.h" +#include "vtedraw.h" +#include "vtefc.h" +#include "vteglyph.h" +#include "vtergb.h" + +#define FONT_INDEX_FUDGE 10 +#define CHAR_WIDTH_FUDGE 10 + +struct _vte_ft2_data +{ + struct _vte_glyph_cache *cache; + struct _vte_rgb_buffer *rgb; + GdkColor color; + GdkPixbuf *pixbuf; + gint scrollx, scrolly; + gint left, right, top, bottom; +}; + +static gboolean +_vte_ft2_check(struct _vte_draw *draw, GtkWidget *widget) +{ + /* We can draw onto any widget. */ + return TRUE; +} + +static void +_vte_ft2_create(struct _vte_draw *draw, GtkWidget *widget) +{ + struct _vte_ft2_data *data; + data = (struct _vte_ft2_data*) g_malloc0(sizeof(struct _vte_ft2_data)); + draw->impl_data = data; + data->rgb = NULL; + memset(&data->color, 0, sizeof(data->color)); + data->pixbuf = NULL; + data->scrollx = data->scrolly = 0; +} + +static void +_vte_ft2_destroy(struct _vte_draw *draw) +{ + struct _vte_ft2_data *data; + data = (struct _vte_ft2_data*) draw->impl_data; + if (data->cache != NULL) { + _vte_glyph_cache_free(data->cache); + data->cache = NULL; + } + if (data->rgb != NULL) { + _vte_rgb_buffer_free(data->rgb); + } + memset(&data->color, 0, sizeof(data->color)); + if (GDK_IS_PIXBUF(data->pixbuf)) { + g_object_unref(G_OBJECT(data->pixbuf)); + data->pixbuf = NULL; + } + data->scrollx = data->scrolly = 0; + g_free(data); +} + +static GdkVisual * +_vte_ft2_get_visual(struct _vte_draw *draw) +{ + return gtk_widget_get_visual(draw->widget); +} + +static GdkColormap * +_vte_ft2_get_colormap(struct _vte_draw *draw) +{ + return gtk_widget_get_colormap(draw->widget); +} + +static void +_vte_ft2_start(struct _vte_draw *draw) +{ + struct _vte_ft2_data *data; + guint width, height; + data = (struct _vte_ft2_data*) draw->impl_data; + + gdk_window_get_geometry(draw->widget->window, + NULL, NULL, &width, &height, NULL); + if (data->rgb == NULL) { + data->rgb = _vte_rgb_buffer_new(width, height); + } else { + _vte_rgb_buffer_resize(data->rgb, width, height); + } + data->left = data->right = data->top = data->bottom = -1; +} + +static void +_vte_ft2_end(struct _vte_draw *draw) +{ + struct _vte_ft2_data *data; + guint width, height; + GtkWidget *widget; + GtkStateType state; + data = (struct _vte_ft2_data*) draw->impl_data; + widget = draw->widget; + gdk_window_get_geometry(widget->window, + NULL, NULL, &width, &height, NULL); + gtk_widget_ensure_style(widget); + state = GTK_WIDGET_STATE(widget); + if ((data->left == -1) && + (data->right == -1) && + (data->top == -1) && + (data->bottom == -1)) { + _vte_rgb_draw_on_drawable(widget->window, + widget->style->fg_gc[state], + 0, 0, + width, height, + data->rgb, + 0, 0); + } else { + _vte_rgb_draw_on_drawable(widget->window, + widget->style->fg_gc[state], + data->left, data->top, + data->right - data->left + 1, + data->bottom - data->top + 1, + data->rgb, + data->left, data->top); + } +} + +static void +_vte_ft2_set_background_color(struct _vte_draw *draw, GdkColor *color) +{ + struct _vte_ft2_data *data; + data = (struct _vte_ft2_data*) draw->impl_data; + data->color = *color; +} + +static void +_vte_ft2_set_background_pixbuf(struct _vte_draw *draw, GdkPixbuf *pixbuf) +{ + struct _vte_ft2_data *data; + + data = (struct _vte_ft2_data*) draw->impl_data; + + if (GDK_IS_PIXBUF(data->pixbuf)) { + g_object_unref(G_OBJECT(data->pixbuf)); + } + data->pixbuf = pixbuf; + if (GDK_IS_PIXBUF(data->pixbuf)) { + g_object_ref(G_OBJECT(data->pixbuf)); + } +} + +static void +update_bbox(struct _vte_ft2_data *data, gint x, gint y, gint width, gint height) +{ + data->left = (data->left == -1) ? + x : MIN(data->left, x); + data->right = (data->right == -1) ? + x + width - 1 : MAX(data->right, x + width - 1); + data->top = (data->top == -1) ? + y : MIN(data->top, y); + data->bottom = (data->bottom == -1) ? + y + height - 1 : MAX(data->bottom, y + height - 1); +} + +static void +_vte_ft2_clear(struct _vte_draw *draw, + gint x, gint y, gint width, gint height) +{ + struct _vte_ft2_data *data; + data = (struct _vte_ft2_data*) draw->impl_data; + + if (GDK_IS_PIXBUF(data->pixbuf)) { + /* Tile a pixbuf in. */ + _vte_rgb_draw_pixbuf(data->rgb, x, y, width, height, + data->pixbuf, + data->scrollx + x, data->scrolly + y); + } else { + /* The simple case is a solid color. */ + _vte_rgb_draw_color(data->rgb, x, y, width, height, + &data->color); + } + update_bbox(data, x, y, width, height); +} + +static void +_vte_ft2_set_text_font(struct _vte_draw *draw, + const PangoFontDescription *fontdesc) +{ + struct _vte_ft2_data *data; + + data = (struct _vte_ft2_data*) draw->impl_data; + + if (data->cache != NULL) { + _vte_glyph_cache_free(data->cache); + data->cache = NULL; + } + data->cache = _vte_glyph_cache_new(); + _vte_glyph_cache_set_description(NULL, data->cache, fontdesc); +} + +static int +_vte_ft2_get_text_width(struct _vte_draw *draw) +{ + struct _vte_ft2_data *data; + data = (struct _vte_ft2_data*) draw->impl_data; + return data->cache->width; +} + +static int +_vte_ft2_get_text_height(struct _vte_draw *draw) +{ + struct _vte_ft2_data *data; + data = (struct _vte_ft2_data*) draw->impl_data; + return data->cache->height; +} + +static int +_vte_ft2_get_text_ascent(struct _vte_draw *draw) +{ + struct _vte_ft2_data *data; + data = (struct _vte_ft2_data*) draw->impl_data; + return data->cache->ascent; +} + +static void +_vte_ft2_draw_text(struct _vte_draw *draw, + struct _vte_draw_text_request *requests, gsize n_requests, + GdkColor *color, guchar alpha) +{ + struct _vte_ft2_data *data; + struct _vte_glyph_cache *cache; + int i; + + data = (struct _vte_ft2_data*) draw->impl_data; + cache = data->cache; + + for (i = 0; i < n_requests; i++) { + _vte_glyph_draw(data->cache, requests[i].c, color, + requests[i].x, requests[i].y, + requests[i].columns, + 0, + data->rgb); + update_bbox(data, requests[i].x, requests[i].y, + cache->width * requests[i].columns, cache->height); + } +} + +static void +_vte_ft2_draw_rectangle(struct _vte_draw *draw, + gint x, gint y, gint width, gint height, + GdkColor *color, guchar alpha) +{ + struct _vte_ft2_data *data; + + data = (struct _vte_ft2_data*) draw->impl_data; + + _vte_rgb_draw_color(data->rgb, + x, y, + width, 1, + color); + _vte_rgb_draw_color(data->rgb, + x, y, + 1, height, + color); + _vte_rgb_draw_color(data->rgb, + x, y + height - 1, + width, 1, + color); + _vte_rgb_draw_color(data->rgb, + x + width - 1, y, + 1, height, + color); + update_bbox(data, x, y, width, height); +} + +static void +_vte_ft2_fill_rectangle(struct _vte_draw *draw, + gint x, gint y, gint width, gint height, + GdkColor *color, guchar alpha) +{ + struct _vte_ft2_data *data; + + data = (struct _vte_ft2_data*) draw->impl_data; + + _vte_rgb_draw_color(data->rgb, x, y, width, height, color); + update_bbox(data, x, y, width, height); +} + +static void +_vte_ft2_set_scroll(struct _vte_draw *draw, gint x, gint y) +{ + struct _vte_ft2_data *data; + data = (struct _vte_ft2_data*) draw->impl_data; + data->scrollx = x; + data->scrolly = y; +} + +struct _vte_draw_impl _vte_draw_ft2 = { + "VteFT2", "VTE_USE_FT2", + _vte_ft2_check, + _vte_ft2_create, + _vte_ft2_destroy, + _vte_ft2_get_visual, + _vte_ft2_get_colormap, + _vte_ft2_start, + _vte_ft2_end, + _vte_ft2_set_background_color, + _vte_ft2_set_background_pixbuf, + _vte_ft2_clear, + _vte_ft2_set_text_font, + _vte_ft2_get_text_width, + _vte_ft2_get_text_height, + _vte_ft2_get_text_ascent, + _vte_ft2_draw_text, + _vte_ft2_draw_rectangle, + _vte_ft2_fill_rectangle, + _vte_ft2_set_scroll, +}; diff --git a/src/vteft2.h b/src/vteft2.h new file mode 100644 index 0000000..eb3a762 --- /dev/null +++ b/src/vteft2.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2003 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef vte_vteft2_h_included +#define vte_vteft2_h_included + +/* The interfaces in this file are subject to change at any time. */ + +#ident "$Id$" + +#include "../config.h" +#include "vtedraw.h" + +G_BEGIN_DECLS + +extern struct _vte_draw_impl _vte_draw_ft2; + +G_END_DECLS + +#endif diff --git a/src/vtegl.c b/src/vtegl.c new file mode 100644 index 0000000..4861491 --- /dev/null +++ b/src/vtegl.c @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2003 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "../config.h" + +#ifdef HAVE_GL + +#include <sys/param.h> +#include <stdio.h> +#include <string.h> +#include <gtk/gtk.h> +#include <gdk/gdkx.h> +#include <GL/gl.h> +#include <GL/glu.h> +#include <GL/glx.h> +#include <X11/Xutil.h> +#include "debug.h" +#include "vtedraw.h" +#include "vtegl.h" + +struct _vte_gl_data +{ + XVisualInfo *visual_info; + gboolean double_buffered; + GLXContext context; + GLXPixmap pixmap; + GdkColor color; + GdkPixbuf *pixbuf; + gint scrollx, scrolly; +}; + +#define _vte_gl_pixmap_attributes \ + GLX_RGBA, \ + GLX_RED_SIZE, 8, \ + GLX_BLUE_SIZE, 8, \ + GLX_GREEN_SIZE, 8, \ + GLX_ALPHA_SIZE, 8, \ + None, +#define _vte_gl_window_attributes \ + GLX_RGBA, \ + GLX_RED_SIZE, 8, \ + GLX_BLUE_SIZE, 8, \ + GLX_GREEN_SIZE, 8, \ + GLX_ALPHA_SIZE, 8, \ + GLX_DOUBLEBUFFER, \ + None, + +static gboolean +_vte_gl_check(struct _vte_draw *draw, GtkWidget *widget) +{ + int window_attributes[] = {_vte_gl_window_attributes}; + int pixmap_attributes[] = {_vte_gl_pixmap_attributes}; + XVisualInfo *visual_info; + GLXContext context = NULL; + GdkDisplay *gdisplay; + Display *display; + GdkScreen *gscreen; + int screen; + int error, event; + + gdisplay = gdk_display_get_default(); + display = gdk_x11_display_get_xdisplay(gdisplay); + gscreen = gdk_screen_get_default(); + screen = gdk_x11_screen_get_screen_number(gscreen); + + /* Check for GLX. */ + if (!glXQueryExtension(display, &error, &event)) { + g_warning("Unable to use GLX.\n"); + return FALSE; + } + + /* See if a suitable visual exists. */ + visual_info = glXChooseVisual(display, screen, + pixmap_attributes); + if (visual_info == NULL) { + visual_info = glXChooseVisual(display, screen, + window_attributes); + } + if (visual_info == NULL) { + return FALSE; + } + + /* Create a GLX context. */ + context = glXCreateContext(display, visual_info, NULL, False); + if (context == NULL) { + return FALSE; + } + + return TRUE; +} + +static void +_vte_gl_create(struct _vte_draw *draw, GtkWidget *widget) +{ + struct _vte_gl_data *data; + int window_attributes[] = {_vte_gl_window_attributes}; + int pixmap_attributes[] = {_vte_gl_pixmap_attributes}; + GdkDisplay *gdisplay; + Display *display; + GdkScreen *gscreen; + int screen; + + draw->impl_data = g_malloc(sizeof(struct _vte_gl_data)); + data = (struct _vte_gl_data*) draw->impl_data; + + gdisplay = gdk_display_get_default(); + display = gdk_x11_display_get_xdisplay(gdisplay); + gscreen = gdk_screen_get_default(); + screen = gdk_x11_screen_get_screen_number(gscreen); + + data->visual_info = glXChooseVisual(display, screen, + pixmap_attributes); + if (data->visual_info != NULL) { + data->double_buffered = FALSE; + } else { + data->visual_info = glXChooseVisual(display, screen, + window_attributes); + data->double_buffered = TRUE; + } + gtk_widget_set_double_buffered(widget, !data->double_buffered); + + data->context = glXCreateContext(display, data->visual_info, + NULL, False); + if (data->context == NULL) { + g_error("Unable to create GLX context.\n"); + } + + data->color.red = 0; + data->color.green = 0; + data->color.blue = 0; + data->pixbuf = NULL; + data->pixmap = -1; + data->scrollx = data->scrolly = 0; +} + +static void +_vte_gl_destroy(struct _vte_draw *draw) +{ + struct _vte_gl_data *data; + GdkDisplay *gdisplay; + Display *display; + GdkScreen *gscreen; + int screen; + + data = (struct _vte_gl_data*) draw->impl_data; + gdisplay = gdk_display_get_default(); + display = gdk_x11_display_get_xdisplay(gdisplay); + gscreen = gdk_screen_get_default(); + screen = gdk_x11_screen_get_screen_number(gscreen); + + if (data->pixmap != -1) { + glXDestroyGLXPixmap(display, data->pixmap); + } + glXDestroyContext(display, data->context); + + data->scrollx = data->scrolly = 0; + + if (GDK_IS_PIXBUF(data->pixbuf)) { + g_object_unref(G_OBJECT(data->pixbuf)); + } + data->pixbuf = NULL; + memset(&data->color, 0, sizeof(data->color)); + + glXDestroyContext(display, data->context); + + g_free(draw->impl_data); +} + +static GdkVisual * +_vte_gl_get_visual(struct _vte_draw *draw) +{ + GdkScreen *gscreen; + struct _vte_gl_data *data; + + data = (struct _vte_gl_data*) draw->impl_data; + gscreen = gdk_screen_get_default(); + return gdk_x11_screen_lookup_visual(gscreen, + data->visual_info->visualid); +} + +static GdkColormap * +_vte_gl_get_colormap(struct _vte_draw *draw) +{ + return NULL; +} + +static void +_vte_gl_start(struct _vte_draw *draw) +{ + struct _vte_gl_data *data; + GdkDisplay *gdisplay; + Display *display; + GdkScreen *gscreen; + int screen; + guint width, height; + GdkDrawable *drawable; + gint x_offset, y_offset; + GLXDrawable glx_drawable = -1; + + data = (struct _vte_gl_data*) draw->impl_data; + gdisplay = gdk_display_get_default(); + display = gdk_x11_display_get_xdisplay(gdisplay); + gscreen = gdk_screen_get_default(); + screen = gdk_x11_screen_get_screen_number(gscreen); + + gdk_window_get_internal_paint_info(draw->widget->window, + &drawable, + &x_offset, + &y_offset); + if (GDK_IS_PIXMAP(drawable)) { + gdk_drawable_get_size(drawable, &width, &height); + data->pixmap = glXCreateGLXPixmap(display, data->visual_info, + GDK_WINDOW_XID(drawable)); + glx_drawable = data->pixmap; + } else + if (GDK_IS_WINDOW(draw->widget->window)) { + gdk_drawable_get_size(draw->widget->window, &width, &height); + x_offset = y_offset = 0; + glx_drawable = GDK_WINDOW_XID(drawable); + } else { + g_assert_not_reached(); + } + + glXMakeCurrent(display, glx_drawable, data->context); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluOrtho2D(x_offset, width, y_offset, height); + glViewport(x_offset, y_offset, width - x_offset, height - y_offset); + + glClearColor(data->color.red / 65535.0, + data->color.green / 65535.0, + data->color.blue / 65535.0, + 1.0); + glClear(GL_COLOR_BUFFER_BIT); +} + +static void +_vte_gl_end(struct _vte_draw *draw) +{ + struct _vte_gl_data *data; + GdkDisplay *gdisplay; + Display *display; + GdkScreen *gscreen; + int screen; + + data = (struct _vte_gl_data*) draw->impl_data; + gdisplay = gdk_display_get_default(); + display = gdk_x11_display_get_xdisplay(gdisplay); + gscreen = gdk_screen_get_default(); + screen = gdk_x11_screen_get_screen_number(gscreen); + + glFlush(); + if (data->double_buffered) { + glXSwapBuffers(display, GDK_WINDOW_XID(draw->widget->window)); + } else { + glXDestroyGLXPixmap(display, data->pixmap); + data->pixmap = -1; + } +} + +static void +_vte_gl_set_background_color(struct _vte_draw *draw, GdkColor *color) +{ + struct _vte_gl_data *data; + data = (struct _vte_gl_data*) draw->impl_data; + data->color = *color; +} + +static void +_vte_gl_set_background_pixbuf(struct _vte_draw *draw, GdkPixbuf *pixbuf) +{ + struct _vte_gl_data *data; + + data = (struct _vte_gl_data*) draw->impl_data; + if (GDK_IS_PIXBUF(pixbuf)) { + g_object_ref(G_OBJECT(pixbuf)); + } + if (GDK_IS_PIXBUF(data->pixbuf)) { + g_object_unref(G_OBJECT(data->pixbuf)); + } + data->pixbuf = pixbuf; +} + +static void +_vte_gl_clear(struct _vte_draw *draw, + gint x, gint y, gint width, gint height) +{ + struct _vte_gl_data *data; + data = (struct _vte_gl_data*) draw->impl_data; + + glBegin(GL_POLYGON); + glColor4us(data->color.red, data->color.green, data->color.blue, + 0xffff); + glVertex2d(x, y); + glVertex2d(x + width, y); + glVertex2d(x + width, y + height); + glVertex2d(x, y + height); + glEnd(); +} + +static void +_vte_gl_set_text_font(struct _vte_draw *draw, + const PangoFontDescription *fontdesc) +{ +} + +static int +_vte_gl_get_text_width(struct _vte_draw *draw) +{ + return 5; +} + +static int +_vte_gl_get_text_height(struct _vte_draw *draw) +{ + return 10; +} + +static int +_vte_gl_get_text_ascent(struct _vte_draw *draw) +{ + return 8; +} + +static void +_vte_gl_draw_text(struct _vte_draw *draw, + struct _vte_draw_text_request *requests, gsize n_requests, + GdkColor *color, guchar alpha) +{ + struct _vte_gl_data *data; + data = (struct _vte_gl_data*) draw->impl_data; +} + +static void +_vte_gl_draw_rectangle(struct _vte_draw *draw, + gint x, gint y, gint width, gint height, + GdkColor *color, guchar alpha) +{ + struct _vte_gl_data *data; + data = (struct _vte_gl_data*) draw->impl_data; + glBegin(GL_LINE_LOOP); + glColor4us(color->red, color->green, color->blue, + (alpha == VTE_DRAW_OPAQUE) ? 0xffff : (alpha << 8)); + glVertex2d(x, y); + glVertex2d(x + width, y); + glVertex2d(x + width, y + height); + glVertex2d(x, y + height); + glEnd(); +} + +static void +_vte_gl_fill_rectangle(struct _vte_draw *draw, + gint x, gint y, gint width, gint height, + GdkColor *color, guchar alpha) +{ + struct _vte_gl_data *data; + data = (struct _vte_gl_data*) draw->impl_data; + glBegin(GL_POLYGON); + glColor4us(color->red, color->green, color->blue, + (alpha == VTE_DRAW_OPAQUE) ? 0xffff : (alpha << 8)); + glVertex2d(x, y); + glVertex2d(x + width, y); + glVertex2d(x + width, y + height); + glVertex2d(x, y + height); + glEnd(); +} + +static void +_vte_gl_set_scroll(struct _vte_draw *draw, gint x, gint y) +{ + struct _vte_gl_data *data; + data = (struct _vte_gl_data*) draw->impl_data; + data->scrollx = x; + data->scrolly = y; +} + +struct _vte_draw_impl _vte_draw_gl = { + "VteGL", "VTE_USE_GL", + _vte_gl_check, + _vte_gl_create, + _vte_gl_destroy, + _vte_gl_get_visual, + _vte_gl_get_colormap, + _vte_gl_start, + _vte_gl_end, + _vte_gl_set_background_color, + _vte_gl_set_background_pixbuf, + _vte_gl_clear, + _vte_gl_set_text_font, + _vte_gl_get_text_width, + _vte_gl_get_text_height, + _vte_gl_get_text_ascent, + _vte_gl_draw_text, + _vte_gl_draw_rectangle, + _vte_gl_fill_rectangle, + _vte_gl_set_scroll, +}; + +#endif diff --git a/src/vtegl.h b/src/vtegl.h new file mode 100644 index 0000000..5f63103 --- /dev/null +++ b/src/vtegl.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2003 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef vte_vtegl_h_included +#define vte_vtegl_h_included + +/* The interfaces in this file are subject to change at any time. */ + +#ident "$Id$" + +#include "../config.h" +#include "vtedraw.h" + +G_BEGIN_DECLS + +extern struct _vte_draw_impl _vte_draw_gl; + +G_END_DECLS + +#endif diff --git a/src/vteglyph.c b/src/vteglyph.c new file mode 100644 index 0000000..bb021eb --- /dev/null +++ b/src/vteglyph.c @@ -0,0 +1,728 @@ +/* + * Copyright (C) 2002,2003 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ident "$Id$" + +#include "../config.h" +#include <sys/param.h> +#include <math.h> +#include <gdk/gdk.h> +#include <glib.h> +#include "vtedraw.h" +#include "vtefc.h" +#include "vteglyph.h" + +#define FONT_INDEX_FUDGE 10 +#define CHAR_WIDTH_FUDGE 10 +#define INVALID_GLYPH -1 + +static FT_Face _vte_glyph_cache_face_for_char(struct _vte_glyph_cache *cache, + gunichar c); + +static int +_vte_direct_compare(gconstpointer a, gconstpointer b) +{ + return GPOINTER_TO_INT(a) - GPOINTER_TO_INT(b); +} + +struct _vte_glyph_cache * +_vte_glyph_cache_new(void) +{ + struct _vte_glyph_cache *ret; + int error; + + ret = g_malloc(sizeof(struct _vte_glyph_cache)); + + ret->patterns = g_array_new(TRUE, TRUE, sizeof(FcPattern*)); + ret->faces = NULL; + ret->cache = g_tree_new(_vte_direct_compare); + ret->ft_load_flags = 0; + ret->ft_render_flags = 0; + ret->width = 0; + ret->height = 0; + ret->ascent = 0; + + error = FT_Init_FreeType(&ret->ft_library); + g_assert(error == 0); + + return ret; +} + +static gboolean +free_tree_value(gpointer key, gpointer value, gpointer data) +{ + if (GPOINTER_TO_INT(value) != INVALID_GLYPH) { + g_free(value); + } + return FALSE; +} + +void +_vte_glyph_cache_free(struct _vte_glyph_cache *cache) +{ + GList *iter; + int i; + + g_return_if_fail(cache != NULL); + + /* Destroy the patterns. */ + if (cache->patterns != NULL) { + for (i = 0; i < cache->patterns->len; i++) { + FcPatternDestroy(g_array_index(cache->patterns, + FcPattern*, + i)); + } + g_array_free(cache->patterns, TRUE); + cache->patterns = NULL; + } + + /* Close all faces. */ + for (iter = cache->faces; iter != NULL; iter = g_list_next(iter)) { + FT_Done_Face((FT_Face) iter->data); + iter->data = NULL; + } + cache->faces = NULL; + + /* Free the glyph tree. */ + g_tree_foreach(cache->cache, free_tree_value, NULL); + cache->cache = NULL; + + /* Close the FT library. */ + if (cache->ft_library) { + FT_Done_FreeType(cache->ft_library); + cache->ft_library = NULL; + } + + /* Free the cache. */ + cache->ft_load_flags = 0; + cache->ft_render_flags = 0; + cache->width = 0; + cache->height = 0; + cache->ascent = 0; + g_free(cache); +} + +void +_vte_glyph_cache_set_description(FcConfig *config, + struct _vte_glyph_cache *cache, + const PangoFontDescription *fontdesc) +{ + FcChar8 *facefile; + int i, j, error, count, width, faceindex; + double dpi, size; + GList *iter; + FcPattern *pattern; + GArray *patterns; + FT_Face face; + gunichar double_wide_characters[] = {VTE_DRAW_DOUBLE_WIDE_CHARACTERS}; + + g_return_if_fail(cache != NULL); + g_return_if_fail(fontdesc != NULL); + + /* Convert the font description to a sorted set of patterns. */ + patterns = g_array_new(TRUE, TRUE, sizeof(FcPattern*)); + if (!_vte_fc_patterns_from_pango_font_desc(fontdesc, patterns)) { + g_array_free(patterns, TRUE); + g_assert_not_reached(); + } + + /* Set the pattern list. */ + if (cache->patterns != NULL) { + g_array_free(cache->patterns, TRUE); + } + cache->patterns = patterns; + + /* Clear the face list. */ + for (iter = cache->faces; iter != NULL; iter = g_list_next(iter)) { + FT_Done_Face((FT_Face) iter->data); + iter->data = NULL; + } + g_list_free(cache->faces); + cache->faces = NULL; + + /* Clear the glyph tree. */ + g_tree_foreach(cache->cache, free_tree_value, NULL); + g_tree_destroy(cache->cache); + cache->cache = g_tree_new(_vte_direct_compare); + + /* Clear the load and render flags. */ + cache->ft_load_flags = 0; + cache->ft_render_flags = 0; + + /* Open the all of the faces to which the patterns resolve. */ + for (i = 0; i < cache->patterns->len; i++) { + pattern = g_array_index(cache->patterns, FcPattern*, i); + j = 0; + while (FcPatternGetString(pattern, FC_FILE, j, + &facefile) == FcResultMatch) { + face = NULL; + if (FcPatternGetInteger(pattern, FC_INDEX, i, + &faceindex) != FcResultMatch) { + faceindex = 0; + } + error = FT_New_Face(cache->ft_library, + facefile, faceindex, + &face); + if (error == 0) { + /* Set the requested size. FIXME: what do we + do if horizontal and vertical DPI aren't the + same? */ + dpi = 72; + FcPatternGetDouble(pattern, FC_DPI, 0, &dpi); + size = 12; + FcPatternGetDouble(pattern, FC_SIZE, 0, &size); + FT_Set_Char_Size(face, 0, floor(size * 64.0), + floor(dpi), floor(dpi)); + cache->faces = g_list_append(cache->faces, + face); + } else { + if (face != NULL) { + FT_Done_Face(face); + } + face = NULL; + } + j++; + } + } + + /* Make sure that we were able to load at least one face. */ + g_assert(cache->faces != NULL); + + /* Pull out other settings. */ + cache->ft_load_flags = 0; + cache->ft_render_flags = 0; + i = 0; + pattern = g_array_index(cache->patterns, FcPattern*, 0); + if (FcPatternGetBool(pattern, FC_AUTOHINT, 0, &i) == FcResultMatch) { + if (i != 0) { + cache->ft_load_flags |= FT_LOAD_FORCE_AUTOHINT; + } + } + if (FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &i) == FcResultMatch) { + if (i == 0) { + cache->ft_load_flags |= FT_LOAD_MONOCHROME; +#if HAVE_DECL_FT_RENDER_MODE_MONO + cache->ft_render_flags = FT_RENDER_MODE_MONO; +#endif + } + } + if (FcPatternGetBool(pattern, FC_HINTING, 0, &i) == FcResultMatch) { + if (i == 0) { + cache->ft_load_flags |= FT_LOAD_NO_HINTING; + } else { + if (FcPatternGetBool(pattern, FC_AUTOHINT, 0, + &i) == FcResultMatch) { + if (i != 0) { + cache->ft_render_flags |= + FT_LOAD_FORCE_AUTOHINT; + } + } + if (FcPatternGetInteger(pattern, FC_HINT_STYLE, 0, + &i) == FcResultMatch) { + switch (i) { +#if HAVE_DECL_FT_LOAD_NO_HINTING + case FC_HINT_NONE: + cache->ft_load_flags |= + FT_LOAD_NO_HINTING; + break; +#endif +#if HAVE_DECL_FT_RENDER_MODE_LIGHT + case FC_HINT_SLIGHT: + cache->ft_render_flags |= + FT_RENDER_MODE_LIGHT; + break; +#endif +#if HAVE_DECL_FT_RENDER_MODE_NORMAL + case FC_HINT_MEDIUM: + cache->ft_render_flags |= + FT_RENDER_MODE_NORMAL; + break; +#endif +#if HAVE_DECL_FT_RENDER_MODE_NORMAL + case FC_HINT_FULL: + cache->ft_render_flags |= + FT_RENDER_MODE_NORMAL; + break; +#endif + default: + break; + } + } + } + } + + /* Calculate average cell size using the first face. */ + cache->width = 0; + cache->height = 0; + cache->ascent = 0; + count = 0; + for (i = 0; VTE_DRAW_SINGLE_WIDE_CHARACTERS[i] != '\0'; i++) { + face = _vte_glyph_cache_face_for_char(cache, + VTE_DRAW_SINGLE_WIDE_CHARACTERS[i]); + if (face == NULL) { + face = cache->faces->data; + } + error = FT_Load_Char((FT_Face) face, + VTE_DRAW_SINGLE_WIDE_CHARACTERS[i], + FT_LOAD_RENDER | cache->ft_load_flags); + if (error == 0) { + cache->width += face->glyph->bitmap.width; + if (face->size->metrics.ascender != 0) { + cache->height += face->size->metrics.ascender - + face->size->metrics.descender; + cache->ascent += face->size->metrics.ascender; + } else + if (face->glyph->metrics.height != 0) { + cache->height += face->glyph->metrics.height; + cache->ascent += face->glyph->metrics.height; + } else { + cache->height += face->glyph->bitmap.rows * 64; + cache->ascent += face->glyph->bitmap.rows * 64; + } + count++; + } + } + if (count > 0) { + cache->width = howmany(cache->width, count); + cache->height = howmany((cache->height / 64), count); + cache->ascent = howmany((cache->ascent / 64), count); + } else { + cache->width = 1; + cache->height = 1; + cache->ascent = 1; + } + width = 0; + for (i = 0; i < G_N_ELEMENTS(double_wide_characters); i++) { + face = _vte_glyph_cache_face_for_char(cache, + double_wide_characters[i]); + if (face == NULL) { + continue; + } + error = FT_Load_Char((FT_Face) face, + double_wide_characters[i], + FT_LOAD_RENDER | cache->ft_load_flags); + if (error == 0) { + width += face->glyph->bitmap.width; + count++; + } + } + if (count > 0) { + if (cache->width == width / count) { + cache->width /= 2; + } + } +} + +static FT_Face +_vte_glyph_cache_face_for_char(struct _vte_glyph_cache *cache, gunichar c) +{ + GList *iter; + for (iter = cache->faces; iter != NULL; iter = g_list_next(iter)) { + if (FT_Get_Char_Index((FT_Face) iter->data, c) != 0) { + return (FT_Face) iter->data; + } + } + return NULL; +} + +gboolean +_vte_glyph_cache_has_char(struct _vte_glyph_cache *cache, gunichar c) +{ + GList *iter; + gpointer p; + + if ((p = g_tree_lookup(cache->cache, GINT_TO_POINTER(c))) != NULL) { + if (GPOINTER_TO_INT(p) == INVALID_GLYPH) { + return FALSE; + } + } + + for (iter = cache->faces; iter != NULL; iter = g_list_next(iter)) { + if (FT_Get_Char_Index((FT_Face) iter->data, c) != 0) { + return TRUE; + } + } + + return FALSE; +} + +static gunichar +_vte_glyph_remap_char(struct _vte_glyph_cache *cache, gunichar origc) +{ + gunichar newc; + + if (_vte_glyph_cache_has_char(cache, origc)) { + return origc; + } + + switch (origc) { + case 0: /* NUL */ + case 0x00A0: /* NO-BREAK SPACE */ + newc = 0x0020; /* SPACE */ + break; + case 0x2010: /* HYPHEN */ + case 0x2011: /* NON-BREAKING HYPHEN */ + case 0x2012: /* FIGURE DASH */ + case 0x2013: /* EN DASH */ + case 0x2014: /* EM DASH */ + case 0x2212: /* MINUS SIGN */ + newc = 0x002D; /* HYPHEN-MINUS */ + break; + default: + newc = origc; + break; + } + + if (_vte_glyph_cache_has_char(cache, newc)) { + return newc; + } else { + return origc; + } +} + +const struct _vte_glyph * +_vte_glyph_get(struct _vte_glyph_cache *cache, gunichar c) +{ + int error = 0; + GList *iter; + struct _vte_glyph *glyph = NULL; + FT_Face face; + gpointer p; + gint x, y, ooffset, ioffset; + guchar r, g, b, t; + + g_return_val_if_fail(cache != NULL, NULL); + + /* See if we already have a glyph for this character. */ + if ((p = g_tree_lookup(cache->cache, GINT_TO_POINTER(c))) != NULL) { + if (GPOINTER_TO_INT(p) == INVALID_GLYPH) { + return NULL; + } else { + return p; + } + } + + /* Search through all of the faces to find one which contains a glyph + * for this character. */ + iter = cache->faces; + face = NULL; + while (iter != NULL) { + /* Check if the face contains a proper glyph. We do this + * separately because we don't want the "unknown glyph" + * glyph. */ + if (FT_Get_Char_Index((FT_Face) iter->data, c) == 0) { + /* Try the next face. */ + iter = g_list_next(iter); + face = NULL; + continue; + } + /* Try to load the character. */ + error = FT_Load_Char((FT_Face) iter->data, + c, + cache->ft_load_flags); + if (error != 0) { + /* Try the next face. */ + iter = g_list_next(iter); + face = NULL; + continue; + } + /* Try to render the character. */ + error = FT_Render_Glyph(((FT_Face) iter->data)->glyph, + cache->ft_render_flags); + if (error != 0) { + /* Try the next face. */ + iter = g_list_next(iter); + face = NULL; + continue; + } + + /* Keep track of which face loaded it. */ + face = iter->data; + break; + } + + /* Bail if we weren't able to load the glyph. */ + if (face == NULL) { + g_tree_insert(cache->cache, GINT_TO_POINTER(c), + GINT_TO_POINTER(INVALID_GLYPH)); + return NULL; + } + + /* Build a new glyph. */ + glyph = g_malloc0(sizeof(struct _vte_glyph) + + face->glyph->bitmap.width * + face->glyph->bitmap.rows * + 4); + glyph->width = face->glyph->bitmap.width; + glyph->height = face->glyph->bitmap.rows; + glyph->skip = MAX((face->size->metrics.ascender >> 6) - + face->glyph->bitmap_top, 0); + glyph->bytes_per_pixel = 4; + + memset(glyph->bytes, 0, + glyph->width * glyph->height * glyph->bytes_per_pixel); + + for (y = 0; y < face->glyph->bitmap.rows; y++) + for (x = 0; x < face->glyph->bitmap.width; x++) { + ooffset = (y * glyph->width + x) * 4; + if (face->glyph->bitmap.pitch > 0) { + ioffset = y; + ioffset *= face->glyph->bitmap.pitch; + } else { + ioffset = face->glyph->bitmap.rows - (y + 1); + ioffset *= (-face->glyph->bitmap.pitch); + } + switch (face->glyph->bitmap.pixel_mode) { + case FT_PIXEL_MODE_MONO: + ioffset += (x / 8); + t = (face->glyph->bitmap.buffer[ioffset] << (x % 8)); + r = g = b = (t >> 7) ? 0xff : 0; + break; + case FT_PIXEL_MODE_GRAY2: + ioffset += (x / 4); + t = (face->glyph->bitmap.buffer[ioffset] << ((x % 4) * 2)); + r = g = b = CLAMP((t >> 6) * 0x55, 0, 0xff); + break; + case FT_PIXEL_MODE_GRAY4: + ioffset += (x / 2); + t = (face->glyph->bitmap.buffer[ioffset] << ((x % 2) * 4)) & 7; + r = g = b = CLAMP((t >> 4) * 0x25, 0, 0xff); + break; + case FT_PIXEL_MODE_GRAY: + ioffset += x; + r = g = b = face->glyph->bitmap.buffer[ioffset]; + break; + case FT_PIXEL_MODE_LCD: + case FT_PIXEL_MODE_LCD_V: + ioffset += (x * 3); + r = face->glyph->bitmap.buffer[ioffset++]; + g = face->glyph->bitmap.buffer[ioffset++]; + b = face->glyph->bitmap.buffer[ioffset++]; + break; + default: + r = g = b = 0; + g_assert_not_reached(); + break; + } + if (face->glyph->bitmap.pitch > 0) { + g_assert(ioffset < ((y + 1) * face->glyph->bitmap.pitch)); + } else { + g_assert(ioffset < ((y + 1) * -face->glyph->bitmap.pitch)); + } + glyph->bytes[ooffset + 0] = r; + glyph->bytes[ooffset + 1] = g; + glyph->bytes[ooffset + 2] = b; + glyph->bytes[ooffset + 3] = 0xff; + } + + /* Cache it. */ + g_tree_insert(cache->cache, GINT_TO_POINTER(c), glyph); + + return glyph; +} + +void +_vte_glyph_draw(struct _vte_glyph_cache *cache, + gunichar c, GdkColor *color, + gint x, gint y, gint columns, + enum vte_glyph_flags flags, + struct _vte_rgb_buffer *buffer) +{ + const struct _vte_glyph *glyph; + gint col, row, ioffset, ooffset, icol, ocol, ecol; + gint strikethrough, underline, underline2; + gint32 r, g, b, ar, ag, ab; + guchar *pixels; + + if (cache == NULL) { + return; + } + glyph = _vte_glyph_get(cache, _vte_glyph_remap_char(cache, c)); + if (glyph == NULL) { + return; + } + + if (x > buffer->width) { + return; + } + if (y > buffer->height) { + return; + } + + pixels = buffer->pixels; + r = color->red >> 8; + g = color->green >> 8; + b = color->blue >> 8; + + if (cache->ascent > 0) { + strikethrough = cache->ascent >> 1; + underline = cache->ascent + 1; + underline2 = cache->ascent + 2; + } else { + strikethrough = MAX(0, cache->height >> 1); + underline = MAX(0, cache->height - 2); + underline2 = MAX(0, cache->height - 1); + } + + icol = MAX(0, (glyph->width - (columns * cache->width)) >> 1); + ocol = MAX(0, ((columns * cache->width) - glyph->width) >> 1); + +_vte_glyph_draw_loop: + + for (row = glyph->skip; + row < MIN(cache->height, glyph->skip + glyph->height); + row++) { + if (row + y >= buffer->height) { + break; + } + ooffset = (y + row) * buffer->stride + + ((x + ocol) * 3); + ioffset = (((row - glyph->skip) * glyph->width) + icol) * 4; + ecol = MIN(cache->width * columns, glyph->width); + for (col = 0; col < ecol; col++) { + if (col + x >= buffer->width) { + break; + } + ar = glyph->bytes[ioffset + 0]; + ag = glyph->bytes[ioffset + 1]; + ab = glyph->bytes[ioffset + 2]; + ioffset += glyph->bytes_per_pixel; + + if (flags & vte_glyph_dim) { + ar = ar >> 1; + ag = ag >> 1; + ab = ab >> 1; + } + + switch (ar) { + case 0: + break; + case 0xff: + pixels[ooffset + 0] = r; + break; + default: + pixels[ooffset + 0] += + (((r - pixels[ooffset + 0]) * ar) >> 8); + break; + } + + switch (ag) { + case 0: + break; + case 0xff: + pixels[ooffset + 1] = g; + break; + default: + pixels[ooffset + 1] += + (((g - pixels[ooffset + 1]) * ag) >> 8); + break; + } + + switch (ab) { + case 0: + break; + case 0xff: + pixels[ooffset + 2] = b; + break; + default: + pixels[ooffset + 2] += + (((b - pixels[ooffset + 2]) * ab) >> 8); + break; + } + + ooffset += 3; + } + } + + if (flags & + (vte_glyph_underline | vte_glyph_underline2 | + vte_glyph_strikethrough | vte_glyph_boxed)) { + for (col = 0; col < cache->width; col++) { + if ((flags & vte_glyph_strikethrough) && + (strikethrough >= 0) && + (strikethrough < cache->height)) { + ooffset = (y + strikethrough) * buffer->stride + + (x + col) * 3; + pixels[ooffset + 0] = r; + pixels[ooffset + 1] = g; + pixels[ooffset + 2] = b; + } + if ((flags & vte_glyph_underline) && + (underline >= 0) && + (underline < cache->height)) { + ooffset = (y + underline) * buffer->stride + + (x + col) * 3; + pixels[ooffset + 0] = r; + pixels[ooffset + 1] = g; + pixels[ooffset + 2] = b; + } + if ((flags & vte_glyph_underline2) && + (underline2 >= 0) && + (underline2 < cache->height)) { + ooffset = (y + underline2) * buffer->stride + + (x + col) * 3; + pixels[ooffset + 0] = r; + pixels[ooffset + 1] = g; + pixels[ooffset + 2] = b; + } + if (flags & vte_glyph_boxed) { + ooffset = y * buffer->stride + (x + col) * 3; + pixels[ooffset + 0] = r; + pixels[ooffset + 1] = g; + pixels[ooffset + 2] = b; + ooffset = (y + cache->height - 1) * buffer->stride + + (x + col) * 3; + pixels[ooffset + 0] = r; + pixels[ooffset + 1] = g; + pixels[ooffset + 2] = b; + } + } + } + + if (flags & vte_glyph_bold) { + flags &= ~vte_glyph_bold; + pixels += 3; + goto _vte_glyph_draw_loop; + } +} + +void +_vte_glyph_draw_string(struct _vte_glyph_cache *cache, + const char *s, GdkColor *color, + gint x, gint y, + enum vte_glyph_flags flags, + struct _vte_rgb_buffer *buffer) +{ + gunichar c; + gint width; + + if (y + cache->height > buffer->height) { + return; + } + + while (*s != '\0') { + c = g_utf8_get_char(s); + width = 1; /* FIXME */ + if (x + width * cache->width > buffer->width) { + break; + } + _vte_glyph_draw(cache, c, color, x, y, width, flags, buffer); + x += (width * cache->width); + s = g_utf8_next_char(s); + } +} diff --git a/src/vteglyph.h b/src/vteglyph.h new file mode 100644 index 0000000..6629a9c --- /dev/null +++ b/src/vteglyph.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2002,2003 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef vte_vteglyph_h_included +#define vte_vteglyph_h_included + +#ident "$Id$" + +#include <glib.h> +#include "vtergb.h" + +#include <fontconfig/fontconfig.h> + +#include <ft2build.h> +#include FT_FREETYPE_H + +enum vte_glyph_flags { + vte_glyph_bold = 1 << 0, + vte_glyph_dim = 1 << 1, + vte_glyph_underline = 1 << 2, + vte_glyph_underline2 = 1 << 3, + vte_glyph_strikethrough = 1 << 4, + vte_glyph_boxed = 1 << 5, +}; + +#define vte_glyph_double_underline \ + (vte_glyph_underline | vte_glyph_underline2) +#define vte_glyph_all \ + (vte_glyph_bold | vte_glyph_dim | \ + vte_glyph_underline | vte_glyph_underline2 | \ + vte_glyph_strikethrough | vte_glyph_boxed) + +struct _vte_glyph { + glong width; + glong height; + glong skip; + guchar bytes_per_pixel; + guchar bytes[1]; +}; + +struct _vte_glyph_cache { + GArray *patterns; + GList *faces; + GTree *cache; + gint ft_load_flags; + gint ft_render_flags; + glong width, height, ascent; + FT_Library ft_library; +}; + +struct _vte_glyph_cache *_vte_glyph_cache_new(void); +void _vte_glyph_cache_free(struct _vte_glyph_cache *cache); +const FcPattern *_vte_glyph_cache_get_pattern(struct _vte_glyph_cache *cache); +void _vte_glyph_cache_set_description(FcConfig *config, + struct _vte_glyph_cache *cache, + const PangoFontDescription *fontdesc); +gboolean _vte_glyph_cache_has_char(struct _vte_glyph_cache *cache, gunichar c); +const struct _vte_glyph *_vte_glyph_get(struct _vte_glyph_cache *cache, + gunichar c); +void _vte_glyph_draw(struct _vte_glyph_cache *cache, + gunichar c, GdkColor *color, + gint x, gint y, gint columns, + enum vte_glyph_flags flags, + struct _vte_rgb_buffer *buffer); +void _vte_glyph_draw_string(struct _vte_glyph_cache *cache, + const char *s, GdkColor *color, + gint x, gint y, + enum vte_glyph_flags flags, + struct _vte_rgb_buffer *buffer); + +#endif diff --git a/src/vtepango.c b/src/vtepango.c index ced2902..13cffcf 100644 --- a/src/vtepango.c +++ b/src/vtepango.c @@ -94,6 +94,18 @@ _vte_pango_destroy(struct _vte_draw *draw) g_free(draw->impl_data); } +static GdkVisual * +_vte_pango_get_visual(struct _vte_draw *draw) +{ + return gtk_widget_get_visual(draw->widget); +} + +static GdkColormap * +_vte_pango_get_colormap(struct _vte_draw *draw) +{ + return gtk_widget_get_colormap(draw->widget); +} + static void _vte_pango_start(struct _vte_draw *draw) { @@ -148,8 +160,7 @@ _vte_pango_set_background_color(struct _vte_draw *draw, GdkColor *color) } static void -_vte_pango_set_background_pixbuf(struct _vte_draw *draw, GdkPixbuf *pixbuf, - gboolean pan, gboolean scroll) +_vte_pango_set_background_pixbuf(struct _vte_draw *draw, GdkPixbuf *pixbuf) { GdkColormap *colormap; GdkPixmap *pixmap; @@ -287,12 +298,12 @@ _vte_pango_set_text_font(struct _vte_draw *draw, draw->width = howmany(draw->width, PANGO_SCALE); draw->height = howmany(logical.height, PANGO_SCALE); - draw->base = draw->height; + draw->ascent = draw->height; #ifdef VTE_DEBUG if (_vte_debug_on(VTE_DEBUG_MISC)) { fprintf(stderr, "VtePango font metrics = %dx%d (%d).\n", - draw->width, draw->height, draw->base); + draw->width, draw->height, draw->ascent); } #endif } @@ -310,9 +321,9 @@ _vte_pango_get_text_height(struct _vte_draw *draw) } static int -_vte_pango_get_text_base(struct _vte_draw *draw) +_vte_pango_get_text_ascent(struct _vte_draw *draw) { - return draw->base; + return draw->ascent; } static void @@ -378,20 +389,6 @@ _vte_pango_fill_rectangle(struct _vte_draw *draw, x, y, width, height); } -static gboolean -_vte_pango_scroll(struct _vte_draw *draw, gint dx, gint dy) -{ - struct _vte_pango_data *data; - data = (struct _vte_pango_data*) draw->impl_data; - if (GDK_IS_WINDOW(draw->widget->window)) { - gdk_window_scroll(GDK_WINDOW(draw->widget->window), dx, dy); - data->scrollx += dx; - data->scrolly += dy; - return TRUE; - } - return FALSE; -} - static void _vte_pango_set_scroll(struct _vte_draw *draw, gint x, gint y) { @@ -406,6 +403,8 @@ struct _vte_draw_impl _vte_draw_pango = { _vte_pango_check, _vte_pango_create, _vte_pango_destroy, + _vte_pango_get_visual, + _vte_pango_get_colormap, _vte_pango_start, _vte_pango_end, _vte_pango_set_background_color, @@ -414,10 +413,9 @@ struct _vte_draw_impl _vte_draw_pango = { _vte_pango_set_text_font, _vte_pango_get_text_width, _vte_pango_get_text_height, - _vte_pango_get_text_base, + _vte_pango_get_text_ascent, _vte_pango_draw_text, _vte_pango_draw_rectangle, _vte_pango_fill_rectangle, - _vte_pango_scroll, _vte_pango_set_scroll, }; diff --git a/src/vtepangox.c b/src/vtepangox.c new file mode 100644 index 0000000..1d765c6 --- /dev/null +++ b/src/vtepangox.c @@ -0,0 +1,466 @@ +/* + * Copyright (C) 2003 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "../config.h" + +#ifdef HAVE_PANGOX + +#include <sys/param.h> +#include <stdio.h> +#include <string.h> +#include <gtk/gtk.h> +#include <pango/pango.h> +#include "debug.h" +#include "vtedraw.h" +#include "vtepangox.h" + +#include <pango/pangox.h> +#include <gdk/gdkx.h> + +struct _vte_pango_x_data +{ + GdkColor color; + GdkPixmap *pixmap; + gint pixmapw, pixmaph; + gint scrollx, scrolly; + PangoFontDescription *font; + PangoLayout *layout; + GdkGC *gc; + PangoContext *ctx; + Drawable drawable; + int x_offs, y_offs; +}; + +static gboolean +_vte_pango_x_check(struct _vte_draw *draw, GtkWidget *widget) +{ + /* We can draw onto any widget. */ + return TRUE; +} + +static void +_vte_pango_x_create(struct _vte_draw *draw, GtkWidget *widget) +{ + struct _vte_pango_x_data *data; + + draw->impl_data = g_malloc(sizeof(struct _vte_pango_x_data)); + data = (struct _vte_pango_x_data*) draw->impl_data; + + data->color.red = 0; + data->color.green = 0; + data->color.blue = 0; + data->pixmap = NULL; + data->pixmapw = data->pixmaph = 0; + data->scrollx = data->scrolly = 0; + data->font = NULL; + data->layout = NULL; + data->gc = NULL; + data->ctx = NULL; +} + +static void +_vte_pango_x_destroy(struct _vte_draw *draw) +{ + struct _vte_pango_x_data *data; + data = (struct _vte_pango_x_data*) draw->impl_data; + + data->scrollx = data->scrolly = 0; + + if (GDK_IS_PIXMAP(data->pixmap)) { + g_object_unref(G_OBJECT(data->pixmap)); + data->pixmap = NULL; + data->pixmapw = data->pixmaph = 0; + } + if (data->font != NULL) { + pango_font_description_free(data->font); + data->font = NULL; + } + if (PANGO_IS_LAYOUT(data->layout)) { + g_object_unref(G_OBJECT(data->layout)); + data->layout = NULL; + } + if (GDK_IS_GC(data->gc)) { + g_object_unref(G_OBJECT(data->gc)); + data->gc = NULL; + } + if (PANGO_IS_CONTEXT(data->ctx)) { + g_object_unref(G_OBJECT(data->ctx)); + data->ctx = NULL; + } + + memset(&data->color, 0, sizeof(data->color)); + + g_free(draw->impl_data); +} + +static GdkVisual * +_vte_pango_x_get_visual(struct _vte_draw *draw) +{ + return gtk_widget_get_visual(draw->widget); +} + +static GdkColormap * +_vte_pango_x_get_colormap(struct _vte_draw *draw) +{ + return gtk_widget_get_colormap(draw->widget); +} + +static void +_vte_pango_x_start(struct _vte_draw *draw) +{ + struct _vte_pango_x_data *data; + Display *display; + GdkDrawable *drawable; + int x_offs, y_offs; + + data = (struct _vte_pango_x_data*) draw->impl_data; + + display = gdk_x11_drawable_get_xdisplay(draw->widget->window); + if (PANGO_IS_CONTEXT(data->ctx)) { + g_object_unref(G_OBJECT(data->ctx)); + } + data->ctx = pango_x_get_context(display); + + if (PANGO_IS_LAYOUT(data->layout)) { + g_object_unref(G_OBJECT(data->layout)); + } + data->layout = pango_layout_new(data->ctx); + + if (data->font) { + pango_layout_set_font_description(data->layout, data->font); + } + + if (GDK_IS_GC(data->gc)) { + g_object_unref(G_OBJECT(data->gc)); + } + data->gc = gdk_gc_new(draw->widget->window); + + gdk_rgb_find_color(gdk_drawable_get_colormap(draw->widget->window), + &data->color); + + gdk_window_get_internal_paint_info(draw->widget->window, &drawable, + &x_offs, &y_offs); + data->drawable = gdk_x11_drawable_get_xid(drawable); + data->x_offs = x_offs; + data->y_offs = y_offs; +} + +static void +_vte_pango_x_end(struct _vte_draw *draw) +{ + struct _vte_pango_x_data *data; + data = (struct _vte_pango_x_data*) draw->impl_data; + + data->drawable = -1; + data->x_offs = 0; + data->y_offs = 0; + + if (PANGO_IS_LAYOUT(data->layout)) { + g_object_unref(G_OBJECT(data->layout)); + } + data->layout = NULL; + + if (GDK_IS_GC(data->gc)) { + g_object_unref(G_OBJECT(data->gc)); + } + data->gc = NULL; + + if (PANGO_IS_CONTEXT(data->ctx)) { + g_object_unref(G_OBJECT(data->ctx)); + } + data->ctx = NULL; +} + +static void +_vte_pango_x_set_background_color(struct _vte_draw *draw, GdkColor *color) +{ + struct _vte_pango_x_data *data; + data = (struct _vte_pango_x_data*) draw->impl_data; + data->color = *color; +} + +static void +_vte_pango_x_set_background_pixbuf(struct _vte_draw *draw, GdkPixbuf *pixbuf) +{ + GdkColormap *colormap; + GdkPixmap *pixmap; + GdkBitmap *bitmap; + struct _vte_pango_x_data *data; + + data = (struct _vte_pango_x_data*) draw->impl_data; + if (data->pixmap) { + g_object_unref(G_OBJECT(data->pixmap)); + data->pixmap = NULL; + data->pixmapw = data->pixmaph = 0; + } + if ((pixbuf != NULL) && + (gdk_pixbuf_get_width(pixbuf) > 0) && + (gdk_pixbuf_get_height(pixbuf) > 0)) { + colormap = gdk_drawable_get_colormap(draw->widget->window); + gdk_pixbuf_render_pixmap_and_mask_for_colormap(pixbuf, colormap, + &pixmap, &bitmap, + 0); + if (bitmap) { + g_object_unref(G_OBJECT(bitmap)); + } + if (pixmap) { + data->pixmap = pixmap; + data->pixmapw = gdk_pixbuf_get_width(pixbuf); + data->pixmaph = gdk_pixbuf_get_height(pixbuf); + } + } +} + +static void +_vte_pango_x_clear(struct _vte_draw *draw, + gint x, gint y, gint width, gint height) +{ + struct _vte_pango_x_data *data; + gint i, j, istart, jstart, h, w, xstop, ystop; + + data = (struct _vte_pango_x_data*) draw->impl_data; + + if ((data->pixmap == NULL) || + (data->pixmapw == 0) || + (data->pixmaph == 0)) { + gdk_gc_set_foreground(data->gc, &data->color); + gdk_draw_rectangle(draw->widget->window, + data->gc, + TRUE, + x, y, width, height); + return; + } + + /* Determine the origin of the pixmap if x = y = 0. */ + i = data->scrollx % data->pixmapw; + j = data->scrolly % data->pixmaph; + + /* Adjust the drawing offsets. */ + istart = (i + x) % data->pixmapw; + jstart = (j + y) % data->pixmaph; + + /* Flood fill. */ + xstop = x + width; + ystop = y + height; + j = jstart; + while (y < ystop) { + h = MIN(data->pixmaph - (j % data->pixmaph), + ystop - j); + i = istart; + while (x < xstop) { + w = MIN(data->pixmapw - (i % data->pixmapw), + xstop - i); + gdk_draw_drawable(draw->widget->window, + data->gc, + data->pixmap, + i, j, + x, y, + w, h); + x += w; + i = 0; + } + y += h; + j = 0; + } +} + +static void +_vte_pango_x_set_text_font(struct _vte_draw *draw, + const PangoFontDescription *fontdesc) +{ + GdkScreen *screen; + PangoContext *ctx; + PangoLayout *layout; + PangoRectangle ink, logical; + gunichar full_codepoints[] = {VTE_DRAW_DOUBLE_WIDE_CHARACTERS}; + GString *full_string; + gint full_width; + int i; + struct _vte_pango_x_data *data; + + data = (struct _vte_pango_x_data*) draw->impl_data; + + screen = gdk_screen_get_default(); + ctx = gdk_pango_context_get_for_screen(screen); + layout = pango_layout_new(ctx); + if (data->font != NULL) { + pango_font_description_free(data->font); + } + data->font = pango_font_description_copy(fontdesc); + pango_layout_set_font_description(layout, data->font); + + /* Estimate for ASCII characters. */ + pango_layout_set_text(layout, + VTE_DRAW_SINGLE_WIDE_CHARACTERS, + strlen(VTE_DRAW_SINGLE_WIDE_CHARACTERS)); + pango_layout_get_extents(layout, &ink, &logical); + draw->width = logical.width; + draw->width = howmany(draw->width, + strlen(VTE_DRAW_SINGLE_WIDE_CHARACTERS)); + + /* Estimate for CJK characters. */ + full_width = draw->width * 2; + full_string = g_string_new(""); + for (i = 0; i < G_N_ELEMENTS(full_codepoints); i++) { + g_string_append_unichar(full_string, full_codepoints[i]); + } + pango_layout_set_text(layout, full_string->str, full_string->len); + pango_layout_get_extents(layout, &ink, &logical); + full_width = howmany(logical.width, G_N_ELEMENTS(full_codepoints)); + g_string_free(full_string, TRUE); + + /* If they're the same, then we have a screwy font. */ + if (full_width == draw->width) { + draw->width /= 2; + } + + g_object_unref(G_OBJECT(layout)); + + draw->width = howmany(draw->width, PANGO_SCALE); + draw->height = howmany(logical.height, PANGO_SCALE); + draw->ascent = draw->height; + +#ifdef VTE_DEBUG + if (_vte_debug_on(VTE_DEBUG_MISC)) { + fprintf(stderr, "VtePango font metrics = %dx%d (%d).\n", + draw->width, draw->height, draw->ascent); + } +#endif +} + +static int +_vte_pango_x_get_text_width(struct _vte_draw *draw) +{ + return draw->width; +} + +static int +_vte_pango_x_get_text_height(struct _vte_draw *draw) +{ + return draw->height; +} + +static int +_vte_pango_x_get_text_ascent(struct _vte_draw *draw) +{ + return draw->ascent; +} + +static void +_vte_pango_x_draw_text(struct _vte_draw *draw, + struct _vte_draw_text_request *requests, + gsize n_requests, + GdkColor *color, guchar alpha) +{ + Display *display; + GC gc; + struct _vte_pango_x_data *data; + char buf[VTE_UTF8_BPC]; + int i; + gsize length; + GdkColor wcolor; + + data = (struct _vte_pango_x_data*) draw->impl_data; + + wcolor = *color; + gdk_rgb_find_color(gdk_drawable_get_colormap(draw->widget->window), + &wcolor); + gdk_gc_set_foreground(data->gc, &wcolor); + display = gdk_x11_drawable_get_xdisplay(draw->widget->window); + gc = gdk_x11_gc_get_xgc(data->gc); + + for (i = 0; i < n_requests; i++) { + length = g_unichar_to_utf8(requests[i].c, buf); + pango_layout_set_text(data->layout, buf, length); + pango_x_render_layout(display, + data->drawable, + gc, + data->layout, + requests[i].x - data->x_offs, + requests[i].y - data->y_offs); + } +} + +static void +_vte_pango_x_draw_rectangle(struct _vte_draw *draw, + gint x, gint y, gint width, gint height, + GdkColor *color, guchar alpha) +{ + struct _vte_pango_x_data *data; + GdkColor wcolor; + + data = (struct _vte_pango_x_data*) draw->impl_data; + + wcolor = *color; + gdk_rgb_find_color(gdk_drawable_get_colormap(draw->widget->window), + &wcolor); + gdk_gc_set_foreground(data->gc, &wcolor); + + gdk_draw_rectangle(draw->widget->window, data->gc, FALSE, + x, y, width, height); +} + +static void +_vte_pango_x_fill_rectangle(struct _vte_draw *draw, + gint x, gint y, gint width, gint height, + GdkColor *color, guchar alpha) +{ + struct _vte_pango_x_data *data; + GdkColor wcolor; + + data = (struct _vte_pango_x_data*) draw->impl_data; + wcolor = *color; + gdk_rgb_find_color(gdk_drawable_get_colormap(draw->widget->window), + &wcolor); + gdk_gc_set_foreground(data->gc, &wcolor); + gdk_draw_rectangle(draw->widget->window, data->gc, TRUE, + x, y, width, height); +} + +static void +_vte_pango_x_set_scroll(struct _vte_draw *draw, gint x, gint y) +{ + struct _vte_pango_x_data *data; + data = (struct _vte_pango_x_data*) draw->impl_data; + data->scrollx = x; + data->scrolly = y; +} + +struct _vte_draw_impl _vte_draw_pango_x = { + "VtePangoX", "VTE_USE_PANGOX", + _vte_pango_x_check, + _vte_pango_x_create, + _vte_pango_x_destroy, + _vte_pango_x_get_visual, + _vte_pango_x_get_colormap, + _vte_pango_x_start, + _vte_pango_x_end, + _vte_pango_x_set_background_color, + _vte_pango_x_set_background_pixbuf, + _vte_pango_x_clear, + _vte_pango_x_set_text_font, + _vte_pango_x_get_text_width, + _vte_pango_x_get_text_height, + _vte_pango_x_get_text_ascent, + _vte_pango_x_draw_text, + _vte_pango_x_draw_rectangle, + _vte_pango_x_fill_rectangle, + _vte_pango_x_set_scroll, +}; + +#endif diff --git a/src/vtepangox.h b/src/vtepangox.h new file mode 100644 index 0000000..4f83146 --- /dev/null +++ b/src/vtepangox.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2003 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef vte_vtepangox_h_included +#define vte_vtepangox_h_included + +/* The interfaces in this file are subject to change at any time. */ + +#ident "$Id$" + +#include "../config.h" +#include "vtedraw.h" + +G_BEGIN_DECLS + +extern struct _vte_draw_impl _vte_draw_pango_x; + +G_END_DECLS + +#endif diff --git a/src/vtergb.c b/src/vtergb.c new file mode 100644 index 0000000..c0aba9b --- /dev/null +++ b/src/vtergb.c @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2003 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ident "$Id$" + +#include "../config.h" +#include <gdk/gdk.h> +#include <glib.h> +#include <fontconfig/fontconfig.h> +#include <ft2build.h> +#include FT_FREETYPE_H +#include "vtergb.h" + +struct _vte_rgb_buffer_p { + guchar *pixels; + gint width, height, stride; + gint length; +}; + +struct _vte_rgb_buffer * +_vte_rgb_buffer_new(gint width, gint height) +{ + struct _vte_rgb_buffer_p *ret; + + ret = g_malloc0(sizeof(*ret)); + + width = MAX(width, 1); + height = MAX(height, 1); + + ret->width = width; + ret->height = height; + ret->stride = width * 3; + ret->length = width * height * 3; + ret->pixels = g_malloc(ret->length); + + return (struct _vte_rgb_buffer *) ret; +} + +void +_vte_rgb_buffer_free(struct _vte_rgb_buffer *buffer) +{ + struct _vte_rgb_buffer_p *buf = (struct _vte_rgb_buffer_p *) buffer; + + g_free(buf->pixels); + + buf->length = 0; + buf->stride = 0; + buf->height = 0; + buf->width = 0; + buf->pixels = NULL; + + g_free(buf); +} + +void +_vte_rgb_buffer_resize(struct _vte_rgb_buffer *buffer, + gint minimum_width, + gint minimum_height) +{ + struct _vte_rgb_buffer_p *buf = (struct _vte_rgb_buffer_p *) buffer; + gssize size = minimum_width * minimum_height * 3; + + if (size > buf->length) { + g_free(buf->pixels); + buf->length = size; + buf->pixels = g_malloc(buf->length); + } + + buf->width = minimum_width; + buf->height = minimum_height; + buf->stride = buf->width * 3; +} + +void +_vte_rgb_draw_color_rgb(struct _vte_rgb_buffer *buffer, + gint x, gint y, gint width, gint height, + guchar r, guchar g, guchar b) +{ + gint row, rows, col, cols; + gint offset, dest, count; + guchar *pixels; + + /* Perform a simple clipping check. */ + if (x > buffer->width) { + return; + } + if (y > buffer->height) { + return; + } + + /* Find the lower right corner. */ + pixels = buffer->pixels; + rows = MIN(y + height, buffer->height); + cols = MIN(x + width, buffer->width); + + /* If we had negative or nonsensical width or height, bail. */ + if (rows <= y) { + return; + } + if (cols <= x) { + return; + } + + /* Draw the first row by iteration. */ + dest = y * buffer->stride + x * 3; + offset = dest; + for (col = x; col < cols; col++) { + pixels[dest++] = r; + pixels[dest++] = g; + pixels[dest++] = b; + } + + /* Draw the other rows by copying the data. */ + count = width * 3; + for (row = y + 1; row < rows; row++) { + dest = row * buffer->stride + x * 3; + memmove(pixels + dest, pixels + offset, count); + } +} + +void +_vte_rgb_draw_color(struct _vte_rgb_buffer *buffer, + gint x, gint y, gint width, gint height, GdkColor *color) +{ + guchar r, g, b; + r = MIN(color->red >> 8, 0xff); + g = MIN(color->green >> 8, 0xff); + b = MIN(color->blue >> 8, 0xff); + _vte_rgb_draw_color_rgb(buffer, x, y, width, height, r, g, b); +} + +void +_vte_rgb_draw_pixbuf(struct _vte_rgb_buffer *buffer, + gint x, gint y, gint width, gint height, + GdkPixbuf *pixbuf, gint xbias, gint ybias) +{ + struct _vte_rgb_buffer_p *buf = (struct _vte_rgb_buffer_p *) buffer; + gint row, col, rows, cols; + guchar bits, channels, *ipixels, *pixels; + gint ioffset, offset, istride, stride, iwidth, iheight, ix, iy, irange; + + /* Find the stopping points. */ + cols = MIN(x + width, buffer->width); + rows = MIN(y + height, buffer->height); + if (cols < x) { + return; + } + if (rows < y) { + return; + } + + /* Check that we can handle the pixbuf format. */ + bits = gdk_pixbuf_get_bits_per_sample(pixbuf); + g_assert(bits == 8); + channels = gdk_pixbuf_get_n_channels(pixbuf); + + /* Get the addresses of the pixels and set things up. */ + ipixels = gdk_pixbuf_get_pixels(pixbuf); + pixels = buf->pixels; + istride = gdk_pixbuf_get_rowstride(pixbuf); + stride = buf->stride; + iwidth = gdk_pixbuf_get_width(pixbuf); + iheight = gdk_pixbuf_get_height(pixbuf); + xbias %= iwidth; + ybias %= iheight; + + /* Start at the first row of the pixbuf we want. */ + iy = ybias; + row = y; + while (row < rows) { + /* If the source layout is the same as the output, we can + * use memcpy, otherwise we need to do it the slow way. */ + if (channels == 3) { + /* Get the offset for this row, and find the + * first column. */ + ix = xbias; + col = x; + while (col < cols) { + /* Calculate the destination, the number of + * pixels to copy, and the source location. */ + irange = MIN(cols - col, iwidth - ix); + offset = row * stride + col * 3; + ioffset = iy * istride + ix * 3; + /* Copy a range of pixels . */ + memcpy(pixels + offset, + ipixels + ioffset, + irange * 3); + /* Move on to the next range, wrapping + * if necessary. */ + col += irange; + ix += irange; + ix %= iwidth; + } + /* Move on to the next row, wrapping if necessary. */ + iy++; + iy %= iheight; + } else { + /* Get the offset for this row, and find the + * first column. */ + ix = xbias; + offset = row * stride + x * 3; + col = x; + while (col < cols) { + ioffset = iy * istride + ix * channels; + /* Copy one pixel . */ + pixels[offset++] = ipixels[ioffset++]; + pixels[offset++] = ipixels[ioffset++]; + pixels[offset++] = ipixels[ioffset++]; + /* Move on to the next pixel, wrapping + * if necessary. */ + ix++; + ix %= iwidth; + col++; + } + /* Move on to the next row, wrapping if necessary. */ + iy++; + iy %= iheight; + } + row++; + } +} + +void +_vte_rgb_draw_on_drawable(GdkDrawable *drawable, GdkGC *gc, + gint x, gint y, gint width, gint height, + struct _vte_rgb_buffer *buffer, + gint xbias, gint ybias) +{ + g_return_if_fail(xbias + width <= buffer->width); + g_return_if_fail(ybias + height <= buffer->height); + g_return_if_fail((xbias + width) * 3 <= buffer->stride); + gdk_draw_rgb_image(drawable, gc, x, y, width, height, + GDK_RGB_DITHER_NORMAL, + buffer->pixels + + ybias * buffer->stride + + xbias * 3, + buffer->stride); +} + +void +_vte_rgb_buffer_clear(struct _vte_rgb_buffer *buffer) +{ + struct _vte_rgb_buffer_p *buf = (struct _vte_rgb_buffer_p *) buffer; + memset(buf->pixels, '\0', buf->length); +} diff --git a/src/vtergb.h b/src/vtergb.h new file mode 100644 index 0000000..6685873 --- /dev/null +++ b/src/vtergb.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2003 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef vte_vte_rgb_h_included +#define vte_vte_rgb_h_included + +#ident "$Id$" + +#include <gdk/gdk.h> +#include <glib.h> + +struct _vte_rgb_buffer { + guchar *pixels; + gint width, height, stride; +}; + +struct _vte_rgb_buffer *_vte_rgb_buffer_new(gint width, gint height); +void _vte_rgb_buffer_free(struct _vte_rgb_buffer *buffer); +void _vte_rgb_buffer_clear(struct _vte_rgb_buffer *buffer); +void _vte_rgb_buffer_resize(struct _vte_rgb_buffer *buffer, + gint minimum_width, gint minimum_height); + +void _vte_rgb_draw_color_rgb(struct _vte_rgb_buffer *buffer, + gint x, gint y, gint width, gint height, + guchar r, guchar g, guchar b); +void _vte_rgb_draw_color(struct _vte_rgb_buffer *buffer, + gint x, gint y, gint width, gint height, + GdkColor *color); +void _vte_rgb_draw_pixbuf(struct _vte_rgb_buffer *buffer, + gint x, gint y, gint width, gint height, + GdkPixbuf *pixbuf, gint xbias, gint ybias); +void _vte_rgb_draw_on_drawable(GdkDrawable *drawable, GdkGC *gc, + gint x, gint y, gint width, gint height, + struct _vte_rgb_buffer *buffer, + gint xbias, gint ybias); + +#endif diff --git a/src/vteskel.c b/src/vteskel.c index 2f409a3..3e11a29 100644 --- a/src/vteskel.c +++ b/src/vteskel.c @@ -74,6 +74,18 @@ _vte_skel_destroy(struct _vte_draw *draw) g_free(draw->impl_data); } +static GdkVisual * +_vte_skel_get_visual(struct _vte_draw *draw) +{ + return gtk_widget_get_visual(draw->widget); +} + +static GdkColormap * +_vte_skel_get_colormap(struct _vte_draw *draw) +{ + return gtk_widget_get_colormap(draw->widget); +} + static void _vte_skel_start(struct _vte_draw *draw) { @@ -99,12 +111,8 @@ _vte_skel_set_background_color(struct _vte_draw *draw, GdkColor *color) } static void -_vte_skel_set_background_pixbuf(struct _vte_draw *draw, GdkPixbuf *pixbuf, - gboolean pan, gboolean scroll) +_vte_skel_set_background_pixbuf(struct _vte_draw *draw, GdkPixbuf *pixbuf) { - GdkColormap *colormap; - GdkPixmap *pixmap; - GdkBitmap *bitmap; struct _vte_skel_data *data; data = (struct _vte_skel_data*) draw->impl_data; @@ -139,9 +147,9 @@ _vte_skel_get_text_height(struct _vte_draw *draw) } static int -_vte_skel_get_text_base(struct _vte_draw *draw) +_vte_skel_get_text_ascent(struct _vte_draw *draw) { - return draw->base; + return draw->ascent; } static void @@ -171,14 +179,6 @@ _vte_skel_fill_rectangle(struct _vte_draw *draw, data = (struct _vte_skel_data*) draw->impl_data; } -static gboolean -_vte_skel_scroll(struct _vte_draw *draw, gint dx, gint dy) -{ - struct _vte_skel_data *data; - data = (struct _vte_skel_data*) draw->impl_data; - return FALSE; -} - static void _vte_skel_set_scroll(struct _vte_draw *draw, gint x, gint y) { @@ -193,6 +193,8 @@ struct _vte_draw_impl _vte_draw_skel = { _vte_skel_check, _vte_skel_create, _vte_skel_destroy, + _vte_skel_get_visual, + _vte_skel_get_colormap, _vte_skel_start, _vte_skel_end, _vte_skel_set_background_color, @@ -201,10 +203,9 @@ struct _vte_draw_impl _vte_draw_skel = { _vte_skel_set_text_font, _vte_skel_get_text_width, _vte_skel_get_text_height, - _vte_skel_get_text_base, + _vte_skel_get_text_ascent, _vte_skel_draw_text, _vte_skel_draw_rectangle, _vte_skel_fill_rectangle, - _vte_skel_scroll, _vte_skel_set_scroll, }; diff --git a/src/vtexft.c b/src/vtexft.c index 1a5f322..29e62b0 100644 --- a/src/vtexft.c +++ b/src/vtexft.c @@ -327,6 +327,18 @@ _vte_xft_destroy(struct _vte_draw *draw) g_free(data); } +static GdkVisual * +_vte_xft_get_visual(struct _vte_draw *draw) +{ + return gtk_widget_get_visual(draw->widget); +} + +static GdkColormap * +_vte_xft_get_colormap(struct _vte_draw *draw) +{ + return gtk_widget_get_colormap(draw->widget); +} + static void _vte_xft_start(struct _vte_draw *draw) { @@ -501,7 +513,7 @@ _vte_xft_set_text_font(struct _vte_draw *draw, draw->width = 1; draw->height = 1; - draw->base = 1; + draw->ascent = 1; string = g_string_new(""); n = width = height = 0; @@ -522,8 +534,8 @@ _vte_xft_set_text_font(struct _vte_draw *draw, draw->width = howmany(width, n); draw->height = (font != NULL) ? font->ascent + font->descent : height; - draw->base = (font != NULL) ? - font->ascent : height; + draw->ascent = (font != NULL) ? + font->ascent : height; } /* Estimate a typical cell width by looking at double-width * characters, and if it's the same as the single width, assume the @@ -550,7 +562,7 @@ _vte_xft_set_text_font(struct _vte_draw *draw, #ifdef VTE_DEBUG if (_vte_debug_on(VTE_DEBUG_MISC)) { fprintf(stderr, "VteXft font metrics = %dx%d (%d).\n", - draw->width, draw->height, draw->base); + draw->width, draw->height, draw->ascent); } #endif } @@ -568,9 +580,9 @@ _vte_xft_get_text_height(struct _vte_draw *draw) } static int -_vte_xft_get_text_base(struct _vte_draw *draw) +_vte_xft_get_text_ascent(struct _vte_draw *draw) { - return draw->base; + return draw->ascent; } static void @@ -602,7 +614,7 @@ _vte_xft_draw_text(struct _vte_draw *draw, pad = CLAMP(pad / 2, 0, draw->width); specs[j].x += pad; } - specs[j].y = requests[i].y - data->y_offs + draw->base; + specs[j].y = requests[i].y - data->y_offs + draw->ascent; specs[j].ucs4 = requests[i].c; j++; } else { @@ -687,14 +699,6 @@ _vte_xft_fill_rectangle(struct _vte_draw *draw, } } -static gboolean -_vte_xft_scroll(struct _vte_draw *draw, gint dx, gint dy) -{ - struct _vte_xft_data *data; - data = (struct _vte_xft_data*) draw->impl_data; - return FALSE; -} - static void _vte_xft_set_scroll(struct _vte_draw *draw, gint x, gint y) { @@ -709,6 +713,8 @@ struct _vte_draw_impl _vte_draw_xft = { _vte_xft_check, _vte_xft_create, _vte_xft_destroy, + _vte_xft_get_visual, + _vte_xft_get_colormap, _vte_xft_start, _vte_xft_end, _vte_xft_set_background_color, @@ -717,11 +723,10 @@ struct _vte_draw_impl _vte_draw_xft = { _vte_xft_set_text_font, _vte_xft_get_text_width, _vte_xft_get_text_height, - _vte_xft_get_text_base, + _vte_xft_get_text_ascent, _vte_xft_draw_text, _vte_xft_draw_rectangle, _vte_xft_fill_rectangle, - _vte_xft_scroll, _vte_xft_set_scroll, }; #endif @@ -6,6 +6,6 @@ includedir=@includedir@ Name: vte Description: Vte terminal widget. Version: @VERSION@ -Requires: glib-2.0 gobject-2.0 atk pango pangox gtk+-2.0 gdk-pixbuf-2.0 fontconfig xft >= 2.0 +Requires: @NEEDEDPACKAGES@ Libs: -L${libdir} -lvte @FT2_LIBS@ @OTHERLIBS@ Cflags: -I${includedir} @FT2_CFLAGS@ @@ -1,5 +1,5 @@ Name: vte -Version: 0.11.0 +Version: 0.11.1 Release: 1 Summary: An experimental terminal emulator. License: LGPL @@ -93,6 +93,10 @@ rm -f $RPM_BUILD_ROOT/%{_libdir}/python*/site-packages/*.a %{_libdir}/pkgconfig/* %changelog +* Wed Apr 9 2003 Nalin Dahyabhai <nalin@redhat.com> 0.11.1-1 +- rework drawing with Xft2 to use font sets +- implement drawing with freetype using font sets + * Thu Jan 30 2003 Nalin Dahyabhai <nalin@redhat.com> 0.11.0-1 - start of experimental series |