Avoid masking fatal errors by enforcing any error to be returned via an
error surface, so that the NULL return only means UNSUPPORTED. A few
backends called their create_similar() directly, without correctly checking
for a potential NULL (for example, the directfb backend was a timebomb,
since it used NULL to indicate out-of-memory).
A little bit of sleep and reflection suggested that the use of
device_offset_[xy] was confusing and clone_offset_[xy] more consistent
with the function naming.
Previously the rule for clone_similar() was that the returned surface
had exactly the same size as the original, but only the contents within
the region of interest needed to be copied. This caused failures for very
large images in the xlib-backend (see test/large-source).
The obvious solution to allow cloning only the region of interest seemed
to be to simply set the device offset on the cloned surface. However, this
fails as a) nothing respects the device offset on the surface at that
layer in the compositing stack and b) possibly returning references to the
original source surface provides further confusion by mixing in another
source of device offset.
The second method was to add extra out parameters so that the
device offset could be returned separately and, for example, mixed into
the pattern matrix. Not as elegant, a couple of extra warts to the
interface, but it works - one less XFAIL...
If the internal buffer is wrapped in an image surface in acquire_dest_image,
that image surface needs the current clip region propagated to it. If not,
then the clip needs to be applied at release_dest_image time.
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.
Added a couple of (boolean) env. vars affecting the backend:
CAIRO_DIRECTFB_NO_ACCEL, disables acceleration
CAIRO_DIRECTFB_ARGB_FONT, enables using ARGB fonts instead of A8
- Improved performance in case of surface conversion: allocate a shadow buffer that can only grow
- Fixed support for small surfaces (less than 8x8)
- Optimize the blending function according to the surface format
- Added _directfb_categorize_operation(): selects the blitting function according to the transform matrix
- Avoid inverting the matrix when doing a simple StretchBlit()
- Use TextureTriangles() instead of StretchBlit() when scale factors are negative
- Added support for ARGB32 fonts (converted to A8 internally)
- Removed unused functions (flush() and mark_dirty_rectangle())
- Code cosmetics
gcc -ansi -pedantic gives a few syntax warnings, principally for use of
'//' comments and a comma at the end of enumerators. Apply these
corrections as they are trivial.
Every time we assign or return a hard-coded error status wrap that value
with a call to _cairo_error(). So the idiom becomes:
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
or
return _cairo_error (CAIRO_STATUS_INVALID_DASH);
This ensures that a breakpoint placed on _cairo_error() will trigger
immediately cairo detects the error.
This reverts commit 919bea6dbb.
Sadly as Behdad points out some backends do modify the glyph array and,
for example cairo-xlib-surface, hide this from the compiler with some
evil casts.
Skip the memory duplication of the incoming glyphs if we do not need
to transform them into the backend coordinate system.
As a consequence we need to constify the glyphs passed to the backend
functions.
Seems like all over the code, we have been using negated device_offset
values for glyph surfaces. Here is all the math(!):
A device_transform converts from device space (a conceptual space) to
surface space. For simple cases of translation only, it's called a
device_offset and is public API (cairo_surface_[gs]et_device_offset).
A possibly better name for those functions could have been
cairo_surface_[gs]et_origing. So, that's what they do: they set where
the device-space origin (0,0) is in the surface. If the origin is inside
the surface, device_offset values are positive. It may look like this:
Device space:
(-x,-y) <-- negative numbers
+----------------+
| . |
| . |
|......(0,0) <---|-- device-space origin
| |
| |
+----------------+
(width-x,height-y)
Surface space:
(0,0) <-- surface-space origin
+---------------+
| . |
| . |
|......(x,y) <--|-- device_offset
| |
| |
+---------------+
(width,height)
In other words: device_offset is the coordinates of the device-space
origin relative to the top-left of the surface.
We use device offsets in a couple of places:
- Public API: To let toolkits like Gtk+ give user a surface that
only represents part of the final destination (say, the expose
area), but has the same device space as the destination. In these
cases device_offset is typically negative. Example:
application window
+---------------+
| . |
| (x,y). |
|......+---+ |
| | | <--|-- expose area
| +---+ |
+---------------+
In this case, the user of cairo API can set the device_space on
the expose area to (-x,-y) to move the device space origin to that
of the application window, such that drawing in the expose area
surface and painting it in the application window has the same
effect as drawing in the application window directly. Gtk+ has
been using this feature.
- Glyph surfaces: In most font rendering systems, glyph surfaces
have an origin at (0,0) and a bounding box that is typically
represented as (x_bearing,y_bearing,width,height). Depending on
which way y progresses in the system, y_bearing may typically be
negative (for systems similar to cairo, with origin at top left),
or be positive (in systems like PDF with origin at bottom left).
No matter which is the case, it is important to note that
(x_bearing,y_bearing) is the coordinates of top-left of the glyph
relative to the glyph origin. That is, for example:
Scaled-glyph space:
(x_bearing,y_bearing) <-- negative numbers
+----------------+
| . |
| . |
|......(0,0) <---|-- glyph origin
| |
| |
+----------------+
(width+x_bearing,height+y_bearing)
Note the similarity of the origin to the device space. That is
exactly how we use the device_offset to represent scaled glyphs:
to use the device-space origin as the glyph origin.
Now compare the scaled-glyph space to device-space and surface-space
and convince yourself that:
(x_bearing,y_bearing) = (-x,-y) = - device_offset
That's right. If you are not convinced yet, contrast the definition
of the two:
"(x_bearing,y_bearing) is the coordinates of top-left of the
glyph relative to the glyph origin."
"In other words: device_offset is the coordinates of the
device-space origin relative to the top-left of the surface."
and note that glyph origin = device-space origin.
So, that was the bug. Fixing it removed lots of wonders and magic
negation signs.
The way I discovered the bug was that in the user-font API, to make
rendering the glyph from meta-surface to an image-surface work I had
to do:
cairo_surface_set_device_offset (surface, -x_bearing, -y_bearing);
_cairo_meta_surface_replay (meta_surface, surface);
cairo_surface_set_device_offset (surface, x_bearing, y_bearing);
This suggested that the use of device_offset for glyph origin is
different from its use for rendering with meta-surface. This reminded
me of the large comment in the xlib backend blaming XRender for having
weird glyph space, and of a similar problem I had in the PS backend
for bitmap glyph positioning (see d47388ad75)
...those are all fixed now.
This patch introduces three macros: _cairo_malloc_ab,
_cairo_malloc_abc, _cairo_malloc_ab_plus_c and replaces various calls
to malloc(a*b), malloc(a*b*c), and malloc(a*b+c) with them. The macros
return NULL if int overflow would occur during the allocation. See
CODING_STYLE for more information.
Original work by Jorn Baayen <jorn@openedhand.com>,
2715f20981
We use a small cache of size 16 for surfaces created for solid patterns.
This mainly helps with the X backends where we don't have to create a
pattern for every operation, so we save a lot on X traffic. Xft uses a
similar cache, so cairo's text rendering traffic with the xlib backend
now completely matches that of Xft.
The cache uses an static index variable, which itself acts like a cache of
size 1, remembering the most recently used solid pattern. So repeated
lookups for the same pattern hit immediately. If that fails, the cache is
searched linearly, and if that fails too, a new surface is created and a
random member of the cache is evicted.
A cached surface can only be reused if it is similar to the destination.
In order to check for similar surfaces a new test is introduced for the
backends to determine that the cached surface is as would be returned by
a _create_similar() call for the destination and content.
As surfaces are in general complex encapsulation of graphics state we
only return unshared cached surfaces and reset them (to clear any error
conditions and graphics state). In practice this makes little difference
to the efficacy of the cache during various benchmarks. However, in order
to transparently share solid surfaces it would be possible to implement a
COW scheme.
Cache hit rates: (hit same index + hit in cache) / lookups
cairo-perf: (42346 + 28480) / 159600 = 44.38%
gtk-theme-torturer: (3023 + 3502) / 6528 = 99.95%
gtk-perf: (8270 + 3190) / 21504 = 53.29%
This translates into a reduction of about 25% of the XRENDER traffic during
cairo-perf.
This is necessary to avoid many portability problems as cairoint.h includes
config.h. Without a test, we will regress again, hence add it.
The inclusion idiom for cairo now is:
#include "cairoint.h"
#include "cairo-something.h"
#include "cairo-anotherthing-private.h"
#include <some-library.h>
#include <other-library/other-file.h>
Moreover, some standard headers files are included from cairoint.h and need
not be included again.
This reverts the following commits:
2715f2098167e3b3c53b
See this thread for an analysis of the problems it caused:
http://lists.freedesktop.org/archives/cairo/2007-February/009825.html
In short, a single cache for all backends doesn't work, as one thread
using any backend can cause an unused xlib pattern to be evicted from
the cache, and trigger an xlib call while the display is being used
from another thread. Xlib is not prepared for this.
We use a small cache of size 16 for surfaces created for solid patterns.
This mainly helps with the X backends where we don't have to create a
pattern for every operation, so we save a lot on X traffic. Xft uses a
similar cache, so cairo's text rendering traffic with the xlib backend
now completely matches that of Xft.
The cache uses an static index variable, which itself acts like a cache of
size 1, remembering the most recently used solid pattern. So repeated
lookups for the same pattern hit immediately. If that fails, the cache is
searched linearly, and if that fails too, a new surface is created and a
random member of the cache is evicted.
Only surfaces that are "compatible" are used. The definition of compatible
is backend specific. For the xlib backend, it means that the two surfaces
are allocated on the same display. Implementations for compatibility are
provided for all backends that it makes sense.
The rule is: cairo_glyph_t* is always passed as const for measurement
purposes. This was not reflected in our public api previously. Fixed
Showing glyphs used to have cairo_glyph_t* always as const. With this
changed, it is only const on cairo_t and cairo_gstate_t operations.
cairo_surface_t, cairo_scaled_font_t, and individual backends receive
cairo_glyph_t* as non-const. The desired semantics is that they may modify
the contents of the array as long as they do not return
CAIRO_STATUS_UNSUPPORTED. This makes it possible to avoid copying the glyph
array again and again, and edit it in-place. Backends are in fact free to use
the array as a generic buffer as they see fit.
This fixes a huge performance bug (entire image was being pushed to X
server in order to copy a tiny piece of it). I see up to 50x improvement
from subimage_copy (which was designed to expose this problem) but also
a 5x improvement in some text performance cases.
xlib-rgba subimage_copy-512 3.93 2.46% -> 0.07 2.71%: 52.91x faster
███████████████████████████████████████████████████▉
xlib-rgb subimage_copy-512 4.03 1.97% -> 0.09 2.61%: 44.74x faster
███████████████████████████████████████████▊
xlib-rgba subimage_copy-256 1.02 2.25% -> 0.07 0.56%: 14.42x faster
█████████████▍
xlib-rgba text_image_rgb_over-256 63.21 1.53% -> 11.87 2.17%: 5.33x faster
████▍
xlib-rgba text_image_rgba_over-256 62.31 0.72% -> 11.87 2.82%: 5.25x faster
████▎
xlib-rgba text_image_rgba_source-256 67.97 0.85% -> 16.48 2.23%: 4.13x faster
███▏
xlib-rgba text_image_rgb_source-256 68.82 0.55% -> 16.93 2.10%: 4.07x faster
███▏
xlib-rgba subimage_copy-128 0.19 1.72% -> 0.06 0.85%: 3.10x faster
██▏
This is a step toward allowing device scaling in addition to device offsets.
So far, the scale values are still always 1.0 so only the translation is
actually being used. But most of the code is in place for doing scaling as
well and it just needs to be hooked up.
There are some fragile parts in this code, all of which involve using the
translation without the scale, (so grep for device_transform.x0 or
device_transform->x0). Some of these are likely bugs that will hopefully
be obvious once we start using the scale. Others are OK if only because
we 'know' that we aren't ever setting device scaling on a surface that
has a device offset (we only set device scaling on surfaces we create
internally and we don't export device scaling to the user).
All of these fragile parts in the code have been marked with comments of
the form: XXX: FRAGILE.