Some sparse questions

Andrea De Michele andrea.demichele at
Sun Jan 19 13:56:56 UTC 2020

Hello Daniel,

yes, I'am @admich but the pronouns that you have used is right: in Italy
Andrea is a male name.

Follow some comments, in particular I think that what you wrote about
transformations is wrong.

Daniel Kochmański <daniel at> writes:

> Hello Andrea,
> thank you for working to improve McCLIM!
> Andrea De Michele writes:
>> Dear all,
>> I'm working on CLIM-PDF backend and I solved some problems like the
>> text direction in landscape orientation, but I don't like the solution
>> so I didn't submit any PR.
> CLIM-PDF backend is a prototype at best. It still has numerous rough
> edges. Another person who works on improving it is a github user @admich
> (he sometimes drops on IRC channel too, I don't his real name).
>> Instead I write here to have some feedback from you about some issues that I
>> have found, some very PDF specific other in the very core of McCLIM.
>> I'm start from the more pdf specific (and easier) to the more general one (and harder):
>> The PDF backend is used through WITH-OUTPUT-TO-PDF-STREAM that is
>> based on the analogous macro for Postscript backend defined in the
>> Spec.
>> I think it is better to define for PDF backend a
>> WITH-OUTPUT-TO-PDF-FILE with a string or a pathname as argument
>> instead of a stream. In this way the user don't have to open the file
>> stream (the user needs also to known that the stream must be open with
>> keyword :element-type '(unsigned-byte 8)). If we remove the
>> WITH-OUTPUT-TO-PDF-STREAM McCLIM can remove the dependency to
>> FLEXI-STREM system.
> Macro lambda list is ((stream-var file-stream &rest options) &body body)
> Word "stream" in WITH-OUTPUT-TO-PDF-STREAM refers to STREAM-VAR, because
> that's on what you call the drawing operations, i.e
>   (with-output-to-pdf-stream (stream file-stream)
>     (draw-rectangle* stream 0 0 10 10))
> Same thing goes for PostScript backend. I don't see a problem if you
> write a PR which makes invoke-with-output-to-pdf-stream accept
> file-stream as a string or pathname and then open the stream
> automatically. That will be somewhat DWIM-y approach which doesn't
> change the interface. In that case I'd like to see a similar change
> proposed for function implementing:
> - with-output-to-ps-stream
> - with-output-to-raster-image-stream

Ok so your suggestion is to modify the actual WITH-OUTPUT-TO-PDF-STREAM
macro without introduce new WITH-OUTPUT-TO-PDF-FILE macro, I will try to
do it.

>> 2) GRAFT in PDF and Postscript Backend
>> PDF and Postscript Backend define their GRAFT but then never use
>> it. The stream sheet where the output is drawn is not a child of a
>> graft. I think this is not correct.
> Graft purpose is twofold: accessing a device properties and posing as
> the display server "root window". The latter doesn't make sense for
> output-only backends because there is no root window and windowing
> substrate doesn't apply to them.
> Having graft implementation for PDF and PS allows i.e to say, at which
> millimeter is a middle of the sheet of paper. Whether it is implemented
> correctly is another story. I think that (graf pdf-stream) should return
> the graft.
>> 3) GRAFT in general
>> Now each backend define its GRAFT. I think that the backend could only
>> initialize a standard-graft with the right information (in MAKE-GRAFT
>> generic) like: mirror, width, height, device-millimiter-density,
>> backend-transformation, and leave all the other stuff in the common
>> graft module "Core/clim-basic/windowing/grafts.lisp"
> Currently our grafts are stubs which allow converting physical sizes to
> pixels and vice versa, but in principle they have a more profound
> meaning for output operations with different coordinate systems. I've
> started exploring this topic with a console backend (interactive), which
> is different enough to expose many interesting implications.
> My current understanding is as follows (I'll use a console example):
> - device coordinates are specified by a column and a row
> - sheet user coordinates are specified by x and y in pixels
> Now let's draw something on a sheet:
>   (draw-rectangle* sheet 0 0 100 100)
> MEDIUM-TRANSFORMATION is used to transform user coordinates to device
> coordinates. To be able to construct such transformation you need to
> know how many horizontal pixels matches one column, how many vertical
> pixels matches one row, and if there is some translation between both
> (i.e pixels start at 0,0 while console starts at 1,1). One way to do
> that is:
> (defun make-px-to-ch-transformation (graft)
>   (let* ((sx (/ (clim:graft-width  graft :units :glyph)
>                 (clim:graft-width  graft :units :pixel)))
>          (sy (/ (clim:graft-height graft :units :glyph)
>                 (clim:graft-height graft :units :pixel)))
>          (dx 1)
>          (dy 1))
>     (clim:compose-translation-with-transformation
>      (clim:make-scaling-transformation sx sy)
>      dx dy)))
> which would initialize the sheet's medium when created. Moreover, we
> could imagine, that sheet user coordinates have no graft representation
> (i.e they are a density independent pixels), in that case
> sheet-native-transformation is initialized to transform dp to px, and
> then medium-transformation is composition of the
> sheet-native-transformation and a result of the above function.
> Of course none of this is currently implemented, but I hope it gives you
> an idea why graft's are a) useful, b) in case of non-pixel-based devices
> they are essential.
>> 4) transformation and region machinery
>> Is it the transformation and region machinery correct? Or it is works
>> only in some standard situaions? For example I think that we could
>> obtain a Zoom effect simply by: (setf (sheet-transformation
>> some-sheet) (make-scaling-transformation 1.5 1.5)) but this doesn't
>> work on McCLIM (I try it in the listener demo of clim-tos and there it
>> works). Follow some more specific topics:
> I did not investigate how the zooming effect could be conformingly
> achieved, but I think that modifying the SHEET-TRANSFORMATION is not the
> way to do that. If I were speculating I'd be more inclined to tinker
> with the medium transformation. No guarantees it will work (even if it
> is allowed by the spec which I'm not sure it is).

Why not? If you change the medium-transformation instead of
sheet-transformation you can not obtain zoom effect because in the
replay of output-record the medium-transformation is not take in
account. The Spec. (16.2) says for replay-output-record:

"Displays the output captured by the output record record on the output
recording stream stream, exactly as it was originally captured (subject
to subsequent modifications). 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

The "user transformation" *is* the medium-transformation as stated in
the Spec (10.1):

medium-transformation   medium                                   [Generic Function]

The current user transformation for the medium medium. This             
transformation is used to transform the coordinates supplied as         
arguments to drawing functions to the coordinate system of the drawing  
plane. See Chapter 5 for a complete description of transformations. The 
:transformation drawing option temporarily changes the value of         

>> 4a) Setting sheet-native-transformation:
>> %%SET-SHEET-NATIVE-TRANSFORMATION. I think this is not correct the
>> sheet-native-transformation must be computated and only cached never
>> set directly, otherwise you can lost the parent trasformation.
> It is an internal interface which makes possible to update a native
> transformation when we update the mirror geometry. You are right that it
> should never be used to change the native transformation, it is only
> used to update it when it changes (when we know what we are
> doing). %% prefix means "dangerous".

