gtk/gdk/linux-fb/gdkdrawable-fb2.c
Alex Larsson c16e87bcba Initialize image->bits_per_pixel from the drawable, not from the root
2001-07-26  Alex Larsson  <alexl@redhat.com>

	* gdk/linux-fb/gdkimage-fb.c (_gdk_fb_get_image):
	Initialize image->bits_per_pixel from the drawable, not from
	the root window.

	* gdk/linux-fb/gdkdrawable-fb2.c (gdk_fb_get_depth):
	Fix cast. argument is an IMPL already.
2001-07-26 20:07:08 +00:00

1640 lines
44 KiB
C

#include "config.h"
#include "gdkprivate-fb.h"
#include "mi.h"
#include <string.h>
#include <gdkregion-generic.h>
#include <pango/pangoft2.h>
#include <freetype/ftglyph.h>
#ifndef g_alloca
#define g_alloca alloca
#endif
void gdk_fb_draw_rectangle (GdkDrawable *drawable,
GdkGC *gc,
gint filled,
gint x,
gint y,
gint width,
gint height);
static void gdk_fb_draw_arc (GdkDrawable *drawable,
GdkGC *gc,
gint filled,
gint x,
gint y,
gint width,
gint height,
gint angle1,
gint angle2);
static void gdk_fb_draw_polygon (GdkDrawable *drawable,
GdkGC *gc,
gint filled,
GdkPoint *points,
gint npoints);
static void gdk_fb_draw_text (GdkDrawable *drawable,
GdkFont *font,
GdkGC *gc,
gint x,
gint y,
const gchar *text,
gint text_length);
static void gdk_fb_draw_text_wc (GdkDrawable *drawable,
GdkFont *font,
GdkGC *gc,
gint x,
gint y,
const GdkWChar *text,
gint text_length);
static void gdk_fb_draw_glyphs (GdkDrawable *drawable,
GdkGC *gc,
PangoFont *font,
gint x,
gint y,
PangoGlyphString *glyphs);
void gdk_fb_draw_drawable (GdkDrawable *drawable,
GdkGC *gc,
GdkPixmap *src,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height);
static void gdk_fb_draw_image (GdkDrawable *drawable,
GdkGC *gc,
GdkImage *image,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height);
static void gdk_fb_draw_points (GdkDrawable *drawable,
GdkGC *gc,
GdkPoint *points,
gint npoints);
static void gdk_fb_draw_segments (GdkDrawable *drawable,
GdkGC *gc,
GdkSegment *segs,
gint nsegs);
static void gdk_fb_draw_lines (GdkDrawable *drawable,
GdkGC *gc,
GdkPoint *points,
gint npoints);
static GdkColormap* gdk_fb_get_colormap (GdkDrawable *drawable);
static void gdk_fb_set_colormap (GdkDrawable *drawable,
GdkColormap *colormap);
static gint gdk_fb_get_depth (GdkDrawable *drawable);
static GdkVisual* gdk_fb_get_visual (GdkDrawable *drawable);
static void gdk_fb_drawable_finalize (GObject *object);
#ifdef ENABLE_SHADOW_FB
static void gdk_shadow_fb_draw_rectangle (GdkDrawable *drawable,
GdkGC *gc,
gint filled,
gint x,
gint y,
gint width,
gint height);
static void gdk_shadow_fb_draw_arc (GdkDrawable *drawable,
GdkGC *gc,
gint filled,
gint x,
gint y,
gint width,
gint height,
gint angle1,
gint angle2);
static void gdk_shadow_fb_draw_polygon (GdkDrawable *drawable,
GdkGC *gc,
gint filled,
GdkPoint *points,
gint npoints);
static void gdk_shadow_fb_draw_text (GdkDrawable *drawable,
GdkFont *font,
GdkGC *gc,
gint x,
gint y,
const gchar *text,
gint text_length);
static void gdk_shadow_fb_draw_text_wc (GdkDrawable *drawable,
GdkFont *font,
GdkGC *gc,
gint x,
gint y,
const GdkWChar *text,
gint text_length);
static void gdk_shadow_fb_draw_glyphs (GdkDrawable *drawable,
GdkGC *gc,
PangoFont *font,
gint x,
gint y,
PangoGlyphString *glyphs);
static void gdk_shadow_fb_draw_drawable (GdkDrawable *drawable,
GdkGC *gc,
GdkPixmap *src,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height);
static void gdk_shadow_fb_draw_image (GdkDrawable *drawable,
GdkGC *gc,
GdkImage *image,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height);
static void gdk_shadow_fb_draw_points (GdkDrawable *drawable,
GdkGC *gc,
GdkPoint *points,
gint npoints);
static void gdk_shadow_fb_draw_segments (GdkDrawable *drawable,
GdkGC *gc,
GdkSegment *segs,
gint nsegs);
static void gdk_shadow_fb_draw_lines (GdkDrawable *drawable,
GdkGC *gc,
GdkPoint *points,
gint npoints);
#endif
static gpointer parent_class = NULL;
static void
gdk_fb_get_size (GdkDrawable *d, gint *width, gint *height)
{
if (width)
*width = GDK_DRAWABLE_FBDATA (d)->width;
if (height)
*height = GDK_DRAWABLE_FBDATA (d)->height;
}
static void
gdk_drawable_impl_fb_class_init (GdkDrawableFBClass *klass)
{
GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
object_class->finalize = gdk_fb_drawable_finalize;
drawable_class->create_gc = _gdk_fb_gc_new;
#ifdef ENABLE_SHADOW_FB
drawable_class->draw_rectangle = gdk_shadow_fb_draw_rectangle;
drawable_class->draw_arc = gdk_shadow_fb_draw_arc;
drawable_class->draw_polygon = gdk_shadow_fb_draw_polygon;
drawable_class->draw_text = gdk_shadow_fb_draw_text;
drawable_class->draw_text_wc = gdk_shadow_fb_draw_text_wc;
drawable_class->draw_drawable = gdk_shadow_fb_draw_drawable;
drawable_class->draw_points = gdk_shadow_fb_draw_points;
drawable_class->draw_segments = gdk_shadow_fb_draw_segments;
drawable_class->draw_lines = gdk_shadow_fb_draw_lines;
drawable_class->draw_glyphs = gdk_shadow_fb_draw_glyphs;
drawable_class->draw_image = gdk_shadow_fb_draw_image;
#else
drawable_class->draw_rectangle = gdk_fb_draw_rectangle;
drawable_class->draw_arc = gdk_fb_draw_arc;
drawable_class->draw_polygon = gdk_fb_draw_polygon;
drawable_class->draw_text = gdk_fb_draw_text;
drawable_class->draw_text_wc = gdk_fb_draw_text_wc;
drawable_class->draw_drawable = gdk_fb_draw_drawable;
drawable_class->draw_points = gdk_fb_draw_points;
drawable_class->draw_segments = gdk_fb_draw_segments;
drawable_class->draw_lines = gdk_fb_draw_lines;
drawable_class->draw_glyphs = gdk_fb_draw_glyphs;
drawable_class->draw_image = gdk_fb_draw_image;
#endif
drawable_class->set_colormap = gdk_fb_set_colormap;
drawable_class->get_colormap = gdk_fb_get_colormap;
drawable_class->get_size = gdk_fb_get_size;
drawable_class->get_depth = gdk_fb_get_depth;
drawable_class->get_visual = gdk_fb_get_visual;
drawable_class->get_image = _gdk_fb_get_image;
}
static void
gdk_fb_drawable_finalize (GObject *object)
{
gdk_drawable_set_colormap (GDK_DRAWABLE (object), NULL);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
GType
gdk_drawable_impl_fb_get_type (void)
{
static GType object_type = 0;
if (!object_type)
{
static const GTypeInfo object_info =
{
sizeof (GdkDrawableFBClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gdk_drawable_impl_fb_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GdkDrawableFBData),
0, /* n_preallocs */
(GInstanceInitFunc) NULL,
};
object_type = g_type_register_static (GDK_TYPE_DRAWABLE,
"GdkDrawableFB",
&object_info,
0);
}
return object_type;
}
/*****************************************************
* FB specific implementations of generic functions *
*****************************************************/
static GdkColormap*
gdk_fb_get_colormap (GdkDrawable *drawable)
{
GdkColormap *retval = GDK_DRAWABLE_FBDATA (drawable)->colormap;
if (!retval)
retval = gdk_colormap_get_system ();
return retval;
}
static void
gdk_fb_set_colormap (GdkDrawable *drawable,
GdkColormap *colormap)
{
GdkDrawableFBData *private;
private = GDK_DRAWABLE_FBDATA (drawable);
if (private->colormap == colormap)
return;
if (private->colormap)
gdk_colormap_unref (private->colormap);
private->colormap = colormap;
if (private->colormap)
gdk_colormap_ref (private->colormap);
}
/* Calculates the real clipping region for a drawable, taking into account
* other windows, gc clip region and gc clip mask.
*/
GdkRegion *
gdk_fb_clip_region (GdkDrawable *drawable,
GdkGC *gc,
gboolean do_clipping,
gboolean do_children,
gboolean full_shapes)
{
GdkRectangle draw_rect;
GdkRegion *real_clip_region, *tmpreg, *shape;
gboolean skipit = FALSE;
GdkDrawableFBData *private;
GdkWindowObject *parent;
GDK_CHECK_IMPL (drawable);
private = GDK_DRAWABLE_FBDATA (drawable);
g_assert(!GDK_IS_WINDOW (private->wrapper) ||
!GDK_WINDOW_P (private->wrapper)->input_only);
draw_rect.x = private->llim_x;
draw_rect.y = private->llim_y;
if (!GDK_IS_WINDOW (private) ||
GDK_WINDOW_IS_MAPPED (private->wrapper))
{
draw_rect.width = private->lim_x - draw_rect.x;
draw_rect.height = private->lim_y - draw_rect.y;
}
else
{
draw_rect.width = draw_rect.height = 0;
skipit = TRUE;
}
real_clip_region = gdk_region_rectangle (&draw_rect);
if (skipit)
return real_clip_region;
if (GDK_IS_WINDOW (private->wrapper))
{
parent = GDK_WINDOW_P (private->wrapper);
while (parent != (GdkWindowObject *)gdk_parent_root)
{
if (full_shapes)
{
shape = gdk_fb_window_get_abs_shape (GDK_DRAWABLE (parent));
if (shape)
{
gdk_region_intersect (real_clip_region, shape);
gdk_region_destroy (shape);
}
}
else
{
gint dx, dy;
shape = gdk_fb_window_peek_shape (GDK_DRAWABLE (parent), &dx, &dy);
if (shape)
{
GdkRectangle rect;
GdkRegion *reg;
gdk_region_get_clipbox (shape, &rect);
rect.x += GDK_DRAWABLE_IMPL_FBDATA (parent)->abs_x + dx;
rect.y += GDK_DRAWABLE_IMPL_FBDATA (parent)->abs_y + dy;
reg = gdk_region_rectangle(&rect);
gdk_region_intersect (real_clip_region, reg);
gdk_region_destroy (reg);
}
}
parent = parent->parent;
}
}
if (gc && GDK_GC_FBDATA(gc)->values.subwindow_mode == GDK_INCLUDE_INFERIORS)
do_children = FALSE;
if (do_clipping &&
GDK_IS_WINDOW (private->wrapper) &&
GDK_WINDOW_IS_MAPPED (private->wrapper) &&
!GDK_WINDOW_P (private->wrapper)->input_only)
{
GdkWindow *parentwin, *lastwin;
GdkDrawableFBData *impl_private;
lastwin = private->wrapper;
if (do_children)
parentwin = lastwin;
else
parentwin = (GdkWindow *)GDK_WINDOW_P (lastwin)->parent;
/* Remove the areas of all overlapping windows above parentwin in the hiearachy */
for (; parentwin; lastwin = parentwin, parentwin = (GdkWindow *)GDK_WINDOW_P (parentwin)->parent)
{
GList *cur;
for (cur = GDK_WINDOW_P (parentwin)->children; cur && cur->data != lastwin; cur = cur->next)
{
if (!GDK_WINDOW_IS_MAPPED (cur->data) || GDK_WINDOW_P (cur->data)->input_only)
continue;
impl_private = GDK_DRAWABLE_IMPL_FBDATA(cur->data);
/* This shortcut is really necessary for performance when there are a lot of windows */
if (impl_private->llim_x >= real_clip_region->extents.x2 ||
impl_private->lim_x <= real_clip_region->extents.x1 ||
impl_private->llim_y >= real_clip_region->extents.y2 ||
impl_private->lim_y <= real_clip_region->extents.y1)
continue;
draw_rect.x = impl_private->llim_x;
draw_rect.y = impl_private->llim_y;
draw_rect.width = impl_private->lim_x - draw_rect.x;
draw_rect.height = impl_private->lim_y - draw_rect.y;
tmpreg = gdk_region_rectangle (&draw_rect);
shape = gdk_fb_window_get_abs_shape (impl_private->wrapper);
if (shape)
{
gdk_region_intersect (tmpreg, shape);
gdk_region_destroy (shape);
}
gdk_region_subtract (real_clip_region, tmpreg);
gdk_region_destroy (tmpreg);
}
}
}
if (gc)
{
if (GDK_GC_FBDATA (gc)->clip_region)
{
tmpreg = gdk_region_copy (GDK_GC_FBDATA (gc)->clip_region);
gdk_region_offset (tmpreg, private->abs_x + GDK_GC_P (gc)->clip_x_origin,
private->abs_y + GDK_GC_P (gc)->clip_y_origin);
gdk_region_intersect (real_clip_region, tmpreg);
gdk_region_destroy (tmpreg);
}
if (GDK_GC_FBDATA (gc)->values.clip_mask)
{
GdkDrawable *cmask = GDK_GC_FBDATA (gc)->values.clip_mask;
GdkDrawableFBData *cmask_private;
cmask_private = GDK_DRAWABLE_IMPL_FBDATA (cmask);
g_assert (cmask_private->depth == 1);
g_assert (cmask_private->abs_x == 0 &&
cmask_private->abs_y == 0);
draw_rect.x = private->abs_x +
cmask_private->llim_x +
GDK_GC_FBDATA (gc)->values.clip_x_origin;
draw_rect.y = private->abs_y +
cmask_private->llim_y +
GDK_GC_FBDATA (gc)->values.clip_y_origin;
draw_rect.width = cmask_private->width;
draw_rect.height = cmask_private->height;
tmpreg = gdk_region_rectangle (&draw_rect);
gdk_region_intersect (real_clip_region, tmpreg);
gdk_region_destroy (tmpreg);
/*
if (!real_clip_region->numRects)
g_warning ("Empty clip region");
*/
}
}
return real_clip_region;
}
struct GdkSpanHelper
{
GdkDrawable *drawable;
GdkGC *gc;
GdkColor color;
};
static void
gdk_fb_fill_span_helper(GdkSpan *span,
gpointer data)
{
struct GdkSpanHelper *info = (struct GdkSpanHelper *)data;
GdkGC * gc = info->gc;
(GDK_GC_FBDATA (gc)->fill_span) (info->drawable, gc, span, &info->color);
}
void
gdk_fb_fill_spans (GdkDrawable *real_drawable,
GdkGC *gc,
GdkSpan *spans,
int nspans,
gboolean sorted)
{
int i;
struct GdkSpanHelper info;
GdkRegion *real_clip_region;
gboolean handle_cursor = FALSE;
GdkDrawable *drawable;
GdkDrawableFBData *private;
drawable = real_drawable;
private = GDK_DRAWABLE_FBDATA (drawable);
g_assert (gc);
if (GDK_IS_WINDOW (private->wrapper) && !GDK_WINDOW_IS_MAPPED (private->wrapper))
return;
if (GDK_IS_WINDOW (private->wrapper) && GDK_WINDOW_P (private->wrapper)->input_only)
g_error ("Drawing on the evil input-only!");
info.drawable = drawable;
info.gc = gc;
if (GDK_GC_FBDATA (gc)->values_mask & GDK_GC_FOREGROUND)
info.color = GDK_GC_FBDATA (gc)->values.foreground;
else if (GDK_IS_WINDOW (private->wrapper))
info.color = GDK_WINDOW_P (private->wrapper)->bg_color;
else
gdk_color_black (private->colormap, &info.color);
real_clip_region = gdk_fb_clip_region (drawable, gc, TRUE, GDK_GC_FBDATA (gc)->values.function != GDK_INVERT, TRUE);
if (private->mem == GDK_DRAWABLE_IMPL_FBDATA (gdk_parent_root)->mem &&
gdk_fb_cursor_region_need_hide (real_clip_region))
{
handle_cursor = TRUE;
gdk_fb_cursor_hide ();
}
for (i = 0; i < nspans; i++)
{
GdkSpan *cur;
cur = &spans[i];
cur->x += private->abs_x;
cur->y += private->abs_y;
if ( (cur->y < private->llim_y) || (cur->y >= private->lim_y))
cur->width = 0;
if (cur->x < private->llim_x)
{
cur->width -= private->llim_x - cur->x;
cur->x = private->llim_x;
}
if (cur->x + cur->width > private->lim_x)
{
cur->width = private->lim_x - cur->x;
}
if (cur->width <= 0)
cur->width = 0;
}
gdk_region_spans_intersect_foreach (real_clip_region,
spans,
nspans,
sorted,
gdk_fb_fill_span_helper,
&info);
gdk_region_destroy (real_clip_region);
if (handle_cursor)
gdk_fb_cursor_unhide ();
}
void
gdk_fb_drawing_context_init (GdkFBDrawingContext *dc,
GdkDrawable *drawable,
GdkGC *gc,
gboolean draw_bg,
gboolean do_clipping)
{
GdkDrawableFBData *private = GDK_DRAWABLE_FBDATA (drawable);
dc->mem = private->mem;
dc->rowstride = private->rowstride;
dc->handle_cursor = FALSE;
dc->bgpm = NULL;
dc->bg_relto = private->wrapper;
dc->draw_bg = draw_bg;
GDK_CHECK_IMPL (drawable);
if (GDK_IS_WINDOW (private->wrapper))
{
dc->bgpm = GDK_WINDOW_P (private->wrapper)->bg_pixmap;
if (dc->bgpm == GDK_PARENT_RELATIVE_BG)
{
for (; dc->bgpm == GDK_PARENT_RELATIVE_BG && dc->bg_relto; dc->bg_relto = (GdkWindow *)GDK_WINDOW_P (dc->bg_relto)->parent)
dc->bgpm = GDK_WINDOW_P (dc->bg_relto)->bg_pixmap;
}
if (dc->bgpm == GDK_NO_BG)
dc->bgpm = NULL;
}
dc->clipxoff = - private->abs_x;
dc->clipyoff = - private->abs_y;
dc->real_clip_region = gdk_fb_clip_region (drawable, gc, do_clipping, TRUE, TRUE);
if (gc)
{
dc->clipxoff -= GDK_GC_FBDATA (gc)->values.clip_x_origin;
dc->clipyoff -= GDK_GC_FBDATA (gc)->values.clip_y_origin;
if (GDK_GC_FBDATA (gc)->values.clip_mask)
{
dc->clipmem = GDK_DRAWABLE_IMPL_FBDATA (GDK_GC_FBDATA (gc)->values.clip_mask)->mem;
dc->clip_rowstride = GDK_DRAWABLE_IMPL_FBDATA (GDK_GC_FBDATA (gc)->values.clip_mask)->rowstride;
}
}
if (do_clipping &&
private->mem == GDK_DRAWABLE_IMPL_FBDATA (gdk_parent_root)->mem &&
gdk_fb_cursor_region_need_hide (dc->real_clip_region))
{
dc->handle_cursor = TRUE;
gdk_fb_cursor_hide ();
}
}
void
gdk_fb_drawing_context_finalize (GdkFBDrawingContext *dc)
{
gdk_region_destroy (dc->real_clip_region);
if (dc->handle_cursor)
gdk_fb_cursor_unhide ();
}
void
gdk_fb_draw_drawable_2 (GdkDrawable *drawable,
GdkGC *gc,
GdkPixmap *src,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height,
gboolean draw_bg,
gboolean do_clipping)
{
GdkFBDrawingContext *dc, dc_data;
dc = &dc_data;
GDK_CHECK_IMPL (src);
GDK_CHECK_IMPL (drawable);
gdk_fb_drawing_context_init (dc, drawable, gc, draw_bg, do_clipping);
gdk_fb_draw_drawable_3 (drawable, gc, src, dc, xsrc, ysrc, xdest, ydest, width, height);
gdk_fb_drawing_context_finalize (dc);
}
void
gdk_fb_draw_drawable_3 (GdkDrawable *drawable,
GdkGC *gc,
GdkPixmap *src,
GdkFBDrawingContext *dc,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height)
{
GdkDrawableFBData *private = GDK_DRAWABLE_FBDATA (drawable);
GdkDrawableFBData *src_private = GDK_DRAWABLE_FBDATA (src);
GdkRectangle rect;
int src_x_off, src_y_off;
GdkRegion *tmpreg, *real_clip_region;
int i;
int draw_direction = 1;
gdk_fb_draw_drawable_func *draw_func = NULL;
GdkGCFBData *gc_private;
g_assert (gc);
GDK_CHECK_IMPL (src);
GDK_CHECK_IMPL (drawable);
if (GDK_IS_WINDOW (private->wrapper))
{
if (!GDK_WINDOW_IS_MAPPED (private->wrapper))
return;
if (GDK_WINDOW_P (private->wrapper)->input_only)
g_error ("Drawing on the evil input-only!");
}
gc_private = GDK_GC_FBDATA (gc);
if (drawable == src)
{
GdkRegionBox srcb, destb;
srcb.x1 = xsrc;
srcb.y1 = ysrc;
srcb.x2 = xsrc + width;
srcb.y2 = ysrc + height;
destb.x1 = xdest;
destb.y1 = ydest;
destb.x2 = xdest + width;
destb.y2 = ydest + height;
if (EXTENTCHECK (&srcb, &destb) && ((ydest > ysrc) || ((ydest == ysrc) && (xdest > xsrc))))
draw_direction = -1;
}
switch (src_private->depth)
{
case 1:
draw_func = gc_private->draw_drawable[GDK_FB_SRC_BPP_1];
break;
case 8:
draw_func = gc_private->draw_drawable[GDK_FB_SRC_BPP_8];
break;
case 16:
draw_func = gc_private->draw_drawable[GDK_FB_SRC_BPP_16];
break;
case 24:
draw_func = gc_private->draw_drawable[GDK_FB_SRC_BPP_24];
break;
case 32:
draw_func = gc_private->draw_drawable[GDK_FB_SRC_BPP_32];
break;
case 77:
draw_func = gc_private->draw_drawable[GDK_FB_SRC_BPP_7_AA_GRAYVAL];
break;
case 78:
draw_func = gc_private->draw_drawable[GDK_FB_SRC_BPP_8_AA_GRAYVAL];
break;
default:
g_assert_not_reached ();
break;
}
/* Do some magic to avoid creating extra regions unnecessarily */
tmpreg = dc->real_clip_region;
rect.x = xdest + private->abs_x;
rect.y = ydest + private->abs_y;
rect.width = width;
rect.height = height;
real_clip_region = gdk_region_rectangle (&rect);
gdk_region_intersect (real_clip_region, tmpreg);
rect.x = xdest + private->abs_x;
rect.y = ydest + private->abs_y;
rect.width = MAX (src_private->width - xsrc, 0);
rect.height = MAX (src_private->height - ysrc, 0);
if (!rect.width || !rect.height)
goto out;
tmpreg = gdk_region_rectangle (&rect);
gdk_region_intersect (real_clip_region, tmpreg);
gdk_region_destroy (tmpreg);
src_x_off = (src_private->abs_x + xsrc) - (private->abs_x + xdest);
src_y_off = (src_private->abs_y + ysrc) - (private->abs_y + ydest);
for (i = (draw_direction>0)?0:real_clip_region->numRects-1; i >= 0 && i < real_clip_region->numRects; i+=draw_direction)
{
GdkRegionBox *cur = &real_clip_region->rects[i];
(*draw_func) (drawable,
gc,
src,
dc,
cur->y1,
cur->y2,
cur->x1,
cur->x2,
src_x_off,
src_y_off,
draw_direction);
}
out:
gdk_region_destroy (real_clip_region);
}
void
gdk_fb_draw_drawable (GdkDrawable *drawable,
GdkGC *gc,
GdkPixmap *src,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height)
{
GdkPixmap *src_impl;
if (GDK_IS_DRAWABLE_IMPL_FBDATA (src))
src_impl = src;
else
src_impl = GDK_DRAWABLE_IMPL (src);
GDK_CHECK_IMPL (drawable);
gdk_fb_draw_drawable_2 (drawable, gc, src_impl , xsrc, ysrc, xdest, ydest, width, height, TRUE, TRUE);
}
#ifdef EMULATE_GDKFONT
static void
gdk_fb_draw_text(GdkDrawable *drawable,
GdkFont *font,
GdkGC *gc,
gint x,
gint y,
const gchar *text,
gint text_length)
{
GdkFontPrivateFB *private;
guchar *utf8, *utf8_end;
PangoGlyphString *glyphs = pango_glyph_string_new ();
PangoEngineShape *shaper, *last_shaper;
PangoAnalysis analysis;
guchar *p, *start;
gint x_offset;
int i;
g_return_if_fail (font != NULL);
g_return_if_fail (text != NULL);
private = (GdkFontPrivateFB*) font;
utf8 = alloca (text_length*2);
/* Convert latin-1 to utf8 */
p = utf8;
for (i = 0; i < text_length; i++)
{
if (text[i]==0)
*p++ = 1; /* Hack to handle embedded nulls */
else
{
if(((guchar)text[i])<128)
*p++ = text[i];
else
{
*p++ = ((((guchar)text[i])>>6) & 0x3f) | 0xC0;
*p++ = (((guchar)text[i]) & 0x3f) | 0x80;
}
}
}
utf8_end = p;
last_shaper = NULL;
shaper = NULL;
x_offset = 0;
p = start = utf8;
while (p < utf8_end)
{
gunichar wc = g_utf8_get_char (p);
p = g_utf8_next_char (p);
shaper = pango_font_find_shaper (private->pango_font, "fr", wc);
if (shaper != last_shaper)
{
analysis.shape_engine = shaper;
analysis.lang_engine = NULL;
analysis.font = private->pango_font;
analysis.level = 0;
pango_shape (start, p - start, &analysis, glyphs);
gdk_fb_draw_glyphs (drawable, gc, private->pango_font,
x + PANGO_PIXELS (x_offset), y,
glyphs);
for (i = 0; i < glyphs->num_glyphs; i++)
x_offset += glyphs->glyphs[i].geometry.width;
start = p;
}
last_shaper = shaper;
}
if (p > start)
{
analysis.shape_engine = shaper;
analysis.lang_engine = NULL;
analysis.font = private->pango_font;
analysis.level = 0;
pango_shape (start, p - start, &analysis, glyphs);
gdk_fb_draw_glyphs (drawable, gc, private->pango_font,
x + PANGO_PIXELS (x_offset), y,
glyphs);
}
pango_glyph_string_free (glyphs);
return;
}
#else
static void
gdk_fb_draw_text(GdkDrawable *drawable,
GdkFont *font,
GdkGC *gc,
gint x,
gint y,
const gchar *text,
gint text_length)
{
g_warning ("gdk_fb_draw_text NYI");
}
#endif
static void
gdk_fb_draw_text_wc (GdkDrawable *drawable,
GdkFont *font,
GdkGC *gc,
gint x,
gint y,
const GdkWChar *text,
gint text_length)
{
g_warning ("gdk_fb_draw_text_wc NYI");
}
void
gdk_fb_draw_rectangle (GdkDrawable *drawable,
GdkGC *gc,
gint filled,
gint x,
gint y,
gint width,
gint height)
{
GdkDrawableFBData *private;
private = GDK_DRAWABLE_FBDATA (drawable);
if (filled)
{
gboolean handle_cursor = FALSE;
GdkRectangle tmprect;
GdkRegion *tmpreg;
GdkRegion *real_clip_region;
GdkColor color;
int i;
if (GDK_GC_FBDATA (gc)->values_mask & GDK_GC_FOREGROUND)
color = GDK_GC_FBDATA (gc)->values.foreground;
else if (GDK_IS_WINDOW (private->wrapper))
color = GDK_WINDOW_P (private->wrapper)->bg_color;
else
gdk_color_black (private->colormap, &color);
real_clip_region = gdk_fb_clip_region (drawable, gc, TRUE, GDK_GC_FBDATA (gc)->values.function != GDK_INVERT, TRUE);
if (private->mem == GDK_DRAWABLE_IMPL_FBDATA (gdk_parent_root)->mem &&
gdk_fb_cursor_region_need_hide (real_clip_region))
{
handle_cursor = TRUE;
gdk_fb_cursor_hide ();
}
x += private->abs_x;
y += private->abs_y;
if (x < private->llim_x)
{
width -= private->llim_x - x;
x = private->llim_x;
}
if (x + width > private->lim_x)
width = private->lim_x - x;
if (y < private->llim_y)
{
height -= private->llim_y - y;
y = private->llim_y;
}
if (y + height > private->lim_y)
height = private->lim_y - y;
tmprect.x = x;
tmprect.y = y;
tmprect.width = width;
tmprect.height = height;
tmpreg = gdk_region_rectangle (&tmprect);
gdk_region_intersect (tmpreg, real_clip_region);
for (i = 0; i < tmpreg->numRects; i++)
{
GdkRectangle r;
r.x = tmpreg->rects[i].x1;
r.y = tmpreg->rects[i].y1;
r.width = tmpreg->rects[i].x2 - tmpreg->rects[i].x1;
r.height = tmpreg->rects[i].y2 - tmpreg->rects[i].y1;
if ((r.width > 0) && (r.height > 0))
(GDK_GC_FBDATA (gc)->fill_rectangle) (drawable, gc, &r, &color);
}
gdk_region_destroy (tmpreg);
gdk_region_destroy (real_clip_region);
if (handle_cursor)
gdk_fb_cursor_unhide ();
}
else
{
GdkPoint pts[5];
pts[0].x = pts[4].x = x;
pts[0].y = pts[4].y = y;
pts[1].x = x + width;
pts[1].y = y;
pts[2].x = x + width;
pts[2].y = y + height;
pts[3].x = x;
pts[3].y = y + height;
gdk_fb_draw_lines (drawable, gc, pts, 5);
}
}
static void
gdk_fb_draw_points (GdkDrawable *drawable,
GdkGC *gc,
GdkPoint *points,
gint npoints)
{
GdkSpan *spans = g_alloca (npoints * sizeof(GdkSpan));
int i;
for (i = 0; i < npoints; i++)
{
spans[i].x = points[i].x;
spans[i].y = points[i].y;
spans[i].width = 1;
}
gdk_fb_fill_spans (drawable, gc, spans, npoints, FALSE);
}
static void
gdk_fb_draw_arc (GdkDrawable *drawable,
GdkGC *gc,
gint filled,
gint x,
gint y,
gint width,
gint height,
gint angle1,
gint angle2)
{
miArc arc;
arc.x = x;
arc.y = y;
arc.width = width;
arc.height = height;
arc.angle1 = angle1;
arc.angle2 = angle2;
if (filled)
miPolyFillArc (drawable, gc, 1, &arc);
else
miPolyArc (drawable, gc, 1, &arc);
}
static void
gdk_fb_draw_polygon (GdkDrawable *drawable,
GdkGC *gc,
gint filled,
GdkPoint *points,
gint npoints)
{
if (filled)
miFillPolygon (drawable, gc, 0, 0, npoints, points);
else
{
gint tmp_npoints;
gboolean free_points = FALSE;
GdkPoint *tmp_points;
if (points[0].x != points[npoints-1].x || points[0].y != points[npoints-1].y)
{
tmp_npoints = npoints + 1;
tmp_points = g_new (GdkPoint, tmp_npoints);
free_points = TRUE;
memcpy (tmp_points, points, sizeof(GdkPoint) * npoints);
tmp_points[npoints].x = points[0].x;
tmp_points[npoints].y = points[0].y;
}
else
{
tmp_npoints = npoints;
tmp_points = points;
}
gdk_fb_draw_lines (drawable, gc, tmp_points, tmp_npoints);
if (free_points)
g_free (tmp_points);
}
}
static void
gdk_fb_draw_lines (GdkDrawable *drawable,
GdkGC *gc,
GdkPoint *points,
gint npoints)
{
GdkGCFBData *private;
private = GDK_GC_FBDATA (gc);
if (private->values.line_width > 0)
{
if ((private->values.line_style != GDK_LINE_SOLID) && private->dash_list)
miWideDash (drawable, gc, 0, npoints, points);
else
miWideLine (drawable, gc, 0, npoints, points);
}
else
{
if ((private->values.line_style != GDK_LINE_SOLID) && private->dash_list)
miZeroDashLine (drawable, gc, 0, npoints, points);
else
miZeroLine (drawable, gc, 0, npoints, points);
}
}
static void
gdk_fb_draw_segments (GdkDrawable *drawable,
GdkGC *gc,
GdkSegment *segs,
gint nsegs)
{
GdkPoint pts[2];
int i;
for(i = 0; i < nsegs; i++)
{
pts[0].x = segs[i].x1;
pts[0].y = segs[i].y1;
pts[1].x = segs[i].x2;
pts[1].y = segs[i].y2;
gdk_fb_draw_lines (drawable, gc, pts, 2);
}
}
void
gdk_fb_drawable_clear (GdkDrawable *d)
{
extern void
_gdk_windowing_window_clear_area (GdkWindow *window,
gint x,
gint y,
gint width,
gint height);
_gdk_windowing_window_clear_area (d, 0, 0, GDK_DRAWABLE_IMPL_FBDATA (d)->width, GDK_DRAWABLE_IMPL_FBDATA (d)->height);
}
static void
_gdk_fb_draw_glyphs (GdkDrawable *drawable,
GdkGC *gc,
PangoFont *font,
gint x,
gint y,
PangoGlyphString *glyphs,
GdkRectangle *bbox)
{
GdkFBDrawingContext fbdc;
GdkPixmapFBData pixmap;
PangoFT2Subfont subfont_index;
PangoGlyphInfo *gi;
FT_Face face;
FT_UInt glyph_index;
int i, xpos;
int maxy, miny;
int topy;
g_return_if_fail (font);
gdk_fb_drawing_context_init (&fbdc, drawable, gc, FALSE, TRUE);
/* Fake its existence as a pixmap */
((GTypeInstance *)&pixmap)->g_class = g_type_class_peek (_gdk_pixmap_impl_get_type ());
pixmap.drawable_data.abs_x = 0;
pixmap.drawable_data.abs_y = 0;
pixmap.drawable_data.depth = 78;
maxy = miny = 0;
gi = glyphs->glyphs;
for (i = 0, xpos = 0; i < glyphs->num_glyphs; i++, gi++)
{
if (gi->glyph)
{
glyph_index = PANGO_FT2_GLYPH_INDEX (gi->glyph);
subfont_index = PANGO_FT2_GLYPH_SUBFONT (gi->glyph);
face = pango_ft2_get_face (font, subfont_index);
if (face)
{
/* Draw glyph */
FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT);
if (face->glyph->format != ft_glyph_format_bitmap)
FT_Render_Glyph (face->glyph, ft_render_mode_normal);
pixmap.drawable_data.mem = face->glyph->bitmap.buffer;
pixmap.drawable_data.rowstride = face->glyph->bitmap.pitch;
pixmap.drawable_data.width = face->glyph->bitmap.width;
pixmap.drawable_data.height = face->glyph->bitmap.rows;
topy = y - face->glyph->bitmap_top + 1;
miny = MIN (miny, topy);
maxy = MAX (maxy, topy + face->glyph->bitmap.rows);
gdk_fb_draw_drawable_3 (drawable, gc, (GdkPixmap *)&pixmap,
&fbdc,
0, 0,
x + PANGO_PIXELS (xpos) + face->glyph->bitmap_left,
topy,
face->glyph->bitmap.width, face->glyph->bitmap.rows);
}
}
xpos += glyphs->glyphs[i].geometry.width;
}
gdk_fb_drawing_context_finalize (&fbdc);
if (bbox)
{
bbox->x = x;
bbox->y = miny;
bbox->width = xpos;
bbox->height = maxy - miny;
}
}
static void
gdk_fb_draw_glyphs (GdkDrawable *drawable,
GdkGC *gc,
PangoFont *font,
gint x,
gint y,
PangoGlyphString *glyphs)
{
_gdk_fb_draw_glyphs (drawable, gc, font, x, y, glyphs, NULL);
}
static void
gdk_fb_draw_image (GdkDrawable *drawable,
GdkGC *gc,
GdkImage *image,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height)
{
GdkImagePrivateFB *image_private;
GdkPixmapFBData fbd;
g_return_if_fail (drawable != NULL);
g_return_if_fail (image != NULL);
g_return_if_fail (gc != NULL);
image_private = (GdkImagePrivateFB*) image;
g_return_if_fail (image->type == GDK_IMAGE_NORMAL);
/* Fake its existence as a pixmap */
memset (&fbd, 0, sizeof(fbd));
((GTypeInstance *)&fbd)->g_class = g_type_class_peek (_gdk_pixmap_impl_get_type ());
fbd.drawable_data.mem = image->mem;
fbd.drawable_data.rowstride = image->bpl;
fbd.drawable_data.width = fbd.drawable_data.lim_x = image->width;
fbd.drawable_data.height = fbd.drawable_data.lim_y = image->height;
fbd.drawable_data.depth = image->depth;
fbd.drawable_data.window_type = GDK_DRAWABLE_PIXMAP;
fbd.drawable_data.colormap = gdk_colormap_get_system ();
gdk_fb_draw_drawable_2 (drawable, gc, (GdkPixmap *)&fbd, xsrc, ysrc, xdest, ydest, width, height, TRUE, TRUE);
}
static gint
gdk_fb_get_depth (GdkDrawable *drawable)
{
return GDK_DRAWABLE_FBDATA (drawable)->depth;
}
static GdkVisual*
gdk_fb_get_visual (GdkDrawable *drawable)
{
return gdk_visual_get_system();
}
#ifdef ENABLE_SHADOW_FB
static void
gdk_shadow_fb_draw_rectangle (GdkDrawable *drawable,
GdkGC *gc,
gint filled,
gint x,
gint y,
gint width,
gint height)
{
GdkDrawableFBData *private;
gdk_fb_draw_rectangle (drawable, gc, filled, x, y, width, height);
private = GDK_DRAWABLE_FBDATA (drawable);
if (GDK_IS_WINDOW (private->wrapper))
{
gint minx, miny, maxx, maxy;
gint extra_width;
minx = x + private->abs_x;
miny = y + private->abs_y;
maxx = x + width + private->abs_x;
maxy = y + height + private->abs_y;
if (!filled)
{
extra_width = (GDK_GC_FBDATA (gc)->values.line_width + 1) / 2;
minx -= extra_width;
miny -= extra_width;
maxx += extra_width;
maxy += extra_width;
}
gdk_shadow_fb_update (minx, miny, maxx, maxy);
}
}
static void
gdk_shadow_fb_draw_arc (GdkDrawable *drawable,
GdkGC *gc,
gint filled,
gint x,
gint y,
gint width,
gint height,
gint angle1,
gint angle2)
{
GdkDrawableFBData *private;
gdk_fb_draw_arc (drawable, gc, filled, x, y, width, height, angle1, angle2);
private = GDK_DRAWABLE_FBDATA (drawable);
if (GDK_IS_WINDOW (private->wrapper))
{
gint minx, miny, maxx, maxy;
gint extra_width;
minx = x + private->abs_x;
miny = y + private->abs_y;
maxx = x + width + private->abs_x;
maxy = y + height + private->abs_y;
if (!filled)
{
extra_width = (GDK_GC_FBDATA (gc)->values.line_width + 1) / 2;
minx -= extra_width;
miny -= extra_width;
maxx += extra_width;
maxy += extra_width;
}
gdk_shadow_fb_update (minx, miny, maxx, maxy);
}
}
static void
gdk_shadow_fb_draw_polygon (GdkDrawable *drawable,
GdkGC *gc,
gint filled,
GdkPoint *points,
gint npoints)
{
GdkDrawableFBData *private;
gdk_fb_draw_polygon (drawable, gc, filled, points, npoints);
private = GDK_DRAWABLE_FBDATA (drawable);
if (GDK_IS_WINDOW (private->wrapper))
{
gint minx, miny, maxx, maxy;
gint extra_width;
int i;
minx = maxx = points[0].x;
miny = maxy = points[0].y;
for (i = 1; i < npoints; i++)
{
minx = MIN(minx, points[i].x);
maxx = MAX(maxx, points[i].x);
miny = MIN(miny, points[i].y);
maxy = MAX(maxy, points[i].y);
}
if (!filled)
{
extra_width = (GDK_GC_FBDATA (gc)->values.line_width + 1) / 2;
minx -= extra_width;
miny -= extra_width;
maxx += extra_width;
maxy += extra_width;
}
gdk_shadow_fb_update (minx + private->abs_x, miny + private->abs_y,
maxx + private->abs_x, maxy + private->abs_y);
}
}
static void
gdk_shadow_fb_draw_text (GdkDrawable *drawable,
GdkFont *font,
GdkGC *gc,
gint x,
gint y,
const gchar *text,
gint text_length)
{
gdk_fb_draw_text (drawable, font, gc, x, y, text, text_length);
}
static void
gdk_shadow_fb_draw_text_wc (GdkDrawable *drawable,
GdkFont *font,
GdkGC *gc,
gint x,
gint y,
const GdkWChar *text,
gint text_length)
{
gdk_fb_draw_text_wc (drawable, font, gc, x, y, text, text_length);
}
static void
gdk_shadow_fb_draw_glyphs (GdkDrawable *drawable,
GdkGC *gc,
PangoFont *font,
gint x,
gint y,
PangoGlyphString *glyphs)
{
GdkDrawableFBData *private;
GdkRectangle bbox;
_gdk_fb_draw_glyphs (drawable, gc, font, x, y, glyphs, &bbox);
private = GDK_DRAWABLE_FBDATA (drawable);
if (GDK_IS_WINDOW (private->wrapper))
gdk_shadow_fb_update (bbox.x + private->abs_x, bbox.y + private->abs_y,
bbox.x + private->abs_x + bbox.width, bbox.y + private->abs_y + bbox.height);
}
static void
gdk_shadow_fb_draw_drawable (GdkDrawable *drawable,
GdkGC *gc,
GdkPixmap *src,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height)
{
GdkDrawableFBData *private;
gdk_fb_draw_drawable (drawable, gc, src, xsrc, ysrc, xdest, ydest, width, height);
private = GDK_DRAWABLE_FBDATA (drawable);
if (GDK_IS_WINDOW (private->wrapper))
gdk_shadow_fb_update (xdest + private->abs_x, ydest + private->abs_y,
xdest + private->abs_x + width, ydest + private->abs_y + height);
}
static void
gdk_shadow_fb_draw_image (GdkDrawable *drawable,
GdkGC *gc,
GdkImage *image,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height)
{
GdkDrawableFBData *private;
gdk_fb_draw_image (drawable, gc, image, xsrc, ysrc, xdest, ydest, width, height);
private = GDK_DRAWABLE_FBDATA (drawable);
if (GDK_IS_WINDOW (private->wrapper))
gdk_shadow_fb_update (xdest + private->abs_x, ydest + private->abs_y,
xdest + private->abs_x + width, ydest + private->abs_y + height);
}
static void
gdk_shadow_fb_draw_points (GdkDrawable *drawable,
GdkGC *gc,
GdkPoint *points,
gint npoints)
{
GdkDrawableFBData *private;
gdk_fb_draw_points (drawable, gc, points, npoints);
private = GDK_DRAWABLE_FBDATA (drawable);
if (GDK_IS_WINDOW (private->wrapper))
{
gint minx, miny, maxx, maxy;
int i;
minx = maxx = points[0].x;
miny = maxy = points[0].y;
for (i = 1; i < npoints; i++)
{
minx = MIN(minx, points[i].x);
maxx = MAX(maxx, points[i].x);
miny = MIN(miny, points[i].y);
maxy = MAX(maxy, points[i].y);
}
gdk_shadow_fb_update (minx + private->abs_x, miny + private->abs_y,
maxx + private->abs_x, maxy + private->abs_y);
}
}
static void
gdk_shadow_fb_draw_segments (GdkDrawable *drawable,
GdkGC *gc,
GdkSegment *segs,
gint nsegs)
{
GdkDrawableFBData *private;
gdk_fb_draw_segments (drawable, gc, segs, nsegs);
private = GDK_DRAWABLE_FBDATA (drawable);
if (GDK_IS_WINDOW (private->wrapper))
{
gint minx, miny, maxx, maxy;
gint extra_width;
int i;
minx = maxx = segs[0].x1;
miny = maxy = segs[0].y1;
for (i = 0; i < nsegs; i++)
{
minx = MIN(minx, segs[i].x1);
maxx = MAX(maxx, segs[i].x1);
minx = MIN(minx, segs[i].x2);
maxx = MAX(maxx, segs[i].x2);
miny = MIN(miny, segs[i].y1);
maxy = MAX(maxy, segs[i].y1);
miny = MIN(miny, segs[i].y2);
maxy = MAX(maxy, segs[i].y2);
}
extra_width = (GDK_GC_FBDATA (gc)->values.line_width + 1) / 2;
minx -= extra_width;
miny -= extra_width;
maxx += extra_width;
maxy += extra_width;
gdk_shadow_fb_update (minx + private->abs_x, miny + private->abs_y,
maxx + private->abs_x, maxy + private->abs_y);
}
}
static void
gdk_shadow_fb_draw_lines (GdkDrawable *drawable,
GdkGC *gc,
GdkPoint *points,
gint npoints)
{
GdkDrawableFBData *private;
gdk_fb_draw_lines (drawable, gc, points, npoints);
private = GDK_DRAWABLE_FBDATA (drawable);
if (GDK_IS_WINDOW (private->wrapper))
{
gint minx, miny, maxx, maxy;
gint extra_width;
int i;
minx = maxx = points[0].x;
miny = maxy = points[0].y;
for (i = 1; i < npoints; i++)
{
minx = MIN(minx, points[i].x);
maxx = MAX(maxx, points[i].x);
miny = MIN(miny, points[i].y);
maxy = MAX(maxy, points[i].y);
}
extra_width = (GDK_GC_FBDATA (gc)->values.line_width + 1) / 2;
minx -= extra_width;
miny -= extra_width;
maxx += extra_width;
maxy += extra_width;
gdk_shadow_fb_update (minx + private->abs_x, miny + private->abs_y,
maxx + private->abs_x, maxy + private->abs_y);
}
}
#endif