mirror of
https://gitlab.winehq.org/wine/fontforge.git
synced 2025-10-14 02:47:57 +08:00
2316 lines
85 KiB
C
2316 lines
85 KiB
C
#ifdef __VMS
|
|
#include <vms_x_fix.h>
|
|
#endif
|
|
|
|
#include "gxdrawP.h"
|
|
#include "gxcdrawP.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
|
|
#include <ustring.h>
|
|
#include <utype.h>
|
|
#include "fontP.h"
|
|
|
|
#ifdef __Mac
|
|
# include <sys/utsname.h>
|
|
#endif
|
|
|
|
#ifdef _NO_LIBPANGO
|
|
static int usepango=false;
|
|
#else
|
|
static int usepango=true;
|
|
#endif
|
|
#ifdef _NO_LIBCAIRO
|
|
static int usecairo = false;
|
|
#else
|
|
static int usecairo = true;
|
|
#endif
|
|
|
|
static void MacVersionTest(void) {
|
|
/* pango and cairo do not work on mac 10.5.0 same code runs fine on 10.5.6 */
|
|
/* I'm guessing that there is a problem with libfontconfig under Xfree86 */
|
|
/* which is not present in the X.org release. (X11->About says it is */
|
|
/* Xfree under 10.5.0, and X.org under 10.5.6) */
|
|
/* If I try to use pango or cairo under 10.5.0 fontforge crashes instantly*/
|
|
/* and people blame me */
|
|
/* Note that pango runs fine under 10.4.? */
|
|
/* So how to detect a bad X library? */
|
|
/* well `uname -r` gives us 9.0.0 on 10.5, so problems may happen above that */
|
|
/* the X.org bin directory contains the file "Xnest" while the */
|
|
/* XFree bin directory does not */
|
|
#ifdef __Mac
|
|
struct utsname osinfo;
|
|
static int tested=0;
|
|
|
|
if ( tested || (!usepango && !usecairo))
|
|
return;
|
|
tested = true;
|
|
|
|
if ( uname(&osinfo)!=0 ) {
|
|
/* Error? Shouldn't happen */
|
|
usecairo = usepango = false;
|
|
return;
|
|
}
|
|
if ( *osinfo.release!='9' || access("/usr/X11R6/bin/Xnest",0)==0 )
|
|
return; /* Not 10.5.* or we've got the Xorg distribution */
|
|
usecairo = usepango = false;
|
|
fprintf( stderr, "You appear to have a version of X11 with a bug in it.\n" );
|
|
fprintf( stderr, " This bug will cause fontforge to crash if it attempts\n" );
|
|
fprintf( stderr, " to use the pango or cairo libraries. FontForge will\n" );
|
|
fprintf( stderr, " not attempt to use these libraries.\n\n" );
|
|
fprintf( stderr, "You can install a fix by going to <Apple>->Software Update\n" );
|
|
fprintf( stderr, " and selecting \"Mac OS X Update Combined\".\n\n" );
|
|
fprintf( stderr, "If you believe you do have the correct software, then\n" );
|
|
fprintf( stderr, " simply create the file \"/usr/X11R6/bin/Xnest\" and\n" );
|
|
fprintf( stderr, " fontforge will shut up.\n" );
|
|
GDrawError(
|
|
"You appear to have a version of X11 with a bug in it."
|
|
" This bug will cause fontforge to crash if it attempts"
|
|
" to use the pango or cairo libraries. FontForge will"
|
|
" not attempt to use these libraries.\n\n"
|
|
"You can install a fix by going to <Apple>->Software Update"
|
|
" and selecting \"Mac OS X Update Combined\".\n\n"
|
|
"If you don't want to see this message at startup, go to"
|
|
" File->Preferences->Generic and turn off both"
|
|
" UseCairo and UsePango.\n\n"
|
|
"If you believe you do have the correct software, then"
|
|
" simply create the file \"/usr/X11R6/bin/Xnest\" and"
|
|
" fontforge will shut up.\n"
|
|
);
|
|
#endif
|
|
}
|
|
|
|
void GDrawEnableCairo(int on) {
|
|
usecairo=on;
|
|
/* Obviously, if we have no library, enabling it will do nothing */
|
|
}
|
|
|
|
void GDrawEnablePango(int on) {
|
|
usepango=on;
|
|
/* Obviously, if we have no library, enabling it will do nothing */
|
|
}
|
|
|
|
#ifndef _NO_LIBCAIRO
|
|
# if (CAIRO_VERSION_MAJOR==1 && CAIRO_VERSION_MINOR<6) || (!defined(_STATIC_LIBCAIRO) && !defined(NODYNAMIC))
|
|
static int __cairo_format_stride_for_width(cairo_format_t f,int width) {
|
|
if ( f==CAIRO_FORMAT_ARGB32 || f==CAIRO_FORMAT_RGB24 )
|
|
return( 4*width );
|
|
else if ( f==CAIRO_FORMAT_A8 )
|
|
return( ((width+3)>>2)<<2 );
|
|
else if ( f==CAIRO_FORMAT_A1 )
|
|
return( ((width+31)>>5)<<5 );
|
|
else
|
|
return( 4*width );
|
|
}
|
|
#endif
|
|
|
|
/* ************************************************************************** */
|
|
/* ***************************** Cairo Library ****************************** */
|
|
/* ************************************************************************** */
|
|
|
|
# if !defined(_STATIC_LIBCAIRO) && !defined(NODYNAMIC)
|
|
# include <dynamic.h>
|
|
static DL_CONST void *libcairo=NULL, *libfontconfig;
|
|
static cairo_surface_t *(*_cairo_xlib_surface_create)(Display *,Drawable,Visual*,int,int);
|
|
static cairo_t *(*_cairo_create)(cairo_surface_t *);
|
|
static void (*_cairo_destroy)(cairo_t *);
|
|
static void (*_cairo_surface_destroy)(cairo_surface_t *);
|
|
static void (*_cairo_xlib_surface_set_size)(cairo_surface_t *,int,int);
|
|
static void (*_cairo_set_line_width)(cairo_t *,double);
|
|
/* I don't actually use line join/cap. On a screen with small line_width they don't matter */
|
|
static void (*_cairo_set_line_cap)(cairo_t *,cairo_line_cap_t);
|
|
static void (*_cairo_set_line_join)(cairo_t *,cairo_line_join_t);
|
|
static void (*_cairo_set_source_rgba)(cairo_t *,double,double,double,double);
|
|
static void (*_cairo_set_operator)(cairo_t *,cairo_operator_t);
|
|
static void (*_cairo_set_dash)(cairo_t *,double *, int, double);
|
|
static void (*_cairo_stroke)(cairo_t *);
|
|
static void (*_cairo_fill)(cairo_t *);
|
|
static void (*_cairo_fill_preserve)(cairo_t *);
|
|
static void (*_cairo_clip)(cairo_t *);
|
|
static void (*_cairo_save)(cairo_t *);
|
|
static void (*_cairo_restore)(cairo_t *);
|
|
static void (*_cairo_new_path)(cairo_t *);
|
|
static void (*_cairo_close_path)(cairo_t *);
|
|
static void (*_cairo_move_to)(cairo_t *,double,double);
|
|
static void (*_cairo_line_to)(cairo_t *,double,double);
|
|
static void (*_cairo_curve_to)(cairo_t *,double,double,double,double,double,double);
|
|
static void (*_cairo_rectangle)(cairo_t *,double,double,double,double);
|
|
static void (*_cairo_scaled_font_extents)(cairo_scaled_font_t *,cairo_font_extents_t *);
|
|
static void (*_cairo_scaled_font_text_extents)(cairo_scaled_font_t *,const char *,cairo_text_extents_t *);
|
|
static void (*_cairo_set_scaled_font)(cairo_t *,const cairo_scaled_font_t *);
|
|
static void (*_cairo_show_text)(cairo_t *,const char *);
|
|
static cairo_scaled_font_t *(*_cairo_scaled_font_create)(cairo_font_face_t *, const cairo_matrix_t *, const cairo_matrix_t *, const cairo_font_options_t *);
|
|
static cairo_font_face_t *(*_cairo_ft_font_face_create_for_pattern)(FcPattern *);
|
|
static void (*_cairo_set_source_surface)(cairo_t *,cairo_surface_t *,double,double);
|
|
static void (*_cairo_mask_surface)(cairo_t *,cairo_surface_t *,double,double);
|
|
static void (*_cairo_scale)(cairo_t *,double,double);
|
|
static void (*_cairo_translate)(cairo_t *,double,double);
|
|
static cairo_format_t (*_cairo_image_surface_get_format)(cairo_surface_t *);
|
|
static cairo_surface_t *(*_cairo_image_surface_create_for_data)(unsigned char *,cairo_format_t,int,int,int);
|
|
static int (*_cairo_format_stride_for_width)(cairo_format_t,int);
|
|
static cairo_font_options_t *(*_cairo_font_options_create)(void);
|
|
static void (*_cairo_surface_mark_dirty_rectangle)(cairo_surface_t *,double,double,double,double);
|
|
static void (*_cairo_surface_flush)(cairo_surface_t *);
|
|
static cairo_pattern_t *(*_cairo_pattern_create_for_surface)(cairo_surface_t *);
|
|
static void (*_cairo_pattern_set_extend)(cairo_pattern_t *,cairo_extend_t);
|
|
static void (*_cairo_pattern_destroy)(cairo_pattern_t *);
|
|
static void (*_cairo_set_source)(cairo_t *, cairo_pattern_t *);
|
|
static void (*_cairo_push_group)(cairo_t *);
|
|
static void (*_cairo_pop_group_to_source)(cairo_t *);
|
|
static cairo_surface_t *(*_cairo_get_group_target)(cairo_t *);
|
|
static void (*_cairo_paint)(cairo_t *);
|
|
|
|
static FcBool (*_FcCharSetHasChar)(const FcCharSet *,FcChar32);
|
|
static FcPattern *(*_FcPatternCreate)(void);
|
|
static void (*_FcPatternDestroy)(FcPattern *);
|
|
static FcBool (*_FcPatternAddDouble)(FcPattern *,const char *,double);
|
|
static FcBool (*_FcPatternAddInteger)(FcPattern *,const char *,int);
|
|
static FcBool (*_FcPatternAddString)(FcPattern *,const char *,const char *);
|
|
static FcPattern *(*_FcFontRenderPrepare)(FcConfig *, FcPattern *,FcPattern *);
|
|
static FcBool (*_FcConfigSubstitute)(FcConfig *, FcPattern *,FcMatchKind);
|
|
static void (*_FcDefaultSubstitute)(FcPattern *);
|
|
static FcFontSet *(*_FcFontSort)(FcConfig *,FcPattern *,FcBool,FcCharSet **,FcResult *);
|
|
static FcResult (*_FcPatternGetCharSet)(FcPattern *,const char *,int,FcCharSet **);
|
|
|
|
int _GXCDraw_hasCairo(void) {
|
|
static int initted = false, hasC=false;
|
|
FcBool (*_FcInit)(void);
|
|
|
|
if ( !usecairo )
|
|
return( false );
|
|
|
|
if ( initted )
|
|
return( hasC );
|
|
|
|
initted = true;
|
|
libfontconfig = dlopen("libfontconfig" SO_EXT,RTLD_LAZY);
|
|
#ifdef SO_1_EXT
|
|
if ( libfontconfig==NULL )
|
|
libfontconfig = dlopen("libfontconfig" SO_1_EXT,RTLD_LAZY);
|
|
#endif
|
|
/* The mac doesn't put /usr/X11R6/lib into the default library load path. Very annoying */
|
|
if ( libfontconfig==NULL )
|
|
libfontconfig = dlopen("/usr/X11R6/lib/libfontconfig" SO_EXT,RTLD_LAZY);
|
|
#ifdef SO_1_EXT
|
|
if ( libfontconfig==NULL )
|
|
libfontconfig = dlopen("/usr/X11R6/lib/libfontconfig" SO_1_EXT,RTLD_LAZY);
|
|
#endif
|
|
if ( libfontconfig==NULL ) {
|
|
fprintf(stderr,"libfontconfig: %s\n", dlerror());
|
|
return( 0 );
|
|
}
|
|
_FcInit = (FcBool (*)(void)) dlsym(libfontconfig,"FcInit");
|
|
if ( _FcInit==NULL || !_FcInit() )
|
|
return( 0 );
|
|
_FcCharSetHasChar = (FcBool (*)(const FcCharSet *,FcChar32))
|
|
dlsym(libfontconfig,"FcCharSetHasChar");
|
|
_FcPatternCreate = (FcPattern *(*)(void))
|
|
dlsym(libfontconfig,"FcPatternCreate");
|
|
_FcPatternDestroy = (void (*)(FcPattern *))
|
|
dlsym(libfontconfig,"FcPatternDestroy");
|
|
_FcPatternAddDouble = (FcBool (*)(FcPattern *,const char *,double))
|
|
dlsym(libfontconfig,"FcPatternAddDouble");
|
|
_FcPatternAddInteger = (FcBool (*)(FcPattern *,const char *,int))
|
|
dlsym(libfontconfig,"FcPatternAddInteger");
|
|
_FcPatternAddString = (FcBool (*)(FcPattern *,const char *,const char *))
|
|
dlsym(libfontconfig,"FcPatternAddString");
|
|
_FcFontRenderPrepare = (FcPattern *(*)(FcConfig *, FcPattern *,FcPattern *))
|
|
dlsym(libfontconfig,"FcFontRenderPrepare");
|
|
_FcConfigSubstitute = (FcBool (*)(FcConfig *, FcPattern *,FcMatchKind))
|
|
dlsym(libfontconfig,"FcConfigSubstitute");
|
|
_FcDefaultSubstitute = (void (*)(FcPattern *))
|
|
dlsym(libfontconfig,"FcDefaultSubstitute");
|
|
_FcFontSort = (FcFontSet *(*)(FcConfig *,FcPattern *,FcBool,FcCharSet **,FcResult *))
|
|
dlsym(libfontconfig,"FcFontSort");
|
|
_FcPatternGetCharSet = (FcResult (*)(FcPattern *,const char *,int,FcCharSet **))
|
|
dlsym(libfontconfig,"FcPatternGetCharSet");
|
|
if ( _FcFontSort==NULL || _FcConfigSubstitute==NULL )
|
|
return( 0 );
|
|
|
|
|
|
libcairo = dlopen("libcairo" SO_EXT,RTLD_LAZY);
|
|
#ifdef SO_2_EXT
|
|
if ( libcairo==NULL )
|
|
libcairo = dlopen("libcairo" SO_2_EXT,RTLD_LAZY);
|
|
#endif
|
|
if ( libcairo==NULL ) {
|
|
fprintf(stderr,"libcairo: %s\n", dlerror());
|
|
return( 0 );
|
|
}
|
|
|
|
_cairo_xlib_surface_create = (cairo_surface_t *(*)(Display *,Drawable,Visual*,int,int))
|
|
dlsym(libcairo,"cairo_xlib_surface_create");
|
|
_cairo_create = (cairo_t *(*)(cairo_surface_t *))
|
|
dlsym(libcairo,"cairo_create");
|
|
_cairo_destroy = (void (*)(cairo_t *))
|
|
dlsym(libcairo,"cairo_destroy");
|
|
_cairo_surface_destroy = (void (*)(cairo_surface_t *))
|
|
dlsym(libcairo,"cairo_surface_destroy");
|
|
_cairo_xlib_surface_set_size = (void (*)(cairo_surface_t *,int,int))
|
|
dlsym(libcairo,"cairo_xlib_surface_set_size");
|
|
_cairo_set_line_width = (void (*)(cairo_t *, double))
|
|
dlsym(libcairo,"cairo_set_line_width");
|
|
_cairo_set_line_cap = (void (*)(cairo_t *, cairo_line_cap_t))
|
|
dlsym(libcairo,"cairo_set_line_cap");
|
|
_cairo_set_line_join = (void (*)(cairo_t *, cairo_line_join_t))
|
|
dlsym(libcairo,"cairo_set_line_join");
|
|
_cairo_set_operator = (void (*)(cairo_t *, cairo_operator_t))
|
|
dlsym(libcairo,"cairo_set_operator");
|
|
_cairo_set_dash = (void (*)(cairo_t *, double *, int, double))
|
|
dlsym(libcairo,"cairo_set_dash");
|
|
_cairo_set_source_rgba = (void (*)(cairo_t *,double,double,double,double))
|
|
dlsym(libcairo,"cairo_set_source_rgba");
|
|
_cairo_new_path = (void (*)(cairo_t *))
|
|
dlsym(libcairo,"cairo_new_path");
|
|
_cairo_move_to = (void (*)(cairo_t *,double,double))
|
|
dlsym(libcairo,"cairo_move_to");
|
|
_cairo_line_to = (void (*)(cairo_t *,double,double))
|
|
dlsym(libcairo,"cairo_line_to");
|
|
_cairo_curve_to = (void (*)(cairo_t *,double,double,double,double,double,double))
|
|
dlsym(libcairo,"cairo_curve_to");
|
|
_cairo_rectangle = (void (*)(cairo_t *,double,double,double,double))
|
|
dlsym(libcairo,"cairo_rectangle");
|
|
_cairo_close_path = (void (*)(cairo_t *))
|
|
dlsym(libcairo,"cairo_close_path");
|
|
_cairo_stroke = (void (*)(cairo_t *))
|
|
dlsym(libcairo,"cairo_stroke");
|
|
_cairo_fill = (void (*)(cairo_t *))
|
|
dlsym(libcairo,"cairo_fill");
|
|
_cairo_fill_preserve = (void (*)(cairo_t *))
|
|
dlsym(libcairo,"cairo_fill_preserve");
|
|
_cairo_clip = (void (*)(cairo_t *))
|
|
dlsym(libcairo,"cairo_clip");
|
|
_cairo_save = (void (*)(cairo_t *))
|
|
dlsym(libcairo,"cairo_save");
|
|
_cairo_restore = (void (*)(cairo_t *))
|
|
dlsym(libcairo,"cairo_restore");
|
|
_cairo_scaled_font_extents = (void (*)(cairo_scaled_font_t *,cairo_font_extents_t *))
|
|
dlsym(libcairo,"cairo_scaled_font_extents");
|
|
_cairo_scaled_font_text_extents = (void (*)(cairo_scaled_font_t *,const char *,cairo_text_extents_t *))
|
|
dlsym(libcairo,"cairo_scaled_font_text_extents");
|
|
_cairo_set_scaled_font = (void (*)(cairo_t *,const cairo_scaled_font_t *))
|
|
dlsym(libcairo,"cairo_set_scaled_font");
|
|
_cairo_show_text = (void (*)(cairo_t *,const char *))
|
|
dlsym(libcairo,"cairo_show_text");
|
|
_cairo_scaled_font_create = (cairo_scaled_font_t *(*)(cairo_font_face_t *, const cairo_matrix_t *, const cairo_matrix_t *, const cairo_font_options_t *))
|
|
dlsym(libcairo,"cairo_scaled_font_create");
|
|
_cairo_ft_font_face_create_for_pattern = (cairo_font_face_t *(*)(FcPattern *))
|
|
dlsym(libcairo,"cairo_ft_font_face_create_for_pattern");
|
|
_cairo_set_source_surface = (void (*)(cairo_t *,cairo_surface_t *,double,double))
|
|
dlsym(libcairo,"cairo_set_source_surface");
|
|
_cairo_mask_surface = (void (*)(cairo_t *,cairo_surface_t *,double,double))
|
|
dlsym(libcairo,"cairo_mask_surface");
|
|
_cairo_scale = (void (*)(cairo_t *,double,double))
|
|
dlsym(libcairo,"cairo_scale");
|
|
_cairo_translate = (void (*)(cairo_t *,double,double))
|
|
dlsym(libcairo,"cairo_translate");
|
|
_cairo_image_surface_get_format = (cairo_format_t (*)(cairo_surface_t *))
|
|
dlsym(libcairo,"cairo_image_surface_get_format");
|
|
_cairo_image_surface_create_for_data = (cairo_surface_t *(*)(unsigned char *,cairo_format_t,int,int,int))
|
|
dlsym(libcairo,"cairo_image_surface_create_for_data");
|
|
_cairo_format_stride_for_width = (int (*)(cairo_format_t,int))
|
|
dlsym(libcairo,"cairo_format_stride_for_width");
|
|
_cairo_font_options_create = (cairo_font_options_t *(*)(void))
|
|
dlsym(libcairo,"cairo_font_options_create");
|
|
_cairo_surface_flush = (void (*)(cairo_surface_t *))
|
|
dlsym(libcairo,"cairo_surface_flush");
|
|
_cairo_surface_mark_dirty_rectangle = (void (*)(cairo_surface_t *,double,double,double,double))
|
|
dlsym(libcairo,"cairo_surface_mark_dirty_rectangle");
|
|
_cairo_pattern_create_for_surface = (cairo_pattern_t *(*)(cairo_surface_t *))
|
|
dlsym(libcairo,"cairo_pattern_create_for_surface");
|
|
_cairo_pattern_destroy = (void (*)(cairo_pattern_t *))
|
|
dlsym(libcairo,"cairo_pattern_destroy");
|
|
_cairo_pattern_set_extend = (void (*)(cairo_pattern_t *,cairo_extend_t))
|
|
dlsym(libcairo,"cairo_pattern_set_extend");
|
|
_cairo_set_source = (void (*)(cairo_t *, cairo_pattern_t *))
|
|
dlsym(libcairo,"cairo_set_source");
|
|
_cairo_push_group = (void (*)(cairo_t *))
|
|
dlsym(libcairo,"cairo_push_group");
|
|
_cairo_pop_group_to_source = (void (*)(cairo_t *))
|
|
dlsym(libcairo,"cairo_pop_group_to_source");
|
|
_cairo_get_group_target = (cairo_surface_t *(*)(cairo_t *))
|
|
dlsym(libcairo,"cairo_get_group_target");
|
|
_cairo_paint = (void (*)(cairo_t *))
|
|
dlsym(libcairo,"cairo_paint");
|
|
|
|
/* Didn't show up until 1.6, and I've got 1.2 on my machine */
|
|
if ( _cairo_format_stride_for_width==NULL )
|
|
_cairo_format_stride_for_width = __cairo_format_stride_for_width;
|
|
|
|
if ( _cairo_xlib_surface_create==NULL || _cairo_create==NULL ) {
|
|
fprintf(stderr,"libcairo: Missing symbols\n" );
|
|
return( 0 );
|
|
}
|
|
if ( _cairo_scaled_font_text_extents==NULL ) {
|
|
fprintf(stderr,"libcairo: FontForge needs at least version 1.2\n" );
|
|
return( 0 );
|
|
}
|
|
|
|
hasC = true;
|
|
return( true );
|
|
}
|
|
# else
|
|
# define _cairo_xlib_surface_create cairo_xlib_surface_create
|
|
# define _cairo_create cairo_create
|
|
# define _cairo_xlib_surface_set_size cairo_xlib_surface_set_size
|
|
# define _cairo_destroy cairo_destroy
|
|
# define _cairo_surface_destroy cairo_surface_destroy
|
|
# define _cairo_set_line_width cairo_set_line_width
|
|
# define _cairo_set_line_cap cairo_set_line_cap
|
|
# define _cairo_set_line_join cairo_set_line_join
|
|
# define _cairo_set_operator cairo_set_operator
|
|
# define _cairo_set_dash cairo_set_dash
|
|
# define _cairo_set_source_rgba cairo_set_source_rgba
|
|
# define _cairo_new_path cairo_new_path
|
|
# define _cairo_move_to cairo_move_to
|
|
# define _cairo_line_to cairo_line_to
|
|
# define _cairo_curve_to cairo_curve_to
|
|
# define _cairo_rectangle cairo_rectangle
|
|
# define _cairo_close_path cairo_close_path
|
|
# define _cairo_stroke cairo_stroke
|
|
# define _cairo_fill cairo_fill
|
|
# define _cairo_fill_preserve cairo_fill_preserve
|
|
# define _cairo_clip cairo_clip
|
|
# define _cairo_save cairo_save
|
|
# define _cairo_restore cairo_restore
|
|
# define _cairo_scaled_font_extents cairo_scaled_font_extents
|
|
# define _cairo_scaled_font_text_extents cairo_scaled_font_text_extents
|
|
# define _cairo_set_scaled_font cairo_set_scaled_font
|
|
# define _cairo_show_text cairo_show_text
|
|
# define _cairo_scaled_font_create cairo_scaled_font_create
|
|
# define _cairo_set_source_surface cairo_set_source_surface
|
|
# define _cairo_mask_surface cairo_mask_surface
|
|
# define _cairo_scale cairo_scale
|
|
# define _cairo_translate cairo_translate
|
|
# define _cairo_image_surface_create_for_data cairo_image_surface_create_for_data
|
|
# define _cairo_image_surface_get_format cairo_image_surface_get_format
|
|
# if CAIRO_VERSION_MAJOR==1 && CAIRO_VERSION_MINOR>=6
|
|
# define _cairo_format_stride_for_width cairo_format_stride_for_width
|
|
# else
|
|
# define _cairo_format_stride_for_width __cairo_format_stride_for_width
|
|
#endif
|
|
# define _cairo_ft_font_face_create_for_pattern cairo_ft_font_face_create_for_pattern
|
|
# define _cairo_font_options_create cairo_font_options_create
|
|
# define _cairo_surface_flush cairo_surface_flush
|
|
# define _cairo_surface_mark_dirty_rectangle cairo_surface_mark_dirty_rectangle
|
|
# define _cairo_pattern_create_for_surface cairo_pattern_create_for_surface
|
|
# define _cairo_pattern_set_extend cairo_pattern_set_extend
|
|
# define _cairo_pattern_destroy cairo_pattern_destroy
|
|
# define _cairo_set_source cairo_set_source
|
|
# define _cairo_push_group cairo_push_group
|
|
# define _cairo_pop_group_to_source cairo_pop_group_to_source
|
|
# define _cairo_get_group_target cairo_get_group_target
|
|
# define _cairo_paint cairo_paint
|
|
|
|
# define _FcCharSetHasChar FcCharSetHasChar
|
|
# define _FcPatternDestroy FcPatternDestroy
|
|
# define _FcPatternAddDouble FcPatternAddDouble
|
|
# define _FcPatternAddInteger FcPatternAddInteger
|
|
# define _FcPatternAddString FcPatternAddString
|
|
# define _FcFontRenderPrepare FcFontRenderPrepare
|
|
# define _FcConfigSubstitute FcConfigSubstitute
|
|
# define _FcDefaultSubstitute FcDefaultSubstitute
|
|
# define _FcFontSort FcFontSort
|
|
# define _FcPatternGetCharSet FcPatternGetCharSet
|
|
# define _FcPatternCreate FcPatternCreate
|
|
|
|
int _GXCDraw_hasCairo(void) {
|
|
int initted = false, hasC;
|
|
if ( !usecairo )
|
|
return( false );
|
|
if ( !initted )
|
|
hasC = FcInit();
|
|
return( hasC );
|
|
}
|
|
# endif
|
|
|
|
/* ************************************************************************** */
|
|
/* ****************************** Cairo Window ****************************** */
|
|
/* ************************************************************************** */
|
|
void _GXCDraw_NewWindow(GXWindow nw,Color bg) {
|
|
GXDisplay *gdisp = nw->display;
|
|
Display *display = gdisp->display;
|
|
|
|
MacVersionTest();
|
|
if ( !usecairo || !_GXCDraw_hasCairo())
|
|
return;
|
|
|
|
nw->cs = _cairo_xlib_surface_create(display,nw->w,gdisp->visual,
|
|
nw->pos.width, nw->pos.height );
|
|
if ( nw->cs!=NULL ) {
|
|
nw->cc = _cairo_create(nw->cs);
|
|
if ( nw->cc!=NULL )
|
|
nw->usecairo = true;
|
|
else {
|
|
_cairo_surface_destroy(nw->cs);
|
|
nw->cs=NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
void _GXCDraw_ResizeWindow(GXWindow gw,GRect *rect) {
|
|
_cairo_xlib_surface_set_size( gw->cs, rect->width,rect->height);
|
|
}
|
|
|
|
void _GXCDraw_DestroyWindow(GXWindow gw) {
|
|
_cairo_destroy(gw->cc);
|
|
_cairo_surface_destroy(gw->cs);
|
|
gw->usecairo = false;
|
|
}
|
|
|
|
/* ************************************************************************** */
|
|
/* ******************************* Cairo State ****************************** */
|
|
/* ************************************************************************** */
|
|
static void GXCDraw_StippleMePink(GXWindow gw,int ts, Color fg) {
|
|
static unsigned char grey_init[8] = { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa };
|
|
static unsigned char fence_init[8] = { 0x55, 0x22, 0x55, 0x88, 0x55, 0x22, 0x55, 0x88};
|
|
uint8 *spt;
|
|
int bit,i,j;
|
|
uint32 *data;
|
|
static uint32 space[8*8];
|
|
static cairo_surface_t *is = NULL;
|
|
static cairo_pattern_t *pat = NULL;
|
|
|
|
if ( (fg>>24)!=0xff ) {
|
|
int alpha = fg>>24, r = COLOR_RED(fg), g=COLOR_GREEN(fg), b=COLOR_BLUE(fg);
|
|
r = (alpha*r+128)/255; g = (alpha*g+128)/255; b=(alpha*b+128)/255;
|
|
fg = (alpha<<24) | (r<<16) | (g<<8) | b;
|
|
}
|
|
|
|
spt = ts==2 ? fence_init : grey_init;
|
|
for ( i=0; i<8; ++i ) {
|
|
data = space+8*i;
|
|
for ( j=0, bit=0x80; bit!=0; ++j, bit>>=1 ) {
|
|
if ( spt[i]&bit )
|
|
data[j] = fg;
|
|
else
|
|
data[j] = 0;
|
|
}
|
|
}
|
|
if ( is==NULL ) {
|
|
is = _cairo_image_surface_create_for_data((uint8 *) space,CAIRO_FORMAT_ARGB32,
|
|
8,8,8*4);
|
|
pat = _cairo_pattern_create_for_surface(is);
|
|
_cairo_pattern_set_extend(pat,CAIRO_EXTEND_REPEAT);
|
|
}
|
|
_cairo_set_source(gw->cc,pat);
|
|
}
|
|
|
|
static int GXCDrawSetcolfunc(GXWindow gw, GGC *mine) {
|
|
/*GCState *gcs = &gw->cairo_state;*/
|
|
Color fg = mine->fg;
|
|
|
|
if ( (fg>>24 ) == 0 )
|
|
fg |= 0xff000000;
|
|
|
|
if ( mine->ts != 0 ) {
|
|
GXCDraw_StippleMePink(gw,mine->ts,fg);
|
|
} else {
|
|
_cairo_set_source_rgba(gw->cc,COLOR_RED(fg)/255.0,COLOR_GREEN(fg)/255.0,COLOR_BLUE(fg)/255.0,
|
|
(fg>>24)/255.);
|
|
}
|
|
#if 0
|
|
/* As far as I can tell, XOR doesn't work */
|
|
/* Or perhaps it is more accurate to say that I don't understand what xor does in cairo*/
|
|
if ( mine->func!=gcs->func || mine->func!=df_copy ) {
|
|
_cairo_set_operator( gw->cc,mine->func==df_copy?CAIRO_OPERATOR_OVER:CAIRO_OPERATOR_XOR );
|
|
gcs->func = mine->func;
|
|
}
|
|
if ( mine->func==df_xor )
|
|
fg ^= mine->xor_base;
|
|
#endif
|
|
return( true );
|
|
}
|
|
|
|
static int GXCDrawSetline(GXWindow gw, GGC *mine) {
|
|
GCState *gcs = &gw->cairo_state;
|
|
Color fg = mine->fg;
|
|
|
|
if ( ( fg>>24 ) == 0 )
|
|
fg |= 0xff000000;
|
|
|
|
#if 0
|
|
/* As far as I can tell, XOR doesn't work */
|
|
/* Or perhaps it is more accurate to say that I don't understand what xor does*/
|
|
if ( mine->func!=gcs->func || mine->func!=df_copy ) {
|
|
_cairo_set_operator( gw->cc, mine->func==df_copy?CAIRO_OPERATOR_OVER:CAIRO_OPERATOR_XOR);
|
|
gcs->func = mine->func;
|
|
}
|
|
if ( mine->func==df_xor )
|
|
fg ^= mine->xor_base;
|
|
#endif
|
|
if ( mine->line_width<=0 ) mine->line_width = 1;
|
|
if ( mine->line_width!=gcs->line_width || mine->line_width!=2 ) {
|
|
_cairo_set_line_width(gw->cc,mine->line_width);
|
|
gcs->line_width = mine->line_width;
|
|
}
|
|
if ( mine->dash_len != gcs->dash_len || mine->skip_len != gcs->skip_len ||
|
|
mine->dash_offset != gcs->dash_offset ) {
|
|
double dashes[2];
|
|
dashes[0] = mine->dash_len; dashes[1] = mine->skip_len;
|
|
_cairo_set_dash(gw->cc,dashes,0,mine->dash_offset);
|
|
gcs->dash_offset = mine->dash_offset;
|
|
gcs->dash_len = mine->dash_len;
|
|
gcs->skip_len = mine->skip_len;
|
|
}
|
|
/* I don't use line join/cap. On a screen with small line_width they are irrelevant */
|
|
|
|
if ( mine->ts != 0 ) {
|
|
GXCDraw_StippleMePink(gw,mine->ts,fg);
|
|
} else {
|
|
_cairo_set_source_rgba(gw->cc,COLOR_RED(fg)/255.0,COLOR_GREEN(fg)/255.0,COLOR_BLUE(fg)/255.0,
|
|
(fg>>24)/255.0);
|
|
}
|
|
return( mine->line_width );
|
|
}
|
|
|
|
void _GXCDraw_PushClip(GXWindow gw) {
|
|
_cairo_save(gw->cc);
|
|
_cairo_new_path(gw->cc);
|
|
_cairo_rectangle(gw->cc,gw->ggc->clip.x,gw->ggc->clip.y,gw->ggc->clip.width,gw->ggc->clip.height);
|
|
_cairo_clip(gw->cc);
|
|
}
|
|
|
|
void _GXCDraw_PopClip(GXWindow gw) {
|
|
_cairo_restore(gw->cc);
|
|
}
|
|
|
|
/* ************************************************************************** */
|
|
/* ***************************** Cairo Drawing ****************************** */
|
|
/* ************************************************************************** */
|
|
void _GXCDraw_Clear(GXWindow gw, GRect *rect) {
|
|
GRect *r = rect, temp;
|
|
if ( r==NULL ) {
|
|
temp = gw->pos;
|
|
temp.x = temp.y = 0;
|
|
r = &temp;
|
|
}
|
|
_cairo_new_path(gw->cc);
|
|
_cairo_rectangle(gw->cc,r->x,r->y,r->width,r->height);
|
|
_cairo_set_source_rgba(gw->cc,COLOR_RED(gw->ggc->bg)/255.0,COLOR_GREEN(gw->ggc->bg)/255.0,COLOR_BLUE(gw->ggc->bg)/255.0,
|
|
1.0);
|
|
_cairo_fill(gw->cc);
|
|
}
|
|
|
|
void _GXCDraw_DrawLine(GXWindow gw, int32 x,int32 y, int32 xend,int32 yend) {
|
|
int width = GXCDrawSetline(gw,gw->ggc);
|
|
|
|
_cairo_new_path(gw->cc);
|
|
if ( width&1 ) {
|
|
_cairo_move_to(gw->cc,x+.5,y+.5);
|
|
_cairo_line_to(gw->cc,xend+.5,yend+.5);
|
|
} else {
|
|
_cairo_move_to(gw->cc,x,y);
|
|
_cairo_line_to(gw->cc,xend,yend);
|
|
}
|
|
_cairo_stroke(gw->cc);
|
|
}
|
|
|
|
void _GXCDraw_DrawRect(GXWindow gw, GRect *rect) {
|
|
int width = GXCDrawSetline(gw,gw->ggc);
|
|
|
|
_cairo_new_path(gw->cc);
|
|
if ( width&1 ) {
|
|
_cairo_rectangle(gw->cc,rect->x+.5,rect->y+.5,rect->width,rect->height);
|
|
} else {
|
|
_cairo_rectangle(gw->cc,rect->x,rect->y,rect->width,rect->height);
|
|
}
|
|
_cairo_stroke(gw->cc);
|
|
}
|
|
|
|
void _GXCDraw_FillRect(GXWindow gw, GRect *rect) {
|
|
GXCDrawSetcolfunc(gw,gw->ggc);
|
|
|
|
_cairo_new_path(gw->cc);
|
|
_cairo_rectangle(gw->cc,rect->x,rect->y,rect->width,rect->height);
|
|
_cairo_fill(gw->cc);
|
|
}
|
|
|
|
static void GXCDraw_EllipsePath(cairo_t *cc,double cx,double cy,double width,double height) {
|
|
_cairo_new_path(cc);
|
|
_cairo_move_to(cc,cx,cy+height);
|
|
_cairo_curve_to(cc,
|
|
cx+.552*width,cy+height,
|
|
cx+width,cy+.552*height,
|
|
cx+width,cy);
|
|
_cairo_curve_to(cc,
|
|
cx+width,cy-.552*height,
|
|
cx+.552*width,cy-height,
|
|
cx,cy-height);
|
|
_cairo_curve_to(cc,
|
|
cx-.552*width,cy-height,
|
|
cx-width,cy-.552*height,
|
|
cx-width,cy);
|
|
_cairo_curve_to(cc,
|
|
cx-width,cy+.552*height,
|
|
cx-.552*width,cy+height,
|
|
cx,cy+height);
|
|
_cairo_close_path(cc);
|
|
}
|
|
|
|
void _GXCDraw_DrawEllipse(GXWindow gw, GRect *rect) {
|
|
/* It is tempting to use the cairo arc command and scale the */
|
|
/* coordinates to get an elipse, but that distorts the stroke width */
|
|
int lwidth = GXCDrawSetline(gw,gw->ggc);
|
|
double cx, cy, width, height;
|
|
|
|
width = rect->width/2.0; height = rect->height/2.0;
|
|
cx = rect->x + width;
|
|
cy = rect->y + height;
|
|
if ( lwidth&1 ) {
|
|
if ( rint(width)==width )
|
|
cx += .5;
|
|
if ( rint(height)==height )
|
|
cy += .5;
|
|
}
|
|
GXCDraw_EllipsePath(gw->cc,cx,cy,width,height);
|
|
_cairo_stroke(gw->cc);
|
|
}
|
|
|
|
void _GXCDraw_FillEllipse(GXWindow gw, GRect *rect) {
|
|
/* It is tempting to use the cairo arc command and scale the */
|
|
/* coordinates to get an elipse, but that distorts the stroke width */
|
|
double cx, cy, width, height;
|
|
|
|
GXCDrawSetcolfunc(gw,gw->ggc);
|
|
|
|
width = rect->width/2.0; height = rect->height/2.0;
|
|
cx = rect->x + width;
|
|
cy = rect->y + height;
|
|
GXCDraw_EllipsePath(gw->cc,cx,cy,width,height);
|
|
_cairo_fill(gw->cc);
|
|
}
|
|
|
|
void _GXCDraw_DrawPoly(GXWindow gw, GPoint *pts, int16 cnt) {
|
|
int width = GXCDrawSetline(gw,gw->ggc);
|
|
double off = width&1 ? .5 : 0;
|
|
int i;
|
|
|
|
_cairo_new_path(gw->cc);
|
|
_cairo_move_to(gw->cc,pts[0].x+off,pts[0].y+off);
|
|
for ( i=1; i<cnt; ++i )
|
|
_cairo_line_to(gw->cc,pts[i].x+off,pts[i].y+off);
|
|
_cairo_stroke(gw->cc);
|
|
}
|
|
|
|
void _GXCDraw_FillPoly(GXWindow gw, GPoint *pts, int16 cnt) {
|
|
GXCDrawSetcolfunc(gw,gw->ggc);
|
|
int i;
|
|
|
|
_cairo_new_path(gw->cc);
|
|
_cairo_move_to(gw->cc,pts[0].x,pts[0].y);
|
|
for ( i=1; i<cnt; ++i )
|
|
_cairo_line_to(gw->cc,pts[i].x,pts[i].y);
|
|
_cairo_close_path(gw->cc);
|
|
_cairo_fill(gw->cc);
|
|
|
|
_cairo_set_line_width(gw->cc,1);
|
|
_cairo_new_path(gw->cc);
|
|
_cairo_move_to(gw->cc,pts[0].x+.5,pts[0].y+.5);
|
|
for ( i=1; i<cnt; ++i )
|
|
_cairo_line_to(gw->cc,pts[i].x+.5,pts[i].y+.5);
|
|
_cairo_close_path(gw->cc);
|
|
_cairo_stroke(gw->cc);
|
|
}
|
|
|
|
/* ************************************************************************** */
|
|
/* ****************************** Cairo Paths ******************************* */
|
|
/* ************************************************************************** */
|
|
void _GXCDraw_PathStartNew(GWindow w) {
|
|
_cairo_new_path( ((GXWindow) w)->cc );
|
|
}
|
|
|
|
void _GXCDraw_PathClose(GWindow w) {
|
|
_cairo_close_path( ((GXWindow) w)->cc );
|
|
}
|
|
|
|
void _GXCDraw_PathMoveTo(GWindow w,double x, double y) {
|
|
_cairo_move_to( ((GXWindow) w)->cc,x,y );
|
|
}
|
|
|
|
void _GXCDraw_PathLineTo(GWindow w,double x, double y) {
|
|
_cairo_line_to( ((GXWindow) w)->cc,x,y );
|
|
}
|
|
|
|
void _GXCDraw_PathCurveTo(GWindow w,
|
|
double cx1, double cy1,
|
|
double cx2, double cy2,
|
|
double x, double y) {
|
|
_cairo_curve_to( ((GXWindow) w)->cc,cx1,cy1,cx2,cy2,x,y );
|
|
}
|
|
|
|
void _GXCDraw_PathStroke(GWindow w,Color col) {
|
|
w->ggc->fg = col;
|
|
GXCDrawSetline((GXWindow) w,w->ggc);
|
|
_cairo_stroke( ((GXWindow) w)->cc );
|
|
}
|
|
|
|
void _GXCDraw_PathFill(GWindow w,Color col) {
|
|
_cairo_set_source_rgba(((GXWindow) w)->cc,COLOR_RED(col)/255.0,COLOR_GREEN(col)/255.0,COLOR_BLUE(col)/255.0,
|
|
(col>>24)/255.0);
|
|
_cairo_fill( ((GXWindow) w)->cc );
|
|
}
|
|
|
|
void _GXCDraw_PathFillAndStroke(GWindow w,Color fillcol, Color strokecol) {
|
|
GXWindow gw = (GXWindow) w;
|
|
|
|
_cairo_save(gw->cc);
|
|
_cairo_set_source_rgba(gw->cc,COLOR_RED(fillcol)/255.0,COLOR_GREEN(fillcol)/255.0,COLOR_BLUE(fillcol)/255.0,
|
|
(fillcol>>24)/255.0);
|
|
_cairo_fill( gw->cc );
|
|
_cairo_restore(gw->cc);
|
|
w->ggc->fg = strokecol;
|
|
GXCDrawSetline(gw,gw->ggc);
|
|
_cairo_fill( gw->cc );
|
|
}
|
|
|
|
/* ************************************************************************** */
|
|
/* *************************** Cairo Text & Fonts *************************** */
|
|
/* ************************************************************************** */
|
|
|
|
static int indexOfChar(GFont *font,unichar_t ch,int last_index) {
|
|
int new_index = -1, i;
|
|
|
|
if ( last_index>=0 && last_index<font->ordered->nfont ) {
|
|
if ( _FcCharSetHasChar(font->cscf[last_index].cs,ch) )
|
|
new_index = last_index;
|
|
}
|
|
if ( new_index==-1 ) {
|
|
for ( i=0; i<font->ordered->nfont; ++i ) if ( i!=last_index ) {
|
|
if ( _FcCharSetHasChar(font->cscf[i].cs,ch) ) {
|
|
new_index = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ( new_index!=-1 && font->cscf[new_index].cf==NULL ) {
|
|
FcPattern *onefont;
|
|
cairo_matrix_t fm, cm;
|
|
static cairo_font_options_t *def=NULL;
|
|
|
|
if ( def==NULL ) /* Docs claim this isn't needed. Docs appear wrong */
|
|
def = _cairo_font_options_create();
|
|
|
|
onefont = _FcFontRenderPrepare(NULL,font->pat,font->ordered->fonts[new_index]);
|
|
#if 0
|
|
{ double ps, pre=-1;
|
|
FcPatternGetDouble(onefont,FC_PIXEL_SIZE,0,&ps);
|
|
FcPatternGetDouble(font->ordered->fonts[new_index],FC_PIXEL_SIZE,0,&pre);
|
|
printf( "Pixel size desired=%d, pre=%g, in font=%g\n", font->pixelsize, pre, ps );
|
|
}
|
|
#endif
|
|
|
|
memset(&fm,0,sizeof(fm)); memset(&cm,0,sizeof(cm));
|
|
fm.xx = fm.yy = font->pixelsize;
|
|
cm.xx = cm.yy = 1;
|
|
font->cscf[new_index].cf = _cairo_scaled_font_create(
|
|
_cairo_ft_font_face_create_for_pattern(onefont),
|
|
&fm,&cm,def );
|
|
/*_FcPatternDestroy(onefont);*/
|
|
}
|
|
return( new_index );
|
|
}
|
|
|
|
static void configfont(GFont *font) {
|
|
FcPattern *pat;
|
|
int pixel_size;
|
|
FcResult retval;
|
|
int i;
|
|
static unichar_t replacements[] = { 0xfffd, 0xfffc, '?', 0 };
|
|
|
|
if ( font->ordered!=NULL )
|
|
return;
|
|
|
|
pat = _FcPatternCreate();
|
|
_FcPatternAddDouble(pat,FC_DPI,GDrawPointsToPixels(NULL,72));
|
|
if ( font->rq.point_size>0 ) {
|
|
_FcPatternAddDouble(pat,FC_SIZE,font->rq.point_size);
|
|
pixel_size = GDrawPointsToPixels(NULL,font->rq.point_size);
|
|
} else {
|
|
_FcPatternAddDouble(pat,FC_PIXEL_SIZE,-font->rq.point_size);
|
|
pixel_size = -font->rq.point_size;
|
|
}
|
|
|
|
if ( font->rq.style&fs_italic )
|
|
_FcPatternAddInteger(pat,FC_SLANT,FC_SLANT_ITALIC);
|
|
else
|
|
_FcPatternAddInteger(pat,FC_SLANT,FC_SLANT_ROMAN);
|
|
|
|
if ( font->rq.weight<=200 )
|
|
_FcPatternAddInteger(pat,FC_WEIGHT,FC_WEIGHT_LIGHT);
|
|
else if ( font->rq.weight<=400 )
|
|
_FcPatternAddInteger(pat,FC_WEIGHT,FC_WEIGHT_LIGHT+
|
|
((font->rq.weight-200)/(400-200)) * (FC_WEIGHT_MEDIUM-FC_WEIGHT_LIGHT));
|
|
else if ( font->rq.weight<=600 )
|
|
_FcPatternAddInteger(pat,FC_WEIGHT,FC_WEIGHT_MEDIUM+
|
|
((font->rq.weight-400)/(600-400)) * (FC_WEIGHT_DEMIBOLD-FC_WEIGHT_MEDIUM));
|
|
else if ( font->rq.weight<=700 )
|
|
_FcPatternAddInteger(pat,FC_WEIGHT,FC_WEIGHT_DEMIBOLD+
|
|
((font->rq.weight-600)/(700-600)) * (FC_WEIGHT_BOLD-FC_WEIGHT_DEMIBOLD));
|
|
else if ( font->rq.weight<=900 )
|
|
_FcPatternAddInteger(pat,FC_WEIGHT,FC_WEIGHT_BOLD+
|
|
((font->rq.weight-700)/(900-700)) * (FC_WEIGHT_BLACK-FC_WEIGHT_BOLD));
|
|
else
|
|
_FcPatternAddInteger(pat,FC_WEIGHT,FC_WEIGHT_BLACK);
|
|
|
|
if ( font->rq.utf8_family_name != NULL ) {
|
|
char *start, *end;
|
|
for ( start=font->rq.utf8_family_name; *start; start=end ) {
|
|
for ( end=start; *end!='\0' && *end!=',' ; ++end );
|
|
_FcPatternAddString(pat,FC_FAMILY,copyn(start,end-start));
|
|
while ( *end==',' ) ++end;
|
|
}
|
|
} else {
|
|
const unichar_t *start, *end;
|
|
for ( start=font->rq.family_name; *start; start=end ) {
|
|
for ( end=start; *end!='\0' && *end!=',' ; ++end );
|
|
_FcPatternAddString(pat,FC_FAMILY,u2utf8_copyn(start,end-start));
|
|
while ( *end==',' ) ++end;
|
|
}
|
|
}
|
|
|
|
_FcConfigSubstitute(NULL,pat,FcMatchPattern);
|
|
_FcDefaultSubstitute(pat);
|
|
font->ordered = _FcFontSort(NULL,pat,true,NULL,&retval);
|
|
font->pat = pat;
|
|
font->pixelsize = pixel_size;
|
|
font->replacement_index = -1;
|
|
if ( font->ordered!=NULL ) {
|
|
font->cscf = gcalloc(font->ordered->nfont,sizeof(struct charset_cairofont));
|
|
for ( i=0; i<font->ordered->nfont; ++i )
|
|
_FcPatternGetCharSet(font->ordered->fonts[i],FC_CHARSET,0,
|
|
&font->cscf[i].cs);
|
|
for ( i=0; replacements[i]!=0 ; ++i ) {
|
|
font->replacement_char = replacements[i];
|
|
font->replacement_index = indexOfChar(font,replacements[i],-1);
|
|
if ( font->replacement_index!=-1 )
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void _GXCDraw_FontMetrics(GXWindow gw,GFont *fi,int *as, int *ds, int *ld) {
|
|
int index;
|
|
|
|
if ( fi->ordered==NULL )
|
|
configfont(fi);
|
|
if ( fi->ordered==NULL ) {
|
|
*as = *ds = *ld = -1;
|
|
return;
|
|
}
|
|
index = indexOfChar(fi,'A',-1);
|
|
if ( index==-1 )
|
|
index = fi->replacement_index;
|
|
if ( index==-1 )
|
|
*as = *ds = *ld = -1;
|
|
else {
|
|
cairo_font_extents_t bounds;
|
|
_cairo_scaled_font_extents(fi->cscf[index].cf,&bounds);
|
|
*as = rint(bounds.ascent);
|
|
*ds = rint(bounds.descent);
|
|
*ld = rint(bounds.height-(bounds.ascent+bounds.descent));
|
|
}
|
|
}
|
|
|
|
int32 _GXCDraw_DoText8(GWindow w, int32 x, int32 y,
|
|
const char *text, int32 cnt, FontMods *mods, Color col,
|
|
enum text_funcs drawit, struct tf_arg *arg) {
|
|
GXWindow gw = (GXWindow) w;
|
|
const char *end = text+(cnt<0?strlen(text):cnt);
|
|
struct font_instance *fi = gw->ggc->fi;
|
|
const char *start, *pt, *last_good;
|
|
uint32 ch;
|
|
int index, last_index;
|
|
char outbuffer[100], *outpt, *outend;
|
|
cairo_text_extents_t ct;
|
|
cairo_font_extents_t bounds;
|
|
|
|
if ( fi->ordered==NULL )
|
|
configfont(fi);
|
|
if ( fi->ordered==NULL )
|
|
return( x );
|
|
|
|
if ( drawit==tf_drawit ) {
|
|
gw->ggc->fg = col;
|
|
GXCDrawSetcolfunc(gw,gw->ggc);
|
|
_cairo_move_to(gw->cc,x,y);
|
|
}
|
|
|
|
for ( start = text; start<end; ) {
|
|
pt = start;
|
|
ch = utf8_ildb(&pt);
|
|
if ( ch<=0 )
|
|
break;
|
|
outpt = outbuffer; outend = outpt+100-5;
|
|
last_index = indexOfChar(fi,ch,-1);
|
|
if ( last_index==-1 ) {
|
|
last_index = fi->replacement_index;
|
|
if ( last_index!=-1 )
|
|
outpt = utf8_idpb(outpt,fi->replacement_char);
|
|
last_good = pt;
|
|
} else {
|
|
outpt = utf8_idpb(outpt,ch);
|
|
last_good = pt;
|
|
if ( drawit==tf_width || drawit==tf_drawit || drawit==tf_rect )
|
|
/* Stopat functions should examine each glyph drawn */
|
|
while ( pt<end && outpt<=outend ) {
|
|
ch = utf8_ildb((const char **) &pt);
|
|
if ( ch<=0 )
|
|
break;
|
|
index = indexOfChar(fi,ch,last_index);
|
|
if ( index!=last_index )
|
|
break;
|
|
outpt = utf8_idpb(outpt,ch);
|
|
last_good = pt;
|
|
}
|
|
}
|
|
if ( last_index!=-1 ) {
|
|
*outpt++ = '\0';
|
|
_cairo_scaled_font_text_extents(fi->cscf[last_index].cf,outbuffer,&ct);
|
|
switch ( drawit ) {
|
|
case tf_width:
|
|
/* We just need to increment x, which happens at the end */;
|
|
break;
|
|
case tf_drawit:
|
|
_cairo_set_scaled_font(gw->cc,fi->cscf[last_index].cf);
|
|
_cairo_show_text(gw->cc,outbuffer);
|
|
break;
|
|
case tf_rect:
|
|
if ( x==0 )
|
|
arg->size.lbearing = x+ct.x_bearing;
|
|
arg->size.rbearing = x+ct.width;
|
|
_cairo_scaled_font_extents(fi->cscf[last_index].cf,&bounds);
|
|
if ( arg->size.fas<bounds.ascent )
|
|
arg->size.fas = bounds.ascent;
|
|
if ( arg->size.fds<bounds.descent )
|
|
arg->size.fds = bounds.descent;
|
|
if ( arg->size.as<-ct.y_bearing )
|
|
arg->size.as = -ct.y_bearing;
|
|
if ( arg->size.ds<ct.height+ct.y_bearing )
|
|
arg->size.ds = ct.height+ct.y_bearing;
|
|
arg->size.width += ct.x_advance;
|
|
break;
|
|
case tf_stopat:
|
|
if ( x+ct.x_advance < arg->maxwidth )
|
|
/* Do Nothing here */;
|
|
else if ( x+ct.x_advance/2 >= arg->maxwidth ) {
|
|
arg->utf8_last = (char *) start;
|
|
arg->width = x;
|
|
return( x );
|
|
} else {
|
|
arg->utf8_last = (char *) pt;
|
|
x += ct.x_advance;
|
|
arg->width = x;
|
|
return( x );
|
|
}
|
|
break;
|
|
case tf_stopbefore:
|
|
if ( x+ct.x_advance >= arg->maxwidth ) {
|
|
arg->utf8_last = (char *) start;
|
|
arg->width = x;
|
|
return( x );
|
|
}
|
|
break;
|
|
case tf_stopafter:
|
|
if ( x+ct.x_advance >= arg->maxwidth ) {
|
|
arg->utf8_last = (char *) pt;
|
|
x += ct.x_advance;
|
|
arg->width = x;
|
|
return( x );
|
|
}
|
|
break;
|
|
}
|
|
x += ct.x_advance;
|
|
}
|
|
start = last_good;
|
|
}
|
|
return( x );
|
|
}
|
|
|
|
int32 _GXCDraw_DoText(GWindow w, int32 x, int32 y,
|
|
const unichar_t *text, int32 cnt, FontMods *mods, Color col,
|
|
enum text_funcs drawit, struct tf_arg *arg) {
|
|
GXWindow gw = (GXWindow) w;
|
|
const unichar_t *end = text+(cnt<0?u_strlen(text):cnt);
|
|
struct font_instance *fi = gw->ggc->fi;
|
|
const unichar_t *start, *pt, *last_good;
|
|
uint32 ch;
|
|
int index, last_index;
|
|
char outbuffer[100], *outpt, *outend;
|
|
cairo_text_extents_t ct;
|
|
cairo_font_extents_t bounds;
|
|
|
|
if ( fi->ordered==NULL )
|
|
configfont(fi);
|
|
if ( fi->ordered==NULL )
|
|
return( x );
|
|
|
|
if ( drawit==tf_drawit ) {
|
|
gw->ggc->fg = col;
|
|
GXCDrawSetcolfunc(gw,gw->ggc);
|
|
_cairo_move_to(gw->cc,x,y);
|
|
}
|
|
|
|
for ( start = text; start<end; ) {
|
|
pt = start;
|
|
ch = *pt++;
|
|
if ( ch<=0 )
|
|
break;
|
|
outpt = outbuffer; outend = outpt+100-5;
|
|
last_index = indexOfChar(fi,ch,-1);
|
|
if ( last_index==-1 ) {
|
|
last_index = fi->replacement_index;
|
|
if ( last_index!=-1 )
|
|
outpt = utf8_idpb(outpt,fi->replacement_char);
|
|
last_good = pt;
|
|
} else {
|
|
outpt = utf8_idpb(outpt,ch);
|
|
last_good = pt;
|
|
if ( drawit==tf_width || drawit==tf_drawit || drawit==tf_rect )
|
|
/* Stopat functions should examine each glyph drawn */
|
|
while ( pt<end && outpt<=outend ) {
|
|
ch = *pt++;
|
|
if ( ch<=0 )
|
|
break;
|
|
index = indexOfChar(fi,ch,last_index);
|
|
if ( index!=last_index )
|
|
break;
|
|
outpt = utf8_idpb(outpt,ch);
|
|
last_good = pt;
|
|
}
|
|
}
|
|
if ( last_index!=-1 ) {
|
|
*outpt++ = '\0';
|
|
_cairo_scaled_font_text_extents(fi->cscf[last_index].cf,outbuffer,&ct);
|
|
switch ( drawit ) {
|
|
case tf_width:
|
|
/* We just need to increment x, which happens at the end */;
|
|
break;
|
|
case tf_drawit:
|
|
_cairo_set_scaled_font(gw->cc,fi->cscf[last_index].cf);
|
|
_cairo_show_text(gw->cc,outbuffer);
|
|
break;
|
|
case tf_rect:
|
|
if ( x==0 )
|
|
arg->size.lbearing = x+ct.x_bearing;
|
|
arg->size.rbearing = x+ct.width;
|
|
/* I can't understand how ct.y_bearing & ct.height provide useful data !!!!*/
|
|
_cairo_scaled_font_extents(fi->cscf[last_index].cf,&bounds);
|
|
if ( arg->size.fas<bounds.ascent )
|
|
arg->size.fas = bounds.ascent;
|
|
if ( arg->size.fds<bounds.descent )
|
|
arg->size.fds = bounds.descent;
|
|
if ( arg->size.as<-ct.y_bearing )
|
|
arg->size.as = -ct.y_bearing;
|
|
if ( arg->size.ds<ct.height+ct.y_bearing )
|
|
arg->size.ds = ct.height+ct.y_bearing;
|
|
arg->size.width += ct.x_advance;
|
|
break;
|
|
case tf_stopat:
|
|
if ( x+ct.x_advance < arg->maxwidth )
|
|
/* Do Nothing here */;
|
|
else if ( x+ct.x_advance/2 >= arg->maxwidth ) {
|
|
arg->last = (unichar_t *) start;
|
|
arg->width = x;
|
|
return( x );
|
|
} else {
|
|
arg->last = (unichar_t *) pt;
|
|
x += ct.x_advance;
|
|
arg->width = x;
|
|
return( x );
|
|
}
|
|
break;
|
|
case tf_stopbefore:
|
|
if ( x+ct.x_advance >= arg->maxwidth ) {
|
|
arg->last = (unichar_t *) start;
|
|
arg->width = x;
|
|
return( x );
|
|
}
|
|
break;
|
|
case tf_stopafter:
|
|
if ( x+ct.x_advance >= arg->maxwidth ) {
|
|
arg->last = (unichar_t *) pt;
|
|
x += ct.x_advance;
|
|
arg->width = x;
|
|
return( x );
|
|
}
|
|
break;
|
|
}
|
|
x += ct.x_advance;
|
|
}
|
|
start = last_good;
|
|
}
|
|
return( x );
|
|
}
|
|
|
|
/* ************************************************************************** */
|
|
/* ****************************** Cairo Images ****************************** */
|
|
/* ************************************************************************** */
|
|
static cairo_surface_t *GImage2Surface(GImage *image, GRect *src, uint8 **_data) {
|
|
struct _GImage *base = image->list_len==0?image->u.image:image->u.images[0];
|
|
cairo_format_t type;
|
|
uint8 *data, *pt;
|
|
uint32 *idata, *ipt, *ito;
|
|
int i,j,jj,tjj,stride;
|
|
int bit, tobit;
|
|
cairo_surface_t *cs;
|
|
|
|
if ( base->image_type == it_rgba )
|
|
type = CAIRO_FORMAT_ARGB32;
|
|
else if ( base->image_type == it_true && base->trans!=COLOR_UNKNOWN )
|
|
type = CAIRO_FORMAT_ARGB32;
|
|
else if ( base->image_type == it_index && base->clut->trans_index!=COLOR_UNKNOWN )
|
|
type = CAIRO_FORMAT_ARGB32;
|
|
else if ( base->image_type == it_true )
|
|
type = CAIRO_FORMAT_RGB24;
|
|
else if ( base->image_type == it_index )
|
|
type = CAIRO_FORMAT_RGB24;
|
|
else if ( base->image_type == it_mono && base->clut!=NULL &&
|
|
base->clut->trans_index!=COLOR_UNKNOWN )
|
|
type = CAIRO_FORMAT_A1;
|
|
else
|
|
type = CAIRO_FORMAT_RGB24;
|
|
|
|
/* We can't reuse the image's data for alpha images because we must */
|
|
/* premultiply each channel by alpha. We can reuse it for non-transparent*/
|
|
/* rgb images */
|
|
# if CAIRO_VERSION_MAJOR==1 && CAIRO_VERSION_MINOR>=6
|
|
/* Bug in old cairos. In them, this code doesn't work */
|
|
if ( base->image_type == it_true && type == CAIRO_FORMAT_RGB24 ) {
|
|
idata = ((uint32 *) (base->data)) + src->y*base->bytes_per_line + src->x;
|
|
*_data = NULL; /* We can reuse the image's own data, don't need a copy */
|
|
return( _cairo_image_surface_create_for_data((uint8 *) idata,type,
|
|
src->width, src->height,
|
|
base->bytes_per_line));
|
|
}
|
|
#endif
|
|
|
|
stride = _cairo_format_stride_for_width(type,src->width);
|
|
*_data = data = galloc(stride * src->height);
|
|
cs = _cairo_image_surface_create_for_data(data,type,
|
|
src->width, src->height, stride);
|
|
idata = (uint32 *) data;
|
|
|
|
if ( base->image_type == it_rgba ) {
|
|
ipt = ((uint32 *) (base->data + src->y*base->bytes_per_line)) + src->x;
|
|
ito = idata;
|
|
for ( i=0; i<src->height; ++i ) {
|
|
for ( j=0; j<src->width; ++j ) {
|
|
uint32 orig = ipt[j];
|
|
int alpha = orig>>24;
|
|
if ( alpha==0xff )
|
|
ito[j] = orig;
|
|
else if ( alpha==0 )
|
|
ito[j] = 0x00000000;
|
|
else
|
|
ito[j] = (alpha<<24) |
|
|
((COLOR_RED (orig)*alpha/255)<<16)|
|
|
((COLOR_GREEN(orig)*alpha/255)<<8 )|
|
|
((COLOR_BLUE (orig)*alpha/255));
|
|
}
|
|
ipt = (uint32 *) (((uint8 *) ipt) + base->bytes_per_line);
|
|
ito = (uint32 *) (((uint8 *) ito) +stride);
|
|
}
|
|
} else if ( base->image_type == it_true && base->trans!=COLOR_UNKNOWN ) {
|
|
Color trans = base->trans;
|
|
ipt = ((uint32 *) (base->data + src->y*base->bytes_per_line)) + src->x;
|
|
ito = idata;
|
|
for ( i=0; i<src->height; ++i ) {
|
|
for ( j=0; j<src->width; ++j ) {
|
|
if ( ipt[j]==trans )
|
|
ito[j] = 0x00000000;
|
|
else
|
|
ito[j] = ipt[j]|0xff000000;
|
|
}
|
|
ipt = (uint32 *) (((uint8 *) ipt) + base->bytes_per_line);
|
|
ito = (uint32 *) (((uint8 *) ito) +stride);
|
|
}
|
|
} else if ( base->image_type == it_true ) {
|
|
ipt = ((uint32 *) (base->data + src->y*base->bytes_per_line)) + src->x;
|
|
ito = idata;
|
|
for ( i=0; i<src->height; ++i ) {
|
|
for ( j=0; j<src->width; ++j ) {
|
|
ito[j] = ipt[j]|0xff000000;
|
|
}
|
|
ipt = (uint32 *) (((uint8 *) ipt) + base->bytes_per_line);
|
|
ito = (uint32 *) (((uint8 *) ito) +stride);
|
|
}
|
|
} else if ( base->image_type == it_index && base->clut->trans_index!=COLOR_UNKNOWN ) {
|
|
int trans = base->clut->trans_index;
|
|
Color *clut = base->clut->clut;
|
|
pt = base->data + src->y*base->bytes_per_line + src->x;
|
|
ito = idata;
|
|
for ( i=0; i<src->height; ++i ) {
|
|
for ( j=0; j<src->width; ++j ) {
|
|
int index = pt[j];
|
|
if ( index==trans )
|
|
ito[j] = 0x00000000;
|
|
else
|
|
/* In theory RGB24 images don't need the alpha channel set*/
|
|
/* but there is a bug in Cairo 1.2, and they do. */
|
|
ito[j] = clut[index]|0xff000000;
|
|
}
|
|
pt += base->bytes_per_line;
|
|
ito = (uint32 *) (((uint8 *) ito) +stride);
|
|
}
|
|
} else if ( base->image_type == it_index ) {
|
|
Color *clut = base->clut->clut;
|
|
pt = base->data + src->y*base->bytes_per_line + src->x;
|
|
ito = idata;
|
|
for ( i=0; i<src->height; ++i ) {
|
|
for ( j=0; j<src->width; ++j ) {
|
|
int index = pt[j];
|
|
ito[j] = clut[index] | 0xff000000;
|
|
}
|
|
pt += base->bytes_per_line;
|
|
ito = (uint32 *) (((uint8 *) ito) +stride);
|
|
}
|
|
#ifdef WORDS_BIGENDIAN
|
|
} else if ( base->image_type == it_mono && base->clut!=NULL &&
|
|
base->clut->trans_index!=COLOR_UNKNOWN ) {
|
|
pt = base->data + src->y*base->bytes_per_line + (src->x>>3);
|
|
ito = idata;
|
|
memset(data,0,src->height*stride);
|
|
if ( base->clut->trans_index==0 ) {
|
|
for ( i=0; i<src->height; ++i ) {
|
|
bit = (0x80>>(src->x&0x7));
|
|
tobit = 0x80000000;
|
|
for ( j=jj=tjj=0; j<src->width; ++j ) {
|
|
if ( pt[jj]&bit )
|
|
ito[tjj] |= tobit;
|
|
if ( (bit>>=1)==0 ) {
|
|
bit = 0x80;
|
|
++jj;
|
|
}
|
|
if ( (tobit>>=1)==0 ) {
|
|
tobit = 0x80000000;
|
|
++tjj;
|
|
}
|
|
}
|
|
pt += base->bytes_per_line;
|
|
ito = (uint32 *) (((uint8 *) ito) +stride);
|
|
}
|
|
} else {
|
|
for ( i=0; i<src->height; ++i ) {
|
|
bit = (0x80>>(src->x&0x7));
|
|
tobit = 0x80000000;
|
|
for ( j=jj=tjj=0; j<src->width; ++j ) {
|
|
if ( !(pt[jj]&bit) )
|
|
ito[tjj] |= tobit;
|
|
if ( (bit>>=1)==0 ) {
|
|
bit = 0x80;
|
|
++jj;
|
|
}
|
|
if ( (tobit>>=1)==0 ) {
|
|
tobit = 0x80000000;
|
|
++tjj;
|
|
}
|
|
}
|
|
pt += base->bytes_per_line;
|
|
ito = (uint32 *) (((uint8 *) ito) +stride);
|
|
}
|
|
}
|
|
#else
|
|
} else if ( base->image_type == it_mono && base->clut!=NULL &&
|
|
base->clut->trans_index!=COLOR_UNKNOWN ) {
|
|
pt = base->data + src->y*base->bytes_per_line + (src->x>>3);
|
|
ito = idata;
|
|
memset(data,0,src->height*stride);
|
|
if ( base->clut->trans_index==0 ) {
|
|
for ( i=0; i<src->height; ++i ) {
|
|
bit = (0x80>>(src->x&0x7));
|
|
tobit = 1;
|
|
for ( j=jj=tjj=0; j<src->width; ++j ) {
|
|
if ( pt[jj]&bit )
|
|
ito[tjj] |= tobit;
|
|
if ( (bit>>=1)==0 ) {
|
|
bit = 0x80;
|
|
++jj;
|
|
}
|
|
if ( (tobit<<=1)==0 ) {
|
|
tobit = 0x1;
|
|
++tjj;
|
|
}
|
|
}
|
|
pt += base->bytes_per_line;
|
|
ito = (uint32 *) (((uint8 *) ito) +stride);
|
|
}
|
|
} else {
|
|
for ( i=0; i<src->height; ++i ) {
|
|
bit = (0x80>>(src->x&0x7));
|
|
tobit = 1;
|
|
for ( j=jj=tjj=0; j<src->width; ++j ) {
|
|
if ( !(pt[jj]&bit) )
|
|
ito[tjj] |= tobit;
|
|
if ( (bit>>=1)==0 ) {
|
|
bit = 0x80;
|
|
++jj;
|
|
}
|
|
if ( (tobit<<=1)==0 ) {
|
|
tobit = 0x1;
|
|
++tjj;
|
|
}
|
|
}
|
|
pt += base->bytes_per_line;
|
|
ito = (uint32 *) (((uint8 *) ito) +stride);
|
|
}
|
|
}
|
|
#endif
|
|
} else {
|
|
Color fg = base->clut==NULL ? 0xffffff : base->clut->clut[1];
|
|
Color bg = base->clut==NULL ? 0x000000 : base->clut->clut[0];
|
|
/* In theory RGB24 images don't need the alpha channel set*/
|
|
/* but there is a bug in Cairo 1.2, and they do. */
|
|
fg |= 0xff000000; bg |= 0xff000000;
|
|
pt = base->data + src->y*base->bytes_per_line + (src->x>>3);
|
|
ito = idata;
|
|
for ( i=0; i<src->height; ++i ) {
|
|
bit = (0x80>>(src->x&0x7));
|
|
for ( j=jj=0; j<src->width; ++j ) {
|
|
ito[j] = (pt[jj]&bit) ? fg : bg;
|
|
if ( (bit>>=1)==0 ) {
|
|
bit = 0x80;
|
|
++jj;
|
|
}
|
|
}
|
|
pt += base->bytes_per_line;
|
|
ito = (uint32 *) (((uint8 *) ito) +stride);
|
|
}
|
|
}
|
|
return( cs );
|
|
}
|
|
|
|
void _GXCDraw_Image( GXWindow gw, GImage *image, GRect *src, int32 x, int32 y) {
|
|
uint8 *data;
|
|
cairo_surface_t *is = GImage2Surface(image,src,&data);
|
|
struct _GImage *base = image->list_len==0?image->u.image:image->u.images[0];
|
|
|
|
if ( _cairo_image_surface_get_format(is)==CAIRO_FORMAT_A1 ) {
|
|
/* No color info, just alpha channel */
|
|
Color fg = base->clut->trans_index==0 ? base->clut->clut[1] : base->clut->clut[0];
|
|
_cairo_set_source_rgba(gw->cc,COLOR_RED(fg)/255.0,COLOR_GREEN(fg)/255.0,COLOR_BLUE(fg)/255.0,1.0);
|
|
_cairo_mask_surface(gw->cc,is,x,y);
|
|
} else {
|
|
_cairo_set_source_surface(gw->cc,is,x,y);
|
|
_cairo_rectangle(gw->cc,x,y,src->width,src->height);
|
|
_cairo_fill(gw->cc);
|
|
}
|
|
/* Clear source and mask, in case we need to */
|
|
_cairo_new_path(gw->cc);
|
|
_cairo_set_source_rgba(gw->cc,0,0,0,0);
|
|
|
|
_cairo_surface_destroy(is);
|
|
free(data);
|
|
gw->cairo_state.fore_col = COLOR_UNKNOWN;
|
|
}
|
|
|
|
void _GXCDraw_TileImage( GXWindow gw, GImage *image, GRect *src, int32 x, int32 y) {
|
|
}
|
|
|
|
/* What we really want to do is use the grey levels as an alpha channel */
|
|
void _GXCDraw_Glyph( GXWindow gw, GImage *image, GRect *src, int32 x, int32 y) {
|
|
struct _GImage *base = image->list_len==0?image->u.image:image->u.images[0];
|
|
cairo_surface_t *is;
|
|
|
|
if ( base->image_type!=it_index )
|
|
_GXCDraw_Image(gw,image,src,x,y);
|
|
else {
|
|
int stride = _cairo_format_stride_for_width(CAIRO_FORMAT_A8,src->width);
|
|
uint8 *basedata = galloc(stride*src->height),
|
|
*data = basedata,
|
|
*srcd = base->data + src->y*base->bytes_per_line + src->x;
|
|
int factor = base->clut->clut_len==256 ? 1 :
|
|
base->clut->clut_len==16 ? 17 :
|
|
base->clut->clut_len==4 ? 85 : 255;
|
|
int i,j;
|
|
Color fg = base->clut->clut[base->clut->clut_len-1];
|
|
|
|
for ( i=0; i<src->height; ++i ) {
|
|
for ( j=0; j<src->width; ++j )
|
|
data[j] = factor*srcd[j];
|
|
srcd += base->bytes_per_line;
|
|
data += stride;
|
|
}
|
|
is = _cairo_image_surface_create_for_data(basedata,CAIRO_FORMAT_A8,
|
|
src->width,src->height,stride);
|
|
_cairo_set_source_rgba(gw->cc,COLOR_RED(fg)/255.0,COLOR_GREEN(fg)/255.0,COLOR_BLUE(fg)/255.0,1.0);
|
|
_cairo_mask_surface(gw->cc,is,x,y);
|
|
/* I think the mask is sufficient, setting a rectangle would provide */
|
|
/* a new mask? */
|
|
/*_cairo_rectangle(gw->cc,x,y,src->width,src->height);*/
|
|
/* I think setting the mask also draws... at least so the tutorial implies */
|
|
/* _cairo_fill(gw->cc);*/
|
|
/* Presumably that doesn't leave the mask surface pattern lying around */
|
|
/* but dereferences it so we can free it */
|
|
_cairo_surface_destroy(is);
|
|
free(basedata);
|
|
}
|
|
gw->cairo_state.fore_col = COLOR_UNKNOWN;
|
|
}
|
|
|
|
void _GXCDraw_ImageMagnified(GXWindow gw, GImage *image, GRect *magsrc,
|
|
int32 x, int32 y, int32 width, int32 height) {
|
|
struct _GImage *base = image->list_len==0?image->u.image:image->u.images[0];
|
|
GRect full;
|
|
double xscale, yscale;
|
|
GRect viewable;
|
|
|
|
viewable = gw->ggc->clip;
|
|
if ( viewable.width > gw->pos.width-viewable.x )
|
|
viewable.width = gw->pos.width-viewable.x;
|
|
if ( viewable.height > gw->pos.height-viewable.y )
|
|
viewable.height = gw->pos.height-viewable.y;
|
|
|
|
xscale = (base->width>=1) ? ((double) (width))/(base->width) : 1;
|
|
yscale = (base->height>=1) ? ((double) (height))/(base->height) : 1;
|
|
/* Intersect the clip rectangle with the scaled image to find the */
|
|
/* portion of screen that we want to draw */
|
|
if ( viewable.x<x ) {
|
|
viewable.width -= (x-viewable.x);
|
|
viewable.x = x;
|
|
}
|
|
if ( viewable.y<y ) {
|
|
viewable.height -= (y-viewable.y);
|
|
viewable.y = y;
|
|
}
|
|
if ( viewable.x+viewable.width > x+width ) viewable.width = x+width - viewable.x;
|
|
if ( viewable.y+viewable.height > y+height ) viewable.height = y+height - viewable.y;
|
|
if ( viewable.height<0 || viewable.width<0 )
|
|
return;
|
|
|
|
/* Now find that same rectangle in the coordinates of the unscaled image */
|
|
/* (translation & scale) */
|
|
viewable.x -= x; viewable.y -= y;
|
|
full.x = viewable.x/xscale; full.y = viewable.y/yscale;
|
|
full.width = viewable.width/xscale; full.height = viewable.height/yscale;
|
|
if ( full.x+full.width>base->width ) full.width = base->width-full.x; /* Rounding errors */
|
|
if ( full.y+full.height>base->height ) full.height = base->height-full.y; /* Rounding errors */
|
|
/* Rounding errors */
|
|
#if 1
|
|
{
|
|
GImage *temp = _GImageExtract(base,&full,&viewable,xscale,yscale);
|
|
GRect src;
|
|
src.x = src.y = 0; src.width = viewable.width; src.height = viewable.height;
|
|
_GXCDraw_Image( gw, temp, &src, x+viewable.x, y+viewable.y);
|
|
}
|
|
#else
|
|
{
|
|
cairo_surface_t *is;
|
|
uint8 *data;
|
|
/* I don't see why this doesn't work, but every now and then it will crash*/
|
|
/* deep inside of cairo. Perhaps cairo can't handle scaling images? */
|
|
/* Perhaps there's a bug in my code? */
|
|
is = GImage2Surface(image,&full,&data);
|
|
|
|
_cairo_save(gw->cc);
|
|
_cairo_scale(gw->cc,viewable.width/((double) full.width),viewable.height/((double) full.height));
|
|
|
|
if ( _cairo_image_surface_get_format(is)==CAIRO_FORMAT_A1 ) {
|
|
/* No color info, just alpha channel */
|
|
Color fg = base->clut->trans_index==0 ? base->clut->clut[1] : base->clut->clut[0];
|
|
_cairo_set_source_rgba(gw->cc,COLOR_RED(fg)/255.0,COLOR_GREEN(fg)/255.0,COLOR_BLUE(fg)/255.0,1.0);
|
|
_cairo_mask_surface(gw->cc,is,viewable.x*xscale,viewable.y*yscale);
|
|
} else {
|
|
_cairo_set_source_surface(gw->cc,is,viewable.x/xscale,viewable.y/yscale);
|
|
_cairo_paint(gw->cc);
|
|
}
|
|
_cairo_restore(gw->cc);
|
|
|
|
_cairo_surface_destroy(is);
|
|
free(data);
|
|
gw->cairo_state.fore_col = COLOR_UNKNOWN;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* ************************************************************************** */
|
|
/* ******************************** Copy Area ******************************* */
|
|
/* ************************************************************************** */
|
|
|
|
void _GXCDraw_CopyArea( GXWindow from, GXWindow into, GRect *src, int32 x, int32 y) {
|
|
|
|
if ( !into->usecairo || !from->usecairo ) {
|
|
fprintf( stderr, "Cairo CopyArea called from something not cairo enabled\n" );
|
|
return;
|
|
}
|
|
|
|
_cairo_set_source_surface(into->cc,from->cs,x-src->x,y-src->y);
|
|
_cairo_rectangle(into->cc,x,y,src->width,src->height);
|
|
_cairo_fill(into->cc);
|
|
|
|
/* Clear source and mask, in case we need to */
|
|
_cairo_set_source_rgba(into->cc,0,0,0,0);
|
|
|
|
into->cairo_state.fore_col = COLOR_UNKNOWN;
|
|
}
|
|
|
|
/* ************************************************************************** */
|
|
/* **************************** Memory Buffering **************************** */
|
|
/* ************************************************************************** */
|
|
/* We can't draw with XOR in cairo. We can do all the cairo processing, copy */
|
|
/* cairo's data to the x window, and then do the xor drawing. But if the X */
|
|
/* window isn't available (if we are buffering cairo) then we must save the */
|
|
/* XOR drawing operations until we've popped the buffering */
|
|
/* Mmm. Now we use pixmaps rather than groups and the issue isn't relevant -- I think */
|
|
|
|
enum gcairo_flags _GXCDraw_CairoCapabilities( GXWindow gw) {
|
|
enum gcairo_flags flags = gc_all;
|
|
|
|
if ( gw->usepango )
|
|
flags |= gc_pango;
|
|
|
|
return( flags|gc_xor ); /* If not buffered, we can emulate xor by having X11 do it in the X layer */
|
|
}
|
|
/* ************************************************************************** */
|
|
/* **************************** Synchronization ***************************** */
|
|
/* ************************************************************************** */
|
|
void _GXCDraw_Flush(GXWindow gw) {
|
|
_cairo_surface_flush(gw->cs);
|
|
}
|
|
|
|
void _GXCDraw_DirtyRect(GXWindow gw,double x, double y, double width, double height) {
|
|
_cairo_surface_mark_dirty_rectangle(gw->cs,x,y,width,height);
|
|
}
|
|
#else
|
|
int _GXCDraw_hasCairo(void) {
|
|
return(false);
|
|
}
|
|
#endif
|
|
|
|
/* ************************************************************************** */
|
|
/* ***************************** Pango Library ****************************** */
|
|
/* ************************************************************************** */
|
|
|
|
#ifndef _NO_LIBPANGO
|
|
# if !defined(_STATIC_LIBPANGO) && !defined(NODYNAMIC)
|
|
# include <dynamic.h>
|
|
static DL_CONST void *libpango=NULL, *libpangoxft, *libXft;
|
|
static XftDraw *(*_XftDrawCreate)(Display *,Drawable,Visual *,Colormap);
|
|
static void (*_XftDrawDestroy)(XftDraw *);
|
|
static Bool (*_XftColorAllocValue)(Display *,Visual *,Colormap,XRenderColor *,XftColor *);
|
|
static Bool (*_XftDrawSetClipRectangles)(XftDraw *,int,int,_Xconst XRectangle *,int);
|
|
|
|
|
|
static PangoFontDescription *(*_pango_font_description_new)(void);
|
|
static void (*_pango_font_description_set_family)(PangoFontDescription *,const char *);
|
|
static void (*_pango_font_description_set_style)(PangoFontDescription *,PangoStyle);
|
|
static void (*_pango_font_description_set_variant)(PangoFontDescription *,PangoVariant);
|
|
static void (*_pango_font_description_set_weight)(PangoFontDescription *,PangoWeight);
|
|
static void (*_pango_font_description_set_stretch)(PangoFontDescription *,PangoStretch);
|
|
static void (*_pango_font_description_set_size)(PangoFontDescription *,gint);
|
|
static void (*_pango_font_description_set_absolute_size)(PangoFontDescription *,double);
|
|
|
|
static void (*_pango_layout_set_font_description)(PangoLayout *,PangoFontDescription *);
|
|
static void (*_pango_layout_set_text)(PangoLayout *,char *,int);
|
|
static void (*_pango_layout_get_pixel_extents)(PangoLayout *,PangoRectangle *,PangoRectangle *);
|
|
static PangoLayout *(*_pango_layout_new)(PangoContext *);
|
|
static void (*_pango_layout_index_to_pos)(PangoLayout *,int,PangoRectangle *);
|
|
static gboolean (*_pango_layout_xy_to_index)(PangoLayout *,int,int,int *,int *);
|
|
static void (*_pango_layout_set_width)(PangoLayout *layout,int width); /* -1 => No wrap */
|
|
static int (*_pango_layout_get_line_count)(PangoLayout *layout);
|
|
static PangoLayoutLine *(*_pango_layout_get_line)(PangoLayout *layout, int line);
|
|
|
|
static PangoLayoutIter *(*_pango_layout_get_iter)(PangoLayout *);
|
|
static void (*_pango_layout_iter_free)(PangoLayoutIter *);
|
|
static gboolean (*_pango_layout_iter_next_run)(PangoLayoutIter *);
|
|
static PangoLayoutRun *(*_pango_layout_iter_get_run)(PangoLayoutIter *);
|
|
static void (*_pango_layout_iter_get_run_extents)(PangoLayoutIter *,PangoRectangle *,PangoRectangle *);
|
|
|
|
# define GTimer GTimer_GTK
|
|
# include <pango/pangoxft.h>
|
|
# if !defined(_NO_LIBCAIRO) && PANGO_VERSION_MINOR>=10
|
|
# include <pango/pangocairo.h>
|
|
static DL_CONST void *libpangocairo;
|
|
static void (*_pango_cairo_layout_path)(cairo_t *,PangoLayout *);
|
|
static void (*_pango_cairo_show_glyph_string)(cairo_t *,PangoFont *, PangoGlyphString *);
|
|
static PangoContext *(*_pango_cairo_font_map_create_context)(PangoCairoFontMap *);
|
|
static PangoFontMap *(*_pango_cairo_font_map_get_default)(void);
|
|
static void (*_pango_cairo_context_set_resolution)(PangoContext *,double);
|
|
# endif
|
|
# undef GTimer
|
|
|
|
static PangoFont *(*_pango_font_map_load_font)(PangoFontMap *, PangoContext *, const PangoFontDescription *);
|
|
static PangoFontMetrics *(*_pango_font_get_metrics)(PangoFont *, PangoLanguage *);
|
|
static void (*_pango_font_metrics_unref)(PangoFontMetrics *);
|
|
static int (*_pango_font_metrics_get_ascent)(PangoFontMetrics *);
|
|
static int (*_pango_font_metrics_get_descent)(PangoFontMetrics *);
|
|
|
|
static void (*_pango_xft_render_layout)(XftDraw *,XftColor *,PangoLayout *,int,int);
|
|
static PangoFontMap *(*_pango_xft_get_font_map)(Display *, int);
|
|
static PangoContext *(*_pango_xft_get_context)(Display *, int);
|
|
static void (*_pango_xft_render)(XftDraw *, XftColor *, PangoFont *,
|
|
PangoGlyphString *, gint, gint);
|
|
static void my_xft_render_layout(XftDraw *xftw,XftColor *fgcol,
|
|
PangoLayout *layout,int x,int y);
|
|
|
|
static PangoFontDescription *(*_pango_font_describe)(PangoFont *);
|
|
static char *(*_pango_font_description_to_string)(PangoFontDescription *);
|
|
|
|
static int pango_initted=false, hasP=false;
|
|
|
|
int _GXPDraw_hasPango(void) {
|
|
|
|
if ( !usepango )
|
|
return( false );
|
|
|
|
if ( pango_initted )
|
|
return( hasP );
|
|
|
|
pango_initted = true;
|
|
libpango = dlopen("libpango-1.0" SO_EXT,RTLD_LAZY);
|
|
#ifdef SO_0_EXT
|
|
if ( libpango==NULL )
|
|
libpango = dlopen("libpango-1.0" SO_0_EXT,RTLD_LAZY);
|
|
#endif
|
|
if ( libpango==NULL ) {
|
|
fprintf(stderr,"libpango: %s\n", dlerror());
|
|
return( 0 );
|
|
}
|
|
_pango_font_description_new = (PangoFontDescription *(*)(void))
|
|
dlsym(libpango,"pango_font_description_new");
|
|
_pango_font_description_set_family = (void (*)(PangoFontDescription *,const char *))
|
|
dlsym(libpango,"pango_font_description_set_family");
|
|
_pango_font_description_set_style = (void (*)(PangoFontDescription *,PangoStyle))
|
|
dlsym(libpango,"pango_font_description_set_style");
|
|
_pango_font_description_set_variant = (void (*)(PangoFontDescription *,PangoVariant))
|
|
dlsym(libpango,"pango_font_description_set_variant");
|
|
_pango_font_description_set_weight = (void (*)(PangoFontDescription *,PangoWeight))
|
|
dlsym(libpango,"pango_font_description_set_weight");
|
|
_pango_font_description_set_stretch = (void (*)(PangoFontDescription *,PangoStretch))
|
|
dlsym(libpango,"pango_font_description_set_stretch");
|
|
_pango_font_description_set_size = (void (*)(PangoFontDescription *,gint))
|
|
dlsym(libpango,"pango_font_description_set_size");
|
|
_pango_font_description_set_absolute_size = (void (*)(PangoFontDescription *,double))
|
|
dlsym(libpango,"pango_font_description_set_absolute_size");
|
|
|
|
_pango_layout_set_font_description = (void (*)(PangoLayout *,PangoFontDescription *))
|
|
dlsym(libpango,"pango_layout_set_font_description");
|
|
_pango_layout_set_text = (void (*)(PangoLayout *,char *,int))
|
|
dlsym(libpango,"pango_layout_set_text");
|
|
_pango_layout_get_pixel_extents = (void (*)(PangoLayout *,PangoRectangle *,PangoRectangle *))
|
|
dlsym(libpango,"pango_layout_get_pixel_extents");
|
|
_pango_layout_new = (PangoLayout *(*)(PangoContext *))
|
|
dlsym(libpango,"pango_layout_new");
|
|
_pango_layout_index_to_pos = (void (*)(PangoLayout *, int, PangoRectangle *))
|
|
dlsym(libpango,"pango_layout_index_to_pos");
|
|
_pango_layout_xy_to_index = (gboolean (*)(PangoLayout *,int,int,int *,int *))
|
|
dlsym(libpango,"pango_layout_xy_to_index");
|
|
|
|
_pango_font_map_load_font = (PangoFont *(*)(PangoFontMap *, PangoContext *, const PangoFontDescription *))
|
|
dlsym(libpango,"pango_font_map_load_font");
|
|
_pango_font_get_metrics = (PangoFontMetrics *(*)(PangoFont *, PangoLanguage *))
|
|
dlsym(libpango,"pango_font_get_metrics");
|
|
_pango_font_metrics_unref = (void (*)(PangoFontMetrics *))
|
|
dlsym(libpango,"pango_font_metrics_unref");
|
|
_pango_font_metrics_get_ascent = (int (*)(PangoFontMetrics *))
|
|
dlsym(libpango,"pango_font_metrics_get_ascent");
|
|
_pango_font_metrics_get_descent = (int (*)(PangoFontMetrics *))
|
|
dlsym(libpango,"pango_font_metrics_get_descent");
|
|
|
|
/* Only used if we don't have pango_xft_render_layout */
|
|
_pango_layout_get_iter = (PangoLayoutIter *(*)(PangoLayout *))
|
|
dlsym(libpango,"pango_layout_get_iter");
|
|
_pango_layout_iter_free = (void (*)(PangoLayoutIter *))
|
|
dlsym(libpango,"pango_layout_iter_free");
|
|
_pango_layout_iter_next_run = (gboolean (*)(PangoLayoutIter *))
|
|
dlsym(libpango,"pango_layout_iter_next_run");
|
|
_pango_layout_iter_get_run = (PangoLayoutRun *(*)(PangoLayoutIter *))
|
|
dlsym(libpango,"pango_layout_iter_get_run_readonly");
|
|
if ( _pango_layout_iter_get_run==NULL )
|
|
_pango_layout_iter_get_run = (PangoLayoutRun *(*)(PangoLayoutIter *))
|
|
dlsym(libpango,"pango_layout_iter_get_run"); /* Only used if we dont have pango_layout_iter_get_run_readonly */
|
|
_pango_layout_iter_get_run_extents = (void (*)(PangoLayoutIter *,PangoRectangle *,PangoRectangle *))
|
|
dlsym(libpango,"pango_layout_iter_get_run_extents");
|
|
_pango_layout_set_width = (void (*)(PangoLayout *,int ))
|
|
dlsym(libpango,"pango_layout_set_width");
|
|
_pango_layout_get_line_count = (int (*)(PangoLayout *))
|
|
dlsym(libpango,"pango_layout_get_line_count");
|
|
_pango_layout_get_line = (PangoLayoutLine *(*)(PangoLayout *, int))
|
|
dlsym(libpango,"pango_layout_get_line_readonly");
|
|
if ( _pango_layout_get_line==NULL )
|
|
_pango_layout_get_line = (PangoLayoutLine *(*)(PangoLayout *, int))
|
|
dlsym(libpango,"pango_layout_get_line"); /* Only used if we dont have pango_layout_iter_get_run_readonly */
|
|
|
|
libpangoxft = dlopen("libpangoxft-1.0" SO_EXT,RTLD_LAZY);
|
|
#ifdef SO_0_EXT
|
|
if ( libpangoxft==NULL )
|
|
libpangoxft = dlopen("libpangoxft-1.0" SO_0_EXT,RTLD_LAZY);
|
|
#endif
|
|
if ( libpangoxft==NULL ) {
|
|
fprintf(stderr,"libpangoxft: %s\n", dlerror());
|
|
return( 0 );
|
|
}
|
|
_pango_xft_render_layout = (void (*)(XftDraw *,XftColor *,PangoLayout *,int,int))
|
|
dlsym(libpangoxft,"pango_xft_render_layout");
|
|
_pango_xft_get_font_map = (PangoFontMap *(*)(Display *, int))
|
|
dlsym(libpangoxft,"pango_xft_get_font_map");
|
|
_pango_xft_get_context = (PangoContext *(*)(Display *, int))
|
|
dlsym(libpangoxft,"pango_xft_get_context");
|
|
_pango_xft_render = (void (*)(XftDraw *,XftColor *,PangoFont *, PangoGlyphString *, gint, gint))
|
|
dlsym(libpangoxft,"pango_xft_render");
|
|
|
|
if ( _pango_font_description_new==NULL || _pango_xft_render==NULL ) {
|
|
fprintf(stderr,"libpango: Missing symbols\n" );
|
|
return( 0 );
|
|
}
|
|
|
|
libXft = dlopen("libXft" SO_EXT,RTLD_LAZY);
|
|
#ifdef SO_2_EXT
|
|
if ( libXft==NULL )
|
|
libXft = dlopen("libXft" SO_2_EXT,RTLD_LAZY);
|
|
#endif
|
|
/* The mac doesn't put /usr/X11R6/lib into the default library load path. Very annoying */
|
|
if ( libXft==NULL )
|
|
libXft = dlopen("/usr/X11R6/lib/libXft" SO_EXT,RTLD_LAZY);
|
|
#ifdef SO_2_EXT
|
|
if ( libXft==NULL )
|
|
libXft = dlopen("/usr/X11R6/lib/libXft" SO_2_EXT,RTLD_LAZY);
|
|
#endif
|
|
if ( libXft==NULL ) {
|
|
fprintf(stderr,"libXft: %s\n", dlerror());
|
|
} else {
|
|
_XftDrawCreate = (XftDraw *(*)(Display *,Drawable,Visual *,Colormap))
|
|
dlsym(libXft,"XftDrawCreate");
|
|
_XftDrawDestroy = (void (*)(XftDraw *))
|
|
dlsym(libXft,"XftDrawDestroy");
|
|
_XftColorAllocValue = (Bool (*)(Display *,Visual *,Colormap,XRenderColor *,XftColor *))
|
|
dlsym(libXft,"XftColorAllocValue");
|
|
_XftDrawSetClipRectangles = (Bool (*)(XftDraw *,int,int,_Xconst XRectangle *,int))
|
|
dlsym(libXft,"XftDrawSetClipRectangles");
|
|
if ( _XftDrawCreate!=NULL && _XftColorAllocValue!=NULL )
|
|
hasP |= 1;
|
|
}
|
|
|
|
# if !defined(_NO_LIBCAIRO) && PANGO_VERSION_MINOR>=10
|
|
libpangocairo = dlopen("libpangocairo-1.0" SO_EXT,RTLD_LAZY);
|
|
#ifdef SO_0_EXT
|
|
if ( libpangocairo==NULL )
|
|
libpangocairo = dlopen("libpangocairo-1.0" SO_0_EXT,RTLD_LAZY);
|
|
#endif
|
|
if ( libpangocairo==NULL )
|
|
fprintf(stderr,"libpangocairo: %s\n", dlerror());
|
|
else {
|
|
_pango_cairo_layout_path = (void (*)(cairo_t *,PangoLayout *))
|
|
dlsym(libpangocairo,"pango_cairo_layout_path");
|
|
_pango_cairo_show_glyph_string = (void (*)(cairo_t *,PangoFont *, PangoGlyphString *))
|
|
dlsym(libpangocairo,"pango_cairo_show_glyph_string");
|
|
_pango_cairo_font_map_create_context = (PangoContext *(*)(PangoCairoFontMap *))
|
|
dlsym(libpangocairo,"pango_cairo_font_map_create_context");
|
|
_pango_cairo_font_map_get_default = (PangoFontMap *(*)(void))
|
|
dlsym(libpangocairo,"pango_cairo_font_map_get_default");
|
|
_pango_cairo_context_set_resolution = (void (*)(PangoContext *,double))
|
|
dlsym(libpangocairo,"pango_cairo_context_set_resolution");
|
|
if ( _pango_cairo_show_glyph_string!=NULL && _pango_cairo_font_map_create_context!=NULL &&
|
|
_pango_cairo_font_map_get_default!=NULL && _GXCDraw_hasCairo())
|
|
hasP |= 2;
|
|
}
|
|
#endif
|
|
|
|
_pango_font_describe = (PangoFontDescription * (*)(PangoFont *))
|
|
dlsym(libpango,"pango_font_describe");
|
|
_pango_font_description_to_string = (char * (*)(PangoFontDescription *))
|
|
dlsym(libpango,"pango_font_description_to_string");
|
|
return( hasP );
|
|
}
|
|
# else
|
|
# define _XftDrawCreate XftDrawCreate
|
|
# define _XftDrawDestroy XftDrawDestroy
|
|
# define _XftColorAllocValue XftColorAllocValue
|
|
# define _XftDrawSetClipRectangles XftDrawSetClipRectangles
|
|
|
|
# define _pango_font_description_new pango_font_description_new
|
|
# define _pango_font_description_set_family pango_font_description_set_family
|
|
# define _pango_font_description_set_style pango_font_description_set_style
|
|
# define _pango_font_description_set_variant pango_font_description_set_variant
|
|
# define _pango_font_description_set_weight pango_font_description_set_weight
|
|
# define _pango_font_description_set_stretch pango_font_description_set_stretch
|
|
# define _pango_font_description_set_size pango_font_description_set_size
|
|
# if PANGO_VERSION_MINOR>=8
|
|
# define _pango_font_description_set_absolute_size pango_font_description_set_absolute_size
|
|
# else
|
|
# define no_pango_font_description_set_absolute_size
|
|
# endif
|
|
# define _pango_layout_set_font_description pango_layout_set_font_description
|
|
# define _pango_layout_set_text pango_layout_set_text
|
|
# define _pango_layout_set_font_description pango_layout_set_font_description
|
|
# define _pango_layout_set_text pango_layout_set_text
|
|
# define _pango_layout_get_pixel_extents pango_layout_get_pixel_extents
|
|
# define _pango_layout_index_to_pos pango_layout_index_to_pos
|
|
# define _pango_layout_xy_to_index pango_layout_xy_to_index
|
|
# define _pango_layout_set_width pango_layout_set_width
|
|
# define _pango_layout_get_line_count pango_layout_get_line_count
|
|
# define _pango_layout_get_line pango_layout_get_line
|
|
# define _pango_font_map_load_font pango_font_map_load_font
|
|
# define _pango_font_get_metrics pango_font_get_metrics
|
|
# define _pango_font_metrics_unref pango_font_metrics_unref
|
|
# define _pango_font_metrics_get_ascent pango_font_metrics_get_ascent
|
|
# define _pango_font_metrics_get_descent pango_font_metrics_get_descent
|
|
# define _pango_layout_new pango_layout_new
|
|
# define _pango_layout_get_iter pango_layout_get_iter
|
|
# define _pango_layout_iter_free pango_layout_iter_free
|
|
# define _pango_layout_iter_next_run pango_layout_iter_next_run
|
|
# define _pango_layout_iter_get_run pango_layout_iter_get_run
|
|
# define _pango_layout_iter_get_run_extents pango_layout_iter_get_run_extents
|
|
# define GTimer GTimer_GTK
|
|
# include <pango/pangoxft.h>
|
|
# if !defined(_NO_LIBCAIRO) && PANGO_VERSION_MINOR>=10
|
|
# include <pango/pangocairo.h>
|
|
# define _pango_cairo_layout_path pango_cairo_layout_path
|
|
# define _pango_cairo_font_map_create_context pango_cairo_font_map_create_context
|
|
# define _pango_cairo_font_map_get_default pango_cairo_font_map_get_default
|
|
# define _pango_cairo_context_set_resolution pango_cairo_context_set_resolution
|
|
# define _pango_cairo_show_glyph_string pango_cairo_show_glyph_string
|
|
# endif
|
|
# undef GTimer
|
|
# if PANGO_VERSION_MINOR>=8
|
|
# define _pango_xft_render_layout pango_xft_render_layout
|
|
# else
|
|
# define _pango_xft_render_layout my_xft_render_layout
|
|
# endif
|
|
# define _pango_xft_get_font_map pango_xft_get_font_map
|
|
# define _pango_xft_get_context pango_xft_get_context
|
|
# define _pango_xft_render pango_xft_render
|
|
|
|
int _GXPDraw_hasPango(void) {
|
|
|
|
if ( !usepango )
|
|
return( false );
|
|
|
|
# if !defined(_NO_LIBCAIRO) && PANGO_VERSION_MINOR>=10
|
|
return( 3 );
|
|
# else
|
|
return( 1 );
|
|
# endif
|
|
}
|
|
# endif
|
|
|
|
/* ************************************************************************** */
|
|
/* ****************************** Pango Render ****************************** */
|
|
/* ************************************************************************** */
|
|
|
|
/* This routine exists in pango 1.8, but I depend on it, and I've only got 1.2*/
|
|
/* as a test bed. So... */
|
|
|
|
static void my_xft_render_layout(XftDraw *xftw,XftColor *fgcol,
|
|
PangoLayout *layout,int x,int y) {
|
|
PangoRectangle rect, r2;
|
|
PangoLayoutIter *iter;
|
|
|
|
iter = _pango_layout_get_iter(layout);
|
|
do {
|
|
PangoLayoutRun *run = _pango_layout_iter_get_run(iter);
|
|
if ( run!=NULL ) { /* NULL runs mark end of line */
|
|
_pango_layout_iter_get_run_extents(iter,&r2,&rect);
|
|
_pango_xft_render(xftw,fgcol,run->item->analysis.font,run->glyphs,
|
|
x+(rect.x+PANGO_SCALE/2)/PANGO_SCALE, y+(rect.y+PANGO_SCALE/2)/PANGO_SCALE);
|
|
/* I doubt I'm supposed to free (or unref) the run? */
|
|
}
|
|
} while ( _pango_layout_iter_next_run(iter));
|
|
_pango_layout_iter_free(iter);
|
|
}
|
|
|
|
# if !defined(_NO_LIBCAIRO) && PANGO_VERSION_MINOR>=10
|
|
/* Strangely the equivalent routine was not part of the pangocairo library */
|
|
/* Oh there's _pango_cairo_layout_path but that's more restrictive and probably*/
|
|
/* less efficient */
|
|
|
|
static void my_cairo_render_layout(cairo_t *cc, Color fg,
|
|
PangoLayout *layout,int x,int y) {
|
|
PangoRectangle rect, r2;
|
|
PangoLayoutIter *iter;
|
|
|
|
iter = _pango_layout_get_iter(layout);
|
|
do {
|
|
PangoLayoutRun *run = _pango_layout_iter_get_run(iter);
|
|
if ( run!=NULL ) { /* NULL runs mark end of line */
|
|
_pango_layout_iter_get_run_extents(iter,&r2,&rect);
|
|
_cairo_move_to(cc,x+(rect.x+PANGO_SCALE/2)/PANGO_SCALE, y+(rect.y+PANGO_SCALE/2)/PANGO_SCALE);
|
|
if ( COLOR_ALPHA(fg)==0 )
|
|
_cairo_set_source_rgba(cc,COLOR_RED(fg)/255.0,COLOR_GREEN(fg)/255.0,COLOR_BLUE(fg)/255.0,
|
|
1.0);
|
|
else
|
|
_cairo_set_source_rgba(cc,COLOR_RED(fg)/255.0,COLOR_GREEN(fg)/255.0,COLOR_BLUE(fg)/255.0,
|
|
COLOR_ALPHA(fg)/255.);
|
|
_pango_cairo_show_glyph_string(cc,run->item->analysis.font,run->glyphs);
|
|
}
|
|
} while ( _pango_layout_iter_next_run(iter));
|
|
_pango_layout_iter_free(iter);
|
|
}
|
|
#endif
|
|
|
|
/* ************************************************************************** */
|
|
/* ****************************** Pango Window ****************************** */
|
|
/* ************************************************************************** */
|
|
void _GXPDraw_NewWindow(GXWindow nw) {
|
|
GXDisplay *gdisp = nw->display;
|
|
|
|
MacVersionTest();
|
|
if ( !usepango || !_GXPDraw_hasPango())
|
|
return;
|
|
|
|
# if !defined(_NO_LIBCAIRO) && PANGO_VERSION_MINOR>=10
|
|
if ( nw->usecairo ) {
|
|
if ( _pango_cairo_font_map_create_context==NULL )
|
|
return;
|
|
/* using pango through cairo is different from using it on bare X */
|
|
if ( gdisp->pangoc_context==NULL ) {
|
|
gdisp->pangoc_fontmap = _pango_cairo_font_map_get_default();
|
|
gdisp->pangoc_context = _pango_cairo_font_map_create_context(
|
|
(PangoCairoFontMap *) (gdisp->pangoc_fontmap));
|
|
if ( _pango_cairo_context_set_resolution!=NULL )
|
|
_pango_cairo_context_set_resolution(gdisp->pangoc_context,
|
|
gdisp->res);
|
|
gdisp->pangoc_layout = _pango_layout_new(gdisp->pangoc_context);
|
|
}
|
|
} else
|
|
# endif
|
|
{
|
|
if ( gdisp->pango_context==NULL ) {
|
|
gdisp->pango_fontmap = _pango_xft_get_font_map(gdisp->display,gdisp->screen);
|
|
gdisp->pango_context = _pango_xft_get_context(gdisp->display,gdisp->screen);
|
|
/* No obvious way to get or set the resolution of pango_xft */
|
|
}
|
|
nw->xft_w = _XftDrawCreate(gdisp->display,nw->w,gdisp->visual,gdisp->cmap);
|
|
if ( gdisp->pango_layout==NULL )
|
|
gdisp->pango_layout = _pango_layout_new(gdisp->pango_context);
|
|
}
|
|
nw->usepango = true;
|
|
return;
|
|
}
|
|
|
|
void _GXPDraw_DestroyWindow(GXWindow nw) {
|
|
/* And why doesn't the man page mention this essential function? */
|
|
if ( nw->usepango && _XftDrawDestroy!=NULL && nw->xft_w!=NULL ) {
|
|
_XftDrawDestroy(nw->xft_w);
|
|
nw->xft_w = NULL;
|
|
}
|
|
}
|
|
|
|
/* ************************************************************************** */
|
|
/* ******************************* Pango Text ******************************* */
|
|
/* ************************************************************************** */
|
|
static PangoFontDescription *_GXPDraw_configfont(GXDisplay *gdisp, GFont *font,int pc) {
|
|
PangoFontDescription *fd;
|
|
#ifdef _NO_LIBCAIRO
|
|
PangoFontDescription **fdbase = &font->pango_fd;
|
|
#else
|
|
PangoFontDescription **fdbase = pc ? &font->pangoc_fd : &font->pango_fd;
|
|
#endif
|
|
|
|
if ( *fdbase!=NULL )
|
|
return( *fdbase );
|
|
*fdbase = fd = _pango_font_description_new();
|
|
|
|
if ( font->rq.utf8_family_name != NULL )
|
|
_pango_font_description_set_family(fd,font->rq.utf8_family_name);
|
|
else {
|
|
char *temp = u2utf8_copy(font->rq.family_name);
|
|
_pango_font_description_set_family(fd,temp);
|
|
free(temp);
|
|
}
|
|
_pango_font_description_set_style(fd,(font->rq.style&fs_italic)?
|
|
PANGO_STYLE_ITALIC:
|
|
PANGO_STYLE_NORMAL);
|
|
_pango_font_description_set_variant(fd,(font->rq.style&fs_smallcaps)?
|
|
PANGO_VARIANT_SMALL_CAPS:
|
|
PANGO_VARIANT_NORMAL);
|
|
_pango_font_description_set_weight(fd,font->rq.weight);
|
|
_pango_font_description_set_stretch(fd,
|
|
(font->rq.style&fs_condensed)? PANGO_STRETCH_CONDENSED :
|
|
(font->rq.style&fs_extended )? PANGO_STRETCH_EXPANDED :
|
|
PANGO_STRETCH_NORMAL);
|
|
|
|
if ( font->rq.point_size<=0 )
|
|
GDrawIError( "Bad point size for pango" ); /* any negative (pixel) values should be converted when font opened */
|
|
|
|
/* Pango doesn't give me any control over the resolution on X, so I do my */
|
|
/* own conversion from points to pixels */
|
|
/* But under pangocairo I can set the resolution, so behavior is different*/
|
|
/* But then, set_absolute_size doesn't exist in some versions of the */
|
|
/* library */
|
|
#ifndef no_pango_font_description_set_absolute_size
|
|
if ( _pango_font_description_set_absolute_size!=NULL ) {
|
|
_pango_font_description_set_absolute_size(fd,
|
|
GDrawPointsToPixels(NULL,font->rq.point_size*PANGO_SCALE));
|
|
} else
|
|
#endif
|
|
{
|
|
if ( pc ) /* pango Resolution set correctly */
|
|
_pango_font_description_set_size(fd,font->rq.point_size*PANGO_SCALE);
|
|
else /* pango Resolution probably wrong */
|
|
_pango_font_description_set_size(fd,(font->rq.point_size*gdisp->res+gdisp->xres/2)*PANGO_SCALE/gdisp->xres);
|
|
}
|
|
return( fd );
|
|
}
|
|
|
|
int32 _GXPDraw_DoText8(GWindow w, int32 x, int32 y,
|
|
const char *text, int32 cnt, FontMods *mods, Color col,
|
|
enum text_funcs drawit, struct tf_arg *arg) {
|
|
GXWindow gw = (GXWindow) w;
|
|
GXDisplay *gdisp = gw->display;
|
|
struct font_instance *fi = gw->ggc->fi;
|
|
PangoRectangle rect, ink;
|
|
PangoLayout *layout = gdisp->pango_layout;
|
|
PangoFontDescription *fd;
|
|
|
|
# if !defined(_NO_LIBCAIRO) && PANGO_VERSION_MINOR>=10
|
|
if ( gw->usecairo )
|
|
layout = gdisp->pangoc_layout;
|
|
# endif
|
|
fd = _GXPDraw_configfont(gdisp,fi,layout!=gdisp->pango_layout);
|
|
_pango_layout_set_font_description(layout,fd);
|
|
_pango_layout_set_text(layout,(char *) text,cnt);
|
|
_pango_layout_get_pixel_extents(layout,NULL,&rect);
|
|
if ( drawit==tf_drawit ) {
|
|
# if !defined(_NO_LIBCAIRO) && PANGO_VERSION_MINOR>=10
|
|
if ( gw->usecairo ) {
|
|
layout = gdisp->pangoc_layout;
|
|
my_cairo_render_layout(gw->cc,col,layout,x,y);
|
|
#if 0
|
|
_cairo_move_to(gw->cc,x,y - fi->ascent);
|
|
gw->ggc->fg = col;
|
|
GXCDrawSetcolfunc(gw,gw->ggc);
|
|
_pango_cairo_layout_path(gw->cc,layout);
|
|
_cairo_fill(gw->cc);
|
|
#endif
|
|
} else
|
|
#endif
|
|
{
|
|
XftColor fg;
|
|
XRenderColor fgcol;
|
|
XRectangle clip;
|
|
fgcol.red = COLOR_RED(col)<<8; fgcol.green = COLOR_GREEN(col)<<8; fgcol.blue = COLOR_BLUE(col)<<8;
|
|
if ( COLOR_ALPHA(col)!=0 )
|
|
fgcol.alpha = COLOR_ALPHA(col)*0x101;
|
|
else
|
|
fgcol.alpha = 0xffff;
|
|
_XftColorAllocValue(gdisp->display,gdisp->visual,gdisp->cmap,&fgcol,&fg);
|
|
clip.x = gw->ggc->clip.x;
|
|
clip.y = gw->ggc->clip.y;
|
|
clip.width = gw->ggc->clip.width;
|
|
clip.height = gw->ggc->clip.height;
|
|
_XftDrawSetClipRectangles(gw->xft_w,0,0,&clip,1);
|
|
my_xft_render_layout(gw->xft_w,&fg,layout,x,y);
|
|
}
|
|
} else if ( drawit==tf_rect ) {
|
|
PangoLayoutIter *iter;
|
|
PangoLayoutRun *run;
|
|
PangoFontMetrics *fm;
|
|
|
|
_pango_layout_get_pixel_extents(layout,&ink,&rect);
|
|
arg->size.lbearing = ink.x - rect.x;
|
|
arg->size.rbearing = ink.x+ink.width - rect.x;
|
|
arg->size.width = rect.width;
|
|
if ( *text=='\0' ) {
|
|
/* There are no runs if there are no characters */
|
|
memset(&arg->size,0,sizeof(arg->size));
|
|
} else {
|
|
iter = _pango_layout_get_iter(layout);
|
|
run = _pango_layout_iter_get_run(iter);
|
|
if ( run==NULL ) {
|
|
/* Pango doesn't give us runs in a couple of other places */
|
|
/* surrogates, not unicode (0xfffe, 0xffff), etc. */
|
|
memset(&arg->size,0,sizeof(arg->size));
|
|
} else {
|
|
fm = _pango_font_get_metrics(run->item->analysis.font,NULL);
|
|
arg->size.fas = _pango_font_metrics_get_ascent(fm)/PANGO_SCALE;
|
|
arg->size.fds = _pango_font_metrics_get_descent(fm)/PANGO_SCALE;
|
|
arg->size.as = ink.y + ink.height - arg->size.fds;
|
|
arg->size.ds = arg->size.fds - ink.y;
|
|
if ( arg->size.ds<0 ) {
|
|
--arg->size.as;
|
|
arg->size.ds = 0;
|
|
}
|
|
/* In the one case I've looked at fds is one pixel off from rect.y */
|
|
/* I don't know what to make of that */
|
|
_pango_font_metrics_unref(fm);
|
|
}
|
|
_pango_layout_iter_free(iter);
|
|
}
|
|
}
|
|
return( rect.width );
|
|
}
|
|
|
|
int32 _GXPDraw_DoText(GWindow w, int32 x, int32 y,
|
|
const unichar_t *text, int32 cnt, FontMods *mods, Color col,
|
|
enum text_funcs drawit, struct tf_arg *arg) {
|
|
char *temp = cnt>=0 ? u2utf8_copyn(text,cnt) : u2utf8_copy(text);
|
|
int width = _GXPDraw_DoText8(w,x,y,temp,-1,mods,col,drawit,arg);
|
|
free(temp);
|
|
return(width);
|
|
}
|
|
|
|
void _GXPDraw_FontMetrics(GXWindow gw,GFont *fi,int *as, int *ds, int *ld) {
|
|
GXDisplay *gdisp = gw->display;
|
|
PangoFont *pfont;
|
|
PangoFontMetrics *fm;
|
|
|
|
# if !defined(_NO_LIBCAIRO) && PANGO_VERSION_MINOR>=10
|
|
if ( gw->usecairo ) {
|
|
_GXPDraw_configfont(gdisp,fi,true);
|
|
pfont = _pango_font_map_load_font(gdisp->pangoc_fontmap,gdisp->pangoc_context,
|
|
fi->pangoc_fd);
|
|
} else
|
|
#endif
|
|
{
|
|
_GXPDraw_configfont(gdisp,fi,false);
|
|
pfont = _pango_font_map_load_font(gdisp->pango_fontmap,gdisp->pango_context,
|
|
fi->pango_fd);
|
|
}
|
|
fm = _pango_font_get_metrics(pfont,NULL);
|
|
*as = _pango_font_metrics_get_ascent(fm)/PANGO_SCALE;
|
|
*ds = _pango_font_metrics_get_descent(fm)/PANGO_SCALE;
|
|
*ld = 0;
|
|
_pango_font_metrics_unref(fm);
|
|
}
|
|
|
|
/* ************************************************************************** */
|
|
/* ****************************** Pango Layout ****************************** */
|
|
/* ************************************************************************** */
|
|
void _GXPDraw_LayoutInit(GWindow w, char *text, int cnt, GFont *fi) {
|
|
GXWindow gw = (GXWindow) w;
|
|
GXDisplay *gdisp = gw->display;
|
|
PangoLayout *layout = gdisp->pango_layout;
|
|
PangoFontDescription *fd;
|
|
|
|
if ( fi==NULL )
|
|
fi = gw->ggc->fi;
|
|
|
|
# if !defined(_NO_LIBCAIRO) && PANGO_VERSION_MINOR>=10
|
|
if ( gw->usecairo )
|
|
layout = gdisp->pangoc_layout;
|
|
# endif
|
|
fd = _GXPDraw_configfont(gdisp,fi,layout!=gdisp->pango_layout);
|
|
_pango_layout_set_font_description(layout,fd);
|
|
_pango_layout_set_text(layout,(char *) text,cnt);
|
|
}
|
|
|
|
void _GXPDraw_LayoutDraw(GWindow w, int32 x, int32 y, Color col) {
|
|
GXWindow gw = (GXWindow) w;
|
|
GXDisplay *gdisp = gw->display;
|
|
PangoLayout *layout = gdisp->pango_layout;
|
|
|
|
# if !defined(_NO_LIBCAIRO) && PANGO_VERSION_MINOR>=10
|
|
if ( gw->usecairo ) {
|
|
layout = gdisp->pangoc_layout;
|
|
my_cairo_render_layout(gw->cc,col,layout,x,y);
|
|
} else
|
|
#endif
|
|
{
|
|
XftColor fg;
|
|
XRenderColor fgcol;
|
|
XRectangle clip;
|
|
fgcol.red = COLOR_RED(col)<<8; fgcol.green = COLOR_GREEN(col)<<8; fgcol.blue = COLOR_BLUE(col)<<8;
|
|
if ( COLOR_ALPHA(col)!=0 )
|
|
fgcol.alpha = COLOR_ALPHA(col)*0x101;
|
|
else
|
|
fgcol.alpha = 0xffff;
|
|
_XftColorAllocValue(gdisp->display,gdisp->visual,gdisp->cmap,&fgcol,&fg);
|
|
clip.x = gw->ggc->clip.x;
|
|
clip.y = gw->ggc->clip.y;
|
|
clip.width = gw->ggc->clip.width;
|
|
clip.height = gw->ggc->clip.height;
|
|
_XftDrawSetClipRectangles(gw->xft_w,0,0,&clip,1);
|
|
my_xft_render_layout(gw->xft_w,&fg,layout,x,y);
|
|
}
|
|
}
|
|
|
|
void _GXPDraw_LayoutIndexToPos(GWindow w, int index, GRect *pos) {
|
|
GXWindow gw = (GXWindow) w;
|
|
GXDisplay *gdisp = gw->display;
|
|
PangoLayout *layout = gdisp->pango_layout;
|
|
PangoRectangle rect;
|
|
|
|
# if !defined(_NO_LIBCAIRO) && PANGO_VERSION_MINOR>=10
|
|
if ( gw->usecairo )
|
|
layout = gdisp->pangoc_layout;
|
|
# endif
|
|
_pango_layout_index_to_pos(layout,index,&rect);
|
|
pos->x = rect.x/PANGO_SCALE; pos->y = rect.y/PANGO_SCALE; pos->width = rect.width/PANGO_SCALE; pos->height = rect.height/PANGO_SCALE;
|
|
}
|
|
|
|
int _GXPDraw_LayoutXYToIndex(GWindow w, int x, int y) {
|
|
GXWindow gw = (GXWindow) w;
|
|
GXDisplay *gdisp = gw->display;
|
|
PangoLayout *layout = gdisp->pango_layout;
|
|
int trailing, index;
|
|
|
|
# if !defined(_NO_LIBCAIRO) && PANGO_VERSION_MINOR>=10
|
|
if ( gw->usecairo )
|
|
layout = gdisp->pangoc_layout;
|
|
# endif
|
|
/* Pango retuns the last character if x is negative, not the first */
|
|
if ( x<0 ) x=0;
|
|
_pango_layout_xy_to_index(layout,x*PANGO_SCALE,y*PANGO_SCALE,&index,&trailing);
|
|
/* If I give pango a position after the last character on a line, it */
|
|
/* returns to me the first character. Strange. And annoying -- you click */
|
|
/* at the end of a line and the cursor moves to the start */
|
|
/* Of course in right to left text an initial position is correct... */
|
|
if ( index+trailing==0 && x>0 ) {
|
|
PangoRectangle rect;
|
|
_pango_layout_get_pixel_extents(layout,&rect,NULL);
|
|
if ( x>=rect.width ) {
|
|
x = rect.width-1;
|
|
_pango_layout_xy_to_index(layout,x*PANGO_SCALE,y*PANGO_SCALE,&index,&trailing);
|
|
}
|
|
}
|
|
return( index+trailing );
|
|
}
|
|
|
|
void _GXPDraw_LayoutExtents(GWindow w, GRect *size) {
|
|
GXWindow gw = (GXWindow) w;
|
|
GXDisplay *gdisp = gw->display;
|
|
PangoLayout *layout = gdisp->pango_layout;
|
|
PangoRectangle rect;
|
|
|
|
# if !defined(_NO_LIBCAIRO) && PANGO_VERSION_MINOR>=10
|
|
if ( gw->usecairo )
|
|
layout = gdisp->pangoc_layout;
|
|
# endif
|
|
_pango_layout_get_pixel_extents(layout,NULL,&rect);
|
|
size->x = rect.x; size->y = rect.y; size->width = rect.width; size->height = rect.height;
|
|
}
|
|
|
|
void _GXPDraw_LayoutSetWidth(GWindow w, int width) {
|
|
GXWindow gw = (GXWindow) w;
|
|
GXDisplay *gdisp = gw->display;
|
|
PangoLayout *layout = gdisp->pango_layout;
|
|
|
|
# if !defined(_NO_LIBCAIRO) && PANGO_VERSION_MINOR>=10
|
|
if ( gw->usecairo )
|
|
layout = gdisp->pangoc_layout;
|
|
# endif
|
|
_pango_layout_set_width(layout,width==-1? -1 : width*PANGO_SCALE);
|
|
}
|
|
|
|
int _GXPDraw_LayoutLineCount(GWindow w) {
|
|
GXWindow gw = (GXWindow) w;
|
|
GXDisplay *gdisp = gw->display;
|
|
PangoLayout *layout = gdisp->pango_layout;
|
|
|
|
# if !defined(_NO_LIBCAIRO) && PANGO_VERSION_MINOR>=10
|
|
if ( gw->usecairo )
|
|
layout = gdisp->pangoc_layout;
|
|
# endif
|
|
return( _pango_layout_get_line_count(layout));
|
|
}
|
|
|
|
int _GXPDraw_LayoutLineStart(GWindow w, int l) {
|
|
GXWindow gw = (GXWindow) w;
|
|
GXDisplay *gdisp = gw->display;
|
|
PangoLayout *layout = gdisp->pango_layout;
|
|
PangoLayoutLine *line;
|
|
|
|
# if !defined(_NO_LIBCAIRO) && PANGO_VERSION_MINOR>=10
|
|
if ( gw->usecairo )
|
|
layout = gdisp->pangoc_layout;
|
|
# endif
|
|
line = _pango_layout_get_line(layout,l);
|
|
if ( line==NULL )
|
|
return( -1 );
|
|
|
|
return( line->start_index );
|
|
}
|
|
#endif /* _NO_LIBPANGO */
|