[gs-cvs] rev 6926 - in trunk/gs: doc lib src

raph at ghostscript.com raph at ghostscript.com
Thu Jul 20 15:35:32 PDT 2006


Author: raph
Date: 2006-07-20 15:35:31 -0700 (Thu, 20 Jul 2006)
New Revision: 6926

Modified:
   trunk/gs/doc/Drivers.htm
   trunk/gs/doc/Language.htm
   trunk/gs/lib/gs_setpd.ps
   trunk/gs/src/gdevdflt.c
   trunk/gs/src/gsdevice.c
   trunk/gs/src/gsdparam.c
   trunk/gs/src/gxdevcli.h
   trunk/gs/src/gxdevice.h
Log:
Finishes implementation of LeadingEdge parameter, primarily intended for
rotating pages to fit paper tray orientation. The LeadingEdge parameter
is an Adobe-defined setpagedevice parameter, and can be set by 
PostScript code for explicit control over rotation, or can be set by the
device to reflect device knowledge of the tray orientation (the 
mechanism for the latter is documented in Drivers.htm). This patch
completely replaces the old TrayOrientation parameter, which had similar 
goals but was not standard, and fixes some problems with that 
implementation.


Modified: trunk/gs/doc/Drivers.htm
===================================================================
--- trunk/gs/doc/Drivers.htm	2006-07-20 19:18:25 UTC (rev 6925)
+++ trunk/gs/doc/Drivers.htm	2006-07-20 22:35:31 UTC (rev 6926)
@@ -25,56 +25,61 @@
 <li><a href="#KISS">Keeping things simple</a>
 <li><a href="#Structure">Driver structure</a>
 <ul>
-<li><a href="#Structure_definition">Structure definition</a>
-<li><a href="#Sophisticated">For sophisticated developers only</a>
+  <li><a href="#Structure_definition">Structure definition</a>
+  <li><a href="#Sophisticated">For sophisticated developers only</a>
 </ul>
 <li><a href="#coordinates_and_types">Coordinates and types</a>
 <ul>
-<li><a href="#Coordinate_system">Coordinate system</a>
-<li><a href="#Color_definition">Color definition</a>
+  <li><a href="#Coordinate_system">Coordinate system</a>
+  <li><a href="#Color_definition">Color definition</a>
 <ul>
-<li><a href="#sep_and_linear_fields">Separable and linear fields</a>
-<li><a href="#Changing_color_info_data">Changing color_info data</a>           
+  <li><a href="#sep_and_linear_fields">Separable and linear fields</a>
+  <li><a href="#Changing_color_info_data">Changing color_info data</a>           
 </ul>
 <li><a href="#Types">Types</a>
 </ul>
 <li><a href="#Coding_conventions">Coding conventions</a>
 <ul>
-<li><a href="#Allocating_storage">Allocating storage</a>
-<li><a href="#Driver_instance_allocation">Driver instance allocation</a>
+  <li><a href="#Allocating_storage">Allocating storage</a>
+  <li><a href="#Driver_instance_allocation">Driver instance allocation</a>
 </ul>
 <li><a href="#Printer_drivers">Printer drivers</a>
 <li><a href="#Driver_procedures">Driver procedures</a>
 <ul>
-<li><a href="#Life_cycle">Life cycle</a>
-<li><a href="#Open_close">Open, close, sync, copy</a>
-<li><a href="#Color_mapping">Color and alpha mapping</a>
-<li><a href="#Pixel_level_drawing">Pixel-level drawing</a>
+  <li><a href="#Life_cycle">Life cycle</a>
+  <li><a href="#Open_close">Open, close, sync, copy</a>
+  <li><a href="#Color_mapping">Color and alpha mapping</a>
+  <li><a href="#Pixel_level_drawing">Pixel-level drawing</a>
 <ul>
-<li><a href="#Bitmap_imaging">Bitmap imaging</a>
-<li><a href="#Pixmap_imaging">Pixmap imaging</a>
-<li><a href="#Compositing">Compositing</a>
+    <li><a href="#Bitmap_imaging">Bitmap imaging</a>
+    <li><a href="#Pixmap_imaging">Pixmap imaging</a>
+    <li><a href="#Compositing">Compositing</a>
   [<a href="#S_spec">S</a>, <a href="#T_spec">T</a>, <a href="#F_spec">f</a>,
    <a href="#Compositing_notes">Notes</a>]
 </ul>
