[cairo] Cairo 1.14.2 problems with Solaris 10, libXrender

Andreas F. Borchert andreas.borchert at uni-ulm.de
Wed Aug 5 07:44:32 PDT 2015


On Wed, Aug 05, 2015 at 11:07:20PM +0900, suzuki toshiya wrote:
> The issue was found by the inconsistent header/library in
> Solaris 10 (so, it would be possible for Solaris 10 users
> to bypass this problem by tweaking the configure script),
> but your comment is that the hardwired configuration about
> the availability of XrenderCreateSolidFill etc is not good
> idea, they should be checked in runtime.
>
> Is this correct understanding?

We have checks by configure (compile time) and during runtime (using
XRenderQueryVersion, see below). Currently both is checked and we need
also both. The point is that we should not invoke functions that were
no-op'd as they are not included in the libXrender client library when
they appear to be supported by an actual X server (i.e. display) we
connect to.

> If this is correct understanding, the runtime checking of
> the availability would be a symbol checking in libXrender?

No. Symbol checking is done at compile time (by configure). The runtime
check is performed using the function

   Status XRenderQueryVersion (Display *dpy,
			       int     *major_versionp,
			       int     *minor_versionp);

which is declared in Xrender.h and which queries the version of the X
server (i.e. display) we have connected to (represented by the Display
pointer).

The actual code checks the runtime version only. Example:

   if (CAIRO_RENDER_HAS_GRADIENTS(dst->display)) {
      picture = XRenderCreateSolidFill (dpy, &xcolor);
   } else {
      // ...
   }

The macro CAIRO_RENDER_HAS_GRADIENTS has been defined in
cairo-xlib-private.h as

   #define CAIRO_RENDER_HAS_GRADIENTS(surface) \
       CAIRO_RENDER_AT_LEAST((surface), 0, 10)

where CAIRO_RENDER_AT_LEAST accesses render_major and
render_minor which are initialized by using XRenderQueryVersion
(see cairo-xlib-display.c):

   #define CAIRO_RENDER_AT_LEAST(surface, major, minor) \
        (((surface)->render_major > major) || \
	 (((surface)->render_major == major) && \
	  ((surface)->render_minor >= minor)))

The Cairo library should be prepared for the case that
the XRender version of the actual X Server is more recent
than that of the XRender client library Cairo was linked
against. Hence I would suggest to use #ifdefs as follows:

#if HAVE_XRENDERCREATELINEARGRADIENT
   if (CAIRO_RENDER_HAS_GRADIENTS(dst->display)) {
      picture = XRenderCreateSolidFill (dpy, &xcolor);
   } else {
#endif
      // ...
#if HAVE_XRENDERCREATELINEARGRADIENT
   }
#endif

And to defend against accidental invocations of a no-op
I would suggest to replace in cairo-xlib-xrender-private.h

   __attribute__((__unused__)) static int
   _int_consume (void *p, ...)   { return 0; }

   // ...

   #if !HAVE_XRENDERCREATESOLIDFILL
   #define XRenderCreateSolidFill _int_consume
   #endif

by

   __attribute__((__unused__)) static int
   _int_consume_and_abort (void *p, ...)   { assert(0); return 0; }

   // ...

   #if !HAVE_XRENDERCREATESOLIDFILL
   #define XRenderCreateSolidFill _int_consume_and_abort
   #endif

or something similar, i.e. if against all odds a no-op is called,
a crash, error or warning message would be most helpful to track
this down. Rendering should not be silently skipped.

Regards, Andreas.

-- 
Dr. Andreas F. Borchert, Institut für Numerische Mathematik,
Universität Ulm, Helmholtzstraße 20, Zimmer 1.22, 89081 Ulm


More information about the cairo mailing list