BOOL WINAPI StretchBlt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, DWORD dwRop) { HWND hwnd; POINT dst, src; if(!hdcDest || !hdcSrc) return FALSE; dst.x = nXOriginDest; dst.y = nYOriginDest; src.x = nXOriginSrc; src.y = nYOriginSrc; /* if src screen DC, convert coords*/ /* FIXME: src clipping isn't checked, only one set of cliprects also*/ if(!MwIsMemDC(hdcSrc) && MwIsClientDC(hdcSrc)) { if(!(hwnd = MwPrepareDC(hdcSrc))) return FALSE; ClientToScreen(hwnd, &src); } /* if dst screen DC, convert coords and set clipping*/ /* FIXME: if dest is also screen, src clipping will be overwritten*/ if(!MwIsMemDC(hdcDest) && MwIsClientDC(hdcDest)) { if(!(hwnd = MwPrepareDC(hdcDest))) return FALSE; ClientToScreen(hwnd, &dst); } if (nWidthDest == nWidthSrc && nHeightDest == nHeightSrc) { GdBlit(hdcDest->psd, dst.x, dst.y, nWidthDest, nHeightDest, hdcSrc->psd, src.x, src.y, dwRop); } else { GdStretchBlit(hdcDest->psd, dst.x, dst.y, nWidthDest, nHeightDest, hdcSrc->psd, src.x, src.y, nWidthSrc, nHeightSrc, dwRop); } return TRUE; }
/* * Draw a tiled pixmap window background. */ void GsWpTileBackgroundPixmap(GR_WINDOW *wp, GR_PIXMAP *pm, GR_COORD x, GR_COORD y, GR_SIZE width, GR_SIZE height) { GR_COORD tilex = 0, tiley = 0, fromx, fromy, cx, cy; GR_SIZE destwidth, destheight, pmwidth, pmheight, cwidth, cheight; if(pm->width > wp->width) pmwidth = wp->width; else pmwidth = pm->width; if(pm->height > wp->height) pmheight = wp->height; else pmheight = pm->height; for(;tiley < wp->height; tiley += pmheight, tilex = 0) { if(tiley > (y + height)) continue; if(y > (tiley + pmheight)) continue; if((tiley + pmheight) > wp->height) destheight = wp->height - tiley; else destheight = pmheight; for(;tilex < wp->width; tilex += pmwidth) { if(tilex > (x + width)) continue; if(x > (tilex + pmwidth)) continue; if((tilex + pmwidth) > wp->width) destwidth = wp->width - tilex; else destwidth = pmwidth; if((tilex >= x) && ((tilex + destwidth)<=(x + width))) { fromx = 0; cx = tilex + wp->x; cwidth = destwidth; } else { if(x > tilex) { fromx = x - tilex; cwidth = destwidth - fromx; } else { fromx = 0; cwidth = x + width - tilex; } if(cwidth > width) cwidth = width; if(cwidth > destwidth) cwidth = destwidth; cx = wp->x + tilex + fromx; } if((tiley >= y)&&((tiley + destheight)<=(y + height))) { fromy = 0; cy = tiley + wp->y; cheight = destheight; } else { if(y > tiley) { fromy = y - tiley; cheight = destheight - fromy; } else { fromy = 0; cheight = y + height - tiley; } if(cwidth > width) cwidth = width; if(cheight > destheight) cheight = destheight; cy = wp->y + tiley + fromy; } if((cwidth > 0) && (cheight > 0)) { GdBlit(wp->psd, cx, cy, cwidth, cheight, pm->psd, fromx, fromy, MWROP_COPY); } } } }
/* * Draw a window's background pixmap. * * The flags mean: * GR_BACKGROUND_TILE- tile the pixmap across the window (default). * GR_BACKGROUND_TOPLEFT- draw the pixmap at (0,0) relative to the window. * GR_BACKGROUND_CENTER- draw the pixmap in the middle of the window. * GR_BACKGROUND_STRETCH- stretch the pixmap within the window. * GR_BACKGROUND_TRANS- if the pixmap is smaller than the window and not * using tile mode, there will be gaps around the pixmap. This flag causes * to not fill in the spaces with the background colour. */ void GsWpDrawBackgroundPixmap(GR_WINDOW *wp, GR_PIXMAP *pm, GR_COORD x, GR_COORD y, GR_SIZE width, GR_SIZE height) { GR_SIZE destwidth, destheight, fillwidth, fillheight, pmwidth, pmheight; GR_COORD fromx, fromy, destx, desty, pixmapx = 0, pixmapy = 0; if(wp->bgpixmapflags & (GR_BACKGROUND_TOPLEFT|GR_BACKGROUND_STRETCH)) { pixmapx = 0; pixmapy = 0; } else if(wp->bgpixmapflags & GR_BACKGROUND_CENTER) { if(pm->width >= wp->width) pixmapx = 0; else pixmapx = (wp->width - pm->width) / 2; if(pm->height >= wp->height) pixmapy = 0; else pixmapy = (wp->height - pm->height) / 2; } else { /* GR_BACKGROUND_TILE (default)*/ GsWpTileBackgroundPixmap(wp, pm, x, y, width, height); return; } if(pm->width > wp->width) pmwidth = wp->width; else pmwidth = pm->width; if(pm->height > wp->height) pmheight = wp->height; else pmheight = pm->height; if(x > pixmapx) { destx = x; fromx = x - pixmapx; destwidth = pixmapx + pmwidth - x; } else { destx = pixmapx; fromx = 0; destwidth = x + width - pixmapx; } if(y > pixmapy) { desty = y; fromy = y - pixmapy; destheight = pixmapy + pmheight - desty; } else { desty = pixmapy; fromy = 0; destheight = y + height - pixmapy; } if(destwidth > 0 && destheight > 0) { if (wp->bgpixmapflags & GR_BACKGROUND_STRETCH) { GdStretchBlit(wp->psd, destx + wp->x, desty + wp->y, destwidth, destheight, pm->psd, fromx, fromy, pm->width, pm->height, MWROP_COPY); } else GdBlit(wp->psd, destx + wp->x, desty + wp->y, destwidth, destheight, pm->psd, fromx, fromy, MWROP_COPY); } if(wp->bgpixmapflags & (GR_BACKGROUND_TRANS|GR_BACKGROUND_STRETCH)) return; /* Fill in the gaps around the pixmap */ if(x < pixmapx) { fillwidth = pixmapx - x; if(fillwidth > width) fillwidth = width; fillheight = height; GdFillRect(wp->psd, wp->x + x, wp->y + y, fillwidth,fillheight); } if((x + width) > (pixmapx + pmwidth)) { fillwidth = (x + width) - (pixmapx + pmwidth); if(fillwidth > width) fillwidth = width; fillheight = height; if(x < (pixmapx + pmwidth)) destx = pixmapx + pmwidth + wp->x; else destx = x + wp->x; GdFillRect(wp->psd, destx, wp->y + y, fillwidth, fillheight); } if(y < pixmapy) { fillheight = pixmapy - y; if(fillheight > height) fillheight = height; if(x < pixmapx) destx = pixmapx + wp->x; else destx = x + wp->x; if((x + width) > (pixmapx + pmwidth)) fillwidth = pixmapx + pmwidth - destx; else fillwidth = x + width - destx; if((fillwidth > 0) && (fillheight > 0)) { GdFillRect(wp->psd, destx, wp->y + y, fillwidth, fillheight); } } if((y + height) > (pixmapy + pmheight)) { fillheight = (y + height) - (pixmapy + pmheight); if(fillheight > height) fillheight = height; if(x < pixmapx) destx = pixmapx + wp->x; else destx = x + wp->x; if(y < (pixmapy + pmheight)) desty = pixmapy + pmheight + wp->y; else desty = y + wp->y; if((x + width) > (pixmapx + pmwidth)) fillwidth = pixmapx + pmwidth - destx; else fillwidth = x + width - destx; if((fillwidth > 0) && (fillheight > 0)) { GdFillRect(wp->psd, destx, desty, fillwidth,fillheight); } } }
/* * Clear the specified area of a window and possibly make an exposure event. * This sets the area window to its background color or pixmap. If the * exposeflag is 1, then this also creates an exposure event for the window. * For buffered windows, mark drawing finalized and draw if * exposeflag = 2. */ void GsClearWindow(GR_WINDOW *wp, GR_COORD x, GR_COORD y, GR_SIZE width, GR_SIZE height, int exposeflag) { if (!wp->realized || !wp->output) return; /* * Reduce the arguments so that they actually lie within the window. */ if (x < 0) { width += x; x = 0; } if (y < 0) { height += y; y = 0; } if (x + width > wp->width) width = wp->width - x; if (y + height > wp->height) height = wp->height - y; /* * Now see if the region is really in the window. If not, then * do nothing. */ if (x >= wp->width || y >= wp->height || width <= 0 || height <= 0) return; /* * Buffered window drawing. First check if drawing finalized and * set flag. Physical window background erase is never performed * with buffered windows, all drawing is postponed until the application * is finished by calling GrClearWindow(..., 2), ie. GrFlushWindow() */ if (exposeflag == 2) wp->props |= GR_WM_PROPS_DRAWING_DONE; if (wp->props & GR_WM_PROPS_BUFFERED) { /* nothing to do until drawing finalized*/ if (!(wp->props & GR_WM_PROPS_DRAWING_DONE)) return; /* prepare clipping to window boundaries*/ GsSetClipWindow(wp, NULL, 0); clipwp = NULL; /* reset clip cache since no user regions used*/ #if DEBUG_EXPOSE curgcp = NULL; GdSetFillMode(GR_FILL_SOLID); GdSetMode(GR_MODE_COPY); GdSetForegroundColor(wp->psd, MWRGB(255,255,0)); /* yellow*/ GdFillRect(wp->psd, wp->x+x, wp->y+y, width, height); usleep(500000); #endif /* copy window pixmap buffer to window*/ GdBlit(wp->psd, wp->x + x, wp->y + y, width, height, wp->buffer->psd, x, y, MWROP_COPY); return; /* don't deliver exposure events*/ } /* * Unbuffered window: erase background unless nobackground flag set */ if (!(wp->props & GR_WM_PROPS_NOBACKGROUND)) { /* perhaps find a better way of determining whether pixmap needs src_over*/ int hasalpha = wp->bgpixmap && (wp->bgpixmap->psd->data_format & MWIF_HASALPHA); /* * Draw the background of the window. * Invalidate the current graphics context since * we are changing the foreground color and mode. */ GsSetClipWindow(wp, NULL, 0); clipwp = NULL; /* reset clip cache since no user regions used*/ #if DEBUG_EXPOSE GdSetFillMode(GR_FILL_SOLID); GdSetMode(GR_MODE_COPY); GdSetForegroundColor(wp->psd, MWRGB(255,255,0)); /* yellow*/ GdFillRect(wp->psd, wp->x+x, wp->y+y, width, height); usleep(500000); #endif curgcp = NULL; GdSetFillMode(GR_FILL_SOLID); GdSetMode(GR_MODE_COPY); GdSetForegroundColor(wp->psd, wp->background); /* if background pixmap w/alpha channel and stretchblit, fill entire (clipped) window*/ if (hasalpha && wp->bgpixmapflags == GR_BACKGROUND_STRETCH) GdFillRect(wp->psd, wp->x, wp->y, wp->width, wp->height); else /* if no pixmap background clear exposed area*/ if (!wp->bgpixmap || hasalpha) /* FIXME will flash with pixmap, should check src_over*/ if (!(wp->bgpixmapflags & GR_BACKGROUND_TRANS)) GdFillRect(wp->psd, wp->x + x, wp->y + y, width, height); if (wp->bgpixmap) GsDrawBackgroundPixmap(wp, wp->bgpixmap, x, y, width, height); } /* * Do the exposure if required for unbuffered windows. */ if (exposeflag) GsDeliverExposureEvent(wp, x, y, width, height); }
/* * Draw a window's background pixmap. * * The flags mean: * GR_BACKGROUND_TILE- tile the pixmap across the window (default). * GR_BACKGROUND_TOPLEFT- draw the pixmap at (0,0) relative to the window. * GR_BACKGROUND_CENTER- draw the pixmap in the middle of the window. * GR_BACKGROUND_STRETCH- stretch the pixmap within the window. * GR_BACKGROUND_TRANS- if the pixmap is smaller than the window and not * using tile mode, there will be gaps around the pixmap. This flag causes * to not fill in the spaces with the background colour. */ void GsDrawBackgroundPixmap(GR_WINDOW *wp, GR_PIXMAP *pm, GR_COORD x, GR_COORD y, GR_SIZE width, GR_SIZE height) { GR_SIZE destwidth, destheight, fillwidth, fillheight, pmwidth, pmheight; GR_COORD fromx, fromy, destx, desty, pixmapx = 0, pixmapy = 0; if(wp->bgpixmapflags & GR_BACKGROUND_STRETCH) { /* must use whole window coords or stretch will have incorrect ratios*/ GdStretchBlit(wp->psd, wp->x, wp->y, wp->x + wp->width, wp->y + wp->height, pm->psd, 0, 0, pm->width - 1, pm->height - 1, MWROP_SRC_OVER); return; } if(wp->bgpixmapflags == GR_BACKGROUND_TILE) { GsTileBackgroundPixmap(wp, pm, x, y, width, height); return; } if(wp->bgpixmapflags & GR_BACKGROUND_CENTER) { if (pm->width < wp->width) pixmapx = (wp->width - pm->width) / 2; if (pm->height < wp->height) pixmapy = (wp->height - pm->height) / 2; } /* topleft & center calcs*/ pmwidth = MWMIN(pm->width, wp->width); pmheight = MWMIN(pm->height, wp->height); if(x > pixmapx) { destx = x; fromx = x - pixmapx; destwidth = pixmapx + pmwidth - x; } else { destx = pixmapx; fromx = 0; destwidth = x + width - pixmapx; } if(y > pixmapy) { desty = y; fromy = y - pixmapy; destheight = pixmapy + pmheight - desty; } else { desty = pixmapy; fromy = 0; destheight = y + height - pixmapy; } if(destwidth > 0 && destheight > 0) { destwidth = MWMIN(width, destwidth); destheight = MWMIN(height, destheight); GdBlit(wp->psd, wp->x + destx, wp->y + desty, destwidth, destheight, pm->psd, fromx, fromy, MWROP_SRC_OVER); } if(wp->bgpixmapflags & GR_BACKGROUND_TRANS) return; /* Fill in the gaps around the pixmap */ if(x < pixmapx) { fillwidth = pixmapx - x; if(fillwidth > width) fillwidth = width; fillheight = height; GdFillRect(wp->psd, wp->x + x, wp->y + y, fillwidth, fillheight); } if(x + width > pixmapx + pmwidth) { fillwidth = (x + width) - (pixmapx + pmwidth); if(fillwidth > width) fillwidth = width; fillheight = height; if(x < pixmapx + pmwidth) destx = pixmapx + pmwidth + wp->x; else destx = x + wp->x; GdFillRect(wp->psd, destx, wp->y + y, fillwidth, fillheight); } if(y < pixmapy) { fillheight = pixmapy - y; if(fillheight > height) fillheight = height; if(x < pixmapx) destx = pixmapx + wp->x; else destx = x + wp->x; if(x + width > pixmapx + pmwidth) fillwidth = pixmapx + pmwidth - destx; else fillwidth = x + width - destx; if(fillwidth > 0 && fillheight > 0) GdFillRect(wp->psd, destx, wp->y + y, fillwidth, fillheight); } if(y + height > pixmapy + pmheight) { fillheight = (y + height) - (pixmapy + pmheight); if(fillheight > height) fillheight = height; if(x < pixmapx) destx = pixmapx + wp->x; else destx = x + wp->x; if(y < pixmapy + pmheight) desty = pixmapy + pmheight + wp->y; else desty = y + wp->y; if(x + width > pixmapx + pmwidth) fillwidth = pixmapx + pmwidth - destx; else fillwidth = x + width - destx; if(fillwidth > 0 && fillheight > 0) GdFillRect(wp->psd, destx, desty, fillwidth, fillheight); } }