315 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			315 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
/*******************************************************************
 | 
						|
**
 | 
						|
**    *********************************************************
 | 
						|
**    *
 | 
						|
**    *  File:		PclLine.c
 | 
						|
**    *
 | 
						|
**    *  Contents:
 | 
						|
**    *                 Line drawing routines for the PCL driver
 | 
						|
**    *
 | 
						|
**    *  Created:	10/11/95
 | 
						|
**    *
 | 
						|
**    *********************************************************
 | 
						|
**
 | 
						|
********************************************************************/
 | 
						|
/*
 | 
						|
(c) Copyright 1996 Hewlett-Packard Company
 | 
						|
(c) Copyright 1996 International Business Machines Corp.
 | 
						|
(c) Copyright 1996 Sun Microsystems, Inc.
 | 
						|
(c) Copyright 1996 Novell, Inc.
 | 
						|
(c) Copyright 1996 Digital Equipment Corp.
 | 
						|
(c) Copyright 1996 Fujitsu Limited
 | 
						|
(c) Copyright 1996 Hitachi, Ltd.
 | 
						|
 | 
						|
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
						|
of this software and associated documentation files (the "Software"), to deal
 | 
						|
in the Software without restriction, including without limitation the rights
 | 
						|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
						|
copies of the Software, and to permit persons to whom the Software is
 | 
						|
furnished to do so, subject to the following conditions:
 | 
						|
 | 
						|
The above copyright notice and this permission notice shall be included in
 | 
						|
all copies or substantial portions of the Software.
 | 
						|
 | 
						|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
						|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
						|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 | 
						|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 | 
						|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 | 
						|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
						|
 | 
						|
Except as contained in this notice, the names of the copyright holders shall
 | 
						|
not be used in advertising or otherwise to promote the sale, use or other
 | 
						|
dealings in this Software without prior written authorization from said
 | 
						|
copyright holders.
 | 
						|
*/
 | 
						|
 | 
						|
#ifdef HAVE_DIX_CONFIG_H
 | 
						|
#include <dix-config.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include "Pcl.h"
 | 
						|
#include "gcstruct.h"
 | 
						|
#include "windowstr.h"
 | 
						|
 | 
						|
/*
 | 
						|
 * PclPolyLine()
 | 
						|
 * PclPolySegment()
 | 
						|
 *
 | 
						|
 * Generates PCL code to draw a polyline, or a collection of distinct
 | 
						|
 * line segments, clipped by the current clip region.  Since PCL
 | 
						|
 * supports clipping to a rectangle, and the clip region is
 | 
						|
 * represented as a collection of visible rectangles, we can draw and
 | 
						|
 * clip the line by repeatedly drawing the complete line, clipped to
 | 
						|
 * each rectangle in the clip region.
 | 
						|
 *
 | 
						|
 * Since each box in the clipping region generates approximately 30
 | 
						|
 * bytes of PCL code, we have to have a way to avoid having a large
 | 
						|
 * number of boxes.  The worst problem the case where the clipping
 | 
						|
 * region is a collection of one-pixel-high boxes, perhaps arising
 | 
						|
 * from a bitmap clip mask, or a region defined by a non-rectangular
 | 
						|
 * polygon.
 | 
						|
 *
 | 
						|
 * To alleviate this problem, we create a second clipping region,
 | 
						|
 * which consists of the union of the bounding boxes of each line
 | 
						|
 * segment.  (Each bounding box is also increased by some amount
 | 
						|
 * related to the current line width to allow for non-zero-width
 | 
						|
 * lines, and for the various end and join styles.)  This region is
 | 
						|
 * intersected with the "real" clipping region to get the region used
 | 
						|
 * to actually clip the polyline.  This should result in a significant
 | 
						|
 * reduction in the number of clip rectangles, as the region-handling
 | 
						|
 * code should consolidate many of the fragments of one-pixel-high
 | 
						|
 * rectangles into larger rectangles.
 | 
						|
 */
 | 
						|
 | 
						|
void
 | 
						|
