aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/hw/xgl/xglfill.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/hw/xgl/xglfill.c')
-rw-r--r--xorg-server/hw/xgl/xglfill.c742
1 files changed, 742 insertions, 0 deletions
diff --git a/xorg-server/hw/xgl/xglfill.c b/xorg-server/hw/xgl/xglfill.c
new file mode 100644
index 000000000..64759ab2e
--- /dev/null
+++ b/xorg-server/hw/xgl/xglfill.c
@@ -0,0 +1,742 @@
+/*
+ * 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 <davidr@novell.com>
+ */
+
+#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)
+{
+ if (!nBox)
+ return;
+
+ if (!xglFill (pDrawable, pGC, NULL, x, y, width, height, pBox, nBox))
+ {
+ RegionRec region;
+
+ 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;
+ }
+
+ pPixmapPriv->damageBox = miEmptyBox;
+
+ while (nBox--)
+ {
+ fbFill (pDrawable, pGC,
+ pBox->x1, pBox->y1,
+ pBox->x2 - pBox->x1, pBox->y2 - pBox->y1);
+
+ REGION_INIT (pDrawable->pScreen, &region, pBox, 1);
+ xglAddSurfaceDamage (pDrawable, &region);
+ REGION_UNINIT (pDrawable->pScreen, &region);
+
+ 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)))
+ {
+ xglAddCurrentBitDamage (pDrawable);
+ 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)))
+ {
+ xglAddCurrentBitDamage (pDrawable);
+ 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);
+ xglAddCurrentBitDamage (pDrawable);
+ return TRUE;
+ }
+
+ GEOMETRY_UNINIT (&geometry);
+ return FALSE;
+}