Bug 449959: gfxGdkNativeRenderer: look for GdkDrawable on group target,

use default display for fallback. r=vlad/karlt
This commit is contained in:
Vladimir Vukicevic ext:(%2C%20Karl%20Tomlinson%20%3Ckarlt%2B%40karlt.net%3E) 2008-08-19 15:22:42 +12:00
parent 6a59eaa59b
commit 82238e4cc8
7 changed files with 132 additions and 36 deletions

View File

@ -81,7 +81,7 @@ public:
// visual passed in must be the default visual for dpy's default screen
DRAW_SUPPORTS_NONDEFAULT_VISUAL = 0x10,
// If set, then the Screen 'screen' in the callback can be different
// from the default Screen of the display passed to 'Draw' and can be
// from the default Screen of the default display and can be
// on a different display.
DRAW_SUPPORTS_ALTERNATE_SCREEN = 0x20
};

View File

@ -80,7 +80,6 @@ _convert_coord_to_unsigned_short (double coord, unsigned short *v)
void cairo_draw_with_gdk (cairo_t *cr,
GdkDrawable * drawable,
cairo_gdk_drawing_callback callback,
void * closure,
unsigned int width, unsigned int height,
@ -101,7 +100,7 @@ void cairo_draw_with_gdk (cairo_t *cr,
_convert_coord_to_short (matrix.y0 + device_offset_y, &offset_y);
cairo_surface_flush (target);
callback (closure, drawable, offset_x, offset_y, NULL, 0);
callback (closure, target, offset_x, offset_y, NULL, 0);
cairo_surface_mark_dirty (target);
}

View File

@ -52,11 +52,11 @@ CAIRO_BEGIN_DECLS
* is composited if you call the callback multiple times with the same closure,
* display and visual during a single cairo_draw_with_gdk call.
*
* @return True on success, False on non-recoverable error
* @return True when able to draw, False otherwise
*/
typedef cairo_bool_t (* cairo_gdk_drawing_callback)
(void *closure,
GdkDrawable * drawable,
cairo_surface_t *surface,
short offset_x, short offset_y,
GdkRectangle * clip_rects, unsigned int num_rects);
@ -136,7 +136,6 @@ typedef enum {
* a surface for it.
*/
void cairo_draw_with_gdk (cairo_t *cr,
GdkDrawable * drawable,
cairo_gdk_drawing_callback callback,
void * closure,
unsigned int width, unsigned int height,

View File

@ -20,6 +20,8 @@
*
* Contributor(s):
* rocallahan@novell.com
* Vladimir Vukicevic <vladimir@pobox.com>
* Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -204,6 +206,7 @@ _draw_with_xlib_direct (cairo_t *cr,
Screen *screen;
Visual *visual;
cairo_bool_t have_rectangular_clip;
cairo_bool_t ret;
target = cairo_get_group_target (cr);
cairo_surface_get_device_offset (target, &device_offset_x, &device_offset_y);
@ -301,11 +304,12 @@ _draw_with_xlib_direct (cairo_t *cr,
/* we're good to go! */
CAIRO_GDK_DRAWING_NOTE("TAKING FAST PATH\n");
cairo_surface_flush (target);
callback (closure, GDK_DRAWABLE(gdk_xid_table_lookup(d)),
offset_x, offset_y, rectangles,
needs_clip ? rect_count : 0);
cairo_surface_mark_dirty (target);
return True;
ret = callback (closure, target, offset_x, offset_y, rectangles,
needs_clip ? rect_count : 0);
if (ret) {
cairo_surface_mark_dirty (target);
}
return ret;
}
static cairo_surface_t *
@ -364,7 +368,6 @@ _draw_onto_temp_xlib_surface (cairo_surface_t *temp_xlib_surface,
void *closure,
double background_gray_value)
{
Drawable d = cairo_xlib_surface_get_drawable (temp_xlib_surface);
cairo_bool_t result;
cairo_t *cr = cairo_create (temp_xlib_surface);
@ -377,8 +380,7 @@ _draw_onto_temp_xlib_surface (cairo_surface_t *temp_xlib_surface,
cairo_surface_flush (temp_xlib_surface);
/* no clipping is needed because the callback can't draw outside the native
surface anyway */
result = callback (closure, GDK_DRAWABLE(gdk_xid_table_lookup(d)),
0, 0, NULL, 0);
result = callback (closure, temp_xlib_surface, 0, 0, NULL, 0);
cairo_surface_mark_dirty (temp_xlib_surface);
return result;
}
@ -492,7 +494,6 @@ _compute_alpha_values (uint32_t *black_data,
void
cairo_draw_with_gdk (cairo_t *cr,
GdkDrawable * drawable,
cairo_gdk_drawing_callback callback,
void * closure,
unsigned int width, unsigned int height,
@ -505,7 +506,7 @@ cairo_draw_with_gdk (cairo_t *cr,
cairo_surface_t *white_image_surface;
unsigned char *black_data;
unsigned char *white_data;
Display *dpy = gdk_x11_drawable_get_xdisplay(drawable);
Display *dpy = gdk_x11_get_default_xdisplay();
if (result) {
result->surface = NULL;
@ -522,7 +523,7 @@ cairo_draw_with_gdk (cairo_t *cr,
if (_draw_with_xlib_direct (cr, dpy, callback, closure, width, height,
capabilities))
return;
temp_xlib_surface = _create_temp_xlib_surface (cr, dpy, width, height,
capabilities);
if (temp_xlib_surface == NULL)

View File

@ -20,6 +20,7 @@
*
* Contributor(s):
* rocallahan@novell.com
* Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -50,11 +51,17 @@ typedef struct {
static cairo_bool_t
NativeRendering(void *closure,
GdkDrawable * drawable,
cairo_surface_t *surface,
short offset_x, short offset_y,
GdkRectangle * rectangles, unsigned int num_rects)
{
NativeRenderingClosure* cl = (NativeRenderingClosure*)closure;
nsRefPtr<gfxASurface> gfxSurface = gfxASurface::Wrap(surface);
GdkDrawable *drawable =
gfxPlatformGtk::GetPlatform()->GetGdkDrawable(gfxSurface);
if (!drawable)
return 0;
nsresult rv = cl->mRenderer->
NativeDraw(drawable, offset_x, offset_y,
rectangles, num_rects);
@ -96,7 +103,6 @@ gfxGdkNativeRenderer::Draw(gfxContext* ctx, int width, int height,
cairoFlags |= CAIRO_GDK_DRAWING_SUPPORTS_NONDEFAULT_VISUAL;
}
cairo_draw_with_gdk(ctx->GetCairo(),
gfxPlatformGtk::GetPlatform()->GetGdkDrawable(ctx->OriginalSurface()),
NativeRendering,
&closure, width, height,
(flags & DRAW_IS_OPAQUE) ? CAIRO_GDK_DRAWING_OPAQUE : CAIRO_GDK_DRAWING_TRANSPARENT,

View File

@ -21,6 +21,7 @@
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com>
* Masayuki Nakano <masayuki@d-toybox.com>
* Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -61,6 +62,7 @@
#ifdef MOZ_X11
#include <gdk/gdkx.h>
#include "gfxXlibSurface.h"
#include "cairo-xlib.h"
#endif /* MOZ_X11 */
#ifdef MOZ_DFB
@ -90,8 +92,6 @@
PRInt32 gfxPlatformGtk::sDPI = -1;
gfxFontconfigUtils *gfxPlatformGtk::sFontconfigUtils = nsnull;
static cairo_user_data_key_t cairo_gdk_drawable_key;
#ifndef MOZ_PANGO
typedef nsDataHashtable<nsStringHashKey, nsRefPtr<FontFamily> > FontTable;
static FontTable *gPlatformFonts = NULL;
@ -99,12 +99,11 @@ static FontTable *gPlatformFontAliases = NULL;
static FT_Library gPlatformFTLibrary = NULL;
#endif
static cairo_user_data_key_t cairo_gdk_pixmap_key;
static void do_gdk_pixmap_unref (void *data)
static cairo_user_data_key_t cairo_gdk_drawable_key;
static void do_gdk_drawable_unref (void *data)
{
GdkPixmap *pmap = (GdkPixmap*)data;
gdk_pixmap_unref (pmap);
GdkDrawable *d = (GdkDrawable*) data;
g_object_unref (d);
}
gfxPlatformGtk::gfxPlatformGtk()
@ -212,17 +211,16 @@ gfxPlatformGtk::CreateOffscreenSurface(const gfxIntSize& size,
if (newSurface && newSurface->CairoStatus() == 0) {
// set up the surface to auto-unref the gdk pixmap when
// the surface is released
newSurface->SetData(&cairo_gdk_pixmap_key,
pixmap,
do_gdk_pixmap_unref);
SetGdkDrawable(newSurface, GDK_DRAWABLE(pixmap));
SetGdkDrawable(newSurface, GDK_DRAWABLE(pixmap));
} else {
// something went wrong with the surface creation.
// Ignore and let's fall back to image surfaces.
if (pixmap)
gdk_pixmap_unref(pixmap);
newSurface = nsnull;
}
// always unref; SetGdkDrawable takes its own ref
if (pixmap)
g_object_unref(pixmap);
}
if (!newSurface) {
@ -722,18 +720,109 @@ gfxPlatformGtk::SetGdkDrawable(gfxASurface *target,
if (target->CairoStatus())
return;
gdk_drawable_ref(drawable);
cairo_surface_set_user_data (target->CairoSurface(),
&cairo_gdk_drawable_key,
drawable,
NULL);
do_gdk_drawable_unref);
}
#ifdef MOZ_X11
// Look for an existing Colormap that is known to be associated with visual.
static GdkColormap *
LookupGdkColormapForVisual(const Screen* screen, const Visual* visual)
{
Display* dpy = DisplayOfScreen(screen);
GdkDisplay* gdkDpy = gdk_x11_lookup_xdisplay(dpy);
if (!gdkDpy)
return NULL;
// I wish there were a gdk_x11_display_lookup_screen.
gint screen_num = 0;
for (int s = 0; s < ScreenCount(dpy); ++s) {
if (ScreenOfDisplay(dpy, s) == screen) {
screen_num = s;
break;
}
}
GdkScreen* gdkScreen = gdk_display_get_screen(gdkDpy, screen_num);
// Common case: the display's default colormap
if (visual ==
GDK_VISUAL_XVISUAL(gdk_screen_get_system_visual(gdkScreen)))
return gdk_screen_get_system_colormap(gdkScreen);
// widget/src/gtk2/mozcontainer.c uses gdk_rgb_get_colormap()
// which is inherited by child widgets, so this is the visual
// expected when drawing directly to widget surfaces or surfaces
// created using cairo_surface_create_similar with
// CAIRO_CONTENT_COLOR.
// gdk_screen_get_rgb_colormap is the generalization of
// gdk_rgb_get_colormap for any screen.
if (visual ==
GDK_VISUAL_XVISUAL(gdk_screen_get_rgb_visual(gdkScreen)))
return gdk_screen_get_rgb_colormap(gdkScreen);
// This is the visual expected on displays with the Composite
// extension enabled when the surface has been created using
// cairo_surface_create_similar with CAIRO_CONTENT_COLOR_ALPHA,
// as happens with non-unit opacity.
if (visual ==
GDK_VISUAL_XVISUAL(gdk_screen_get_rgba_visual(gdkScreen)))
return gdk_screen_get_rgba_colormap(gdkScreen);
return NULL;
}
#endif
GdkDrawable *
gfxPlatformGtk::GetGdkDrawable(gfxASurface *target)
{
if (target->CairoStatus())
return nsnull;
return (GdkDrawable*) cairo_surface_get_user_data (target->CairoSurface(),
&cairo_gdk_drawable_key);
GdkDrawable *result;
result = (GdkDrawable*) cairo_surface_get_user_data (target->CairoSurface(),
&cairo_gdk_drawable_key);
if (result)
return result;
#ifdef MOZ_X11
if (target->GetType() == gfxASurface::SurfaceTypeXlib) {
gfxXlibSurface *xs = (gfxXlibSurface*) target;
// try looking it up in gdk's table
result = (GdkDrawable*) gdk_xid_table_lookup(xs->XDrawable());
if (result) {
SetGdkDrawable(target, result);
return result;
}
// If all else fails, try doing a foreign_new
// but don't bother if we can't get a colormap.
// Without a colormap GDK won't know how to draw.
Screen *screen = cairo_xlib_surface_get_screen(xs->CairoSurface());
Visual *visual = cairo_xlib_surface_get_visual(xs->CairoSurface());
GdkColormap *cmap = LookupGdkColormapForVisual(screen, visual);
if (cmap == None)
return nsnull;
result = (GdkDrawable*) gdk_pixmap_foreign_new_for_display
(gdk_display_get_default(), xs->XDrawable());
if (result) {
gdk_drawable_set_colormap(result, cmap);
SetGdkDrawable(target, result);
// Release our ref. The object is held by target. Caller will
// only need to ref if it wants to keep the drawable longer than
// target.
g_object_unref(result);
return result;
}
}
#endif
return nsnull;
}

View File

@ -1730,7 +1730,8 @@ nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent)
// do double-buffering and clipping here
nsRefPtr<gfxContext> ctx = rc->ThebesContext();
gfxPlatformGtk::GetPlatform()->SetGdkDrawable(ctx->OriginalSurface(), GDK_DRAWABLE(mDrawingarea->inner_window));
gfxPlatformGtk::GetPlatform()->SetGdkDrawable(ctx->OriginalSurface(),
GDK_DRAWABLE(mDrawingarea->inner_window));
// clip to the update region
ctx->Save();
@ -1800,6 +1801,7 @@ nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent)
gfxPlatformGtk::GetPlatform()->SetGdkDrawable(
static_cast<gfxASurface *>(bufferPixmapSurface),
GDK_DRAWABLE(bufferPixmap));
bufferPixmapSurface->SetDeviceOffset(gfxPoint(-boundsRect.x, -boundsRect.y));
nsCOMPtr<nsIRenderingContext> newRC;
nsresult rv = GetDeviceContext()->