Bug 19652 - [CAIRO] wrong drawing of border-image
Summary: [CAIRO] wrong drawing of border-image
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: CSS (show other bugs)
Version: 528+ (Nightly build)
Hardware: PC All
: P2 Normal
Assignee: Nobody
URL:
Keywords: Cairo, Gtk
Depends on:
Blocks:
 
Reported: 2008-06-18 05:29 PDT by Dirk Schulze
Modified: 2009-05-24 04:29 PDT (History)
2 users (show)

See Also:


Attachments
border-image (2.18 KB, patch)
2008-06-18 05:38 PDT, Dirk Schulze
no flags Details | Formatted Diff | Diff
border-image (2.46 KB, patch)
2008-06-18 07:55 PDT, Dirk Schulze
no flags Details | Formatted Diff | Diff
border-image (2.53 KB, patch)
2008-06-18 13:42 PDT, Dirk Schulze
mrowe: review-
Details | Formatted Diff | Diff
border-image (2.21 KB, patch)
2008-08-18 12:42 PDT, Dirk Schulze
eric: review-
Details | Formatted Diff | Diff
Cairo border-image (1.85 KB, patch)
2008-09-09 04:43 PDT, Dirk Schulze
eric: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Dirk Schulze 2008-06-18 05:29:14 PDT
The pattern in ImageCairo::drawImage() doesn't use tileRect(). Thats why border-images are drawn wrong in some cases. See: http://www.css3.info/preview/border-image/
Comment 1 Dirk Schulze 2008-06-18 05:38:48 PDT
Created attachment 21816 [details]
border-image

Added support for tileRect() for a correct drawing of border-images. I hope it is effiecent enough.
Comment 2 Dirk Schulze 2008-06-18 07:55:09 PDT
Created attachment 21818 [details]
border-image

for more safety
Comment 3 Dirk Schulze 2008-06-18 13:42:26 PDT
Created attachment 21823 [details]
border-image

cairo_t* cr_surface must be defined before the if clause, to make cairo_destroy(cr_surface). Even if we don't need cr_surface :-(

I changed rectangle and fill with cairo_paint, it's more efficient.
Comment 4 Mark Rowe (bdash) 2008-06-18 22:54:42 PDT
Comment on attachment 21823 [details]
border-image

This call to cairo_destroy can pass an uninitialized value for cr_surface which I doubt is safe:

+    cairo_destroy(cr_surface);

