Validate that we find an appropriate depth for the Xlib surface, before
attempting to create the surface. This was manifesting itself with
XInitImage() failures during _draw_image_surface() (actually detected as
a segmentation fault in XPutPixel() due to an incomplete XImage). So we
also add a couple of asserts to ensure that XInitImage() is successful -
which to the best of our knowledge, they should always be.
Do this by tiling the surface form the solid pattern. The pattern in
turn calls into xlib's create_solid_surface which returns a dithered
pattern.
This can get into infinite loop right now, because of the way solid
surface cache tries to repaint cached surfaces.
Otherwise we can't do dithering. This drastically improves gradient rendering
on 16bit displays, essentially making them indistinguishable from 32bit ones
with a naked eye.
Remove the intermediate rgb333 for PseudoColor and work on the
cube directly. Also upgrade to a 6x6x6 cube instead of 5x5x5.
Do dithering on both PseudoColor and TrueColor, using a 4x4 pattern.
This only affects X servers with no XRender.
Replace a clip rectangle that covers the entire surface with no
clipping as this is quite a common operation when toolkits (i.e. GTK+)
clear surfaces before drawing and avoids a redundant
XRenderSetClipRectangles.
It is possible for an XRender capable surface to use
_cairo_xlib_surface_solid_fill_rectangle() if the surface
HAS_CREATE_PICTURE() && ! HAS_FILL_RECTANGLES(), in which case we need to
handle the surface having no associated visual.
Fixes test/xlib-expose-event.
Instead of allocating the union of all possible pattern types, just
allocate the specific pattern as used by the function in order to trim
the stack space consumption and flag potential misuse.
In order to avoid re-rasterising a glyph that is pending an
XRenderFreeGlyph, we first scan all glyphsets and their arrays of
pending_free_glyphs for a matching glyph. The additional cost of
scanning the extra arrays should be negligble as most fonts will only
have the single array (which we would scan anyway) but we potentially
save an expensive rasterisation and short-lived image surface.
(As suggested by Behdad Esfahbod.)
Someone reported on cairo list that on some system with gcc, he had the
compile-time assertion failing, meaning that the following struct:
typedef struct {
unsigned long index;
union {
struct {
double x;
double y;
} d;
struct {
int x;
int y;
} i;
} p;
} cairo_xlib_glyph_t;
had a different size from:
typedef struct {
unsigned long index;
double x;
double y;
} cairo_glyph_t;
That looks quite a weird thing for a compiler to do. Anyway, rewriting
our struct like this may help in those weird situations:
typedef union {
cairo_glyph_t d;
unsigned long index;
struct {
unsigned long index;
int x;
int y;
} i;
} cairo_xlib_glyph_t;
That's what we do now.
From -1024..15359, to -4096..122887. This still does not fix the
large-font test as that uses a 10000 font. Working on a proper fix
for glyph dropping now.
First, XMaxRequestSize returns number of 4-byte words. So multiply by 4 is
needed in all uses. Next, XRenderAddGlyphs uses BIG-REQUEST extension if
available, so when checking for glyph size overflow, we should use
XExtendedMaxRequestSize() first.
Also use the right format when calculating glyph size.
These changes combined, push the biggest font size that can be uploaded to the
server from under 200 to about 5000.
See bug #4339 for history.
Originally reported here:
http://lists.cairographics.org/archives/cairo/2008-May/014032.html
and analyized later in the thread.
Change (font and surface) backend show_glyphs() API to take a
int *remaining_glyphs argument. It's used to communicate to the caller,
by way of setting remaining_glyphs and returning INT_STATUS_UNSUPPORTED,
that some of the glyphs were shown but not the others. The xlib backend
now correctly uses this to handle failure to upload a glyph to the server.
So the large-font test passes now.
An alternative approach could be to add some public value for glyphs
indices that are not shown. -1 perhaps (the xlib backend already uses
that value internally). Then instead of remaining_glyphs, a backend
could simply set glyph indices of glyphs shown to that -1 value.
For every glyph evicted from the cache we would allocate a very small
structure to push onto the xlib work queue. This quickly becomes
noticably for an app that consumes a lot of scaled fonts and glyphs,
e.g. trying to draw text at various angles. So we maintain a small array
of glyphs pending finalisation and issue the XRenderFreeGlyphs() once the
array is full.
During the destruction of every font used with an xlib surface, we send
an XRenderFreeGlyphs() for every single glyph in the cache. These
requests are redundant as the server-side glyphs will be released along
with the XRenderFreeGlyphSet(), so we skip the individual glyph
destruction if the font is marked as finished.
XRender performs a round-trip in order to query the available formats on
the xserver, before searching for a matching format. In order to save
that round-trip and to avoid the short-lived allocation of the array of
available formats, we cache the result on the display.
As identified by Vladimir Vukicevic,
_cairo_xlib_surface_create_similar_with_format() was erroneously passing
down the source Visual when creating a surface with a different
XRenderPictFormat.
If the xserver doesn't support the RENDER extension or simply doesn't
have the matching PictFormat then xrender_format might be NULL. Check
and fallback in this case.
XRenderAddGlyph() does not split its image data across multiple requests
and so the glyph surface must be smaller than XMaxRequestSize or else
the server will disconnect the client, causing "Fatal IO error 104".
As this will require an extension to the XRender spec, we can work
around the issue by using our fallbacks if we detect that the glyph will
be too large for a single request.
See bugs https://bugs.freedesktop.org/show_bug.cgi?id=4339 and
http://bugs.freedesktop.org/show_bug.cgi?id=13266 for examples.
Previously, given a valid XRenderFormat the Visual was discarded
when creating similar surfaces. However the original Visual is
required to support reading back from non-TrueColor surfaces.
The compiler isn't clever enough to notice that these
variables are always initialized (in either the TrueColor
or ! TrueColor conditions corresponding to the later
identical conditions in which the variables are used).
This support involves allocating a 16-bit grayscale ramp as well
as a 5x5x5 RGB color cube. Afterwards, the 256 colors are queried
and an array is generated mapping from r3g3b3 colors to the closest
available color. Both the queried colors and the reverse mapping
are stored in a new visual-specific cairo_xlib_visual_info_t
structure which hangs off of the cairo_xlib_screen_info_t.
Both the color-cube allocation and the distance metric could be
improved by someone sufficiently motivated, (for example, allocating
and matching in a perceptually linear color space rather than just
in RGB space). Also, making this work well in the face of a changing
color map, or in the case of GrayScale, StaticGray, or DirectColor
visuals are left entirely as exercises for the reader. StaticColor
support should be fine as is, but is entirely untested.
We're moving the assertion up from inside _pixman_format_to_mask
to its callers. This will allow us to selectively eliminate the
assertion from the supported xlib backend, while leaving it in
the unsupported glitz and xcb backends for now.