PclPolyLine(
 | 
						|
     DrawablePtr pDrawable,
 | 
						|
     GCPtr pGC,
 | 
						|
     int mode,
 | 
						|
     int nPoints,
 | 
						|
     xPoint *pPoints)
 | 
						|
{
 | 
						|
    char t[80];
 | 
						|
    FILE *outFile;
 | 
						|
    int xoffset = 0, yoffset = 0;
 | 
						|
    int nbox;
 | 
						|
    BoxPtr pbox;
 | 
						|
    xRectangle *drawRects, *r;
 | 
						|
    RegionPtr drawRegion, region;
 | 
						|
    short fudge;
 | 
						|
    int i;
 | 
						|
    XpContextPtr pCon;
 | 
						|
    PclContextPrivPtr pConPriv;
 | 
						|
 | 
						|
    if( PclUpdateDrawableGC( pGC, pDrawable, &outFile ) == FALSE )
 | 
						|
      return;
 | 
						|
 | 
						|
    pCon = PclGetContextFromWindow( (WindowPtr) pDrawable );
 | 
						|
    pConPriv = (PclContextPrivPtr)
 | 
						|
			pCon->devPrivates[PclContextPrivateIndex].ptr;
 | 
						|
 | 
						|
    /*
 | 
						|
     * Allocate the storage required to deal with the clipping
 | 
						|
     * regions.
 | 
						|
     */
 | 
						|
    region = REGION_CREATE( pGC->pScreen, NULL, 0 );
 | 
						|
    drawRects = (xRectangle *)
 | 
						|
      xalloc( ( nPoints - 1 ) * sizeof( xRectangle ) );
 | 
						|
 | 
						|
    /*
 | 
						|
     * Calculate the "fudge factor" based on the line width.
 | 
						|
     * Multiplying by three seems to be a good first guess.
 | 
						|
     * XXX I need to think of a way to test this.
 | 
						|
     */
 | 
						|
    fudge = 3 * pGC->lineWidth + 1;
 | 
						|
 | 
						|
    /*
 | 
						|
     * Generate the PCL code to draw the polyline, by defining it as a
 | 
						|
     * macro which uses the HP-GL/2 line drawing function.
 | 
						|
     */
 | 
						|
 | 
						|
    MACRO_START( outFile, pConPriv );
 | 
						|
    SAVE_PCL( outFile, pConPriv, "\033%0B" );
 | 
						|
 | 
						|
    sprintf( t, "PU%d,%dPD\n", pPoints[0].x + pDrawable->x,
 | 
						|
	    pPoints[0].y + pDrawable->y );
 | 
						|
    SAVE_PCL( outFile, pConPriv, t ); /* Move to the start of the polyline */
 | 
						|
 | 
						|
    switch( mode )
 | 
						|
      {
 | 
						|
	case CoordModeOrigin:
 | 
						|
	  xoffset = pDrawable->x;
 | 
						|
	  yoffset = pDrawable->y;
 | 
						|
	  SAVE_PCL( outFile, pConPriv, "PA" );
 | 
						|
	  break;
 | 
						|
	case CoordModePrevious:
 | 
						|
	  xoffset = yoffset = 0;
 | 
						|
	  SAVE_PCL( outFile, pConPriv, "PR" );
 | 
						|
	  break;
 | 
						|
      }
 | 
						|
 | 
						|
    /*
 | 
						|
     * Build the "drawing region" as we build the PCL to draw the
 | 
						|
     * line.
 | 
						|
     */
 | 
						|
    for(i = 1, r = drawRects; i < nPoints; i++, r++ )
 | 
						|
      {
 | 
						|
	  if( i != 1 )
 | 
						|
	    SAVE_PCL( outFile, pConPriv, "," );
 | 
						|
 | 
						|
	  sprintf( t, "%d,%d", pPoints[i].x + xoffset,
 | 
						|
		  pPoints[i].y + yoffset );
 | 
						|
	  SAVE_PCL( outFile, pConPriv, t );
 | 
						|
 | 
						|
	  r->x = MIN( pPoints[i-1].x, pPoints[i].x ) + xoffset - fudge;
 | 
						|
	  r->y = MIN( pPoints[i-1].y, pPoints[i].y ) + yoffset - fudge;
 | 
						|
	  r->width = abs( pPoints[i-1].x - pPoints[i].x ) + 2 * fudge;
 | 
						|
	  r->height = abs( pPoints[i-1].y - pPoints[i].y ) + 2 * fudge;
 | 
						|
      }
 | 
						|
    SAVE_PCL( outFile, pConPriv, ";\033%0A" ); /* End the macro */
 | 
						|
    MACRO_END( outFile );
 | 
						|
 | 
						|
    /*
 | 
						|
     * Convert the collection of rectangles into a proper region, then
 | 
						|
     * intersect it with the clip region.
 | 
						|
     */
 | 
						|
    drawRegion = RECTS_TO_REGION( pGC->pScreen, nPoints - 1,
 | 
						|
				  drawRects, CT_UNSORTED );
 | 
						|
    if( mode == CoordModePrevious )
 | 
						|
      REGION_TRANSLATE( pGC->pScreen, drawRegion, pPoints[0].x, pPoints[0].y );
 | 
						|
    REGION_INTERSECT( pGC->pScreen, region, drawRegion, pGC->pCompositeClip );
 | 
						|
 | 
						|
    /*
 | 
						|
     * For each rectangle in the clip region, set the HP-GL/2 "input
 | 
						|
     * window" and render the entire polyline to it.
 | 
						|
     */
 | 
						|
    pbox = REGION_RECTS( region );
 | 
						|
    nbox = REGION_NUM_RECTS( region );
 | 
						|
 | 
						|
    PclSendData(outFile, pConPriv, pbox, nbox, 1.0);
 | 
						|
 | 
						|
    /*
 | 
						|
     * Clean up the temporary regions
 | 
						|
     */
 | 
						|
    REGION_DESTROY( pGC->pScreen, drawRegion );
 | 
						|
    REGION_DESTROY( pGC->pScreen, region );
 | 
						|
    xfree( drawRects );
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
PclPolySegment(
 | 
						|
     DrawablePtr pDrawable,
 | 
						|
     GCPtr pGC,
 | 
						|
     int nSegments,
 | 
						|
     xSegment *pSegments)
 | 
						|
{
 | 
						|
    FILE *outFile, *dummy;
 | 
						|
    char t[80];
 | 
						|
    int xoffset, yoffset;
 | 
						|
    int nbox, i;
 | 
						|
    unsigned long valid;
 | 
						|
    BoxPtr pbox;
 | 
						|
    xRectangle *drawRects, *r;
 | 
						|
    RegionPtr drawRegion, region;
 | 
						|
    short fudge;
 | 
						|
    XpContextPtr pCon;
 | 
						|
    PclContextPrivPtr pConPriv;
 | 
						|
    GC cacheGC;
 | 
						|
 | 
						|
 | 
						|
    if( PclUpdateDrawableGC( pGC, pDrawable, &outFile ) == FALSE )
 | 
						|
      return;
 | 
						|
 | 
						|
    pCon = PclGetContextFromWindow( (WindowPtr) pDrawable );
 | 
						|
    pConPriv = (PclContextPrivPtr)
 | 
						|
			pCon->devPrivates[PclContextPrivateIndex].ptr;
 | 
						|
 | 
						|
    /*
 | 
						|
     * Allocate the storage for the temporary regions.
 | 
						|
     */
 | 
						|
    region = REGION_CREATE( pGC->pScreen, NULL, 0 );
 | 
						|
    drawRects = (xRectangle *)
 | 
						|
      xalloc( nSegments * sizeof( xRectangle ) );
 | 
						|
 | 
						|
    /*
 | 
						|
     * Calculate the fudge factor, based on the line width
 | 
						|
     */
 | 
						|
    fudge = pGC->lineWidth * 3 + 1;
 | 
						|
 | 
						|
    /*
 | 
						|
     * Turn off line joining.
 | 
						|
     */
 | 
						|
    SEND_PCL( outFile, "\033%0BLA2,6;\033%0A" );
 | 
						|
 | 
						|
    /*
 | 
						|
     * Generate the PCL code to draw the segments, by defining them as
 | 
						|
     * a macro which uses the HP-GL/2 line drawing function.
 | 
						|
     *
 | 
						|
     * XXX I wonder if this should be implemented using the Encoded
 | 
						|
     * XXX Polyline function.  Since I'm only sending it once, it's not
 | 
						|
     * XXX necessarily too important.
 | 
						|
     */
 | 
						|
 | 
						|
    MACRO_START( outFile, pConPriv );
 | 
						|
    SAVE_PCL( outFile, pConPriv, "\033%0B" );
 | 
						|
 | 
						|
    xoffset = pDrawable->x;
 | 
						|
    yoffset = pDrawable->y;
 | 
						|
 | 
						|
    for( i = 0, r = drawRects; i < nSegments; i++, r++ )
 | 
						|
      {
 | 
						|
	  r->x = MIN( pSegments[i].x1, pSegments[i].x2 ) + xoffset;
 | 
						|
	  r->y = MIN( pSegments[i].y1, pSegments[i].y2 ) + yoffset;
 | 
						|
	  r->width = abs( pSegments[i].x1 - pSegments[i].x2 );
 | 
						|
	  r->height = abs( pSegments[i].y1 - pSegments[i].y2 );
 | 
						|
 | 
						|
	  sprintf( t, "PU%d,%d;PD%d,%d;", pSegments[i].x1 + xoffset,
 | 
						|
		  pSegments[i].y1 + yoffset, pSegments[i].x2 +
 | 
						|
		  xoffset, pSegments[i].y2 + yoffset );
 | 
						|
	  SAVE_PCL( outFile, pConPriv, t );
 | 
						|
 | 
						|
	  r->x -= fudge;
 | 
						|
	  r->y -= fudge;
 | 
						|
	  r->width += 2 * fudge;
 | 
						|
	  r->height += 2 * fudge;
 | 
						|
      }
 | 
						|
    SAVE_PCL( outFile, pConPriv, "\033%0A" );
 | 
						|
    MACRO_END ( outFile );
 | 
						|
 | 
						|
    /*
 | 
						|
     * Convert the collection of rectangles into a proper region, then
 | 
						|
     * intersect it with the clip region.
 | 
						|
     */
 | 
						|
    drawRegion = RECTS_TO_REGION( pGC->pScreen, nSegments,
 | 
						|
				  drawRects, CT_UNSORTED );
 | 
						|
    REGION_INTERSECT( pGC->pScreen, region, drawRegion, pGC->pCompositeClip );
 | 
						|
 | 
						|
    /*
 | 
						|
     * For each rectangle in the clip region, set the HP-GL/2 "input
 | 
						|
     * window" and render the entire set of segments to it.
 | 
						|
     */
 | 
						|
    pbox = REGION_RECTS( region );
 | 
						|
    nbox = REGION_NUM_RECTS( region );
 | 
						|
 | 
						|
    PclSendData(outFile, pConPriv, pbox, nbox, 1.0);
 | 
						|
 | 
						|
    /*
 | 
						|
     * Now we need to reset the line join mode to whatever it was at before.
 | 
						|
     * The easiest way is to force the cached GC's joinstyle to be different
 | 
						|
     * from the current GC's joinstyle, then re-update the GC.  This way, we
 | 
						|
     * don't have to duplicate code unnecessarily.
 | 
						|
     */
 | 
						|
    PclGetDrawablePrivateStuff( pDrawable, &cacheGC, &valid, &dummy );
 | 
						|
    cacheGC.joinStyle = !cacheGC.joinStyle;
 | 
						|
    PclSetDrawablePrivateGC( pDrawable, cacheGC );
 | 
						|
    PclUpdateDrawableGC( pGC, pDrawable, &outFile );
 | 
						|
 | 
						|
    /*
 | 
						|
     * Clean up
 | 
						|
     */
 | 
						|
    REGION_DESTROY( pGC->pScreen, drawRegion );
 | 
						|
    REGION_DESTROY( pGC->pScreen, region );
 | 
						|
    xfree( drawRects );
 | 
						|
}
 |