SVG clipPath support


#1

I’ve noticed that the current implementation of the SVG parser does not support the clipPath tag.

Are there chances it will be supported in future?


#2

No immediate plans, but maybe one day. It’s actually a tricky one to implement though - clipping to paths is quite a tough problem to perform quickly.


#3

Hey Jules,

Have there been any updates on this since 2009?


#4

The graphics classes do support that now, but no, I’ve not been back and updated the SVG classes to handle it yet.


#5

Here's my new patches to add clipPath support to JUCE:

  • add clipPath support to DrawableShape: https://github.com/soundradix/JUCE/commit/063a2bddd21bcfa46c8525b0be36a10f035e6954
  • add clipPaths to SVG parser: https://github.com/soundradix/JUCE/commit/0cd01c33fa947f635458c5d226bf553459d4256a
  • add <defs>/<use> support*: https://github.com/soundradix/JUCE/commit/afbc104f31d5c1a3933c202bb82104bd4ca1dd4b

* looks like in SVGs made in Adobe Illustrator, clipPaths always use <use> tags which refers to paths previously declared in <defs>. For my app to draw the SVGs created by our designer, clipPath support was meaningless without also supporting these

As usual, I hope to see these (code changes or the features implemented otherwise) added to JUCE so I won't have to maintain merges. Cheers! Yair


#6

Thanks! Will have a look v. soon..


#7

Thanks for posting these. I'm just returning to using SVGs and these will come in useful, I've no doubt. Can't wait to see these and the other SVG patches in the main tip soon. Another nice addition would be the ability to extract a given layer from an SVG. I imagine it would be trivial enough to do. 


#8

Btw, just refactored my changes to better conform SVGParser's style, using findElementForId etc.

Cheers, Yair


#9

FYI I've just been having a look at this, but hit a whole lot more problems than I expected, so can't finish it now.. There's no sense in me implementing something that's not fully correct, and I don't have any more time right now to spend on it, so I'm going to commit what I've done so far (I've fixed the dash stuff at least, and got some of the basic code for parsing the clip paths in place), and will have to revisit it at some point later.

The main issue is that the clip-path attribute may be applied to lots of SVG elements, not just DrawablePath, so would require changes to all the classes, or maybe the Drawable base class.

Also, Drawables at the moment need to be able to save/load their state to a ValueTree, so it's not trivial to add features like dashes or extra paths without suporting their serialisation.. This is messy, and is actually a feature that we'll probably deprecate and remove in future, but it needs to be taken into account at the moment.

I fixed some other issues with your dash parser, which was ignoring coordinate types and some other things, but I had to remove your hack to workaround Adobe having zero-length lines because what you wrote would have given the path parser O(n*n) complexity! Not sure what could be done as an alternative, and I didn't have an example to try, but maybe you could find a more appropriate place to handle that particular case.


#10

Thanks for adding these! Now my diff from mainstream JUCE to support clipPaths is much smaller.

After merging with your changes, all still works good, except an assert triggers in XmlElement::hasTagName from applyClipPath, at xmlPath->hasTagNameIgnoringNamespace ("clippath"), because it seems like it should be "clipPath" rather than "clippath".  see https://developer.mozilla.org/en-US/docs/Web/SVG/Element/clipPath

Cheers, Yair


#11

Damn, I deliberately changed it to "clippath" because I was referring to this page: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/clip-path

..but that page is obviously full of typos! Thanks, will change it back..


#12

The main issue is that the clip-path attribute may be applied to lots of SVG elements, not just DrawablePath, so would require changes to all the classes, or maybe the Drawable base class.

I'd like to implement this (mainly for masks, because my SVGs have masks applied on group elements) but I need a little bit of advice:

Suppose we'd add a clip-path and mask to the base class, how would it be used, specifically for DrawableComposite?

Iiuc, for a DrawableComposite, its paintEntireComponent will just invoke its child drawables's paint and those would not be affected by any clipping/masking of the parent.. Should they no longer be child components added to the parent via addAndMakeVisible etc??

Cheers, Yair


#13

Yes.. that does make it tricky. I'd really like to undo the fact that Drawables are Components, but it'd probably break a lot of code.


#14

*cough* *cough* +1 to undo and deprecate Drawable as Components *cough* *cough* 

Then, you could create a.. BlackboardComponent? CanvasComponent? where all the "new" Drawables (Paintables?) can be stitched together, and it will take care of keeping a reference to them and paint them at each of its paint() callback..

This would be an approach that takes the best of the two extremes: having Drawables as full fledged Components on one side, and having to paint them explicitly into the Graphics at each paint() call on the other side (which is as it was done before they were Components, for the new people reading this)


#15

Btw what if clipping and masking were features that are available to all components, like "transform" is currently? It would probably also allow for some cool UIs and transition effects :)


#16

Definitely an interesting idea! Would need some careful refactoring in the rendering classes, but it could indeed create some good effects.