968 lines
23 KiB
C
968 lines
23 KiB
C
|
/*******************************************************************
|
||
|
**
|
||
|
** *********************************************************
|
||
|
** *
|
||
|
** * File: PclGC.c
|
||
|
** *
|
||
|
** * Contents:
|
||
|
** * Graphics Context handling 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 "gcstruct.h"
|
||
|
|
||
|
#include "Pcl.h"
|
||
|
#include "pixmapstr.h"
|
||
|
#include "colormapst.h"
|
||
|
#include "windowstr.h"
|
||
|
#include "fb.h"
|
||
|
#include "scrnintstr.h"
|
||
|
#include "resource.h"
|
||
|
|
||
|
static GCOps PclGCOps =
|
||
|
{
|
||
|
PclFillSpans,
|
||
|
PclSetSpans,
|
||
|
PclPutImage,
|
||
|
PclCopyArea,
|
||
|
PclCopyPlane,
|
||
|
PclPolyPoint,
|
||
|
PclPolyLine,
|
||
|
PclPolySegment,
|
||
|
PclPolyRectangle,
|
||
|
PclPolyArc,
|
||
|
PclFillPolygon,
|
||
|
PclPolyFillRect,
|
||
|
PclPolyFillArc,
|
||
|
PclPolyText8,
|
||
|
PclPolyText16,
|
||
|
PclImageText8,
|
||
|
PclImageText16,
|
||
|
PclImageGlyphBlt,
|
||
|
PclPolyGlyphBlt,
|
||
|
PclPushPixels
|
||
|
}
|
||
|
;
|
||
|
|
||
|
|
||
|
static GCFuncs PclGCFuncs =
|
||
|
{
|
||
|
PclValidateGC,
|
||
|
miChangeGC,
|
||
|
miCopyGC,
|
||
|
PclDestroyGC,
|
||
|
miChangeClip,
|
||
|
miDestroyClip,
|
||
|
miCopyClip,
|
||
|
}
|
||
|
;
|
||
|
|
||
|
Bool
|
||
|
PclCreateGC(GCPtr pGC)
|
||
|
{
|
||
|
if (fbCreateGC(pGC) == FALSE)
|
||
|
return FALSE;
|
||
|
|
||
|
pGC->clientClip = NULL;
|
||
|
pGC->clientClipType = CT_NONE;
|
||
|
|
||
|
pGC->ops = &PclGCOps;
|
||
|
pGC->funcs = &PclGCFuncs;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
PclDestroyGC(GCPtr pGC)
|
||
|
{
|
||
|
/* fb doesn't specialize DestroyGC */
|
||
|
miDestroyGC( pGC );
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
PclGetDrawablePrivateStuff(
|
||
|
DrawablePtr pDrawable,
|
||
|
GC *gc,
|
||
|
unsigned long *valid,
|
||
|
FILE **file)
|
||
|
{
|
||
|
XpContextPtr pCon;
|
||
|
PclContextPrivPtr cPriv;
|
||
|
|
||
|
switch( pDrawable->type )
|
||
|
{
|
||
|
case DRAWABLE_PIXMAP:
|
||
|
/*
|
||
|
* If we ever get here, something is wrong.
|
||
|
*/
|
||
|
return FALSE;
|
||
|
|
||
|
case DRAWABLE_WINDOW:
|
||
|
pCon = PclGetContextFromWindow( (WindowPtr)pDrawable );
|
||
|
|
||
|
if( pCon == NULL )
|
||
|
return FALSE;
|
||
|
else
|
||
|
{
|
||
|
cPriv = pCon->devPrivates[PclContextPrivateIndex].ptr;
|
||
|
*gc = cPriv->lastGC;
|
||
|
*valid = cPriv->validGC;
|
||
|
*file = cPriv->pPageFile;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
PclSetDrawablePrivateGC(
|
||
|
DrawablePtr pDrawable,
|
||
|
GC gc)
|
||
|
{
|
||
|
PixmapPtr pix;
|
||
|
XpContextPtr pCon;
|
||
|
PclPixmapPrivPtr pixPriv;
|
||
|
PclContextPrivPtr pPriv;
|
||
|
int i;
|
||
|
|
||
|
switch( pDrawable->type )
|
||
|
{
|
||
|
case DRAWABLE_PIXMAP:
|
||
|
pix = (PixmapPtr)pDrawable;
|
||
|
pixPriv = pix->devPrivates[PclPixmapPrivateIndex].ptr;
|
||
|
|
||
|
pixPriv->lastGC = gc;
|
||
|
pixPriv->validGC = 1;
|
||
|
break;
|
||
|
|
||
|
case DRAWABLE_WINDOW:
|
||
|
pCon = PclGetContextFromWindow( (WindowPtr)pDrawable );
|
||
|
pPriv = ((PclContextPrivPtr)
|
||
|
(pCon->devPrivates[PclContextPrivateIndex].ptr));
|
||
|
|
||
|
pPriv->validGC = 1;
|
||
|
pPriv->lastGC = gc;
|
||
|
|
||
|
/*
|
||
|
* Store the dash list separately, to avoid having it freed
|
||
|
* out from under us.
|
||
|
*/
|
||
|
if( pPriv->dash != NULL )
|
||
|
xfree( pPriv->dash );
|
||
|
if( gc.numInDashList != 0 )
|
||
|
{
|
||
|
pPriv->dash = (unsigned char *)xalloc( sizeof( unsigned char )
|
||
|
* gc.numInDashList );
|
||
|
for( i = 0; i < gc.numInDashList; i++ )
|
||
|
pPriv->dash[i] = gc.dash[i];
|
||
|
}
|
||
|
else
|
||
|
pPriv->dash = NULL;
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Store the dash list separately, to avoid having it freed
|
||
|
* out from under us.
|
||
|
*/
|
||
|
if( pPriv->dash != NULL )
|
||
|
xfree( pPriv->dash );
|
||
|
if( gc.numInDashList != 0 )
|
||
|
{
|
||
|
pPriv->dash = (unsigned char *)xalloc( sizeof( unsigned char )
|
||
|
* gc.numInDashList );
|
||
|
for( i = 0; i < gc.numInDashList; i++ )
|
||
|
pPriv->dash[i] = gc.dash[i];
|
||
|
}
|
||
|
else
|
||
|
pPriv->dash = NULL;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
PclSendPattern(char *bits,
|
||
|
int sz,
|
||
|
int depth,
|
||
|
int h,
|
||
|
int w,
|
||
|
int patNum,
|
||
|
FILE *outFile)
|
||
|
{
|
||
|
char t[80], *row, *mod;
|
||
|
int w2;
|
||
|
int i, j;
|
||
|
|
||
|
SEND_PCL( outFile, "\033%0A" );
|
||
|
|
||
|
if( depth == 1 )
|
||
|
{
|
||
|
/* Each row must be word-aligned */
|
||
|
w2 = ( w / 8 ) + ( ( w%8 ) ? 1 : 0 );
|
||
|
/*
|
||
|
if( w2 % 2 )
|
||
|
w2++;
|
||
|
*/
|
||
|
|
||
|
sprintf( t, "\033*c%dg%dW", patNum, h * w2 + 8 );
|
||
|
SEND_PCL( outFile, t );
|
||
|
|
||
|
sprintf( t, "%c%c%c%c%c%c%c%c", 0, 0, 1, 0, h>>8, h&0xff, w>>8,
|
||
|
w&0xff );
|
||
|
SEND_PCL_COUNT( outFile, t, 8 );
|
||
|
|
||
|
for( row = bits, i = 0; i < h; i++, row += BitmapBytePad( w ) )
|
||
|
SEND_PCL_COUNT( outFile, row, w2 );
|
||
|
}
|
||
|
else if( depth == 8 )
|
||
|
{
|
||
|
w2 = ( w % 2 ) ? w + 1 : w;
|
||
|
|
||
|
sprintf( t, "\033*c%dg%dW", patNum, h * w2 + 8 );
|
||
|
SEND_PCL( outFile, t );
|
||
|
|
||
|
sprintf( t, "%c%c%c%c%c%c%c%c", 1, 0, 8, 0, h>>8, h&0xff,
|
||
|
w>>8, w&0xff );
|
||
|
SEND_PCL_COUNT( outFile, t, 8 );
|
||
|
|
||
|
for( row = bits, i = 0; i < h; i++,
|
||
|
row += PixmapBytePad( w, 8 ) )
|
||
|
SEND_PCL_COUNT( outFile, row, w2 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
w2 = ( w % 2 ) ? w + 1 : w;
|
||
|
|
||
|
sprintf( t, "\033*c%dg%dW", patNum, h * w2 + 8 );
|
||
|
SEND_PCL( outFile, t );
|
||
|
|
||
|
sprintf( t, "%c%c%c%c%c%c%c%c", 1, 0, 8, 0, h>>8, h&0xff,
|
||
|
w>>8, w&0xff );
|
||
|
SEND_PCL_COUNT( outFile, t, 8 );
|
||
|
|
||
|
mod = (char *)xalloc( w2 );
|
||
|
|
||
|
for( row = bits, i = 0; i < h; i++,
|
||
|
row += PixmapBytePad( w, 24 ) )
|
||
|
{
|
||
|
char r, g, b;
|
||
|
for( j = 0; j < w2; j++ ) {
|
||
|
r = ((row[j*4+1] >> 5) & 0x7) << 5;
|
||
|
g = ((row[j*4+2] >> 5) & 0x7) << 2;
|
||
|
b = ((row[j*4+3] >> 6) & 0x3);
|
||
|
mod[j] = r | g | b;
|
||
|
}
|
||
|
SEND_PCL_COUNT( outFile, mod, w2 );
|
||
|
}
|
||
|
|
||
|
xfree( mod );
|
||
|
}
|
||
|
|
||
|
SEND_PCL( outFile, "\033%0B" );
|
||
|
}
|
||
|
|
||
|
int
|
||
|
PclUpdateDrawableGC(
|
||
|
GCPtr pGC,
|
||
|
DrawablePtr pDrawable,
|
||
|
FILE **outFile)
|
||
|
{
|
||
|
Mask changeMask = 0;
|
||
|
GC dGC;
|
||
|
unsigned long valid;
|
||
|
int i;
|
||
|
XpContextPtr pCon;
|
||
|
PclContextPrivPtr cPriv;
|
||
|
PclGCPrivPtr gcPriv = (PclGCPrivPtr)
|
||
|
(pGC->devPrivates[PclGCPrivateIndex].ptr);
|
||
|
|
||
|
if( !PclGetDrawablePrivateStuff( pDrawable, &dGC, &valid, outFile ) )
|
||
|
return FALSE;
|
||
|
|
||
|
pCon = PclGetContextFromWindow( (WindowPtr)pDrawable );
|
||
|
cPriv = pCon->devPrivates[PclContextPrivateIndex].ptr;
|
||
|
|
||
|
/*
|
||
|
* Here's where we update the colormap. Since there can be
|
||
|
* different colormaps installed on each window, we need to check
|
||
|
* before each drawing request that the correct palette is active in
|
||
|
* the printer. This is as good a place as any.
|
||
|
*/
|
||
|
if( !PclUpdateColormap( pDrawable, pCon, pGC, *outFile ) )
|
||
|
return FALSE;
|
||
|
|
||
|
/*
|
||
|
* If the drawable's last GC is NULL, this means that this is
|
||
|
* the first time the drawable is being used. Therefore, we need
|
||
|
* to emit PCL for all the GC fields.
|
||
|
*/
|
||
|
if( valid == 0 )
|
||
|
changeMask = ~0;
|
||
|
|
||
|
/*
|
||
|
* If we have two different GC structures, there is no alternative
|
||
|
* but to scan through them both to determine the changeMask.
|
||
|
*/
|
||
|
else
|
||
|
{
|
||
|
if( dGC.alu != pGC->alu )
|
||
|
changeMask |= GCFunction;
|
||
|
if( dGC.fgPixel != pGC->fgPixel )
|
||
|
changeMask |= GCForeground;
|
||
|
if( dGC.bgPixel != pGC->bgPixel )
|
||
|
changeMask |= GCBackground;
|
||
|
if( dGC.lineWidth != pGC->lineWidth )
|
||
|
changeMask |= GCLineWidth;
|
||
|
if( dGC.lineStyle != pGC->lineStyle )
|
||
|
changeMask |= GCLineStyle;
|
||
|
if( dGC.capStyle != pGC->capStyle )
|
||
|
changeMask |= GCCapStyle;
|
||
|
if( dGC.joinStyle != pGC->joinStyle )
|
||
|
changeMask |= GCJoinStyle;
|
||
|
if( dGC.fillStyle != pGC->fillStyle )
|
||
|
changeMask |= GCFillStyle;
|
||
|
if( dGC.tile.pixmap != pGC->tile.pixmap )
|
||
|
changeMask |= GCTile;
|
||
|
if( dGC.stipple != pGC->stipple )
|
||
|
changeMask |= GCStipple;
|
||
|
if( dGC.patOrg.x != pGC->patOrg.x )
|
||
|
changeMask |= GCTileStipXOrigin;
|
||
|
if( dGC.patOrg.y != pGC->patOrg.y )
|
||
|
changeMask |= GCTileStipYOrigin;
|
||
|
|
||
|
if( dGC.numInDashList == pGC->numInDashList )
|
||
|
{
|
||
|
for( i = 0; i < dGC.numInDashList; i++ )
|
||
|
if( cPriv->dash[i] != pGC->dash[i] )
|
||
|
{
|
||
|
changeMask |= GCDashList;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
changeMask |= GCDashList;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Once the changeMask has been determined, we scan it and emit
|
||
|
* the appropriate PCL code to set the drawing attributes.
|
||
|
*/
|
||
|
|
||
|
/* Must be in HP-GL/2 mode to set attributes */
|
||
|
SEND_PCL( *outFile, "\033%0B" );
|
||
|
|
||
|
if( changeMask & GCFunction )
|
||
|
{
|
||
|
#ifdef XP_PCL_COLOR
|
||
|
|
||
|
if( pGC->alu == GXclear )
|
||
|
SEND_PCL( *outFile, "SP0;" );
|
||
|
else
|
||
|
SEND_PCL( *outFile, "SP1;" );
|
||
|
#else
|
||
|
if( pGC->alu == GXclear )
|
||
|
SEND_PCL( *outFile, "SP0;" );
|
||
|
else
|
||
|
SEND_PCL( *outFile, "SP1;" );
|
||
|
#endif /* XP_PCL_COLOR */
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
if( changeMask & GCFunction )
|
||
|
{
|
||
|
int rop = -1;
|
||
|
char t[10];
|
||
|
|
||
|
switch( pGC->alu )
|
||
|
{
|
||
|
case GXclear:
|
||
|
rop = 1;
|
||
|
break;
|
||
|
case GXand:
|
||
|
rop = 136;
|
||
|
break;
|
||
|
case GXandReverse:
|
||
|
rop = 68;
|
||
|
break;
|
||
|
case GXcopy:
|
||
|
rop = 204;
|
||
|
break;
|
||
|
case GXandInverted:
|
||
|
rop = 34;
|
||
|
break;
|
||
|
case GXnoop:
|
||
|
rop = 170;
|
||
|
break;
|
||
|
case GXxor:
|
||
|
rop = 238;
|
||
|
break;
|
||
|
case GXor:
|
||
|
rop = 238;
|
||
|
break;
|
||
|
case GXnor:
|
||
|
rop = 17;
|
||
|
break;
|
||
|
case GXequiv:
|
||
|
rop = 153;
|
||
|
break;
|
||
|
case GXinvert:
|
||
|
rop = 85;
|
||
|
break;
|
||
|
case GXorReverse:
|
||
|
rop = 221;
|
||
|
break;
|
||
|
case GXcopyInverted:
|
||
|
rop = 51;
|
||
|
break;
|
||
|
case GXorInverted:
|
||
|
rop = 187;
|
||
|
break;
|
||
|
case GXnand:
|
||
|
rop = 119;
|
||
|
break;
|
||
|
case GXset:
|
||
|
rop = 0;
|
||
|
break;
|
||
|
}
|
||
|
if( rop != -1 )
|
||
|
{
|
||
|
sprintf( t, "MC1,%d;", rop );
|
||
|
SEND_PCL( *outFile, t );
|
||
|
#endif
|
||
|
|
||
|
if( changeMask & GCForeground )
|
||
|
switch( pGC->fgPixel )
|
||
|
{
|
||
|
case 1:
|
||
|
SEND_PCL( *outFile, "SP1;" );
|
||
|
break;
|
||
|
default:
|
||
|
SEND_PCL( *outFile, "SP0;" );
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if( changeMask & GCForeground )
|
||
|
{
|
||
|
#ifdef XP_PCL_COLOR
|
||
|
ColormapPtr cmap;
|
||
|
Colormap c;
|
||
|
char t[40];
|
||
|
|
||
|
c = wColormap( ((WindowPtr)pDrawable) );
|
||
|
cmap = (ColormapPtr)LookupIDByType( c, RT_COLORMAP );
|
||
|
|
||
|
if( cmap->class == TrueColor )
|
||
|
{
|
||
|
if( pGC->fillStyle != FillTiled || pGC->tileIsPixel ) {
|
||
|
unsigned short r, g, b;
|
||
|
|
||
|
r = (pGC->fgPixel & cmap->pVisual->redMask)
|
||
|
>> (cmap->pVisual->offsetRed );
|
||
|
g = (pGC->fgPixel & cmap->pVisual->greenMask)
|
||
|
>> (cmap->pVisual->offsetGreen);
|
||
|
b = (pGC->fgPixel & cmap->pVisual->blueMask)
|
||
|
>> (cmap->pVisual->offsetBlue);
|
||
|
|
||
|
PclLookUp(cmap, cPriv, &r, &g, &b);
|
||
|
sprintf( t, "\033%%0A\033*v%ua%ub%uc0I\033%%0B", r, g, b);
|
||
|
SEND_PCL( *outFile, t );
|
||
|
}
|
||
|
}
|
||
|
else /* PseudoColor or StaticGray */
|
||
|
{
|
||
|
sprintf( t, "SP%ld;", (long) pGC->fgPixel );
|
||
|
SEND_PCL( *outFile, t );
|
||
|
}
|
||
|
#else
|
||
|
ScreenPtr screen;
|
||
|
screen = pDrawable->pScreen;
|
||
|
if ( pGC->fgPixel == screen->whitePixel )
|
||
|
SEND_PCL( *outFile, "SP0;");
|
||
|
else
|
||
|
SEND_PCL( *outFile, "SP1;");
|
||
|
#endif /* XP_PCL_COLOR */
|
||
|
}
|
||
|
|
||
|
if( changeMask & GCJoinStyle )
|
||
|
switch( pGC->joinStyle )
|
||
|
{
|
||
|
case JoinMiter:
|
||
|
SEND_PCL( *outFile, "LA2,1;" );
|
||
|
break;
|
||
|
case JoinRound:
|
||
|
SEND_PCL( *outFile, "LA2,4;" );
|
||
|
break;
|
||
|
case JoinBevel:
|
||
|
SEND_PCL( *outFile, "LA2,5;" );
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if( changeMask & GCCapStyle )
|
||
|
switch( pGC->capStyle )
|
||
|
{
|
||
|
case CapNotLast:
|
||
|
case CapButt:
|
||
|
SEND_PCL( *outFile, "LA1,1;" );
|
||
|
break;
|
||
|
case CapRound:
|
||
|
SEND_PCL( *outFile, "LA1,4;" );
|
||
|
break;
|
||
|
case CapProjecting:
|
||
|
SEND_PCL( *outFile, "LA1,2;" );
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if( changeMask & GCLineWidth )
|
||
|
{
|
||
|
float penWidth, pixelsPerMM;
|
||
|
ScreenPtr screen;
|
||
|
char temp[30];
|
||
|
|
||
|
if( pGC->lineWidth == 0 || pGC->lineWidth == 1 )
|
||
|
/* A pen width of 0.0 mm gives a one-pixel-wide line */
|
||
|
penWidth = 0.0;
|
||
|
else
|
||
|
{
|
||
|
screen = pDrawable->pScreen;
|
||
|
pixelsPerMM = (float)screen->width / (float)screen->mmWidth;
|
||
|
|
||
|
penWidth = pGC->lineWidth / pixelsPerMM;
|
||
|
}
|
||
|
sprintf( temp, "PW%g;", penWidth );
|
||
|
SEND_PCL( *outFile, temp );
|
||
|
}
|
||
|
|
||
|
if( changeMask & GCLineStyle )
|
||
|
{
|
||
|
int i, num = pGC->numInDashList;
|
||
|
double total;
|
||
|
char t[30];
|
||
|
|
||
|
switch( pGC->lineStyle )
|
||
|
{
|
||
|
case LineSolid:
|
||
|
SEND_PCL( *outFile, "LT;" );
|
||
|
break;
|
||
|
case LineOnOffDash:
|
||
|
/*
|
||
|
* Calculate the pattern length of the dashes, in pixels,
|
||
|
* then convert to mm
|
||
|
*/
|
||
|
for( i = 0, total = 0.0; i < 20 && i < num; i++ )
|
||
|
total += pGC->dash[i];
|
||
|
if( num % 2 )
|
||
|
for( i = num; i < 20 && i < num + num; i++ )
|
||
|
total += pGC->dash[i-num];
|
||
|
|
||
|
total *= ( (double)pDrawable->pScreen->mmWidth /
|
||
|
(double)pDrawable->pScreen->width );
|
||
|
|
||
|
sprintf( t, "LT8,%f,1;", total );
|
||
|
SEND_PCL( *outFile, t );
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if( changeMask & GCFillStyle )
|
||
|
switch( pGC->fillStyle )
|
||
|
{
|
||
|
case FillSolid:
|
||
|
SEND_PCL( *outFile, "FT1;TR0;CF;" );
|
||
|
break;
|
||
|
case FillTiled:
|
||
|
SEND_PCL( *outFile, "FT22,100;TR0;CF2,0;" );
|
||
|
break;
|
||
|
case FillOpaqueStippled:
|
||
|
SEND_PCL( *outFile, "FT22,101;TR0;CF2,0;" );
|
||
|
if( pGC->fgPixel != gcPriv->stippleFg ||
|
||
|
pGC->bgPixel != gcPriv->stippleBg )
|
||
|
changeMask |= GCStipple;
|
||
|
break;
|
||
|
case FillStippled:
|
||
|
SEND_PCL( *outFile, "FT22,102;TR1;CF2,0;" );
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if( changeMask & GCTile && !pGC->tileIsPixel )
|
||
|
{
|
||
|
char *bits;
|
||
|
int h, w, sz;
|
||
|
|
||
|
h = pGC->tile.pixmap->drawable.height;
|
||
|
w = pGC->tile.pixmap->drawable.width;
|
||
|
|
||
|
sz = h * PixmapBytePad(w, pGC->tile.pixmap->drawable.depth);
|
||
|
bits = (char *)xalloc(sz);
|
||
|
fbGetImage(&(pGC->tile.pixmap->drawable), 0, 0, w, h, XYPixmap, ~0,
|
||
|
bits);
|
||
|
PclSendPattern( bits, sz, 1, h, w, 100, *outFile );
|
||
|
xfree( bits );
|
||
|
}
|
||
|
|
||
|
if( changeMask & ( GCTileStipXOrigin | GCTileStipYOrigin ) )
|
||
|
{
|
||
|
char t[30];
|
||
|
|
||
|
sprintf( t, "AC%d,%d;", pGC->patOrg.x, pGC->patOrg.y );
|
||
|
SEND_PCL( *outFile, t );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* We have to resend the stipple pattern either when the stipple itself
|
||
|
* changes, or if we're in FillOpaqueStippled mode and either the
|
||
|
* foreground or the background color changes.
|
||
|
*/
|
||
|
if( changeMask & GCStipple ||
|
||
|
( pGC->fillStyle == FillOpaqueStippled &&
|
||
|
( pGC->fgPixel != gcPriv->stippleFg ||
|
||
|
pGC->bgPixel != gcPriv->stippleBg ) ) )
|
||
|
{
|
||
|
int h, w, i, sz, w2;
|
||
|
char *bits, *row, t[30];
|
||
|
PixmapPtr scratchPix;
|
||
|
GCPtr scratchGC;
|
||
|
|
||
|
if( pGC->stipple != NULL )
|
||
|
{
|
||
|
SEND_PCL( *outFile, "\033%0A" );
|
||
|
|
||
|
h = pGC->stipple->drawable.height;
|
||
|
w = pGC->stipple->drawable.width;
|
||
|
sz = h * BitmapBytePad( w );
|
||
|
|
||
|
bits = (char *)xalloc( sz );
|
||
|
fbGetImage( &(pGC->stipple->drawable), 0, 0, w, h, XYPixmap, ~0, bits );
|
||
|
|
||
|
w2 = ( w / 8 ) + ( ( w%8 ) ? 1 : 0 );
|
||
|
/*
|
||
|
* XXX The PCL docs say that I need to word-align each
|
||
|
* XXX row, but I get garbage when I do...
|
||
|
*/
|
||
|
/*
|
||
|
if( w2 % 2 )
|
||
|
w2++;
|
||
|
*/
|
||
|
|
||
|
sprintf( t, "\033*c102g%dW", h * w2 + 8 );
|
||
|
SEND_PCL( *outFile, t );
|
||
|
|
||
|
sprintf( t, "%c%c%c%c%c%c%c%c", 0, 0, 1, 0, h>>8, h&0xff, w>>8,
|
||
|
w&0xff );
|
||
|
SEND_PCL_COUNT( *outFile, t, 8 );
|
||
|
|
||
|
for( row = bits, i = 0; i < h; i++, row += BitmapBytePad( w ) )
|
||
|
SEND_PCL_COUNT( *outFile, row, w2 );
|
||
|
|
||
|
SEND_PCL( *outFile, "\033%0B" );
|
||
|
|
||
|
xfree( bits );
|
||
|
|
||
|
/*
|
||
|
* Also do the opaque stipple, as a tile
|
||
|
*/
|
||
|
if( pGC->depth != 1 )
|
||
|
sz = h * PixmapBytePad( w, pGC->depth );
|
||
|
bits = (char *)xalloc( sz );
|
||
|
|
||
|
scratchPix =
|
||
|
(*pGC->pScreen->CreatePixmap)( pGC->pScreen,
|
||
|
w, h, pGC->depth );
|
||
|
scratchGC = GetScratchGC( pGC->depth, pGC->pScreen );
|
||
|
CopyGC( pGC, scratchGC, ~0L );
|
||
|
|
||
|
fbValidateGC(scratchGC, ~0L, (DrawablePtr)scratchPix);
|
||
|
fbCopyPlane(&(pGC->stipple->drawable), (DrawablePtr)scratchPix,
|
||
|
scratchGC, 0, 0, w, h, 0, 0, 1);
|
||
|
fbGetImage(&(scratchPix->drawable), 0, 0, w, h, XYPixmap, ~0,
|
||
|
bits);
|
||
|
PclSendPattern( bits, sz, pGC->depth, h, w, 101, *outFile );
|
||
|
FreeScratchGC( scratchGC );
|
||
|
(*pGC->pScreen->DestroyPixmap)( scratchPix );
|
||
|
xfree( bits );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( changeMask & ( GCTileStipXOrigin | GCTileStipYOrigin ) )
|
||
|
{
|
||
|
char t[30];
|
||
|
|
||
|
sprintf( t, "AC%d,%d;", pGC->patOrg.x, pGC->patOrg.y );
|
||
|
SEND_PCL( *outFile, t );
|
||
|
}
|
||
|
|
||
|
if( changeMask & GCDashList )
|
||
|
{
|
||
|
int num = pGC->numInDashList;
|
||
|
double total;
|
||
|
char dashes[20];
|
||
|
char t[100], t2[20];
|
||
|
|
||
|
/* Make up the doubled dash list, if necessary */
|
||
|
for( i = 0; i < 20 && i < num; i++ )
|
||
|
dashes[i] = pGC->dash[i];
|
||
|
|
||
|
if( num % 2 )
|
||
|
{
|
||
|
for( i = num; i < 20 && i < num + num; i++ )
|
||
|
dashes[i] = dashes[i-num];
|
||
|
if( ( num *= 2 ) > 20 )
|
||
|
num = 20;
|
||
|
}
|
||
|
|
||
|
/* Add up dash lengths to get percentage */
|
||
|
for( i = 0, total = 0; i < num; i++ )
|
||
|
total += dashes[i];
|
||
|
|
||
|
/* Build up the HP-GL/2 for the dash list */
|
||
|
strcpy( t, "UL8" );
|
||
|
for( i = 0; i < num; i++ )
|
||
|
{
|
||
|
sprintf( t2, ",%d",
|
||
|
(int)( ( (double)dashes[i] / total * 100.0 ) + 0.5 ) );
|
||
|
strcat( t, t2 );
|
||
|
}
|
||
|
strcat( t, ";" );
|
||
|
SEND_PCL( *outFile, t );
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Go back to PCL mode */
|
||
|
SEND_PCL( *outFile, "\033%0A" );
|
||
|
|
||
|
/*
|
||
|
* Update the drawable's private information, which includes
|
||
|
* erasing the drawable's private changeMask, since all the
|
||
|
* changes have been made.
|
||
|
*/
|
||
|
if( changeMask )
|
||
|
PclSetDrawablePrivateGC( pDrawable, *pGC );
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* PclComputeCompositeClip()
|
||
|
*
|
||
|
* I'd like to use the miComputeCompositeClip function, but it sticks
|
||
|
* things into the mi GC privates, where the PCL driver can't get at
|
||
|
* it. So, rather than mess around with the mi code, I ripped it out
|
||
|
* and made the appropriate changes here.
|
||
|
*/
|
||
|
|
||
|
|
||
|
void
|
||
|
PclComputeCompositeClip(
|
||
|
GCPtr pGC,
|
||
|
DrawablePtr pDrawable)
|
||
|
{
|
||
|
if (pDrawable->type == DRAWABLE_WINDOW)
|
||
|
{
|
||
|
WindowPtr pWin = (WindowPtr) pDrawable;
|
||
|
RegionPtr pregWin;
|
||
|
Bool freeTmpClip, freeCompClip;
|
||
|
|
||
|
if (pGC->subWindowMode == IncludeInferiors)
|
||
|
{
|
||
|
pregWin = NotClippedByChildren(pWin);
|
||
|
freeTmpClip = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pregWin = &pWin->clipList;
|
||
|
freeTmpClip = FALSE;
|
||
|
}
|
||
|
freeCompClip = pGC->freeCompClip;
|
||
|
|
||
|
/*
|
||
|
* if there is no client clip, we can get by with just keeping the
|
||
|
* pointer we got, and remembering whether or not should destroy (or
|
||
|
* maybe re-use) it later. this way, we avoid unnecessary copying of
|
||
|
* regions. (this wins especially if many clients clip by children
|
||
|
* and have no client clip.)
|
||
|
*/
|
||
|
if (pGC->clientClipType == CT_NONE)
|
||
|
{
|
||
|
if (freeCompClip)
|
||
|
REGION_DESTROY(pGC->pScreen, pGC->pCompositeClip);
|
||
|
pGC->pCompositeClip = pregWin;
|
||
|
pGC->freeCompClip = freeTmpClip;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/*
|
||
|
* we need one 'real' region to put into the composite clip. if
|
||
|
* pregWin the current composite clip are real, we can get rid of
|
||
|
* one. if pregWin is real and the current composite clip isn't,
|
||
|
* use pregWin for the composite clip. if the current composite
|
||
|
* clip is real and pregWin isn't, use the current composite
|
||
|
* clip. if neither is real, create a new region.
|
||
|
*/
|
||
|
|
||
|
REGION_TRANSLATE(pGC->pScreen, pGC->clientClip,
|
||
|
pDrawable->x + pGC->clipOrg.x,
|
||
|
pDrawable->y + pGC->clipOrg.y);
|
||
|
|
||
|
if (freeCompClip)
|
||
|
{
|
||
|
REGION_INTERSECT(pGC->pScreen, pGC->pCompositeClip,
|
||
|
pregWin, pGC->clientClip);
|
||
|
if (freeTmpClip)
|
||
|
REGION_DESTROY(pGC->pScreen, pregWin);
|
||
|
}
|
||
|
else if (freeTmpClip)
|
||
|
{
|
||
|
REGION_INTERSECT(pGC->pScreen, pregWin, pregWin,
|
||
|
pGC->clientClip);
|
||
|
pGC->pCompositeClip = pregWin;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pGC->pCompositeClip = REGION_CREATE(pGC->pScreen, NullBox, 0);
|
||
|
REGION_INTERSECT(pGC->pScreen, pGC->pCompositeClip,
|
||
|
pregWin, pGC->clientClip);
|
||
|
}
|
||
|
pGC->freeCompClip = TRUE;
|
||
|
REGION_TRANSLATE(pGC->pScreen, pGC->clientClip,
|
||
|
-(pDrawable->x + pGC->clipOrg.x),
|
||
|
-(pDrawable->y + pGC->clipOrg.y));
|
||
|
}
|
||
|
} /* end of composite clip for a window */
|
||
|
else
|
||
|
{
|
||
|
BoxRec pixbounds;
|
||
|
|
||
|
/* XXX should we translate by drawable.x/y here ? */
|
||
|
pixbounds.x1 = 0;
|
||
|
pixbounds.y1 = 0;
|
||
|
pixbounds.x2 = pDrawable->width;
|
||
|
pixbounds.y2 = pDrawable->height;
|
||
|
|
||
|
if (pGC->freeCompClip)
|
||
|
{
|
||
|
REGION_RESET(pGC->pScreen, pGC->pCompositeClip, &pixbounds);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pGC->freeCompClip = TRUE;
|
||
|
pGC->pCompositeClip = REGION_CREATE(pGC->pScreen, &pixbounds, 1);
|
||
|
}
|
||
|
|
||
|
if (pGC->clientClipType == CT_REGION)
|
||
|
{
|
||
|
REGION_TRANSLATE(pGC->pScreen, pGC->pCompositeClip,
|
||
|
-pGC->clipOrg.x, -pGC->clipOrg.y);
|
||
|
REGION_INTERSECT(pGC->pScreen, pGC->pCompositeClip,
|
||
|
pGC->pCompositeClip, pGC->clientClip);
|
||
|
REGION_TRANSLATE(pGC->pScreen, pGC->pCompositeClip,
|
||
|
pGC->clipOrg.x, pGC->clipOrg.y);
|
||
|
}
|
||
|
} /* end of composite clip for pixmap */
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* PclValidateGC()
|
||
|
*
|
||
|
* Unlike many screen GCValidate routines, this function should not need
|
||
|
* to mess with setting the drawing functions. Different drawing
|
||
|
* functions are usually needed to optimize such things as drawing
|
||
|
* wide or dashed lines; this functionality will be handled primarily
|
||
|
* by the printer itself, while the necessary PCL code to set the
|
||
|
* attributes will be done in PclUpdateDrawableGC().
|
||
|
*/
|
||
|
|
||
|
/*ARGSUSED*/
|
||
|
void
|
||
|
PclValidateGC(
|
||
|
GCPtr pGC,
|
||
|
unsigned long changes,
|
||
|
DrawablePtr pDrawable)
|
||
|
{
|
||
|
/*
|
||
|
* Pixmaps should be handled by their respective validation
|
||
|
* functions.
|
||
|
*/
|
||
|
if( pDrawable->type == DRAWABLE_PIXMAP )
|
||
|
{
|
||
|
fbValidateGC(pGC, ~0, pDrawable);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Reset the drawing operations
|
||
|
*/
|
||
|
pGC->ops = &PclGCOps;
|
||
|
|
||
|
/*
|
||
|
* Validate the information, and correct it if necessary.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* If necessary, compute the composite clip region. (Code ripped
|
||
|
* from migc.c)
|
||
|
*/
|
||
|
if ((changes & (GCClipXOrigin|GCClipYOrigin|GCClipMask|GCSubwindowMode)) ||
|
||
|
(pDrawable->serialNumber != (pGC->serialNumber & DRAWABLE_SERIAL_BITS))
|
||
|
)
|
||
|
{
|
||
|
PclComputeCompositeClip(pGC, pDrawable);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* PCL does not directly support the DoubleDash line style, nor is
|
||
|
* there an easy way to simulate it, so we'll just change it to a
|
||
|
* LineOnOffDash, which is supported by PCL.
|
||
|
*/
|
||
|
if( ( changes & GCLineStyle ) && ( pGC->lineStyle == LineDoubleDash ) )
|
||
|
pGC->lineStyle = LineOnOffDash;
|
||
|
|
||
|
/*
|
||
|
* Update the drawable's changeMask to reflect the changes made to the GC.
|
||
|
*/
|
||
|
/*
|
||
|
PclSetDrawablePrivateGC( pDrawable, *pGC, changes );
|
||
|
*/
|
||
|
}
|