Hi,
I think that CLIM underspecifies how clipping regions (and text-styles and line-styles) are handled for output records. For REPLAY-OUTPUT-RECORD, it says
"The current user transformation, line style, text style, ink, and clipping region of stream are all ignored during the replay operation. Instead, these are gotten from the output record."
which is good, but unfortunately it doesn't specify /how/ they are gotten, which means that implementing one's own output record class is tricky.
Why does this matter? In gsharp, we implement sloped beams with our own kind of output record; as of this morning, I taught that output record, and the replay-output-record methods, about the medium clipping region, so that sloped short beams (as in http://www-jcsu.jesus.cam.ac.uk/~csr21/sloped-short-beams.png) survive repainting; previously the output record had no record of the clipping region, and so a repaint would cause the entire width, rather than just the short segment, to be drawn. So this now works acceptably.
However, we implement horizontal beams with an ordinary rectangle, and short ones with an ordinary rectangle and clipping region. Before a repaint, this works fine: see http://www-jcsu.jesus.cam.ac.uk/~csr21/horizontal-beams.png. However, obscuring and uncovering the window, triggering a repaint, results in http://www-jcsu.jesus.cam.ac.uk/~csr21/horizontal-beams-after-repaint.png.
This happens because the replay-output-record methods for the clim internal graphics things (such as rectangles) set the medium clipping region while they're replaying, but don't set it back; they simply rely on a method on replay. In fact, in McCLIM itself as distributed the set-medium-graphics-state :after method on gs-clip-mixin is essentially disabled, though I'm not entirely sure why; gsharp re-enables it, presumably in an attempt to get some of this working, but disabling it again simply means that replaying horizontal beams (i.e. rectangles) which have been clipped ignores the previous clipping region.
What is one to do? Well, I think with the standard as it is there's no way of writing output record classes. However, the case of changing ink can be handled in the spec, as CLIM specifies a function displayed-output-record-ink; using that, dealing with the ink looks like
(defmethod replay-output-record :around ((record displayed-output-record) stream ...) (let ((medium (sheet-medium stream))) (with-drawing-options (medium :ink (displayed-output-record-ink record)) (call-next-method))))
and this will work, given that all displayed-output-record objects obey the displayed-output-record protocol. If we were to extend the protocol to require displayed-output-record-clipping-region, displayed-output-record-text-style and displayed-output-record-line-style, then I think this would cover the difficult cases, most of the set-medium-graphics-state methods could go away, and gsharp could have horizontal short beams.
Comments?
Cheers,
Christophe
Christophe Rhodes csr21@cam.ac.uk writes:
Comments?
Here's an implementation of a more minimal, less invasive change. SET-MEDIUM-GRAPHICS-STATE goes away and is replaced by :AROUND methods on REPLAY-OUTPUT-RECORD the various graphics state mixin types, which use WITH-DRAWING-OPTIONS to bind dynamically the various bits of graphics state that they need. The uses of SET-MEDIUM-GRAPHICS-STATE in incremental-redisplay then boil down to setting the stream cursor position; the uses of MEDIUM-GRAPHICS-STATE there actually should just retrieve the cursor position, but I haven't altered that in the source.
Then GSharp, which specializes DISPLAYED-OUTPUT-RECORD (a specified class, unlike STANDARD-DISPLAYED-OUTPUT-RECORD, where all of these changes have been occurring) can itself remember the bits of medium state it needs (ink and clipping-region), and then the effect of the graphics state of each output record is dynamically contained to its own replay, and not any other records'.
And all this lets me put up screenshots like http://www-jcsu.jesus.cam.ac.uk/~csr21/gsharp-with-working-repaint.png.
I have tested a couple of other applications with this (the Address Book still works!) and nothing seems terribly amiss. I'd like a sanity check, though, and maybe consideration of whether having analogues to displayed-output-record-ink would make sense. (I think it would, and in fact I think that with this change the various bits of graphics state /are/ attached to the output record).
Cheers,
Christophe