the sheet-native-transformation method already have the caching
mechanism. I think that the only things to do when we update the mirror
geometry is to invalidate-cached-transformations and
invalidate-cached-regions. The next call of sheet-native-transformation
will recompute it.

>> 4b) sheet-native-transformation for basic-sheet:
>> (defmethod sheet-native-transformation ((sheet basic-sheet))
>>   (with-slots (native-transformation) sheet
>>     (unless native-transformation
>>       (setf native-transformation
>> 	    (if-let ((parent (sheet-parent sheet)))
>> 	      (compose-transformations
>>                (sheet-native-transformation parent)
>>                (sheet-transformation sheet))
>>               +identity-transformation+)))
>>     native-transformation))
>> it's not correct because didn't take in account the mirror
>> transformation if the mirror of sheet it is not the same of the
>> parent.  So we need to correct this or to add a method for
>> mirrored-sheet-mixin.  Of course we didn't see the error because often
>> McCLIM set directly sheet-native-transform as written before in 4a)
> Mirrors have little to do with native transformations. See below.
> As far as sheet is concerned there are three coordinate systems which do
> not always match (i.e because of mirroring):
> - local  - coordinates of a current drawing context
> - user   - coordinates of a sheet
> - native - coordinates of a graft (screen)
> - device - coordinates of a medium
> As we know in the sheet hierarchy we may have multiple mirrors. Let's
> consider a very simple hierarchy where each next sheet is a child of the
> previous one:
> graft - (mirror sheet1) - sheet2 - (mirror sheet3) - sheet4
> Now some shortened definitions:
> SHEET-TRANSFORMATION "Returns a transformation that converts coordinates
> in the sheet sheet's coordinate system into coordinates in its parent's
> coordinate system."
> SHEET-NATIVE-TRANSFORMATION "Returns the transformation for the sheet
> sheet that converts sheet coordinates into native coordinates."
> SHEET-DELTA-TRANSFORMATION "Returns a transformation that is the
> composition of all of the sheet transformations between the sheets sheet
> and ancestor."
> SHEET-DEVICE-TRANSFORMATION "Returns the transformation used by the
> graphics output routines when drawing on the mirror."
> -----------------------------
> For illustration purpose let's assume that sheet4's transformation is a
> translation [20,20] (layout panes do that to position their children)
> and that sheet3's transformation is translation [100,100]. Other sheet
> Point [0,0] in sheet4 "user" coordinates is:
> - [20,20] in sheet3 "user" coordinates
> - [120,120] in sheet2 "user" coordinates
> - [120,120] in sheet1 "user" coordinates
> - [120,120] in graft "user" coordinates
> Since graft represents a screen, its "user" coordinats are native
> coordianates. We completely ignore mirrors when we compute
> SHEET-NATIVE-TRANSFORMATION, because it is a jump from sheet4 to the
> graft. That means, that the method mentioned by you earlier is correct.
> Delta transformation is a bit more interesting, because it allows to
> pick another ancestor (than a graft) to whose "user" coordinates we want
> to transform "our user" coordinates.
> Device transformation is the most confusing though, because mirror may
> have its local (in display server terms) coordinates which do not
> coincide with native coordinates.
> Point [0,0] in sheet4 "user" coordinates is:
> - [20,20] in sheet3 "device" coordinates
> Point [0,0] in sheet3 "user" coordinates is:
> - [0,0] in sheet3 "device" coordinates

