Bug 703308

Summary: HWResolution does not change X-Window resolution
Product: Ghostscript Reporter: Eponymous <eponymousalias>
Component: X Display DriverAssignee: Chris Liddell (chrisl) <chris.liddell>
Status: RESOLVED FIXED    
Severity: normal CC: eponymousalias
Priority: P4    
Version: 9.53.3   
Hardware: PC   
OS: Linux   
Customer: Word Size: ---
Attachments: test file for HWResolution failure
test image showing proper behavior
test image showing incorrect behavior

Description Eponymous 2020-12-26 16:43:48 UTC
Created attachment 20392 [details]
test file for HWResolution failure

When switching one of my PostScript applications from
running under GS 7.07.1 to running under GS 9.26, I
found that setting HWResolution no longer changes the
window resolution as far as user-to-device space mapping
is concerned.  It does change the on-screen window size,
but it does not change HWSize, either, unless I do that
manually as well.  The net effect is a different scale of
the drawn objects than if you had set the resolution to
its final value on the command line, and that should not
be the case.

My context is, running under Linux, using X-Windows as
the display device.

I tracked down the time at which the change in behavior
occurred, as best I could.  It happened sometime between
GS 8.71.1 (which works as expected) and GS 9.05.0 (which
fails to change the page resolution).  I then dug into
the GS 9.53.3 code and found that these are the offending
lines (879-883), in the devices/gdevxini.c file:

    /* Preserve screen resolution */
    dev->x_pixels_per_inch = values.x_pixels_per_inch;
    dev->y_pixels_per_inch = values.y_pixels_per_inch;
    dev->HWResolution[0] = values.HWResolution[0];
    dev->HWResolution[1] = values.HWResolution[1];

If I comment out those lines, the expected and desired
behavior of HWResolution returns.  That means the physical
size of a user-space unit scales with the change in device
resolution, so the overall user-space page size remains
unchanged and still fills the window.  So as far as I can
tell (though I have not looked at any of the surrounding
code), the fix appears to be to just remove those lines
from the code.

For reference as to when the code change was made that put
those lines into play, see bug #690444 and:
http://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff;h=5d2d901fd7f831dfd7c17fb89a2b9e0c9def8a54
My use case suggests that perhaps a slightly more nuanced
fix is appropriate.

I have prepared a resolution.ps test file that demonstrates
the problem (gs -sDEVICE=x11 resolution.ps).  You can run
it against GS 8.71.1 to see the expected behavior (see
good_resolution.png), then against 9.53.3 to see the buggy
behavior (see bad_resolution.png).  Also see the output
printed in the terminal window, for more detail as to the
values understood by the PostScript interpreter.

Separately, it is surprising that HWSize does not change
automatically at the same time as the window is resized.
I have not tracked down what code changes are needed
to make that happen.  But in that regard, for reference
as to the proper processing in such changes due to the
natural relationships between different parameters,
see the following comment (lines 1492-1509) in the
base/gsdparam.c file:

   /*
    * The HWResolution, HWSize, and MediaSize parameters interact in
    * the following way:
    *      1. Setting HWResolution recomputes HWSize from MediaSize.
    *      2. Setting HWSize recomputes MediaSize from HWResolution.
    *      3. Setting MediaSize recomputes HWSize from HWResolution.
    * If more than one parameter is being set, we apply these rules
    * in the order 1, 2, 3.  This does the right thing in the most
    * common case of setting more than one parameter, namely,
    * setting both HWResolution and HWSize.
    *
    * Changing of LeadingEdge is treated exactly the same as a
    * change in HWResolution. In typical usage, MediaSize is
    * short-edge (MediaSize[0] < MediaSize[1]), so if LeadingEdge
    * is 1 or 3, then HWSize will become long-edge. For nonsquare
    * resolutions, HWResolution[0] always corresponds with width
    * (scan length), and [1] with height (number of scans).
    */
