RESOLVED FIXED 23526
[CAIRO] Support ImageBuffers clip operation on all Cairo ports
https://bugs.webkit.org/show_bug.cgi?id=23526
Summary [CAIRO] Support ImageBuffers clip operation on all Cairo ports
Dirk Schulze
Reported 2009-01-24 23:32:35 PST
The current idea of clipToImageBuffer is very specialized to CG. CG needs to render the mask first and masks the object afterwards. Cairo makes it the other way arround. Qt seems to need to QPixmaps (our ImageBuffer) of the mask and the masked object. It is not possible to make workarounds for every case we use clipToImageBuffer. Currently clipToImageBuffer is used to fill/stroke texts with pattern/gradients in Canvas and SVG and -webkit-background-clip. But we may need it for completing clipping support on SVG and a platform independent masking in SVG. clipToImageBuffer should be redesigned and should get the mask and the masked object to work for every platform that supports masking at all (CG, Cairo, Qt, not sure about Skia)
Attachments
example code (10.83 KB, patch)
2009-01-24 23:44 PST, Dirk Schulze
no flags
clipToImageBuffer via CompositeSourceIn (7.08 KB, patch)
2009-01-31 04:45 PST, Dirk Schulze
no flags
clipToImageBuffer for cairo (3.76 KB, patch)
2009-02-05 13:31 PST, Dirk Schulze
no flags
-webkit-mask-clip: text fails with this patch (9.06 KB, application/octet-stream)
2010-06-23 12:21 PDT, Andrei Bucur
no flags
How Safari renders the example (94.37 KB, image/png)
2010-06-24 00:22 PDT, Andrei Bucur
no flags
Patch (1.03 MB, patch)
2011-02-20 10:39 PST, Martin Robinson
no flags
Updated patch that uses avoids creation of new surface (1.04 MB, patch)
2011-02-23 09:39 PST, Martin Robinson
no flags
Patch with reviwer suggestions (1.04 MB, patch)
2011-02-24 08:25 PST, Martin Robinson
no flags
Dirk Schulze
Comment 1 2009-01-24 23:44:07 PST
Created attachment 27009 [details] example code This is an example, how a platform independent clipToImageBuffer could look like. We give clipToImageBuffer to ImageBuffers, one for the mask, the other is the masked object. The replacment is not complete. Gradients are still a bit bugy and no work has been done on -webkit-background-clip. But it demonstrates that it is possible with this design.
Dirk Schulze
Comment 2 2009-01-24 23:46:50 PST
*** Bug 20647 has been marked as a duplicate of this bug. ***
Dirk Schulze
Comment 3 2009-01-31 04:45:59 PST
Created attachment 27215 [details] clipToImageBuffer via CompositeSourceIn Added support for clipToImageBuffer by using the composite operator CompositeSourceIn. This is a easy way to support it, with a minumum of code changes to WebKit. We need a new Layer for a composite operator, to ensure that we don't influence the drawing before and after the masking. Therefore I added a new method closeClipToImageBuffer.
Dirk Schulze
Comment 4 2009-02-02 12:25:17 PST
Comment on attachment 27215 [details] clipToImageBuffer via CompositeSourceIn we need an implementation without closeClipToImageBuffer
Dirk Schulze
Comment 5 2009-02-05 13:31:03 PST
Created attachment 27361 [details] clipToImageBuffer for cairo An clipToImageBuffer implemetation for Cairo. I'm using composite operators here, because on cairo we need the masked object before the mask. It doesn't work the other way arround like on CG.
Oliver Hunt
Comment 6 2009-04-16 23:40:14 PDT
Comment on attachment 27361 [details] clipToImageBuffer for cairo r=me -- i've tried to make sure i understand what this patch is doing, as it doesn't appear there are any active cairo/canvas/gtk reviewers around :-/
Eric Seidel (no email)
Comment 7 2009-04-29 14:09:50 PDT
Comment on attachment 27361 [details] clipToImageBuffer for cairo I think we can make this more clear. The problem here is that in CG you can set a mask image on the context, and then CG will automatically apply it when necessary. In Cairo, masking is an immediate operation. GraphicsContext expects masking to function lazily like CG does. So we have to fix GraphicsContextCairo to save off the mask image, and apply the mask at the last moment possible (when popping the context). I think we could do this clearer by saving the mask image on the GraphicsContextState and applying it during m_data->restore(); You could write a new applyMaskImage() function on m_data which does the actual apply using the stored image. the mask image would not inherit between graphics context states. Does that seem sane?
Dirk Schulze
Comment 8 2009-12-01 00:28:37 PST
(In reply to comment #7) > I think we could do this clearer by saving the mask image on the > GraphicsContextState and applying it during m_data->restore(); > You could write a new applyMaskImage() function on m_data which does the actual > apply using the stored image. the mask image would not inherit between > graphics context states. > > Does that seem sane? A new GraphicsContextState is the copy of a previous one, so every content gets copied too. This is impossible for ImageBuffers. So we can't store ImageBuffers into the state, but even references will be copied. That means we still need something that counts the save/restores as well as the number of clipToImageBuffer calls. That is what the current patch is doing (Vector of int). With pushing the context I move the store operation out of webkit into cairo. That makes it possibly clearer. applyMaskImage sounds reasonable, but it doesn't change anything on the general problem. It would just move the code out of restorePlatformState.
Andrei Bucur
Comment 9 2010-06-23 12:19:44 PDT
The original email from webkit-dev: "I'm trying to implement this CSS value on the Cairo backend and I'm stuck with a problem regarding the Porter-Duff composition operators (why is CAIRO_OPERATOR_DEST_IN unbound?). I've made the following changes to reach this point: 1. I implemented a version of GraphicsContext::clipToImageBuffer starting from this patch: https://bugs.webkit.org/show_bug.cgi?id=23526 , but saving the image mask and the masking rect on a stack and pushing only a group for the masked content. 2. In GraphicsContext::restorePlatformState when the save count is 0 for the current mask, I recover the masked content as a pattern, I clip it using the mask from the stack (I used a new group and operator CAIRO_OPERATOR_IN) and then I should apply the result on the destination surface using CAIRO_OPERATOR_DEST_IN, but bounded to the current mask. The problem here is that CAIRO_OPERATOR_DEST_IN is unbounded so it doesn't take into account the mask, thus affecting all the surface. 3. I modify RenderBoxModelObject::paintFillLayerExtended so that when drawing the background image to use the bgLayer->composite() operator if the clip is TextFillBox. Using CompositeSourceIn can't work because clipToImageBuffer started a new group which uses a different surface for drawing (so there is no destination text to composite with). This way the composition will be done in restorePlatformState. I know this is ugly and that it's highly unlikely to work in this form with SVG masking. For now I just need a hook to make this work. Do you have any other suggestions to make this CSS value work with Cairo?" This is the rendering path I discovered for "-webkit-mask-clip: text" and why it doesn't work with this Cairo patch: 1. The text is rendered on the destination surface. 2. In PaintPhaseMask the filling is achieved using RenderBoxModelObject::paintFillLayerExtended with bgLayer->clip() == TextFillBox. The text is re-rendered in an image to be used a mask for the background. By calling clipToImageBuffer this image is painted on a new group and another one is also pushed for the masked image. 3. When drawing the background, the composite operator used is an IN kind. This operator needs to have the text rendered on the destination surface. By pushing a new group in the previous step, the destination surface becomes empty so the IN operator can't work properly. In the end the background is not painted. I have attached an example. The result should be green text with white gradient stripes (masked by that .png) on red background. Andrei.
Andrei Bucur
Comment 10 2010-06-23 12:21:21 PDT
Created attachment 59549 [details] -webkit-mask-clip: text fails with this patch
Dirk Schulze
Comment 11 2010-06-23 12:34:52 PDT
(In reply to comment #10) > Created an attachment (id=59549) [details] > -webkit-mask-clip: text fails with this patch This doesn't pass on chromium either, but IIRC they used the same idea of the patch above. If you already get it managed to save the mask image and the mask rect, why don't you use cairo_mask_surface()? This should solve all ugly problems with setting composite operators!
Andrei Bucur
Comment 12 2010-06-23 13:19:45 PDT
There are 3 render elements involved: 1. The rendered text 2. The text mask 3. The image mask The paint effect should be: the rendered text is displayed only under the image mask and only under the text mask. What is under the text mask and not under the image mask must be "clear" (as you can see with Safari, the background for the stripes is white, not red). I don't know how to achieve the "clear" effect without using composite operators.
Dirk Schulze
Comment 13 2010-06-23 23:26:39 PDT
(In reply to comment #12) > There are 3 render elements involved: > 1. The rendered text > 2. The text mask > 3. The image mask > > The paint effect should be: the rendered text is displayed only under the image mask and only under the text mask. What is under the text mask and not under the image mask must be "clear" (as you can see with Safari, the background for the stripes is white, not red). > > I don't know how to achieve the "clear" effect without using composite operators. Thats a bit silly. I don't have Safari here, so I can't test it on my own. But if I apply a clip mask to an object, it should mask the object with all it's content, including the background. Why should the background get removed? Or if we see the object without it's background, the background in your example should be solid red and and the text would be "filled" with a red-green-red gradient.
Andrei Bucur
Comment 14 2010-06-23 23:49:22 PDT
(In reply to comment #13) > Thats a bit silly. I don't have Safari here, so I can't test it on my own. But if I apply a clip mask to an object, it should mask the object with all it's content, including the background. Why should the background get removed? Or if we see the object without it's background, the background in your example should be solid red and and the text would be "filled" with a red-green-red gradient. Well... on Safari the stripes are white, not red :). This is because the red background is applied first and then the IN operator (the "op" parameter of RenderBoxModelObject::paintFillLayerExtended) I talked about removes some of the text with respect to the text mask. The composition operation doesn't "know" there is a red background and just keeps some of the content with respect to the mask image (the gradient box in our case) and removes the other content (the gradient stripes).
Dirk Schulze
Comment 15 2010-06-24 00:13:38 PDT
Is it possible, that you can apply a screenshot of Safaris behavior please?
Andrei Bucur
Comment 16 2010-06-24 00:22:48 PDT
Created attachment 59619 [details] How Safari renders the example As you can see the "masked" content is white because of the composite operator used.
Dirk Schulze
Comment 17 2010-06-24 01:02:25 PDT
(In reply to comment #16) > Created an attachment (id=59619) [details] > How Safari renders the example > > As you can see the "masked" content is white because of the composite operator used. Thank you for uploading the image. After reading the blog-post, the result is expected. I don't think, that any other platform than CG is able to render it with the current RenderBoxModelObject::paintFillLayerExtended. So we might think about changing the order of rendering somehow, wihtout breaking CG's output :-/
Dirk Schulze
Comment 18 2010-06-24 01:25:38 PDT
(In reply to comment #17) Checked Skia and Qt. They realy have the same Problem. So we might need to change the concept, not only of RenderBoxModelObject::paintFillLayerExtended, but also of clipToImageBuffer. All platforms use the same hack, similar to the patch of above. We should open a new bug to track this problem, since the issue is not limited to Cairo.
Andrei Bucur
Comment 19 2010-06-24 01:51:25 PDT
I might talk rubbish... but I think that CAIRO_OPERATOR_DEST_IN may be the solution in cairo's case (I guess Skia has something equivalent). As described on this page http://cairographics.org/operators/ we can use the mask image (the gradient box in example) to select the areas from the text that remain unchanged and remove the other parts. The only problem is that we need this operator to be "bounded", to respect the text mask and not affect the entire surface. I asked on the Cairo mailgroup about why this operator is not bounded and the reply was pretty straightforward "Mostly due to an accident of definitions inherited from XRender I think.". Maybe there is a way to push a bounded version of this operator in Cairo.
Dirk Schulze
Comment 20 2010-06-24 01:57:04 PDT
(In reply to comment #19) > I might talk rubbish... but I think that CAIRO_OPERATOR_DEST_IN may be the solution in cairo's case (I guess Skia has something equivalent). > As described on this page http://cairographics.org/operators/ we can use the mask image (the gradient box in example) to select the areas from the text that remain unchanged and remove the other parts. The only problem is that we need this operator to be "bounded", to respect the text mask and not affect the entire surface. > I asked on the Cairo mailgroup about why this operator is not bounded and the reply was pretty straightforward "Mostly due to an accident of definitions inherited from XRender I think.". Maybe there is a way to push a bounded version of this operator in Cairo. This should be possible by clipping, but you'll need the boundaries of the text for it.
Andrei Bucur
Comment 21 2010-06-24 02:29:21 PDT
(In reply to comment #20) I thought about this also and I don't think it's a solution. We need to limit the clip path only to the text. From what I read in documentation this is not achievable in Cairo.
Dirk Schulze
Comment 22 2010-06-24 02:36:38 PDT
(In reply to comment #21) > (In reply to comment #20) > I thought about this also and I don't think it's a solution. We need to limit the clip path only to the text. From what I read in documentation this is not achievable in Cairo. Oh, you don't mean the boundingBox, but something like this?: http://cairographics.org/manual/cairo-paths.html#cairo-glyph-path
Andrei Bucur
Comment 23 2010-06-24 04:44:28 PDT
(In reply to comment #22) Ooooh... I skipped that section :). You are right, that function could be what I need to fix this issue using DEST_IN operator. These days I'll try to write a workaround using it and I'll post the results.
Martin Robinson
Comment 24 2011-02-20 10:39:38 PST
Martin Robinson
Comment 25 2011-02-20 10:42:51 PST
I've uploaded a completed patch for this issue. It does two things: 1. Instead of pushing two groups to emulate the image clip, it pushes one (to isolate the mask) and then calls cairo_mask_surface during restorePlatformState. 2. Cairo does not composite with the previous group when you push a group. To deal with this problem, I blit the contents of the previous group onto the new group after pushing it. This produces the correct rendering with Andrei's test case.
Dirk Schulze
Comment 26 2011-02-20 10:49:10 PST
(In reply to comment #25) > I've uploaded a completed patch for this issue. It does two things: > > 1. Instead of pushing two groups to emulate the image clip, it pushes one (to isolate the mask) and then calls cairo_mask_surface during restorePlatformState. > > 2. Cairo does not composite with the previous group when you push a group. To deal with this problem, I blit the contents of the previous group onto the new group after pushing it. This produces the correct rendering with Andrei's test case. Did you run pixel tests on LayoutTests/svg/clip-path/? Or even better LayoutTests/svg/ in general?
Dirk Schulze
Comment 27 2011-02-20 10:50:58 PST
(In reply to comment #26) > (In reply to comment #25) > > I've uploaded a completed patch for this issue. It does two things: > > > > 1. Instead of pushing two groups to emulate the image clip, it pushes one (to isolate the mask) and then calls cairo_mask_surface during restorePlatformState. > > > > 2. Cairo does not composite with the previous group when you push a group. To deal with this problem, I blit the contents of the previous group onto the new group after pushing it. This produces the correct rendering with Andrei's test case. > > Did you run pixel tests on LayoutTests/svg/clip-path/? Or even better LayoutTests/svg/ in general? Oops. Forget this comment. Saw the results in your patch.
Carlos Garcia Campos
Comment 28 2011-02-23 02:12:28 PST
Comment on attachment 83097 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=83097&action=review > Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp:1193 > + RefPtr<cairo_surface_t> currentContents(adoptRef(cairo_surface_create_similar(currentTarget, > + CAIRO_CONTENT_COLOR_ALPHA, > + rect.width(), rect.height()))); > + RefPtr<cairo_t> currentContentsContext(adoptRef(cairo_create(currentContents.get()))); > + cairo_surface_flush(currentTarget); > + cairo_set_source_surface(currentContentsContext.get(), currentTarget, -rect.x(), -rect.y()); > + cairo_rectangle(currentContentsContext.get(), 0, 0, rect.width(), rect.height()); > + cairo_fill(currentContentsContext.get()); I think this can be done with a cairo subsurface, all this block could be just: RefPtr<cairo_surface_t> currentContents(adoptRef(cairo_surface_create_for_rectangle(cairo_get_target(cr), rect.x(), rect.y(), rect.width(), rect.height())));
Benjamin Otte
Comment 29 2011-02-23 03:03:47 PST
> Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp:1185 > + cairo_surface_t* currentTarget = cairo_get_target(cr); This should be cairo_get_group_target(cr); cairo_get_target() will always reference the original surface that was passed to cairo_create(), not the one that's currently painted to. >> Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp:1193 >> + cairo_fill(currentContentsContext.get()); > > I think this can be done with a cairo subsurface, all this block could be just: > RefPtr<cairo_surface_t> currentContents(adoptRef(cairo_surface_create_for_rectangle(cairo_get_target(cr), > rect.x(), rect.y(), > rect.width(), rect.height()))); If that block was meant to get around the problem with self-copies, then no, this cannot be done with subsurfaces, because subsurfaces are just a bit of shim that still proxies all calls to the original surface. > Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp:1199 > + cairo_set_source_surface(cr, currentContents.get(), rect.x(), rect.y()); You could just do cairo_set_source_surface(cr, currentTarget, rect.x(), rect.y()); here and avoid the whole currentContents surface, unless I'M not understanding why you do the currentContents thing.
Carlos Garcia Campos
Comment 30 2011-02-23 03:13:12 PST
(In reply to comment #29) > > Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp:1185 > > + cairo_surface_t* currentTarget = cairo_get_target(cr); > > This should be cairo_get_group_target(cr); > cairo_get_target() will always reference the original surface that was passed to cairo_create(), not the one that's currently painted to. > > >> Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp:1193 > >> + cairo_fill(currentContentsContext.get()); > > > > I think this can be done with a cairo subsurface, all this block could be just: > > RefPtr<cairo_surface_t> currentContents(adoptRef(cairo_surface_create_for_rectangle(cairo_get_target(cr), > > rect.x(), rect.y(), > > rect.width(), rect.height()))); > > If that block was meant to get around the problem with self-copies, then no, this cannot be done with subsurfaces, because subsurfaces are just a bit of shim that still proxies all calls to the original surface. In this case the subsurface it's only used as a source, so it shouldn't affect the original surface, just to avoid having to create a new surface and fill with current contents. > > Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp:1199 > > + cairo_set_source_surface(cr, currentContents.get(), rect.x(), rect.y()); > > You could just do cairo_set_source_surface(cr, currentTarget, rect.x(), rect.y()); here and avoid the whole currentContents surface, unless I'M not understanding why you do the currentContents thing.
Benjamin Otte
Comment 31 2011-02-23 03:25:24 PST
(In reply to comment #30) > In this case the subsurface it's only used as a source, so it shouldn't affect the original surface, just to avoid having to create a new surface and fill with current contents. > But why not just use the original surface for that?
Carlos Garcia Campos
Comment 32 2011-02-23 03:26:51 PST
(In reply to comment #29) > > Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp:1185 > > + cairo_surface_t* currentTarget = cairo_get_target(cr); > > This should be cairo_get_group_target(cr); > cairo_get_target() will always reference the original surface that was passed to cairo_create(), not the one that's currently painted to. I'm not sure why, but using cairo_get_group_target(cr) breaks the example attached in comment #10. > > Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp:1199 > > + cairo_set_source_surface(cr, currentContents.get(), rect.x(), rect.y()); > > You could just do cairo_set_source_surface(cr, currentTarget, rect.x(), rect.y()); here and avoid the whole currentContents surface, unless I'M not understanding why you do the currentContents thing. indeed, we can use the current target here.
Martin Robinson
Comment 33 2011-02-23 09:15:11 PST
*** Bug 37539 has been marked as a duplicate of this bug. ***
Martin Robinson
Comment 34 2011-02-23 09:39:47 PST
Created attachment 83492 [details] Updated patch that uses avoids creation of new surface
Martin Robinson
Comment 35 2011-02-23 09:47:19 PST
(In reply to comment #34) > Created an attachment (id=83492) [details] > Updated patch that uses avoids creation of new surface Thanks for the comments! I've updated the patch to just copy from the original surface. I guess originally I wasn't sure if this was valid, but apparently it is. :)
Nikolas Zimmermann
Comment 36 2011-02-23 10:46:57 PST
Comment on attachment 83492 [details] Updated patch that uses avoids creation of new surface View in context: https://bugs.webkit.org/attachment.cgi?id=83492&action=review Looks great to me, I'll leave some notes, as I'm not yet certain whether it's r+, as I'm not too familiar with the Cairo port. > Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp:240 > + if (maskInformation.valid()) { s/valid/isValid/ > Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp:255 > + cairo_restore(m_data->cr); > + m_data->restore(); Why do you need, to do anything if maskInformation was not valid at this point? If no mask is used at all, you're now doing one cairo_restore/restore more, is that desired/needed? > Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h:59 > + bool valid() const { return m_maskSurface; } s/valid/isValid/ > Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h:125 > ContextShadow shadow; > Vector<ContextShadow> shadowStack; > + Vector<ImageMaskInformation> m_maskImageStack; This is inconsistent, either make all of them private (I think this is out of scope for this bug), or just name it maskImageStack as well, and put a FIXME: Make these private. above the ContextShadow line.
Eric Seidel (no email)
Comment 37 2011-02-24 02:49:56 PST
Comment on attachment 83492 [details] Updated patch that uses avoids creation of new surface This is so exciting!
Dirk Schulze
Comment 38 2011-02-24 03:12:18 PST
Btw. Can we rename the bug report to "[CAIRO] clipToImageBuffer implementation for Cairo ports"? Since the original idea of the bug was to redesign clipToImageBuffer so that all platforms could use it in a native way for the certain platform. All platforms (beside the cairo ports) already have work arounds, so bug title is no longer valid.
Dirk Schulze
Comment 39 2011-02-24 03:24:07 PST
Comment on attachment 83492 [details] Updated patch that uses avoids creation of new surface View in context: https://bugs.webkit.org/attachment.cgi?id=83492&action=review > Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp:1209 > + cairo_t* cr = m_data->cr; > + cairo_surface_t* currentTarget = cairo_get_target(cr); > + cairo_surface_flush(currentTarget); > + > + // Pushing a new group ensures that only things painted after this point are clipped. > + cairo_push_group(cr); > + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); > + > + cairo_set_source_surface(cr, currentTarget, 0, 0); > + cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); > + cairo_fill(cr); Is this faster than cairo-mask-surface? (http://cairographics.org/manual/cairo-cairo-t.html#cairo-mask-surface)
Dirk Schulze
Comment 40 2011-02-24 03:28:12 PST
(In reply to comment #38) > Btw. Can we rename the bug report to "[CAIRO] clipToImageBuffer implementation for Cairo ports"? Oops, forgot that clipToImageBuffer was replaced. So maybe "[CAIRO] Support ImageBuffers clip operation on all Cairo ports"?
Martin Robinson
Comment 41 2011-02-24 08:25:48 PST
Created attachment 83662 [details] Patch with reviwer suggestions
Martin Robinson
Comment 42 2011-02-24 08:31:47 PST
(In reply to comment #36) Thanks for the comments! > (From update of attachment 83492 [details]) > View in context: https://bugs.webkit.org/attachment.cgi?id=83492&action=review > > Looks great to me, I'll leave some notes, as I'm not yet certain whether it's r+, as I'm not too familiar with the Cairo port. > > > Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp:240 > > + if (maskInformation.valid()) { > > s/valid/isValid/ Done! > > Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp:255 > > + cairo_restore(m_data->cr); > > + m_data->restore(); > > Why do you need, to do anything if maskInformation was not valid at this point? If no mask is used at all, you're now doing one cairo_restore/restore more, is that desired/needed? I just moved these two lines from the top of the method. We still need to restore the platform state even if no masking operation was started after the call to savePlatformState. restorePlatformState is just the most reasonable time to pop the group and apply the mask since we know this is where it will end. It's still a distinct operation from the save/restore pair though. > > > Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h:59 > > + bool valid() const { return m_maskSurface; } > > s/valid/isValid/ Done! > > Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h:125 > > ContextShadow shadow; > > Vector<ContextShadow> shadowStack; > > + Vector<ImageMaskInformation> m_maskImageStack; > > This is inconsistent, either make all of them private (I think this is out of scope for this bug), or just name it maskImageStack as well, and put a FIXME: Make these private. above the ContextShadow line. Changed this to be simply maskImageStack. Some of the members of this class use the m_namingScheme and some don't. You're right that another patch should address that. I've opened https://bugs.webkit.org/show_bug.cgi?id=55150.
Martin Robinson
Comment 43 2011-02-24 08:36:02 PST
(In reply to comment #39) Thanks for the comments. :) > Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp:1209 > + cairo_t* cr = m_data->cr; > + cairo_surface_t* currentTarget = cairo_get_target(cr); > + cairo_surface_flush(currentTarget); > + > + // Pushing a new group ensures that only things painted after this point are clipped. > + cairo_push_group(cr); > + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); > + > + cairo_set_source_surface(cr, currentTarget, 0, 0); > + cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); > + cairo_fill(cr); Is this faster than cairo-mask-surface? (http://cairographics.org/manual/cairo-cairo-t.html#cairo-mask-surface) Since cairo_mask_surface is immediate it cannot affect anything that's painted later. I use cairo_mask_surface in platformRestoreContext to mask the group, but if I had not pushed a group here, it would mask everything that was painted before pushMaskSurface and everything after. (In reply to comment #40) > > Btw. Can we rename the bug report to "[CAIRO] clipToImageBuffer implementation for Cairo ports"? > Oops, forgot that clipToImageBuffer was replaced. So maybe "[CAIRO] Support ImageBuffers clip operation on all Cairo ports"? Done!
Nikolas Zimmermann
Comment 44 2011-02-24 10:19:05 PST
Comment on attachment 83662 [details] Patch with reviwer suggestions Looks great, r=me.
Martin Robinson
Comment 45 2011-02-24 11:01:23 PST
WebKit Review Bot
Comment 46 2011-02-24 15:59:17 PST
http://trac.webkit.org/changeset/79592 might have broken GTK Linux 32-bit Release
Sergio Villar Senin
Comment 47 2011-02-25 00:50:24 PST
(In reply to comment #46) > http://trac.webkit.org/changeset/79592 might have broken GTK Linux 32-bit Release I Skipped the following 3 SVG tests because they're still not working on 32-bit Release bot. Looks like the mask operation is ok but bot results have 2 decimal places instead of none (50.00 is shown instead of 50) svg/batik/masking/maskRegions.svg svg/clip-path/deep-nested-clip-in-mask-different-unitTypes.svg svg/zoom/page/zoom-mask-with-percentages.svg
Nikolas Zimmermann
Comment 48 2011-02-25 02:51:58 PST
(In reply to comment #47) > (In reply to comment #46) > > http://trac.webkit.org/changeset/79592 might have broken GTK Linux 32-bit Release > > I Skipped the following 3 SVG tests because they're still not working on 32-bit Release bot. Looks like the mask operation is ok but bot results have 2 decimal places instead of none (50.00 is shown instead of 50) > > svg/batik/masking/maskRegions.svg > svg/clip-path/deep-nested-clip-in-mask-different-unitTypes.svg > svg/zoom/page/zoom-mask-with-percentages.svg Unfortunately a known bug. Side effect of String::format usage in svg/. I'm still on my mission to eliminate String::format, but it's still going to take a while.
Note You need to log in before you can comment on or make changes to this bug.