BOOL WINAPI DeleteObject(HGDIOBJ hObject) { if(!hObject || hObject->hdr.stockobj) return FALSE; if(hObject->hdr.type == OBJ_FONT) GdDestroyFont(((MWFONTOBJ *)hObject)->pfont); if(hObject->hdr.type == OBJ_REGION) GdDestroyRegion(((MWRGNOBJ *)hObject)->rgn); GdItemFree(hObject); return TRUE; }
/* close framebuffer*/ static void fb_close(PSD psd) { if (fb >= 0) close(fb); fb = -1; if ((psd->flags & PSF_ADDRMALLOC) && psd->addr) free (psd->addr); psd->addr = NULL; if (fb_updateregion) GdDestroyRegion(fb_updateregion); fb_updateregion = NULL; }
HRGN WINAPI CreatePolygonRgn(const POINT *points, INT count, INT mode) { #if POLYREGIONS HRGN hrgn; MWRGNOBJ * obj; MWCLIPREGION * rgn; if (!(hrgn = REGION_CreateRegion())) return NULL; obj = (MWRGNOBJ *)GDI_GetObjPtr(hrgn, OBJ_REGION); if (!obj) return NULL; rgn = GdAllocPolygonRegion((POINT *)points, count, mode); if (!rgn) return hrgn; GdDestroyRegion(obj->rgn); obj->rgn = rgn; return hrgn; #endif }
/* * Prepare to do drawing in a window or pixmap using the specified * graphics context. Returns the drawable pointer if successful, * and the type of drawing id that was supplied. Returns the special value * GR_DRAW_TYPE_NONE if an error is generated, or if drawing is useless. */ GR_DRAW_TYPE GsPrepareDrawing(GR_DRAW_ID id, GR_GC_ID gcid, GR_DRAWABLE **retdp) { GR_WINDOW *wp; /* found window */ GR_PIXMAP *pp; /* found pixmap */ GR_GC *gcp; /* found graphics context */ GR_FONT *fontp; GR_REGION *regionp; /* user clipping region */ MWCLIPREGION *reg; PMWFONT pf; *retdp = NULL; gcp = GsFindGC(gcid); if (gcp == NULL) return GR_DRAW_TYPE_NONE; /* * If the graphics context is not the current one, then * make it the current one and remember to update it. */ if (gcp != curgcp) { curgcp = gcp; gcp->changed = GR_TRUE; } /* * Look for window or pixmap id */ pp = NULL; wp = GsFindWindow(id); if (wp == NULL) { pp = GsFindPixmap(id); if (pp == NULL) return GR_DRAW_TYPE_NONE; #if DYNAMICREGIONS reg = GdAllocRectRegion(0, 0, pp->psd->xvirtres, pp->psd->yvirtres); /* intersect with user region if any*/ if (gcp->regionid) { regionp = GsFindRegion(gcp->regionid); if (regionp) GdIntersectRegion(reg, reg, regionp->rgn); } GdSetClipRegion(pp->psd, reg); #else { MWCLIPRECT cliprect; /* FIXME: setup pixmap clipping, different from windows*/ cliprect.x = 0; cliprect.y = 0; cliprect.width = pp->psd->xvirtres; cliprect.height = pp->psd->yvirtres; GdSetClipRects(pp->psd, 1, &cliprect); } #endif /* reset clip cache for next window draw*/ clipwp = NULL; } else { if (!wp->output) { GsError(GR_ERROR_INPUT_ONLY_WINDOW, id); return GR_DRAW_TYPE_NONE; } if (wp->unmapcount) return GR_DRAW_TYPE_NONE; /* * If the window is not the currently clipped one, * then make it the current one and define its clip rectangles. */ if (wp != clipwp || gcp->changed) { /* find user region for intersect*/ if (gcp->regionid) regionp = GsFindRegion(gcp->regionid); else regionp = NULL; /* * Special handling if user region is not at offset 0,0 */ if (regionp && (gcp->xoff || gcp->yoff)) { MWCLIPREGION *local = GdAllocRegion(); GdCopyRegion(local, regionp->rgn); GdOffsetRegion(local, gcp->xoff, gcp->yoff); GsSetClipWindow(wp, local, gcp->mode & ~GR_MODE_DRAWMASK); GdDestroyRegion(local); } else { GsSetClipWindow(wp, regionp? regionp->rgn: NULL, gcp->mode & ~GR_MODE_DRAWMASK); } } } /* * If the graphics context has been changed, then tell the * device driver about it. */ if (gcp->changed) { GdSetForeground(GdFindColor(gcp->foreground)); GdSetBackground(GdFindColor(gcp->background)); GdSetMode(gcp->mode & GR_MODE_DRAWMASK); GdSetUseBackground(gcp->usebackground); fontp = GsFindFont(gcp->fontid); pf = fontp? fontp->pfont: stdfont; GdSetFont(pf); gcp->changed = GR_FALSE; } *retdp = wp? (GR_DRAWABLE *)wp: (GR_DRAWABLE *)pp; return wp? GR_DRAW_TYPE_WINDOW: GR_DRAW_TYPE_PIXMAP; }
/* * Set the clip rectangles for a window taking into account other * windows that may be obscuring it. The windows that may be obscuring * this one are the siblings of each direct ancestor which are higher * in priority than those ancestors. Also, each parent limits the visible * area of the window. */ void MwSetClipWindow(HDC hdc) { HWND wp = hdc->hwnd; HWND pwp; /* parent window */ HWND sibwp; /* sibling windows */ MWCOORD diff; /* difference in coordinates */ PRECT prc; /* client or window rectangle*/ MWCLIPREGION *vis, *r; MWCOORD x, y, width, height; /* * Start with the rectangle for the complete window. * We will then cut pieces out of it as needed. */ prc = MwIsClientDC(hdc)? &wp->clirect: &wp->winrect; x = prc->left; y = prc->top; width = prc->right - prc->left; height = prc->bottom - prc->top; /* * First walk upwards through all parent windows, * and restrict the visible part of this window to the part * that shows through all of those parent windows client areas. */ pwp = wp; while (pwp != rootwp) { pwp = pwp->parent; diff = pwp->clirect.left - x; if (diff > 0) { width -= diff; x = pwp->clirect.left; } diff = pwp->clirect.right - (x + width); if (diff < 0) width += diff; diff = pwp->clirect.top - y; if (diff > 0) { height -= diff; y = pwp->clirect.top; } diff = pwp->clirect.bottom - (y + height); if (diff < 0) height += diff; } /* * If the window is completely clipped out of view, then * set the clipping region to indicate that. */ if (width <= 0 || height <= 0) { GdSetClipRegion(hdc->psd, NULL); return; } /* * Allocate initial vis region to parent-clipped size of window */ vis = GdAllocRectRegion(x, y, x+width, y+height); /* * Allocate temp region */ r = GdAllocRegion(); /* * Now examine all windows that obscure this window, and * for each obscuration, break up the clip rectangles into * the smaller pieces that are still visible. The windows * that can obscure us are the earlier siblings of all of * our parents. When clipping the root window, search all children. */ pwp = wp; while (pwp != NULL) { wp = pwp; pwp = wp->parent; if(!pwp) { /* We're clipping the root window*/ if(hdc->flags & DCX_CLIPCHILDREN) /* start with root's children*/ sibwp = rootwp->children; else sibwp = NULL; /* no search*/ wp = NULL; /* search all root's children*/ } else { if(hdc->flags & DCX_CLIPSIBLINGS) sibwp = pwp->children; else sibwp = wp; /* no search*/ } for (; sibwp != wp; sibwp = sibwp->siblings) { if (sibwp->unmapcount) continue; GdSetRectRegionIndirect(r, &sibwp->winrect); GdSubtractRegion(vis, vis, r); } /* if not clipping the root window, stop when you reach it*/ if(pwp == rootwp) break; } /* * If not the root window and we're going to be drawing * in the client area, clip all children. This is * required for non-special paint handling for child windows. * Non-client dc's don't clip children in order to get * proper border clipping in the case of border-clipped children. */ wp = hdc->hwnd; if(wp != rootwp && MwIsClientDC(hdc)) { for (sibwp=wp->children; sibwp; sibwp = sibwp->siblings) { if (sibwp->unmapcount) continue; GdSetRectRegionIndirect(r, &sibwp->winrect); GdSubtractRegion(vis, vis, r); } } #if UPDATEREGIONS /* * Intersect with update region, unless requested not to. */ if(!(hdc->flags & DCX_EXCLUDEUPDATE)) GdIntersectRegion(vis, vis, wp->update); #endif /* * Intersect with user region, if set. */ if (hdc->region) GdIntersectRegion(vis, vis, hdc->region->rgn); /* * Set the clip region (later destroy handled by GdSetClipRegion) */ GdSetClipRegion(hdc->psd, vis); /* * Destroy temp region */ GdDestroyRegion(r); }
/* * Destroy the specified window, and all of its children. * This is a recursive routine. */ void GsDestroyWindow(GR_WINDOW *wp) { GR_WINDOW *prevwp; /* previous window pointer */ GR_EVENT_CLIENT *ecp; /* selections for window */ GR_WINDOW_ID oldwid; /* old selection owner */ GR_GRABBED_KEY *keygrab; GR_GRABBED_KEY **keygrab_prev_next; if (wp == rootwp) { GsError(GR_ERROR_ILLEGAL_ON_ROOT_WINDOW, wp->id); return; } /* Disable selection if this window is the owner */ if(selection_owner.wid == wp->id) { oldwid = selection_owner.wid; selection_owner.wid = 0; if(selection_owner.typelist) free(selection_owner.typelist); selection_owner.typelist = NULL; GsDeliverSelectionChangedEvent(oldwid, 0); } /* * Unmap the window first. */ if (wp->realized) GsUnrealizeWindow(wp, GR_FALSE); /* send destroy update event*/ GsDeliverUpdateEvent(wp, GR_UPDATE_DESTROY, wp->x, wp->y, wp->width, wp->height); /* * Destroy all children. */ while (wp->children) GsDestroyWindow(wp->children); /* * Free all client selection structures. */ while (wp->eventclients) { ecp = wp->eventclients; wp->eventclients = ecp->next; DPRINTF("FREE 1 %lx\n", (long)ecp); // FIXME free(ecp); } /* * Remove this window from the child list of its parent. */ prevwp = wp->parent->children; if (prevwp == wp) wp->parent->children = wp->siblings; else { while (prevwp->siblings != wp) prevwp = prevwp->siblings; prevwp->siblings = wp->siblings; } wp->siblings = NULL; /* * Remove this window from the complete list of windows. */ prevwp = listwp; if (prevwp == wp) listwp = wp->next; else { while (prevwp->next != wp) prevwp = prevwp->next; prevwp->next = wp->next; } wp->next = NULL; /* * Forget various information if they related to this window. * Then finally free the structure. */ if (wp == clipwp) clipwp = NULL; if (wp == grabbuttonwp) grabbuttonwp = NULL; if (wp == cachewp) { cachewindowid = 0; cachewp = NULL; } if (wp == focuswp) { /* don't revert to mouse enter/leave focus if fixed*/ /*focusfixed = GR_FALSE;*/ focuswp = rootwp; } GsCheckMouseWindow(); /* * Free title, pixmaps and clipregions associated with window. */ if (wp->title) free(wp->title); if (wp->bgpixmap) GsDestroyPixmap(wp->bgpixmap); if (wp->buffer) GsDestroyPixmap(wp->buffer); #if DYNAMICREGIONS if (wp->clipregion) GdDestroyRegion(wp->clipregion); #endif /* Remove any grabbed keys for this window. */ keygrab_prev_next = &list_grabbed_keys; keygrab = list_grabbed_keys; while (keygrab != NULL) { if (keygrab->wid == wp->id){ /* Delete keygrab. */ *keygrab_prev_next = keygrab->next; free(keygrab); keygrab = *keygrab_prev_next; } else { keygrab_prev_next = &keygrab->next; keygrab = keygrab->next; } } free(wp); }
/* * Prepare to do drawing in a window or pixmap using the specified * graphics context. Returns the drawable pointer if successful, * and the type of drawing id that was supplied. Returns the special value * GR_DRAW_TYPE_NONE if an error is generated, or if drawing is useless. */ GR_DRAW_TYPE GsPrepareDrawing(GR_DRAW_ID id, GR_GC_ID gcid, GR_DRAWABLE **retdp) { GR_WINDOW *wp; /* found window */ GR_PIXMAP *pp; /* found pixmap */ GR_GC *gcp; /* found graphics context */ GR_REGION *regionp; /* user clipping region */ MWCLIPREGION*reg; *retdp = NULL; gcp = GsFindGC(gcid); if (gcp == NULL) return GR_DRAW_TYPE_NONE; /* * If the graphics context is not the current one, then * make it the current one and remember to update it. */ if (gcp != curgcp) { curgcp = gcp; gcp->changed = GR_TRUE; } /* * Look for window or pixmap id */ pp = NULL; wp = GsFindWindow(id); if (wp == NULL) { pp = GsFindPixmap(id); if (pp == NULL) return GR_DRAW_TYPE_NONE; havepixmap: #if DYNAMICREGIONS reg = GdAllocRectRegion(0, 0, pp->psd->xvirtres, pp->psd->yvirtres); /* intersect with user region if any*/ if (gcp->regionid) { regionp = GsFindRegion(gcp->regionid); if (regionp) { /* handle pixmap offsets*/ if (gcp->xoff || gcp->yoff) { MWCLIPREGION *local = GdAllocRegion(); GdCopyRegion(local, regionp->rgn); GdOffsetRegion(local, gcp->xoff, gcp->yoff); GdIntersectRegion(reg, reg, local); GdDestroyRegion(local); } else GdIntersectRegion(reg, reg, regionp->rgn); } } GdSetClipRegion(pp->psd, reg); #else { MWCLIPRECT cliprect; /* FIXME: setup pixmap clipping, different from windows*/ cliprect.x = 0; cliprect.y = 0; cliprect.width = pp->psd->xvirtres; cliprect.height = pp->psd->yvirtres; GdSetClipRects(pp->psd, 1, &cliprect); } #endif /* reset clip cache for next window draw*/ clipwp = NULL; } else { if (!wp->output) { GsError(GR_ERROR_INPUT_ONLY_WINDOW, id); return GR_DRAW_TYPE_NONE; } /* check if buffered window*/ if (wp->props & GR_WM_PROPS_BUFFERED) { pp = wp->buffer; wp = NULL; goto havepixmap; /* draw into pixmap buffer*/ } if (!wp->realized) return GR_DRAW_TYPE_NONE; /* * If the window is not the currently clipped one, * then make it the current one and define its clip rectangles. */ if (wp != clipwp || gcp->changed) { #if DYNAMICREGIONS /* find user region for intersect*/ regionp = gcp->regionid? GsFindRegion(gcp->regionid): NULL; /* Special handling if user region is not at offset 0,0*/ if (regionp && (gcp->xoff || gcp->yoff)) { MWCLIPREGION *local = GdAllocRegion(); GdCopyRegion(local, regionp->rgn); GdOffsetRegion(local, gcp->xoff, gcp->yoff); GsSetClipWindow(wp, local, gcp->mode & ~GR_MODE_DRAWMASK); GdDestroyRegion(local); } else GsSetClipWindow(wp, regionp? regionp->rgn: NULL, gcp->mode & ~GR_MODE_DRAWMASK); #else GsSetClipWindow(wp, NULL, gcp->mode & ~GR_MODE_DRAWMASK); #endif /* DYNAMICREGIONS*/ } } /* * If the graphics context has been changed, then tell the * device driver about it. */ if (gcp->changed) { PSD psd = (wp ? wp->psd : pp->psd); uint32_t mask; int count; if (gcp->linestyle == GR_LINE_SOLID) { mask = 0; count = 0; } else { mask = gcp->dashmask; count = gcp->dashcount; } if (gcp->fgispixelval) GdSetForegroundPixelVal(psd, gcp->foreground); else GdSetForegroundColor(psd, gcp->foreground); if (gcp->bgispixelval) GdSetBackgroundPixelVal(psd, gcp->background); else GdSetBackgroundColor(psd, gcp->background); GdSetMode(gcp->mode & GR_MODE_DRAWMASK); GdSetUseBackground(gcp->usebackground); #if MW_FEATURE_SHAPES GdSetDash(&mask, &count); GdSetFillMode(gcp->fillmode); GdSetTSOffset(gcp->ts_offset.x, gcp->ts_offset.y); switch(gcp->fillmode) { case GR_FILL_STIPPLE: case GR_FILL_OPAQUE_STIPPLE: GdSetStippleBitmap(gcp->stipple.bitmap, gcp->stipple.width, gcp->stipple.height); break; case GR_FILL_TILE: GdSetTilePixmap(gcp->tile.psd, gcp->tile.width, gcp->tile.height); break; } #endif gcp->changed = GR_FALSE; } *retdp = wp? (GR_DRAWABLE *)wp: (GR_DRAWABLE *)pp; return wp? GR_DRAW_TYPE_WINDOW: GR_DRAW_TYPE_PIXMAP; }
/* * Set the clip rectangles for a window taking into account other * windows that may be obscuring it. The windows that may be obscuring * this one are the siblings of each direct ancestor which are higher * in priority than those ancestors. Also, each parent limits the visible * area of the window. The clipping is not done if it is already up to * date of if the window is not outputtable. */ void GsSetClipWindow(GR_WINDOW *wp, MWCLIPREGION *userregion, int flags) { GR_WINDOW *orgwp; /* original window pointer */ GR_WINDOW *pwp; /* parent window */ GR_WINDOW *sibwp; /* sibling windows */ GR_COORD minx; /* minimum clip x coordinate */ GR_COORD miny; /* minimum clip y coordinate */ GR_COORD maxx; /* maximum clip x coordinate */ GR_COORD maxy; /* maximum clip y coordinate */ GR_COORD diff; /* difference in coordinates */ GR_SIZE bs; /* border size */ GR_COORD x, y, width, height; MWCLIPREGION *vis, *r; if (wp->unmapcount || !wp->output) return; clipwp = wp; /* * Start with the rectangle for the complete window. * We will then cut pieces out of it as needed. */ x = wp->x; y = wp->y; width = wp->width; height = wp->height; /* * First walk upwards through all parent windows, * and restrict the visible part of this window to the part * that shows through all of those parent windows. */ pwp = wp; while (pwp != rootwp) { pwp = pwp->parent; diff = pwp->x - x; if (diff > 0) { width -= diff; x = pwp->x; } diff = (pwp->x + pwp->width) - (x + width); if (diff < 0) width += diff; diff = pwp->y - y; if (diff > 0) { height -= diff; y = pwp->y; } diff = (pwp->y + pwp->height) - (y + height); if (diff < 0) height += diff; } /* * If the window is completely clipped out of view, then * set the clipping region to indicate that. */ if (width <= 0 || height <= 0) { GdSetClipRegion(clipwp->psd, NULL); return; } /* * Allocate region to clipped size of window */ vis = GdAllocRectRegion(x, y, x+width, y+height); /* * Allocate temp region */ r = GdAllocRegion(); /* * Now examine all windows that obscure this window, and * for each obscuration, break up the clip rectangles into * the smaller pieces that are still visible. The windows * that can obscure us are the earlier siblings of all of * our parents. */ orgwp = wp; pwp = wp; while (pwp != NULL) { wp = pwp; pwp = wp->parent; if(!pwp) { /* We're clipping the root window*/ if (!(flags & GR_MODE_EXCLUDECHILDREN)) /* start with root's children*/ sibwp = rootwp->children; else sibwp = NULL; /* no search*/ wp = NULL; /* search all root's children*/ } else { sibwp = pwp->children; /* clip siblings*/ } for (; sibwp != wp; sibwp = sibwp->siblings) { if (sibwp->unmapcount || !sibwp->output) continue; bs = sibwp->bordersize; minx = sibwp->x - bs; miny = sibwp->y - bs; maxx = sibwp->x + sibwp->width + bs; maxy = sibwp->y + sibwp->height + bs; GdSetRectRegion(r, minx, miny, maxx, maxy); GdSubtractRegion(vis, vis, r); } /* if not clipping the root window, stop when you reach it*/ if (pwp == rootwp) break; } wp = orgwp; /* * If not the root window, clip all children. * (Root window's children are are clipped above) */ if(wp != rootwp && !(flags & GR_MODE_EXCLUDECHILDREN)) { for (sibwp=wp->children; sibwp; sibwp = sibwp->siblings) { if (sibwp->unmapcount || !sibwp->output) continue; bs = sibwp->bordersize; minx = sibwp->x - bs; miny = sibwp->y - bs; maxx = sibwp->x + sibwp->width + bs; maxy = sibwp->y + sibwp->height + bs; GdSetRectRegion(r, minx, miny, maxx, maxy); GdSubtractRegion(vis, vis, r); } } /* * Intersect with user region, if set. */ if (userregion) { /* temporarily offset region by window coordinates*/ GdOffsetRegion(userregion, wp->x, wp->y); GdIntersectRegion(vis, vis, userregion); GdOffsetRegion(userregion, -wp->x, -wp->y); } /* * Set the clip region (later destroy handled by GdSetClipRegion) */ GdSetClipRegion(clipwp->psd, vis); /* * Destroy temp region */ GdDestroyRegion(r); }
/* * Destroy the specified window, and all of its children. * This is a recursive routine. */ void MwDestroyWindow(HWND hwnd,BOOL bSendMsg) { HWND wp = hwnd; HWND prevwp; PMWLIST p; PMSG pmsg; if (wp == rootwp || !IsWindow (hwnd)) return; /* * Unmap the window. */ if (wp->unmapcount == 0) MwHideWindow(wp, FALSE, FALSE); if(bSendMsg) SendMessage(hwnd, WM_DESTROY, 0, 0L); /* * Remove from timers */ MwRemoveWndFromTimers(hwnd); /* * Remove hotkeys */ MwRemoveWndFromHotkeys(hwnd); /* * Disable all sendmessages to this window. */ wp->lpfnWndProc = NULL; /* * Destroy all children, sending WM_DESTROY messages. */ while (wp->children) MwDestroyWindow(wp->children, bSendMsg); wp->pClass = NULL; /* * Free any cursor associated with the window. */ if (wp->cursor->usecount-- == 1) { free(wp->cursor); wp->cursor = NULL; } /* * Remove this window from the child list of its parent. */ prevwp = wp->parent->children; if (prevwp == wp) wp->parent->children = wp->siblings; else { while (prevwp && prevwp->siblings != wp) prevwp = prevwp->siblings; if (prevwp) prevwp->siblings = wp->siblings; } wp->siblings = NULL; /* * Remove this window from the complete list of windows. */ prevwp = listwp; if (prevwp == wp) listwp = wp->next; else { while (prevwp->next && prevwp->next != wp) prevwp = prevwp->next; prevwp->next = wp->next; } wp->next = NULL; /* * Forget various information related to this window. * Then finally free the structure. */ /* Remove all messages from msg queue for this window*/ for(p=mwMsgHead.head; p; ) { pmsg = GdItemAddr(p, MSG, link); if(pmsg->hwnd == wp) { p = p->next; GdListRemove(&mwMsgHead, &pmsg->link); GdItemFree(pmsg); } else p = p->next; } /* * Remove all properties from this window. */ for(p=hwnd->props.head; p; ) { MWPROP *pProp = GdItemAddr(p, MWPROP, link); p = p->next; GdListRemove (&hwnd->props, &pProp->link); GdItemFree (pProp); } /* FIXME: destroy hdc's relating to window?*/ if (wp == capturewp) { capturewp = NULL; MwCheckMouseWindow(); } if (wp == MwGetTopWindow(focuswp)) SetFocus(rootwp->children? rootwp->children: rootwp); /* destroy private DC*/ if(wp->owndc) { HDC hdc = wp->owndc; wp->owndc = NULL; /* force destroy with ReleaseDC*/ ReleaseDC(wp, hdc); } if (wp->szTitle) { free(wp->szTitle); wp->szTitle = NULL; } #if UPDATEREGIONS if (wp->update) { GdDestroyRegion(wp->update); wp->update = NULL; } #endif GdItemFree(wp); }
/* * GdAllocPolyPolygonRegion */ MWCLIPREGION * GdAllocPolyPolygonRegion(MWPOINT *points, int *count, int nbpolygons, int mode) { MWCLIPREGION *rgn; EdgeTableEntry *pAET; /* Active Edge Table */ int y; /* current scanline */ int iPts = 0; /* number of pts in buffer */ EdgeTableEntry *pWETE; /* Winding Edge Table Entry*/ ScanLineList *pSLL; /* current scanLineList */ MWPOINT *pts; /* output buffer */ EdgeTableEntry *pPrevAET; /* ptr to previous AET */ EdgeTable ET; /* header node for ET */ EdgeTableEntry AET; /* header node for AET */ EdgeTableEntry *pETEs; /* EdgeTableEntries pool */ ScanLineListBlock SLLBlock; /* header for scanlinelist */ int fixWAET = FALSE; POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */ POINTBLOCK *tmpPtBlock; int numFullPtBlocks = 0; int poly, total; if(!(rgn = GdAllocRegion())) return NULL; /* special case a rectangle */ if (((nbpolygons == 1) && ((*count == 4) || ((*count == 5) && (points[4].x == points[0].x) && (points[4].y == points[0].y)))) && (((points[0].y == points[1].y) && (points[1].x == points[2].x) && (points[2].y == points[3].y) && (points[3].x == points[0].x)) || ((points[0].x == points[1].x) && (points[1].y == points[2].y) && (points[2].x == points[3].x) && (points[3].y == points[0].y)))) { GdSetRectRegion( rgn, MWMIN(points[0].x, points[2].x), MWMIN(points[0].y, points[2].y), MWMAX(points[0].x, points[2].x), MWMAX(points[0].y, points[2].y) ); return rgn; } for(poly = total = 0; poly < nbpolygons; poly++) total += count[poly]; if (! (pETEs = malloc( sizeof(EdgeTableEntry) * total ))) { GdDestroyRegion( rgn ); return 0; } pts = FirstPtBlock.pts; REGION_CreateETandAET(count, nbpolygons, points, &ET, &AET, pETEs, &SLLBlock); pSLL = ET.scanlines.next; curPtBlock = &FirstPtBlock; if (mode != MWPOLY_WINDING) { /* * for each scanline */ for (y = ET.ymin; y < ET.ymax; y++) { /* * Add a new edge to the active edge table when we * get to the next edge. */ if (pSLL != NULL && y == pSLL->scanline) { REGION_loadAET(&AET, pSLL->edgelist); pSLL = pSLL->next; } pPrevAET = &AET; pAET = AET.next; /* * for each active edge */ while (pAET) { pts->x = pAET->bres.minor_axis, pts->y = y; pts++, iPts++; /* * send out the buffer */ if (iPts == NUMPTSTOBUFFER) { tmpPtBlock = malloc( sizeof(POINTBLOCK)); if(!tmpPtBlock) { return 0; } curPtBlock->next = tmpPtBlock; curPtBlock = tmpPtBlock; pts = curPtBlock->pts; numFullPtBlocks++; iPts = 0; } EVALUATEEDGEEVENODD(pAET, pPrevAET, y); } REGION_InsertionSort(&AET); } } else { /* * for each scanline */ for (y = ET.ymin; y < ET.ymax; y++) { /* * Add a new edge to the active edge table when we * get to the next edge. */ if (pSLL != NULL && y == pSLL->scanline) { REGION_loadAET(&AET, pSLL->edgelist); REGION_computeWAET(&AET); pSLL = pSLL->next; } pPrevAET = &AET; pAET = AET.next; pWETE = pAET; /* * for each active edge */ while (pAET) { /* * add to the buffer only those edges that * are in the Winding active edge table. */ if (pWETE == pAET) { pts->x = pAET->bres.minor_axis, pts->y = y; pts++, iPts++; /* * send out the buffer */ if (iPts == NUMPTSTOBUFFER) { tmpPtBlock = malloc( sizeof(POINTBLOCK) ); if(!tmpPtBlock) { return 0; } curPtBlock->next = tmpPtBlock; curPtBlock = tmpPtBlock; pts = curPtBlock->pts; numFullPtBlocks++; iPts = 0; } pWETE = pWETE->nextWETE; } EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET); } /* * recompute the winding active edge table if * we just resorted or have exited an edge. */ if (REGION_InsertionSort(&AET) || fixWAET) { REGION_computeWAET(&AET); fixWAET = FALSE; } } } REGION_FreeStorage(SLLBlock.next); REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, rgn); for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) { tmpPtBlock = curPtBlock->next; free( curPtBlock ); curPtBlock = tmpPtBlock; } free( pETEs ); return rgn; }
/** * Set a clip region for future drawing actions. * Each pixel will be drawn only if lies in one or more of the contained * clip rectangles. All clip rectangles are modified * if necessary to lie within the device area. Call only after device * has been initialized. * * @param psd Drawing surface. * @param reg New clipping region. */ void GdSetClipRegion(PSD psd, MWCLIPREGION *reg) { if(clipregion) GdDestroyRegion(clipregion); if(!reg) reg = GdAllocRegion(); clipregion = reg; #if 0 MWRECT rc; /* Copy the clip table to our own static array, modifying each * rectangle as necesary to fit within the device area. If the clip * rectangle lies entirely outside of the device area, then skip it. */ while (count-- > 0) { MWCLIPRECT cr; MWCLIPRECT *rp = &cr; *rp = *table++; if (rp->x < 0) { rp->width += rp->x; rp->x = 0; } if (rp->y < 0) { rp->height += rp->y; rp->y = 0; } if ((rp->x >= psd->xvirtres) || (rp->width <= 0) || (rp->y >= psd->yvirtres) || (rp->height <= 0)) continue; if (rp->x + rp->width > psd->xvirtres) rp->width = psd->xvirtres - rp->x; if (rp->y + rp->height > psd->yvirtres) rp->height = psd->yvirtres - rp->y; rc.left = rp->x; rc.top = rp->y; rc.right = rp->x+rp->width; rc.bottom = rp->y+rp->height; GdUnionRectWithRegion(&rc, clipregion); } #endif /* If there were no surviving clip rectangles, then set the clip * cache to prevent all drawing. */ if (clipregion->numRects == 0) { clipminx = MIN_MWCOORD; clipminy = MIN_MWCOORD; clipmaxx = MAX_MWCOORD; clipmaxy = MAX_MWCOORD; clipresult = FALSE; return; } /* There was at least one valid clip rectangle. Default the clip * cache to be the first clip rectangle. */ clipminx = clipregion->rects[0].left; clipminy = clipregion->rects[0].top; clipmaxx = clipregion->rects[0].right - 1; clipmaxy = clipregion->rects[0].bottom - 1; clipresult = TRUE; }