#include #include #include "log.h" #include "gfxtype.h" #include "gfxobj.h" #include "devctxt.h" #include "bitmap.h" #include "dc_screen.h" inline static BYTE line_clip_outcode(INT32 x, INT32 y, INT32 xmin, INT32 ymin, INT32 xmax, INT32 ymax) { BYTE rc = 0; if (y < ymin) rc |= 0x8; else if (y >= ymax) rc |= 0x4; if (x < xmin) rc |= 0x1; else if (x >= xmax) rc |= 0x2; return rc; } #define CPX 8 /* clipping precision in bits */ #define ONE (1 << CPX) /* constant for mathematics */ /* these macros keep the number of bits straight when doing fixed-point multiply & divide */ #define M(a, b) ((((a) * (b))) >> CPX) #define D(a, b) (((a) << CPX) / (b)) static BOOL line_clip(PINT32 output, INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 xmin, INT32 ymin, INT32 xmax, INT32 ymax) { BYTE outcode1, outcode2; INT32 tmp; int nloop = 0; /* Cohen-Sutherland line-clipping algorithm (see Foley & Van Dam, pp. 145-149) */ for (;;) { if (++nloop == 20) { Log(LDEBUG, "POSSIBLE INFINITE LOOP DETECTED - REJECTING"); return FALSE; } outcode1 = line_clip_outcode(x1, y1, xmin, ymin, xmax, ymax); outcode2 = line_clip_outcode(x2, y2, xmin, ymin, xmax, ymax); if ((outcode1 & outcode2) != 0) return FALSE; /* trivial rejection */ else if ((outcode1 == 0) && (outcode2 == 0)) break; /* trivial acceptance */ if (outcode1 == 0) { tmp = x1; x1 = x2; x2 = tmp; tmp = y1; y1 = y2; y2 = tmp; outcode1 = outcode2; /* we don't reference outcode2 in the rest of the loop */ } if (outcode1 & 0x8) { x1 += M(x2 - x1, D(ymin - y1, y2 - y1)); y1 = ymin; } else if (outcode1 & 0x4) { x1 += M(x2 - x1, D(ymax - ONE - y1, y2 - y1)); y1 = ymax - ONE; } else if (outcode1 & 0x2) { y1 += M(y2 - y1, D(xmax - ONE - x1, x2 - x1)); x1 = xmax - ONE; } else if (outcode1 & 0x1) { y1 += M(y2 - y1, D(xmin - x1, x2 - x1)); x1 = xmin; } } output[0] = x1; output[1] = y1; output[2] = x2; output[3] = y2; return TRUE; } static BOOL internal_line(PDCTXT pdctxt, INT32 x1, INT32 y1, INT32 x2, INT32 y2) { INT32 buffer[4]; if (line_clip(buffer, x1 << CPX, y1 << CPX, x2 << CPX, y2 << CPX, pdctxt->cliprect.left << CPX, pdctxt->cliprect.top << CPX, pdctxt->cliprect.right << CPX, pdctxt->cliprect.bottom << CPX)) return (*pdctxt->funcs->line)(pdctxt->privdata, buffer[0] >> CPX, buffer[1] >> CPX, buffer[2] >> CPX, buffer[3] >> CPX, pdctxt->color, pdctxt->rop2); return TRUE; } PDCTXT _DC_Allocate(PDCFUNTABLE funcs, PVOID privdata) { PDCTXT rc = (PDCTXT)malloc(sizeof(DCTXT)); if (!rc) return NULL; memset(rc, 0, sizeof(DCTXT)); _Go_init(&(rc->hdr), DCTXT_SIG_WORD, sizeof(DCTXT)); rc->funcs = funcs; rc->privdata = privdata; rc->rop2 = R2_COPYPEN; return rc; } void _DC_FinalizeCommon(PDCTXT pdctxt) { if (pdctxt->cur_bitmap) Go_release(&(pdctxt->cur_bitmap->hdr)); } COLORREF DC_SetPixel(PDCTXT pdctxt, INT32 x, INT32 y, COLORREF color) { if (!G_coords_in_rect(&(pdctxt->cliprect), x, y)) return (COLORREF)(-1); return (*(pdctxt->funcs->set_pixel))(pdctxt->privdata, x, y, color, pdctxt->rop2); } BOOL DC_LineTo(PDCTXT pdctxt, INT32 x, INT32 y) { BOOL rc = internal_line(pdctxt, pdctxt->pos.x, pdctxt->pos.y, x, y); if (rc) { pdctxt->pos.x = x; pdctxt->pos.y = y; } return rc; } BOOL DC_MoveTo(PDCTXT pdctxt, INT32 x, INT32 y, PPOINT oldpt) { if (oldpt) memcpy(oldpt, &(pdctxt->pos), sizeof(POINT)); pdctxt->pos.x = x; pdctxt->pos.y = y; return TRUE; } BOOL DC_Rectangle(PDCTXT pdctxt, INT32 left, INT32 top, INT32 right, INT32 bottom) { internal_line(pdctxt, left, top, right - 1, top); internal_line(pdctxt, left, top + 1, left, bottom - 2); internal_line(pdctxt, right - 1, top + 1, right - 1, bottom - 2); internal_line(pdctxt, left, bottom - 1, right - 1, bottom - 1); return TRUE; } BOOL DC_SolidRectangle(PDCTXT pdctxt, INT32 left, INT32 top, INT32 right, INT32 bottom) { RECT rect, actual; G_set_rect(&rect, left, top, right, bottom); if (!G_rect_intersect(&actual, &rect, &(pdctxt->cliprect))) return TRUE; return (*(pdctxt->funcs->solid_rect))(pdctxt->privdata, &actual, pdctxt->color, pdctxt->rop2); } UINT32 DC_GetROP2(PDCTXT pdctxt) { return pdctxt->rop2; } UINT32 DC_SetROP2(PDCTXT pdctxt, UINT32 rop) { UINT32 rc = pdctxt->rop2; pdctxt->rop2 = rop; return rc; } COLORREF DC_GetTextColor(PDCTXT pdctxt) { return pdctxt->color; } COLORREF DC_SetTextColor(PDCTXT pdctxt, COLORREF cr) { COLORREF rc = pdctxt->color; pdctxt->color = cr; return rc; } BOOL DC_GetClipRect(PDCTXT pdctxt, PRECT prect) { memcpy(prect, &(pdctxt->cliprect), sizeof(RECT)); return TRUE; } BOOL DC_SetClipRect(PDCTXT pdctxt, PRECT prect) { memcpy(&(pdctxt->cliprect), prect, sizeof(RECT)); return TRUE; } PDCTXT DC_CreateCompatible(PDCTXT pdctxt) { if (pdctxt) return (*(pdctxt->funcs->create_compat))(pdctxt->privdata); return _DC_CreateScreenCompatibleContext(); } PGFXOBJECT DC_SelectObject(PDCTXT pdctxt, PGFXOBJECT pobj) { if (pobj->sig == BMP_SIG_WORD) { if ((pdctxt->flags & DCFLG_TYPES) == DCFLG_IS_MEMORY) { RECT rtmp; PBITMAP rbmp = pdctxt->cur_bitmap; Go_addref(pobj); if ((*(pdctxt->funcs->new_bitmap))(pdctxt->privdata, (PBITMAP)pobj)) { pdctxt->cur_bitmap = (PBITMAP)pobj; pdctxt->baserect.left = pdctxt->baserect.top = 0; pdctxt->baserect.right = ((PBITMAP)pobj)->width; pdctxt->baserect.bottom = ((PBITMAP)pobj)->height; G_rect_intersect(&rtmp, &(pdctxt->baserect), &(pdctxt->cliprect)); memcpy(&(pdctxt->cliprect), &rtmp, sizeof(RECT)); return (PGFXOBJECT)rbmp; } Go_release(pobj); } } return NULL; } BOOL DC_BitBlt(PDCTXT dest, INT32 x, INT32 y, INT32 width, INT32 height, PDCTXT source, INT32 x1, INT32 y1, UINT32 rop) { RECT destrect, actualdest, srcrect, actualsrc; G_set_rect(&destrect, x, y, x + width, y + height); if (!G_rect_intersect(&actualdest, &destrect, &(dest->cliprect))) return TRUE; /* no-op */ G_set_rect(&srcrect, x1, y1, x1 + (actualdest.right - actualdest.left), y1 + (actualdest.bottom - actualdest.top)); if (!G_rect_intersect(&actualsrc, &srcrect, &(source->baserect))) return TRUE; actualdest.right = actualdest.left + (actualsrc.right - actualsrc.left); actualdest.bottom = actualdest.top + (actualsrc.bottom - actualsrc.top); return (*(dest->funcs->bitblt))(dest->privdata, &actualdest, source->privdata, &actualsrc, rop); }