-<li><a href="#Polygon_level_drawing">Polygon-level drawing</a>
-<li><a href="#Linear_color_drawing">Linear color drawing</a>
-<li><a href="#High_level_drawing">High-level drawing</a>
+  <li><a href="#Polygon_level_drawing">Polygon-level drawing</a>
+  <li><a href="#Linear_color_drawing">Linear color drawing</a>
+  <li><a href="#High_level_drawing">High-level drawing</a>
 <ul>
-<li><a href="#Paths">Paths</a>
-<li><a href="#Images">Images</a> [<a href="#Images_notes">Notes</a>]
-<li><a href="#Text">Text</a> [<a href="#Text_notes">Notes</a>]
-<li><a href="#Unicode">Unicode support for high level devices</a>
+    <li><a href="#Paths">Paths</a>
+    <li><a href="#Images">Images</a> [<a href="#Images_notes">Notes</a>]
+    <li><a href="#Text">Text</a> [<a href="#Text_notes">Notes</a>]
+    <li><a href="#Unicode">Unicode support for high level devices</a>
 </ul>
-<li><a href="#Reading_bits_back">Reading bits back</a>
-<li><a href="#Parameters">Parameters</a>
+  <li><a href="#Reading_bits_back">Reading bits back</a>
+  <li><a href="#Parameters">Parameters</a>
 <ul>
-<li><a href="#Default_CRD_parameters">Default color rendering dictionary (CRD) parameters</a>
+    <li><a href="#Default_CRD_parameters">Default color rendering dictionary (CRD) parameters</a>
 </ul>
-<li><a href="#External_fonts">External fonts</a>
-<li><a href="#Page_devices">Page devices</a>
-<li><a href="#Miscellaneous">Miscellaneous</a>
+  <li><a href="#External_fonts">External fonts</a>
+  <li><a href="#Page_devices">Page devices</a>
+  <li><a href="#Miscellaneous">Miscellaneous</a>
 </ul>
+<li><a href="#Tray">Tray selection</a>
+<ul>
+  <li><a href="#LeadingEdge">Tray rotation and the LeadingEdge parameter</a>
+  <li><a href="#LeadingPage">Interaction between LeadingEdge and PageSize</a>
+</ul>
 </ul></blockquote>
 
 <!-- [1.2 end table of contents] =========================================== -->
@@ -3067,6 +3072,179 @@
 <em>((0,0),(width,height))</em>.
 </dl>
 
