437 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			437 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
/*******************************************************************
 | 
						|
**
 | 
						|
**    *********************************************************
 | 
						|
**    *
 | 
						|
**    *  File:		PclArea.c
 | 
						|
**    *
 | 
						|
**    *  Contents:
 | 
						|
**    *                 Image and Area functions for the PCL DDX driver
 | 
						|
**    *
 | 
						|
**    *  Created:	10/23/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 <stdio.h>
 | 
						|
#include <sys/types.h>
 | 
						|
#include <sys/stat.h>
 | 
						|
#include "Pcl.h"
 | 
						|
#include "pixmapstr.h"
 | 
						|
#include "region.h"
 | 
						|
 | 
						|
#include "fb.h"
 | 
						|
 | 
						|
void
 | 
						|
PclPutImage(DrawablePtr pDrawable,
 | 
						|
	    GCPtr pGC,
 | 
						|
	    int depth,
 | 
						|
	    int x,
 | 
						|
	    int y,
 | 
						|
	    int w,
 | 
						|
	    int h,
 | 
						|
	    int leftPad,
 | 
						|
	    int format,
 | 
						|
	    char *pImage)
 | 
						|
{
 | 
						|
    PixmapPtr pPixmap;
 | 
						|
    unsigned long oldFg, oldBg;
 | 
						|
    XID gcv[3];
 | 
						|
    unsigned long oldPlanemask;
 | 
						|
    unsigned long i;
 | 
						|
    long bytesPer;
 | 
						|
 | 
						|
    if( ( w == 0 ) || ( h == 0 ) )
 | 
						|
      return;
 | 
						|
 | 
						|
    if( format != XYPixmap )
 | 
						|
      {
 | 
						|
	  pPixmap = GetScratchPixmapHeader( pDrawable->pScreen,
 | 
						|
					   w+leftPad, h, depth,
 | 
						|
					   BitsPerPixel( depth ),
 | 
						|
					   PixmapBytePad( w + leftPad,
 | 
						|
					   depth ), (pointer)pImage );
 | 
						|
	  if( !pPixmap )
 | 
						|
	    return;
 | 
						|
 | 
						|
	  if( format == ZPixmap )
 | 
						|
	    (void)(*pGC->ops->CopyArea)( (DrawablePtr)pPixmap, pDrawable, pGC,
 | 
						|
				  leftPad, 0, w, h, x, y );
 | 
						|
	  else
 | 
						|
	    (void)(*pGC->ops->CopyPlane)( (DrawablePtr)pPixmap, pDrawable, pGC,
 | 
						|
			 leftPad, 0, w, h, x, y, 1 );
 | 
						|
	  FreeScratchPixmapHeader( pPixmap );
 | 
						|
      }
 | 
						|
    else
 | 
						|
      {
 | 
						|
	  pPixmap = GetScratchPixmapHeader( pDrawable->pScreen,
 | 
						|
					   w+leftPad, h, depth,
 | 
						|
					   BitsPerPixel( depth ),
 | 
						|
					   PixmapBytePad( w + leftPad,
 | 
						|
					   depth ), (pointer)pImage );
 | 
						|
 | 
						|
	  if( !pPixmap )
 | 
						|
	    return;
 | 
						|
 | 
						|
	  depth = pGC->depth;
 | 
						|
	  oldPlanemask = pGC->planemask;
 | 
						|
	  oldFg = pGC->fgPixel;
 | 
						|
	  oldBg = pGC->bgPixel;
 | 
						|
	  gcv[0] = ~0L;
 | 
						|
	  gcv[1] = 0;
 | 
						|
	  DoChangeGC( pGC, GCForeground | GCBackground, gcv, 0 );
 | 
						|
	  bytesPer = (long)h * BitmapBytePad( w + leftPad );
 | 
						|
 | 
						|
	  for( i = 1 << (depth-1); i != 0; i >>= 1, pImage += bytesPer )
 | 
						|
	    {
 | 
						|
		if( i & oldPlanemask )
 | 
						|
		  {
 | 
						|
		      gcv[0] = i;
 | 
						|
		      DoChangeGC( pGC, GCPlaneMask, gcv, 0 );
 | 
						|
		      ValidateGC( pDrawable, pGC );
 | 
						|
		      fbPutImage( (DrawablePtr)pPixmap, pGC, 1, x, y, w, h,
 | 
						|
				  leftPad, XYBitmap, pImage );
 | 
						|
		  }
 | 
						|
	    }
 | 
						|
	  gcv[0] = oldPlanemask;
 | 
						|
	  gcv[1] = oldFg;
 | 
						|
	  gcv[2] = oldBg;
 | 
						|
	  DoChangeGC( pGC, GCPlaneMask | GCForeground | GCBackground,
 | 
						|
		     gcv, 0 );
 | 
						|
 | 
						|
	  PclCopyArea( (DrawablePtr)pPixmap, pDrawable, pGC, leftPad,
 | 
						|
		      0, w, h, x, y );
 | 
						|
	  FreeScratchPixmapHeader( pPixmap );
 | 
						|
      }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * PclMonoPixmapFragment()
 | 
						|
 *
 | 
						|
 * Given a 1-bit-deep pixmap, send the appropriate part of it to the
 | 
						|
 * output file as a PCL raster graphics command.
 | 
						|
 */
 | 
						|
