[cairo] Cairo - PDF backend

Carl Worth cworth at cworth.org
Sat Jun 24 13:33:11 PDT 2006


On Sat, 24 Jun 2006 17:29:12 +0200, "=?ISO-8859-1?Q?Mikl=F3s_Erd=E9lyi?=" wrote:
> 
> By the excuse of Google's SoC I started doing Inkscape's PDF export with Cairo.
> The Cairo library is really fun to use, so the simple things like
> filling with solid color, setting stroking style has been implemented
> quickly.
>

Fantastic! I knew cairo was getting some SoC help through mozilla, but
I hadn't also expected to get some through inkscape. I think it's
wonderful that you're hooking inkscape and cairo up. And I'm truly
delighted to hear that you're having fun with cairo. That's definitely
my favorite reaction.

> Now I'm struck with drawing linear/radial gradients, because they just
> don't work. The first problem was that because _pattern_supported said
> gradient patterns aren't supported, the output was always an image
> fallback. So I re-enabled native gradients which resulted in no
> visible output. The interpolation functions and other stuff are well
> exported but the painting/filling itself doesn't produce any visible
> output (I'm testing with a simple linear gradient from cairo-snippets'
> gradient.cairo).

And I think it's great that you're looking at improving this code. It
should be fairly straightforward to get something going right
away. The history is that Kristian did all the original work on the
gradients---and that code handled a lot of the most important cases,
(such as 2-color-stop gradients) but not everything cairo could throw
at it.

At the time, we didn't have the good analysis support that we have now
and I just disabled the gradient code (with the UNSUPPORTED return
value you found). Now that we have all the analysis stuff in place
what you should do is characterize the functionality of the code and
correctly return UNSUPPORTED from _pattern_supported if the code is
known to not handle particular cases. Then we can incrementally
improve things from there.

> I tried changing to shading dictionaries but still there's no
> output,

As for debugging why the gradient code isn't working at all, I suspect
it's just some minor bit-rot, (I have shaken up the PDF surface
implementation a time or two since disabling the gradient code).

> Please help me with some ideas regarding the cause of this problem (it
> might just be related to me not getting  the PDF spec right). I know
> you're an expert in PDF, so that's why I turned to you :)
> Thank you in advance. I'm looking forward to your answer.

I'm definitely not a PDF expert, but I will give you some debugging
strategies I've come up with. For PostScript stuff I start with broken
output and manually tweak it until it works. With PDF, manual editing
often ends up being more trouble than it's worth, (there are tricks
like emitting lots of extra whitespace into content streams and then
typing in overwrite mode so that the stream length is undisturbed).

But what really helps is to get your hands on a minimal, working PDF
file that is as close as possible to what you are trying to
achieve. And that should be pretty easy in your case since cairo
definitely did do what you want (for simple cases at least) in the
past.

So all you need to do is take your simple gradient-using,
PDF-generating program that is currently failing and then run it
against an old version of cairo that had working PDF gradients. To do
that you would do something like the following in your git clone of
cairo (please pardon me for launching into one of my mini git
tutorials here).

1) Start with a clean tree. Certain git commands, (as we will be using
   in step 2), really need a clean tree to start with. You can get
   this clean tree in several different ways, depending on your
   mood. These are ordered as least-learning-required first, so you
   can just stop reading if you get burned out. But the real gems are
   at the end...

    a) Tree is already clan to start with

       You might be lucky and already have a clean tree. You can check
       with git-status which will report if you've modified any files
       under version control. If so, (and I think you do since you've
       described some changes you've made to the PDF code), then this
       is the "dirty" state we need to get rid of.

    b) Throw away dirty state permanently

       If you never want to see the code again you can throw it away
       permanently with "git reset --hard". That's an important
       command to know, but it's often not what you really want. We're
       dealing with a case of one piece of work getting interrupted by
       another, (you need to explore the old state of cairo to
       develop the new), so you don't really want to throw things away
       and start over. Keep reading:

    c) Make a new clone of cairo from scratch

       You could just git-clone a fresh clone of cairo from
       cairographics.org. This doesn't require you to learn anything
       new, (but what's the fun of that?), but this is also horribly
       slow. You haven't read a really good solution yet.

    d) Make a local clone of your existing repository:

	cd ..
	git clone -l -s cairo cairo-old-working-gradients

       That's _really_ fast, and it's maybe a very natural approach if
       you're used to keep separate branches in separate
       directories. So this is the first workable approach to dealing
       with dirty files that happen to be "in the way".

       This approach does have drawbacks though. For example, git
       configuration like .git/remotes doesn't get cloned/shared so if
       you use lots of separate repositories you end up having to
       manually copy configuration changes around. That's annoying. So
       my preferred approach is to work within a single git
       repository:

    d) Commit good work to a new branch

       If the local modifications you have are in a good state, then
       they belong on their own branch, so come up with a logical name
       for the branch and let them live there:

	git checkout -b descriptive-branch-name
	git commit -a -m "Description of change"

       That's definitely good advice, and its what you should be doing
       already as soon as you have good code. But sometimes you need
       to get to a clean working tree even when you're in the middle
       of making a mess of the code. The code doesn't work, so it's
       not an interesting state to commit and describe. But you want
       to stash it somewhere and get back to it later:

    a) Commit local changes to a temporary (stash) branch:

	git checkout -b stash
	git commit -a -m stash

       So the commands here are basically the same as in step (e)
       above. The difference comes in when you want to come back to
       the work. If you had made a "real" branch you would get back to
       work by simply checking it out and then going from there. But
       with this stash commit, you don't actually want to build off of
       it. An easy thing to do is to checkout the actual branch of
       interest, (master, for example), and then re-apply the stashed
       change with:

	git cherry-pick -r stash

       Then clean up the stash branch which we don't need anymore:

	git branch -D stash

