/* * Copyright © 2004 David Reveman * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without * fee, provided that the above copyright notice appear in all copies * and that both that copyright notice and this permission notice * appear in supporting documentation, and that the name of * David Reveman not be used in advertising or publicity pertaining to * distribution of the software without specific, written prior permission. * David Reveman makes no representations about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. * * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN * NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: David Reveman */ #include "xgl.h" #include "gcstruct.h" #include "fb.h" Bool xglFill (DrawablePtr pDrawable, GCPtr pGC, xglGeometryPtr pGeometry, int x, int y, int width, int height, BoxPtr pBox, int nBox) { XGL_GC_PRIV (pGC); switch (pGC->fillStyle) { case FillSolid: if (xglSolid (pDrawable, pGCPriv->op, &pGCPriv->fg, pGeometry, x, y, width, height, pBox, nBox)) return TRUE; break; case FillStippled: case FillOpaqueStippled: break; case FillTiled: if (xglTile (pDrawable, pGCPriv->op, pGC->tile.pixmap, -(pGC->patOrg.x + pDrawable->x), -(pGC->patOrg.y + pDrawable->y), pGeometry, x, y, width, height, pBox, nBox)) return TRUE; break; } return FALSE; } static void xglFillBox (DrawablePtr pDrawable, GCPtr pGC, int x, int y, int width, int height, BoxPtr pBox, int nBox) { BoxRec box; if (!nBox) return; if (!xglFill (pDrawable, pGC, NULL, x, y, width, height, pBox, nBox)) { RegionRec region; RegionPtr pDamageRegion; glitz_surface_t *surface; int xOff, yOff; XGL_DRAWABLE_PIXMAP (pDrawable); XGL_PIXMAP_PRIV (pPixmap); if (!xglMapPixmapBits (pPixmap)) FatalError (XGL_SW_FAILURE_STRING); switch (pGC->fillStyle) { case FillSolid: break; case FillStippled: case FillOpaqueStippled: if (!xglSyncBits (&pGC->stipple->drawable, NullBox)) FatalError (XGL_SW_FAILURE_STRING); break; case FillTiled: if (!xglSyncBits (&pGC->tile.pixmap->drawable, NullBox)) FatalError (XGL_SW_FAILURE_STRING); break; } pDamageRegion = DamageRegion (pPixmapPriv->pDamage); XGL_GET_DRAWABLE (pDrawable, surface, xOff, yOff); pPixmapPriv->damageBox = miEmptyBox; while (nBox--) { fbFill (pDrawable, pGC, pBox->x1, pBox->y1, pBox->x2 - pBox->x1, pBox->y2 - pBox->y1); if (pPixmapPriv->format) { box.x1 = pBox->x1 + xOff; box.y1 = pBox->y1 + yOff; box.x2 = pBox->x2 + xOff; box.y2 = pBox->y2 + yOff; REGION_INIT (pDrawable->pScreen, ®ion, &box, 1); REGION_UNION (pDrawable->pScreen, pDamageRegion, pDamageRegion, ®ion); REGION_UNINIT (pDrawable->pScreen, ®ion); } pBox++; } } else xglAddCurrentBitDamage (pDrawable); } #define N_STACK_BOX 1024 static BoxPtr xglMoreBoxes (BoxPtr stackBox, BoxPtr heapBox, int nBoxes) { Bool stack = !heapBox; heapBox = xrealloc (heapBox, sizeof (BoxRec) * nBoxes); if (!heapBox) return NULL; if (stack) memcpy (heapBox, stackBox, sizeof (BoxRec) * N_STACK_BOX); return heapBox; } #define ADD_BOX(pBox, nBox, stackBox, heapBox, size, box) \ { \ if ((nBox) == (size)) \ { \ (size) *= 2; \ (heapBox) = xglMoreBoxes (stackBox, heapBox, size); \ if (heapBox) \ { \ (pBox) = (heapBox) + (nBox); \ *(pBox)++ = (box); \ (nBox)++; \ } \ } \ else \ { \ *(pBox)++ = (box); \ (nBox)++; \ } \ } void xglFillRect (DrawablePtr pDrawable, GCPtr pGC, int nrect, xRectangle *prect) { RegionPtr pClip = pGC->pCompositeClip; BoxPtr pClipBox; BoxPtr pExtent = REGION_EXTENTS (pGC->pScreen, pClip); BoxRec part, full; BoxPtr heapBox = NULL; BoxRec stackBox[N_STACK_BOX]; int size = N_STACK_BOX; BoxPtr pBox = stackBox; int nClip, nBox = 0; while (nrect--) { full.x1 = prect->x + pDrawable->x; full.y1 = prect->y + pDrawable->y; full.x2 = full.x1 + (int) prect->width; full.y2 = full.y1 + (int) prect->height; prect++; if (full.x1 < pExtent->x1) full.x1 = pExtent->x1; if (full.y1 < pExtent->y1) full.y1 = pExtent->y1; if (full.x2 > pExtent->x2) full.x2 = pExtent->x2; if (full.y2 > pExtent->y2) full.y2 = pExtent->y2; if (full.x1 >= full.x2 || full.y1 >= full.y2) continue; nClip = REGION_NUM_RECTS (pClip); if (nClip == 1) { ADD_BOX (pBox, nBox, stackBox, heapBox, size, full); } else { pClipBox = REGION_RECTS (pClip); while (nClip--) { part = *pClipBox++; if (part.x1 < full.x1) part.x1 = full.x1; if (part.y1 < full.y1) part.y1 = full.y1; if (part.x2 > full.x2) part.x2 = full.x2; if (part.y2 > full.y2) part.y2 = full.y2; if (part.x1 < part.x2 && part.y1 < part.y2) ADD_BOX (pBox, nBox, stackBox, heapBox, size, part); } } } xglFillBox (pDrawable, pGC, pExtent->x1, pExtent->y1, pExtent->x2 - pExtent->x1, pExtent->y2 - pExtent->y1, (heapBox) ? heapBox : stackBox, nBox); if (heapBox) xfree (heapBox); } void xglFillSpan (DrawablePtr pDrawable, GCPtr pGC, int n, DDXPointPtr ppt, int *pwidth) { RegionPtr pClip = pGC->pCompositeClip; BoxPtr pClipBox; BoxPtr pExtent = REGION_EXTENTS (pGC->pScreen, pClip); BoxRec part, full; BoxPtr heapBox = NULL; BoxRec stackBox[N_STACK_BOX]; int size = N_STACK_BOX; BoxPtr pBox = stackBox; int nClip, nBox = 0; while (n--) { full.x1 = ppt->x; full.y1 = ppt->y; full.x2 = full.x1 + *pwidth; full.y2 = full.y1 + 1; pwidth++; ppt++; if (full.x1 < pExtent->x1) full.x1 = pExtent->x1; if (full.y1 < pExtent->y1) full.y1 = pExtent->y1; if (full.x2 > pExtent->x2) full.x2 = pExtent->x2; if (full.y2 > pExtent->y2) full.y2 = pExtent->y2; if (full.x1 >= full.x2 || full.y1 >= full.y2) continue; nClip = REGION_NUM_RECTS (pClip); if (nClip == 1) { ADD_BOX (pBox, nBox, stackBox, heapBox, size, full); } else { pClipBox = REGION_RECTS (pClip); while (nClip--) { part = *pClipBox++; if (part.x1 < full.x1) part.x1 = full.x1; if (part.y1 < full.y1) part.y1 = full.y1; if (part.x2 > full.x2) part.x2 = full.x2; if (part.y2 > full.y2) part.y2 = full.y2; if (part.x1 < part.x2 && part.y1 < part.y2) ADD_BOX (pBox, nBox, stackBox, heapBox, size, part); } } } xglFillBox (pDrawable, pGC, pExtent->x1, pExtent->y1, pExtent->x2 - pExtent->x1, pExtent->y2 - pExtent->y1, (heapBox) ? heapBox : stackBox, nBox); if (heapBox) xfree (heapBox); } Bool xglFillLine (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppt) { RegionPtr pClip = pGC->pCompositeClip; BoxPtr pExtent = REGION_EXTENTS (pGC->pScreen, pClip); Bool coincidentEndpoints = FALSE; Bool horizontalAndVertical = TRUE; DDXPointPtr pptTmp; int nptTmp; DDXPointRec pt; xglGeometryPtr pGeometry; XGL_SCREEN_PRIV (pGC->pScreen); if (npt < 2) return TRUE; pt = *ppt; nptTmp = npt - 1; pptTmp = ppt + 1; if (mode == CoordModePrevious) { while (nptTmp--) { if (pptTmp->x && pptTmp->y) horizontalAndVertical = FALSE; pt.x += pptTmp->x; pt.y += pptTmp->y; pptTmp++; } if (pt.x == ppt->x && pt.y == ppt->y) coincidentEndpoints = TRUE; } else { while (nptTmp--) { if (pptTmp->x != pt.x && pptTmp->y != pt.y) { horizontalAndVertical = FALSE; break; } pt = *pptTmp++; } if (ppt[npt - 1].x == ppt->x && ppt[npt - 1].y == ppt->y) coincidentEndpoints = TRUE; } if (horizontalAndVertical) { BoxPtr pClipBox; BoxRec part, full; BoxPtr heapBox = NULL; BoxRec stackBox[N_STACK_BOX]; int size = N_STACK_BOX; BoxPtr pBox = stackBox; int nClip, nBox = 0; int dx, dy; pt = *ppt; ppt++; npt--; while (npt--) { if (mode == CoordModePrevious) { dx = ppt->x; dy = ppt->y; } else { dx = ppt->x - pt.x; dy = ppt->y - pt.y; } if (dx) { if (dx > 0) { full.x1 = pt.x + pDrawable->x; if (npt || coincidentEndpoints) full.x2 = full.x1 + dx; else full.x2 = full.x1 + dx + 1; } else { full.x2 = pt.x + pDrawable->x + 1; if (npt || coincidentEndpoints) full.x1 = full.x2 + dx; else full.x1 = full.x2 + dx - 1; } full.y1 = pt.y + pDrawable->y; full.y2 = full.y1 + 1; } else { if (dy > 0) { full.y1 = pt.y + pDrawable->y; if (npt || coincidentEndpoints) full.y2 = full.y1 + dy; else full.y2 = full.y1 + dy + 1; } else { full.y2 = pt.y + pDrawable->y + 1; if (npt || coincidentEndpoints) full.y1 = full.y2 + dy; else full.y1 = full.y2 + dy - 1; } full.x1 = pt.x + pDrawable->x; full.x2 = full.x1 + 1; } pt.x += dx; pt.y += dy; ppt++; if (full.x1 < pExtent->x1) full.x1 = pExtent->x1; if (full.y1 < pExtent->y1) full.y1 = pExtent->y1; if (full.x2 > pExtent->x2) full.x2 = pExtent->x2; if (full.y2 > pExtent->y2) full.y2 = pExtent->y2; if (full.x1 >= full.x2 || full.y1 >= full.y2) continue; nClip = REGION_NUM_RECTS (pClip); if (nClip == 1) { ADD_BOX (pBox, nBox, stackBox, heapBox, size, full); } else { pClipBox = REGION_RECTS (pClip); while (nClip--) { part = *pClipBox++; if (part.x1 < full.x1) part.x1 = full.x1; if (part.y1 < full.y1) part.y1 = full.y1; if (part.x2 > full.x2) part.x2 = full.x2; if (part.y2 > full.y2) part.y2 = full.y2; if (part.x1 < part.x2 && part.y1 < part.y2) ADD_BOX (pBox, nBox, stackBox, heapBox, size, part); } } } xglFillBox (pDrawable, pGC, pExtent->x1, pExtent->y1, pExtent->x2 - pExtent->x1, pExtent->y2 - pExtent->y1, (heapBox) ? heapBox : stackBox, nBox); if (heapBox) xfree (heapBox); return TRUE; } if (!pScreenPriv->lines) return FALSE; if (coincidentEndpoints) npt--; pGeometry = xglGetScratchVertexGeometry (pGC->pScreen, npt); GEOMETRY_ADD_LINE (pGC->pScreen, pGeometry, coincidentEndpoints, mode, npt, ppt); if (coincidentEndpoints) GEOMETRY_SET_VERTEX_PRIMITIVE (pGeometry, GLITZ_PRIMITIVE_LINE_LOOP); else GEOMETRY_SET_VERTEX_PRIMITIVE (pGeometry, GLITZ_PRIMITIVE_LINE_STRIP); /* Lines need a 0.5 translate */ GEOMETRY_TRANSLATE_FIXED (pGeometry, 1 << 15, 1 << 15); GEOMETRY_TRANSLATE (pGeometry, pDrawable->x, pDrawable->y); pExtent = REGION_EXTENTS (pDrawable->pScreen, pGC->pCompositeClip); if (xglFill (pDrawable, pGC, pGeometry, pExtent->x1, pExtent->y1, pExtent->x2 - pExtent->x1, pExtent->y2 - pExtent->y1, REGION_RECTS (pGC->pCompositeClip), REGION_NUM_RECTS (pGC->pCompositeClip))) return TRUE; return FALSE; } Bool xglFillSegment (DrawablePtr pDrawable, GCPtr pGC, int nSegInit, xSegment *pSegInit) { RegionPtr pClip = pGC->pCompositeClip; BoxPtr pExtent = REGION_EXTENTS (pGC->pScreen, pClip); Bool horizontalAndVertical = TRUE; xglGeometryPtr pGeometry; xSegment *pSeg; int nSeg; XGL_SCREEN_PRIV (pGC->pScreen); if (nSegInit < 1) return TRUE; pSeg = pSegInit; nSeg = nSegInit; while (nSeg--) { if (pSeg->x1 != pSeg->x2 && pSeg->y1 != pSeg->y2) horizontalAndVertical = FALSE; pSeg++; } if (horizontalAndVertical) { BoxPtr pClipBox; BoxRec part, full; BoxPtr heapBox = NULL; BoxRec stackBox[N_STACK_BOX]; int size = N_STACK_BOX; BoxPtr pBox = stackBox; int nClip, nBox = 0; while (nSegInit--) { if (pSegInit->x1 != pSegInit->x2) { if (pSegInit->x1 < pSegInit->x2) { full.x1 = pSegInit->x1; full.x2 = pSegInit->x2; } else { full.x1 = pSegInit->x2; full.x2 = pSegInit->x1; } full.x1 += pDrawable->x; full.x2 += pDrawable->x + 1; full.y1 = pSegInit->y1 + pDrawable->y; full.y2 = full.y1 + 1; } else { if (pSegInit->y1 < pSegInit->y2) { full.y1 = pSegInit->y1; full.y2 = pSegInit->y2; } else { full.y1 = pSegInit->y2; full.y2 = pSegInit->y1; } full.y1 += pDrawable->y; full.y2 += pDrawable->y + 1; full.x1 = pSegInit->x1 + pDrawable->x; full.x2 = full.x1 + 1; } pSegInit++; if (full.x1 < pExtent->x1) full.x1 = pExtent->x1; if (full.y1 < pExtent->y1) full.y1 = pExtent->y1; if (full.x2 > pExtent->x2) full.x2 = pExtent->x2; if (full.y2 > pExtent->y2) full.y2 = pExtent->y2; if (full.x1 >= full.x2 || full.y1 >= full.y2) continue; nClip = REGION_NUM_RECTS (pClip); if (nClip == 1) { ADD_BOX (pBox, nBox, stackBox, heapBox, size, full); } else { pClipBox = REGION_RECTS (pClip); while (nClip--) { part = *pClipBox++; if (part.x1 < full.x1) part.x1 = full.x1; if (part.y1 < full.y1) part.y1 = full.y1; if (part.x2 > full.x2) part.x2 = full.x2; if (part.y2 > full.y2) part.y2 = full.y2; if (part.x1 < part.x2 && part.y1 < part.y2) ADD_BOX (pBox, nBox, stackBox, heapBox, size, part); } } } xglFillBox (pDrawable, pGC, pExtent->x1, pExtent->y1, pExtent->x2 - pExtent->x1, pExtent->y2 - pExtent->y1, (heapBox) ? heapBox : stackBox, nBox); if (heapBox) xfree (heapBox); return TRUE; } if (!pScreenPriv->lines) return FALSE; pGeometry = xglGetScratchVertexGeometry (pGC->pScreen, 2 * nSegInit); GEOMETRY_ADD_SEGMENT (pGC->pScreen, pGeometry, nSegInit, pSegInit); /* Line segments need 0.5 translate */ GEOMETRY_TRANSLATE_FIXED (pGeometry, 1 << 15, 1 << 15); GEOMETRY_SET_VERTEX_PRIMITIVE (pGeometry, GLITZ_PRIMITIVE_LINES); GEOMETRY_TRANSLATE (pGeometry, pDrawable->x, pDrawable->y); if (xglFill (pDrawable, pGC, pGeometry, pExtent->x1, pExtent->y1, pExtent->x2 - pExtent->x1, pExtent->y2 - pExtent->y1, REGION_RECTS (pGC->pCompositeClip), REGION_NUM_RECTS (pGC->pCompositeClip))) return TRUE; return FALSE; } Bool xglFillGlyph (DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nGlyph, CharInfoPtr *ppci, pointer pglyphBase) { BoxPtr pExtent; xglGeometryRec geometry; if (nGlyph < 1) return TRUE; pExtent = REGION_EXTENTS (pDrawable->pScreen, pGC->pCompositeClip); x += pDrawable->x; y += pDrawable->y; GEOMETRY_INIT (pDrawable->pScreen, &geometry, GLITZ_GEOMETRY_TYPE_BITMAP, GEOMETRY_USAGE_SYSMEM, 0); GEOMETRY_FOR_GLYPH (pDrawable->pScreen, &geometry, nGlyph, ppci, pglyphBase); GEOMETRY_TRANSLATE (&geometry, x, y); if (xglFill (pDrawable, pGC, &geometry, pExtent->x1, pExtent->y1, pExtent->x2 - pExtent->x1, pExtent->y2 - pExtent->y1, REGION_RECTS (pGC->pCompositeClip), REGION_NUM_RECTS (pGC->pCompositeClip))) { GEOMETRY_UNINIT (&geometry); return TRUE; } GEOMETRY_UNINIT (&geometry); return FALSE; }