static void
 | 
						|
PclMonoPixmapFragment(FILE *outFile,
 | 
						|
		      PixmapPtr pix,
 | 
						|
		      short x1,
 | 
						|
		      short y1,
 | 
						|
		      short x2,
 | 
						|
		      short y2,
 | 
						|
		      short dstx,
 | 
						|
		      short dsty)
 | 
						|
{
 | 
						|
    char *bits, t[80], *row;
 | 
						|
    int h, w, i;
 | 
						|
 | 
						|
    /*
 | 
						|
     * Create a storage area large enough to hold the entire pixmap,
 | 
						|
     * then use fbGetImage to get the appropriate bits.
 | 
						|
     */
 | 
						|
    h = y2 - y1;
 | 
						|
    w = BitmapBytePad( x2 - x1 );
 | 
						|
 | 
						|
    bits = (char *)xalloc( h * w );
 | 
						|
    fbGetImage( (DrawablePtr)pix, x1, y1, x2 - x1, h,
 | 
						|
		XYPixmap, ~0, bits );
 | 
						|
 | 
						|
    /*
 | 
						|
     * Move the cursor to the appropriate place on the page.  We have
 | 
						|
     * to jump into HP-GL/2 to do this correctly, then go back to PCL
 | 
						|
     * for the actual drawing.
 | 
						|
     */
 | 
						|
    sprintf( t, "\033%%0BPU%d,%d;\033%%1A", dstx, dsty );
 | 
						|
    SEND_PCL( outFile, t );
 | 
						|
 | 
						|
    /*
 | 
						|
     * Now, wrap the raster in the appropriate PCL code.  Right now,
 | 
						|
     * it's going to go down the wire without any compression.  That
 | 
						|
     * will have to be good enough for the sample implementation.
 | 
						|
     */
 | 
						|
    sprintf( t, "\033*t300R\033*r%dT\033*r%dS\033*r1A\033*b0M",
 | 
						|
	    h, x2 - x1 );
 | 
						|
    SEND_PCL( outFile, t );
 | 
						|
 | 
						|
    sprintf( t, "\033*b%dW", w );
 | 
						|
    for( row = bits, i = 0; i <= h; i++, row += w )
 | 
						|
      {
 | 
						|
	  SEND_PCL( outFile, t );
 | 
						|
	  SEND_PCL_COUNT( outFile, row, w );
 | 
						|
      }
 | 
						|
 | 
						|
    SEND_PCL( outFile, "\033*rC" );
 | 
						|
 | 
						|
    /*
 | 
						|
     * Clean things up a bit
 | 
						|
     */
 | 
						|
    xfree( bits );
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
PclColorPixmapFragment(FILE *outFile,
 | 
						|
		       PixmapPtr pix,
 | 
						|
		       short x1,
 | 
						|
		       short y1,
 | 
						|
		       short x2,
 | 
						|
		       short y2,
 | 
						|
		       short dstx,
 | 
						|
		       short dsty)
 | 
						|
{
 | 
						|
    char *bits, t[80], *row;
 | 
						|
    int h, w, i;
 | 
						|
 | 
						|
    /*
 | 
						|
     * Create a storage area large enough to hold the entire pixmap,
 | 
						|
     * then use fbGetImage to get the appropriate bits.
 | 
						|
     */
 | 
						|
    h = y2 - y1;
 | 
						|
    w = PixmapBytePad( x2 - x1, pix->drawable.depth );
 | 
						|
 | 
						|
    bits = (char *)xalloc( h * w );
 | 
						|
    fbGetImage( (DrawablePtr)pix, x1, y1, x2 - x1, h, ZPixmap, ~0, bits );
 | 
						|
 | 
						|
    /*
 | 
						|
     * Move the cursor to the appropriate place on the page.  We have
 | 
						|
     * to jump into HP-GL/2 to do this correctly, then go back to PCL
 | 
						|
     * for the actual drawing.
 | 
						|
     */
 | 
						|
    sprintf( t, "\033%%0BPU%d,%d;\033%%1A", dstx, dsty );
 | 
						|
    SEND_PCL( outFile, t );
 | 
						|
 | 
						|
    /*
 | 
						|
     * Now, wrap the raster in the appropriate PCL code.  Right now,
 | 
						|
     * it's going to go down the wire without any compression.  That
 | 
						|
     * will have to be good enough for the sample implementation.
 | 
						|
     */
 | 
						|
    sprintf( t, "\033*t300R\033*r%dt%ds1A\033*b0M",
 | 
						|
	    h, x2 - x1 );
 | 
						|
    SEND_PCL( outFile, t );
 | 
						|
 | 
						|
    sprintf( t, "\033*b%dW", w );
 | 
						|
    for( row = bits, i = 0; i < h; i++, row += w )
 | 
						|
      {
 | 
						|
	  SEND_PCL( outFile, t );
 | 
						|
	  SEND_PCL_COUNT( outFile, row, w );
 | 
						|
      }
 | 
						|
 | 
						|
    SEND_PCL( outFile, "\033*rC" );
 | 
						|
 | 
						|
    /*
 | 
						|
     * Clean things up a bit
 | 
						|
     */
 | 
						|
    xfree( bits );
 | 
						|
}
 | 
						|
 | 
						|
RegionPtr
 | 
						|
PclCopyArea(DrawablePtr pSrc,
 | 
						|
	    DrawablePtr pDst,
 | 
						|
	    GCPtr pGC,
 | 
						|
	    int srcx,
 | 
						|
	    int srcy,
 | 
						|
	    int width,
 | 
						|
	    int height,
 | 
						|
	    int dstx,
 | 
						|
	    int dsty)
 | 
						|
{
 | 
						|
    PixmapPtr pixSrc = (PixmapPtr)pSrc;
 | 
						|
/*
 | 
						|
    FILE *srcFile;
 | 
						|
    GC srcGC;
 | 
						|
*/
 | 
						|
    FILE *dstFile;
 | 
						|
    GC dstGC;
 | 
						|
    unsigned long valid;
 | 
						|
    RegionPtr drawRegion, region, whole, ret;
 | 
						|
    BoxRec box;
 | 
						|
    BoxPtr prect;
 | 
						|
    int nrect;
 | 
						|
    void (*doFragment)(FILE *, PixmapPtr, short, short, short, short,
 | 
						|
		       short, short );
 | 
						|
 | 
						|
    /*
 | 
						|
     * Since we don't store any information on a per-window basis, we
 | 
						|
     * can't copy from a window.
 | 
						|
     */
 | 
						|
    if( pSrc->type == DRAWABLE_WINDOW )
 | 
						|
      return NULL;
 | 
						|
 | 
						|
    /*
 | 
						|
     * If we're copying from a pixmap to a pixmap, we just use the
 | 
						|
     * fb code to do the work.
 | 
						|
     */
 | 
						|
    if( pDst->type == DRAWABLE_PIXMAP )
 | 
						|
      fbCopyArea( pSrc, pDst, pGC, srcx, srcy, width, height, dstx, dsty );
 | 
						|
 | 
						|
/*
 | 
						|
    PclGetDrawablePrivateStuff( pSrc, &srcGC, &valid, &srcFile );
 | 
						|
*/
 | 
						|
    PclGetDrawablePrivateStuff( pDst, &dstGC, &valid, &dstFile );
 | 
						|
 | 
						|
    /*
 | 
						|
     * If we're copying to a window, we have to do some actual
 | 
						|
     * drawing, instead of just handing it off to fb.  Start
 | 
						|
     * by determining the region that will be drawn.
 | 
						|
     */
 | 
						|
    box.x1 = srcx;
 | 
						|
    box.y1 = srcy;
 | 
						|
    box.x2 = srcx + width;
 | 
						|
    box.y2 = srcy + height;
 | 
						|
    drawRegion = REGION_CREATE( pGC->pScreen, &box, 0 );
 | 
						|
    REGION_TRANSLATE( pGC->pScreen, drawRegion, dstx, dsty );
 | 
						|
 | 
						|
    region = REGION_CREATE( pGC->pScreen, NULL, 0 );
 | 
						|
    REGION_INTERSECT( pGC->pScreen, region, drawRegion, pGC->pCompositeClip );
 | 
						|
 | 
						|
    /*
 | 
						|
     * Now select the operation to be performed on each box in the
 | 
						|
     * region.
 | 
						|
     */
 | 
						|
    if( pSrc->depth == 1 )
 | 
						|
      doFragment = PclMonoPixmapFragment;
 | 
						|
    else
 | 
						|
      doFragment = PclColorPixmapFragment;
 | 
						|
 | 
						|
    /*
 | 
						|
     * Actually draw each section of the bitmap.
 | 
						|
     */
 | 
						|
    nrect = REGION_NUM_RECTS( region );
 | 
						|
    prect = REGION_RECTS( region );
 | 
						|
 | 
						|
    while( nrect )
 | 
						|
      {
 | 
						|
	  (*doFragment)( dstFile, (PixmapPtr)pSrc, prect->x1 - dstx,
 | 
						|
			prect->y1 - dsty, prect->x2 - dstx,
 | 
						|
			prect->y2 - dsty, prect->x1, prect->y1 );
 | 
						|
 | 
						|
	  nrect--;
 | 
						|
	  prect++;
 | 
						|
      }
 | 
						|
 | 
						|
    /*
 | 
						|
     * Update the destination's GC to the source's GC.
 | 
						|
     */
 | 
						|
/*
 | 
						|
    PclSetDrawablePrivateGC( pDst, srcGC );
 | 
						|
*/
 | 
						|
 | 
						|
    /*
 | 
						|
     * Determine the region that needs to be returned.  This is the
 | 
						|
     * region of the source that falls outside the boundary of the
 | 
						|
     * pixmap.
 | 
						|
     */
 | 
						|
    box.x1 = 0;
 | 
						|
    box.y1 = 0;
 | 
						|
    box.x2 = pixSrc->drawable.width;
 | 
						|
    box.y2 = pixSrc->drawable.height;
 | 
						|
    whole = REGION_CREATE( pGC->pScreen, &box, 0 );
 | 
						|
    ret = REGION_CREATE( pGC->pScreen, NULL, 0 );
 | 
						|
 | 
						|
    REGION_TRANSLATE( pGC->pScreen, drawRegion, -dstx, -dsty );
 | 
						|
    REGION_SUBTRACT( pGC->pScreen, ret, drawRegion, whole );
 | 
						|
 | 
						|
    /*
 | 
						|
     * Clean up the regions
 | 
						|
     */
 | 
						|
    REGION_DESTROY( pGC->pScreen, drawRegion );
 | 
						|
    REGION_DESTROY( pGC->pScreen, region );
 | 
						|
    REGION_DESTROY( pGC->pScreen, whole );
 | 
						|
 | 
						|
    if( REGION_NOTEMPTY( pGC->pScreen, ret ) )
 | 
						|
      return ret;
 | 
						|
    else
 | 
						|
      {
 | 
						|
	  REGION_DESTROY( pGC->pScreen, ret );
 | 
						|
	  return NULL;
 | 
						|
      }
 | 
						|
}
 | 
						|
 | 
						|
RegionPtr
 | 
						|
PclCopyPlane(DrawablePtr pSrc,
 | 
						|
	     DrawablePtr pDst,
 | 
						|
	     GCPtr pGC,
 | 
						|
	     int srcx,
 | 
						|
	     int srcy,
 | 
						|
	     int width,
 | 
						|
	     int height,
 | 
						|
	     int dstx,
 | 
						|
	     int dsty,
 | 
						|
	     unsigned long plane)
 | 
						|
{
 | 
						|
    RegionPtr reg;
 | 
						|
    GCPtr scratchGC;
 | 
						|
    PixmapPtr scratchPix;
 | 
						|
 | 
						|
    /*
 | 
						|
     * Since we don't store PCL on a per-window basis, there's no good
 | 
						|
     * way to copy from a window.
 | 
						|
     */
 | 
						|
    if( pSrc->type == DRAWABLE_WINDOW )
 | 
						|
      return NULL;
 | 
						|
 | 
						|
    /* Copying from a pixmap to a pixmap is already implemented by fb. */
 | 
						|
    if( pSrc->type == DRAWABLE_PIXMAP &&
 | 
						|
       pDst->type == DRAWABLE_PIXMAP )
 | 
						|
      fbCopyPlane( pSrc, pDst, pGC, srcx, srcy, width, height,
 | 
						|
                   dstx, dsty, plane );
 | 
						|
 | 
						|
    /*
 | 
						|
     * We can use fbCopyPlane to do the work of grabbing the plane and
 | 
						|
     * converting it to the desired visual.  Once that's done, we already
 | 
						|
     * know how to do a CopyArea.
 | 
						|
     */
 | 
						|
    scratchPix = (*pDst->pScreen->CreatePixmap)( pDst->pScreen, width,
 | 
						|
						height, pDst->depth,
 | 
						|
						CREATE_PIXMAP_USAGE_SCRATCH );
 | 
						|
 | 
						|
    scratchGC = GetScratchGC( pDst->depth, pDst->pScreen );
 | 
						|
    CopyGC( pGC, scratchGC, ~0L );
 | 
						|
 | 
						|
    fbValidateGC( scratchGC, ~0L, (DrawablePtr)scratchPix );
 | 
						|
    fbCopyPlane( pSrc, (DrawablePtr)scratchPix, scratchGC,
 | 
						|
		 srcx, srcy, width, height, 0, 0, plane );
 | 
						|
 | 
						|
    reg = PclCopyArea( (DrawablePtr)scratchPix, pDst, pGC, 0, 0, width,
 | 
						|
		      height, dstx, dsty );
 | 
						|
 | 
						|
    FreeScratchGC( scratchGC );
 | 
						|
 | 
						|
    (*pDst->pScreen->DestroyPixmap)( scratchPix );
 | 
						|
 | 
						|
    return reg;
 | 
						|
}
 |