Comment 1 Eponymous 2020-12-26 16:45:23 UTC
Created attachment 20393 [details]
test image showing proper behavior
Comment 2 Eponymous 2020-12-26 16:46:15 UTC
Created attachment 20394 [details]
test image showing incorrect behavior
Comment 3 Till Kamppeter 2021-08-30 16:59:15 UTC
Unfortunately, I cannot help much here. The commit you mention was uploaded by me but probably a patch created by someone else and after testing that it fixes the originally reported bug I have uploaded the patch.

So I do not know the exact meanings of each of the lines of the patch.

So if someone more knowledgeable than me about the X11 device could check whether removing the 4 lines mentioned does not cause any other problem, this would be great.
Comment 4 Chris Liddell (chrisl) 2022-02-21 17:01:47 UTC
This presents something of a problem.

Obviously, we can't just allow attempts to resize the window with the media size or resolution which would potentially crash (or even just massively slow down) the X server. So simply removing those lines isn't really an option.

OTOH, I agree the current behaviour is not what I would expect.

Further, I'm loath to just add some arbitrary limits because, really, sensible limits will differ hugely between different machines. On that basis, I think it makes sense to still limit the requested dimensions by the available screen area.

This is where I'm at right now:
https://git.ghostscript.com/?p=user/chrisl/ghostpdl.git;a=commitdiff;h=502112b78469


The remaining oddity is related to a specific implementation detail of how Ghostscript's setpagedevice/currentpagedevice work. If I change your Postscript to use the "/.MediaSize" key, instead of the "/PageSize" it all behaves as I expect.

I'd welcome opinions on that approach.
Comment 5 Eponymous 2022-02-21 18:50:06 UTC
There are times when I, perhaps accidentally, set
the page size to something much larger than my 
screen size.  And sometimes it is then convenient
to grab the window top framestripe and move the
window left and right so I can see some part of 
what would not fit all at once on my screen. 
But that doesn't work for vertical panning,
because the other edges of the window just resize
the window, so it's not a general solution.
Which means, that is literally an edge case
([not] sorry for the pun), that I would not
expect you to support.

That said, your proposed code change goes
beyond just clamping to the screen size.
It also attempts to maintain a notion of the
page aspect ratio, by changing the height when
the width needs to be clamped, and vice versa.
I think that is a bridge too far.  Each dimension
should be limited on its own, without thereby 
limiting the other dimension.  Which means that
these lines should be dropped:

dev->height *= ((float)area_width / dev->width);

dev->width *= ((float)area_height / dev->height);

While perhaps there is no perfect solution,
perhaps the way to think of this is to compare 
it to what happens when you print on paper.
In that situation, there is a natural clipping
at the edges of the paper, or as close to the
edges as the printer can image.  But that's it;
no additional restriction is imposed.

My perspective is that it would be nice to 
have scrollbars appear only when needed, when
the requested area is larger than the visible 
window area.  But I'm not expecting that sort
of development just to fix this bug.  It's maybe
something to ruminate over for the future.
Comment 6 Chris Liddell (chrisl) 2022-02-24 16:08:03 UTC
I guess my reasoning was that I would expect the the content to scale with the dimensions, and thus we'd want to maintain the aspect ratio to avoid the content being distorted.

I'm wary about using "what a printer would do" as much of a guide because a real printer can't (in general) arbitrarily change page sizes, nor resolutions, and also whether a Postscript printer clips, scales, scales down only.... are all, or should be, configurable to the users needs (see the PLRM "PageSize Policies").


Also, the X11 devices were intended to be, and are, pretty dumb. Their architecture makes adding things like scrolling, at best, extremely awkward, and worst maybe impossible (without a substantial re-architecting).

Obviously, the ideal solution would be that we could rely on the X server to reject a unreasonable requests, but that seems not to be the case. Or, alternatively, provide some way to identify what is an unreasonable request before trying it, also seems not to be the case.

Hence the available screen area still feels like the best compromise.

I don't see any specific problem clamping each dimension individually, so it would looks like:

https://git.ghostscript.com/?p=user/chrisl/ghostpdl.git;a=commitdiff;h=afb3c1d9597
Comment 7 Chris Liddell (chrisl) 2022-06-01 15:14:22 UTC
Above proposed change pushed:

https://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff;h=1030e59c64c9