Bug 90166

Summary: Add a way to specify units
Product: cairo Reporter: Antonio Ospite <ao2>
Component: svg backendAssignee: Emmanuel Pacaud <emmanuel.pacaud>
Status: RESOLVED FIXED QA Contact: cairo-bugs mailing list <cairo-bugs>
Severity: enhancement    
Priority: medium CC: ao2, federico
Version: unspecified   
Hardware: Other   
OS: All   
Whiteboard:
i915 platform: i915 features:
Attachments: svg: add a new function to specify the SVG document units
Example program for cairo_svg_surface_set_document_unit()
svg: add a new function to specify the SVG document unit v2
Example program for cairo_svg_surface_set_document_unit()

Description Antonio Ospite 2015-04-24 21:44:54 UTC
Hi, what about adding a way to specify units for the SVG output?

SVG supports several units[1]: em, ex, px, pt, pc, cm, mm, in, and percentages;
but cairo hardcodes the document units to be pt.

What about a function like cairo_svg_surface_set_unit(surface, unit) ?

The units can be passed as enum values and the function would set the right unit identifier as a string to use when writing the <svg> element in _cairo_svg_document_finish()

If the idea looks good I can work on a patch.

Thanks,
   Antonio

[1] http://www.w3.org/TR/SVG/coords.html
Comment 1 Federico Mena-Quintero 2015-08-25 00:41:31 UTC
This would be useful in librsvg as well.  The rsvg-convert(1) utility can extract an object from an existing SVG file and render it to another SVG.  We'd like to preserve the units used in the original SVG file.

GNOME would like to use that to do:

  rsvg-convert --export-id=some-icon-name -o some-icon-name.svg big-file-with-all-icons.svg
Comment 2 Antonio Ospite 2015-09-10 11:03:32 UTC
Hi Federico, if the signature cairo_svg_surface_set_unit(surface, unit) looks OK to you I can come up with a proper patch to cairo.

Are the cairo upstream developers interested in this functionality?

Thanks,
   Antonio
Comment 3 Bryce Harrington 2017-09-21 00:13:56 UTC
Antonio, sorry for the extreme delay in reply, but I'd certainly be interested in seeing your patch.

Inkscape supports the various SVG units so may be worth referencing.  I don't know if it applies here but Inkscape also needed to update the dpi assumptions for the units, so that's something to be aware of.
Comment 4 Antonio Ospite 2017-09-21 06:38:27 UTC
Hi Bryce, I'll try to come up with something in the next few weeks after taking  a look at what Inkscape does.

Thanks,
   Antonio
Comment 5 Antonio Ospite 2017-10-11 17:37:19 UTC
Created attachment 134799 [details] [review]
svg: add a new function to specify the SVG document units

Hi,

the attached patch shows what I have in mind, it adds a cairo_svg_surface_set_document_unit() function to allow users to
set a unit for the width and height values of the root <svg> element.

In particular my use case is to draw on the surface thinking in pixels and still have the expected result when generating SVG output. Currently this is not possible because cairo hadcodes the unit as "pt" in the generated SVG file.

I noticed that rsvg behaves quite sanely with any of the units while Inkscape doesn't seem to like the relative ones (em, ex, %).

Finally, since the change only affects the header of the generated output file I have the feeling that there is no need to deal with dpi in cairo: editors and rasterizers will do that if appropriate.

Thanks,
   Antonio
Comment 6 Antonio Ospite 2017-10-11 17:41:15 UTC
Created attachment 134800 [details]
Example program for cairo_svg_surface_set_document_unit()

Here is an example program for cairo_svg_surface_set_document_unit().
Comment 7 Bill Spitzak 2017-10-11 17:45:08 UTC
Seems like it would be ok for the api to just take the string that is printed, rather than defining an enumeration in Cairo that will have to be updated if svg's set of units changes.
Comment 8 Adrian Johnson 2017-10-11 20:45:40 UTC
Please post API proposals to the mailing list for discussion.
Comment 9 Bill Spitzak 2017-10-11 23:19:21 UTC
Comment # 8 on bug 90166 from Adrian Johnson