[Finally, I should comment that what I really think should happen in
git is that all commands are fixed to never require a clean tree to
start with. Instead the dirty state of the tree should be able to be
left behind as state stored in the branch being switched away
from. Then when switching back to the branch, the dirty state would be
restored. This would basically just be a little bit of automation of
my step (e)]

OK, that was a big aside, but now, to what you were asking about

2) checkout an old state of cairo that is expected to work

   The checkout command needs a branch name, (even though you don't
   plan on committing on it), so choose something that describes why
   you're exploring the history:

	git checkout -b working-gradient <commit>

   The question then is what commit to use. I think just using the
   state of the PDF code as of the last stable release (1.0.4) should
   work just fine. So try:

	git checkout -b working-gradient 1.0.4

3) Build that, then run your test program against it.

   Hopefully at this point you will get a working example of a
   cairo-generated PDF file with a gradient and you can figure out
   from looking at that output what should be changed in the current
   code.

4) Maybe examine other states in the tree

   If that doesn't do what you want, another point to look at would be
   the state of the tree just before I started reworking everything
   about how PDF is implemented. I found that by browsing through the
   output of "git log -- src/cairo-pdf-surface.c". I've quoted below
   an interesting part of that output: My c23d7d4758 commit is when
   the gradients effectively got disabled and they haven't come back
   yet. Interestingly, the two previous changes to the PDF code,
   (6995a835972 and 5ac6e85455fce) specifically changed the
   gradients. So that's probably the last time this code was touched,
   so you might want to get familiar with those commits, (just use
   "git show <commit>" to examine any one.) And you might even want to
   look at the state of the tree just before those two changes,
   (6ba777213).

   So if you want to look at these states, you'll need a slightly
   different command. You can't use "git checkout -b
   working-gradient" again since the working-gradient branch has
   already been created, (and you're on it). Instead you can just move
   the working-gradient branch to a different point with:

	git reset --hard <commit>

    Warning: "git reset --hard" will destroy any dirty state you have
    in files. That's why I went through all that explanation in step 1
    to make sure you put that somewhere safe so it wouldn't get lost
    here.

I hope that helps,

-Carl

commit c23d7d4758c7915505437b0fc8b57df9ef628289
Author: Carl Worth <cworth at cworth.org>
Date:   Wed Jan 11 11:53:33 2006 +0000

    Note that from here on out, the PDF output should always pass the
    entire test suite!
    Add new functions needed by users of cairo_paginated_surface_t.
    Always snapshot a paginated surface to an image surface, rather
    than a surface similar to the target. We do this since paginated
    target surfaces are allowed to not b    Switch the implementation
    of cairo_pdf_surface_t to use cairo_paginated_surface_t. For now
    this means that all PDF output is fallback images, but this can
    change inc

commit 6995a83597217bd422e74d79ce3c989334ada871
Author: David Reveman <davidr at novell.com>
Date:   Thu Jan 5 15:00:37 2006 +0000

    Gradient updates in SVG backend and no sorting of color stops in
    SVG or PDF backend

commit 5ac6e85455fce862989033d5ff98576d159664bd
Author: David Reveman <davidr at novell.com>
Date:   Thu Jan 5 05:06:50 2006 +0000

    Update gradient code in PDF backend

commit 6ba7772138d5ce64cef13b296cb61f94b49f9c24
Author: Christian Biesinger <cbiesinger at web.de>
Date:   Fri Dec 16 03:02:35 2005 +0000

    Globally rename "operator" to "op", to allow writing backends in
    C++
    reviewed by: cworth
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://lists.freedesktop.org/archives/cairo/attachments/20060624/c0db4912/attachment.pgp


More information about the cairo mailing list