#include "gdkprivate-fb.h" #include "mi.h" #include #include #include #ifndef __BYTE_ORDER #error "endian.h needs to #define __BYTE_ORDER" #endif #ifndef g_alloca #define g_alloca alloca #endif static void gdk_fb_drawable_set_pixel(GdkDrawable *drawable, GdkGC *gc, int x, int y, GdkColor *spot, gboolean abs_coords); typedef enum { GPR_USED_BG, GPR_AA_GRAYVAL, GPR_NONE, GPR_ERR_BOUNDS } GetPixelRet; static GetPixelRet gdk_fb_drawable_get_pixel(GdkDrawable *drawable, GdkGC *gc, int x, int y, GdkColor *spot, gboolean abs_coords, GdkDrawable *bg_relto, GdkDrawable *bgpm); 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 gpointer parent_class = NULL; static void gdk_fb_get_size(GdkDrawable *d, gint *width, gint *height) { if(width) *width = GDK_DRAWABLE_P(d)->width; if(height) *height = GDK_DRAWABLE_P(d)->height; } static void gdk_drawable_impl_fb_class_init (GdkDrawableFBClass *klass) { GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass); parent_class = g_type_class_peek_parent (klass); drawable_class->create_gc = _gdk_fb_gc_new; 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; 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; } 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) { GdkColormap *old_cmap; old_cmap = GDK_DRAWABLE_FBDATA(drawable)->colormap; GDK_DRAWABLE_FBDATA(drawable)->colormap = gdk_colormap_ref(colormap); gdk_colormap_unref(old_cmap); } /* Drawing */ GdkRegion * gdk_fb_clip_region(GdkDrawable *drawable, GdkGC *gc, gboolean do_clipping, gboolean do_children) { GdkRectangle draw_rect; GdkRegion *real_clip_region, *tmpreg; gboolean watchit = FALSE, skipit = FALSE; g_assert(!GDK_IS_WINDOW(GDK_DRAWABLE_P(drawable)->wrapper) || !GDK_WINDOW_P(GDK_DRAWABLE_P(drawable)->wrapper)->input_only); draw_rect.x = GDK_DRAWABLE_FBDATA(drawable)->llim_x; draw_rect.y = GDK_DRAWABLE_FBDATA(drawable)->llim_y; if(!GDK_IS_WINDOW(GDK_DRAWABLE_FBDATA(drawable)) || GDK_WINDOW_P(GDK_DRAWABLE_P(drawable)->wrapper)->mapped) { draw_rect.width = GDK_DRAWABLE_FBDATA(drawable)->lim_x - draw_rect.x; draw_rect.height = GDK_DRAWABLE_FBDATA(drawable)->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(gc && GDK_GC_FBDATA(gc)->values.subwindow_mode == GDK_INCLUDE_INFERIORS) do_children = FALSE; if(do_clipping && GDK_IS_WINDOW(GDK_DRAWABLE_FBDATA(drawable)->wrapper) && GDK_WINDOW_P(GDK_DRAWABLE_P(drawable)->wrapper)->mapped && !GDK_WINDOW_P(GDK_DRAWABLE_FBDATA(drawable)->wrapper)->input_only) { GdkWindow *parentwin, *lastwin; lastwin = GDK_DRAWABLE_FBDATA(drawable)->wrapper; if(do_children) parentwin = lastwin; else parentwin = (GdkWindow *)GDK_WINDOW_P(lastwin)->parent; 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) { GdkRegion *reg2; if(!GDK_WINDOW_P(cur->data)->mapped || GDK_WINDOW_P(cur->data)->input_only) continue; draw_rect.x = GDK_DRAWABLE_IMPL_FBDATA(cur->data)->llim_x; draw_rect.y = GDK_DRAWABLE_IMPL_FBDATA(cur->data)->llim_y; draw_rect.width = GDK_DRAWABLE_IMPL_FBDATA(cur->data)->lim_x - draw_rect.x; draw_rect.height = GDK_DRAWABLE_IMPL_FBDATA(cur->data)->lim_y - draw_rect.y; tmpreg = gdk_region_rectangle(&draw_rect); reg2 = gdk_region_copy(real_clip_region); gdk_region_subtract(reg2, tmpreg); if(watchit && !gdk_region_point_in(reg2, 100, 353)) G_BREAKPOINT(); gdk_region_destroy(real_clip_region); real_clip_region = reg2; 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, GDK_DRAWABLE_FBDATA(drawable)->abs_x + GDK_GC_P(gc)->clip_x_origin, GDK_DRAWABLE_FBDATA(drawable)->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; g_assert(GDK_DRAWABLE_IMPL_FBDATA(cmask)->depth == 1); g_assert(GDK_DRAWABLE_IMPL_FBDATA(cmask)->abs_x == 0 && GDK_DRAWABLE_IMPL_FBDATA(cmask)->abs_y == 0); draw_rect.x = GDK_DRAWABLE_FBDATA(drawable)->abs_x + GDK_DRAWABLE_IMPL_FBDATA(cmask)->llim_x + GDK_GC_FBDATA(gc)->values.clip_x_origin; draw_rect.y = GDK_DRAWABLE_FBDATA(drawable)->abs_y + GDK_DRAWABLE_IMPL_FBDATA(cmask)->llim_y + GDK_GC_FBDATA(gc)->values.clip_y_origin; draw_rect.width = GDK_DRAWABLE_IMPL_FBDATA(cmask)->width; draw_rect.height = GDK_DRAWABLE_IMPL_FBDATA(cmask)->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; } static void gdk_fb_fill_span(GdkDrawable *drawable, GdkGC *gc, GdkSegment *cur, GdkColor *color, GdkVisual *visual) { int curx, cury; GdkColor spot = *color; if(gc && (GDK_GC_FBDATA(gc)->values.clip_mask || GDK_GC_FBDATA(gc)->values.tile || GDK_GC_FBDATA(gc)->values.stipple || GDK_GC_FBDATA(gc)->values.function == GDK_INVERT)) { int clipxoff, clipyoff; /* Amounts to add to curx & cury to get x & y in clip mask */ int tsxoff, tsyoff; GdkDrawable *cmask; guchar *clipmem; guint mask_rowstride; GdkPixmap *ts = NULL; gboolean solid_stipple; GdkFunction func = GDK_GC_FBDATA(gc)->values.function; cmask = GDK_GC_FBDATA(gc)->values.clip_mask; clipxoff = clipyoff = tsxoff = tsyoff = 0; mask_rowstride = 0; solid_stipple = FALSE; clipmem = NULL; if(cmask) { clipmem = GDK_DRAWABLE_IMPL_FBDATA(cmask)->mem; clipxoff = GDK_DRAWABLE_IMPL_FBDATA(cmask)->abs_x - GDK_GC_FBDATA(gc)->values.clip_x_origin - GDK_DRAWABLE_FBDATA(drawable)->abs_x; clipyoff = GDK_DRAWABLE_IMPL_FBDATA(cmask)->abs_y - GDK_GC_FBDATA(gc)->values.clip_y_origin - GDK_DRAWABLE_FBDATA(drawable)->abs_y; mask_rowstride = GDK_DRAWABLE_IMPL_FBDATA(cmask)->rowstride; } if(GDK_GC_FBDATA(gc)->values.fill == GDK_TILED && GDK_GC_FBDATA(gc)->values.tile) { gint xstep, ystep; gint relx, rely; GdkFBDrawingContext *dc, dc_data; dc = &dc_data; gdk_fb_drawing_context_init(dc, drawable, gc, FALSE, TRUE); ts = GDK_GC_FBDATA(gc)->values.tile; for(cury = cur->y1; cury < cur->y2; cury += ystep) { int drawh; rely = cury - GDK_DRAWABLE_FBDATA(drawable)->abs_y; drawh = (rely + GDK_GC_FBDATA(gc)->values.ts_y_origin) % GDK_DRAWABLE_IMPL_FBDATA(ts)->height; if(drawh < 0) drawh += GDK_DRAWABLE_P(ts)->height; ystep = MIN(GDK_DRAWABLE_IMPL_FBDATA(ts)->height - drawh, cur->y2 - rely); for(curx = cur->x1; curx < cur->x2; curx += xstep) { int draww; relx = curx - GDK_DRAWABLE_FBDATA(drawable)->abs_x; draww = (relx + GDK_GC_FBDATA(gc)->values.ts_x_origin) % GDK_DRAWABLE_IMPL_FBDATA(ts)->width; if(draww < 0) draww += GDK_DRAWABLE_IMPL_FBDATA(ts)->width; xstep = MIN(GDK_DRAWABLE_IMPL_FBDATA(ts)->width - draww, cur->x2 - relx); gdk_fb_draw_drawable_3(drawable, gc, GDK_DRAWABLE_IMPL(ts), dc, draww, drawh, relx, rely, xstep, ystep); } } gdk_fb_drawing_context_finalize(dc); return; } else if((GDK_GC_FBDATA(gc)->values.fill == GDK_STIPPLED || GDK_GC_FBDATA(gc)->values.fill == GDK_OPAQUE_STIPPLED) && GDK_GC_FBDATA(gc)->values.stipple) { ts = GDK_GC_FBDATA(gc)->values.stipple; tsxoff = GDK_DRAWABLE_FBDATA(ts)->abs_x - GDK_GC_FBDATA(gc)->values.ts_x_origin - GDK_DRAWABLE_FBDATA(drawable)->abs_x; tsyoff = GDK_DRAWABLE_FBDATA(ts)->abs_y - GDK_GC_FBDATA(gc)->values.ts_y_origin - GDK_DRAWABLE_FBDATA(drawable)->abs_y; solid_stipple = (GDK_GC_FBDATA(gc)->values.fill == GDK_OPAQUE_STIPPLED); } for(cury = cur->y1; cury < cur->y2; cury++) { for(curx = cur->x1; curx < cur->x2; curx++) { int maskx = curx+clipxoff, masky = cury + clipyoff; guchar foo; if(cmask) { foo = clipmem[masky*mask_rowstride + (maskx >> 3)]; if(!(foo & (1 << (maskx % 8)))) continue; } if(func == GDK_INVERT) { gdk_fb_drawable_get_pixel(drawable, gc, curx, cury, &spot, TRUE, NULL, NULL); spot.pixel = ~spot.pixel; spot.red = ~spot.red; spot.green = ~spot.green; spot.blue = ~spot.blue; } else if(ts) { int wid = GDK_DRAWABLE_IMPL_FBDATA(ts)->width, hih = GDK_DRAWABLE_IMPL_FBDATA(ts)->height; maskx = (curx+tsxoff)%wid; masky = (cury+tsyoff)%hih; if(maskx < 0) maskx += wid; if(masky < 0) masky += hih; foo = GDK_DRAWABLE_IMPL_FBDATA(ts)->mem[(maskx >> 3) + GDK_DRAWABLE_IMPL_FBDATA(ts)->rowstride*masky]; if(foo & (1 << (maskx % 8))) { spot = GDK_GC_FBDATA(gc)->values.foreground; } else if(solid_stipple) { spot = GDK_GC_FBDATA(gc)->values.background; } else continue; } gdk_fb_drawable_set_pixel(drawable, gc, curx, cury, &spot, TRUE); } } } else { guchar *mem = GDK_DRAWABLE_FBDATA(drawable)->mem, *ptr; guint rowstride = GDK_DRAWABLE_FBDATA(drawable)->rowstride; int n; switch(GDK_DRAWABLE_P(drawable)->depth) { case 1: { int fromx = MIN((cur->x1+7)&(~7), cur->x2); int begn = fromx - cur->x1, begoff = cur->x1 % 8, endn; guchar begmask, endmask; int body_end = cur->x2 & ~7; int body_len = (body_end - fromx)/8; begmask = ((1 << (begn + begoff)) - 1) & ~((1 << (begoff)) - 1); endn = cur->x2 - body_end; endmask = (1 << endn) - 1; for(cury = cur->y1; cury < cur->y2; cury++) { ptr = mem + cury*rowstride + (cur->x1 >> 3); if(spot.pixel) *ptr |= begmask; else *ptr &= ~begmask; curx = fromx; if(curx < cur->x2) { ptr = mem + cury*rowstride + (curx >> 3); memset(ptr, spot.pixel?0xFF:0, body_len); if(endn) { ptr = mem + cury*rowstride + (body_end >> 3); if(spot.pixel) *ptr |= endmask; else *ptr &= ~endmask; } } } } break; case 8: for(cury = cur->y1; cury < cur->y2; cury++) { ptr = mem + cury*rowstride + cur->x1; memset(ptr, spot.pixel, cur->x2 - cur->x1); } break; case 16: { int i; n = cur->x2 - cur->x1; for(cury = cur->y1; cury < cur->y2; cury++) { guint16 *p16 = (guint16 *)(mem + cury * rowstride + cur->x1*2); for(i = 0; i < n; i++) *(p16++) = spot.pixel; } } break; case 24: { guchar redval = spot.red>>8, greenval=spot.green>>8, blueval=spot.blue>>8; guchar *firstline, *ptr_end; if((cur->y2 - cur->y1) <= 0) break; n = (cur->x2 - cur->x1)*3; firstline = ptr = mem + cur->y1 * rowstride + cur->x1*3; ptr_end = ptr+n; while(ptr < ptr_end) { ptr[gdk_display->red_byte] = redval; ptr[gdk_display->green_byte] = greenval; ptr[gdk_display->blue_byte] = blueval; ptr += 3; } for(cury = cur->y1 + 1, ptr = mem + cury * rowstride + cur->x1*3; cury < cur->y2; cury++, ptr += rowstride) { memcpy(ptr, firstline, n); } } break; case 32: { int i; n = cur->x2 - cur->x1; for(cury = cur->y1; cury < cur->y2; cury++) { guint32 *p32 = (guint32 *)(mem + cury * rowstride + cur->x1*4); for(i = 0; i < n; i++) *(p32++) = spot.pixel; } } break; default: g_assert_not_reached(); #if 0 for(cury = cur->y1; cury < cur->y2; cury++) { for(curx = cur->x1; curx < cur->x2; curx++) { gdk_fb_drawable_set_pixel(drawable, gc, curx, cury, &spot, TRUE); } } #endif break; } } } void gdk_fb_fill_spans(GdkDrawable *real_drawable, GdkGC *gc, GdkRectangle *rects, int nrects) { int i; GdkColor color; GdkRegion *real_clip_region, *tmpreg; GdkRectangle draw_rect; GdkVisual *visual = gdk_visual_get_system(); gboolean handle_cursor = FALSE; GdkDrawable *drawable; drawable = real_drawable; if(GDK_IS_WINDOW(GDK_DRAWABLE_P(drawable)->wrapper) && !GDK_WINDOW_P(GDK_DRAWABLE_P(drawable)->wrapper)->mapped) return; if(GDK_IS_WINDOW(GDK_DRAWABLE_P(drawable)->wrapper) && GDK_WINDOW_P(GDK_DRAWABLE_P(drawable)->wrapper)->input_only) g_error("Drawing on the evil input-only!"); if(gc && (GDK_GC_FBDATA(gc)->values_mask | GDK_GC_FOREGROUND)) color = GDK_GC_FBDATA(gc)->values.foreground; else if(GDK_IS_WINDOW(GDK_DRAWABLE_P(drawable)->wrapper)) color = GDK_WINDOW_P(GDK_DRAWABLE_P(drawable)->wrapper)->bg_color; else gdk_color_black(GDK_DRAWABLE_P(drawable)->colormap, &color); real_clip_region = gdk_fb_clip_region(drawable, gc, TRUE, (!gc || GDK_GC_FBDATA(gc)->values.function!=GDK_INVERT)); if(GDK_DRAWABLE_FBDATA(drawable)->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 < nrects; i++) { GdkSegment cur; int j; cur.x1 = rects[i].x; cur.y1 = rects[i].y; cur.x2 = cur.x1 + rects[i].width; cur.y2 = cur.y1 + rects[i].height; g_assert(cur.x2 >= cur.x1); g_assert(cur.y2 >= cur.y1); cur.x1 += GDK_DRAWABLE_FBDATA(drawable)->abs_x; cur.x1 = MAX(cur.x1, GDK_DRAWABLE_FBDATA(drawable)->llim_x); cur.x2 += GDK_DRAWABLE_FBDATA(drawable)->abs_x; cur.x2 = MIN(cur.x2, GDK_DRAWABLE_FBDATA(drawable)->lim_x); cur.x1 = MIN(cur.x1, cur.x2); cur.y1 += GDK_DRAWABLE_FBDATA(drawable)->abs_y; cur.y1 = MAX(cur.y1, GDK_DRAWABLE_FBDATA(drawable)->llim_y); cur.y2 += GDK_DRAWABLE_FBDATA(drawable)->abs_y; cur.y2 = MIN(cur.y2, GDK_DRAWABLE_FBDATA(drawable)->lim_y); cur.y1 = MIN(cur.y1, cur.y2); draw_rect.x = cur.x1; draw_rect.y = cur.y1; draw_rect.width = cur.x2 - cur.x1; draw_rect.height = cur.y2 - cur.y1; switch(gdk_region_rect_in(real_clip_region, &draw_rect)) { case GDK_OVERLAP_RECTANGLE_PART: tmpreg = gdk_region_rectangle(&draw_rect); gdk_region_intersect(tmpreg, real_clip_region); for(j = 0; j < tmpreg->numRects; j++) { cur = tmpreg->rects[j]; gdk_fb_fill_span(drawable, gc, &cur, &color, visual); } gdk_region_destroy(tmpreg); break; case GDK_OVERLAP_RECTANGLE_IN: gdk_fb_fill_span(drawable, gc, &cur, &color, visual); break; default: break; } } gdk_region_destroy(real_clip_region); if(handle_cursor) gdk_fb_cursor_unhide(); } static GetPixelRet gdk_fb_drawable_get_pixel(GdkDrawable *drawable, GdkGC *gc, int x, int y, GdkColor *spot, gboolean abs_coords, GdkDrawable *bg_relto, GdkDrawable *bgpm) { GetPixelRet retval = GPR_NONE; guchar *mem = GDK_DRAWABLE_FBDATA(drawable)->mem; guint rowstride = GDK_DRAWABLE_FBDATA(drawable)->rowstride; if(!abs_coords) { x += GDK_DRAWABLE_FBDATA(drawable)->abs_x; y += GDK_DRAWABLE_FBDATA(drawable)->abs_y; } switch(GDK_DRAWABLE_P(drawable)->depth) { case 1: { guchar foo = mem[(x >> 3) + y * rowstride]; if(foo & (1 << (x % 8))) *spot = GDK_GC_FBDATA(gc)->values.foreground; else { retval = GPR_USED_BG; if(bgpm) { int bgx, bgy; bgx = (x - GDK_DRAWABLE_IMPL_FBDATA(bg_relto)->abs_x) % GDK_DRAWABLE_IMPL_FBDATA(bgpm)->width; bgy = (y - GDK_DRAWABLE_IMPL_FBDATA(bg_relto)->abs_y) % GDK_DRAWABLE_IMPL_FBDATA(bgpm)->height; gdk_fb_drawable_get_pixel(bgpm, gc, bgx, bgy, spot, FALSE, NULL, NULL); retval = GPR_USED_BG; } else { *spot = GDK_GC_FBDATA(gc)->values.background; } } } break; case 71: if(mem[x + y * rowstride]) *spot = GDK_GC_FBDATA(gc)->values.foreground; else *spot = GDK_GC_FBDATA(gc)->values.background; break; case 77: retval = GPR_AA_GRAYVAL; spot->pixel = mem[x + y * rowstride] << 1; spot->red = spot->green = spot->blue = spot->pixel << 8; break; case 78: /* AA mode */ retval = GPR_AA_GRAYVAL; spot->pixel = mem[x + y * rowstride]; spot->red = spot->green = spot->blue = spot->pixel << 8; break; case 8: spot->pixel = mem[x + y * rowstride]; *spot = GDK_DRAWABLE_P(drawable)->colormap->colors[spot->pixel]; break; case 16: { guint16 val16 = *((guint16 *)&mem[x*2 + y*rowstride]); spot->red = (((1<modeinfo.red.length) - 1) & (val16 >> gdk_display->modeinfo.red.offset)) << (16 - gdk_display->modeinfo.red.length); spot->green = (((1<modeinfo.green.length) - 1) & (val16 >> gdk_display->modeinfo.green.offset)) << (16 - gdk_display->modeinfo.green.length); spot->blue = (((1<modeinfo.blue.length) - 1) & (val16 >> gdk_display->modeinfo.blue.offset)) << (16 - gdk_display->modeinfo.blue.length); spot->pixel = val16; } break; case 24: { guchar *smem = &mem[x*3 + y*rowstride]; spot->red = smem[gdk_display->red_byte] << 8; spot->green = smem[gdk_display->green_byte] << 8; spot->blue = smem[gdk_display->blue_byte] << 8; #if (__BYTE_ORDER == __BIG_ENDIAN) spot->pixel = (smem[0]<<16)|(smem[1]<<8)|smem[2]; #else spot->pixel = smem[0]|(smem[1]<<8)|(smem[2]<<16); #endif } break; case 32: { guchar *smem = &mem[x*4 + y*rowstride]; spot->red = smem[gdk_display->red_byte] << 8; spot->green = smem[gdk_display->green_byte] << 8; spot->blue = smem[gdk_display->blue_byte] << 8; spot->pixel = *(guint32 *)smem; } break; } return retval; } static void gdk_fb_drawable_set_pixel(GdkDrawable *drawable, GdkGC *gc, int x, int y, GdkColor *spot, gboolean abs_coords) { guchar *mem = GDK_DRAWABLE_FBDATA(drawable)->mem; guint rowstride = GDK_DRAWABLE_FBDATA(drawable)->rowstride; if(!abs_coords) { x += GDK_DRAWABLE_FBDATA(drawable)->abs_x; y += GDK_DRAWABLE_FBDATA(drawable)->abs_y; } switch(GDK_DRAWABLE_P(drawable)->depth) { case 1: { guchar *foo = mem + (y*rowstride) + (x >> 3); if(spot->pixel) *foo |= (1 << (x % 8)); else *foo &= ~(1 << (x % 8)); } break; case 8: mem[x + y*rowstride] = spot->pixel; break; case 16: { guint16 *p16 = (guint16 *)&mem[x*2 + y*rowstride]; *p16 = spot->pixel; } break; case 24: { guchar *smem = &mem[x*3 + y*rowstride]; smem[gdk_display->red_byte] = spot->red >> 8; smem[gdk_display->green_byte] = spot->green >> 8; smem[gdk_display->blue_byte] = spot->blue >> 8; }; break; case 32: { guint32 *smem = (guint32 *)&mem[x*4 + y*rowstride]; *smem = spot->pixel; } break; default: g_assert_not_reached(); break; } } void gdk_fb_drawing_context_init(GdkFBDrawingContext *dc, GdkDrawable *drawable, GdkGC *gc, gboolean draw_bg, gboolean do_clipping) { dc->mem = GDK_DRAWABLE_FBDATA(drawable)->mem; dc->rowstride = GDK_DRAWABLE_FBDATA(drawable)->rowstride; dc->handle_cursor = FALSE; dc->bgpm = NULL; dc->bg_relto = GDK_DRAWABLE_P(drawable)->wrapper; dc->draw_bg = draw_bg; if(GDK_IS_WINDOW(GDK_DRAWABLE_P(drawable)->wrapper)) { dc->bgpm = GDK_WINDOW_P(GDK_DRAWABLE_P(drawable)->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 = - GDK_DRAWABLE_FBDATA(drawable)->abs_x; dc->clipyoff = - GDK_DRAWABLE_FBDATA(drawable)->abs_y; dc->real_clip_region = gdk_fb_clip_region(drawable, gc, do_clipping, 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 && GDK_DRAWABLE_FBDATA(drawable)->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_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) { GdkRectangle rect; guchar *srcmem = GDK_DRAWABLE_FBDATA(src)->mem; int src_x_off, src_y_off; GdkRegion *tmpreg, *real_clip_region; int i; int draw_direction = 1; gboolean do_quick_draw; if(GDK_IS_WINDOW(GDK_DRAWABLE_P(drawable)->wrapper)) { if(!GDK_WINDOW_P(GDK_DRAWABLE_P(drawable)->wrapper)->mapped) return; if(GDK_WINDOW_P(GDK_DRAWABLE_P(drawable)->wrapper)->input_only) g_error("Drawing on the evil input-only!"); } 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 = xdest + height; if(EXTENTCHECK(&srcb, &destb) && ydest > ysrc) draw_direction = -1; #if 0 { GdkDrawableFBData *fbd = GDK_DRAWABLE_FBDATA(src); /* One lame hack deserves another ;-) */ srcmem = g_alloca(fbd->rowstride * (fbd->lim_y - fbd->llim_y)); memmove(srcmem, dc->mem + (fbd->rowstride * fbd->llim_y), fbd->rowstride * (fbd->lim_y - fbd->llim_y)); srcmem -= (fbd->rowstride * fbd->llim_y); } #endif } /* Do some magic to avoid creating extra regions unnecessarily */ tmpreg = dc->real_clip_region; rect.x = xdest + GDK_DRAWABLE_FBDATA(drawable)->abs_x; rect.y = ydest + GDK_DRAWABLE_FBDATA(drawable)->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 + GDK_DRAWABLE_FBDATA(drawable)->abs_x; rect.y = ydest + GDK_DRAWABLE_FBDATA(drawable)->abs_y; rect.width = MAX(GDK_DRAWABLE_P(src)->width - xsrc, 0); rect.height = MAX(GDK_DRAWABLE_P(src)->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 = (GDK_DRAWABLE_FBDATA(src)->abs_x + xsrc) - (GDK_DRAWABLE_FBDATA(drawable)->abs_x + xdest); src_y_off = (GDK_DRAWABLE_FBDATA(src)->abs_y + ysrc) - (GDK_DRAWABLE_FBDATA(drawable)->abs_y + ydest); do_quick_draw = GDK_DRAWABLE_P(src)->depth == GDK_DRAWABLE_P(drawable)->depth && GDK_DRAWABLE_P(src)->depth >= 8 && GDK_DRAWABLE_P(src)->depth <= 32 && (!gc || !GDK_GC_FBDATA(gc)->values.clip_mask); for(i = 0; i < real_clip_region->numRects; i++) { GdkRegionBox *cur = &real_clip_region->rects[i]; int start_y, end_y, cur_y; if(draw_direction > 0) { start_y = cur->y1; end_y = cur->y2; } else { start_y = cur->y2 - 1; end_y = cur->y1 - 1; } if(do_quick_draw) { guint depth = GDK_DRAWABLE_P(src)->depth; guint src_rowstride = GDK_DRAWABLE_FBDATA(src)->rowstride; int linelen = (cur->x2 - cur->x1)*(depth>>3); for(cur_y = start_y; cur_y*draw_direction < end_y*draw_direction; cur_y += draw_direction) { memmove(dc->mem + (cur_y * dc->rowstride) + cur->x1*(depth>>3), srcmem + ((cur_y + src_y_off)*src_rowstride) + (cur->x1 + src_x_off)*(depth>>3), linelen); } } else { int cur_x; for(cur_y = start_y; cur_y*draw_direction < end_y*draw_direction; cur_y+=draw_direction) { for(cur_x = cur->x1; cur_x < cur->x2; cur_x++) { GdkColor spot; if(gc && GDK_GC_FBDATA(gc)->values.clip_mask) { int maskx = cur_x+dc->clipxoff, masky = cur_y + dc->clipyoff; guchar foo; foo = dc->clipmem[masky*dc->clip_rowstride + (maskx >> 3)]; if(!(foo & (1 << (maskx % 8)))) continue; } switch(gdk_fb_drawable_get_pixel(src, gc, cur_x + src_x_off, cur_y + src_y_off, &spot, TRUE, NULL, NULL)) { case GPR_AA_GRAYVAL: { GdkColor realspot, fg; guint graylevel = spot.pixel; gint tmp; if(GDK_DRAWABLE_P(drawable)->depth == 1) { if(spot.pixel > 192) spot = GDK_GC_FBDATA(gc)->values.foreground; else spot = GDK_GC_FBDATA(gc)->values.background; break; } else { if(graylevel >= 254) { spot = GDK_GC_FBDATA(gc)->values.foreground; } else if(graylevel <= 2) { if(!dc->draw_bg) continue; spot = GDK_GC_FBDATA(gc)->values.background; } else { switch(gdk_fb_drawable_get_pixel(drawable, gc, cur_x, cur_y, &realspot, TRUE, dc->bg_relto, dc->bgpm)) { case GPR_NONE: case GPR_USED_BG: break; default: g_assert_not_reached(); break; } fg = GDK_GC_FBDATA(gc)->values.foreground; /* Now figure out what 'spot' should actually look like */ fg.red >>= 8; fg.green >>= 8; fg.blue >>= 8; realspot.red >>= 8; realspot.green >>= 8; realspot.blue >>= 8; tmp = (fg.red - realspot.red) * graylevel; spot.red = realspot.red + ((tmp + (tmp >> 8) + 0x80) >> 8); spot.red <<= 8; tmp = (fg.green - realspot.green) * graylevel; spot.green = realspot.green + ((tmp + (tmp >> 8) + 0x80) >> 8); spot.green <<= 8; tmp = (fg.blue - realspot.blue) * graylevel; spot.blue = realspot.blue + ((tmp + (tmp >> 8) + 0x80) >> 8); spot.blue <<= 8; /* Now find the pixel for this thingie */ switch(GDK_DRAWABLE_P(drawable)->depth) { case 8: if(!gdk_colormap_alloc_color(GDK_DRAWABLE_P(drawable)->colormap, &spot, FALSE, TRUE)) { g_error("Can't allocate AA color!"); } break; case 16: spot.pixel = (spot.red >> (16 - gdk_display->modeinfo.red.length)) << gdk_display->modeinfo.red.offset; spot.pixel |= (spot.green >> (16 - gdk_display->modeinfo.green.length)) << gdk_display->modeinfo.green.offset; spot.pixel |= (spot.blue >> (16 - gdk_display->modeinfo.blue.length)) << gdk_display->modeinfo.blue.offset; break; case 24: case 32: spot.pixel = ((spot.red & 0xFF00) << (gdk_display->modeinfo.red.offset - 8)) | ((spot.green & 0xFF00) << (gdk_display->modeinfo.green.offset - 8)) | ((spot.blue & 0xFF00) << (gdk_display->modeinfo.blue.offset - 8)); break; } } } } break; case GPR_USED_BG: if(!dc->draw_bg) continue; break; case GPR_NONE: break; default: g_assert_not_reached(); break; } gdk_fb_drawable_set_pixel(drawable, gc, cur_x, cur_y, &spot, GDK_DRAWABLE_P(src)->depth); } } } } 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) { gdk_fb_draw_drawable_2(drawable, gc, GDK_DRAWABLE_IMPL(src), xsrc, ysrc, xdest, ydest, width, height, TRUE, TRUE); } 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"); } 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) { GdkRectangle rect; if(filled) { rect.x = x; rect.y = y; rect.width = width; rect.height = height; gdk_fb_fill_spans(drawable, gc, &rect, 1); } 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) { GdkRectangle *rects = g_alloca(npoints * sizeof(GdkRectangle)); int i; for(i = 0; i < npoints; i++) { rects[i].x = points[i].x; rects[i].y = points[i].y; rects[i].width = rects[i].height = 1; } gdk_fb_fill_spans(drawable, gc, rects, npoints); } 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 { GdkPoint *realpts = g_alloca(sizeof(GdkPoint) * (npoints + 1)); memcpy(realpts, points, sizeof(GdkPoint) * npoints); realpts[npoints] = points[0]; gdk_fb_draw_lines(drawable, gc, points, npoints); } } static void gdk_fb_draw_lines (GdkDrawable *drawable, GdkGC *gc, GdkPoint *points, gint npoints) { if(GDK_GC_FBDATA(gc)->values.line_width > 0) miWideLine(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); } extern FT_Library gdk_fb_ft_lib; extern void pango_fb_font_set_size(PangoFont *font); static void gdk_fb_draw_glyphs(GdkDrawable *drawable, GdkGC *gc, PangoFont *font, gint x, gint y, PangoGlyphString *glyphs) { int i; int xpos; GdkFBDrawingContext fbdc; g_return_if_fail(font); gdk_fb_drawing_context_init(&fbdc, drawable, gc, FALSE, TRUE); /* Fake its existence as a pixmap */ pango_fb_font_set_size(font); for(i = xpos = 0; i < glyphs->num_glyphs; i++) { PangoFBGlyphInfo *pgi; int this_wid; pgi = pango_fb_font_get_glyph_info(font, glyphs->glyphs[i].glyph); this_wid = (xpos + glyphs->glyphs[i].geometry.width)/PANGO_SCALE; gdk_fb_draw_drawable_3(drawable, gc, (GdkPixmap *)&pgi->fbd, &fbdc, 0, 0, x + (xpos + glyphs->glyphs[i].geometry.x_offset)/PANGO_SCALE, y + glyphs->glyphs[i].geometry.y_offset / PANGO_SCALE + pgi->hbearing, this_wid, pgi->fbd.drawable_data.height); xpos += glyphs->glyphs[i].geometry.width; } gdk_fb_drawing_context_finalize(&fbdc); } 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)); 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; 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_IMPL_FBDATA (drawable)->depth; } static GdkVisual* gdk_fb_get_visual (GdkDrawable *drawable) { return gdk_visual_get_system(); }