The proposed api in this bug
https://bugs.freedesktop.org/show_bug.cgi?id=90166 uses an enumeration
for each of the svg unit types, but nothing is ever done with that
enumeration other than to print a 2-letter string into the svg output.

I propose a better api would be to just accept the string and print it
without any checking. This would remove the need to modify cairo on
any svg updates that add new units, and also probably makes it much
easier to copy the units from one svg to another.

Proposed api:

void cairo_svg_surface_set_document_unit (cairo_surface_t*, const char*)

The string pointer must point at a valid svg unit type, such as "pt"
or "em". NULL is the same as "" (which means "user" units). The
function should do some basic sanity checks (maximum length, and only
printing ASCII) and is a no-op if it fails.

On Wed, Oct 11, 2017 at 1:45 PM,  <bugzilla-daemon@freedesktop.org> wrote:
> Comment # 8 on bug 90166 from Adrian Johnson
>
> Please post API proposals to the mailing list for discussion.
>
> ________________________________
> You are receiving this mail because:
>
> You are watching the QA Contact of the bug.
Comment 10 Antonio Ospite 2017-10-12 06:29:02 UTC
(In reply to Bill Spitzak from comment #9)
> 
[...]
> Proposed api:
> 
> void cairo_svg_surface_set_document_unit (cairo_surface_t*, const char*)
> 
> The string pointer must point at a valid svg unit type, such as "pt"
> or "em". NULL is the same as "" (which means "user" units). The
> function should do some basic sanity checks (maximum length, and only
> printing ASCII) and is a no-op if it fails.
> 

Hi Bill,

the API I propose is modeled after cairo_svg_surface_restrict_to_version() which also uses an enum, so cairo users are already familiar with this approach, and I think it's OK for a few more reasons:

1. IMHO it's a little more robust, it allows to produce only valid documents (after we discuss if relative units are OK to use).

2. The implementation is simple, hence more verifiable, for instance there is no need to escape special characters like " to assure that the XML is well formed.

3. The event of new units being added to the SVG spec seems quite rare, so having cairo react to that (even in a minor release) seems OK considering the benefits of 1. and 2.

Sanitizing user strings is a bother, when possible I prefer avoiding a problem rather than having to solve it.

Ah, after writing the reply I noticed you already posted to cairo@cairographics.org, I'll subscribe and follow up over there as well.

Ciao,
   Antonio
Comment 11 Antonio Ospite 2017-11-03 11:52:22 UTC
Created attachment 135226 [details] [review]
svg: add a new function to specify the SVG document unit v2

Hi,

here is v2 of the patch.

Changes since v1:

  * Reoder the units: put the USER unit as the first one as this seems to be
    the default unit according to the SVG specification.

  * Fix some minor typos in comments, reword some sentences in the
    documentation.

  * Mention that the default unit for SVG documents generated by cairo is
    "pt".

  * Add a getter function to retrieve the current unit of a SVG surface.


NOTE: In the documentation blocks I left the parameter name to @surface even
though the actual parameter in the code is called abstract_surface, because
this is how it's done in other places like cairo_svg_surface_restrict_to_version().

Ciao,
   Antonio
Comment 12 Antonio Ospite 2017-11-03 11:53:50 UTC
Created attachment 135227 [details]
Example program for cairo_svg_surface_set_document_unit()

An here is an updated test program.
Comment 13 Bryce Harrington 2017-12-04 23:01:41 UTC
commit 15559b54af473d720da9e03b0e769c54a53505a9
Author:     Antonio Ospite <ao2@ao2.it>
AuthorDate: Wed Oct 11 18:51:13 2017 +0200
Commit:     Bryce Harrington <bryce@osg.samsung.com>
CommitDate: Mon Dec 4 13:58:34 2017 -0800

    svg: add a new function to specify the SVG document unit

    Add a cairo_svg_surface_set_document_unit() function to allow users to
    set a unit for the width and height values of the root <svg> element.

    In particular this allows to draw in pixels and still have the expected
    result when generating SVG output.

    Add also the correspondent getter function.

    Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=90166
    Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.