mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
798 lines
21 KiB
798 lines
21 KiB
//--------------------------------------------------------------------------
|
|
//
|
|
// Module Name: PATFILL.C
|
|
//
|
|
// Brief Description: This module contains the PSCRIPT driver's pattern
|
|
// filling routines.
|
|
//
|
|
// Author: Kent Settle (kentse)
|
|
// Created: 12-Dec-1990
|
|
//
|
|
// Copyright (c) 1990 - 1992 Microsoft Corporation
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "pscript.h"
|
|
|
|
//
|
|
// Local function declarations
|
|
//
|
|
|
|
BOOL
|
|
GenerateBrushImage(
|
|
PDEVDATA pdev,
|
|
DEVBRUSH* pBrush,
|
|
LONG orgX,
|
|
LONG orgY
|
|
);
|
|
|
|
VOID vPatfill_Base(PDEVDATA, FLONG, PSRGB *, MIX);
|
|
|
|
//--------------------------------------------------------------------------
|
|
// BOOL ps_patfill(pdev, pso, flFillMethod, pbo, pptlBrushOrg, rop4,
|
|
// prclBound, bInvertPat, bFillPath)
|
|
// PDEVDATA pdev;
|
|
// SURFOBJ *pso;
|
|
// FLONG flFillMethod;
|
|
// BRUSHOBJ *pbo;
|
|
// PPOINTL pptlBrushOrg;
|
|
// ROP4 rop4;
|
|
// RECTL *prclBound;
|
|
// BOOL bInvertPat;
|
|
// BOOL bFillPath; // TRUE if fill path is defined in printer.
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns:
|
|
// This function returns no value.
|
|
//
|
|
// History:
|
|
//
|
|
// 17-Mar-1993 updated -by- Rob Kiesler
|
|
// For non-1BPP pattern brushes, create the target bitmap to be passed
|
|
// to the engine in the same format as the brush pattern.
|
|
// 10-Feb-1993 updated -by- Rob Kiesler
|
|
// Let the PS Interpreter perform tiling of 1BPP Pattern Brushes.
|
|
// 03-May-1991 -by- Kent Settle [kentse]
|
|
// Wrote it.
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL ps_patfill(pdev, pso, flFillMethod, pbo, pptlBrushOrg, rop4,
|
|
prclBound, bInvertPat, bFillPath)
|
|
PDEVDATA pdev;
|
|
SURFOBJ *pso;
|
|
FLONG flFillMethod;
|
|
BRUSHOBJ *pbo;
|
|
PPOINTL pptlBrushOrg;
|
|
ROP4 rop4;
|
|
RECTL *prclBound;
|
|
BOOL bInvertPat;
|
|
BOOL bFillPath; // TRUE if fill path is defined in printer.
|
|
{
|
|
DEVBRUSH *pBrush;
|
|
ULONG iPatternIndex;
|
|
PSRGB *prgb;
|
|
PSRGB *prgbTmp;
|
|
HBITMAP hbmMem;
|
|
SURFOBJ *psoMem;
|
|
RECTL rclFill;
|
|
ULONG ulNextScan;
|
|
ULONG ulWidthBytes;
|
|
BYTE curByte;
|
|
PBYTE pbPat;
|
|
ULONG ulbpp;
|
|
LONG row, hatchsize;
|
|
LONG width, height, orgX, orgY;
|
|
|
|
// just output the solid color if there is one.
|
|
|
|
prgb = (PSRGB *)&pbo->iSolidColor;
|
|
iPatternIndex = HS_DDI_MAX;
|
|
|
|
if (pbo->iSolidColor == NOT_SOLID_COLOR)
|
|
{
|
|
// get the device brush to draw with.
|
|
|
|
pBrush = (DEVBRUSH *)BRUSHOBJ_pvGetRbrush(pbo);
|
|
|
|
if (!pBrush)
|
|
{
|
|
DBGMSG(DBG_LEVEL_WARNING, "Null brush.\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
// get the foreground color.
|
|
|
|
prgb = (PSRGB *)((PBYTE)pBrush + pBrush->offsetXlate +
|
|
sizeof(ULONG));
|
|
|
|
// get the index for the pattern.
|
|
|
|
iPatternIndex = pBrush->iPatIndex;
|
|
}
|
|
|
|
// now handle the different patterns. the PostScript driver handles
|
|
// patterns in the following manner: at DrvEnablePDEV time we created
|
|
// bitmaps for each of the patterns, in the event that someone actually
|
|
// wants to draw with the pattern in a compatible bitmap. assuming
|
|
// someone is not doing something silly like that, we have been called
|
|
// here to handle the pattern filling. at DrvRealizeBrush time, the
|
|
// driver does a lookup in our internal table to determine the pattern
|
|
// index from the bitmap handle (pBrush->iPatIndex). since bltting
|
|
// these patterns would be SLOW, we will draw them in reasonable
|
|
// ways, depeding on the pattern.
|
|
|
|
switch(iPatternIndex) {
|
|
case HS_DDI_MAX:
|
|
ps_setrgbcolor(pdev, prgb);
|
|
ps_fill(pdev, flFillMethod);
|
|
break;
|
|
|
|
case HS_HORIZONTAL:
|
|
case HS_VERTICAL:
|
|
case HS_BDIAGONAL:
|
|
case HS_FDIAGONAL:
|
|
case HS_CROSS:
|
|
case HS_DIAGCROSS:
|
|
|
|
// set the foreground color. check to see if the invert pattern
|
|
// flag is set, and reverse the colors if so.
|
|
|
|
if (bInvertPat)
|
|
{
|
|
prgbTmp = prgb;
|
|
prgb = (PSRGB *)((PBYTE)pBrush + pBrush->offsetXlate);
|
|
}
|
|
|
|
ps_setrgbcolor(pdev, prgb);
|
|
|
|
// if the background is not transparent, save the path, fill the path
|
|
// with the background color, then restore the path.
|
|
|
|
// The background is transparent when rop4 is 0xAAxx.
|
|
|
|
if (((rop4 >> 8) & 0xFF) != 0xAA)
|
|
{
|
|
// this section of code does a gsave, fills the background
|
|
// color, and then a grestore. it does this so that the
|
|
// foreground pattern can then be drawn. TRUE means to do
|
|
// a gsave, not a save command.
|
|
|
|
if (!ps_save(pdev, TRUE, FALSE))
|
|
return(FALSE);
|
|
|
|
if (bInvertPat)
|
|
prgb = prgbTmp;
|
|
else
|
|
prgb = (PSRGB *)((PBYTE)pBrush + pBrush->offsetXlate);
|
|
|
|
ps_setrgbcolor(pdev, prgb);
|
|
ps_fill(pdev, flFillMethod);
|
|
|
|
if (!ps_restore(pdev, TRUE, FALSE))
|
|
return(FALSE);
|
|
}
|
|
|
|
// if the base pattern definitions code has not yet been downloaded
|
|
// to the printer, do it now.
|
|
|
|
if (!(pdev->cgs.dwFlags & CGS_BASEPATSENT)) {
|
|
|
|
if (! bSendPSProcSet(pdev, PSPROC_HATCH)) {
|
|
|
|
DBGERRMSG("bSendPSProcSet");
|
|
return(FALSE);
|
|
}
|
|
|
|
pdev->cgs.dwFlags |= CGS_BASEPATSENT;
|
|
}
|
|
|
|
// we will do a gsave/grestore around the pattern fill. TRUE
|
|
// means to do a gsave, not a save command.
|
|
|
|
if (! ps_save(pdev, TRUE, FALSE))
|
|
return FALSE;
|
|
|
|
//
|
|
// Always use solid line when filling hatch patterns
|
|
//
|
|
|
|
psputs(pdev, "[] 0 setdash\n");
|
|
|
|
// let the printer know which fill method to use.
|
|
|
|
if (flFillMethod & FP_WINDINGMODE) {
|
|
|
|
psprintf(pdev, "clip n ");
|
|
|
|
} else {
|
|
|
|
psprintf(pdev, "eoclip n ");
|
|
}
|
|
|
|
// make sure the linewidth for the patterns is .01 inch.
|
|
|
|
ps_setlinewidth(pdev, PSFX_DEFAULT_LINEWIDTH);
|
|
|
|
//
|
|
// prclBound shouldn't be NULL here
|
|
//
|
|
|
|
ASSERT(prclBound != NULL);
|
|
rclFill = *prclBound;
|
|
|
|
//
|
|
// Enlarge the fill rectangle to be a multiple of fill pattern size
|
|
// Also take brush origin into consideration here
|
|
//
|
|
|
|
if (pptlBrushOrg) {
|
|
|
|
orgX = pptlBrushOrg->x;
|
|
orgY = pptlBrushOrg->y;
|
|
|
|
} else
|
|
orgX = orgY = 0;
|
|
|
|
hatchsize = pdev->dm.dmPublic.dmPrintQuality / 15;
|
|
|
|
rclFill.left -= (hatchsize + (rclFill.left - orgX) % hatchsize) % hatchsize;
|
|
rclFill.top -= (hatchsize + (rclFill.top - orgY) % hatchsize) % hatchsize;
|
|
|
|
width = ((rclFill.right - rclFill.left + hatchsize - 1) / hatchsize) * hatchsize;
|
|
height = ((rclFill.bottom - rclFill.top + hatchsize - 1) / hatchsize) * hatchsize;
|
|
|
|
rclFill.right = rclFill.left + width;
|
|
rclFill.bottom = rclFill.top + height;
|
|
|
|
// output the specific command for each pattern.
|
|
|
|
switch(iPatternIndex) {
|
|
|
|
case HS_HORIZONTAL:
|
|
case HS_VERTICAL:
|
|
case HS_CROSS:
|
|
|
|
//
|
|
// Draw horizontal hatch pattern:
|
|
// increment width left top repeat-count
|
|
//
|
|
|
|
if (iPatternIndex != HS_VERTICAL) {
|
|
|
|
psprintf(pdev, "%d %d %d %d %d htxh ",
|
|
hatchsize,
|
|
width,
|
|
rclFill.left,
|
|
rclFill.top,
|
|
height / hatchsize);
|
|
}
|
|
|
|
//
|
|
// Draw vertical hatch pattern:
|
|
// increment height left top repeat-count
|
|
//
|
|
|
|
if (iPatternIndex != HS_HORIZONTAL) {
|
|
|
|
psprintf(pdev, "%d %d %d %d %d htxv ",
|
|
hatchsize,
|
|
height,
|
|
rclFill.left,
|
|
rclFill.top,
|
|
width / hatchsize);
|
|
}
|
|
break;
|
|
|
|
case HS_BDIAGONAL:
|
|
case HS_FDIAGONAL:
|
|
case HS_DIAGCROSS:
|
|
|
|
//
|
|
// Upward diagonal hatch pattern:
|
|
// increment left top repeat-count
|
|
//
|
|
|
|
if (iPatternIndex != HS_FDIAGONAL) {
|
|
|
|
psprintf(pdev, "%d %d %d %d htxbd ",
|
|
hatchsize,
|
|
rclFill.left,
|
|
rclFill.top,
|
|
(width + height) / hatchsize);
|
|
}
|
|
|
|
//
|
|
// Downward diagonal hatch pattern:
|
|
// increment left bottom repeat-count
|
|
//
|
|
|
|
if (iPatternIndex != HS_BDIAGONAL) {
|
|
|
|
psprintf(pdev, "%d %d %d %d htxfd ",
|
|
hatchsize,
|
|
rclFill.left,
|
|
rclFill.bottom,
|
|
(width + height) / hatchsize);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!ps_restore(pdev, TRUE, FALSE)) return(FALSE);
|
|
|
|
break;
|
|
|
|
default:
|
|
// we have a user defined bitmap pattern. the bitmap
|
|
// can be monochrome or color. the initial method for
|
|
// filling with a bitmap pattern will be as follows:
|
|
//
|
|
// If the bitmap is 1BPP, download the PS pattern
|
|
// tiling procest if neccessary and invoke the "prf"
|
|
// operator which will tile the bitmap pattern into the
|
|
// destination rectangle.
|
|
//
|
|
// If the bitmap is more than 1BPP, see comments below.
|
|
//
|
|
// since we have a user defined pattern, and we will be
|
|
// calling BitBlt to do the work, we want to clip to the
|
|
// path which was defined in DrvCommonPath.
|
|
|
|
// Check if PS utilities are downloaded.
|
|
|
|
if (! (pdev->dwFlags & PDEV_UTILSSENT)) {
|
|
//
|
|
// Download the Adobe PS Utilities Procset.
|
|
//
|
|
psputs(pdev, "/Adobe_WinNT_Driver_Gfx 175 dict dup begin\n");
|
|
|
|
if (! bSendPSProcSet(pdev, PSPROC_UTILS)) {
|
|
|
|
DBGERRMSG("bSendPSProcSet");
|
|
return(FALSE);
|
|
}
|
|
|
|
psputs(pdev, "end def\n");
|
|
psputs(pdev, "[1.000 0 0 1.000 0 0] Adobe_WinNT_Driver_Gfx dup ");
|
|
psputs(pdev, "/initialize get exec\n");
|
|
pdev->dwFlags |= PDEV_UTILSSENT;
|
|
}
|
|
|
|
//
|
|
// Check to see if any of the PS bitmap pattern code
|
|
// has been downloaded.
|
|
//
|
|
if (! (pdev->dwFlags & PDEV_BMPPATSENT)) {
|
|
//
|
|
// Download the Adobe PS Pattern Bitmap Procset.
|
|
//
|
|
psputs(pdev, "Adobe_WinNT_Driver_Gfx begin\n");
|
|
|
|
if (! bSendPSProcSet(pdev, PSPROC_PATTERN)) {
|
|
|
|
DBGERRMSG("bSendPSProcSet");
|
|
return(FALSE);
|
|
}
|
|
psputs(pdev, "end reinitialize\n");
|
|
pdev->dwFlags |= PDEV_BMPPATSENT;
|
|
|
|
}
|
|
|
|
// Calculate brush size and origin
|
|
|
|
width = pBrush->sizlBitmap.cx;
|
|
height = pBrush->sizlBitmap.cy;
|
|
orgX = (width + pptlBrushOrg->x % width) % width;
|
|
orgY = (height + pptlBrushOrg->y % height) % height;
|
|
|
|
//
|
|
// If this is a 1BPP Bitmap Brush, generate PS code
|
|
// to handle it.
|
|
//
|
|
|
|
if (pBrush->iFormat == BMF_1BPP) {
|
|
|
|
// If we're filling the current path,
|
|
// use it as the clip path
|
|
|
|
if (bFillPath) {
|
|
ps_save(pdev, TRUE, FALSE);
|
|
ps_clip(pdev, (BOOL) (flFillMethod & FP_WINDINGMODE));
|
|
}
|
|
|
|
//
|
|
// Compute the destination rectangle extents, and convert
|
|
// to fixed point.
|
|
//
|
|
|
|
psputint(pdev, 4, prclBound->left, prclBound->bottom,
|
|
(prclBound->right - prclBound->left),
|
|
(prclBound->top - prclBound->bottom));
|
|
|
|
//
|
|
// Get the bg color from the pBrush and convert to
|
|
// PS format.
|
|
//
|
|
|
|
prgb = (PSRGB *)((PBYTE)pBrush + pBrush->offsetXlate);
|
|
|
|
psputs(pdev, " [");
|
|
psputfix(pdev, 3,
|
|
LTOPSFX((ULONG)prgb->red) / 255,
|
|
LTOPSFX((ULONG)prgb->green) / 255,
|
|
LTOPSFX((ULONG)prgb->blue) / 255);
|
|
psputs(pdev, " false]");
|
|
|
|
//
|
|
// Get the fg color from the pBrush and convert to
|
|
// PS format.
|
|
//
|
|
|
|
prgb = (PSRGB *)((PBYTE)pBrush + pBrush->offsetXlate +
|
|
sizeof(ULONG));
|
|
|
|
psputs(pdev, " [");
|
|
psputfix(pdev, 3,
|
|
LTOPSFX((ULONG)prgb->red) / 255,
|
|
LTOPSFX((ULONG)prgb->green) / 255,
|
|
LTOPSFX((ULONG)prgb->blue) / 255);
|
|
psputs(pdev, " false] ");
|
|
|
|
//
|
|
// Send down the pattern x and y extents.
|
|
//
|
|
psputint(pdev, 2, pBrush->sizlBitmap.cx, pBrush->sizlBitmap.cy);
|
|
|
|
//
|
|
// Compute the width in bytes of each scanline in the
|
|
// pattern bitmap, rounded to the nearest dword boundary.
|
|
//
|
|
ulWidthBytes = (width + 7) / 8;
|
|
ulNextScan = ((width + 31) / 32) << 2;
|
|
|
|
psputs(pdev," <");
|
|
|
|
// Send brush pattern bitmap. Rotation if necesary
|
|
// to get the correct origin.
|
|
|
|
pbPat = pBrush->ajBits;
|
|
row= (pBrush->flBitmap & BMF_TOPDOWN) ? 0 : height-1;
|
|
|
|
for ( ; ; ) {
|
|
PBYTE pStart, pEnd, pNext;
|
|
BYTE byteVal;
|
|
INT shiftBits;
|
|
|
|
pStart = pbPat + ((row + orgY) % height) * ulNextScan;
|
|
pEnd = pStart + ulWidthBytes;
|
|
pNext = pStart + orgX / 8;
|
|
shiftBits = orgX % 8;
|
|
|
|
do {
|
|
byteVal = *pNext << shiftBits;
|
|
if (++pNext == pEnd)
|
|
pNext = pStart;
|
|
byteVal |= *pNext >> (8-shiftBits);
|
|
psputhex(pdev, 1, &byteVal);
|
|
} while (pNext != pStart);
|
|
|
|
if (pBrush->flBitmap & BMF_TOPDOWN) {
|
|
if (++row >= height) break;
|
|
} else {
|
|
if (row-- <= 0) break;
|
|
}
|
|
}
|
|
|
|
// Close the pattern data array object, and invoke the
|
|
// prf (pattern rect fill) operator.
|
|
psputs(pdev,"> prf\n");
|
|
|
|
// restore the original clip area
|
|
|
|
if (bFillPath)
|
|
ps_restore(pdev, TRUE, FALSE);
|
|
} else {
|
|
|
|
// 10-Mar-1995 -davidx-
|
|
//
|
|
// This branch handles the case where the pattern
|
|
// brush is more than 1 bit-per-pixel. For level 2
|
|
// devices, we send the brush bitmap as PostScript
|
|
// pattern to the printer and then use pattern fill.
|
|
// For level 1 devices, we tile the bounds rect
|
|
// with brush bitmap ourselves.
|
|
//
|
|
|
|
// For level 2, brush origin is always lined up
|
|
// at (0, 0) of the device coordinate space.
|
|
|
|
if (Level2Device(pdev->hppd)) {
|
|
orgX += width - prclBound->left % width;
|
|
orgY += height - prclBound->top % height;
|
|
}
|
|
|
|
//
|
|
// Generate image string and PS proc to draw
|
|
// the brush bitmap
|
|
//
|
|
|
|
if (! GenerateBrushImage(pdev, pBrush, orgX%width, orgY%height))
|
|
return TRUE;
|
|
|
|
//
|
|
// Push other parameters on the stack:
|
|
// left bounds rectangle
|
|
// top
|
|
// right
|
|
// bottom
|
|
// width pattern size
|
|
// height
|
|
// fillMethod true = use odd-even rule
|
|
// false = use zero-winding rule
|
|
// fillPath true = fill current path
|
|
// false = fill rect
|
|
//
|
|
|
|
psputint(pdev, 4,
|
|
prclBound->left,
|
|
prclBound->top,
|
|
prclBound->right,
|
|
prclBound->bottom);
|
|
|
|
psputs(pdev, " ");
|
|
psputint(pdev, 2, width, height);
|
|
|
|
psputs(pdev,
|
|
(flFillMethod & FP_WINDINGMODE) ?
|
|
" false " :
|
|
" true ");
|
|
psputs(pdev, bFillPath ? "true " : "false ");
|
|
|
|
//
|
|
// Invoke PS proc to do the actual filling.
|
|
//
|
|
|
|
psputs(pdev, "pbf\n");
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
GenerateBrushImage(
|
|
PDEVDATA pdev,
|
|
DEVBRUSH* pBrush,
|
|
LONG orgX,
|
|
LONG orgY
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Generate image data string and PS proc to draw the brush
|
|
bitmap image. Use colorimage operator for level 2 devices
|
|
or level 1 devices with color extension. Otherwise,
|
|
convert color bitmap to grayscale and use image operator.
|
|
|
|
Arguments:
|
|
|
|
pdev Pointer to device data.
|
|
pBrush Pointer to realized brush data.
|
|
orgX, orgY
|
|
Brush origin
|
|
|
|
Return Value:
|
|
|
|
TRUE if sucessful
|
|
FALSE otherwise
|
|
|
|
--*/
|
|
|
|
#define EXTRACT_RGB(ul, r, g, b) \
|
|
r = (BYTE) ((ul ) & 0xff), \
|
|
g = (BYTE) ((ul >> 8) & 0xff), \
|
|
b = (BYTE) ((ul >> 16) & 0xff)
|
|
|
|
{
|
|
LONG width, height;
|
|
BOOL useColor;
|
|
ULONG* pColorLUT;
|
|
BYTE* pBitmap;
|
|
int bpp;
|
|
BYTE rgb[3];
|
|
LONG x, y, lineOffset;
|
|
|
|
// Cache a local copy of usefull information
|
|
|
|
width = pBrush->sizlBitmap.cx;
|
|
height = pBrush->sizlBitmap.cy;
|
|
pBitmap = pBrush->ajBits;
|
|
pColorLUT = (ULONG*) ((PBYTE) pBrush + pBrush->offsetXlate);
|
|
|
|
// Determine the format of brush bitmap.
|
|
|
|
switch (pBrush->iFormat) {
|
|
|
|
case BMF_4BPP:
|
|
bpp = 4;
|
|
break;
|
|
|
|
case BMF_8BPP:
|
|
bpp = 8;
|
|
break;
|
|
|
|
case BMF_24BPP:
|
|
bpp = 24;
|
|
break;
|
|
|
|
default:
|
|
|
|
// We don't have enough information here to
|
|
// deal with 16BPP and 32BPP case properly.
|
|
|
|
DBGMSG(DBG_LEVEL_ERROR, "Invalid brush format.\n");
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Calculate offset between consecutive scanlines.
|
|
// Remember scanlines are double-word aligned.
|
|
//
|
|
lineOffset = (((bpp * width) + 31) / 32) * 4;
|
|
|
|
//
|
|
// Determine whether the device can support color.
|
|
// If it does, we'll use the colorimage operator.
|
|
// Otherwise, we'll use the normal image operator.
|
|
// We assume all color devices support colorimage
|
|
// operator (either level 1 with color extension
|
|
// or level 2).
|
|
//
|
|
|
|
useColor = (Level2Device(pdev->hppd) || pdev->hppd->bColorDevice);
|
|
|
|
// Generate image data - iterate through each scanline
|
|
|
|
psputs(pdev, "<");
|
|
|
|
y = (pBrush->flBitmap & BMF_TOPDOWN) ? 0 : height-1;
|
|
|
|
for ( ; ; ) {
|
|
|
|
ULONG index;
|
|
BYTE* pRow;
|
|
BYTE* pCol;
|
|
|
|
// Take y brush origin into consideration.
|
|
|
|
pRow = pBitmap + ((y + orgY) % height) * lineOffset;
|
|
|
|
// Iterate through each pixel
|
|
|
|
for (x=0; x<width; x++) {
|
|
|
|
// Calculate a pointer to current pixel data
|
|
|
|
pCol = pRow + ((x + orgX) % width) * bpp / 8;
|
|
|
|
switch (bpp) {
|
|
|
|
// 4bpp - use the lower nibble for even-numbered
|
|
// pixels and the top nibble for odd-numbered pixels.
|
|
// (The first pixel is numbered 0.)
|
|
|
|
case 4:
|
|
if (((x + orgX) % width) & 1) {
|
|
|
|
// Odd-numbered pixel - top nibble
|
|
|
|
index = pColorLUT[*pCol >> 4];
|
|
} else {
|
|
|
|
// Even-numbered pixel - lower nibble
|
|
|
|
index = pColorLUT[*pCol & 15];
|
|
}
|
|
EXTRACT_RGB(index, rgb[0], rgb[1], rgb[2]);
|
|
break;
|
|
|
|
// 8bpp - use each byte as color index.
|
|
|
|
case 8:
|
|
index = pColorLUT[*pCol];
|
|
EXTRACT_RGB(index, rgb[0], rgb[1], rgb[2]);
|
|
break;
|
|
|
|
// 24bpp - assume pixels are in RGB order
|
|
|
|
case 24:
|
|
rgb[0] = *pCol++;
|
|
rgb[1] = *pCol++;
|
|
rgb[2] = *pCol;
|
|
break;
|
|
}
|
|
|
|
if (useColor) {
|
|
|
|
// Generate RGB value for colorimage operator
|
|
|
|
psputhex(pdev, 3, rgb);
|
|
} else {
|
|
|
|
// Convert RGB to gray for image operator.
|
|
|
|
rgb[0] = (BYTE) RgbToGray(rgb[0], rgb[1], rgb[2]);
|
|
psputhex(pdev, 1, rgb);
|
|
}
|
|
}
|
|
|
|
// Move on to the next row
|
|
|
|
if (pBrush->flBitmap & BMF_TOPDOWN) {
|
|
if (++y >= height) break;
|
|
} else {
|
|
if (y-- <= 0) break;
|
|
}
|
|
}
|
|
|
|
// Generate stack operands for the image operators
|
|
|
|
psprintf(pdev, ">\n{%d %d 8 _i {_s} %s}bind\n",
|
|
width, height,
|
|
useColor ? "false 3 colorimage" : "image");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
ROP4
|
|
MixToRop4(
|
|
MIX mix
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert a MIX parameter to a ROP4 parameter
|
|
|
|
Arguments:
|
|
|
|
mix - Specifies the input MIX parameter
|
|
|
|
Return Value:
|
|
|
|
ROP4 value corresponding to the input MIX value
|
|
|
|
--*/
|
|
|
|
{
|
|
static BYTE Rop2ToRop3[] = {
|
|
|
|
0xFF, // R2_WHITE
|
|
0x00, // R2_BLACK
|
|
0x05, // R2_NOTMERGEPEN
|
|
0x0A, // R2_MASKNOTPEN
|
|
0x0F, // R2_NOTCOPYPEN
|
|
0x50, // R2_MASKPENNOT
|
|
0x55, // R2_NOT
|
|
0x5A, // R2_XORPEN
|
|
0x5F, // R2_NOTMASKPEN
|
|
0xA0, // R2_MASKPEN
|
|
0xA5, // R2_NOTXORPEN
|
|
0xAA, // R2_NOP
|
|
0xAF, // R2_MERGENOTPEN
|
|
0xF0, // R2_COPYPEN
|
|
0xF5, // R2_MERGEPENNOT
|
|
0xFA, // R2_MERGEPEN
|
|
0xFF // R2_WHITE
|
|
};
|
|
|
|
return ((ROP4) Rop2ToRop3[(mix >> 8) & 0xf] << 8) | Rop2ToRop3[mix & 0xf];
|
|
}
|
|
|