I think this is not right respect to Spec and certainly is not what
McCLIM does. Try yourself open a clim-listener move the window in some
place of the screen and try: (sheet-native-tranformation
(frame-top-level-sheet *application-frame*)) I always have the identity
transformation as answer.

Check also this schema in Core/clim-basic/windowing/mirrors.lisp:

;;;                  NT                           NT = native transformation
;;;    sheet  ---------------->  mirror          PNT = parent's NT
;;;      |                         |              MT = mirror transformation
;;;      |                         |               T = sheet transformation
;;;      |                         |
;;;    T |                         | MT
;;;      |                         |
;;;      |                         |
;;;      |                         |
;;;      v          PNT            v
;;;    parent ----------------> parent
;;;                             mirror

Seems clear that sheet-native-transformation is the transformation from
sheet coordinate to mirror coordinate and not to the graft coordinate as
you stated. Infact the spec. introduce sheet-native-transformation in
the chapter about the mirrored sheet.

Here how I understand the Spec.:

1) each sheet have a coordinate system. sheet-transformation transform
the coordinate of the sheet to the coordinate of its parent (we agree on

2) for each sheet that it is mirrored (it is not necessary that is
directly mirrored) sheet-native-transformation transform the coordinate
of the sheet to the native coordinate that are used from the backend
drawing functions (e.g. for clx xlib:draw-line, xlib:draw-arc, ....)
i.e. the coordinate of the mirror.

3) the coordinate in clim drawing-functions are the coordinate in the
medium coordinate system that can be different from the sheet coordinate
because you can change it with drawing option or with macro like
with-scaling, with-translation, .... . The transformation from medium
coordinate system to sheet coordinate system is called in the spec. (I
said this before) "user transformation", and sheet-device-transformation
is the composition between user transformation and the sheet
transformation, so is the transformation that transform the coordinate
used in the clim drawing functions to the coordinate used in the backend
native drawing functions. 

>> 4c) What is sheet-native-region?
>> From the spec: "Returns the region for the sheet sheet in native
>> coordinates". This is not clear. The first time that I read it I
>> understood that it is the sheet-region of the sheet transformed in
>> native coordinates, that means for examples that a sheet with a region
>> +everywhere+ have a native-region +everywhere+. Instead for McCLIM,
>> and clim-tos too, it is the region of the mirror "for" the sheet
>> i.e. the sheet-region of the sheet transformed in native coordinates
>> clipped by the mirror region.  This interpretation maybe is correct
>> because the spec said about sheet-device-region:
>> "Returns the actual clipping region to be used when drawing on the
>> mirror. This is the intersection of the user's clipping region
>> (transformed by the device transformation) with the sheet's native
>> region."
>> Anyway, in this case, the sheet-native-region for the graft in Mcclim
>> is wrong: it is +everywhere+
> SHEET-NATIVE-REGION is the sheet region in screen coordinates. Graft
> *is* the screen, so we simply use sheet-region. Child native region is
> always clipped by its parent native region (parent is a "window" into a
> deeper plane), so we use region intersections between parent and child
> native regions.

Again what you said is not true: the sheet-native-region of a
frame-top-level-sheet ever report a region starting from 0 0.

And I continue to be not sure of Spec. interpretation, there are two (at
least) possibilities:

A) sheet-native-region return the sheet-region of the sheet transformed
in native coordinates.

B) sheet-native-region return the sheet-region of the sheet transformed
in native coordinates clipped by the mirror region.

> Things once again get more interesting for device-region. As descibed in
> the spec, it is the sheet-native-region clipped by the mirror
> region. Notice, that device-region may be partially obscured by its
> parent (however in practice it works poorly unless the parent is also a
> mirror, you may experiment with hierarchy tool demo in clim-examples
> with random mirroring arrangement - resize parent's for different
> combinations parent-child mirror-notmirror).
> -----------------------------------------
> I hope that it clarifies at least a little what is going on. I might
> have made a mistake somewhere because it was a long day and I'm looking
> into my notes from around 6 months ago :) and had to reread multiple
> parts of the spec.
> Best regards,
> Daniel
> --
> Daniel Kochmański ;; aka jackdaniel | Przemyśl, Poland
> TurtleWare - Daniel Kochmański      |
> "Be the change that you wish to see in the world." - Mahatma Gandhi

Andrea De Michele

More information about the mcclim-devel mailing list