* Copyright (c) 1991 The Regents of the University of California.
* This code is derived from software contributed to the Computer Systems
* Engineering Group at Lawrence Berkeley Laboratory and to the University
* of California at Berkeley by Jef Poskanzer.
* %sccs.include.redist.c%
* @(#)raster_op.c 7.1 (Berkeley) %G%
* from: $Header: raster_op.c,v 1.22 92/06/17 08:14:44 torek Exp $
* Bitblit routine for raster library.
* This raster-op is machined to exacting tolerances by skilled native
* craftsmen with pride in their work.
* The various cases are broken down like this:
/* CONFIGURE: To save on executable size, you can configure out the seldom-used
** logical operations. With this variable set, the only operations implemented
** are: RAS_SRC, RAS_CLEAR, RAS_SET, RAS_INVERT, RAS_XOR, RAS_INVERTSRC.
#define PARTIAL_LOGICAL_OPS
/* CONFIGURE: bcopy() is supposed to be the ultimately fastest way to move
** bytes, overlapping or not, ignoring the startup cost. Unfortunately
** this is not true on some systems. For example, on a Sun 3 running
** SunOS 3.5, bcopy() is about five times slower than a simple for loop
** on overlapping copies. And on a 4.1.1 SPARC, bcopy() is about 2/3rds
** as fast on backwards overlaps. So, only define this if your bcopy is ok.
/* End of configurable definitions. */
/* Raster-op macros. These encapsulate the switch statements and so make
** the source code 16 times smaller. The pre and pst args are code
** fragments to put before and after the assignment in each case. They
** can be the beginning and end of a loop. If the pst fragment includes a
** masked assignment, for example to handle the left or right edge cases,
** a good optimizing compiler will simplify the boolean expressions very
** nicely - both cc and gcc on the SPARC will do this.
#ifndef PARTIAL_LOGICAL_OPS
#define ROP_DST(op,pre,d,pst) \
#define ROP_DSTCOLOR(op,pre,d,c,pst) \
#define ROP_SRCDST(op,pre,s,d,pst) \
case RAS_NOTSRC_AND_DST: \
case RAS_SRC_AND_NOTDST: \
case RAS_NOTSRC_OR_DST: \
case RAS_SRC_OR_NOTDST: \
#define ROP_SRCDSTCOLOR(op,pre,s,d,c,pst) \
case RAS_NOTSRC_AND_DST: \
case RAS_SRC_AND_NOTDST: \
case RAS_NOTSRC_OR_DST: \
case RAS_SRC_OR_NOTDST: \
#else /*PARTIAL_LOGICAL_OPS*/
#define ROP_DST(op,pre,d,pst) \
#define ROP_DSTCOLOR(op,pre,d,c,pst) \
#define ROP_SRCDST(op,pre,s,d,pst) \
#define ROP_SRCDSTCOLOR(op,pre,s,d,c,pst) \
#endif /*PARTIAL_LOGICAL_OPS*/
static int needsrc
[16] = { 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0 };
/* CLEAR INVERT DST SET */
u_long raster_bitmask
[32] = {
0x80000000, 0x40000000, 0x20000000, 0x10000000,
0x08000000, 0x04000000, 0x02000000, 0x01000000,
0x00800000, 0x00400000, 0x00200000, 0x00100000,
0x00080000, 0x00040000, 0x00020000, 0x00010000,
0x00008000, 0x00004000, 0x00002000, 0x00001000,
0x00000800, 0x00000400, 0x00000200, 0x00000100,
0x00000080, 0x00000040, 0x00000020, 0x00000010,
0x00000008, 0x00000004, 0x00000002, 0x00000001 };
static u_long leftmask
[32] = {
0x00000000, 0x80000000, 0xc0000000, 0xe0000000,
0xf0000000, 0xf8000000, 0xfc000000, 0xfe000000,
0xff000000, 0xff800000, 0xffc00000, 0xffe00000,
0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000,
0xffff0000, 0xffff8000, 0xffffc000, 0xffffe000,
0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00,
0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0,
0xfffffff0, 0xfffffff8, 0xfffffffc, 0xfffffffe };
static u_long rightmask
[32] = {
0x00000000, 0x00000001, 0x00000003, 0x00000007,
0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff };
u_long raster_bitmask
[32] = {
0x00000001, 0x00000002, 0x00000004, 0x00000008,
0x00000010, 0x00000020, 0x00000040, 0x00000080,
0x00000100, 0x00000200, 0x00000400, 0x00000800,
0x00001000, 0x00002000, 0x00004000, 0x00008000,
0x00010000, 0x00020000, 0x00040000, 0x00080000,
0x00100000, 0x00200000, 0x00400000, 0x00800000,
0x01000000, 0x02000000, 0x04000000, 0x08000000,
0x10000000, 0x20000000, 0x40000000, 0x80000000 };
static u_long leftmask
[32] = {
0x00000000, 0x00000001, 0x00000003, 0x00000007,
0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff };
static u_long rightmask
[32] = {
0x00000000, 0x80000000, 0xc0000000, 0xe0000000,
0xf0000000, 0xf8000000, 0xfc000000, 0xfe000000,
0xff000000, 0xff800000, 0xffc00000, 0xffe00000,
0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000,
0xffff0000, 0xffff8000, 0xffffc000, 0xffffe000,
0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00,
0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0,
0xfffffff0, 0xfffffff8, 0xfffffffc, 0xfffffffe };
#endif /*not MSBYTE_FIRST*/
/* (The odd combinations MSBIT+~MSBYTE and ~MSBIT+MSBYTE could be added.) */
static u_long bytemask
[4] = { 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff };
static u_long bytemask
[4] = { 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 };
static int raster_blit();
/* Performs a bitblit. Returns 0 on success, -1 on failure. */
raster_op( dst
, dx
, dy
, w
, h
, rop
, src
, sx
, sy
)
if ( dst
== (struct raster
*) 0 )
return -1; /* no destination */
if ( needsrc
[RAS_GETOP( rop
)] )
if ( src
== (struct raster
*) 0 )
return -1; /* no source */
/* Clip against source. */
if ( sx
+ w
> src
->width
)
if ( sy
+ h
> src
->height
)
if ( dx
+ w
> dst
->width
)
if ( dy
+ h
> dst
->height
)
return 0; /* nothing to do */
return raster_op_noclip( dst
, dx
, dy
, w
, h
, rop
, src
, sx
, sy
);
/* No source necessary - one-operand blit. */
if ( src
!= (struct raster
*) 0 )
return -1; /* unwanted source */
if ( dx
+ w
> dst
->width
)
if ( dy
+ h
> dst
->height
)
return 0; /* nothing to do */
return raster_op_nosrc_noclip( dst
, dx
, dy
, w
, h
, rop
);
/* Semi-public routine to do a bitblit without clipping. Returns 0 on
** success, -1 on failure.
raster_op_noclip( dst
, dx
, dy
, w
, h
, rop
, src
, sx
, sy
)
int srcleftignore
, srcrightignore
, srclongs
;
int dstleftignore
, dstrightignore
, dstlongs
;
srclin1
= RAS_ADDR( src
, sx
, sy
);
dstlin1
= RAS_ADDR( dst
, dx
, dy
);
/* Special-case full-width to full-width copies. */
if ( op
== RAS_SRC
&& src
->width
== w
&& dst
->width
== w
&&
src
->linelongs
== dst
->linelongs
&& src
->linelongs
== w
>> 5 )
(char*) srclin1
, (char*) dstlin1
,
h
* src
->linelongs
* sizeof(u_long
) );
srcleftignore
= ( sx
& 31 );
srclongs
= ( srcleftignore
+ w
+ 31 ) >> 5;
srcrightignore
= ( srclongs
* 32 - w
- srcleftignore
) & 31;
dstleftignore
= ( dx
& 31 );
dstlongs
= ( dstleftignore
+ w
+ 31 ) >> 5;
dstrightignore
= ( dstlongs
* 32 - w
- dstleftignore
) & 31;
src
, srclin1
, srcleftignore
, srcrightignore
, srclongs
,
dst
, dstlin1
, dstleftignore
, dstrightignore
, dstlongs
, h
, op
);
/* One to eight, using the color in the rop. This could
** probably be sped up by handling each four-bit source nybble
** as a group, indexing into a 16-element runtime-constructed
register u_long
* srclong
;
register u_long
* dstlong
;
register u_long color
, dl
;
register int srcbit
, dstbyte
, i
;
color
= RAS_GETCOLOR( rop
);
/* Make 32 bits of color so we can do the ROP without shifting. */
color
|= ( color
<< 24 ) | ( color
<< 16 ) | ( color
<< 8 );
/* Don't have to worry about overlapping blits here. */
srclin1
= RAS_ADDR( src
, sx
, sy
);
srclin2
= srclin1
+ h
* src
->linelongs
;
dstlin1
= RAS_ADDR( dst
, dx
, dy
);
while ( srclin
!= srclin2
)
/* WARNING: this code is KNOWN TO FAIL on Sun 3's / CG2's. */
/*s*/ *srclong
& raster_bitmask
[srcbit
],
/*pst*/ *dstlong
= ( *dstlong
& ~bytemask
[dstbyte
] ) |
( dl
& bytemask
[dstbyte
] );
srclin
+= src
->linelongs
;
dstlin
+= dst
->linelongs
;
/* Eight to eight blit. */
int srcleftignore
, srcrightignore
, srclongs
;
int dstleftignore
, dstrightignore
, dstlongs
;
return -1; /* depth mismatch */
srclin1
= RAS_ADDR( src
, sx
, sy
);
dstlin1
= RAS_ADDR( dst
, dx
, dy
);
/* Special-case full-width to full-width copies. */
if ( op
== RAS_SRC
&& src
->width
== w
&& dst
->width
== w
&&
src
->linelongs
== dst
->linelongs
&& src
->linelongs
== w
>> 2 )
bcopy( (char*) srclin1
, (char*) dstlin1
,
h
* src
->linelongs
* sizeof(u_long
) );
srcleftignore
= ( sx
& 3 ) * 8;
srclongs
= ( srcleftignore
+ w
* 8 + 31 ) >> 5;
srcrightignore
= ( srclongs
* 32 - w
* 8 - srcleftignore
) & 31;
dstleftignore
= ( dx
& 3 ) * 8;
dstlongs
= ( dstleftignore
+ w
* 8 + 31 ) >> 5;
dstrightignore
= ( dstlongs
* 32 - w
* 8 - dstleftignore
) & 31;
src
, srclin1
, srcleftignore
, srcrightignore
, srclongs
,
dst
, dstlin1
, dstleftignore
, dstrightignore
, dstlongs
, h
, op
);
/* Semi-public routine to do a no-src bitblit without clipping. Returns 0
** on success, -1 on failure.
raster_op_nosrc_noclip( dst
, dx
, dy
, w
, h
, rop
)
/* One-bit no-src blit. */
int dstleftignore
, dstrightignore
, dstlongs
;
u_long dl
, lm
, nlm
, rm
, nrm
;
register u_long
* dstlong2
;
register u_long
* dstlong
;
dstlin1
= RAS_ADDR( dst
, dx
, dy
);
/* Special-case full-width clears. */
if ( op
== RAS_CLEAR
&& dst
->width
== w
&& dst
->linelongs
== w
>> 5 )
bzero( (char*) dstlin1
, h
* dst
->linelongs
* sizeof(u_long
) );
dstleftignore
= ( dx
& 31 );
dstlongs
= ( dstleftignore
+ w
+ 31 ) >> 5;
dstrightignore
= ( dstlongs
* 32 - w
- dstleftignore
) & 31;
dstlin2
= dstlin1
+ h
* dst
->linelongs
;
/* It fits into a single longword. */
lm
= leftmask
[dstleftignore
] | rightmask
[dstrightignore
];
while ( dstlin
!= dstlin2
)
/*pst*/ *dstlin
= ( *dstlin
& lm
) | ( dl
& nlm
); )
dstlin
+= dst
->linelongs
;
lm
= leftmask
[dstleftignore
];
rm
= rightmask
[dstrightignore
];
while ( dstlin
!= dstlin2
)
dstlong2
= dstlong
+ dstlongs
;
if ( dstrightignore
!= 0 )
if ( dstleftignore
!= 0 )
/*pst*/ *dstlong
= ( *dstlong
& lm
) | ( dl
& nlm
); )
/*pre*/ while ( dstlong
!= dstlong2
)
if ( dstrightignore
!= 0 )
/*pst*/ *dstlong
= ( dl
& nrm
) | ( *dstlong
& rm
); )
dstlin
+= dst
->linelongs
;
/* Eight-bit no-src blit. */
int dstleftignore
, dstrightignore
, dstlongs
;
u_long dl
, lm
, nlm
, rm
, nrm
;
register u_long
* dstlong2
;
register u_long
* dstlong
;
dstlin1
= RAS_ADDR( dst
, dx
, dy
);
/* Special-case full-width clears. */
if ( op
== RAS_CLEAR
&& dst
->width
== w
&& dst
->linelongs
== w
>> 2 )
bzero( (char*) dstlin1
, h
* dst
->linelongs
* sizeof(u_long
) );
color
= RAS_GETCOLOR( rop
);
/* Make 32 bits of color so we can do the ROP without shifting. */
color
|= ( color
<< 24 ) | ( color
<< 16 ) | ( color
<< 8 );
dstleftignore
= ( dx
& 3 ) * 8;
dstlongs
= ( dstleftignore
+ w
* 8 + 31 ) >> 5;
dstrightignore
= ( dstlongs
* 32 - w
* 8 - dstleftignore
) & 31;
dstlin2
= dstlin1
+ h
* dst
->linelongs
;
/* It fits into a single longword. */
lm
= leftmask
[dstleftignore
] | rightmask
[dstrightignore
];
while ( dstlin
!= dstlin2
)
/*pst*/ *dstlin
= ( *dstlin
& lm
) | ( dl
& nlm
); )
dstlin
+= dst
->linelongs
;
lm
= leftmask
[dstleftignore
];
rm
= rightmask
[dstrightignore
];
while ( dstlin
!= dstlin2
)
dstlong2
= dstlong
+ dstlongs
;
if ( dstrightignore
!= 0 )
if ( dstleftignore
!= 0 )
/*pst*/ *dstlong
= ( *dstlong
& lm
) | ( dl
& nlm
); )
/*pre*/ while ( dstlong
!= dstlong2
)
if ( dstrightignore
!= 0 )
/*pst*/ *dstlong
= ( dl
& nrm
) | ( *dstlong
& rm
); )
dstlin
+= dst
->linelongs
;
/* This is a general bitblit routine, handling overlapping source and
** destination. It's used for both the 1-to-1 and 8-to-8 cases.
raster_blit( src
, srclin1
, srcleftignore
, srcrightignore
, srclongs
, dst
, dstlin1
, dstleftignore
, dstrightignore
, dstlongs
, h
, op
)
int srcleftignore
, srcrightignore
, srclongs
;
int dstleftignore
, dstrightignore
, dstlongs
;
int srclininc
, dstlininc
;
register int prevleftshift
, currrightshift
;
register u_long
* srclong
;
register u_long
* dstlong
;
register u_long
* dstlong2
;
register u_long dl
, lm
, nlm
, rm
, nrm
;
prevleftshift
= ( srcleftignore
- dstleftignore
) & 31;
srclin2
= srclin1
+ h
* src
->linelongs
;
dstlin2
= dstlin1
+ h
* dst
->linelongs
;
srclininc
= src
->linelongs
;
dstlininc
= dst
->linelongs
;
/* Check for overlaps. */
if ( ( dstlin1
>= srclin1
&& dstlin1
< srclin1
+ srclongs
) ||
( srclin1
>= dstlin1
&& srclin1
< dstlin1
+ dstlongs
) )
/* Horizontal overlap. Should we reverse? */
else if ( ( dstlin1
>= srclin1
&& dstlin1
< srclin2
) ||
( srclin1
>= dstlin1
&& srclin1
< dstlin2
) )
/* Vertical overlap. Should we reverse? */
srclin2
= srclin1
- srclininc
;
srclin1
+= ( h
- 1 ) * srclininc
;
dstlin1
+= ( h
- 1 ) * dstlininc
;
if ( prevleftshift
== 0 )
/* The bits line up, no shifting necessary. */
/* It all fits into a single longword. */
lm
= leftmask
[dstleftignore
] | rightmask
[dstrightignore
];
while ( srclin
!= srclin2
)
/*pst*/ *dstlin
= ( *dstlin
& lm
) | ( dl
& nlm
); )
/* Multiple longwords. */
lm
= leftmask
[dstleftignore
];
rm
= rightmask
[dstrightignore
];
while ( srclin
!= srclin2
)
dstlong2
= dstlong
+ dstlongs
;
if ( dstrightignore
!= 0 )
if ( dstleftignore
!= 0 )
/*pst*/ *dstlong
= ( *dstlong
& lm
) | ( dl
& nlm
); )
/*pre*/ while ( dstlong
!= dstlong2
)
if ( dstrightignore
!= 0 )
/*pst*/ *dstlong
= ( dl
& nrm
) | ( *dstlong
& rm
); )
while ( srclin
!= srclin2
)
dstlong2
= dstlong
- dstlongs
;
if ( dstleftignore
!= 0 )
if ( dstrightignore
!= 0 )
/*pst*/ *dstlong
= ( dl
& nrm
) | ( *dstlong
& rm
); )
/*pre*/ while ( dstlong
!= dstlong2
)
if ( dstleftignore
!= 0 )
/*pst*/ *dstlong
= ( *dstlong
& lm
) | ( dl
& nlm
); )
/* General case, with shifting and everything. */
register u_long sl
, prevsl
;
currrightshift
= 32 - prevleftshift
;
if ( srclongs
== 1 && dstlongs
== 1 )
/* It fits into a single longword, with a shift. */
lm
= leftmask
[dstleftignore
] | rightmask
[dstrightignore
];
if ( srcleftignore
> dstleftignore
)
while ( srclin
!= srclin2
)
/*s*/ *srclin
<< prevleftshift
,
/*pst*/ *dstlin
= ( *dstlin
& lm
) | ( dl
& nlm
); )
while ( srclin
!= srclin2
)
/*s*/ *srclin
>> currrightshift
,
/*pst*/ *dstlin
= ( *dstlin
& lm
) | ( dl
& nlm
); )
/* Multiple longwords. */
lm
= leftmask
[dstleftignore
];
rm
= rightmask
[dstrightignore
];
while ( srclin
!= srclin2
)
dstlong2
= dstlong
+ dstlongs
;
if ( srcleftignore
> dstleftignore
)
prevsl
= *srclong
++ << prevleftshift
;
if ( dstrightignore
!= 0 )
if ( dstleftignore
!= 0 )
/*s*/ prevsl
| ( sl
>> currrightshift
),
/*pst*/ *dstlong
= ( *dstlong
& lm
) | ( dl
& nlm
); )
prevsl
= sl
<< prevleftshift
;
/*pre*/ while ( dstlong
!= dstlong2
)
/*s*/ prevsl
| ( sl
>> currrightshift
),
/*pst*/ prevsl
= sl
<< prevleftshift
;
if ( dstrightignore
!= 0 )
/*s*/ prevsl
| ( *srclong
>> currrightshift
),
/*pst*/ *dstlong
= ( dl
& nrm
) | ( *dstlong
& rm
); )
while ( srclin
!= srclin2
)
dstlong2
= dstlong
- dstlongs
;
if ( srcrightignore
> dstrightignore
)
prevsl
= *srclong
-- >> currrightshift
;
if ( dstleftignore
!= 0 )
if ( dstrightignore
!= 0 )
/*s*/ prevsl
| ( sl
<< prevleftshift
),
/*pst*/ *dstlong
= ( dl
& nrm
) | ( *dstlong
& rm
); )
prevsl
= sl
>> currrightshift
;
/*pre*/ while ( dstlong
!= dstlong2
)
/*s*/ prevsl
| ( sl
<< prevleftshift
),
/*pst*/ prevsl
= sl
>> currrightshift
;
if ( dstleftignore
!= 0 )
/*s*/ prevsl
| ( *srclong
<< prevleftshift
),
/*pst*/ *dstlong
= ( *dstlong
& lm
) | ( dl
& nlm
); )