Why does the call to cairo_destroy need to be outside the body of the if block where cr_surface is used?  The naming of cr_surface seems like poor choice too:  both surface and cr_surface are cairo types, and I can't see any particular significance to the cr_ prefix.
Comment 5 Dirk Schulze 2008-06-19 00:57:29 PDT
(In reply to comment #4)
> (From update of attachment 21823 [details] [edit])
> This call to cairo_destroy can pass an uninitialized value for cr_surface which
> I doubt is safe:
> 
> +    cairo_destroy(cr_surface);
> 
> Why does the call to cairo_destroy need to be outside the body of the if block
> where cr_surface is used?

cairo_destroy decreases the reference count. And every acces to image (where the new surface is stored at the end) caused crashes of webkit.

> The naming of cr_surface seems like poor choice too
rigth. How about:
surface -> clippedImage
cr_surface -> clippedImageContext
?
Comment 6 Dirk Schulze 2008-08-18 12:42:12 PDT
Created attachment 22854 [details]
border-image

Renamed the functions and destroy surface after using it.
Comment 7 Eric Seidel (no email) 2008-08-27 17:18:33 PDT
Comment on attachment 22854 [details]
border-image

You can force a FloatSize to an IntSize using IntSize(floatSize);

nativeImageForCurrentFrame is supposed to return a pointer to a cached frame image, so you shouldn't be releasing it.  Does cairo intentionally have a different memory management model for this?  Maybe Images aren't ref-counted in Cairo?
Comment 8 Dirk Schulze 2008-09-09 04:43:56 PDT
Created attachment 23291 [details]
Cairo border-image

cairo_surface's are ref-counted in cairo. Thats why I put auto_ptr<ImageBuffer> above the if-clause. Otherwise the image is cleaned-up to early and I get a ref-count error (ref-count lower than zero).
But I measured the call and it takes only 0.000047s extra time as worst-case (normaly 0.000009s).
I don't know (or understand) what you mean with nativeImageForCurrentFrame().
I need a cairo_suface_t* out of the imageBuffer and nativeImageForCurrentFrame() can give it.
 
I haven't r? the patch, to discuss the changes again.
Comment 9 Alp Toker 2008-09-24 18:54:22 PDT
(In reply to comment #8)
> Created an attachment (id=23291) [edit]
> Cairo border-image
> 
> cairo_surface's are ref-counted in cairo. Thats why I put auto_ptr<ImageBuffer>
> above the if-clause. Otherwise the image is cleaned-up to early and I get a
> ref-count error (ref-count lower than zero).
> But I measured the call and it takes only 0.000047s extra time as worst-case
> (normaly 0.000009s).
> I don't know (or understand) what you mean with nativeImageForCurrentFrame().
> I need a cairo_suface_t* out of the imageBuffer and
> nativeImageForCurrentFrame() can give it.
> 
> I haven't r? the patch, to discuss the changes again.
> 

Maybe you could do something like this (completely untested) instead of using ImageBuffer?

    cairo_pattern_t* pattern;
    if (tileRect.size() == size())
        pattern = cairo_pattern_create_for_surface(image);
    else {
        cairo_push_group(cr);
        //IntRect imageSize = enclosingIntRect(tileRect);
        cairo_set_source_surface(cr, image, -tileRect.x(), -tileRect.y());
        cairo_paint(cr);
        pattern = cairo_pop_group(cr);
    }

Comment 10 Dirk Schulze 2008-09-26 12:29:28 PDT
(In reply to comment #9)
Thanks for your reply. It is a great idea. I tested it with many modifications and spend much time on it, but didn't get it to work.

The problem is, the geometry of the context isn't reset. That means, the dimension of the context is different on every time.
The second problem is: You don't only move the the image by -tileRect.x(), -tileRect.y(), you need a part of it, e.g. if you have a 90x90 surface, you need 5 parts. One would be (30, 0, 30, 30)/(x,y,width,height). I wasn't able to realise it with push_to_group. One thing why i didn't manage it was that a rect with the coordinate 0,0 wasn't placed at the top,left of the context, it was somewhere out of the view area.
I have to admit, that this behavior makes it difficult to understand the sense of push_to_group.

In summary:
I need a context with a height and width of the surface. Otherwise I'll get problems with the pattern. It will give more than just this part of a surface.
If it is possible to get the width and height of the current context and the coordinates of the first pixel in the top/left of the context, you can scale and transform the created image (pop_to_group).
But I don't believe that it will be more affective than just creating a new surface with the height and width given by tileRect and draw the part of the image into it's context.

If you have more suggestions, please post it. It would be great to do it without an new surface or ImageBuffer and an acceptable complexity.
Comment 11 Eric Seidel (no email) 2008-11-26 14:59:15 PST
Comment on attachment 23291 [details]
Cairo border-image

This would be super-easy to approve if Gtk supported pixel tests. ;)
Comment 12 Dirk Schulze 2009-01-29 13:19:38 PST
@eseidel: don't upset the gtk gods.

I talked about this problem in #cairo on irc and it was assured me, that this is already the fastest way. 
cairo_pop_to_group does not work here. We still create a surface, but with a undefined size. That means we have no win, it is neither a speed-up, nor more resource affective.
Comment 13 Eric Seidel (no email) 2009-05-22 08:00:51 PDT
Comment on attachment 23291 [details]
Cairo border-image

Please add a note in the changelog pointing to a LayoutTest which will test this once Gtk has pixel tests.  If there is no such test, please add one.

Otherwise this looks sane enough.
Comment 14 Dirk Schulze 2009-05-24 04:29:21 PDT
landed in r44081.