+<hr>
+
+<h2><a name="Tray"></a>Tray selection</h2>
+
+<!-- Note for documentation maintainers: tray selection overlaps -->
+<!-- significantly across the device interface and the PostScript -->
+<!-- language implementation of setpagedevice, while the rest of -->
+<!-- Drivers.htm focusses on lanugage-independent interfaces. Likely -->
+<!-- the documentation should be refactored a bit so that this section -->
+<!-- has a comfortable home. -->
+
+<p>The logic for selecting input trays, and modifying other parameters
+based on tray selection, can be complex and subtle, largely thanks to
+the requirement to be compatible with the PostScript language
+setpagedevice mechanism. This section will describe recipes for
+several common scenarios for tray selection, with special attention to
+the how the overall task factors into configuration options, generic
+logic provided by the PostScript language (or not, if the device is
+used with other PDL's), and implementation of the put_param /
+get_param device functions within the device.
+
+<p>In general, tray selection is determined primarily through the
+setpagedevice operator, which is part of the PostScript runtime.
+Ghostscript attempts to be as compatible as is reasonable with the
+PostScript standard, so for more details, see the description in the
+<a
+href="http://partners.adobe.com/public/developer/ps/index_specs.html">PostScript
+language specifications</a>, including the "supplements", which tend
+to have more detail about setpagedevice behavior than the PLRM book itself.
+
+<p>The first step is to set up an /InputAttributes dictionary matching
+the trays and so on available in the device. The standard Ghostscript
+initialization files set up a large InputAttributes dictionary with
+many "known" page sizes (the full list is in
+<b><tt>gs_statd.ps</tt></b>, under .setpagesize). It's possible to
+edit this list in the Ghostscript source, of course, but most of the
+time it is better to execute a snippet of PostScript code after the
+default initialization but before sending any actual jobs.
+
+<p>Simply setting a new /InputAttributes dictionary with setpagedevice
+will not work, because the the language specification for
+setpagedevice demands a "merging" behavior - paper tray keys present
+in the old dictionary will be preserved even if the key is not present
+in the new /InputAttributes dictionary. Here is a sample invocation
+that clears out all existing keys, and installs three new ones: a US letter
+page size for trays 0 and 1, and 11x17 for tray 1. Note that you must add at
+least one valid entry into the /InputAttributes dictionary; if all are
+<b><tt>null</tt></b>, then the setpagedevice will fail with a
+/configurationerror.
+
+<blockquote><b><tt>
+&lt;&lt; /InputAttributes<br />
+&nbsp;&nbsp;currentpagedevice /InputAttributes get<br />
+&nbsp;&nbsp;dup { pop 1 index exch null put } forall<br />
+<br />
+&nbsp;&nbsp;dup 0 &lt;&lt; /PageSize [612 792] &gt;&gt; put<br />
+&nbsp;&nbsp;dup 1 &lt;&lt; /PageSize [612 792] &gt;&gt; put<br />
+&nbsp;&nbsp;dup 2 &lt;&lt; /PageSize [792 1224] &gt;&gt; put<br />
+&gt;&gt; setpagedevice<br />
+</tt></b></blockquote>
+
+<p>After this code runs, then requesting a letter page size (612x792
+points) from setpagedevice will select tray 0, and requesting an 11x17
+size will select tray 2. To explicitly request tray 1, run:
+
+<blockquote><b><tt>
+&lt;&lt; /PageSize [612 792] /MediaPosition 1 &gt;&gt; setpagedevice
+</tt></b></blockquote>
+
+<p>At this point, the chosen tray is sent to the device as the
+(nonstandard) %MediaSource device parameter. Devices with switchable
+trays should implement this device parameter in the
+<b><tt>put_params</tt></b> procedure. Unlike the usual protocol for
+device parameters, it is not necessary for devices to also implement
+<b><tt>get_params</tt></b> querying of this paramter; it is
+effectively a write-only communication from the language to the
+device. Currently, among the devices that ship with Ghostscript, only
+PCL (gdevdjet.c) and PCL/XL (gdevpx.c) implement this parameter, but
+that list may well grow over time.
+
+If the device has dynamic configuration of trays, etc., then the
+easiest way to get that information into the tray selection logic is
+to send a setpagedevice request (if using the standard API, then using
+gsapi_run_string_continue) to update the /InputAttributes dictionary
+immediately before beginning a job.
+
+<h3><a name="LeadingEdge"></a>Tray rotation and the LeadingEdge parameter</h3>
+
+<p>Large, sophisticated printers often have multiple trays supporting
+both short-edge and long-edge feed. For example, if the paper path is
+11 inches wide, then 11x17 pages must always print short-edge, but
+letter size pages print with higher throughput if fed from long-edge
+trays. Generally, the device will expect the rasterized bitmap image
+to be rotated with respect to the page, so that it's always the same
+orientation with respect to the paper feed direction.
+
+<p>The simplest way to achieve this behavior is to call
+<b><tt>gx_device_request_leadingedge</tt></b> to request a LeadingEdge
+value
+<b><tt>LeadingEdge</tt></b> field in the device structure based on the
+%MediaSource tray selection index and knowledge of the device's
+trays. The default put_params implementation will then handle this
+request (it's done this way to preserve the transactional semantics of
+put_params; it needs the new value, but the changes can't actually be
+made until all params succeed). For example, if tray 0 is long-edge,
+while trays 1 and 2 are short-edge, the following code outline should
+select the appropriate rotation:
+
+<blockquote><b><tt>
+my_put_params(gx_device *pdev, gs_param_list *plist) {<br />
+&nbsp;&nbsp;&nbsp;&nbsp;my_device *dev = (my_device *)pdev;<br />
+&nbsp;&nbsp;&nbsp;&nbsp;int MediaSource = dev->myMediaSource;<br />
+<br />
+&nbsp;&nbsp;&nbsp;&nbsp;code = param_read_int(plist, "%MediaSource", &MediaSource);<br />
+<br />
+&nbsp;&nbsp;&nbsp;&nbsp;switch (MediaSource) {<br />
+&nbsp;&nbsp;&nbsp;&nbsp;case 0:<br />
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gx_device_req_leadingedge(dev, 1);<br />
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
+&nbsp;&nbsp;&nbsp;&nbsp;case 1:<br />
+&nbsp;&nbsp;&nbsp;&nbsp;case 2:<br />
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gx_device_req_leadingedge(dev, 0);<br />
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
+&nbsp;&nbsp;&nbsp;&nbsp;}<br />
+&nbsp;&nbsp;&nbsp;&nbsp;...call default put_params, which makes the change...<br />
+<br />
+&nbsp;&nbsp;&nbsp;&nbsp;dev->myMediaSource = MediaSource;<br />
+&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br />
+}
+</tt></b></blockquote>
+
+<p>Ghostscript also supports explicit rotation of the page through
+setting the /LeadingEdge parameter with setpagedevice. The above code
+snippet will simply override this request. To give manual setting
+through setpagedevice priority, don't change the LeadingEdge field in
+the device if its LEADINGEDGE_SET_MASK bit is set. In other words,
+simply enclose the above <tt>switch</tt> statement inside an <b><tt>if
+(!(dev->LeadingEdge & LEADINGEDGE_SET_MASK) { ... }</tt></b> statement.
+
+<!-- Note for doc maintainers: the following is much more of a -->
+<!-- discussion of the PS language than a device interface issue, but -->
+<!-- it is essential info for people implementing this stuff. -->
+
+<h3><a name="LeadingPage"></a>Interaction between LeadingEdge and PageSize</h3>
+
+<p>As of LanguageLevel 3, PostScript now has two mechanisms for rotating
+the imaging of the page: the LeadingEdge parameter described in detail
+above, and the automatic rotation as enabled by the /PageSize page
+device parameter (described in detail in Table 6.2 of the PLRM3).
+Briefly, the PageSize autorotation handles the case where the page
+size requested in setpagedevice matches the <i>swapped</i> size of the
+paper source (as set in the InputAttributesDictionary). This mechanism
+can be, and has been, used to implement long-edge feed, but has
+several disadvantages. Among other things, it's overly tied to the PostScript
+language, while the device code above will work with other
+languages. Also, it only specifies one direction of rotation (90
+degrees counterclockwise). Thus, given the choice, LeadingEdge is to
+be preferred.
+
+<p>If PageSize is used, the following things are different:
+
+<ul>
+<li>The PageSize array in InputAttributes is swapped, so it is [long
+short].
+<li>The .MediaSize device parameter is similarly swapped.
+<li>The initial matrix established by the device through the
+<b><tt>get_initial_matrix</tt></b> procedure is the same as for the
+non-rotated case.
+<li>The CTM rotation is done in the setpagedevice implementation.
+</ul>
+
+<!-- Why oh why does it all have to be so complicated? -->
+
 <!-- [2.0 end contents] ==================================================== -->
 
 <!-- [3.0 begin visible trailer] =========================================== -->

Modified: trunk/gs/doc/Language.htm
===================================================================
--- trunk/gs/doc/Language.htm	2006-07-20 19:18:25 UTC (rev 6925)
+++ trunk/gs/doc/Language.htm	2006-07-20 22:35:31 UTC (rev 6926)
@@ -1800,6 +1800,24 @@
 </dl>
 
 <dl>
+<dt><b><tt>%MediaSource &lt;integer&gt;</tt></b>
+<dd>The input tray key as determined by setpagedevice. PostScript
+language programs don't set this parameter directly; they can
+<em>request</em> a particular tray through the MediaPosition
+setpagedevice parameter, but the setpagedevice logic need not
+necessarily honor the request. Devices which support switchable trays
+should implement %MediaSource in their put_params device procedure,
+but (unlike most other such parameters) need not implement
+corresponding reading logic in get_params.
+</dl>
+
+<dl>
+<dt><b><tt>%MediaDestination &lt;integer&gt;</tt></b>
+<dd>The output tray key as determined by setpagedevice. Handling by
+devices should be parallel to %MediaSource.
+</dl>
+
+<dl>
 <dt><b><tt>Name &lt;string&gt; (read-only)</tt></b>
 <dd>The device name.  Currently the same as <b><tt>OutputDevice</tt></b>.
 </dl>
@@ -1840,6 +1858,8 @@
 <b><tt>HWResolution</tt></b><br>
 <b><tt>ImagingBBox</tt></b><br>
 <b><tt>Margins</tt></b><br>
+<b><tt>LeadingEdge</tt></b><br>
+<b><tt>MediaPosition</tt></b><br>
 <b><tt>NumCopies</tt></b> (for printers only)<br>
 <b><tt>Orientation</tt></b> (if supported)<br>
 <b><tt>OutputDevice</tt></b><br>

Modified: trunk/gs/lib/gs_setpd.ps
===================================================================
--- trunk/gs/lib/gs_setpd.ps	2006-07-20 19:18:25 UTC (rev 6925)
+++ trunk/gs/lib/gs_setpd.ps	2006-07-20 22:35:31 UTC (rev 6926)
@@ -230,6 +230,7 @@
 % on its own.
 /.dynamicppkeys mark
   /.MediaSize dup		% because it changes when PageSize is set
+%  /LeadingEdge dup
   /PageCount dup
   /Colors dup
   /BitsPerPixel dup
@@ -407,7 +408,9 @@
 % The procedure leaves all its operands on the stack and returns
 % true iff the key/value pair should be presented to .putdeviceparams.
 /.presentspecial mark
-  .dynamicppkeys { pop //false } forall
+  .dynamicppkeys
+      { pop dup /LeadingEdge ne { //false } { pop } ifelse }
+  forall
 			% We must ignore an explicit request for .MediaSize,
 			% because media matching always handles this.
   /.MediaSize //false
@@ -418,7 +421,7 @@
   /PageSize //false		% obsolete alias for .MediaSize
   /InputAttributes //false
   .inputattrkeys
-    { dup /PageSize eq
+       { dup dup /PageSize eq exch /LeadingEdge eq or
        { pop }
        { { 2 index /InputAttributes .knownget { //null eq } { //true } ifelse } }
       ifelse

Modified: trunk/gs/src/gdevdflt.c
===================================================================
--- trunk/gs/src/gdevdflt.c	2006-07-20 19:18:25 UTC (rev 6925)
+++ trunk/gs/src/gdevdflt.c	2006-07-20 22:35:31 UTC (rev 6926)
@@ -677,17 +677,51 @@
 
 /* Get the initial matrix for a device with inverted Y. */
 /* This includes essentially all printers and displays. */
+/* Supports LeadingEdge, but no margins or viewports */
 void
 gx_default_get_initial_matrix(gx_device * dev, register gs_matrix * pmat)
 {
-    pmat->xx = dev->HWResolution[0] / 72.0;	/* x_pixels_per_inch */
-    pmat->xy = 0;
-    pmat->yx = 0;
-    pmat->yy = dev->HWResolution[1] / -72.0;	/* y_pixels_per_inch */
-    /****** tx/y is WRONG for devices with ******/
-    /****** arbitrary initial matrix ******/
-    pmat->tx = 0;
-    pmat->ty = (float)dev->height;
+    /* NB this device has no paper margins */
+    floatp fs_res = dev->HWResolution[0] / 72.0;
+    floatp ss_res = dev->HWResolution[1] / 72.0;
+
+    switch(dev->LeadingEdge & LEADINGEDGE_MASK) {
+    case 1: /* 90 degrees */
+        pmat->xx = 0;
+        pmat->xy = -ss_res;
+        pmat->yx = -fs_res;
+        pmat->yy = 0;
+        pmat->tx = dev->width;
+        pmat->ty = dev->height;
+        break;
+    case 2: /* 180 degrees */
+        pmat->xx = -fs_res;
+        pmat->xy = 0;
+        pmat->yx = 0;
+        pmat->yy = ss_res;
+        pmat->tx = dev->width;
+        pmat->ty = 0;
+        break;
+    case 3: /* 270 degrees */
+        pmat->xx = 0;
+        pmat->xy = ss_res;
+        pmat->yx = fs_res;
+        pmat->yy = 0;
+        pmat->tx = 0;
+        pmat->ty = 0;
+        break;
+    default:
+    case 0:
+        pmat->xx = fs_res;
+        pmat->xy = 0;
+        pmat->yx = 0;
+        pmat->yy = -ss_res;
+        pmat->tx = 0;
+        pmat->ty = dev->height;
+	/****** tx/y is WRONG for devices with ******/
+	/****** arbitrary initial matrix ******/
+        break;
+    }
 }
 /* Get the initial matrix for a device with upright Y. */
 /* This includes just a few printers and window systems. */

Modified: trunk/gs/src/gsdevice.c
===================================================================
--- trunk/gs/src/gsdevice.c	2006-07-20 19:18:25 UTC (rev 6925)
+++ trunk/gs/src/gsdevice.c	2006-07-20 22:35:31 UTC (rev 6926)
@@ -567,22 +567,31 @@
     }
 }
 
+private void
+gx_device_set_hwsize_from_media(gx_device *dev)
+{
+    int rot = (dev->LeadingEdge & 1);
+    floatp rot_media_x = rot ? dev->MediaSize[1] : dev->MediaSize[0];
+    floatp rot_media_y = rot ? dev->MediaSize[0] : dev->MediaSize[1];
 
-/* Handle 90 and 270 degree rotation of the Tray
- * Device must support TrayOrientation in its InitialMatrix and get/put params
- */
+    dev->width = (int)(rot_media_x * dev->HWResolution[0] / 72.0 + 0.5);
+    dev->height = (int)(rot_media_y * dev->HWResolution[1] / 72.0 + 0.5);
+}
+
 private void
-gx_device_TrayOrientationRotate(gx_device *dev)
+gx_device_set_media_from_hwsize(gx_device *dev)
 {
-  if ( dev->TrayOrientation == 90 || dev->TrayOrientation == 270) {
-    /* page sizes don't rotate, height and width do rotate 
-     * HWResolution, HWSize, and MediaSize parameters interact, 
-     * and must be set before TrayOrientation
-     */
-    int tmp = dev->height;
-    dev->height = dev->width;
-    dev->width = tmp;
-  }
+    int rot = (dev->LeadingEdge & 1);
+    floatp x = dev->width * 72.0 / dev->HWResolution[0];
+    floatp y = dev->height * 72.0 / dev->HWResolution[1];
+
+    if (rot) {
+	dev->MediaSize[1] = x;
+	dev->MediaSize[0] = y;
+    } else {
+	dev->MediaSize[0] = x;
+	dev->MediaSize[1] = y;
+    }
 }
 
 /* Set the width and height, updating MediaSize to remain consistent. */
@@ -591,9 +600,7 @@
 {
     dev->width = width;
     dev->height = height;
-    dev->MediaSize[0] = width * 72.0 / dev->HWResolution[0];
-    dev->MediaSize[1] = height * 72.0 / dev->HWResolution[1];
-    gx_device_TrayOrientationRotate(dev);
+    gx_device_set_media_from_hwsize(dev);
 }
 
 /* Set the resolution, updating width and height to remain consistent. */
@@ -602,9 +609,7 @@
 {
     dev->HWResolution[0] = x_dpi;
     dev->HWResolution[1] = y_dpi;
-    dev->width = (int)(dev->MediaSize[0] * x_dpi / 72.0 + 0.5);
-    dev->height = (int)(dev->MediaSize[1] * y_dpi / 72.0 + 0.5);
-    gx_device_TrayOrientationRotate(dev);
+    gx_device_set_hwsize_from_media(dev);
 }
 
 /* Set the MediaSize, updating width and height to remain consistent. */
@@ -613,9 +618,7 @@
 {
     dev->MediaSize[0] = media_width;
     dev->MediaSize[1] = media_height;
-    dev->width = (int)(media_width * dev->HWResolution[0] / 72.0 + 0.499);
-    dev->height = (int)(media_height * dev->HWResolution[1] / 72.0 + 0.499);
-    gx_device_TrayOrientationRotate(dev);
+    gx_device_set_hwsize_from_media(dev);
 }
 
 /*

Modified: trunk/gs/src/gsdparam.c
===================================================================
--- trunk/gs/src/gsdparam.c	2006-07-20 19:18:25 UTC (rev 6925)
+++ trunk/gs/src/gsdparam.c	2006-07-20 22:35:31 UTC (rev 6926)
@@ -168,6 +168,14 @@
 	)
 	return code;
 
+    /* If LeadingEdge was set explicitly, report it here. */
+    if (dev->LeadingEdge & LEADINGEDGE_SET_MASK) {
+	int leadingedge = dev->LeadingEdge & LEADINGEDGE_MASK;
+	code = param_write_int(plist, "LeadingEdge", &leadingedge);
+    }
+    if (code < 0)
+	return code;
+
     /* Fill in color information. */
 
     if (colors > 1) {
@@ -443,6 +451,7 @@
     int tab = dev->color_info.anti_alias.text_bits;
     int gab = dev->color_info.anti_alias.graphics_bits;
     gs_param_string cms;
+    int leadingedge = dev->LeadingEdge;
 
     /*
      * Template:
@@ -479,6 +488,17 @@
 	ecode = code;
 #endif
     /*
+     * The actual value of LeadingEdge must be changed inside this routine,
+     * so that we can detect that it has been changed. Thus, instead of a
+     * device setting the value itself, it signals a request, which is
+     * now executed.
+     */
+    if (leadingedge & LEADINGEDGE_REQ_BIT) {
+	leadingedge = (leadingedge & LEADINGEDGE_SET_MASK) |
+	    ((leadingedge >> LEADINGEDGE_REQ_VAL_SHIFT) && LEADINGEDGE_MASK);
+    }
+
+    /*
      * The HWResolution, HWSize, and MediaSize parameters interact in
      * the following way:
      *      1. Setting HWResolution recomputes HWSize from MediaSize.
@@ -488,6 +508,13 @@
      * 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).
      */
 
     BEGIN_ARRAY_PARAM(param_read_float_array, "HWResolution", hwra, 2, hwre) {
@@ -513,6 +540,26 @@
 	    break;
     } END_ARRAY_PARAM(hwsa, hwse);
     {
+	int t;
+
+	code = param_read_int(plist, "LeadingEdge", &t);
+	if (code < 0) {
+	    if (param_read_null(plist, "LeadingEdge") == 0) {
+		/* if param is null, clear explicitly-set flag */
+		leadingedge &= ~LEADINGEDGE_SET_MASK;
+		code = 0;
+	    } else {
+		ecode = code;
+	    }
+	} else if (code == 0) {
+	    if (t < 0 || t > 3)
+		param_signal_error(plist, "LeadingEdge",
+				   ecode = gs_error_rangecheck);
+	    else
+		leadingedge = LEADINGEDGE_SET_MASK | t;
+	}
+    }
+    {
 	const float *res = (hwra.data == 0 ? dev->HWResolution : hwra.data);
 
 #ifdef PAGESIZE_IS_MEDIASIZE
@@ -699,12 +746,14 @@
     if (code < 0)
 	return code;
 
-    /* Now actually make the changes. */
-    /* Changing resolution or page size requires closing the device, */
-    /* but changing margins or ImagingBBox does not. */
-    /* In order not to close and reopen the device unnecessarily, */
-    /* we check for replacing the values with the same ones. */
-
+    /* 
+     * Now actually make the changes. Changing resolution, rotation
+     * (through LeadingEdge) or page size requires closing the device,
+     * but changing margins or ImagingBBox does not. In order not to
+     * close and reopen the device unnecessarily, we check for
+     * replacing the values with the same ones.
+     */
+    
     if (hwra.data != 0 &&
 	(dev->HWResolution[0] != hwra.data[0] ||
 	 dev->HWResolution[1] != hwra.data[1])
@@ -713,6 +762,19 @@
 	    gs_closedevice(dev);
 	gx_device_set_resolution(dev, hwra.data[0], hwra.data[1]);
     }
+    if ((leadingedge & LEADINGEDGE_MASK) !=
+	(dev->LeadingEdge & LEADINGEDGE_MASK)) {
+	/* If the LeadingEdge_set flag changes but the value of LeadingEdge
+	   itself does not, don't close device and recompute page size. */
+	dev->LeadingEdge = leadingedge;
+	if (dev->is_open)
+	    gs_closedevice(dev);
+	gx_device_set_resolution(dev, dev->HWResolution[0], dev->HWResolution[1]);
+    }
+    /* clear leadingedge request, preserve "set" flag */
+    dev->LeadingEdge &= LEADINGEDGE_MASK;
+    dev->LeadingEdge |= (leadingedge & LEADINGEDGE_SET_MASK);
+
     if (hwsa.data != 0 &&
 	(dev->width != hwsa.data[0] ||
 	 dev->height != hwsa.data[1])
@@ -759,6 +821,14 @@
     return 0;
 }
 
+void
+gx_device_request_leadingedge(gx_device *dev, int le_req)
+{
+    dev->LeadingEdge = (dev->LeadingEdge & ~LEADINGEDGE_REQ_VAL) |
+	((le_req << LEADINGEDGE_REQ_VAL_SHIFT) & LEADINGEDGE_REQ_VAL) |
+	LEADINGEDGE_REQ_BIT;
+}
+
 /* Read TextAlphaBits or GraphicsAlphaBits. */
 private int
 param_anti_alias_bits(gs_param_list * plist, gs_param_name param_name, int *pa)

Modified: trunk/gs/src/gxdevcli.h
===================================================================
--- trunk/gs/src/gxdevcli.h	2006-07-20 19:18:25 UTC (rev 6925)
+++ trunk/gs/src/gxdevcli.h	2006-07-20 22:35:31 UTC (rev 6926)
@@ -695,7 +695,7 @@
 	gx_device_cached_colors_t cached_colors;\
 	int width;			/* width in pixels */\
 	int height;			/* height in pixels */\
-        int TrayOrientation;            /* default 0 ( 90 180 270 ) if device supports */\
+        int LeadingEdge;                /* see below */\
 	float MediaSize[2];		/* media dimensions in points */\
 	float ImagingBBox[4];		/* imageable region in points */\
 	  bool ImagingBBox_set;\
@@ -717,7 +717,24 @@
 	gx_page_device_procs page_procs;	/* must be last */\
 		/* end of std_device_body */\
 	gx_device_procs procs	/* object procedures */
+
+#define LEADINGEDGE_MASK 3
+#define LEADINGEDGE_SET_MASK (1 << 2)
+#define LEADINGEDGE_REQ_BIT (1 << 3)
+#define LEADINGEDGE_REQ_VAL_SHIFT 4
+#define LEADINGEDGE_REQ_VAL (LEADINGEDGE_MASK << LEADINGEDGE_REQ_VAL_SHIFT)
 /*
+ * The lower two bits of LeadingEdge correspond to the pagedevice
+ * parameter of the same name. The next bit (hex value 4) is set if
+ * the LeadingEdge was set explicitly by the user using setpagedevice.
+ * Otherwise, the value is the default as determined by the device (or
+ * zero if the device has no logic for setting LeadingEdge based on
+ * other parameters (such as %MediaSource). This field replaces the
+ * earlier TrayOrientation, which had a similar purpose but was not
+ * compatible with the PostScript spec.
+ */
+
+/*
  * Note: x/y_pixels_per_inch are here only for backward compatibility.
  * They should not be used in new code.
  */
@@ -754,7 +771,6 @@
 #define assign_dev_procs(todev, fromdev)\
   ((todev)->procs = (fromdev)->procs)
 
-
 /* ---------------- Device procedures ---------------- */
 
 /* Define an opaque type for parameter lists. */

Modified: trunk/gs/src/gxdevice.h
===================================================================
--- trunk/gs/src/gxdevice.h	2006-07-20 19:18:25 UTC (rev 6925)
+++ trunk/gs/src/gxdevice.h	2006-07-20 22:35:31 UTC (rev 6926)
@@ -577,4 +577,6 @@
 
 int gdev_end_output_media(gs_param_list * mlist, gs_param_dict * pdict);
 
+void gx_device_request_leadingedge(gx_device *dev, int le_req);
+
 #endif /* gxdevice_INCLUDED */



More information about the gs-cvs mailing list