Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PDFGraphics2D.setClip does not reliably clear previous clip #39

Open
benediktmu opened this issue Mar 21, 2016 · 0 comments
Open

PDFGraphics2D.setClip does not reliably clear previous clip #39

benediktmu opened this issue Mar 21, 2016 · 0 comments

Comments

@benediktmu
Copy link

In the PDF format, the clipping path operators can only make a clipping path smaller. The only way to make the clipping area wider again is to pop graphics states in the graphics state stack until previously set clipping paths are removed. However, in Java2D there is a method Graphics.setClip which replaces the current clip with another one without relying on popping states from a stack.

PDFGraphics2D.setClip currently tries to mimic the Java2D behaviour in this way:

It caches some of the attributes of the current graphics state.
It pops the current graphics state in order to get rid of the clip.
It pushes a new graphics state and applies the cached values and the new clip.

This procedure works only if the PDF graphics state stack has been kept so shallow that a single pop completely clears the clip. But there is at least one situation where this requirement gets broken: When a new Graphics object is created from another one, e.g.:
Graphics graphics2 = graphics1.create();
This call is basically a push(). The equivalent for pop() is:
graphics2.dispose();

Since those are valid mechanisms in Java2D to realize a kind of state stack, they have to be supported. Currently however, they break PDFGraphics2D.setClip.

Possible fix: Allow arbitrary depths in the graphics state stack and deal with it.

FreeHEP needs a mechanism to keep track of the graphics state stack. Since more than one PDFGraphics2D object can be used, this stack handling needs to be performed in a single object shared by all those PDFGraphics2D instances.

setClip then requires a complex procedure:

  1. Pop all graphics states up to the initial base state. This needs to be some base state where the clip is the largest that shall be allowed, e.g. in openPage, the line with: clipRect(0, 0, size.width, size.height);
  2. Recreate the result state except for the clip, leave the clip like it was in the base state. This doesn't necessarily mean that several graphics states are pushed again - a single cumulated state could be enough. We have to throw that one away later anyway and restore the true original stack contents.
  3. Perform setClip.
  4. Continue doing other stuff until the state is popped beyond the setClip state.
  5. When the graphics state stack is popped beyond the level when the setClip procedure was executed, in the PDF the state will be back in the initial base state. This is because we had popped all states and only pushed a single cumulated state for setClip. PDFGraphics2D now needs to recreate all original state changes and push them again to the PDF graphics state stack.

Idea for an alternative fix:
Keep the graphics state stack shallow in the PDF and hold a stack in Java instead. Perform all state accumulations (transformation matrix concatenation, clip intersection) in Java. Whenever a state is popped in Java (Graphics.dispose), pop the one and only state in PDF and push a new one with the result matrices / clips / colors / etc. calculated from the stack structure in Java.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant