+/*
+ * Command line: opannotate --source
+ *
+ * Interpretation of command line:
+ * Output annotated source file with samples
+ * Output all files
+ *
+ * CPU: Core 2, speed 2133.49 MHz (estimated)
+ * Counted CPU_CLK_UNHALTED events (Clock cycles when not halted) with a unit mask of 0x00 (Unhalted core cycles) count 100000
+ */
+/*
+ * Total samples for file : "/home/cworth/src/xorg/driver/xf86-video-intel/src/i830_accel.c"
+ *
+ * 31562 34.3831
+ */
+
+
+ :/*
+ : * XXX So far, for GXxor this is about 40% of the speed of SW, but CPU
+ : * utilisation falls from 95% to < 5%.
+ : */
+ :
+ :#ifdef HAVE_CONFIG_H
+ :#include "config.h"
+ :#endif
+ :
+ :/**************************************************************************
+ :
+ :Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+ :All Rights Reserved.
+ :
+ :Permission is hereby granted, free of charge, to any person obtaining a
+ :copy of this software and associated documentation files (the
+ :"Software"), to deal in the Software without restriction, including
+ :without limitation the rights to use, copy, modify, merge, publish,
+ :distribute, sub license, and/or sell copies of the Software, and to
+ :permit persons to whom the Software is furnished to do so, subject to
+ :the following conditions:
+ :
+ :The above copyright notice and this permission notice (including the
+ :next paragraph) shall be included in all copies or substantial portions
+ :of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ :OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ :MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ :IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ :ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ :TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ :SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :**************************************************************************/
+ :/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i830_accel.c,v 1.8 2003/04/24 18:00:24 eich Exp $ */
+ :
+ :/*
+ : * Reformatted with GNU indent (2.2.8), using the following options:
+ : *
+ : * -bad -bap -c41 -cd0 -ncdb -ci6 -cli0 -cp0 -ncs -d0 -di3 -i3 -ip3 -l78
+ : * -lp -npcs -psl -sob -ss -br -ce -sc -hnl
+ : *
+ : * This provides a good match with the original i810 code and preferred
+ : * XFree86 formatting conventions.
+ : *
+ : * When editing this driver, please follow the existing formatting, and edit
+ : * with <TAB> characters expanded at 8-column intervals.
+ : */
+ :
+ :/*
+ : * Authors:
+ : * Keith Whitwell <keith@tungstengraphics.com>
+ : *
+ : */
+ :
+ :#include "xf86.h"
+ :#include "xaarop.h"
+ :#include "i830.h"
+ :#include "i810_reg.h"
+ :#include "i830_debug.h"
+ :
+ :unsigned long
+ :intel_get_pixmap_offset(PixmapPtr pPix)
+ 15 0.0163 :{ /* intel_get_pixmap_offset total: 77 0.0839 */
+ : ScreenPtr pScreen = pPix->drawable.pScreen;
+ : ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ 27 0.0294 : I830Ptr pI830 = I830PTR(pScrn);
+ :
+ :#ifdef I830_USE_EXA
+ 24 0.0261 : if (pI830->useEXA)
+ 4 0.0044 : return exaGetPixmapOffset(pPix);
+ :#endif
+ : return (unsigned long)pPix->devPrivate.ptr - (unsigned long)pI830->FbBase;
+ 7 0.0076 :}
+ :
+ :unsigned long
+ :intel_get_pixmap_pitch(PixmapPtr pPix)
+ 12 0.0131 :{ /* intel_get_pixmap_pitch total: 83 0.0904 */
+ : ScreenPtr pScreen = pPix->drawable.pScreen;
+ : ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ : I830Ptr pI830 = I830PTR(pScrn);
+ :
+ :#ifdef I830_USE_EXA
+ 57 0.0621 : if (pI830->useEXA)
+ 4 0.0044 : return exaGetPixmapPitch(pPix);
+ :#endif
+ :#ifdef I830_USE_XAA
+ : return (unsigned long)pPix->devKind;
+ :#endif
+ 10 0.0109 :}
+ :
+ :int
+ :I830WaitLpRing(ScrnInfoPtr pScrn, int n, int timeout_millis)
+ 10 0.0109 :{ /* I830WaitLpRing total: 31130 33.9125 */
+ 2 0.0022 : I830Ptr pI830 = I830PTR(pScrn);
+ 1 0.0011 : I830RingBuffer *ring = pI830->LpRing;
+ : int iters = 0;
+ : unsigned int start = 0;
+ : unsigned int now = 0;
+ : int last_head = 0;
+ : unsigned int first = 0;
+ :
+ : /* If your system hasn't moved the head pointer in 2 seconds, I'm going to
+ : * call it crashed.
+ : */
+ : if (timeout_millis == 0)
+ : timeout_millis = 2000;
+ :
+ : if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) {
+ : ErrorF("I830WaitLpRing %d\n", n);
+ : first = GetTimeInMillis();
+ : }
+ :
+ 383 0.4172 : while (ring->space < n) {
+ 217 0.2364 : ring->head = INREG(LP_RING + RING_HEAD) & I830_HEAD_MASK;
+ 30204 32.9038 : ring->space = ring->head - (ring->tail + 8);
+ :
+ : if (ring->space < 0)
+ 145 0.1580 : ring->space += ring->mem->size;
+ :
+ 93 0.1013 : iters++;
+ : if ((iters & 0xfff) == 0) {
+ : now = GetTimeInMillis();
+ : if (start == 0 || now < start || ring->head != last_head) {
+ : if (I810_DEBUG & DEBUG_VERBOSE_ACCEL)
+ : if (now > start)
+ : ErrorF("space: %d wanted %d\n", ring->space, n);
+ : start = now;
+ : last_head = ring->head;
+ : } else if (now - start > timeout_millis) {
+ : ErrorF("Error in I830WaitLpRing(), timeout for %d seconds\n",
+ : timeout_millis/1000);
+ : if (IS_I965G(pI830))
+ : i965_dump_error_state(pScrn);
+ : else
+ : i830_dump_error_state(pScrn);
+ : ErrorF("space: %d wanted %d\n", ring->space, n);
+ :#ifdef XF86DRI
+ : if (pI830->directRenderingEnabled) {
+ : DRIUnlock(screenInfo.screens[pScrn->scrnIndex]);
+ : DRICloseScreen(screenInfo.screens[pScrn->scrnIndex]);
+ : }
+ :#endif
+ :#ifdef I830_USE_XAA
+ : pI830->AccelInfoRec = NULL; /* Stops recursive behavior */
+ :#endif
+ :#ifdef I830_USE_EXA
+ : pI830->EXADriverPtr = NULL;
+ :#endif
+ 1 0.0011 : FatalError("lockup\n");
+ : }
+ : }
+ : DELAY(10);
+ : }
+ :
+ : if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) {
+ : now = GetTimeInMillis();
+ : if (now - first) {
+ : ErrorF("Elapsed %u ms\n", now - first);
+ : ErrorF("space: %d wanted %d\n", ring->space, n);
+ : }
+ : }
+ :
+ : return iters;
+ 74 0.0806 :}
+ :
+ :void
+ :I830Sync(ScrnInfoPtr pScrn)
+ 6 0.0065 :{ /* I830Sync total: 272 0.2963 */
+ 2 0.0022 : I830Ptr pI830 = I830PTR(pScrn);
+ : int flags = MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE;
+ :
+ : if (I810_DEBUG & (DEBUG_VERBOSE_ACCEL | DEBUG_VERBOSE_SYNC))
+ : ErrorF("I830Sync\n");
+ :
+ :#ifdef XF86DRI
+ : /* VT switching tries to do this.
+ : */
+ : if (!pI830->LockHeld && pI830->directRenderingEnabled) {
+ : return;
+ : }
+ :#endif
+ :
+ 1 0.0011 : if (pI830->entityPrivate && !pI830->entityPrivate->RingRunning) return;
+ :
+ 6 0.0065 : if (IS_I965G(pI830))
+ : flags = 0;
+ :
+ : /* Send a flush instruction and then wait till the ring is empty.
+ : * This is stronger than waiting for the blitter to finish as it also
+ : * flushes the internal graphics caches.
+ : */
+ :
+ : {
+ 3 0.0033 : BEGIN_LP_RING(2);
+ 11 0.0120 : OUT_RING(MI_FLUSH | flags);
+ 11 0.0120 : OUT_RING(MI_NOOP); /* pad to quadword */
+ 17 0.0185 : ADVANCE_LP_RING();
+ : }
+ :
+ 168 0.1830 : I830WaitLpRing(pScrn, pI830->LpRing->mem->size - 8, 0);
+ :
+ 37 0.0403 : pI830->LpRing->space = pI830->LpRing->mem->size - 8;
+ 1 0.0011 : pI830->nextColorExpandBuf = 0;
+ 9 0.0098 :}
+ :
+ :void
+ :I830EmitFlush(ScrnInfoPtr pScrn)
+ :{
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : int flags = MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE;
+ :
+ : if (IS_I965G(pI830))
+ : flags = 0;
+ :
+ : {
+ : BEGIN_LP_RING(2);
+ : OUT_RING(MI_FLUSH | flags);
+ : OUT_RING(MI_NOOP); /* pad to quadword */
+ : ADVANCE_LP_RING();
+ : }
+ :}
+ :
+ :void
+ :I830SelectBuffer(ScrnInfoPtr pScrn, int buffer)
+ :{
+ : I830Ptr pI830 = I830PTR(pScrn);
+ :
+ : switch (buffer) {
+ :#ifdef XF86DRI
+ : case I830_SELECT_BACK:
+ : pI830->bufferOffset = pI830->back_buffer->offset;
+ : break;
+ : case I830_SELECT_THIRD:
+ : pI830->bufferOffset = pI830->third_buffer->offset;
+ : break;
+ : case I830_SELECT_DEPTH:
+ : pI830->bufferOffset = pI830->depth_buffer->offset;
+ : break;
+ :#endif
+ : default:
+ : case I830_SELECT_FRONT:
+ : pI830->bufferOffset = pScrn->fbOffset;
+ : break;
+ : }
+ :
+ : if (I810_DEBUG & DEBUG_VERBOSE_ACCEL)
+ : ErrorF("I830SelectBuffer %d --> offset %x\n",
+ : buffer, pI830->bufferOffset);
+ :}
+ :
+ :void
+ :I830RefreshRing(ScrnInfoPtr pScrn)
+ :{
+ : I830Ptr pI830 = I830PTR(pScrn);
+ :
+ : pI830->LpRing->head = INREG(LP_RING + RING_HEAD) & I830_HEAD_MASK;
+ : pI830->LpRing->tail = INREG(LP_RING + RING_TAIL);
+ : pI830->LpRing->space = pI830->LpRing->head - (pI830->LpRing->tail + 8);
+ : if (pI830->LpRing->space < 0)
+ : pI830->LpRing->space += pI830->LpRing->mem->size;
+ : i830MarkSync(pScrn);
+ :}
+ :
+ :/* The following function sets up the supported acceleration. Call it
+ : * from the FbInit() function in the SVGA driver, or before ScreenInit
+ : * in a monolithic server.
+ : */
+ :Bool
+ :I830AccelInit(ScreenPtr pScreen)
+ :{
+ :#ifdef I830_USE_EXA
+ : ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ : I830Ptr pI830 = I830PTR(pScrn);
+ :
+ : if (pI830->useEXA)
+ : return I830EXAInit(pScreen);
+ :#endif
+ :#ifdef I830_USE_XAA
+ : return I830XAAInit(pScreen);
+ :#endif
+ : return FALSE;
+ :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/driver/xf86-video-intel/src/i965_render.c"
+ *
+ * 12731 13.8689
+ */
+
+
+ :/*
+ : * Copyright © 2006 Intel Corporation
+ : *
+ : * Permission is hereby granted, free of charge, to any person obtaining a
+ : * copy of this software and associated documentation files (the "Software"),
+ : * to deal in the Software without restriction, including without limitation
+ : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ : * and/or sell copies of the Software, and to permit persons to whom the
+ : * Software is furnished to do so, subject to the following conditions:
+ : *
+ : * The above copyright notice and this permission notice (including the next
+ : * paragraph) shall be included in all copies or substantial portions of the
+ : * Software.
+ : *
+ : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ : * SOFTWARE.
+ : *
+ : * Authors:
+ : * Wang Zhenyu <zhenyu.z.wang@intel.com>
+ : * Eric Anholt <eric@anholt.net>
+ : *
+ : */
+ :
+ :#ifdef HAVE_CONFIG_H
+ :#include "config.h"
+ :#endif
+ :
+ :#include <assert.h>
+ :#include "xf86.h"
+ :#include "i830.h"
+ :#include "i915_reg.h"
+ :
+ :/* bring in brw structs */
+ :#include "brw_defines.h"
+ :#include "brw_structs.h"
+ :
+ :#ifdef I830DEBUG
+ :#define DEBUG_I830FALLBACK 1
+ :#endif
+ :
+ :#ifdef DEBUG_I830FALLBACK
+ :#define I830FALLBACK(s, arg...) \
+ :do { \
+ : DPRINTF(PFX, "EXA fallback: " s "\n", ##arg); \
+ : return FALSE; \
+ :} while(0)
+ :#else
+ :#define I830FALLBACK(s, arg...) \
+ :do { \
+ : return FALSE; \
+ :} while(0)
+ :#endif
+ :
+ :struct blendinfo {
+ : Bool dst_alpha;
+ : Bool src_alpha;
+ : CARD32 src_blend;
+ : CARD32 dst_blend;
+ :};
+ :
+ :struct formatinfo {
+ : int fmt;
+ : CARD32 card_fmt;
+ :};
+ :
+ :// refer vol2, 3d rasterization 3.8.1
+ :
+ :/* defined in brw_defines.h */
+ :static struct blendinfo i965_blend_op[] = {
+ : /* Clear */
+ : {0, 0, BRW_BLENDFACTOR_ZERO, BRW_BLENDFACTOR_ZERO},
+ : /* Src */
+ : {0, 0, BRW_BLENDFACTOR_ONE, BRW_BLENDFACTOR_ZERO},
+ : /* Dst */
+ : {0, 0, BRW_BLENDFACTOR_ZERO, BRW_BLENDFACTOR_ONE},
+ : /* Over */
+ : {0, 1, BRW_BLENDFACTOR_ONE, BRW_BLENDFACTOR_INV_SRC_ALPHA},
+ : /* OverReverse */
+ : {1, 0, BRW_BLENDFACTOR_INV_DST_ALPHA, BRW_BLENDFACTOR_ONE},
+ : /* In */
+ : {1, 0, BRW_BLENDFACTOR_DST_ALPHA, BRW_BLENDFACTOR_ZERO},
+ : /* InReverse */
+ : {0, 1, BRW_BLENDFACTOR_ZERO, BRW_BLENDFACTOR_SRC_ALPHA},
+ : /* Out */
+ : {1, 0, BRW_BLENDFACTOR_INV_DST_ALPHA, BRW_BLENDFACTOR_ZERO},
+ : /* OutReverse */
+ : {0, 1, BRW_BLENDFACTOR_ZERO, BRW_BLENDFACTOR_INV_SRC_ALPHA},
+ : /* Atop */
+ : {1, 1, BRW_BLENDFACTOR_DST_ALPHA, BRW_BLENDFACTOR_INV_SRC_ALPHA},
+ : /* AtopReverse */
+ : {1, 1, BRW_BLENDFACTOR_INV_DST_ALPHA, BRW_BLENDFACTOR_SRC_ALPHA},
+ : /* Xor */
+ : {1, 1, BRW_BLENDFACTOR_INV_DST_ALPHA, BRW_BLENDFACTOR_INV_SRC_ALPHA},
+ : /* Add */
+ : {0, 0, BRW_BLENDFACTOR_ONE, BRW_BLENDFACTOR_ONE},
+ :};
+ :
+ :/* FIXME: surface format defined in brw_defines.h, shared Sampling engine
+ : * 1.7.2
+ : */
+ :static struct formatinfo i965_tex_formats[] = {
+ : {PICT_a8r8g8b8, BRW_SURFACEFORMAT_B8G8R8A8_UNORM },
+ : {PICT_x8r8g8b8, BRW_SURFACEFORMAT_B8G8R8X8_UNORM },
+ : {PICT_a8b8g8r8, BRW_SURFACEFORMAT_R8G8B8A8_UNORM },
+ : {PICT_x8b8g8r8, BRW_SURFACEFORMAT_R8G8B8X8_UNORM },
+ : {PICT_r5g6b5, BRW_SURFACEFORMAT_B5G6R5_UNORM },
+ : {PICT_a1r5g5b5, BRW_SURFACEFORMAT_B5G5R5A1_UNORM },
+ : {PICT_a8, BRW_SURFACEFORMAT_A8_UNORM },
+ :};
+ :
+ :static void i965_get_blend_cntl(int op, PicturePtr pMask, CARD32 dst_format,
+ : CARD32 *sblend, CARD32 *dblend)
+ :{
+ :
+ : *sblend = i965_blend_op[op].src_blend;
+ : *dblend = i965_blend_op[op].dst_blend;
+ :
+ : /* If there's no dst alpha channel, adjust the blend op so that we'll treat
+ : * it as always 1.
+ : */
+ : if (PICT_FORMAT_A(dst_format) == 0 && i965_blend_op[op].dst_alpha) {
+ : if (*sblend == BRW_BLENDFACTOR_DST_ALPHA)
+ : *sblend = BRW_BLENDFACTOR_ONE;
+ : else if (*sblend == BRW_BLENDFACTOR_INV_DST_ALPHA)
+ : *sblend = BRW_BLENDFACTOR_ZERO;
+ : }
+ :
+ : /* If the source alpha is being used, then we should only be in a case where
+ : * the source blend factor is 0, and the source blend value is the mask
+ : * channels multiplied by the source picture's alpha.
+ : */
+ : if (pMask && pMask->componentAlpha && PICT_FORMAT_RGB(pMask->format)
+ : && i965_blend_op[op].src_alpha) {
+ : if (*dblend == BRW_BLENDFACTOR_SRC_ALPHA) {
+ : *dblend = BRW_BLENDFACTOR_SRC_COLOR;
+ : } else if (*dblend == BRW_BLENDFACTOR_INV_SRC_ALPHA) {
+ : *dblend = BRW_BLENDFACTOR_INV_SRC_COLOR;
+ : }
+ : }
+ :
+ :}
+ :
+ :static Bool i965_get_dest_format(PicturePtr pDstPicture, CARD32 *dst_format)
+ 8 0.0087 :{ /* i965_get_dest_format total: 28 0.0305 */
+ 10 0.0109 : switch (pDstPicture->format) {
+ : case PICT_a8r8g8b8:
+ : case PICT_x8r8g8b8:
+ 1 0.0011 : *dst_format = BRW_SURFACEFORMAT_B8G8R8A8_UNORM;
+ : break;
+ : case PICT_r5g6b5:
+ : *dst_format = BRW_SURFACEFORMAT_B5G6R5_UNORM;
+ : break;
+ : case PICT_a1r5g5b5:
+ : *dst_format = BRW_SURFACEFORMAT_B5G5R5A1_UNORM;
+ : break;
+ : case PICT_x1r5g5b5:
+ : *dst_format = BRW_SURFACEFORMAT_B5G5R5X1_UNORM;
+ : break;
+ : /* COLR_BUF_8BIT is special for YUV surfaces. While we may end up being
+ : * able to use it depending on how the hardware implements it, disable it
+ : * for now while we don't know what exactly it does (what channel does it
+ : * read from?
+ : */
+ : /*
+ : case PICT_a8:
+ : *dst_format = COLR_BUF_8BIT;
+ : break;
+ : */
+ : case PICT_a4r4g4b4:
+ : case PICT_x4r4g4b4:
+ : *dst_format = BRW_SURFACEFORMAT_B4G4R4A4_UNORM;
+ : break;
+ : default:
+ : I830FALLBACK("Unsupported dest format 0x%x\n",
+ : (int)pDstPicture->format);
+ : }
+ :
+ : return TRUE;
+ 9 0.0098 :}
+ :
+ :static Bool i965_check_composite_texture(PicturePtr pPict, int unit)
+ 28 0.0305 :{ /* i965_check_composite_texture total: 73 0.0795 */
+ 3 0.0033 : int w = pPict->pDrawable->width;
+ : int h = pPict->pDrawable->height;
+ : int i;
+ :
+ 15 0.0163 : if ((w > 0x7ff) || (h > 0x7ff))
+ : I830FALLBACK("Picture w/h too large (%dx%d)\n", w, h);
+ :
+ : for (i = 0; i < sizeof(i965_tex_formats) / sizeof(i965_tex_formats[0]);
+ : i++)
+ : {
+ 9 0.0098 : if (i965_tex_formats[i].fmt == pPict->format)
+ : break;
+ : }
+ 7 0.0076 : if (i == sizeof(i965_tex_formats) / sizeof(i965_tex_formats[0]))
+ : I830FALLBACK("Unsupported picture format 0x%x\n",
+ : (int)pPict->format);
+ :
+ 4 0.0044 : if (pPict->repeat && pPict->repeatType != RepeatNormal)
+ : I830FALLBACK("extended repeat (%d) not supported\n",
+ : pPict->repeatType);
+ :
+ : if (pPict->filter != PictFilterNearest &&
+ : pPict->filter != PictFilterBilinear)
+ : {
+ : I830FALLBACK("Unsupported filter 0x%x\n", pPict->filter);
+ : }
+ :
+ : return TRUE;
+ 7 0.0076 :}
+ :
+ :Bool
+ :i965_check_composite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
+ : PicturePtr pDstPicture)
+ 9 0.0098 :{ /* i965_check_composite total: 54 0.0588 */
+ : CARD32 tmp1;
+ :
+ : /* Check for unsupported compositing operations. */
+ : if (op >= sizeof(i965_blend_op) / sizeof(i965_blend_op[0]))
+ : I830FALLBACK("Unsupported Composite op 0x%x\n", op);
+ :
+ 4 0.0044 : if (pMaskPicture && pMaskPicture->componentAlpha &&
+ : PICT_FORMAT_RGB(pMaskPicture->format)) {
+ : /* Check if it's component alpha that relies on a source alpha and on
+ : * the source value. We can only get one of those into the single
+ : * source value that we get to blend with.
+ : */
+ 11 0.0120 : if (i965_blend_op[op].src_alpha &&
+ : (i965_blend_op[op].src_blend != BRW_BLENDFACTOR_ZERO))
+ : {
+ : I830FALLBACK("Component alpha not supported with source "
+ : "alpha and source value blending.\n");
+ : }
+ : }
+ :
+ 9 0.0098 : if (!i965_check_composite_texture(pSrcPicture, 0))
+ : I830FALLBACK("Check Src picture texture\n");
+ 2 0.0022 : if (pMaskPicture != NULL && !i965_check_composite_texture(pMaskPicture, 1))
+ : I830FALLBACK("Check Mask picture texture\n");
+ :
+ 9 0.0098 : if (!i965_get_dest_format(pDstPicture, &tmp1))
+ : I830FALLBACK("Get Color buffer format\n");
+ :
+ : return TRUE;
+ :
+ 10 0.0109 :}
+ :
+ :#define ALIGN(i,m) (((i) + (m) - 1) & ~((m) - 1))
+ :#define MIN(a,b) ((a) < (b) ? (a) : (b))
+ :#define BRW_GRF_BLOCKS(nreg) ((nreg + 15) / 16 - 1)
+ :
+ :static int urb_vs_start, urb_vs_size;
+ :static int urb_gs_start, urb_gs_size;
+ :static int urb_clip_start, urb_clip_size;
+ :static int urb_sf_start, urb_sf_size;
+ :static int urb_cs_start, urb_cs_size;
+ :
+ :static struct brw_surface_state *dest_surf_state, dest_surf_state_local;
+ :static struct brw_surface_state *src_surf_state, src_surf_state_local;
+ :static struct brw_surface_state *mask_surf_state, mask_surf_state_local;
+ :static struct brw_sampler_state *src_sampler_state, src_sampler_state_local;
+ :static struct brw_sampler_state *mask_sampler_state, mask_sampler_state_local;
+ :static struct brw_sampler_default_color *default_color_state;
+ :
+ :static struct brw_vs_unit_state *vs_state, vs_state_local;
+ :static struct brw_sf_unit_state *sf_state, sf_state_local;
+ :static struct brw_wm_unit_state *wm_state, wm_state_local;
+ :static struct brw_cc_unit_state *cc_state, cc_state_local;
+ :static struct brw_cc_viewport *cc_viewport;
+ :
+ :static struct brw_instruction *sf_kernel;
+ :static struct brw_instruction *ps_kernel;
+ :static struct brw_instruction *sip_kernel;
+ :
+ :static CARD32 *binding_table;
+ :static int binding_table_entries;
+ :
+ :static int dest_surf_offset, src_surf_offset, mask_surf_offset;
+ :static int src_sampler_offset, mask_sampler_offset,vs_offset;
+ :static int sf_offset, wm_offset, cc_offset, vb_offset, cc_viewport_offset;
+ :static int sf_kernel_offset, ps_kernel_offset, sip_kernel_offset;
+ :static int wm_scratch_offset;
+ :static int binding_table_offset;
+ :static int default_color_offset;
+ :static int next_offset, total_state_size;
+ :static char *state_base;
+ :static int state_base_offset;
+ :static float *vb;
+ :static int vb_size = (4 * 4) * 4 ; /* 4 DWORDS per vertex*/
+ :
+ :static CARD32 src_blend, dst_blend;
+ :
+ :static const CARD32 sip_kernel_static[][4] = {
+ :/* wait (1) a0<1>UW a145<0,1,0>UW { align1 + } */
+ : { 0x00000030, 0x20000108, 0x00001220, 0x00000000 },
+ :/* nop (4) g0<1>UD { align1 + } */
+ : { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 },
+ :/* nop (4) g0<1>UD { align1 + } */
+ : { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 },
+ :/* nop (4) g0<1>UD { align1 + } */
+ : { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 },
+ :/* nop (4) g0<1>UD { align1 + } */
+ : { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 },
+ :/* nop (4) g0<1>UD { align1 + } */
+ : { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 },
+ :/* nop (4) g0<1>UD { align1 + } */
+ : { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 },
+ :/* nop (4) g0<1>UD { align1 + } */
+ : { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 },
+ :/* nop (4) g0<1>UD { align1 + } */
+ : { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 },
+ :/* nop (4) g0<1>UD { align1 + } */
+ : { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 },
+ :};
+ :
+ :/*
+ : * this program computes dA/dx and dA/dy for the texture coordinates along
+ : * with the base texture coordinate. It was extracted from the Mesa driver
+ : */
+ :
+ :#define SF_KERNEL_NUM_GRF 16
+ :#define SF_MAX_THREADS 1
+ :
+ :static const CARD32 sf_kernel_static[][4] = {
+ :#include "exa_sf_prog.h"
+ :};
+ :
+ :static const CARD32 sf_kernel_static_mask[][4] = {
+ :#include "exa_sf_mask_prog.h"
+ :};
+ :
+ :static const CARD32 sf_kernel_static_rotation[][4] = {
+ :#include "exa_sf_rotation_prog.h"
+ :};
+ :
+ :/* ps kernels */
+ :#define PS_KERNEL_NUM_GRF 32
+ :#define PS_MAX_THREADS 32
+ :
+ :static const CARD32 ps_kernel_static_nomask [][4] = {
+ :#include "exa_wm_nomask_prog.h"
+ :};
+ :
+ :static const CARD32 ps_kernel_static_maskca [][4] = {
+ :#include "exa_wm_maskca_prog.h"
+ :};
+ :
+ :static const CARD32 ps_kernel_static_maskca_srcalpha [][4] = {
+ :#include "exa_wm_maskca_srcalpha_prog.h"
+ :};
+ :
+ :static const CARD32 ps_kernel_static_masknoca [][4] = {
+ :#include "exa_wm_masknoca_prog.h"
+ :};
+ :
+ :static const CARD32 ps_kernel_static_rotation [][4] = {
+ :#include "exa_wm_rotation_prog.h"
+ :};
+ :
+ :static CARD32
+ :i965_get_card_format(PicturePtr pPict)
+ 27 0.0294 :{ /* i965_get_card_format total: 32 0.0349 */
+ : int i;
+ :
+ 4 0.0044 : for (i = 0; i < sizeof(i965_tex_formats) / sizeof(i965_tex_formats[0]);
+ : i++)
+ : {
+ 1 0.0011 : if (i965_tex_formats[i].fmt == pPict->format)
+ : break;
+ : }
+ : return i965_tex_formats[i].card_fmt;
+ :}
+ :
+ :static Bool
+ :i965_check_rotation_transform(PictTransformPtr t)
+ :{
+ : /* XXX this is arbitrary */
+ : int a, b;
+ : a = xFixedToInt(t->matrix[0][1]);
+ : b = xFixedToInt(t->matrix[1][0]);
+ : if (a == -1 && b == 1)
+ : return TRUE;
+ : else if (a == 1 && b == -1)
+ : return TRUE;
+ : else
+ : return FALSE;
+ :}
+ :
+ :Bool
+ :i965_prepare_composite(int op, PicturePtr pSrcPicture,
+ : PicturePtr pMaskPicture, PicturePtr pDstPicture,
+ : PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst)
+ 3 0.0033 :{ /* i965_prepare_composite total: 9782 10.6564 */
+ 29 0.0316 : ScrnInfoPtr pScrn = xf86Screens[pSrcPicture->pDrawable->pScreen->myNum];
+ 7 0.0076 : I830Ptr pI830 = I830PTR(pScrn);
+ : CARD32 src_offset, src_pitch;
+ : CARD32 mask_offset = 0, mask_pitch = 0;
+ : CARD32 dst_format, dst_offset, dst_pitch;
+ : Bool rotation_program = FALSE;
+ :
+ : IntelEmitInvarientState(pScrn);
+ 6 0.0065 : *pI830->last_3d = LAST_3D_RENDER;
+ :
+ 6 0.0065 : src_offset = intel_get_pixmap_offset(pSrc);
+ : src_pitch = intel_get_pixmap_pitch(pSrc);
+ 2 0.0022 : dst_offset = intel_get_pixmap_offset(pDst);
+ 3 0.0033 : dst_pitch = intel_get_pixmap_pitch(pDst);
+ : if (pMask) {
+ 2 0.0022 : mask_offset = intel_get_pixmap_offset(pMask);
+ 6 0.0065 : mask_pitch = intel_get_pixmap_pitch(pMask);
+ : }
+ 8 0.0087 : pI830->scale_units[0][0] = pSrc->drawable.width;
+ 24 0.0261 : pI830->scale_units[0][1] = pSrc->drawable.height;
+ :
+ 1 0.0011 : pI830->transform[0] = pSrcPicture->transform;
+ :
+ : if (!pMask) {
+ : pI830->transform[1] = NULL;
+ : pI830->scale_units[1][0] = -1;
+ : pI830->scale_units[1][1] = -1;
+ : if (pI830->transform[0] &&
+ : i965_check_rotation_transform(pI830->transform[0]))
+ : rotation_program = TRUE;
+ : } else {
+ : pI830->transform[1] = pMaskPicture->transform;
+ : if (pI830->transform[1])
+ : I830FALLBACK("i965 mask transform not implemented!\n");
+ 3 0.0033 : pI830->scale_units[1][0] = pMask->drawable.width;
+ 3 0.0033 : pI830->scale_units[1][1] = pMask->drawable.height;
+ : }
+ :
+ : /* setup 3d pipeline state */
+ :
+ 1 0.0011 : binding_table_entries = 2; /* default no mask */
+ :
+ : /* Set up our layout of state in framebuffer. First the general state: */
+ : next_offset = 0;
+ 1 0.0011 : vs_offset = ALIGN(next_offset, 64);
+ : next_offset = vs_offset + sizeof(*vs_state);
+ :
+ : sf_offset = ALIGN(next_offset, 32);
+ : next_offset = sf_offset + sizeof(*sf_state);
+ :
+ : wm_offset = ALIGN(next_offset, 32);
+ : next_offset = wm_offset + sizeof(*wm_state);
+ :
+ : wm_scratch_offset = ALIGN(next_offset, 1024);
+ : next_offset = wm_scratch_offset + 1024 * PS_MAX_THREADS;
+ :
+ : cc_offset = ALIGN(next_offset, 32);
+ : next_offset = cc_offset + sizeof(*cc_state);
+ :
+ : /* keep current sf_kernel, which will send one setup urb entry to
+ : * PS kernel
+ : */
+ 1 0.0011 : sf_kernel_offset = ALIGN(next_offset, 64);
+ : if (pMask)
+ : next_offset = sf_kernel_offset + sizeof (sf_kernel_static_mask);
+ : else if (rotation_program)
+ : next_offset = sf_kernel_offset + sizeof (sf_kernel_static_rotation);
+ : else
+ : next_offset = sf_kernel_offset + sizeof (sf_kernel_static);
+ :
+ : ps_kernel_offset = ALIGN(next_offset, 64);
+ : if (pMask) {
+ : if (pMaskPicture->componentAlpha &&
+ : PICT_FORMAT_RGB(pMaskPicture->format)) {
+ : if (i965_blend_op[op].src_alpha) {
+ : next_offset = ps_kernel_offset +
+ : sizeof(ps_kernel_static_maskca_srcalpha);
+ : } else {
+ : next_offset = ps_kernel_offset +
+ : sizeof(ps_kernel_static_maskca);
+ : }
+ : } else
+ 1 0.0011 : next_offset = ps_kernel_offset +
+ : sizeof(ps_kernel_static_masknoca);
+ : } else if (rotation_program) {
+ : next_offset = ps_kernel_offset + sizeof (ps_kernel_static_rotation);
+ : } else {
+ 1 0.0011 : next_offset = ps_kernel_offset + sizeof (ps_kernel_static_nomask);
+ : }
+ :
+ 13 0.0142 : sip_kernel_offset = ALIGN(next_offset, 64);
+ : next_offset = sip_kernel_offset + sizeof (sip_kernel_static);
+ :
+ : /* needed? */
+ 3 0.0033 : cc_viewport_offset = ALIGN(next_offset, 32);
+ : next_offset = cc_viewport_offset + sizeof(*cc_viewport);
+ :
+ : /* for texture sampler */
+ 3 0.0033 : src_sampler_offset = ALIGN(next_offset, 32);
+ 2 0.0022 : next_offset = src_sampler_offset + sizeof(*src_sampler_state);
+ :
+ 3 0.0033 : if (pMask) {
+ : mask_sampler_offset = ALIGN(next_offset, 32);
+ 1 0.0011 : next_offset = mask_sampler_offset + sizeof(*mask_sampler_state);
+ : }
+ : /* Align VB to native size of elements, for safety */
+ 10 0.0109 : vb_offset = ALIGN(next_offset, 8);
+ : next_offset = vb_offset + vb_size;
+ :
+ : /* And then the general state: */
+ 2 0.0022 : dest_surf_offset = ALIGN(next_offset, 32);
+ : next_offset = dest_surf_offset + sizeof(*dest_surf_state);
+ :
+ 2 0.0022 : src_surf_offset = ALIGN(next_offset, 32);
+ 1 0.0011 : next_offset = src_surf_offset + sizeof(*src_surf_state);
+ :
+ 1 0.0011 : if (pMask) {
+ 1 0.0011 : mask_surf_offset = ALIGN(next_offset, 32);
+ : next_offset = mask_surf_offset + sizeof(*mask_surf_state);
+ 3 0.0033 : binding_table_entries = 3;
+ : }
+ :
+ 3 0.0033 : binding_table_offset = ALIGN(next_offset, 32);
+ : next_offset = binding_table_offset + (binding_table_entries * 4);
+ :
+ 4 0.0044 : default_color_offset = ALIGN(next_offset, 32);
+ 2 0.0022 : next_offset = default_color_offset + sizeof(*default_color_state);
+ :
+ 3 0.0033 : total_state_size = next_offset;
+ : assert(total_state_size < pI830->exa_965_state->size);
+ :
+ 3 0.0033 : state_base_offset = pI830->exa_965_state->offset;
+ 9 0.0098 : state_base_offset = ALIGN(state_base_offset, 64);
+ : state_base = (char *)(pI830->FbBase + state_base_offset);
+ :
+ : sf_kernel = (void *)(state_base + sf_kernel_offset);
+ 1 0.0011 : ps_kernel = (void *)(state_base + ps_kernel_offset);
+ : sip_kernel = (void *)(state_base + sip_kernel_offset);
+ :
+ 1 0.0011 : cc_viewport = (void *)(state_base + cc_viewport_offset);
+ :
+ 1 0.0011 : binding_table = (void *)(state_base + binding_table_offset);
+ :
+ 2 0.0022 : vb = (void *)(state_base + vb_offset);
+ :
+ 5 0.0054 : default_color_state = (void*)(state_base + default_color_offset);
+ :
+ : /* Set up a default static partitioning of the URB, which is supposed to
+ : * allow anything we would want to do, at potentially lower performance.
+ : */
+ :#define URB_CS_ENTRY_SIZE 0
+ :#define URB_CS_ENTRIES 0
+ :
+ :#define URB_VS_ENTRY_SIZE 1 // each 512-bit row
+ :#define URB_VS_ENTRIES 8 // we needs at least 8 entries
+ :
+ :#define URB_GS_ENTRY_SIZE 0
+ :#define URB_GS_ENTRIES 0
+ :
+ :#define URB_CLIP_ENTRY_SIZE 0
+ :#define URB_CLIP_ENTRIES 0
+ :
+ :#define URB_SF_ENTRY_SIZE 2
+ :#define URB_SF_ENTRIES 1
+ :
+ : urb_vs_start = 0;
+ 1 0.0011 : urb_vs_size = URB_VS_ENTRIES * URB_VS_ENTRY_SIZE;
+ : urb_gs_start = urb_vs_start + urb_vs_size;
+ : urb_gs_size = URB_GS_ENTRIES * URB_GS_ENTRY_SIZE;
+ : urb_clip_start = urb_gs_start + urb_gs_size;
+ : urb_clip_size = URB_CLIP_ENTRIES * URB_CLIP_ENTRY_SIZE;
+ 1 0.0011 : urb_sf_start = urb_clip_start + urb_clip_size;
+ : urb_sf_size = URB_SF_ENTRIES * URB_SF_ENTRY_SIZE;
+ 2 0.0022 : urb_cs_start = urb_sf_start + urb_sf_size;
+ 1 0.0011 : urb_cs_size = URB_CS_ENTRIES * URB_CS_ENTRY_SIZE;
+ :
+ : /* Because we only have a single static buffer for our state currently,
+ : * we have to sync before updating it every time.
+ : */
+ 3 0.0033 : i830WaitSync(pScrn);
+ :
+ 17 0.0185 : memset (cc_viewport, 0, sizeof (*cc_viewport));
+ 17 0.0185 : cc_viewport->min_depth = -1.e35;
+ 19 0.0207 : cc_viewport->max_depth = 1.e35;
+ :
+ : /* Color calculator state */
+ 7 0.0076 : cc_state = &cc_state_local;
+ 32 0.0349 : memset(cc_state, 0, sizeof(*cc_state));
+ 34 0.0370 : cc_state->cc0.stencil_enable = 0; /* disable stencil */
+ : cc_state->cc2.depth_test = 0; /* disable depth test */
+ : cc_state->cc2.logicop_enable = 0; /* disable logic op */
+ : cc_state->cc3.ia_blend_enable = 1; /* blend alpha just like colors */
+ : cc_state->cc3.blend_enable = 1; /* enable color blend */
+ 6 0.0065 : cc_state->cc3.alpha_test = 0; /* disable alpha test */
+ 12 0.0131 : cc_state->cc4.cc_viewport_state_offset = (state_base_offset +
+ : cc_viewport_offset) >> 5;
+ : cc_state->cc5.dither_enable = 0; /* disable dither */
+ 2 0.0022 : cc_state->cc5.logicop_func = 0xc; /* COPY */
+ : cc_state->cc5.statistics_enable = 1;
+ 1 0.0011 : cc_state->cc5.ia_blend_function = BRW_BLENDFUNCTION_ADD;
+ 38 0.0414 : i965_get_blend_cntl(op, pMaskPicture, pDstPicture->format,
+ : &src_blend, &dst_blend);
+ : /* XXX: alpha blend factor should be same as color, but check
+ : * for CA case in future
+ : */
+ 24 0.0261 : cc_state->cc5.ia_src_blend_factor = src_blend;
+ 9 0.0098 : cc_state->cc5.ia_dest_blend_factor = dst_blend;
+ : cc_state->cc6.blend_function = BRW_BLENDFUNCTION_ADD;
+ 6 0.0065 : cc_state->cc6.src_blend_factor = src_blend;
+ 10 0.0109 : cc_state->cc6.dest_blend_factor = dst_blend;
+ : cc_state->cc6.clamp_post_alpha_blend = 1;
+ 4 0.0044 : cc_state->cc6.clamp_pre_alpha_blend = 1;
+ 1 0.0011 : cc_state->cc6.clamp_range = 0; /* clamp range [0,1] */
+ :
+ 1 0.0011 : cc_state = (void *)(state_base + cc_offset);
+ 51 0.0556 : memcpy (cc_state, &cc_state_local, sizeof (cc_state_local));
+ :
+ : /* Upload system kernel */
+ 10 0.0109 : memcpy (sip_kernel, sip_kernel_static, sizeof (sip_kernel_static));
+ :
+ : /* Set up the state buffer for the destination surface */
+ 8 0.0087 : dest_surf_state = &dest_surf_state_local;
+ 42 0.0458 : memset(dest_surf_state, 0, sizeof(*dest_surf_state));
+ 1 0.0011 : dest_surf_state->ss0.surface_type = BRW_SURFACE_2D;
+ 8 0.0087 : dest_surf_state->ss0.data_return_format = BRW_SURFACERETURNFORMAT_FLOAT32;
+ 4 0.0044 : i965_get_dest_format(pDstPicture, &dst_format);
+ 34 0.0370 : dest_surf_state->ss0.surface_format = dst_format;
+ :
+ : dest_surf_state->ss0.writedisable_alpha = 0;
+ : dest_surf_state->ss0.writedisable_red = 0;
+ : dest_surf_state->ss0.writedisable_green = 0;
+ : dest_surf_state->ss0.writedisable_blue = 0;
+ 27 0.0294 : dest_surf_state->ss0.color_blend = 1;
+ : dest_surf_state->ss0.vert_line_stride = 0;
+ : dest_surf_state->ss0.vert_line_stride_ofs = 0;
+ : dest_surf_state->ss0.mipmap_layout_mode = 0;
+ : dest_surf_state->ss0.render_cache_read_mode = 0;
+ :
+ : dest_surf_state->ss1.base_addr = dst_offset;
+ 4 0.0044 : dest_surf_state->ss2.height = pDst->drawable.height - 1;
+ 40 0.0436 : dest_surf_state->ss2.width = pDst->drawable.width - 1;
+ : dest_surf_state->ss2.mip_count = 0;
+ : dest_surf_state->ss2.render_target_rotation = 0;
+ 23 0.0251 : dest_surf_state->ss3.pitch = dst_pitch - 1;
+ :
+ 1 0.0011 : dest_surf_state = (void *)(state_base + dest_surf_offset);
+ 31 0.0338 : memcpy (dest_surf_state, &dest_surf_state_local, sizeof (dest_surf_state_local));
+ :
+ : /* Set up the source surface state buffer */
+ : src_surf_state = &src_surf_state_local;
+ 48 0.0523 : memset(src_surf_state, 0, sizeof(*src_surf_state));
+ 5 0.0054 : src_surf_state->ss0.surface_type = BRW_SURFACE_2D;
+ 20 0.0218 : src_surf_state->ss0.surface_format = i965_get_card_format(pSrcPicture);
+ :
+ : src_surf_state->ss0.writedisable_alpha = 0;
+ 3 0.0033 : src_surf_state->ss0.writedisable_red = 0;
+ : src_surf_state->ss0.writedisable_green = 0;
+ : src_surf_state->ss0.writedisable_blue = 0;
+ 31 0.0338 : src_surf_state->ss0.color_blend = 1;
+ : src_surf_state->ss0.vert_line_stride = 0;
+ : src_surf_state->ss0.vert_line_stride_ofs = 0;
+ : src_surf_state->ss0.mipmap_layout_mode = 0;
+ : src_surf_state->ss0.render_cache_read_mode = 0;
+ :
+ 3 0.0033 : src_surf_state->ss1.base_addr = src_offset;
+ 7 0.0076 : src_surf_state->ss2.width = pSrc->drawable.width - 1;
+ 6 0.0065 : src_surf_state->ss2.height = pSrc->drawable.height - 1;
+ : src_surf_state->ss2.mip_count = 0;
+ 30 0.0327 : src_surf_state->ss2.render_target_rotation = 0;
+ 15 0.0163 : src_surf_state->ss3.pitch = src_pitch - 1;
+ :
+ : src_surf_state = (void *)(state_base + src_surf_offset);
+ 28 0.0305 : memcpy (src_surf_state, &src_surf_state_local, sizeof (src_surf_state_local));
+ :
+ : /* setup mask surface */
+ 1 0.0011 : if (pMask) {
+ : mask_surf_state = &mask_surf_state_local;
+ 35 0.0381 : memset(mask_surf_state, 0, sizeof(*mask_surf_state));
+ 6 0.0065 : mask_surf_state->ss0.surface_type = BRW_SURFACE_2D;
+ 18 0.0196 : mask_surf_state->ss0.surface_format =
+ : i965_get_card_format(pMaskPicture);
+ :
+ : mask_surf_state->ss0.writedisable_alpha = 0;
+ 8 0.0087 : mask_surf_state->ss0.writedisable_red = 0;
+ : mask_surf_state->ss0.writedisable_green = 0;
+ : mask_surf_state->ss0.writedisable_blue = 0;
+ 20 0.0218 : mask_surf_state->ss0.color_blend = 1;
+ : mask_surf_state->ss0.vert_line_stride = 0;
+ : mask_surf_state->ss0.vert_line_stride_ofs = 0;
+ : mask_surf_state->ss0.mipmap_layout_mode = 0;
+ : mask_surf_state->ss0.render_cache_read_mode = 0;
+ :
+ : mask_surf_state->ss1.base_addr = mask_offset;
+ 11 0.0120 : mask_surf_state->ss2.width = pMask->drawable.width - 1;
+ 4 0.0044 : mask_surf_state->ss2.height = pMask->drawable.height - 1;
+ : mask_surf_state->ss2.mip_count = 0;
+ 31 0.0338 : mask_surf_state->ss2.render_target_rotation = 0;
+ 8 0.0087 : mask_surf_state->ss3.pitch = mask_pitch - 1;
+ :
+ : mask_surf_state = (void *)(state_base + mask_surf_offset);
+ 38 0.0414 : memcpy (mask_surf_state, &mask_surf_state_local, sizeof (mask_surf_state_local));
+ : }
+ :
+ : /* Set up a binding table for our surfaces. Only the PS will use it */
+ 8 0.0087 : binding_table[0] = state_base_offset + dest_surf_offset;
+ 1 0.0011 : binding_table[1] = state_base_offset + src_surf_offset;
+ : if (pMask)
+ 3 0.0033 : binding_table[2] = state_base_offset + mask_surf_offset;
+ :
+ : /* PS kernel use this sampler */
+ : src_sampler_state = &src_sampler_state_local;
+ 3 0.0033 : memset(src_sampler_state, 0, sizeof(*src_sampler_state));
+ : src_sampler_state->ss0.lod_preclamp = 1; /* GL mode */
+ 58 0.0632 : switch(pSrcPicture->filter) {
+ : case PictFilterNearest:
+ 4 0.0044 : src_sampler_state->ss0.min_filter = BRW_MAPFILTER_NEAREST;
+ 38 0.0414 : src_sampler_state->ss0.mag_filter = BRW_MAPFILTER_NEAREST;
+ : break;
+ : case PictFilterBilinear:
+ : src_sampler_state->ss0.min_filter = BRW_MAPFILTER_LINEAR;
+ : src_sampler_state->ss0.mag_filter = BRW_MAPFILTER_LINEAR;
+ : break;
+ : default:
+ : I830FALLBACK("Bad filter 0x%x\n", pSrcPicture->filter);
+ : }
+ :
+ 40 0.0436 : memset(default_color_state, 0, sizeof(*default_color_state));
+ 1 0.0011 : default_color_state->color[0] = 0.0; /* R */
+ 4 0.0044 : default_color_state->color[1] = 0.0; /* G */
+ : default_color_state->color[2] = 0.0; /* B */
+ : default_color_state->color[3] = 0.0; /* A */
+ :
+ 3 0.0033 : src_sampler_state->ss0.default_color_mode = 0; /* GL mode */
+ :
+ 3 0.0033 : if (!pSrcPicture->repeat) {
+ : src_sampler_state->ss1.r_wrap_mode = BRW_TEXCOORDMODE_CLAMP_BORDER;
+ 1 0.0011 : src_sampler_state->ss1.s_wrap_mode = BRW_TEXCOORDMODE_CLAMP_BORDER;
+ : src_sampler_state->ss1.t_wrap_mode = BRW_TEXCOORDMODE_CLAMP_BORDER;
+ : src_sampler_state->ss2.default_color_pointer =
+ : (state_base_offset + default_color_offset) >> 5;
+ : } else {
+ 8 0.0087 : src_sampler_state->ss1.r_wrap_mode = BRW_TEXCOORDMODE_WRAP;
+ : src_sampler_state->ss1.s_wrap_mode = BRW_TEXCOORDMODE_WRAP;
+ 85 0.0926 : src_sampler_state->ss1.t_wrap_mode = BRW_TEXCOORDMODE_WRAP;
+ : }
+ 3 0.0033 : src_sampler_state->ss3.chroma_key_enable = 0; /* disable chromakey */
+ :
+ 6 0.0065 : src_sampler_state = (void *)(state_base + src_sampler_offset);
+ 32 0.0349 : memcpy (src_sampler_state, &src_sampler_state_local, sizeof (src_sampler_state_local));
+ :
+ 3 0.0033 : if (pMask) {
+ : mask_sampler_state = &mask_sampler_state_local;
+ : memset(mask_sampler_state, 0, sizeof(*mask_sampler_state));
+ 3 0.0033 : mask_sampler_state->ss0.lod_preclamp = 1; /* GL mode */
+ 45 0.0490 : switch(pMaskPicture->filter) {
+ : case PictFilterNearest:
+ 5 0.0054 : mask_sampler_state->ss0.min_filter = BRW_MAPFILTER_NEAREST;
+ 41 0.0447 : mask_sampler_state->ss0.mag_filter = BRW_MAPFILTER_NEAREST;
+ : break;
+ : case PictFilterBilinear:
+ : mask_sampler_state->ss0.min_filter = BRW_MAPFILTER_LINEAR;
+ : mask_sampler_state->ss0.mag_filter = BRW_MAPFILTER_LINEAR;
+ : break;
+ : default:
+ : I830FALLBACK("Bad filter 0x%x\n", pMaskPicture->filter);
+ : }
+ :
+ 34 0.0370 : if (!pMaskPicture->repeat) {
+ 3 0.0033 : mask_sampler_state->ss1.r_wrap_mode =
+ : BRW_TEXCOORDMODE_CLAMP_BORDER;
+ 40 0.0436 : mask_sampler_state->ss1.s_wrap_mode =
+ : BRW_TEXCOORDMODE_CLAMP_BORDER;
+ 22 0.0240 : mask_sampler_state->ss1.t_wrap_mode =
+ : BRW_TEXCOORDMODE_CLAMP_BORDER;
+ 7 0.0076 : mask_sampler_state->ss2.default_color_pointer =
+ : (state_base_offset + default_color_offset)>>5;
+ : } else {
+ : mask_sampler_state->ss1.r_wrap_mode = BRW_TEXCOORDMODE_WRAP;
+ : mask_sampler_state->ss1.s_wrap_mode = BRW_TEXCOORDMODE_WRAP;
+ : mask_sampler_state->ss1.t_wrap_mode = BRW_TEXCOORDMODE_WRAP;
+ : }
+ : mask_sampler_state->ss3.chroma_key_enable = 0; /* disable chromakey */
+ :
+ 5 0.0054 : mask_sampler_state = (void *)(state_base + mask_sampler_offset);
+ 27 0.0294 : memcpy (mask_sampler_state, &mask_sampler_state_local, sizeof (mask_sampler_state_local));
+ : }
+ :
+ : /* Set up the vertex shader to be disabled (passthrough) */
+ 4 0.0044 : vs_state = &vs_state_local;
+ 8 0.0087 : memset(vs_state, 0, sizeof(*vs_state));
+ 1 0.0011 : vs_state->thread4.nr_urb_entries = URB_VS_ENTRIES;
+ 1 0.0011 : vs_state->thread4.urb_entry_allocation_size = URB_VS_ENTRY_SIZE - 1;
+ 46 0.0501 : vs_state->vs6.vs_enable = 0;
+ : vs_state->vs6.vert_cache_disable = 1;
+ :
+ 6 0.0065 : vs_state = (void *)(state_base + vs_offset);
+ 22 0.0240 : memcpy (vs_state, &vs_state_local, sizeof (vs_state_local));
+ :
+ : /* Set up the SF kernel to do coord interp: for each attribute,
+ : * calculate dA/dx and dA/dy. Hand these interpolation coefficients
+ : * back to SF which then hands pixels off to WM.
+ : */
+ 4 0.0044 : if (pMask)
+ 5 0.0054 : memcpy(sf_kernel, sf_kernel_static_mask, sizeof (sf_kernel_static));
+ : else if (rotation_program)
+ : memcpy(sf_kernel, sf_kernel_static_rotation,
+ : sizeof (sf_kernel_static_rotation));
+ : else
+ : memcpy(sf_kernel, sf_kernel_static, sizeof (sf_kernel_static));
+ :
+ 3 0.0033 : sf_state = &sf_state_local;
+ 45 0.0490 : memset(sf_state, 0, sizeof(*sf_state));
+ 102 0.1111 : sf_state->thread0.kernel_start_pointer =
+ : (state_base_offset + sf_kernel_offset) >> 6;
+ 1 0.0011 : sf_state->thread0.grf_reg_count = BRW_GRF_BLOCKS(SF_KERNEL_NUM_GRF);
+ 50 0.0545 : sf_state->sf1.single_program_flow = 1;
+ : sf_state->sf1.binding_table_entry_count = 0;
+ : sf_state->sf1.thread_priority = 0;
+ : sf_state->sf1.floating_point_mode = 0; /* Mesa does this */
+ : sf_state->sf1.illegal_op_exception_enable = 1;
+ 7 0.0076 : sf_state->sf1.mask_stack_exception_enable = 1;
+ : sf_state->sf1.sw_exception_enable = 1;
+ 45 0.0490 : sf_state->thread2.per_thread_scratch_space = 0;
+ : /* scratch space is not used in our kernel */
+ 4 0.0044 : sf_state->thread2.scratch_space_base_pointer = 0;
+ 3 0.0033 : sf_state->thread3.const_urb_entry_read_length = 0; /* no const URBs */
+ 8 0.0087 : sf_state->thread3.const_urb_entry_read_offset = 0; /* no const URBs */
+ 9 0.0098 : sf_state->thread3.urb_entry_read_length = 1; /* 1 URB per vertex */
+ : /* don't smash vertex header, read start from dw8 */
+ 4 0.0044 : sf_state->thread3.urb_entry_read_offset = 1;
+ 3 0.0033 : sf_state->thread3.dispatch_grf_start_reg = 3;
+ 10 0.0109 : sf_state->thread4.max_threads = SF_MAX_THREADS - 1;
+ 1 0.0011 : sf_state->thread4.urb_entry_allocation_size = URB_SF_ENTRY_SIZE - 1;
+ 6 0.0065 : sf_state->thread4.nr_urb_entries = URB_SF_ENTRIES;
+ : sf_state->thread4.stats_enable = 1;
+ : sf_state->sf5.viewport_transform = FALSE; /* skip viewport */
+ 32 0.0349 : sf_state->sf6.cull_mode = BRW_CULLMODE_NONE;
+ 40 0.0436 : sf_state->sf6.scissor = 0;
+ 5 0.0054 : sf_state->sf7.trifan_pv = 2;
+ 5 0.0054 : sf_state->sf6.dest_org_vbias = 0x8;
+ 54 0.0588 : sf_state->sf6.dest_org_hbias = 0x8;
+ :
+ 3 0.0033 : sf_state = (void *)(state_base + sf_offset);
+ 14 0.0153 : memcpy (sf_state, &sf_state_local, sizeof (sf_state_local));
+ :
+ : /* Set up the PS kernel (dispatched by WM) */
+ : if (pMask) {
+ 5 0.0054 : if (pMaskPicture->componentAlpha &&
+ : PICT_FORMAT_RGB(pMaskPicture->format)) {
+ 3 0.0033 : if (i965_blend_op[op].src_alpha)
+ 3 0.0033 : memcpy(ps_kernel, ps_kernel_static_maskca_srcalpha,
+ : sizeof (ps_kernel_static_maskca_srcalpha));
+ : else
+ 2 0.0022 : memcpy(ps_kernel, ps_kernel_static_maskca,
+ : sizeof (ps_kernel_static_maskca));
+ : } else
+ 8 0.0087 : memcpy(ps_kernel, ps_kernel_static_masknoca,
+ : sizeof (ps_kernel_static_masknoca));
+ : } else if (rotation_program) {
+ 1 0.0011 : memcpy(ps_kernel, ps_kernel_static_rotation,
+ : sizeof (ps_kernel_static_rotation));
+ : } else {
+ 1 0.0011 : memcpy(ps_kernel, ps_kernel_static_nomask,
+ : sizeof (ps_kernel_static_nomask));
+ : }
+ :
+ 13 0.0142 : wm_state = &wm_state_local;
+ 90 0.0980 : memset(wm_state, 0, sizeof (*wm_state));
+ 90 0.0980 : wm_state->thread0.kernel_start_pointer =
+ : (state_base_offset + ps_kernel_offset) >> 6;
+ 21 0.0229 : wm_state->thread0.grf_reg_count = BRW_GRF_BLOCKS(PS_KERNEL_NUM_GRF);
+ : wm_state->thread1.single_program_flow = 1;
+ : if (!pMask)
+ 1 0.0011 : wm_state->thread1.binding_table_entry_count = 2; /* 1 tex and fb */
+ : else
+ 18 0.0196 : wm_state->thread1.binding_table_entry_count = 3; /* 2 tex and fb */
+ :
+ 6 0.0065 : wm_state->thread2.scratch_space_base_pointer = (state_base_offset +
+ : wm_scratch_offset)>>10;
+ 33 0.0359 : wm_state->thread2.per_thread_scratch_space = 0;
+ : wm_state->thread3.const_urb_entry_read_length = 0;
+ 1 0.0011 : wm_state->thread3.const_urb_entry_read_offset = 0;
+ : /* Each pair of attributes (src/mask coords) is one URB entry */
+ : if (pMask)
+ 7 0.0076 : wm_state->thread3.urb_entry_read_length = 2;
+ : else
+ 2 0.0022 : wm_state->thread3.urb_entry_read_length = 1;
+ 4 0.0044 : wm_state->thread3.urb_entry_read_offset = 0;
+ : /* wm kernel use urb from 3, see wm_program in compiler module */
+ 19 0.0207 : wm_state->thread3.dispatch_grf_start_reg = 3; /* must match kernel */
+ :
+ 10 0.0109 : wm_state->wm4.stats_enable = 1; /* statistic */
+ 7 0.0076 : wm_state->wm4.sampler_state_pointer = (state_base_offset +
+ : src_sampler_offset) >> 5;
+ 19 0.0207 : wm_state->wm4.sampler_count = 1; /* 1-4 samplers used */
+ 6 0.0065 : wm_state->wm5.max_threads = PS_MAX_THREADS - 1;
+ : wm_state->wm5.thread_dispatch_enable = 1;
+ : /* just use 16-pixel dispatch (4 subspans), don't need to change kernel
+ : * start point
+ : */
+ 2 0.0022 : wm_state->wm5.enable_16_pix = 1;
+ : wm_state->wm5.enable_8_pix = 0;
+ 20 0.0218 : wm_state->wm5.early_depth_test = 1;
+ :
+ 3 0.0033 : wm_state = (void *)(state_base + wm_offset);
+ 35 0.0381 : memcpy (wm_state, &wm_state_local, sizeof (wm_state_local));
+ :
+ : /* Begin the long sequence of commands needed to set up the 3D
+ : * rendering pipe
+ : */
+ : {
+ 2 0.0022 : BEGIN_LP_RING(2);
+ 3 0.0033 : OUT_RING(MI_FLUSH |
+ : MI_STATE_INSTRUCTION_CACHE_FLUSH |
+ : BRW_MI_GLOBAL_SNAPSHOT_RESET);
+ 4 0.0044 : OUT_RING(MI_NOOP);
+ 37 0.0403 : ADVANCE_LP_RING();
+ : }
+ : {
+ 2751 2.9969 : BEGIN_LP_RING(12);
+ :
+ : /* Match Mesa driver setup */
+ 5 0.0054 : OUT_RING(BRW_PIPELINE_SELECT | PIPELINE_SELECT_3D);
+ :
+ 10 0.0109 : OUT_RING(BRW_CS_URB_STATE | 0);
+ 5 0.0054 : OUT_RING((0 << 4) | /* URB Entry Allocation Size */
+ : (0 << 0)); /* Number of URB Entries */
+ :
+ : /* Zero out the two base address registers so all offsets are
+ : * absolute.
+ : */
+ 4 0.0044 : OUT_RING(BRW_STATE_BASE_ADDRESS | 4);
+ 1 0.0011 : OUT_RING(0 | BASE_ADDRESS_MODIFY); /* Generate state base address */
+ 2 0.0022 : OUT_RING(0 | BASE_ADDRESS_MODIFY); /* Surface state base address */
+ 5 0.0054 : OUT_RING(0 | BASE_ADDRESS_MODIFY); /* media base addr, don't care */
+ : /* general state max addr, disabled */
+ 4 0.0044 : OUT_RING(0x10000000 | BASE_ADDRESS_MODIFY);
+ : /* media object state max addr, disabled */
+ 7 0.0076 : OUT_RING(0x10000000 | BASE_ADDRESS_MODIFY);
+ :
+ : /* Set system instruction pointer */
+ 4 0.0044 : OUT_RING(BRW_STATE_SIP | 0);
+ 13 0.0142 : OUT_RING(state_base_offset + sip_kernel_offset);
+ 8 0.0087 : OUT_RING(MI_NOOP);
+ 106 0.1155 : ADVANCE_LP_RING();
+ : }
+ : {
+ 1204 1.3116 : BEGIN_LP_RING(26);
+ : /* Pipe control */
+ 2 0.0022 : OUT_RING(BRW_PIPE_CONTROL |
+ : BRW_PIPE_CONTROL_NOWRITE |
+ : BRW_PIPE_CONTROL_IS_FLUSH |
+ : 2);
+ 15 0.0163 : OUT_RING(0); /* Destination address */
+ 6 0.0065 : OUT_RING(0); /* Immediate data low DW */
+ 3 0.0033 : OUT_RING(0); /* Immediate data high DW */
+ :
+ : /* Binding table pointers */
+ 3 0.0033 : OUT_RING(BRW_3DSTATE_BINDING_TABLE_POINTERS | 4);
+ 6 0.0065 : OUT_RING(0); /* vs */
+ 5 0.0054 : OUT_RING(0); /* gs */
+ 5 0.0054 : OUT_RING(0); /* clip */
+ 10 0.0109 : OUT_RING(0); /* sf */
+ : /* Only the PS uses the binding table */
+ 16 0.0174 : OUT_RING(state_base_offset + binding_table_offset); /* ps */
+ :
+ : /* The drawing rectangle clipping is always on. Set it to values that
+ : * shouldn't do any clipping.
+ : */
+ 22 0.0240 : OUT_RING(BRW_3DSTATE_DRAWING_RECTANGLE | 2); /* XXX 3 for BLC or CTG */
+ 12 0.0131 : OUT_RING(0x00000000); /* ymin, xmin */
+ 61 0.0665 : OUT_RING(DRAW_YMAX(pDst->drawable.height - 1) |
+ : DRAW_XMAX(pDst->drawable.width - 1)); /* ymax, xmax */
+ 41 0.0447 : OUT_RING(0x00000000); /* yorigin, xorigin */
+ :
+ : /* skip the depth buffer */
+ : /* skip the polygon stipple */
+ : /* skip the polygon stipple offset */
+ : /* skip the line stipple */
+ :
+ : /* Set the pointers to the 3d pipeline state */
+ : OUT_RING(BRW_3DSTATE_PIPELINED_POINTERS | 5);
+ 29 0.0316 : OUT_RING(state_base_offset + vs_offset); /* 32 byte aligned */
+ 11 0.0120 : OUT_RING(BRW_GS_DISABLE); /* disable GS, resulting in passthrough */
+ 102 0.1111 : OUT_RING(BRW_CLIP_DISABLE); /* disable CLIP, resulting in passthrough */
+ 383 0.4172 : OUT_RING(state_base_offset + sf_offset); /* 32 byte aligned */
+ 26 0.0283 : OUT_RING(state_base_offset + wm_offset); /* 32 byte aligned */
+ 17 0.0185 : OUT_RING(state_base_offset + cc_offset); /* 64 byte aligned */
+ :
+ : /* URB fence */
+ : OUT_RING(BRW_URB_FENCE |
+ : UF0_CS_REALLOC |
+ : UF0_SF_REALLOC |
+ : UF0_CLIP_REALLOC |
+ : UF0_GS_REALLOC |
+ : UF0_VS_REALLOC |
+ : 1);
+ 39 0.0425 : OUT_RING(((urb_clip_start + urb_clip_size) << UF1_CLIP_FENCE_SHIFT) |
+ : ((urb_gs_start + urb_gs_size) << UF1_GS_FENCE_SHIFT) |
+ : ((urb_vs_start + urb_vs_size) << UF1_VS_FENCE_SHIFT));
+ 28 0.0305 : OUT_RING(((urb_cs_start + urb_cs_size) << UF2_CS_FENCE_SHIFT) |
+ : ((urb_sf_start + urb_sf_size) << UF2_SF_FENCE_SHIFT));
+ :
+ : /* Constant buffer state */
+ 11 0.0120 : OUT_RING(BRW_CS_URB_STATE | 0);
+ 3 0.0033 : OUT_RING(((URB_CS_ENTRY_SIZE - 1) << 4) |
+ : (URB_CS_ENTRIES << 0));
+ 62 0.0675 : ADVANCE_LP_RING();
+ : }
+ : {
+ 702 0.7647 : int nelem = pMask ? 3: 2;
+ 12 0.0131 : BEGIN_LP_RING(pMask?12:10);
+ : /* Set up the pointer to our vertex buffer */
+ 4 0.0044 : OUT_RING(BRW_3DSTATE_VERTEX_BUFFERS | 3);
+ 2 0.0022 : OUT_RING((0 << VB0_BUFFER_INDEX_SHIFT) |
+ : VB0_VERTEXDATA |
+ : ((4 * 2 * nelem) << VB0_BUFFER_PITCH_SHIFT));
+ 10 0.0109 : OUT_RING(state_base_offset + vb_offset);
+ 2 0.0022 : OUT_RING(3);
+ 7 0.0076 : OUT_RING(0); // ignore for VERTEXDATA, but still there
+ :
+ : /* Set up our vertex elements, sourced from the single vertex buffer.
+ : */
+ 9 0.0098 : OUT_RING(BRW_3DSTATE_VERTEX_ELEMENTS | ((2 * nelem) - 1));
+ : /* vertex coordinates */
+ 5 0.0054 : OUT_RING((0 << VE0_VERTEX_BUFFER_INDEX_SHIFT) |
+ : VE0_VALID |
+ : (BRW_SURFACEFORMAT_R32G32_FLOAT << VE0_FORMAT_SHIFT) |
+ : (0 << VE0_OFFSET_SHIFT));
+ 2 0.0022 : OUT_RING((BRW_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT) |
+ : (BRW_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT) |
+ : (BRW_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_2_SHIFT) |
+ : (BRW_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_3_SHIFT) |
+ : (4 << VE1_DESTINATION_ELEMENT_OFFSET_SHIFT));
+ : /* u0, v0 */
+ 2 0.0022 : OUT_RING((0 << VE0_VERTEX_BUFFER_INDEX_SHIFT) |
+ : VE0_VALID |
+ : (BRW_SURFACEFORMAT_R32G32_FLOAT << VE0_FORMAT_SHIFT) |
+ : (8 << VE0_OFFSET_SHIFT)); /* offset vb in bytes */
+ 14 0.0153 : OUT_RING((BRW_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT) |
+ : (BRW_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT) |
+ : (BRW_VFCOMPONENT_NOSTORE << VE1_VFCOMPONENT_2_SHIFT) |
+ : (BRW_VFCOMPONENT_NOSTORE << VE1_VFCOMPONENT_3_SHIFT) |
+ : (8 << VE1_DESTINATION_ELEMENT_OFFSET_SHIFT)); /* VUE offset in dwords */
+ : /* u1, v1 */
+ 1 0.0011 : if (pMask) {
+ 4 0.0044 : OUT_RING((0 << VE0_VERTEX_BUFFER_INDEX_SHIFT) |
+ : VE0_VALID |
+ : (BRW_SURFACEFORMAT_R32G32_FLOAT << VE0_FORMAT_SHIFT) |
+ : (16 << VE0_OFFSET_SHIFT));
+ 1 0.0011 : OUT_RING((BRW_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT) |
+ : (BRW_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT) |
+ : (BRW_VFCOMPONENT_NOSTORE << VE1_VFCOMPONENT_2_SHIFT) |
+ : (BRW_VFCOMPONENT_NOSTORE << VE1_VFCOMPONENT_3_SHIFT) |
+ : (10 << VE1_DESTINATION_ELEMENT_OFFSET_SHIFT));
+ : }
+ :
+ 66 0.0719 : ADVANCE_LP_RING();
+ : }
+ :
+ :#ifdef I830DEBUG
+ : ErrorF("try to sync to show any errors...");
+ : I830Sync(pScrn);
+ :#endif
+ : return TRUE;
+ 1196 1.3029 :}
+ :
+ :void
+ :i965_composite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY,
+ : int dstX, int dstY, int w, int h)
+ 707 0.7702 :{ /* i965_composite total: 2800 3.0503 */
+ 38 0.0414 : ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
+ 3 0.0033 : I830Ptr pI830 = I830PTR(pScrn);
+ : Bool has_mask;
+ : float src_x[3], src_y[3], mask_x[3], mask_y[3];
+ : int i;
+ :
+ 22 0.0240 : i830_get_transformed_coordinates(srcX, srcY,
+ : pI830->transform[0],
+ : &src_x[0], &src_y[0]);
+ 5 0.0054 : i830_get_transformed_coordinates(srcX, srcY + h,
+ : pI830->transform[0],
+ : &src_x[1], &src_y[1]);
+ 15 0.0163 : i830_get_transformed_coordinates(srcX + w, srcY + h,
+ : pI830->transform[0],
+ : &src_x[2], &src_y[2]);
+ :
+ 18 0.0196 : if (pI830->scale_units[1][0] == -1 || pI830->scale_units[1][1] == -1) {
+ : has_mask = FALSE;
+ : } else {
+ : has_mask = TRUE;
+ 1 0.0011 : i830_get_transformed_coordinates(maskX, maskY,
+ : pI830->transform[1],
+ : &mask_x[0], &mask_y[0]);
+ 8 0.0087 : i830_get_transformed_coordinates(maskX, maskY + h,
+ : pI830->transform[1],
+ : &mask_x[1], &mask_y[1]);
+ 33 0.0359 : i830_get_transformed_coordinates(maskX + w, maskY + h,
+ : pI830->transform[1],
+ : &mask_x[2], &mask_y[2]);
+ : }
+ :
+ : /* Wait for any existing composite rectangles to land before we overwrite
+ : * the VB with the next one.
+ : */
+ 7 0.0076 : i830WaitSync(pScrn);
+ :
+ : i = 0;
+ : /* rect (x2,y2) */
+ 6 0.0065 : vb[i++] = (float)(dstX + w);
+ 7 0.0076 : vb[i++] = (float)(dstY + h);
+ 4 0.0044 : vb[i++] = src_x[2] / pI830->scale_units[0][0];
+ 8 0.0087 : vb[i++] = src_y[2] / pI830->scale_units[0][1];
+ : if (has_mask) {
+ 77 0.0839 : vb[i++] = mask_x[2] / pI830->scale_units[1][0];
+ 88 0.0959 : vb[i++] = mask_y[2] / pI830->scale_units[1][1];
+ : }
+ :
+ : /* rect (x1,y2) */
+ 2 0.0022 : vb[i++] = (float)dstX;
+ 1 0.0011 : vb[i++] = (float)(dstY + h);
+ 3 0.0033 : vb[i++] = src_x[1] / pI830->scale_units[0][0];
+ 14 0.0153 : vb[i++] = src_y[1] / pI830->scale_units[0][1];
+ 2 0.0022 : if (has_mask) {
+ 7 0.0076 : vb[i++] = mask_x[1] / pI830->scale_units[1][0];
+ 72 0.0784 : vb[i++] = mask_y[1] / pI830->scale_units[1][1];
+ : }
+ :
+ : /* rect (x1,y1) */
+ 2 0.0022 : vb[i++] = (float)dstX;
+ 3 0.0033 : vb[i++] = (float)dstY;
+ 3 0.0033 : vb[i++] = src_x[0] / pI830->scale_units[0][0];
+ 5 0.0054 : vb[i++] = src_y[0] / pI830->scale_units[0][1];
+ : if (has_mask) {
+ 7 0.0076 : vb[i++] = mask_x[0] / pI830->scale_units[1][0];
+ 11 0.0120 : vb[i++] = mask_y[0] / pI830->scale_units[1][1];
+ : }
+ :
+ : {
+ 2 0.0022 : BEGIN_LP_RING(6);
+ 3 0.0033 : OUT_RING(BRW_3DPRIMITIVE |
+ : BRW_3DPRIMITIVE_VERTEX_SEQUENTIAL |
+ : (_3DPRIM_RECTLIST << BRW_3DPRIMITIVE_TOPOLOGY_SHIFT) |
+ : (0 << 9) | /* CTG - indirect vertex count */
+ : 4);
+ 4 0.0044 : OUT_RING(3); /* vertex count per instance */
+ : OUT_RING(0); /* start vertex offset */
+ 3 0.0033 : OUT_RING(1); /* single instance */
+ 4 0.0044 : OUT_RING(0); /* start instance location */
+ 3 0.0033 : OUT_RING(0); /* index buffer offset, ignored */
+ 4 0.0044 : ADVANCE_LP_RING();
+ : }
+ :#ifdef I830DEBUG
+ : ErrorF("sync after 3dprimitive");
+ : I830Sync(pScrn);
+ :#endif
+ : /* we must be sure that the pipeline is flushed before next exa draw,
+ : because that will be new state, binding state and instructions*/
+ : {
+ 804 0.8759 : BEGIN_LP_RING(4);
+ : OUT_RING(BRW_PIPE_CONTROL |
+ : BRW_PIPE_CONTROL_NOWRITE |
+ : BRW_PIPE_CONTROL_WC_FLUSH |
+ : BRW_PIPE_CONTROL_IS_FLUSH |
+ : (1 << 10) | /* XXX texture cache flush for BLC/CTG */
+ : 2);
+ 2 0.0022 : OUT_RING(0); /* Destination address */
+ 5 0.0054 : OUT_RING(0); /* Immediate data low DW */
+ 5 0.0054 : OUT_RING(0); /* Immediate data high DW */
+ 7 0.0076 : ADVANCE_LP_RING();
+ : }
+ :
+ : /* Mark sync so we can wait for it before setting up the VB on the next
+ : * rectangle.
+ : */
+ 773 0.8421 : i830MarkSync(pScrn);
+ 2 0.0022 :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/exa/exa.c"
+ *
+ * 854 0.9303
+ */
+
+
+ :/*
+ : * Copyright © 2001 Keith Packard
+ : *
+ : * Partly based on code that is Copyright © The XFree86 Project Inc.
+ : *
+ : * 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 Keith Packard not be used in
+ : * advertising or publicity pertaining to distribution of the software without
+ : * specific, written prior permission. Keith Packard makes no
+ : * representations about the suitability of this software for any purpose. It
+ : * is provided "as is" without express or implied warranty.
+ : *
+ : * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ : * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ : * EVENT SHALL KEITH PACKARD 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.
+ : */
+ :
+ :/** @file
+ : * This file covers the initialization and teardown of EXA, and has various
+ : * functions not responsible for performing rendering, pixmap migration, or
+ : * memory management.
+ : */
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#ifdef MITSHM
+ :#include "shmint.h"
+ :#endif
+ :
+ :#include <stdlib.h>
+ :
+ :#include "exa_priv.h"
+ :#include <X11/fonts/fontstruct.h>
+ :#include "dixfontstr.h"
+ :#include "exa.h"
+ :#include "cw.h"
+ :
+ :static int exaGeneration;
+ :int exaScreenPrivateIndex;
+ :int exaPixmapPrivateIndex;
+ :
+ :/**
+ : * exaGetPixmapOffset() returns the offset (in bytes) within the framebuffer of
+ : * the beginning of the given pixmap.
+ : *
+ : * Note that drivers are free to, and often do, munge this offset as necessary
+ : * for handing to the hardware -- for example, translating it into a different
+ : * aperture. This function may need to be extended in the future if we grow
+ : * support for having multiple card-accessible offscreen, such as an AGP memory
+ : * pool alongside the framebuffer pool.
+ : */
+ :unsigned long
+ :exaGetPixmapOffset(PixmapPtr pPix)
+ 11 0.0120 :{ /* exaGetPixmapOffset total: 35 0.0381 */
+ 3 0.0033 : ExaScreenPriv (pPix->drawable.pScreen);
+ 6 0.0065 : ExaPixmapPriv (pPix);
+ : void *ptr;
+ :
+ : /* Return the offscreen pointer if we've hidden the data. */
+ 5 0.0054 : if (pPix->devPrivate.ptr == NULL)
+ : ptr = pExaPixmap->fb_ptr;
+ : else
+ : ptr = pPix->devPrivate.ptr;
+ :
+ : return ((unsigned long)ptr - (unsigned long)pExaScr->info->memoryBase);
+ 10 0.0109 :}
+ :
+ :/**
+ : * exaGetPixmapPitch() returns the pitch (in bytes) of the given pixmap.
+ : *
+ : * This is a helper to make driver code more obvious, due to the rather obscure
+ : * naming of the pitch field in the pixmap.
+ : */
+ :unsigned long
+ :exaGetPixmapPitch(PixmapPtr pPix)
+ 2 0.0022 :{ /* exaGetPixmapPitch total: 7 0.0076 */
+ : return pPix->devKind;
+ 5 0.0054 :}
+ :
+ :/**
+ : * exaGetPixmapSize() returns the size in bytes of the given pixmap in video
+ : * memory. Only valid when the pixmap is currently in framebuffer.
+ : */
+ :unsigned long
+ :exaGetPixmapSize(PixmapPtr pPix)
+ :{
+ : ExaPixmapPrivPtr pExaPixmap;
+ :
+ : pExaPixmap = ExaGetPixmapPriv(pPix);
+ : if (pExaPixmap != NULL)
+ : return pExaPixmap->fb_size;
+ : return 0;
+ :}
+ :
+ :/**
+ : * exaGetDrawablePixmap() returns a backing pixmap for a given drawable.
+ : *
+ : * @param pDrawable the drawable being requested.
+ : *
+ : * This function returns the backing pixmap for a drawable, whether it is a
+ : * redirected window, unredirected window, or already a pixmap. Note that
+ : * coordinate translation is needed when drawing to the backing pixmap of a
+ : * redirected window, and the translation coordinates are provided by calling
+ : * exaGetOffscreenPixmap() on the drawable.
+ : */
+ :PixmapPtr
+ :exaGetDrawablePixmap(DrawablePtr pDrawable)
+ 53 0.0577 :{ /* exaGetDrawablePixmap total: 111 0.1209 */
+ 5 0.0054 : if (pDrawable->type == DRAWABLE_WINDOW)
+ : return pDrawable->pScreen->GetWindowPixmap ((WindowPtr) pDrawable);
+ : else
+ 30 0.0327 : return (PixmapPtr) pDrawable;
+ 23 0.0251 :}
+ :
+ :/**
+ : * Sets the offsets to add to coordinates to make them address the same bits in
+ : * the backing drawable. These coordinates are nonzero only for redirected
+ : * windows.
+ : */
+ :void
+ :exaGetDrawableDeltas (DrawablePtr pDrawable, PixmapPtr pPixmap,
+ : int *xp, int *yp)
+ 8 0.0087 :{ /* exaGetDrawableDeltas total: 52 0.0566 */
+ :#ifdef COMPOSITE
+ 21 0.0229 : if (pDrawable->type == DRAWABLE_WINDOW) {
+ : *xp = -pPixmap->screen_x;
+ : *yp = -pPixmap->screen_y;
+ : return;
+ : }
+ :#endif
+ :
+ 4 0.0044 : *xp = 0;
+ 1 0.0011 : *yp = 0;
+ 18 0.0196 :}
+ :
+ :/**
+ : * exaPixmapDirty() marks a pixmap as dirty, allowing for
+ : * optimizations in pixmap migration when no changes have occurred.
+ : */
+ :void
+ :exaPixmapDirty (PixmapPtr pPix, int x1, int y1, int x2, int y2)
+ 20 0.0218 :{ /* exaPixmapDirty total: 90 0.0980 */
+ 6 0.0065 : ExaPixmapPriv(pPix);
+ : BoxRec box;
+ : RegionPtr pDamageReg;
+ : RegionRec region;
+ :
+ 11 0.0120 : if (!pExaPixmap)
+ : return;
+ :
+ 3 0.0033 : box.x1 = max(x1, 0);
+ : box.y1 = max(y1, 0);
+ 6 0.0065 : box.x2 = min(x2, pPix->drawable.width);
+ 13 0.0142 : box.y2 = min(y2, pPix->drawable.height);
+ :
+ 4 0.0044 : if (box.x1 >= box.x2 || box.y1 >= box.y2)
+ : return;
+ :
+ 4 0.0044 : pDamageReg = DamageRegion(pExaPixmap->pDamage);
+ :
+ 5 0.0054 : REGION_INIT(pScreen, ®ion, &box, 1);
+ 6 0.0065 : REGION_UNION(pScreen, pDamageReg, pDamageReg, ®ion);
+ 4 0.0044 : REGION_UNINIT(pScreen, ®ion);
+ 8 0.0087 :}
+ :
+ :static Bool
+ :exaDestroyPixmap (PixmapPtr pPixmap)
+ 3 0.0033 :{ /* exaDestroyPixmap total: 4 0.0044 */
+ : if (pPixmap->refcnt == 1)
+ : {
+ : ExaPixmapPriv (pPixmap);
+ : if (pExaPixmap->area)
+ : {
+ : DBG_PIXMAP(("-- 0x%p (0x%x) (%dx%d)\n",
+ : (void*)pPixmap->drawable.id,
+ : ExaGetPixmapPriv(pPixmap)->area->offset,
+ : pPixmap->drawable.width,
+ : pPixmap->drawable.height));
+ : /* Free the offscreen area */
+ : exaOffscreenFree (pPixmap->drawable.pScreen, pExaPixmap->area);
+ 1 0.0011 : pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
+ : pPixmap->devKind = pExaPixmap->sys_pitch;
+ : }
+ : REGION_UNINIT(pPixmap->drawable.pScreen, &pExaPixmap->validReg);
+ : }
+ : return fbDestroyPixmap (pPixmap);
+ :}
+ :
+ :static int
+ :exaLog2(int val)
+ :{
+ : int bits;
+ :
+ : if (val <= 0)
+ : return 0;
+ : for (bits = 0; val != 0; bits++)
+ : val >>= 1;
+ : return bits - 1;
+ :}
+ :
+ :/**
+ : * exaCreatePixmap() creates a new pixmap.
+ : *
+ : * If width and height are 0, this won't be a full-fledged pixmap and it will
+ : * get ModifyPixmapHeader() called on it later. So, we mark it as pinned, because
+ : * ModifyPixmapHeader() would break migration. These types of pixmaps are used
+ : * for scratch pixmaps, or to represent the visible screen.
+ : */
+ :static PixmapPtr
+ :exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth)
+ 4 0.0044 :{ /* exaCreatePixmap total: 19 0.0207 */
+ : PixmapPtr pPixmap;
+ : ExaPixmapPrivPtr pExaPixmap;
+ : int bpp;
+ 1 0.0011 : ExaScreenPriv(pScreen);
+ :
+ : if (w > 32767 || h > 32767)
+ : return NullPixmap;
+ :
+ 3 0.0033 : pPixmap = fbCreatePixmap (pScreen, w, h, depth);
+ : if (!pPixmap)
+ : return NULL;
+ 1 0.0011 : pExaPixmap = ExaGetPixmapPriv(pPixmap);
+ :
+ : bpp = pPixmap->drawable.bitsPerPixel;
+ :
+ : /* Glyphs have w/h equal to zero, and may not be migrated. See exaGlyphs. */
+ 1 0.0011 : if (!w || !h)
+ : pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
+ : else
+ 2 0.0022 : pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;
+ :
+ : pExaPixmap->area = NULL;
+ :
+ : pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
+ : pExaPixmap->sys_pitch = pPixmap->devKind;
+ :
+ : pExaPixmap->fb_ptr = NULL;
+ 1 0.0011 : if (pExaScr->info->flags & EXA_OFFSCREEN_ALIGN_POT && w != 1)
+ : pExaPixmap->fb_pitch = (1 << (exaLog2(w - 1) + 1)) * bpp / 8;
+ : else
+ 1 0.0011 : pExaPixmap->fb_pitch = w * bpp / 8;
+ 4 0.0044 : pExaPixmap->fb_pitch = EXA_ALIGN(pExaPixmap->fb_pitch,
+ : pExaScr->info->pixmapPitchAlign);
+ : pExaPixmap->fb_size = pExaPixmap->fb_pitch * h;
+ :
+ : if (pExaPixmap->fb_pitch > 32767) {
+ : fbDestroyPixmap(pPixmap);
+ : return NULL;
+ : }
+ :
+ : /* Set up damage tracking */
+ : pExaPixmap->pDamage = DamageCreate (NULL, NULL, DamageReportNone, TRUE,
+ : pScreen, pPixmap);
+ :
+ : if (pExaPixmap->pDamage == NULL) {
+ : fbDestroyPixmap (pPixmap);
+ : return NULL;
+ : }
+ :
+ : DamageRegister (&pPixmap->drawable, pExaPixmap->pDamage);
+ : DamageSetReportAfterOp (pExaPixmap->pDamage, TRUE);
+ :
+ : /* None of the pixmap bits are valid initially */
+ 1 0.0011 : REGION_NULL(pScreen, &pExaPixmap->validReg);
+ :
+ : return pPixmap;
+ :}
+ :
+ :/**
+ : * exaPixmapIsOffscreen() is used to determine if a pixmap is in offscreen
+ : * memory, meaning that acceleration could probably be done to it, and that it
+ : * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it
+ : * with the CPU.
+ : *
+ : * Note that except for UploadToScreen()/DownloadFromScreen() (which explicitly
+ : * deal with moving pixmaps in and out of system memory), EXA will give drivers
+ : * pixmaps as arguments for which exaPixmapIsOffscreen() is TRUE.
+ : *
+ : * @return TRUE if the given drawable is in framebuffer memory.
+ : */
+ :Bool
+ :exaPixmapIsOffscreen(PixmapPtr p)
+ 44 0.0479 :{ /* exaPixmapIsOffscreen total: 267 0.2909 */
+ : ScreenPtr pScreen = p->drawable.pScreen;
+ 53 0.0577 : ExaScreenPriv(pScreen);
+ :
+ : /* If the devPrivate.ptr is NULL, it's offscreen but we've hidden the data.
+ : */
+ 36 0.0392 : if (p->devPrivate.ptr == NULL)
+ : return TRUE;
+ :
+ 80 0.0872 : if (pExaScr->info->PixmapIsOffscreen)
+ : return pExaScr->info->PixmapIsOffscreen(p);
+ :
+ 27 0.0294 : return ((unsigned long) ((CARD8 *) p->devPrivate.ptr -
+ : (CARD8 *) pExaScr->info->memoryBase) <
+ : pExaScr->info->memorySize);
+ 27 0.0294 :}
+ :
+ :/**
+ : * exaDrawableIsOffscreen() is a convenience wrapper for exaPixmapIsOffscreen().
+ : */
+ :Bool
+ :exaDrawableIsOffscreen (DrawablePtr pDrawable)
+ :{
+ : return exaPixmapIsOffscreen (exaGetDrawablePixmap (pDrawable));
+ :}
+ :
+ :/**
+ : * Returns the pixmap which backs a drawable, and the offsets to add to
+ : * coordinates to make them address the same bits in the backing drawable.
+ : */
+ :PixmapPtr
+ :exaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp)
+ 17 0.0185 :{ /* exaGetOffscreenPixmap total: 69 0.0752 */
+ 6 0.0065 : PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
+ :
+ 16 0.0174 : exaGetDrawableDeltas (pDrawable, pPixmap, xp, yp);
+ :
+ 15 0.0163 : if (exaPixmapIsOffscreen (pPixmap))
+ : return pPixmap;
+ : else
+ : return NULL;
+ 15 0.0163 :}
+ :
+ :/**
+ : * exaPrepareAccess() is EXA's wrapper for the driver's PrepareAccess() handler.
+ : *
+ : * It deals with waiting for synchronization with the card, determining if
+ : * PrepareAccess() is necessary, and working around PrepareAccess() failure.
+ : */
+ :void
+ :exaPrepareAccess(DrawablePtr pDrawable, int index)
+ :{ /* exaPrepareAccess total: 1 0.0011 */
+ : ScreenPtr pScreen = pDrawable->pScreen;
+ : ExaScreenPriv (pScreen);
+ : PixmapPtr pPixmap;
+ :
+ : pPixmap = exaGetDrawablePixmap (pDrawable);
+ :
+ : if (exaPixmapIsOffscreen (pPixmap))
+ : exaWaitSync (pDrawable->pScreen);
+ : else
+ : return;
+ :
+ : /* Unhide pixmap pointer */
+ : if (pPixmap->devPrivate.ptr == NULL) {
+ : ExaPixmapPriv (pPixmap);
+ :
+ : pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
+ : }
+ :
+ 1 0.0011 : if (pExaScr->info->PrepareAccess == NULL)
+ : return;
+ :
+ : if (!(*pExaScr->info->PrepareAccess) (pPixmap, index)) {
+ : ExaPixmapPriv (pPixmap);
+ : if (pExaPixmap->score != EXA_PIXMAP_SCORE_PINNED)
+ : FatalError("Driver failed PrepareAccess on a pinned pixmap\n");
+ : exaMoveOutPixmap (pPixmap);
+ : }
+ :}
+ :
+ :/**
+ : * exaFinishAccess() is EXA's wrapper for the driver's FinishAccess() handler.
+ : *
+ : * It deals with calling the driver's FinishAccess() only if necessary.
+ : */
+ :void
+ :exaFinishAccess(DrawablePtr pDrawable, int index)
+ :{ /* exaFinishAccess total: 1 0.0011 */
+ : ScreenPtr pScreen = pDrawable->pScreen;
+ 1 0.0011 : ExaScreenPriv (pScreen);
+ : PixmapPtr pPixmap;
+ : ExaPixmapPrivPtr pExaPixmap;
+ :
+ : pPixmap = exaGetDrawablePixmap (pDrawable);
+ :
+ : pExaPixmap = ExaGetPixmapPriv(pPixmap);
+ :
+ : /* Rehide pixmap pointer if we're doing that. */
+ : if (pExaPixmap != NULL && pExaScr->hideOffscreenPixmapData &&
+ : pExaPixmap->fb_ptr == pPixmap->devPrivate.ptr)
+ : {
+ : pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
+ : }
+ :
+ : if (pExaScr->info->FinishAccess == NULL)
+ : return;
+ :
+ : if (!exaPixmapIsOffscreen (pPixmap))
+ : return;
+ :
+ : (*pExaScr->info->FinishAccess) (pPixmap, index);
+ :}
+ :
+ :/**
+ : * exaValidateGC() sets the ops to EXA's implementations, which may be
+ : * accelerated or may sync the card and fall back to fb.
+ : */
+ :static void
+ :exaValidateGC (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
+ 2 0.0022 :{ /* exaValidateGC total: 8 0.0087 */
+ : /* fbValidateGC will do direct access to pixmaps if the tiling has changed.
+ : * Preempt fbValidateGC by doing its work and masking the change out, so
+ : * that we can do the Prepare/FinishAccess.
+ : */
+ :#ifdef FB_24_32BIT
+ 1 0.0011 : if ((changes & GCTile) && fbGetRotatedPixmap(pGC)) {
+ : (*pGC->pScreen->DestroyPixmap) (fbGetRotatedPixmap(pGC));
+ : fbGetRotatedPixmap(pGC) = 0;
+ : }
+ :
+ : if (pGC->fillStyle == FillTiled) {
+ : PixmapPtr pOldTile, pNewTile;
+ :
+ : pOldTile = pGC->tile.pixmap;
+ : if (pOldTile->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
+ : {
+ : pNewTile = fbGetRotatedPixmap(pGC);
+ : if (!pNewTile ||
+ : pNewTile ->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
+ : {
+ : if (pNewTile)
+ : (*pGC->pScreen->DestroyPixmap) (pNewTile);
+ : /* fb24_32ReformatTile will do direct access of a newly-
+ : * allocated pixmap. This isn't a problem yet, since we don't
+ : * put pixmaps in FB until at least one accelerated EXA op.
+ : */
+ : exaPrepareAccess(&pOldTile->drawable, EXA_PREPARE_SRC);
+ : pNewTile = fb24_32ReformatTile (pOldTile,
+ : pDrawable->bitsPerPixel);
+ : exaPixmapDirty(pNewTile, 0, 0, pNewTile->drawable.width, pNewTile->drawable.height);
+ : exaFinishAccess(&pOldTile->drawable, EXA_PREPARE_SRC);
+ : }
+ : if (pNewTile)
+ : {
+ : fbGetRotatedPixmap(pGC) = pOldTile;
+ : pGC->tile.pixmap = pNewTile;
+ : changes |= GCTile;
+ : }
+ : }
+ : }
+ :#endif
+ : if (changes & GCTile) {
+ : if (!pGC->tileIsPixel && FbEvenTile (pGC->tile.pixmap->drawable.width *
+ : pDrawable->bitsPerPixel))
+ : {
+ : /* XXX This fixes corruption with tiled pixmaps, but may just be a
+ : * workaround for broken drivers
+ : */
+ : exaMoveOutPixmap(pGC->tile.pixmap);
+ : fbPadPixmap (pGC->tile.pixmap);
+ : exaPixmapDirty(pGC->tile.pixmap, 0, 0,
+ : pGC->tile.pixmap->drawable.width,
+ : pGC->tile.pixmap->drawable.height);
+ : }
+ : /* Mask out the GCTile change notification, now that we've done FB's
+ : * job for it.
+ : */
+ : changes &= ~GCTile;
+ : }
+ :
+ 1 0.0011 : fbValidateGC (pGC, changes, pDrawable);
+ :
+ 1 0.0011 : pGC->ops = (GCOps *) &exaOps;
+ 3 0.0033 :}
+ :
+ :static GCFuncs exaGCFuncs = {
+ : exaValidateGC,
+ : miChangeGC,
+ : miCopyGC,
+ : miDestroyGC,
+ : miChangeClip,
+ : miDestroyClip,
+ : miCopyClip
+ :};
+ :
+ :/**
+ : * exaCreateGC makes a new GC and hooks up its funcs handler, so that
+ : * exaValidateGC() will get called.
+ : */
+ :static int
+ :exaCreateGC (GCPtr pGC)
+ :{
+ : if (!fbCreateGC (pGC))
+ : return FALSE;
+ :
+ : pGC->funcs = &exaGCFuncs;
+ :
+ : return TRUE;
+ :}
+ :
+ :/**
+ : * exaCloseScreen() unwraps its wrapped screen functions and tears down EXA's
+ : * screen private, before calling down to the next CloseSccreen.
+ : */
+ :static Bool
+ :exaCloseScreen(int i, ScreenPtr pScreen)
+ :{
+ : ExaScreenPriv(pScreen);
+ :#ifdef RENDER
+ : PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
+ :#endif
+ :
+ : pScreen->CreateGC = pExaScr->SavedCreateGC;
+ : pScreen->CloseScreen = pExaScr->SavedCloseScreen;
+ : pScreen->GetImage = pExaScr->SavedGetImage;
+ : pScreen->GetSpans = pExaScr->SavedGetSpans;
+ : pScreen->PaintWindowBackground = pExaScr->SavedPaintWindowBackground;
+ : pScreen->PaintWindowBorder = pExaScr->SavedPaintWindowBorder;
+ : pScreen->CreatePixmap = pExaScr->SavedCreatePixmap;
+ : pScreen->DestroyPixmap = pExaScr->SavedDestroyPixmap;
+ : pScreen->CopyWindow = pExaScr->SavedCopyWindow;
+ :#ifdef RENDER
+ : if (ps) {
+ : ps->Composite = pExaScr->SavedComposite;
+ : ps->Glyphs = pExaScr->SavedGlyphs;
+ : }
+ :#endif
+ :
+ : xfree (pExaScr);
+ :
+ : return (*pScreen->CloseScreen) (i, pScreen);
+ :}
+ :
+ :/**
+ : * This function allocates a driver structure for EXA drivers to fill in. By
+ : * having EXA allocate the structure, the driver structure can be extended
+ : * without breaking ABI between EXA and the drivers. The driver's
+ : * responsibility is to check beforehand that the EXA module has a matching
+ : * major number and sufficient minor. Drivers are responsible for freeing the
+ : * driver structure using xfree().
+ : *
+ : * @return a newly allocated, zero-filled driver structure
+ : */
+ :ExaDriverPtr
+ :exaDriverAlloc(void)
+ :{
+ : return xcalloc(1, sizeof(ExaDriverRec));
+ :}
+ :
+ :/**
+ : * @param pScreen screen being initialized
+ : * @param pScreenInfo EXA driver record
+ : *
+ : * exaDriverInit sets up EXA given a driver record filled in by the driver.
+ : * pScreenInfo should have been allocated by exaDriverAlloc(). See the
+ : * comments in _ExaDriver for what must be filled in and what is optional.
+ : *
+ : * @return TRUE if EXA was successfully initialized.
+ : */
+ :Bool
+ :exaDriverInit (ScreenPtr pScreen,
+ : ExaDriverPtr pScreenInfo)
+ :{
+ : ExaScreenPrivPtr pExaScr;
+ :#ifdef RENDER
+ : PictureScreenPtr ps;
+ :#endif
+ :
+ : if (pScreenInfo->exa_major != EXA_VERSION_MAJOR ||
+ : pScreenInfo->exa_minor > EXA_VERSION_MINOR)
+ : {
+ : LogMessage(X_ERROR, "EXA(%d): driver's EXA version requirements "
+ : "(%d.%d) are incompatible with EXA version (%d.%d)\n",
+ : pScreen->myNum,
+ : pScreenInfo->exa_major, pScreenInfo->exa_minor,
+ : EXA_VERSION_MAJOR, EXA_VERSION_MINOR);
+ : return FALSE;
+ : }
+ :
+ :#ifdef RENDER
+ : ps = GetPictureScreenIfSet(pScreen);
+ :#endif
+ : if (exaGeneration != serverGeneration)
+ : {
+ : exaScreenPrivateIndex = AllocateScreenPrivateIndex();
+ : exaPixmapPrivateIndex = AllocatePixmapPrivateIndex();
+ : exaGeneration = serverGeneration;
+ : }
+ :
+ : pExaScr = xcalloc (sizeof (ExaScreenPrivRec), 1);
+ :
+ : if (!pExaScr) {
+ : LogMessage(X_WARNING, "EXA(%d): Failed to allocate screen private\n",
+ : pScreen->myNum);
+ : return FALSE;
+ : }
+ :
+ : pExaScr->info = pScreenInfo;
+ :
+ : pScreen->devPrivates[exaScreenPrivateIndex].ptr = (pointer) pExaScr;
+ :
+ : pExaScr->migration = ExaMigrationAlways;
+ :
+ : exaDDXDriverInit(pScreen);
+ :
+ : /*
+ : * Replace various fb screen functions
+ : */
+ : pExaScr->SavedCloseScreen = pScreen->CloseScreen;
+ : pScreen->CloseScreen = exaCloseScreen;
+ :
+ : pExaScr->SavedCreateGC = pScreen->CreateGC;
+ : pScreen->CreateGC = exaCreateGC;
+ :
+ : pExaScr->SavedGetImage = pScreen->GetImage;
+ : pScreen->GetImage = exaGetImage;
+ :
+ : pExaScr->SavedGetSpans = pScreen->GetSpans;
+ : pScreen->GetSpans = exaGetSpans;
+ :
+ : pExaScr->SavedCopyWindow = pScreen->CopyWindow;
+ : pScreen->CopyWindow = exaCopyWindow;
+ :
+ : pExaScr->SavedPaintWindowBackground = pScreen->PaintWindowBackground;
+ : pScreen->PaintWindowBackground = exaPaintWindow;
+ :
+ : pExaScr->SavedPaintWindowBorder = pScreen->PaintWindowBorder;
+ : pScreen->PaintWindowBorder = exaPaintWindow;
+ :
+ : pScreen->BackingStoreFuncs.SaveAreas = ExaCheckSaveAreas;
+ : pScreen->BackingStoreFuncs.RestoreAreas = ExaCheckRestoreAreas;
+ :#ifdef RENDER
+ : if (ps) {
+ : pExaScr->SavedComposite = ps->Composite;
+ : ps->Composite = exaComposite;
+ :
+ : pExaScr->SavedRasterizeTrapezoid = ps->RasterizeTrapezoid;
+ : ps->RasterizeTrapezoid = exaRasterizeTrapezoid;
+ :
+ : pExaScr->SavedAddTriangles = ps->AddTriangles;
+ : ps->AddTriangles = exaAddTriangles;
+ :
+ : pExaScr->SavedGlyphs = ps->Glyphs;
+ : ps->Glyphs = exaGlyphs;
+ : }
+ :#endif
+ :
+ :#ifdef MITSHM
+ : /* Re-register with the MI funcs, which don't allow shared pixmaps.
+ : * Shared pixmaps are almost always a performance loss for us, but this
+ : * still allows for SHM PutImage.
+ : */
+ : ShmRegisterFuncs(pScreen, NULL);
+ :#endif
+ : /*
+ : * Hookup offscreen pixmaps
+ : */
+ : if ((pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) &&
+ : pExaScr->info->offScreenBase < pExaScr->info->memorySize)
+ : {
+ : if (!AllocatePixmapPrivate(pScreen, exaPixmapPrivateIndex,
+ : sizeof (ExaPixmapPrivRec))) {
+ : LogMessage(X_WARNING,
+ : "EXA(%d): Failed to allocate pixmap private\n",
+ : pScreen->myNum);
+ : return FALSE;
+ : }
+ : pExaScr->SavedCreatePixmap = pScreen->CreatePixmap;
+ : pScreen->CreatePixmap = exaCreatePixmap;
+ :
+ : pExaScr->SavedDestroyPixmap = pScreen->DestroyPixmap;
+ : pScreen->DestroyPixmap = exaDestroyPixmap;
+ :
+ : LogMessage(X_INFO, "EXA(%d): Offscreen pixmap area of %d bytes\n",
+ : pScreen->myNum,
+ : pExaScr->info->memorySize - pExaScr->info->offScreenBase);
+ : }
+ : else
+ : {
+ : LogMessage(X_INFO, "EXA(%d): No offscreen pixmaps\n", pScreen->myNum);
+ : if (!AllocatePixmapPrivate(pScreen, exaPixmapPrivateIndex, 0))
+ : return FALSE;
+ : }
+ :
+ : DBG_PIXMAP(("============== %ld < %ld\n", pExaScr->info->offScreenBase,
+ : pExaScr->info->memorySize));
+ : if (pExaScr->info->offScreenBase < pExaScr->info->memorySize) {
+ : if (!exaOffscreenInit (pScreen)) {
+ : LogMessage(X_WARNING, "EXA(%d): Offscreen pixmap setup failed\n",
+ : pScreen->myNum);
+ : return FALSE;
+ : }
+ : }
+ :
+ : LogMessage(X_INFO, "EXA(%d): Driver registered support for the following"
+ : " operations:\n", pScreen->myNum);
+ : assert(pScreenInfo->PrepareSolid != NULL);
+ : LogMessage(X_INFO, " Solid\n");
+ : assert(pScreenInfo->PrepareCopy != NULL);
+ : LogMessage(X_INFO, " Copy\n");
+ : if (pScreenInfo->PrepareComposite != NULL) {
+ : LogMessage(X_INFO, " Composite (RENDER acceleration)\n");
+ : }
+ : if (pScreenInfo->UploadToScreen != NULL) {
+ : LogMessage(X_INFO, " UploadToScreen\n");
+ : }
+ : if (pScreenInfo->DownloadFromScreen != NULL) {
+ : LogMessage(X_INFO, " DownloadFromScreen\n");
+ : }
+ :
+ : return TRUE;
+ :}
+ :
+ :/**
+ : * exaDriverFini tears down EXA on a given screen.
+ : *
+ : * @param pScreen screen being torn down.
+ : */
+ :void
+ :exaDriverFini (ScreenPtr pScreen)
+ :{
+ : /*right now does nothing*/
+ :}
+ :
+ :/**
+ : * exaMarkSync() should be called after any asynchronous drawing by the hardware.
+ : *
+ : * @param pScreen screen which drawing occurred on
+ : *
+ : * exaMarkSync() sets a flag to indicate that some asynchronous drawing has
+ : * happened and a WaitSync() will be necessary before relying on the contents of
+ : * offscreen memory from the CPU's perspective. It also calls an optional
+ : * driver MarkSync() callback, the return value of which may be used to do partial
+ : * synchronization with the hardware in the future.
+ : */
+ :void exaMarkSync(ScreenPtr pScreen)
+ 22 0.0240 :{ /* exaMarkSync total: 88 0.0959 */
+ 10 0.0109 : ExaScreenPriv(pScreen);
+ :
+ 13 0.0142 : pExaScr->info->needsSync = TRUE;
+ 34 0.0370 : if (pExaScr->info->MarkSync != NULL) {
+ : pExaScr->info->lastMarker = (*pExaScr->info->MarkSync)(pScreen);
+ : }
+ 9 0.0098 :}
+ :
+ :/**
+ : * exaWaitSync() ensures that all drawing has been completed.
+ : *
+ : * @param pScreen screen being synchronized.
+ : *
+ : * Calls down into the driver to ensure that all previous drawing has completed.
+ : * It should always be called before relying on the framebuffer contents
+ : * reflecting previous drawing, from a CPU perspective.
+ : */
+ :void exaWaitSync(ScreenPtr pScreen)
+ 9 0.0098 :{ /* exaWaitSync total: 102 0.1111 */
+ 5 0.0054 : ExaScreenPriv(pScreen);
+ :
+ 45 0.0490 : if (pExaScr->info->needsSync && !pExaScr->swappedOut) {
+ 4 0.0044 : (*pExaScr->info->WaitMarker)(pScreen, pExaScr->info->lastMarker);
+ 22 0.0240 : pExaScr->info->needsSync = FALSE;
+ : }
+ 17 0.0185 :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/exa/exa_render.c"
+ *
+ * 785 0.8552
+ */
+
+
+ :/*
+ : * Copyright © 2001 Keith Packard
+ : *
+ : * Partly based on code that is Copyright © The XFree86 Project Inc.
+ : *
+ : * 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 Keith Packard not be used in
+ : * advertising or publicity pertaining to distribution of the software without
+ : * specific, written prior permission. Keith Packard makes no
+ : * representations about the suitability of this software for any purpose. It
+ : * is provided "as is" without express or implied warranty.
+ : *
+ : * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ : * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ : * EVENT SHALL KEITH PACKARD 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.
+ : */
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include <stdlib.h>
+ :
+ :#include "exa_priv.h"
+ :
+ :#ifdef RENDER
+ :#include "mipict.h"
+ :
+ :#if DEBUG_TRACE_FALL
+ :static void exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n)
+ :{
+ : char format[20];
+ : char size[20];
+ : char loc;
+ : int temp;
+ :
+ : if (!pict) {
+ : snprintf(string, n, "None");
+ : return;
+ : }
+ :
+ : switch (pict->format)
+ : {
+ : case PICT_a8r8g8b8:
+ : snprintf(format, 20, "ARGB8888");
+ : break;
+ : case PICT_r5g6b5:
+ : snprintf(format, 20, "RGB565 ");
+ : break;
+ : case PICT_x1r5g5b5:
+ : snprintf(format, 20, "RGB555 ");
+ : break;
+ : case PICT_a8:
+ : snprintf(format, 20, "A8 ");
+ : break;
+ : case PICT_a1:
+ : snprintf(format, 20, "A1 ");
+ : break;
+ : default:
+ : snprintf(format, 20, "0x%x", (int)pict->format);
+ : break;
+ : }
+ :
+ : loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm';
+ :
+ : snprintf(size, 20, "%dx%d%s", pict->pDrawable->width,
+ : pict->pDrawable->height, pict->repeat ?
+ : " R" : "");
+ :
+ : snprintf(string, n, "%p:%c fmt %s (%s)", pict->pDrawable, loc, format, size);
+ :}
+ :
+ :static void
+ :exaPrintCompositeFallback(CARD8 op,
+ : PicturePtr pSrc,
+ : PicturePtr pMask,
+ : PicturePtr pDst)
+ :{
+ : char sop[20];
+ : char srcdesc[40], maskdesc[40], dstdesc[40];
+ :
+ : switch(op)
+ : {
+ : case PictOpSrc:
+ : sprintf(sop, "Src");
+ : break;
+ : case PictOpOver:
+ : sprintf(sop, "Over");
+ : break;
+ : default:
+ : sprintf(sop, "0x%x", (int)op);
+ : break;
+ : }
+ :
+ : exaCompositeFallbackPictDesc(pSrc, srcdesc, 40);
+ : exaCompositeFallbackPictDesc(pMask, maskdesc, 40);
+ : exaCompositeFallbackPictDesc(pDst, dstdesc, 40);
+ :
+ : ErrorF("Composite fallback: op %s, \n"
+ : " src %s, \n"
+ : " mask %s, \n"
+ : " dst %s, \n",
+ : sop, srcdesc, maskdesc, dstdesc);
+ :}
+ :#endif /* DEBUG_TRACE_FALL */
+ :
+ :static Bool
+ :exaOpReadsDestination (CARD8 op)
+ 1 0.0011 :{ /* exaOpReadsDestination total: 4 0.0044 */
+ : /* FALSE (does not read destination) is the list of ops in the protocol
+ : * document with "0" in the "Fb" column and no "Ab" in the "Fa" column.
+ : * That's just Clear and Src. ReduceCompositeOp() will already have
+ : * converted con/disjoint clear/src to Clear or Src.
+ : */
+ 3 0.0033 : switch (op) {
+ : case PictOpClear:
+ : case PictOpSrc:
+ : return FALSE;
+ : default:
+ : return TRUE;
+ : }
+ :}
+ :
+ :
+ :static Bool
+ :exaGetPixelFromRGBA(CARD32 *pixel,
+ : CARD16 red,
+ : CARD16 green,
+ : CARD16 blue,
+ : CARD16 alpha,
+ : CARD32 format)
+ :{
+ : int rbits, bbits, gbits, abits;
+ : int rshift, bshift, gshift, ashift;
+ :
+ : *pixel = 0;
+ :
+ : if (!PICT_FORMAT_COLOR(format))
+ : return FALSE;
+ :
+ : rbits = PICT_FORMAT_R(format);
+ : gbits = PICT_FORMAT_G(format);
+ : bbits = PICT_FORMAT_B(format);
+ : abits = PICT_FORMAT_A(format);
+ :
+ : if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
+ : bshift = 0;
+ : gshift = bbits;
+ : rshift = gshift + gbits;
+ : ashift = rshift + rbits;
+ : } else { /* PICT_TYPE_ABGR */
+ : rshift = 0;
+ : gshift = rbits;
+ : bshift = gshift + gbits;
+ : ashift = bshift + bbits;
+ : }
+ :
+ : *pixel |= ( blue >> (16 - bbits)) << bshift;
+ : *pixel |= ( red >> (16 - rbits)) << rshift;
+ : *pixel |= (green >> (16 - gbits)) << gshift;
+ : *pixel |= (alpha >> (16 - abits)) << ashift;
+ :
+ : return TRUE;
+ :}
+ :
+ :static Bool
+ :exaGetRGBAFromPixel(CARD32 pixel,
+ : CARD16 *red,
+ : CARD16 *green,
+ : CARD16 *blue,
+ : CARD16 *alpha,
+ : CARD32 format)
+ :{
+ : int rbits, bbits, gbits, abits;
+ : int rshift, bshift, gshift, ashift;
+ :
+ : if (!PICT_FORMAT_COLOR(format))
+ : return FALSE;
+ :
+ : rbits = PICT_FORMAT_R(format);
+ : gbits = PICT_FORMAT_G(format);
+ : bbits = PICT_FORMAT_B(format);
+ : abits = PICT_FORMAT_A(format);
+ :
+ : if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
+ : bshift = 0;
+ : gshift = bbits;
+ : rshift = gshift + gbits;
+ : ashift = rshift + rbits;
+ : } else { /* PICT_TYPE_ABGR */
+ : rshift = 0;
+ : gshift = rbits;
+ : bshift = gshift + gbits;
+ : ashift = bshift + bbits;
+ : }
+ :
+ : *red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits);
+ : while (rbits < 16) {
+ : *red |= *red >> rbits;
+ : rbits <<= 1;
+ : }
+ :
+ : *green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits);
+ : while (gbits < 16) {
+ : *green |= *green >> gbits;
+ : gbits <<= 1;
+ : }
+ :
+ : *blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits);
+ : while (bbits < 16) {
+ : *blue |= *blue >> bbits;
+ : bbits <<= 1;
+ : }
+ :
+ : if (abits) {
+ : *alpha = ((pixel >> ashift ) & ((1 << abits) - 1)) << (16 - abits);
+ : while (abits < 16) {
+ : *alpha |= *alpha >> abits;
+ : abits <<= 1;
+ : }
+ : } else
+ : *alpha = 0xffff;
+ :
+ : return TRUE;
+ :}
+ :
+ :static int
+ :exaTryDriverSolidFill(PicturePtr pSrc,
+ : PicturePtr pDst,
+ : INT16 xSrc,
+ : INT16 ySrc,
+ : INT16 xDst,
+ : INT16 yDst,
+ : CARD16 width,
+ : CARD16 height)
+ :{
+ : ExaScreenPriv (pDst->pDrawable->pScreen);
+ : RegionRec region;
+ : BoxPtr pbox;
+ : int nbox;
+ : int dst_off_x, dst_off_y;
+ : PixmapPtr pSrcPix, pDstPix;
+ : CARD32 pixel;
+ : CARD16 red, green, blue, alpha;
+ : ExaMigrationRec pixmaps[1];
+ :
+ : xDst += pDst->pDrawable->x;
+ : yDst += pDst->pDrawable->y;
+ : xSrc += pSrc->pDrawable->x;
+ : ySrc += pSrc->pDrawable->y;
+ :
+ : if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst,
+ : xSrc, ySrc, 0, 0, xDst, yDst,
+ : width, height))
+ : return 1;
+ :
+ : pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable);
+ : pixel = exaGetPixmapFirstPixel (pSrcPix);
+ :
+ : pixmaps[0].as_dst = TRUE;
+ : pixmaps[0].as_src = FALSE;
+ : pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable);
+ : exaDoMigration(pixmaps, 1, TRUE);
+ :
+ : pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y);
+ : if (!pDstPix) {
+ : REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
+ : return 0;
+ : }
+ :
+ : if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha,
+ : pSrc->format))
+ : {
+ : REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
+ : return -1;
+ : }
+ :
+ : if (!exaGetPixelFromRGBA(&pixel, red, green, blue, alpha,
+ : pDst->format))
+ : {
+ : REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
+ : return -1;
+ : }
+ :
+ : if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel))
+ : {
+ : REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
+ : return -1;
+ : }
+ :
+ : nbox = REGION_NUM_RECTS(®ion);
+ : pbox = REGION_RECTS(®ion);
+ :
+ : while (nbox--)
+ : {
+ : (*pExaScr->info->Solid) (pDstPix,
+ : pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
+ : pbox->x2 + dst_off_x, pbox->y2 + dst_off_y);
+ : pbox++;
+ : }
+ :
+ : (*pExaScr->info->DoneSolid) (pDstPix);
+ : exaMarkSync(pDst->pDrawable->pScreen);
+ :
+ : REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
+ : return 1;
+ :}
+ :
+ :static int
+ :exaTryDriverComposite(CARD8 op,
+ : PicturePtr pSrc,
+ : PicturePtr pMask,
+ : PicturePtr pDst,
+ : INT16 xSrc,
+ : INT16 ySrc,
+ : INT16 xMask,
+ : INT16 yMask,
+ : INT16 xDst,
+ : INT16 yDst,
+ : CARD16 width,
+ : CARD16 height)
+ 49 0.0534 :{ /* exaTryDriverComposite total: 348 0.3791 */
+ 23 0.0251 : ExaScreenPriv (pDst->pDrawable->pScreen);
+ : RegionRec region;
+ : BoxPtr pbox;
+ : int nbox;
+ : int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y;
+ : PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix;
+ : struct _Pixmap scratch;
+ : ExaMigrationRec pixmaps[3];
+ :
+ 10 0.0109 : pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
+ 5 0.0054 : pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
+ 2 0.0022 : if (pMask)
+ 2 0.0022 : pMaskPix = exaGetDrawablePixmap(pMask->pDrawable);
+ :
+ : /* Bail if we might exceed coord limits by rendering from/to these. We
+ : * should really be making some scratch pixmaps with offsets and coords
+ : * adjusted to deal with this, but it hasn't been done yet.
+ : */
+ 24 0.0261 : if (pSrcPix->drawable.width > pExaScr->info->maxX ||
+ : pSrcPix->drawable.height > pExaScr->info->maxY ||
+ : pDstPix->drawable.width > pExaScr->info->maxX ||
+ : pDstPix->drawable.height > pExaScr->info->maxY ||
+ : (pMask && (pMaskPix->drawable.width > pExaScr->info->maxX ||
+ : pMaskPix->drawable.height > pExaScr->info->maxY)))
+ : {
+ : return -1;
+ : }
+ :
+ 14 0.0153 : xDst += pDst->pDrawable->x;
+ 2 0.0022 : yDst += pDst->pDrawable->y;
+ :
+ : if (pMask) {
+ 7 0.0076 : xMask += pMask->pDrawable->x;
+ 10 0.0109 : yMask += pMask->pDrawable->y;
+ : }
+ :
+ 9 0.0098 : xSrc += pSrc->pDrawable->x;
+ 2 0.0022 : ySrc += pSrc->pDrawable->y;
+ :
+ 23 0.0251 : if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst,
+ : xSrc, ySrc, xMask, yMask, xDst, yDst,
+ : width, height))
+ : return 1;
+ :
+ 38 0.0414 : if (pExaScr->info->CheckComposite &&
+ : !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst))
+ : {
+ : REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
+ : return -1;
+ : }
+ :
+ : pixmaps[0].as_dst = TRUE;
+ : pixmaps[0].as_src = exaOpReadsDestination(op);
+ 1 0.0011 : pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable);
+ : pixmaps[1].as_dst = FALSE;
+ : pixmaps[1].as_src = TRUE;
+ 3 0.0033 : pixmaps[1].pPix = exaGetDrawablePixmap (pSrc->pDrawable);
+ : if (pMask) {
+ : pixmaps[2].as_dst = FALSE;
+ : pixmaps[2].as_src = TRUE;
+ 6 0.0065 : pixmaps[2].pPix = exaGetDrawablePixmap (pMask->pDrawable);
+ 2 0.0022 : exaDoMigration(pixmaps, 3, TRUE);
+ : } else {
+ 2 0.0022 : exaDoMigration(pixmaps, 2, TRUE);
+ : }
+ :
+ 4 0.0044 : pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y);
+ : if (pMask)
+ 3 0.0033 : pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x,
+ : &mask_off_y);
+ 2 0.0022 : pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y);
+ :
+ : if (!pDstPix) {
+ : REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
+ : return 0;
+ : }
+ :
+ 1 0.0011 : if (!pSrcPix && (!pMask || pMaskPix) && pExaScr->info->UploadToScratch) {
+ : pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable);
+ : if ((*pExaScr->info->UploadToScratch) (pSrcPix, &scratch))
+ : pSrcPix = &scratch;
+ : } else if (pSrcPix && pMask && !pMaskPix && pExaScr->info->UploadToScratch) {
+ : pMaskPix = exaGetDrawablePixmap (pMask->pDrawable);
+ : if ((*pExaScr->info->UploadToScratch) (pMaskPix, &scratch))
+ : pMaskPix = &scratch;
+ : }
+ :
+ 2 0.0022 : if (!pSrcPix || (pMask && !pMaskPix)) {
+ : REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
+ : return 0;
+ : }
+ :
+ 9 0.0098 : if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix,
+ : pMaskPix, pDstPix))
+ : {
+ 5 0.0054 : REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
+ : return -1;
+ : }
+ :
+ 1 0.0011 : nbox = REGION_NUM_RECTS(®ion);
+ : pbox = REGION_RECTS(®ion);
+ :
+ : xMask -= xDst;
+ 16 0.0174 : yMask -= yDst;
+ :
+ : xSrc -= xDst;
+ : ySrc -= yDst;
+ :
+ 5 0.0054 : while (nbox--)
+ : {
+ 26 0.0283 : (*pExaScr->info->Composite) (pDstPix,
+ : pbox->x1 + xSrc + src_off_x,
+ : pbox->y1 + ySrc + src_off_y,
+ : pbox->x1 + xMask + mask_off_x,
+ : pbox->y1 + yMask + mask_off_y,
+ : pbox->x1 + dst_off_x,
+ : pbox->y1 + dst_off_y,
+ : pbox->x2 - pbox->x1,
+ : pbox->y2 - pbox->y1);
+ : pbox++;
+ : }
+ 3 0.0033 : (*pExaScr->info->DoneComposite) (pDstPix);
+ 12 0.0131 : exaMarkSync(pDst->pDrawable->pScreen);
+ :
+ 7 0.0076 : REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
+ : return 1;
+ 18 0.0196 :}
+ :
+ :/**
+ : * exaTryMagicTwoPassCompositeHelper implements PictOpOver using two passes of
+ : * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component
+ : * alpha and limited 1-tmu cards.
+ : *
+ : * From http://anholt.livejournal.com/32058.html:
+ : *
+ : * The trouble is that component-alpha rendering requires two different sources
+ : * for blending: one for the source value to the blender, which is the
+ : * per-channel multiplication of source and mask, and one for the source alpha
+ : * for multiplying with the destination channels, which is the multiplication
+ : * of the source channels by the mask alpha. So the equation for Over is:
+ : *
+ : * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
+ : * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
+ : * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
+ : * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
+ : *
+ : * But we can do some simpler operations, right? How about PictOpOutReverse,
+ : * which has a source factor of 0 and dest factor of (1 - source alpha). We
+ : * can get the source alpha value (srca.X = src.A * mask.X) out of the texture
+ : * blenders pretty easily. So we can do a component-alpha OutReverse, which
+ : * gets us:
+ : *
+ : * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
+ : * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
+ : * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
+ : * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
+ : *
+ : * OK. And if an op doesn't use the source alpha value for the destination
+ : * factor, then we can do the channel multiplication in the texture blenders
+ : * to get the source value, and ignore the source alpha that we wouldn't use.
+ : * We've supported this in the Radeon driver for a long time. An example would
+ : * be PictOpAdd, which does:
+ : *
+ : * dst.A = src.A * mask.A + dst.A
+ : * dst.R = src.R * mask.R + dst.R
+ : * dst.G = src.G * mask.G + dst.G
+ : * dst.B = src.B * mask.B + dst.B
+ : *
+ : * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
+ : * after it, we get:
+ : *
+ : * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
+ : * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
+ : * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
+ : * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
+ : */
+ :
+ :static int
+ :exaTryMagicTwoPassCompositeHelper(CARD8 op,
+ : PicturePtr pSrc,
+ : PicturePtr pMask,
+ : PicturePtr pDst,
+ : INT16 xSrc,
+ : INT16 ySrc,
+ : INT16 xMask,
+ : INT16 yMask,
+ : INT16 xDst,
+ : INT16 yDst,
+ : CARD16 width,
+ : CARD16 height)
+ :{
+ : ExaScreenPriv (pDst->pDrawable->pScreen);
+ : DrawablePtr pDstDraw = pDst->pDrawable;
+ : PixmapPtr pDstPixmap = exaGetDrawablePixmap(pDstDraw);
+ : int xoff, yoff;
+ :
+ : assert(op == PictOpOver);
+ :
+ : if (pExaScr->info->CheckComposite &&
+ : (!(*pExaScr->info->CheckComposite)(PictOpOutReverse, pSrc, pMask,
+ : pDst) ||
+ : !(*pExaScr->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst)))
+ : {
+ : return -1;
+ : }
+ :
+ : /* Now, we think we should be able to accelerate this operation. First,
+ : * composite the destination to be the destination times the source alpha
+ : * factors.
+ : */
+ : exaComposite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
+ : xDst, yDst, width, height);
+ :
+ : exaGetDrawableDeltas(pDstDraw, pDstPixmap, &xoff, &yoff);
+ : xoff += pDstDraw->x;
+ : yoff += pDstDraw->y;
+ : exaPixmapDirty(pDstPixmap, xDst + xoff, yDst + yoff, xDst + xoff + width,
+ : yDst + yoff + height);
+ :
+ : /* Then, add in the source value times the destination alpha factors (1.0).
+ : */
+ : exaComposite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
+ : xDst, yDst, width, height);
+ :
+ : return 1;
+ :}
+ :
+ :void
+ :exaComposite(CARD8 op,
+ : PicturePtr pSrc,
+ : PicturePtr pMask,
+ : PicturePtr pDst,
+ : INT16 xSrc,
+ : INT16 ySrc,
+ : INT16 xMask,
+ : INT16 yMask,
+ : INT16 xDst,
+ : INT16 yDst,
+ : CARD16 width,
+ : CARD16 height)
+ 48 0.0523 :{ /* exaComposite total: 354 0.3856 */
+ 39 0.0425 : ExaScreenPriv (pDst->pDrawable->pScreen);
+ : int ret = -1;
+ 5 0.0054 : Bool saveSrcRepeat = pSrc->repeat;
+ 3 0.0033 : Bool saveMaskRepeat = pMask ? pMask->repeat : 0;
+ : ExaMigrationRec pixmaps[3];
+ : int npixmaps = 1;
+ : PixmapPtr pSrcPixmap = NULL;
+ :
+ : pixmaps[0].as_dst = TRUE;
+ : pixmaps[0].as_src = exaOpReadsDestination(op);
+ 2 0.0022 : pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable);
+ :
+ 4 0.0044 : if (pSrc->pDrawable) {
+ 3 0.0033 : pSrcPixmap = exaGetDrawablePixmap (pSrc->pDrawable);
+ : pixmaps[npixmaps].as_dst = FALSE;
+ : pixmaps[npixmaps].as_src = TRUE;
+ : pixmaps[npixmaps].pPix = pSrcPixmap;
+ : npixmaps++;
+ : }
+ :
+ 1 0.0011 : if (pMask && pMask->pDrawable) {
+ : pixmaps[npixmaps].as_dst = FALSE;
+ : pixmaps[npixmaps].as_src = TRUE;
+ : pixmaps[npixmaps].pPix = exaGetDrawablePixmap (pMask->pDrawable);
+ : npixmaps++;
+ : }
+ :
+ : /* We currently don't support acceleration of gradients, or other pictures
+ : * with a NULL pDrawable.
+ : */
+ 14 0.0153 : if (pExaScr->swappedOut ||
+ : pSrc->pDrawable == NULL || (pMask != NULL && pMask->pDrawable == NULL))
+ : {
+ : goto fallback;
+ : }
+ :
+ : /* Remove repeat in source if useless */
+ 18 0.0196 : if (pSrc->repeat && !pSrc->transform && xSrc >= 0 &&
+ : (xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 &&
+ : (ySrc + height) <= pSrc->pDrawable->height)
+ : pSrc->repeat = 0;
+ :
+ 3 0.0033 : if (!pMask)
+ : {
+ 3 0.0033 : if ((op == PictOpSrc &&
+ : ((pSrc->format == pDst->format) ||
+ : (pSrc->format==PICT_a8r8g8b8 && pDst->format==PICT_x8r8g8b8) ||
+ : (pSrc->format==PICT_a8b8g8r8 && pDst->format==PICT_x8b8g8r8))) ||
+ : (op == PictOpOver && !pSrc->alphaMap && !pDst->alphaMap &&
+ : pSrc->format == pDst->format &&
+ : (pSrc->format==PICT_x8r8g8b8 || pSrc->format==PICT_x8b8g8r8)))
+ : {
+ : if (pSrc->pDrawable->width == 1 &&
+ : pSrc->pDrawable->height == 1 &&
+ : pSrc->repeat)
+ : {
+ : ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst,
+ : width, height);
+ : if (ret == 1)
+ : goto done;
+ : }
+ : else if (pSrcPixmap && !pSrc->repeat && !pSrc->transform)
+ : {
+ : RegionRec region;
+ :
+ : xDst += pDst->pDrawable->x;
+ : yDst += pDst->pDrawable->y;
+ : xSrc += pSrc->pDrawable->x;
+ : ySrc += pSrc->pDrawable->y;
+ :
+ : if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst,
+ : xSrc, ySrc, xMask, yMask, xDst,
+ : yDst, width, height))
+ : goto done;
+ :
+ :
+ : exaCopyNtoN (pSrc->pDrawable, pDst->pDrawable, NULL,
+ : REGION_RECTS(®ion), REGION_NUM_RECTS(®ion),
+ : xSrc - xDst, ySrc - yDst,
+ : FALSE, FALSE, 0, NULL);
+ : REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
+ : goto done;
+ : }
+ : else if (pSrcPixmap && !pSrc->transform &&
+ : pSrc->repeatType == RepeatNormal)
+ : {
+ : RegionRec region;
+ : DDXPointRec srcOrg;
+ :
+ : /* Let's see if the driver can do the repeat in one go */
+ : if (pExaScr->info->PrepareComposite && !pSrc->alphaMap &&
+ : !pDst->alphaMap)
+ : {
+ : ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc,
+ : ySrc, xMask, yMask, xDst, yDst,
+ : width, height);
+ : if (ret == 1)
+ : goto done;
+ : }
+ :
+ : /* Now see if we can use exaFillRegionTiled() */
+ : xDst += pDst->pDrawable->x;
+ : yDst += pDst->pDrawable->y;
+ : xSrc += pSrc->pDrawable->x;
+ : ySrc += pSrc->pDrawable->y;
+ :
+ : if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, xSrc,
+ : ySrc, xMask, yMask, xDst, yDst,
+ : width, height))
+ : goto done;
+ :
+ : srcOrg.x = (xSrc - xDst) % pSrcPixmap->drawable.width;
+ : srcOrg.y = (ySrc - yDst) % pSrcPixmap->drawable.height;
+ :
+ : ret = exaFillRegionTiled(pDst->pDrawable, ®ion, pSrcPixmap,
+ : &srcOrg, FB_ALLONES, GXcopy);
+ :
+ : REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
+ :
+ : if (ret)
+ : goto done;
+ : }
+ : }
+ : }
+ :
+ : /* Remove repeat in mask if useless */
+ 12 0.0131 : if (pMask && pMask->repeat && !pMask->transform && xMask >= 0 &&
+ : (xMask + width) <= pMask->pDrawable->width && yMask >= 0 &&
+ : (yMask + height) <= pMask->pDrawable->height)
+ : pMask->repeat = 0;
+ :
+ 37 0.0403 : if (pExaScr->info->PrepareComposite &&
+ : (!pSrc->repeat || pSrc->repeatType == RepeatNormal) &&
+ : (!pMask || !pMask->repeat || pMask->repeatType == RepeatNormal) &&
+ : !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap)
+ : {
+ : Bool isSrcSolid;
+ :
+ 59 0.0643 : ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask,
+ : yMask, xDst, yDst, width, height);
+ 3 0.0033 : if (ret == 1)
+ : goto done;
+ :
+ : /* For generic masks and solid src pictures, mach64 can do Over in two
+ : * passes, similar to the component-alpha case.
+ : */
+ 8 0.0087 : isSrcSolid = pSrc->pDrawable->width == 1 &&
+ : pSrc->pDrawable->height == 1 &&
+ : pSrc->repeat;
+ :
+ : /* If we couldn't do the Composite in a single pass, and it was a
+ : * component-alpha Over, see if we can do it in two passes with
+ : * an OutReverse and then an Add.
+ : */
+ 2 0.0022 : if (ret == -1 && op == PictOpOver && pMask &&
+ : (pMask->componentAlpha || isSrcSolid)) {
+ : ret = exaTryMagicTwoPassCompositeHelper(op, pSrc, pMask, pDst,
+ : xSrc, ySrc,
+ : xMask, yMask, xDst, yDst,
+ : width, height);
+ : if (ret == 1)
+ : goto done;
+ : }
+ : }
+ :
+ :fallback:
+ : return;
+ :#if DEBUG_TRACE_FALL
+ : exaPrintCompositeFallback (op, pSrc, pMask, pDst);
+ :#endif
+ :
+ : exaDoMigration(pixmaps, npixmaps, FALSE);
+ : ExaCheckComposite (op, pSrc, pMask, pDst, xSrc, ySrc,
+ : xMask, yMask, xDst, yDst, width, height);
+ :
+ :done:
+ 15 0.0163 : pSrc->repeat = saveSrcRepeat;
+ 3 0.0033 : if (pMask)
+ 18 0.0196 : pMask->repeat = saveMaskRepeat;
+ 6 0.0065 :}
+ :#endif
+ :
+ :#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
+ :
+ :/**
+ : * exaRasterizeTrapezoid is just a wrapper around the software implementation.
+ : *
+ : * The trapezoid specification is basically too hard to be done in hardware (at
+ : * the very least, without programmability), so we just do the appropriate
+ : * Prepare/FinishAccess for it before using fbtrap.c.
+ : */
+ :void
+ :exaRasterizeTrapezoid (PicturePtr pPicture, xTrapezoid *trap,
+ : int x_off, int y_off)
+ :{ /* exaRasterizeTrapezoid total: 2 0.0022 */
+ : DrawablePtr pDraw = pPicture->pDrawable;
+ : ExaMigrationRec pixmaps[1];
+ : int xoff, yoff;
+ :
+ : pixmaps[0].as_dst = TRUE;
+ : pixmaps[0].as_src = TRUE;
+ 1 0.0011 : pixmaps[0].pPix = exaGetDrawablePixmap (pDraw);
+ 1 0.0011 : exaDoMigration(pixmaps, 1, FALSE);
+ :
+ : exaPrepareAccess(pDraw, EXA_PREPARE_DEST);
+ : fbRasterizeTrapezoid(pPicture, trap, x_off, y_off);
+ : exaGetDrawableDeltas(pDraw, pixmaps[0].pPix, &xoff, &yoff);
+ : exaPixmapDirty(pixmaps[0].pPix, pDraw->x + xoff, pDraw->y + yoff,
+ : pDraw->x + xoff + pDraw->width,
+ : pDraw->y + yoff + pDraw->height);
+ : exaFinishAccess(pDraw, EXA_PREPARE_DEST);
+ :}
+ :
+ :/**
+ : * exaAddTriangles does migration and syncing before dumping down to the
+ : * software implementation.
+ : */
+ :void
+ :exaAddTriangles (PicturePtr pPicture, INT16 x_off, INT16 y_off, int ntri,
+ : xTriangle *tris)
+ :{
+ : DrawablePtr pDraw = pPicture->pDrawable;
+ : ExaMigrationRec pixmaps[1];
+ : int xoff, yoff;
+ :
+ : pixmaps[0].as_dst = TRUE;
+ : pixmaps[0].as_src = TRUE;
+ : pixmaps[0].pPix = exaGetDrawablePixmap (pDraw);
+ : exaDoMigration(pixmaps, 1, FALSE);
+ :
+ : exaPrepareAccess(pDraw, EXA_PREPARE_DEST);
+ : fbAddTriangles(pPicture, x_off, y_off, ntri, tris);
+ : exaGetDrawableDeltas(pDraw, pixmaps[0].pPix, &xoff, &yoff);
+ : exaPixmapDirty(pixmaps[0].pPix, pDraw->x + xoff, pDraw->y + yoff,
+ : pDraw->x + xoff + pDraw->width,
+ : pDraw->y + yoff + pDraw->height);
+ : exaFinishAccess(pDraw, EXA_PREPARE_DEST);
+ :}
+ :
+ :/**
+ : * Returns TRUE if the glyphs in the lists intersect. Only checks based on
+ : * bounding box, which appears to be good enough to catch most cases at least.
+ : */
+ :static Bool
+ :exaGlyphsIntersect(int nlist, GlyphListPtr list, GlyphPtr *glyphs)
+ :{
+ : int x1, x2, y1, y2;
+ : int n;
+ : GlyphPtr glyph;
+ : int x, y;
+ : BoxRec extents;
+ : Bool first = TRUE;
+ :
+ : x = 0;
+ : y = 0;
+ : while (nlist--) {
+ : x += list->xOff;
+ : y += list->yOff;
+ : n = list->len;
+ : list++;
+ : while (n--) {
+ : glyph = *glyphs++;
+ :
+ : if (glyph->info.width == 0 || glyph->info.height == 0) {
+ : x += glyph->info.xOff;
+ : y += glyph->info.yOff;
+ : continue;
+ : }
+ :
+ : x1 = x - glyph->info.x;
+ : if (x1 < MINSHORT)
+ : x1 = MINSHORT;
+ : y1 = y - glyph->info.y;
+ : if (y1 < MINSHORT)
+ : y1 = MINSHORT;
+ : x2 = x1 + glyph->info.width;
+ : if (x2 > MAXSHORT)
+ : x2 = MAXSHORT;
+ : y2 = y1 + glyph->info.height;
+ : if (y2 > MAXSHORT)
+ : y2 = MAXSHORT;
+ :
+ : if (first) {
+ : extents.x1 = x1;
+ : extents.y1 = y1;
+ : extents.x2 = x2;
+ : extents.y2 = y2;
+ : first = FALSE;
+ : } else {
+ : if (x1 < extents.x2 && x2 > extents.x1 &&
+ : y1 < extents.y2 && y2 > extents.y1)
+ : {
+ : return TRUE;
+ : }
+ :
+ : if (x1 < extents.x1)
+ : extents.x1 = x1;
+ : if (x2 > extents.x2)
+ : extents.x2 = x2;
+ : if (y1 < extents.y1)
+ : extents.y1 = y1;
+ : if (y2 > extents.y2)
+ : extents.y2 = y2;
+ : }
+ : x += glyph->info.xOff;
+ : y += glyph->info.yOff;
+ : }
+ : }
+ :
+ : return FALSE;
+ :}
+ :
+ :/* exaGlyphs is a slight variation on miGlyphs, to support acceleration. The
+ : * issue is that miGlyphs' use of ModifyPixmapHeader makes it impossible to
+ : * migrate these pixmaps. So, instead we create a pixmap at the beginning of
+ : * the loop and upload each glyph into the pixmap before compositing.
+ : */
+ :void
+ :exaGlyphs (CARD8 op,
+ : PicturePtr pSrc,
+ : PicturePtr pDst,
+ : PictFormatPtr maskFormat,
+ : INT16 xSrc,
+ : INT16 ySrc,
+ : int nlist,
+ : GlyphListPtr list,
+ : GlyphPtr *glyphs)
+ 1 0.0011 :{ /* exaGlyphs total: 185 0.2015 */
+ : ExaScreenPriv (pDst->pDrawable->pScreen);
+ : PixmapPtr pPixmap = NULL;
+ : PicturePtr pPicture;
+ : PixmapPtr pMaskPixmap = NULL;
+ 1 0.0011 : PixmapPtr pDstPixmap = exaGetDrawablePixmap(pDst->pDrawable);
+ : PicturePtr pMask;
+ : ScreenPtr pScreen = pDst->pDrawable->pScreen;
+ : int width = 0, height = 0;
+ : int x, y, x1, y1, xoff, yoff;
+ 1 0.0011 : int xDst = list->xOff, yDst = list->yOff;
+ : int n;
+ : int error;
+ : BoxRec extents;
+ : CARD32 component_alpha;
+ :
+ : /* If we have a mask format but it's the same as all the glyphs and
+ : * the glyphs don't intersect, we can avoid accumulating the glyphs in the
+ : * temporary picture.
+ : */
+ : if (maskFormat != NULL) {
+ : Bool sameFormat = TRUE;
+ : int i;
+ :
+ 1 0.0011 : for (i = 0; i < nlist; i++) {
+ : if (maskFormat->format != list[i].format->format) {
+ : sameFormat = FALSE;
+ : break;
+ : }
+ : }
+ : if (sameFormat) {
+ : if (!exaGlyphsIntersect(nlist, list, glyphs)) {
+ : maskFormat = NULL;
+ : }
+ : }
+ : }
+ :
+ : /* If the driver doesn't support accelerated composite, there's no point in
+ : * going to this extra work. Assume that any driver that supports Composite
+ : * will be able to support component alpha using the two-pass helper.
+ : */
+ : if (!pExaScr->info->PrepareComposite)
+ : {
+ : miGlyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
+ : return;
+ : }
+ :
+ : if (maskFormat)
+ : {
+ : GCPtr pGC;
+ : xRectangle rect;
+ :
+ 1 0.0011 : miGlyphExtents (nlist, list, glyphs, &extents);
+ :
+ : extents.x1 = max(extents.x1, 0);
+ : extents.y1 = max(extents.y1, 0);
+ : extents.x2 = min(extents.x2, pDst->pDrawable->width);
+ 1 0.0011 : extents.y2 = min(extents.y2, pDst->pDrawable->height);
+ :
+ : if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
+ : return;
+ : width = extents.x2 - extents.x1;
+ : height = extents.y2 - extents.y1;
+ : pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
+ : maskFormat->depth);
+ : if (!pMaskPixmap)
+ : return;
+ : component_alpha = NeedsComponent(maskFormat->format);
+ 1 0.0011 : pMask = CreatePicture (0, &pMaskPixmap->drawable,
+ : maskFormat, CPComponentAlpha, &component_alpha,
+ : serverClient, &error);
+ : if (!pMask)
+ : {
+ : (*pScreen->DestroyPixmap) (pMaskPixmap);
+ : return;
+ : }
+ : ValidatePicture(pMask);
+ : pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen);
+ : ValidateGC (&pMaskPixmap->drawable, pGC);
+ : rect.x = 0;
+ : rect.y = 0;
+ : rect.width = width;
+ : rect.height = height;
+ 1 0.0011 : (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect);
+ : exaPixmapDirty(pMaskPixmap, 0, 0, width, height);
+ : FreeScratchGC (pGC);
+ : x = -extents.x1;
+ : y = -extents.y1;
+ : }
+ : else
+ : {
+ : pMask = pDst;
+ : x = 0;
+ : y = 0;
+ : }
+ :
+ : exaGetDrawableDeltas(pDst->pDrawable, pDstPixmap, &xoff, &yoff);
+ :
+ : while (nlist--)
+ : {
+ : GCPtr pGC = NULL;
+ : int maxwidth = 0, maxheight = 0, i;
+ : ExaMigrationRec pixmaps[1];
+ : PixmapPtr pScratchPixmap = NULL;
+ :
+ : x += list->xOff;
+ : y += list->yOff;
+ : n = list->len;
+ : for (i = 0; i < n; i++) {
+ 14 0.0153 : if (glyphs[i]->info.width > maxwidth)
+ : maxwidth = glyphs[i]->info.width;
+ : if (glyphs[i]->info.height > maxheight)
+ : maxheight = glyphs[i]->info.height;
+ : }
+ 1 0.0011 : if (maxwidth == 0 || maxheight == 0) {
+ : while (n--)
+ : {
+ : GlyphPtr glyph;
+ :
+ : glyph = *glyphs++;
+ : x += glyph->info.xOff;
+ : y += glyph->info.yOff;
+ : }
+ : list++;
+ : continue;
+ : }
+ :
+ : /* Create the (real) temporary pixmap to store the current glyph in */
+ 1 0.0011 : pPixmap = (*pScreen->CreatePixmap) (pScreen, maxwidth, maxheight,
+ : list->format->depth);
+ : if (!pPixmap)
+ : return;
+ :
+ : /* Create a temporary picture to wrap the temporary pixmap, so it can be
+ : * used as a source for Composite.
+ : */
+ : component_alpha = NeedsComponent(list->format->format);
+ : pPicture = CreatePicture (0, &pPixmap->drawable, list->format,
+ : CPComponentAlpha, &component_alpha,
+ : serverClient, &error);
+ : if (!pPicture) {
+ : (*pScreen->DestroyPixmap) (pPixmap);
+ : return;
+ : }
+ : ValidatePicture(pPicture);
+ :
+ : /* Give the temporary pixmap an initial kick towards the screen, so
+ : * it'll stick there.
+ : */
+ : pixmaps[0].as_dst = TRUE;
+ : pixmaps[0].as_src = TRUE;
+ : pixmaps[0].pPix = pPixmap;
+ : exaDoMigration (pixmaps, 1, pExaScr->info->PrepareComposite != NULL);
+ :
+ 1 0.0011 : while (n--)
+ : {
+ 1 0.0011 : GlyphPtr glyph = *glyphs++;
+ : pointer glyphdata = (pointer) (glyph + 1);
+ 5 0.0054 : DrawablePtr pCmpDrw = (maskFormat ? pMask : pDst)->pDrawable;
+ :
+ : x1 = x - glyph->info.x;
+ 8 0.0087 : y1 = y - glyph->info.y;
+ :
+ 7 0.0076 : if (x1 >= pCmpDrw->width || y1 >= pCmpDrw->height ||
+ : (x1 + glyph->info.width) <= 0 || (y1 + glyph->info.height) <= 0)
+ : goto nextglyph;
+ :
+ 2 0.0022 : (*pScreen->ModifyPixmapHeader) (pScratchPixmap,
+ : glyph->info.width,
+ : glyph->info.height,
+ : 0, 0, -1, glyphdata);
+ :
+ : /* Copy the glyph data into the proper pixmap instead of a fake.
+ : * First we try to use UploadToScreen, if we can, then we fall back
+ : * to a plain exaCopyArea in case of failure.
+ : */
+ 5 0.0054 : if (pExaScr->info->UploadToScreen &&
+ : exaPixmapIsOffscreen(pPixmap) &&
+ : (*pExaScr->info->UploadToScreen) (pPixmap, 0, 0,
+ : glyph->info.width,
+ : glyph->info.height,
+ : glyphdata,
+ : PixmapBytePad(glyph->info.width,
+ : list->format->depth)))
+ : {
+ : exaMarkSync (pScreen);
+ : } else {
+ : /* Set up the scratch pixmap/GC for doing a CopyArea. */
+ : if (pScratchPixmap == NULL) {
+ : /* Get a scratch pixmap to wrap the original glyph data */
+ 2 0.0022 : pScratchPixmap = GetScratchPixmapHeader (pScreen,
+ : glyph->info.width,
+ : glyph->info.height,
+ : list->format->depth,
+ : list->format->depth,
+ : -1, glyphdata);
+ : if (!pScratchPixmap) {
+ : FreePicture(pPicture, 0);
+ : (*pScreen->DestroyPixmap) (pPixmap);
+ : return;
+ : }
+ :
+ : /* Get a scratch GC with which to copy the glyph data from
+ : * scratch to temporary
+ : */
+ : pGC = GetScratchGC (list->format->depth, pScreen);
+ 1 0.0011 : ValidateGC (&pPixmap->drawable, pGC);
+ : } else {
+ 2 0.0022 : (*pScreen->ModifyPixmapHeader) (pScratchPixmap,
+ : glyph->info.width,
+ : glyph->info.height,
+ : 0, 0, -1, glyphdata);
+ 5 0.0054 : pScratchPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ : }
+ :
+ 7 0.0076 : exaCopyArea (&pScratchPixmap->drawable, &pPixmap->drawable, pGC,
+ : 0, 0, glyph->info.width, glyph->info.height, 0, 0);
+ : }
+ :
+ 5 0.0054 : exaPixmapDirty (pPixmap, 0, 0,
+ : glyph->info.width, glyph->info.height);
+ :
+ 5 0.0054 : if (maskFormat)
+ : {
+ 4 0.0044 : exaComposite (PictOpAdd, pPicture, NULL, pMask, 0, 0, 0, 0,
+ : x1, y1, glyph->info.width, glyph->info.height);
+ 2 0.0022 : exaPixmapDirty(pMaskPixmap, x1, y1, x1 + glyph->info.width,
+ : y1 + glyph->info.height);
+ : }
+ : else
+ : {
+ 13 0.0142 : exaComposite (op, pSrc, pPicture, pDst,
+ : xSrc + x1 - xDst, ySrc + y1 - yDst,
+ : 0, 0, x1, y1, glyph->info.width,
+ : glyph->info.height);
+ 11 0.0120 : x1 += pDst->pDrawable->x + xoff;
+ 5 0.0054 : y1 += pDst->pDrawable->y + yoff;
+ 3 0.0033 : exaPixmapDirty(pDstPixmap, x1, y1, x1 + glyph->info.width,
+ : y1 + glyph->info.height);
+ : }
+ :nextglyph:
+ 3 0.0033 : x += glyph->info.xOff;
+ 2 0.0022 : y += glyph->info.yOff;
+ : }
+ : list++;
+ : if (pGC != NULL)
+ : FreeScratchGC (pGC);
+ 1 0.0011 : FreePicture ((pointer) pPicture, 0);
+ : (*pScreen->DestroyPixmap) (pPixmap);
+ : if (pScratchPixmap != NULL)
+ : FreeScratchPixmapHeader (pScratchPixmap);
+ : }
+ : if (maskFormat)
+ : {
+ : x = extents.x1;
+ : y = extents.y1;
+ 1 0.0011 : exaComposite (op, pSrc, pMask, pDst, xSrc + x - xDst, ySrc + y - yDst,
+ : 0, 0, x, y, width, height);
+ : FreePicture ((pointer) pMask, (XID) 0);
+ : (*pScreen->DestroyPixmap) (pMaskPixmap);
+ : }
+ :}
+/*
+ * Total samples for file : "interp.c"
+ *
+ * 753 0.8203
+ */
+
+<credited to line zero> 753 0.8203 :
+ /* __i686.get_pc_thunk.cx total: 1 0.0011 */
+ /* __i686.get_pc_thunk.bx total: 44 0.0479 */
+ /* _nl_load_locale_from_archive total: 1 0.0011 */
+ /* _itoa_word total: 1 0.0011 */
+ /* __find_specmb total: 2 0.0022 */
+ /* _IO_old_init total: 1 0.0011 */
+ /* _IO_str_init_static_internal total: 1 0.0011 */
+ /* _int_free total: 227 0.2473 */
+ /* _int_malloc total: 460 0.5011 */
+ /* _int_realloc total: 10 0.0109 */
+ /* __close_nocancel total: 1 0.0011 */
+ /* __read_nocancel total: 3 0.0033 */
+ /* __xstat32_conv total: 1 0.0011 */
+/*
+ * Total samples for file : "exa_unaccel.c"
+ *
+ * 590 0.6427
+ */
+
+<credited to line zero> 590 0.6427 :
+ /* __i686.get_pc_thunk.cx total: 14 0.0153 */
+ /* __i686.get_pc_thunk.bx total: 576 0.6275 */
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/exa/exa_offscreen.c"
+ *
+ * 534 0.5817
+ */
+
+
+ :/*
+ : * Copyright © 2003 Anders Carlsson
+ : *
+ : * 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 Anders Carlsson not be used in
+ : * advertising or publicity pertaining to distribution of the software without
+ : * specific, written prior permission. Anders Carlsson makes no
+ : * representations about the suitability of this software for any purpose. It
+ : * is provided "as is" without express or implied warranty.
+ : *
+ : * ANDERS CARLSSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ : * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ : * EVENT SHALL ANDERS CARLSSON 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.
+ : */
+ :
+ :/** @file
+ : * This allocator allocates blocks of memory by maintaining a list of areas
+ : * and a score for each area. As an area is marked used, its score is
+ : * incremented, and periodically all of the areas have their scores decayed by
+ : * a fraction. When allocating, the contiguous block of areas with the minimum
+ : * score is found and evicted in order to make room for the new allocation.
+ : */
+ :
+ :#include "exa_priv.h"
+ :
+ :#include <limits.h>
+ :#include <assert.h>
+ :#include <stdlib.h>
+ :
+ :#if DEBUG_OFFSCREEN
+ :#define DBG_OFFSCREEN(a) ErrorF a
+ :#else
+ :#define DBG_OFFSCREEN(a)
+ :#endif
+ :
+ :#if DEBUG_OFFSCREEN
+ :static void
+ :ExaOffscreenValidate (ScreenPtr pScreen)
+ :{
+ : ExaScreenPriv (pScreen);
+ : ExaOffscreenArea *prev = 0, *area;
+ :
+ : assert (pExaScr->info->offScreenAreas->base_offset ==
+ : pExaScr->info->offScreenBase);
+ : for (area = pExaScr->info->offScreenAreas; area; area = area->next)
+ : {
+ : assert (area->offset >= area->base_offset &&
+ : area->offset < (area->base_offset + area->size));
+ : if (prev)
+ : assert (prev->base_offset + prev->size == area->base_offset);
+ : prev = area;
+ : }
+ : assert (prev->base_offset + prev->size == pExaScr->info->memorySize);
+ :}
+ :#else
+ :#define ExaOffscreenValidate(s)
+ :#endif
+ :
+ :static ExaOffscreenArea *
+ :ExaOffscreenKickOut (ScreenPtr pScreen, ExaOffscreenArea *area)
+ :{
+ : if (area->save)
+ : (*area->save) (pScreen, area);
+ : return exaOffscreenFree (pScreen, area);
+ :}
+ :
+ :/**
+ : * exaOffscreenAlloc allocates offscreen memory
+ : *
+ : * @param pScreen current screen
+ : * @param size size in bytes of the allocation
+ : * @param align byte alignment requirement for the offset of the allocated area
+ : * @param locked whether the allocated area is locked and can't be kicked out
+ : * @param save callback for when the area is evicted from memory
+ : * @param privdata private data for the save callback.
+ : *
+ : * Allocates offscreen memory from the device associated with pScreen. size
+ : * and align deteremine where and how large the allocated area is, and locked
+ : * will mark whether it should be held in card memory. privdata may be any
+ : * pointer for the save callback when the area is removed.
+ : *
+ : * Note that locked areas do get evicted on VT switch unless the driver
+ : * requested version 2.1 or newer behavior. In that case, the save callback is
+ : * still called.
+ : */
+ :ExaOffscreenArea *
+ :exaOffscreenAlloc (ScreenPtr pScreen, int size, int align,
+ : Bool locked,
+ : ExaOffscreenSaveProc save,
+ : pointer privData)
+ 2 0.0022 :{ /* exaOffscreenAlloc total: 68 0.0741 */
+ : ExaOffscreenArea *area, *begin, *best;
+ 1 0.0011 : ExaScreenPriv (pScreen);
+ : int tmp, real_size = 0, best_score;
+ :#if DEBUG_OFFSCREEN
+ : static int number = 0;
+ : ErrorF("================= ============ allocating a new pixmap %d\n", ++number);
+ :#endif
+ :
+ : ExaOffscreenValidate (pScreen);
+ 1 0.0011 : if (!align)
+ : align = 1;
+ :
+ : if (!size)
+ : {
+ : DBG_OFFSCREEN (("Alloc 0x%x -> EMPTY\n", size));
+ : return NULL;
+ : }
+ :
+ : /* throw out requests that cannot fit */
+ 2 0.0022 : if (size > (pExaScr->info->memorySize - pExaScr->info->offScreenBase))
+ : {
+ : DBG_OFFSCREEN (("Alloc 0x%x vs (0x%lx) -> TOBIG\n", size,
+ : pExaScr->info->memorySize -
+ : pExaScr->info->offScreenBase));
+ : return NULL;
+ : }
+ :
+ : /* Try to find a free space that'll fit. */
+ 11 0.0120 : for (area = pExaScr->info->offScreenAreas; area; area = area->next)
+ : {
+ : /* skip allocated areas */
+ 11 0.0120 : if (area->state != ExaOffscreenAvail)
+ : continue;
+ :
+ : /* adjust size to match alignment requirement */
+ : real_size = size;
+ 2 0.0022 : tmp = area->base_offset % align;
+ 31 0.0338 : if (tmp)
+ : real_size += (align - tmp);
+ :
+ : /* does it fit? */
+ : if (real_size <= area->size)
+ : break;
+ : }
+ :
+ : if (!area)
+ : {
+ : /*
+ : * Kick out existing users to make space.
+ : *
+ : * First, locate a region which can hold the desired object.
+ : */
+ :
+ : /* prev points at the first object to boot */
+ : best = NULL;
+ : best_score = INT_MAX;
+ : for (begin = pExaScr->info->offScreenAreas; begin != NULL;
+ : begin = begin->next)
+ : {
+ : int avail, score;
+ : ExaOffscreenArea *scan;
+ :
+ : if (begin->state == ExaOffscreenLocked)
+ : continue;
+ :
+ : /* adjust size needed to account for alignment loss for this area */
+ : real_size = size;
+ : tmp = begin->base_offset % align;
+ : if (tmp)
+ : real_size += (align - tmp);
+ :
+ : avail = 0;
+ : score = 0;
+ : /* now see if we can make room here, and how "costly" it'll be. */
+ : for (scan = begin; scan != NULL; scan = scan->next)
+ : {
+ : if (scan->state == ExaOffscreenLocked) {
+ : /* Can't make room here, start after this locked area. */
+ : begin = scan;
+ : break;
+ : }
+ : /* Score should only be non-zero for ExaOffscreenRemovable */
+ : score += scan->score;
+ : avail += scan->size;
+ : if (avail >= real_size)
+ : break;
+ : }
+ : /* Is it the best option we've found so far? */
+ : if (avail >= real_size && score < best_score) {
+ : best = begin;
+ : best_score = score;
+ : }
+ : }
+ : area = best;
+ : if (!area)
+ : {
+ : DBG_OFFSCREEN (("Alloc 0x%x -> NOSPACE\n", size));
+ : /* Could not allocate memory */
+ : ExaOffscreenValidate (pScreen);
+ : return NULL;
+ : }
+ :
+ : /* adjust size needed to account for alignment loss for this area */
+ : real_size = size;
+ : tmp = area->base_offset % align;
+ : if (tmp)
+ : real_size += (align - tmp);
+ :
+ : /*
+ : * Kick out first area if in use
+ : */
+ : if (area->state != ExaOffscreenAvail)
+ : area = ExaOffscreenKickOut (pScreen, area);
+ : /*
+ : * Now get the system to merge the other needed areas together
+ : */
+ : while (area->size < real_size)
+ : {
+ : assert (area->next && area->next->state == ExaOffscreenRemovable);
+ : (void) ExaOffscreenKickOut (pScreen, area->next);
+ : }
+ : }
+ :
+ : /* save extra space in new area */
+ 1 0.0011 : if (real_size < area->size)
+ : {
+ : ExaOffscreenArea *new_area = xalloc (sizeof (ExaOffscreenArea));
+ : if (!new_area)
+ : return NULL;
+ : new_area->base_offset = area->base_offset + real_size;
+ : new_area->offset = new_area->base_offset;
+ : new_area->size = area->size - real_size;
+ : new_area->state = ExaOffscreenAvail;
+ : new_area->save = NULL;
+ : new_area->score = 0;
+ : new_area->next = area->next;
+ 1 0.0011 : area->next = new_area;
+ : area->size = real_size;
+ : }
+ : /*
+ : * Mark this area as in use
+ : */
+ : if (locked)
+ : area->state = ExaOffscreenLocked;
+ : else
+ : area->state = ExaOffscreenRemovable;
+ : area->privData = privData;
+ : area->save = save;
+ : area->score = 0;
+ : area->offset = (area->base_offset + align - 1);
+ 5 0.0054 : area->offset -= area->offset % align;
+ :
+ : ExaOffscreenValidate (pScreen);
+ :
+ : DBG_OFFSCREEN (("Alloc 0x%x -> 0x%x (0x%x)\n", size,
+ : area->base_offset, area->offset));
+ : return area;
+ :}
+ :
+ :/**
+ : * Ejects all offscreen areas, and uninitializes the offscreen memory manager.
+ : */
+ :void
+ :ExaOffscreenSwapOut (ScreenPtr pScreen)
+ :{
+ : ExaScreenPriv (pScreen);
+ :
+ : ExaOffscreenValidate (pScreen);
+ : /* loop until a single free area spans the space */
+ : for (;;)
+ : {
+ : ExaOffscreenArea *area = pExaScr->info->offScreenAreas;
+ :
+ : if (!area)
+ : break;
+ : if (area->state == ExaOffscreenAvail)
+ : {
+ : area = area->next;
+ : if (!area)
+ : break;
+ : }
+ : assert (area->state != ExaOffscreenAvail);
+ : (void) ExaOffscreenKickOut (pScreen, area);
+ : ExaOffscreenValidate (pScreen);
+ : }
+ : ExaOffscreenValidate (pScreen);
+ : ExaOffscreenFini (pScreen);
+ :}
+ :
+ :/** Ejects all pixmaps managed by EXA. */
+ :static void
+ :ExaOffscreenEjectPixmaps (ScreenPtr pScreen)
+ :{
+ : ExaScreenPriv (pScreen);
+ :
+ : ExaOffscreenValidate (pScreen);
+ : /* loop until a single free area spans the space */
+ : for (;;)
+ : {
+ : ExaOffscreenArea *area;
+ :
+ : for (area = pExaScr->info->offScreenAreas; area != NULL;
+ : area = area->next)
+ : {
+ : if (area->state == ExaOffscreenRemovable &&
+ : area->save == exaPixmapSave)
+ : {
+ : (void) ExaOffscreenKickOut (pScreen, area);
+ : ExaOffscreenValidate (pScreen);
+ : break;
+ : }
+ : }
+ : if (area == NULL)
+ : break;
+ : }
+ : ExaOffscreenValidate (pScreen);
+ :}
+ :
+ :void
+ :ExaOffscreenSwapIn (ScreenPtr pScreen)
+ :{
+ : exaOffscreenInit (pScreen);
+ :}
+ :
+ :/**
+ : * Prepares EXA for disabling of FB access, or restoring it.
+ : *
+ : * In version 2.1, the disabling results in pixmaps being ejected, while other
+ : * allocations remain. With this plus the prevention of migration while
+ : * swappedOut is set, EXA by itself should not cause any access of the
+ : * framebuffer to occur while swapped out. Any remaining issues are the
+ : * responsibility of the driver.
+ : *
+ : * Prior to version 2.1, all allocations, including locked ones, are ejected
+ : * when access is disabled, and the allocator is torn down while swappedOut
+ : * is set. This is more drastic, and caused implementation difficulties for
+ : * many drivers that could otherwise handle the lack of FB access while
+ : * swapped out.
+ : */
+ :void
+ :exaEnableDisableFBAccess (int index, Bool enable)
+ :{
+ : ScreenPtr pScreen = screenInfo.screens[index];
+ : ExaScreenPriv (pScreen);
+ :
+ : if (!enable && pExaScr->disableFbCount++ == 0) {
+ : if (pExaScr->info->exa_minor < 1)
+ : ExaOffscreenSwapOut (pScreen);
+ : else
+ : ExaOffscreenEjectPixmaps (pScreen);
+ : pExaScr->swappedOut = TRUE;
+ : }
+ :
+ : if (enable && --pExaScr->disableFbCount == 0) {
+ : if (pExaScr->info->exa_minor < 1)
+ : ExaOffscreenSwapIn (pScreen);
+ : pExaScr->swappedOut = FALSE;
+ : }
+ :}
+ :
+ :/* merge the next free area into this one */
+ :static void
+ :ExaOffscreenMerge (ExaOffscreenArea *area)
+ 1 0.0011 :{ /* ExaOffscreenMerge total: 3 0.0033 */
+ : ExaOffscreenArea *next = area->next;
+ :
+ : /* account for space */
+ : area->size += next->size;
+ : /* frob pointer */
+ 1 0.0011 : area->next = next->next;
+ : xfree (next);
+ 1 0.0011 :}
+ :
+ :/**
+ : * exaOffscreenFree frees an allocation.
+ : *
+ : * @param pScreen current screen
+ : * @param area offscreen area to free
+ : *
+ : * exaOffscreenFree frees an allocation created by exaOffscreenAlloc. Note that
+ : * the save callback of the area is not called, and it is up to the driver to
+ : * do any cleanup necessary as a result.
+ : *
+ : * @return pointer to the newly freed area. This behavior should not be relied
+ : * on.
+ : */
+ :ExaOffscreenArea *
+ :exaOffscreenFree (ScreenPtr pScreen, ExaOffscreenArea *area)
+ :{ /* exaOffscreenFree total: 11 0.0120 */
+ : ExaScreenPriv(pScreen);
+ : ExaOffscreenArea *next = area->next;
+ : ExaOffscreenArea *prev;
+ :
+ : DBG_OFFSCREEN (("Free 0x%x -> 0x%x (0x%x)\n", area->size,
+ : area->base_offset, area->offset));
+ : ExaOffscreenValidate (pScreen);
+ :
+ : area->state = ExaOffscreenAvail;
+ : area->save = NULL;
+ : area->score = 0;
+ : /*
+ : * Find previous area
+ : */
+ : if (area == pExaScr->info->offScreenAreas)
+ : prev = NULL;
+ : else
+ 2 0.0022 : for (prev = pExaScr->info->offScreenAreas; prev; prev = prev->next)
+ 8 0.0087 : if (prev->next == area)
+ : break;
+ :
+ : /* link with next area if free */
+ : if (next && next->state == ExaOffscreenAvail)
+ 1 0.0011 : ExaOffscreenMerge (area);
+ :
+ : /* link with prev area if free */
+ : if (prev && prev->state == ExaOffscreenAvail)
+ : {
+ : area = prev;
+ : ExaOffscreenMerge (area);
+ : }
+ :
+ : ExaOffscreenValidate (pScreen);
+ : DBG_OFFSCREEN(("\tdone freeing\n"));
+ : return area;
+ :}
+ :
+ :void
+ :ExaOffscreenMarkUsed (PixmapPtr pPixmap)
+ 11 0.0120 :{ /* ExaOffscreenMarkUsed total: 452 0.4924 */
+ 4 0.0044 : ExaPixmapPriv (pPixmap);
+ 17 0.0185 : ExaScreenPriv (pPixmap->drawable.pScreen);
+ : static int iter = 0;
+ :
+ 9 0.0098 : if (!pExaPixmap || !pExaPixmap->area)
+ : return;
+ :
+ : /* The numbers here are arbitrary. We may want to tune these. */
+ : pExaPixmap->area->score += 100;
+ 19 0.0207 : if (++iter == 10) {
+ : ExaOffscreenArea *area;
+ 79 0.0861 : for (area = pExaScr->info->offScreenAreas; area != NULL;
+ 27 0.0294 : area = area->next)
+ : {
+ 77 0.0839 : if (area->state == ExaOffscreenRemovable)
+ 198 0.2157 : area->score = (area->score * 7) / 8;
+ : }
+ : iter = 0;
+ : }
+ 11 0.0120 :}
+ :
+ :/**
+ : * exaOffscreenInit initializes the offscreen memory manager.
+ : *
+ : * @param pScreen current screen
+ : *
+ : * exaOffscreenInit is called by exaDriverInit to set up the memory manager for
+ : * the screen, if any offscreen memory is available.
+ : */
+ :Bool
+ :exaOffscreenInit (ScreenPtr pScreen)
+ :{
+ : ExaScreenPriv (pScreen);
+ : ExaOffscreenArea *area;
+ :
+ : /* Allocate a big free area */
+ : area = xalloc (sizeof (ExaOffscreenArea));
+ :
+ : if (!area)
+ : return FALSE;
+ :
+ : area->state = ExaOffscreenAvail;
+ : area->base_offset = pExaScr->info->offScreenBase;
+ : area->offset = area->base_offset;
+ : area->size = pExaScr->info->memorySize - area->base_offset;
+ : area->save = NULL;
+ : area->next = NULL;
+ : area->score = 0;
+ :
+ : /* Add it to the free areas */
+ : pExaScr->info->offScreenAreas = area;
+ :
+ : ExaOffscreenValidate (pScreen);
+ :
+ : return TRUE;
+ :}
+ :
+ :void
+ :ExaOffscreenFini (ScreenPtr pScreen)
+ :{
+ : ExaScreenPriv (pScreen);
+ : ExaOffscreenArea *area;
+ :
+ : /* just free all of the area records */
+ : while ((area = pExaScr->info->offScreenAreas))
+ : {
+ : pExaScr->info->offScreenAreas = area->next;
+ : xfree (area);
+ : }
+ :}
+/*
+ * Total samples for file : "/home/cworth/src/pixman/pixman/pixman-region.c"
+ *
+ * 480 0.5229
+ */
+
+
+ :/***********************************************************
+ :
+ :Copyright 1987, 1988, 1989, 1998 The Open Group
+ :
+ :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.
+ :
+ :The above copyright notice and this permission notice shall be included in
+ :all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ :IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ :FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ :OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ :AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ :CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of The Open Group shall not be
+ :used in advertising or otherwise to promote the sale, use or other dealings
+ :in this Software without prior written authorization from The Open Group.
+ :
+ :Copyright 1987, 1988, 1989 by
+ :Digital Equipment Corporation, Maynard, Massachusetts.
+ :
+ : All Rights Reserved
+ :
+ :Permission to use, copy, modify, and distribute this software and its
+ :documentation for any purpose and without fee is hereby granted,
+ :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 Digital not be
+ :used in advertising or publicity pertaining to distribution of the
+ :software without specific, written prior permission.
+ :
+ :DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ :ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ :DIGITAL 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.
+ :
+ :******************************************************************/
+ :
+ :#include <config.h>
+ :#include <stdlib.h>
+ :#include <limits.h>
+ :#include <string.h>
+ :#include <stdio.h>
+ :
+ :#include "pixman-private.h"
+ :#include "pixman.h"
+ :
+ :typedef struct pixman_region16_point {
+ : int x, y;
+ :} pixman_region16_point_t;
+ :
+ :#define PIXREGION_NIL(reg) ((reg)->data && !(reg)->data->numRects)
+ :/* not a region */
+ :#define PIXREGION_NAR(reg) ((reg)->data == pixman_brokendata)
+ :#define PIXREGION_NUM_RECTS(reg) ((reg)->data ? (reg)->data->numRects : 1)
+ :#define PIXREGION_SIZE(reg) ((reg)->data ? (reg)->data->size : 0)
+ :#define PIXREGION_RECTS(reg) ((reg)->data ? (pixman_box16_t *)((reg)->data + 1) \
+ : : &(reg)->extents)
+ :#define PIXREGION_BOXPTR(reg) ((pixman_box16_t *)((reg)->data + 1))
+ :#define PIXREGION_BOX(reg,i) (&PIXREGION_BOXPTR(reg)[i])
+ :#define PIXREGION_TOP(reg) PIXREGION_BOX(reg, (reg)->data->numRects)
+ :#define PIXREGION_END(reg) PIXREGION_BOX(reg, (reg)->data->numRects - 1)
+ :#define PIXREGION_SZOF(n) (sizeof(pixman_region16_data_t) + ((n) * sizeof(pixman_box16_t)))
+ :
+ :
+ :#undef assert
+ :#ifdef DEBUG_PIXREGION
+ :#define assert(expr) {if (!(expr)) \
+ : FatalError("Assertion failed file %s, line %d: expr\n", \
+ : __FILE__, __LINE__); }
+ :#else
+ :#define assert(expr)
+ :#endif
+ :
+ :#define good(reg) assert(pixman_region_selfcheck(reg))
+ :
+ :#undef MIN
+ :#define MIN(a,b) ((a) < (b) ? (a) : (b))
+ :#undef MAX
+ :#define MAX(a,b) ((a) > (b) ? (a) : (b))
+ :
+ :static const pixman_box16_t _pixman_region_emptyBox = {0, 0, 0, 0};
+ :static const pixman_region16_data_t _pixman_region_emptyData = {0, 0};
+ :static const pixman_region16_data_t _pixman_brokendata = {0, 0};
+ :
+ :static pixman_box16_t *pixman_region_emptyBox = (pixman_box16_t *)&_pixman_region_emptyBox;
+ :static pixman_region16_data_t *pixman_region_emptyData = (pixman_region16_data_t *)&_pixman_region_emptyData;
+ :static pixman_region16_data_t *pixman_brokendata = (pixman_region16_data_t *)&_pixman_brokendata;
+ :
+ :/* This function exists only to make it possible to preserve the X ABI - it should
+ : * go away at first opportunity.
+ : *
+ : * The problem is that the X ABI exports the three structs and has used
+ : * them through macros. So the X server calls this function with
+ : * the addresses of those structs which makes the existing code continue to
+ : * work.
+ : */
+ :void
+ :pixman_region_set_static_pointers (pixman_box16_t *empty_box,
+ : pixman_region16_data_t *empty_data,
+ : pixman_region16_data_t *broken_data)
+ :{
+ : pixman_region_emptyBox = empty_box;
+ : pixman_region_emptyData = empty_data;
+ : pixman_brokendata = broken_data;
+ :}
+ :
+ :static pixman_bool_t
+ :pixman_break (pixman_region16_t *pReg);
+ :
+ :/*
+ : * The functions in this file implement the Region abstraction used extensively
+ : * throughout the X11 sample server. A Region is simply a set of disjoint
+ : * (non-overlapping) rectangles, plus an "extent" rectangle which is the
+ : * smallest single rectangle that contains all the non-overlapping rectangles.
+ : *
+ : * A Region is implemented as a "y-x-banded" array of rectangles. This array
+ : * imposes two degrees of order. First, all rectangles are sorted by top side
+ : * y coordinate first (y1), and then by left side x coordinate (x1).
+ : *
+ : * Furthermore, the rectangles are grouped into "bands". Each rectangle in a
+ : * band has the same top y coordinate (y1), and each has the same bottom y
+ : * coordinate (y2). Thus all rectangles in a band differ only in their left
+ : * and right side (x1 and x2). Bands are implicit in the array of rectangles:
+ : * there is no separate list of band start pointers.
+ : *
+ : * The y-x band representation does not minimize rectangles. In particular,
+ : * if a rectangle vertically crosses a band (the rectangle has scanlines in
+ : * the y1 to y2 area spanned by the band), then the rectangle may be broken
+ : * down into two or more smaller rectangles stacked one atop the other.
+ : *
+ : * ----------- -----------
+ : * | | | | band 0
+ : * | | -------- ----------- --------
+ : * | | | | in y-x banded | | | | band 1
+ : * | | | | form is | | | |
+ : * ----------- | | ----------- --------
+ : * | | | | band 2
+ : * -------- --------
+ : *
+ : * An added constraint on the rectangles is that they must cover as much
+ : * horizontal area as possible: no two rectangles within a band are allowed
+ : * to touch.
+ : *
+ : * Whenever possible, bands will be merged together to cover a greater vertical
+ : * distance (and thus reduce the number of rectangles). Two bands can be merged
+ : * only if the bottom of one touches the top of the other and they have
+ : * rectangles in the same places (of the same width, of course).
+ : *
+ : * Adam de Boor wrote most of the original region code. Joel McCormack
+ : * substantially modified or rewrote most of the core arithmetic routines, and
+ : * added pixman_region_validate in order to support several speed improvements to
+ : * pixman_region_validateTree. Bob Scheifler changed the representation to be more
+ : * compact when empty or a single rectangle, and did a bunch of gratuitous
+ : * reformatting. Carl Worth did further gratuitous reformatting while re-merging
+ : * the server and client region code into libpixregion.
+ : */
+ :
+ :/* true iff two Boxes overlap */
+ :#define EXTENTCHECK(r1,r2) \
+ : (!( ((r1)->x2 <= (r2)->x1) || \
+ : ((r1)->x1 >= (r2)->x2) || \
+ : ((r1)->y2 <= (r2)->y1) || \
+ : ((r1)->y1 >= (r2)->y2) ) )
+ :
+ :/* true iff (x,y) is in Box */
+ :#define INBOX(r,x,y) \
+ : ( ((r)->x2 > x) && \
+ : ((r)->x1 <= x) && \
+ : ((r)->y2 > y) && \
+ : ((r)->y1 <= y) )
+ :
+ :/* true iff Box r1 contains Box r2 */
+ :#define SUBSUMES(r1,r2) \
+ : ( ((r1)->x1 <= (r2)->x1) && \
+ : ((r1)->x2 >= (r2)->x2) && \
+ : ((r1)->y1 <= (r2)->y1) && \
+ : ((r1)->y2 >= (r2)->y2) )
+ :
+ :#define allocData(n) malloc(PIXREGION_SZOF(n))
+ :#define freeData(reg) if ((reg)->data && (reg)->data->size) free((reg)->data)
+ :
+ :#define RECTALLOC_BAIL(pReg,n,bail) \
+ :if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
+ : if (!pixman_rect_alloc(pReg, n)) { goto bail; }
+ :
+ :#define RECTALLOC(pReg,n) \
+ :if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
+ : if (!pixman_rect_alloc(pReg, n)) { return FALSE; }
+ :
+ :#define ADDRECT(pNextRect,nx1,ny1,nx2,ny2) \
+ :{ \
+ : pNextRect->x1 = nx1; \
+ : pNextRect->y1 = ny1; \
+ : pNextRect->x2 = nx2; \
+ : pNextRect->y2 = ny2; \
+ : pNextRect++; \
+ :}
+ :
+ :#define NEWRECT(pReg,pNextRect,nx1,ny1,nx2,ny2) \
+ :{ \
+ : if (!(pReg)->data || ((pReg)->data->numRects == (pReg)->data->size))\
+ : { \
+ : if (!pixman_rect_alloc(pReg, 1)) \
+ : return FALSE; \
+ : pNextRect = PIXREGION_TOP(pReg); \
+ : } \
+ : ADDRECT(pNextRect,nx1,ny1,nx2,ny2); \
+ : pReg->data->numRects++; \
+ : assert(pReg->data->numRects<=pReg->data->size); \
+ :}
+ :
+ :#define DOWNSIZE(reg,numRects) \
+ :if (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) \
+ :{ \
+ : pixman_region16_data_t * NewData; \
+ : NewData = (pixman_region16_data_t *)realloc((reg)->data, PIXREGION_SZOF(numRects)); \
+ : if (NewData) \
+ : { \
+ : NewData->size = (numRects); \
+ : (reg)->data = NewData; \
+ : } \
+ :}
+ :
+ :pixman_bool_t
+ :pixman_region_equal(reg1, reg2)
+ : pixman_region16_t * reg1;
+ : pixman_region16_t * reg2;
+ :{
+ : int i;
+ : pixman_box16_t *rects1;
+ : pixman_box16_t *rects2;
+ :
+ : if (reg1->extents.x1 != reg2->extents.x1) return FALSE;
+ : if (reg1->extents.x2 != reg2->extents.x2) return FALSE;
+ : if (reg1->extents.y1 != reg2->extents.y1) return FALSE;
+ : if (reg1->extents.y2 != reg2->extents.y2) return FALSE;
+ : if (PIXREGION_NUM_RECTS(reg1) != PIXREGION_NUM_RECTS(reg2)) return FALSE;
+ :
+ : rects1 = PIXREGION_RECTS(reg1);
+ : rects2 = PIXREGION_RECTS(reg2);
+ : for (i = 0; i != PIXREGION_NUM_RECTS(reg1); i++) {
+ : if (rects1[i].x1 != rects2[i].x1) return FALSE;
+ : if (rects1[i].x2 != rects2[i].x2) return FALSE;
+ : if (rects1[i].y1 != rects2[i].y1) return FALSE;
+ : if (rects1[i].y2 != rects2[i].y2) return FALSE;
+ : }
+ : return TRUE;
+ :}
+ :
+ :int
+ :pixman_region16_print(rgn)
+ : pixman_region16_t * rgn;
+ :{
+ : int num, size;
+ : int i;
+ : pixman_box16_t * rects;
+ :
+ : num = PIXREGION_NUM_RECTS(rgn);
+ : size = PIXREGION_SIZE(rgn);
+ : rects = PIXREGION_RECTS(rgn);
+ : fprintf(stderr, "num: %d size: %d\n", num, size);
+ : fprintf(stderr, "extents: %d %d %d %d\n",
+ : rgn->extents.x1, rgn->extents.y1, rgn->extents.x2, rgn->extents.y2);
+ : for (i = 0; i < num; i++)
+ : fprintf(stderr, "%d %d %d %d \n",
+ : rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2);
+ : fprintf(stderr, "\n");
+ : return(num);
+ :}
+ :
+ :
+ :void
+ :pixman_region_init (pixman_region16_t *region)
+ 8 0.0087 :{ /* pixman_region_init total: 13 0.0142 */
+ 3 0.0033 : region->extents = *pixman_region_emptyBox;
+ : region->data = pixman_region_emptyData;
+ 2 0.0022 :}
+ :
+ :void
+ :pixman_region_init_rect (pixman_region16_t *region,
+ : int x, int y, unsigned int width, unsigned int height)
+ 2 0.0022 :{ /* pixman_region_init_rect total: 3 0.0033 */
+ : region->extents.x1 = x;
+ : region->extents.y1 = y;
+ : region->extents.x2 = x + width;
+ 1 0.0011 : region->extents.y2 = y + height;
+ : region->data = NULL;
+ :}
+ :
+ :void
+ :pixman_region_init_with_extents (pixman_region16_t *region, pixman_box16_t *extents)
+ 1 0.0011 :{ /* pixman_region_init_with_extents total: 2 0.0022 */
+ 1 0.0011 : region->extents = *extents;
+ : region->data = NULL;
+ :}
+ :
+ :void
+ :pixman_region_fini (pixman_region16_t *region)
+ 41 0.0447 :{ /* pixman_region_fini total: 44 0.0479 */
+ : good (region);
+ 1 0.0011 : freeData (region);
+ 2 0.0022 :}
+ :
+ :int
+ :pixman_region_n_rects (pixman_region16_t *region)
+ 14 0.0153 :{ /* pixman_region_n_rects total: 38 0.0414 */
+ 16 0.0174 : return PIXREGION_NUM_RECTS (region);
+ 8 0.0087 :}
+ :
+ :pixman_box16_t *
+ :pixman_region_rects (pixman_region16_t *region)
+ :{
+ : return PIXREGION_RECTS (region);
+ :}
+ :
+ :pixman_box16_t *
+ :pixman_region_rectangles (pixman_region16_t *region,
+ : int *n_rects)
+ 41 0.0447 :{ /* pixman_region_rectangles total: 82 0.0893 */
+ : if (n_rects)
+ : *n_rects = PIXREGION_NUM_RECTS (region);
+ :
+ 17 0.0185 : return PIXREGION_RECTS (region);
+ 24 0.0261 :}
+ :
+ :static pixman_bool_t
+ :pixman_break (pixman_region16_t *region)
+ :{
+ : freeData (region);
+ : region->extents = *pixman_region_emptyBox;
+ : region->data = pixman_brokendata;
+ : return FALSE;
+ :}
+ :
+ :static pixman_bool_t
+ :pixman_rect_alloc (pixman_region16_t * region, int n)
+ 7 0.0076 :{ /* pixman_rect_alloc total: 16 0.0174 */
+ : pixman_region16_data_t *data;
+ :
+ : if (!region->data)
+ : {
+ : n++;
+ : region->data = allocData(n);
+ : if (!region->data)
+ : return pixman_break (region);
+ : region->data->numRects = 1;
+ : *PIXREGION_BOXPTR(region) = region->extents;
+ : }
+ 1 0.0011 : else if (!region->data->size)
+ : {
+ 4 0.0044 : region->data = allocData(n);
+ 1 0.0011 : if (!region->data)
+ : return pixman_break (region);
+ 1 0.0011 : region->data->numRects = 0;
+ : }
+ : else
+ : {
+ : if (n == 1)
+ : {
+ : n = region->data->numRects;
+ : if (n > 500) /* XXX pick numbers out of a hat */
+ : n = 250;
+ : }
+ : n += region->data->numRects;
+ : data = (pixman_region16_data_t *)realloc(region->data, PIXREGION_SZOF(n));
+ : if (!data)
+ : return pixman_break (region);
+ : region->data = data;
+ : }
+ : region->data->size = n;
+ : return TRUE;
+ 2 0.0022 :}
+ :
+ :pixman_bool_t
+ :pixman_region_copy (pixman_region16_t *dst, pixman_region16_t *src)
+ 4 0.0044 :{ /* pixman_region_copy total: 15 0.0163 */
+ : good(dst);
+ : good(src);
+ : if (dst == src)
+ : return TRUE;
+ 2 0.0022 : dst->extents = src->extents;
+ 1 0.0011 : if (!src->data || !src->data->size)
+ : {
+ 6 0.0065 : freeData(dst);
+ 1 0.0011 : dst->data = src->data;
+ : return TRUE;
+ : }
+ : if (!dst->data || (dst->data->size < src->data->numRects))
+ : {
+ : freeData(dst);
+ : dst->data = allocData(src->data->numRects);
+ : if (!dst->data)
+ : return pixman_break (dst);
+ : dst->data->size = src->data->numRects;
+ : }
+ : dst->data->numRects = src->data->numRects;
+ : memmove((char *)PIXREGION_BOXPTR(dst),(char *)PIXREGION_BOXPTR(src),
+ : dst->data->numRects * sizeof(pixman_box16_t));
+ : return TRUE;
+ 1 0.0011 :}
+ :
+ :/*======================================================================
+ : * Generic Region Operator
+ : *====================================================================*/
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * pixman_coalesce --
+ : * Attempt to merge the boxes in the current band with those in the
+ : * previous one. We are guaranteed that the current band extends to
+ : * the end of the rects array. Used only by pixman_op.
+ : *
+ : * Results:
+ : * The new index for the previous band.
+ : *
+ : * Side Effects:
+ : * If coalescing takes place:
+ : * - rectangles in the previous band will have their y2 fields
+ : * altered.
+ : * - region->data->numRects will be decreased.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static inline int
+ :pixman_coalesce (
+ : pixman_region16_t * region, /* Region to coalesce */
+ : int prevStart, /* Index of start of previous band */
+ : int curStart) /* Index of start of current band */
+ :{
+ : pixman_box16_t * pPrevBox; /* Current box in previous band */
+ : pixman_box16_t * pCurBox; /* Current box in current band */
+ : int numRects; /* Number rectangles in both bands */
+ : int y2; /* Bottom of current band */
+ : /*
+ : * Figure out how many rectangles are in the band.
+ : */
+ : numRects = curStart - prevStart;
+ : assert(numRects == region->data->numRects - curStart);
+ :
+ : if (!numRects) return curStart;
+ :
+ : /*
+ : * The bands may only be coalesced if the bottom of the previous
+ : * matches the top scanline of the current.
+ : */
+ : pPrevBox = PIXREGION_BOX(region, prevStart);
+ : pCurBox = PIXREGION_BOX(region, curStart);
+ : if (pPrevBox->y2 != pCurBox->y1) return curStart;
+ :
+ : /*
+ : * Make sure the bands have boxes in the same places. This
+ : * assumes that boxes have been added in such a way that they
+ : * cover the most area possible. I.e. two boxes in a band must
+ : * have some horizontal space between them.
+ : */
+ : y2 = pCurBox->y2;
+ :
+ : do {
+ : if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) {
+ : return (curStart);
+ : }
+ : pPrevBox++;
+ : pCurBox++;
+ : numRects--;
+ : } while (numRects);
+ :
+ : /*
+ : * The bands may be merged, so set the bottom y of each box
+ : * in the previous band to the bottom y of the current band.
+ : */
+ : numRects = curStart - prevStart;
+ : region->data->numRects -= numRects;
+ : do {
+ : pPrevBox--;
+ : pPrevBox->y2 = y2;
+ : numRects--;
+ : } while (numRects);
+ : return prevStart;
+ :}
+ :
+ :/* Quicky macro to avoid trivial reject procedure calls to pixman_coalesce */
+ :
+ :#define Coalesce(newReg, prevBand, curBand) \
+ : if (curBand - prevBand == newReg->data->numRects - curBand) { \
+ : prevBand = pixman_coalesce(newReg, prevBand, curBand); \
+ : } else { \
+ : prevBand = curBand; \
+ : }
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * pixman_region_appendNonO --
+ : * Handle a non-overlapping band for the union and subtract operations.
+ : * Just adds the (top/bottom-clipped) rectangles into the region.
+ : * Doesn't have to check for subsumption or anything.
+ : *
+ : * Results:
+ : * None.
+ : *
+ : * Side Effects:
+ : * region->data->numRects is incremented and the rectangles overwritten
+ : * with the rectangles we're passed.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :
+ :static inline pixman_bool_t
+ :pixman_region_appendNonO (
+ : pixman_region16_t * region,
+ : pixman_box16_t * r,
+ : pixman_box16_t * rEnd,
+ : int y1,
+ : int y2)
+ :{
+ : pixman_box16_t * pNextRect;
+ : int newRects;
+ :
+ : newRects = rEnd - r;
+ :
+ : assert(y1 < y2);
+ : assert(newRects != 0);
+ :
+ : /* Make sure we have enough space for all rectangles to be added */
+ : RECTALLOC(region, newRects);
+ : pNextRect = PIXREGION_TOP(region);
+ : region->data->numRects += newRects;
+ : do {
+ : assert(r->x1 < r->x2);
+ : ADDRECT(pNextRect, r->x1, y1, r->x2, y2);
+ : r++;
+ : } while (r != rEnd);
+ :
+ : return TRUE;
+ :}
+ :
+ :#define FindBand(r, rBandEnd, rEnd, ry1) \
+ :{ \
+ : ry1 = r->y1; \
+ : rBandEnd = r+1; \
+ : while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) { \
+ : rBandEnd++; \
+ : } \
+ :}
+ :
+ :#define AppendRegions(newReg, r, rEnd) \
+ :{ \
+ : int newRects; \
+ : if ((newRects = rEnd - r)) { \
+ : RECTALLOC(newReg, newRects); \
+ : memmove((char *)PIXREGION_TOP(newReg),(char *)r, \
+ : newRects * sizeof(pixman_box16_t)); \
+ : newReg->data->numRects += newRects; \
+ : } \
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * pixman_op --
+ : * Apply an operation to two regions. Called by pixman_region_union, pixman_region_inverse,
+ : * pixman_region_subtract, pixman_region_intersect.... Both regions MUST have at least one
+ : * rectangle, and cannot be the same object.
+ : *
+ : * Results:
+ : * TRUE if successful.
+ : *
+ : * Side Effects:
+ : * The new region is overwritten.
+ : * pOverlap set to TRUE if overlapFunc ever returns TRUE.
+ : *
+ : * Notes:
+ : * The idea behind this function is to view the two regions as sets.
+ : * Together they cover a rectangle of area that this function divides
+ : * into horizontal bands where points are covered only by one region
+ : * or by both. For the first case, the nonOverlapFunc is called with
+ : * each the band and the band's upper and lower extents. For the
+ : * second, the overlapFunc is called to process the entire band. It
+ : * is responsible for clipping the rectangles in the band, though
+ : * this function provides the boundaries.
+ : * At the end of each band, the new region is coalesced, if possible,
+ : * to reduce the number of rectangles in the region.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :
+ :typedef pixman_bool_t (*OverlapProcPtr)(
+ : pixman_region16_t *region,
+ : pixman_box16_t *r1,
+ : pixman_box16_t *r1End,
+ : pixman_box16_t *r2,
+ : pixman_box16_t *r2End,
+ : short y1,
+ : short y2,
+ : int *pOverlap);
+ :
+ :static pixman_bool_t
+ :pixman_op(
+ : pixman_region16_t *newReg, /* Place to store result */
+ : pixman_region16_t * reg1, /* First region in operation */
+ : pixman_region16_t * reg2, /* 2d region in operation */
+ : OverlapProcPtr overlapFunc, /* Function to call for over-
+ : * lapping bands */
+ : int appendNon1, /* Append non-overlapping bands */
+ : /* in region 1 ? */
+ : int appendNon2, /* Append non-overlapping bands */
+ : /* in region 2 ? */
+ : int *pOverlap)
+ 7 0.0076 :{ /* pixman_op total: 146 0.1591 */
+ : pixman_box16_t * r1; /* Pointer into first region */
+ : pixman_box16_t * r2; /* Pointer into 2d region */
+ : pixman_box16_t * r1End; /* End of 1st region */
+ : pixman_box16_t * r2End; /* End of 2d region */
+ : short ybot; /* Bottom of intersection */
+ : short ytop; /* Top of intersection */
+ : pixman_region16_data_t * oldData; /* Old data for newReg */
+ : int prevBand; /* Index of start of
+ : * previous band in newReg */
+ : int curBand; /* Index of start of current
+ : * band in newReg */
+ : pixman_box16_t * r1BandEnd; /* End of current band in r1 */
+ : pixman_box16_t * r2BandEnd; /* End of current band in r2 */
+ : short top; /* Top of non-overlapping band */
+ : short bot; /* Bottom of non-overlapping band*/
+ : int r1y1; /* Temps for r1->y1 and r2->y1 */
+ : int r2y1;
+ : int newSize;
+ : int numRects;
+ :
+ : /*
+ : * Break any region computed from a broken region
+ : */
+ 3 0.0033 : if (PIXREGION_NAR (reg1) || PIXREGION_NAR(reg2))
+ : return pixman_break (newReg);
+ :
+ : /*
+ : * Initialization:
+ : * set r1, r2, r1End and r2End appropriately, save the rectangles
+ : * of the destination region until the end in case it's one of
+ : * the two source regions, then mark the "new" region empty, allocating
+ : * another array of rectangles for it to use.
+ : */
+ :
+ 3 0.0033 : r1 = PIXREGION_RECTS(reg1);
+ 2 0.0022 : newSize = PIXREGION_NUM_RECTS(reg1);
+ : r1End = r1 + newSize;
+ 4 0.0044 : numRects = PIXREGION_NUM_RECTS(reg2);
+ 1 0.0011 : r2 = PIXREGION_RECTS(reg2);
+ : r2End = r2 + numRects;
+ : assert(r1 != r1End);
+ : assert(r2 != r2End);
+ :
+ : oldData = (pixman_region16_data_t *)NULL;
+ 1 0.0011 : if (((newReg == reg1) && (newSize > 1)) ||
+ : ((newReg == reg2) && (numRects > 1)))
+ : {
+ 1 0.0011 : oldData = newReg->data;
+ 1 0.0011 : newReg->data = pixman_region_emptyData;
+ : }
+ : /* guess at new size */
+ : if (numRects > newSize)
+ : newSize = numRects;
+ : newSize <<= 1;
+ 1 0.0011 : if (!newReg->data)
+ 2 0.0022 : newReg->data = pixman_region_emptyData;
+ : else if (newReg->data->size)
+ : newReg->data->numRects = 0;
+ : if (newSize > newReg->data->size) {
+ : if (!pixman_rect_alloc(newReg, newSize)) {
+ : if (oldData)
+ : free (oldData);
+ : return FALSE;
+ : }
+ : }
+ :
+ : /*
+ : * Initialize ybot.
+ : * In the upcoming loop, ybot and ytop serve different functions depending
+ : * on whether the band being handled is an overlapping or non-overlapping
+ : * band.
+ : * In the case of a non-overlapping band (only one of the regions
+ : * has points in the band), ybot is the bottom of the most recent
+ : * intersection and thus clips the top of the rectangles in that band.
+ : * ytop is the top of the next intersection between the two regions and
+ : * serves to clip the bottom of the rectangles in the current band.
+ : * For an overlapping band (where the two regions intersect), ytop clips
+ : * the top of the rectangles of both regions and ybot clips the bottoms.
+ : */
+ :
+ 2 0.0022 : ybot = MIN(r1->y1, r2->y1);
+ :
+ : /*
+ : * prevBand serves to mark the start of the previous band so rectangles
+ : * can be coalesced into larger rectangles. qv. pixman_coalesce, above.
+ : * In the beginning, there is no previous band, so prevBand == curBand
+ : * (curBand is set later on, of course, but the first band will always
+ : * start at index 0). prevBand and curBand must be indices because of
+ : * the possible expansion, and resultant moving, of the new region's
+ : * array of rectangles.
+ : */
+ : prevBand = 0;
+ :
+ : do {
+ : /*
+ : * This algorithm proceeds one source-band (as opposed to a
+ : * destination band, which is determined by where the two regions
+ : * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
+ : * rectangle after the last one in the current band for their
+ : * respective regions.
+ : */
+ : assert(r1 != r1End);
+ : assert(r2 != r2End);
+ :
+ 2 0.0022 : FindBand(r1, r1BandEnd, r1End, r1y1);
+ 9 0.0098 : FindBand(r2, r2BandEnd, r2End, r2y1);
+ :
+ : /*
+ : * First handle the band that doesn't intersect, if any.
+ : *
+ : * Note that attention is restricted to one band in the
+ : * non-intersecting region at once, so if a region has n
+ : * bands between the current position and the next place it overlaps
+ : * the other, this entire loop will be passed through n times.
+ : */
+ 3 0.0033 : if (r1y1 < r2y1) {
+ : if (appendNon1) {
+ : top = MAX(r1y1, ybot);
+ : bot = MIN(r1->y2, r2y1);
+ : if (top != bot) {
+ : curBand = newReg->data->numRects;
+ : pixman_region_appendNonO(newReg, r1, r1BandEnd, top, bot);
+ : Coalesce(newReg, prevBand, curBand);
+ : }
+ : }
+ : ytop = r2y1;
+ : } else if (r2y1 < r1y1) {
+ 1 0.0011 : if (appendNon2) {
+ 1 0.0011 : top = MAX(r2y1, ybot);
+ : bot = MIN(r2->y2, r1y1);
+ : if (top != bot) {
+ : curBand = newReg->data->numRects;
+ : pixman_region_appendNonO(newReg, r2, r2BandEnd, top, bot);
+ : Coalesce(newReg, prevBand, curBand);
+ : }
+ : }
+ : ytop = r1y1;
+ : } else {
+ : ytop = r1y1;
+ : }
+ :
+ : /*
+ : * Now see if we've hit an intersecting band. The two bands only
+ : * intersect if ybot > ytop
+ : */
+ 2 0.0022 : ybot = MIN(r1->y2, r2->y2);
+ 6 0.0065 : if (ybot > ytop) {
+ 4 0.0044 : curBand = newReg->data->numRects;
+ 4 0.0044 : (* overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot,
+ : pOverlap);
+ 9 0.0098 : Coalesce(newReg, prevBand, curBand);
+ : }
+ :
+ : /*
+ : * If we've finished with a band (y2 == ybot) we skip forward
+ : * in the region to the next band.
+ : */
+ 1 0.0011 : if (r1->y2 == ybot) r1 = r1BandEnd;
+ 3 0.0033 : if (r2->y2 == ybot) r2 = r2BandEnd;
+ :
+ 5 0.0054 : } while (r1 != r1End && r2 != r2End);
+ :
+ : /*
+ : * Deal with whichever region (if any) still has rectangles left.
+ : *
+ : * We only need to worry about banding and coalescing for the very first
+ : * band left. After that, we can just group all remaining boxes,
+ : * regardless of how many bands, into one final append to the list.
+ : */
+ :
+ : if ((r1 != r1End) && appendNon1) {
+ : /* Do first nonOverlap1Func call, which may be able to coalesce */
+ 1 0.0011 : FindBand(r1, r1BandEnd, r1End, r1y1);
+ : curBand = newReg->data->numRects;
+ 2 0.0022 : pixman_region_appendNonO(newReg, r1, r1BandEnd, MAX(r1y1, ybot), r1->y2);
+ 3 0.0033 : Coalesce(newReg, prevBand, curBand);
+ : /* Just append the rest of the boxes */
+ 1 0.0011 : AppendRegions(newReg, r1BandEnd, r1End);
+ :
+ : } else if ((r2 != r2End) && appendNon2) {
+ : /* Do first nonOverlap2Func call, which may be able to coalesce */
+ : FindBand(r2, r2BandEnd, r2End, r2y1);
+ : curBand = newReg->data->numRects;
+ : pixman_region_appendNonO(newReg, r2, r2BandEnd, MAX(r2y1, ybot), r2->y2);
+ : Coalesce(newReg, prevBand, curBand);
+ : /* Append rest of boxes */
+ 7 0.0076 : AppendRegions(newReg, r2BandEnd, r2End);
+ : }
+ :
+ 2 0.0022 : if (oldData)
+ : free(oldData);
+ :
+ 8 0.0087 : if (!(numRects = newReg->data->numRects))
+ : {
+ : freeData(newReg);
+ : newReg->data = pixman_region_emptyData;
+ : }
+ 1 0.0011 : else if (numRects == 1)
+ : {
+ : newReg->extents = *PIXREGION_BOXPTR(newReg);
+ : freeData(newReg);
+ : newReg->data = (pixman_region16_data_t *)NULL;
+ : }
+ : else
+ : {
+ 1 0.0011 : DOWNSIZE(newReg, numRects);
+ : }
+ :
+ : return TRUE;
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * pixman_set_extents --
+ : * Reset the extents of a region to what they should be. Called by
+ : * pixman_region_subtract and pixman_region_intersect as they can't figure it out along the
+ : * way or do so easily, as pixman_region_union can.
+ : *
+ : * Results:
+ : * None.
+ : *
+ : * Side Effects:
+ : * The region's 'extents' structure is overwritten.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :pixman_set_extents (pixman_region16_t *region)
+ :{
+ : pixman_box16_t *box, *boxEnd;
+ :
+ : if (!region->data)
+ : return;
+ : if (!region->data->size)
+ : {
+ : region->extents.x2 = region->extents.x1;
+ : region->extents.y2 = region->extents.y1;
+ : return;
+ : }
+ :
+ : box = PIXREGION_BOXPTR(region);
+ : boxEnd = PIXREGION_END(region);
+ :
+ : /*
+ : * Since box is the first rectangle in the region, it must have the
+ : * smallest y1 and since boxEnd is the last rectangle in the region,
+ : * it must have the largest y2, because of banding. Initialize x1 and
+ : * x2 from box and boxEnd, resp., as good things to initialize them
+ : * to...
+ : */
+ : region->extents.x1 = box->x1;
+ : region->extents.y1 = box->y1;
+ : region->extents.x2 = boxEnd->x2;
+ : region->extents.y2 = boxEnd->y2;
+ :
+ : assert(region->extents.y1 < region->extents.y2);
+ : while (box <= boxEnd) {
+ : if (box->x1 < region->extents.x1)
+ : region->extents.x1 = box->x1;
+ : if (box->x2 > region->extents.x2)
+ : region->extents.x2 = box->x2;
+ : box++;
+ : };
+ :
+ : assert(region->extents.x1 < region->extents.x2);
+ :}
+ :
+ :/*======================================================================
+ : * Region Intersection
+ : *====================================================================*/
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * pixman_region_intersectO --
+ : * Handle an overlapping band for pixman_region_intersect.
+ : *
+ : * Results:
+ : * TRUE if successful.
+ : *
+ : * Side Effects:
+ : * Rectangles may be added to the region.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :/*ARGSUSED*/
+ :static pixman_bool_t
+ :pixman_region_intersectO (pixman_region16_t *region,
+ : pixman_box16_t *r1,
+ : pixman_box16_t *r1End,
+ : pixman_box16_t *r2,
+ : pixman_box16_t *r2End,
+ : short y1,
+ : short y2,
+ : int *pOverlap)
+ :{
+ : int x1;
+ : int x2;
+ : pixman_box16_t * pNextRect;
+ :
+ : pNextRect = PIXREGION_TOP(region);
+ :
+ : assert(y1 < y2);
+ : assert(r1 != r1End && r2 != r2End);
+ :
+ : do {
+ : x1 = MAX(r1->x1, r2->x1);
+ : x2 = MIN(r1->x2, r2->x2);
+ :
+ : /*
+ : * If there's any overlap between the two rectangles, add that
+ : * overlap to the new region.
+ : */
+ : if (x1 < x2)
+ : NEWRECT(region, pNextRect, x1, y1, x2, y2);
+ :
+ : /*
+ : * Advance the pointer(s) with the leftmost right side, since the next
+ : * rectangle on that list may still overlap the other region's
+ : * current rectangle.
+ : */
+ : if (r1->x2 == x2) {
+ : r1++;
+ : }
+ : if (r2->x2 == x2) {
+ : r2++;
+ : }
+ : } while ((r1 != r1End) && (r2 != r2End));
+ :
+ : return TRUE;
+ :}
+ :
+ :pixman_bool_t
+ :pixman_region_intersect (pixman_region16_t * newReg,
+ : pixman_region16_t * reg1,
+ : pixman_region16_t * reg2)
+ 4 0.0044 :{ /* pixman_region_intersect total: 13 0.0142 */
+ : good(reg1);
+ : good(reg2);
+ : good(newReg);
+ : /* check for trivial reject */
+ 4 0.0044 : if (PIXREGION_NIL(reg1) || PIXREGION_NIL(reg2) ||
+ : !EXTENTCHECK(®1->extents, ®2->extents))
+ : {
+ : /* Covers about 20% of all cases */
+ : freeData(newReg);
+ : newReg->extents.x2 = newReg->extents.x1;
+ : newReg->extents.y2 = newReg->extents.y1;
+ : if (PIXREGION_NAR(reg1) || PIXREGION_NAR(reg2))
+ : {
+ : newReg->data = pixman_brokendata;
+ : return FALSE;
+ : }
+ : else
+ : newReg->data = pixman_region_emptyData;
+ : }
+ : else if (!reg1->data && !reg2->data)
+ : {
+ : /* Covers about 80% of cases that aren't trivially rejected */
+ 1 0.0011 : newReg->extents.x1 = MAX(reg1->extents.x1, reg2->extents.x1);
+ 1 0.0011 : newReg->extents.y1 = MAX(reg1->extents.y1, reg2->extents.y1);
+ 1 0.0011 : newReg->extents.x2 = MIN(reg1->extents.x2, reg2->extents.x2);
+ : newReg->extents.y2 = MIN(reg1->extents.y2, reg2->extents.y2);
+ : freeData(newReg);
+ : newReg->data = (pixman_region16_data_t *)NULL;
+ : }
+ : else if (!reg2->data && SUBSUMES(®2->extents, ®1->extents))
+ : {
+ : return pixman_region_copy(newReg, reg1);
+ : }
+ : else if (!reg1->data && SUBSUMES(®1->extents, ®2->extents))
+ : {
+ : return pixman_region_copy(newReg, reg2);
+ : }
+ : else if (reg1 == reg2)
+ : {
+ : return pixman_region_copy(newReg, reg1);
+ : }
+ : else
+ : {
+ : /* General purpose intersection */
+ : int overlap; /* result ignored */
+ : if (!pixman_op(newReg, reg1, reg2, pixman_region_intersectO, FALSE, FALSE,
+ : &overlap))
+ : return FALSE;
+ : pixman_set_extents(newReg);
+ : }
+ :
+ : good(newReg);
+ : return(TRUE);
+ 2 0.0022 :}
+ :
+ :#define MERGERECT(r) \
+ :{ \
+ : if (r->x1 <= x2) { \
+ : /* Merge with current rectangle */ \
+ : if (r->x1 < x2) *pOverlap = TRUE; \
+ : if (x2 < r->x2) x2 = r->x2; \
+ : } else { \
+ : /* Add current rectangle, start new one */ \
+ : NEWRECT(region, pNextRect, x1, y1, x2, y2); \
+ : x1 = r->x1; \
+ : x2 = r->x2; \
+ : } \
+ : r++; \
+ :}
+ :
+ :/*======================================================================
+ : * Region Union
+ : *====================================================================*/
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * pixman_region_unionO --
+ : * Handle an overlapping band for the union operation. Picks the
+ : * left-most rectangle each time and merges it into the region.
+ : *
+ : * Results:
+ : * TRUE if successful.
+ : *
+ : * Side Effects:
+ : * region is overwritten.
+ : * pOverlap is set to TRUE if any boxes overlap.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static pixman_bool_t
+ :pixman_region_unionO (
+ : pixman_region16_t *region,
+ : pixman_box16_t *r1,
+ : pixman_box16_t *r1End,
+ : pixman_box16_t *r2,
+ : pixman_box16_t *r2End,
+ : short y1,
+ : short y2,
+ : int *pOverlap)
+ 11 0.0120 :{ /* pixman_region_unionO total: 39 0.0425 */
+ : pixman_box16_t * pNextRect;
+ : int x1; /* left and right side of current union */
+ : int x2;
+ :
+ : assert (y1 < y2);
+ : assert(r1 != r1End && r2 != r2End);
+ :
+ 6 0.0065 : pNextRect = PIXREGION_TOP(region);
+ :
+ : /* Start off current rectangle */
+ : if (r1->x1 < r2->x1)
+ : {
+ : x1 = r1->x1;
+ : x2 = r1->x2;
+ : r1++;
+ : }
+ : else
+ : {
+ 1 0.0011 : x1 = r2->x1;
+ 2 0.0022 : x2 = r2->x2;
+ : r2++;
+ : }
+ 3 0.0033 : while (r1 != r1End && r2 != r2End)
+ : {
+ : if (r1->x1 < r2->x1) MERGERECT(r1) else MERGERECT(r2);
+ : }
+ :
+ : /* Finish off whoever (if any) is left */
+ : if (r1 != r1End)
+ : {
+ : do
+ : {
+ 8 0.0087 : MERGERECT(r1);
+ 2 0.0022 : } while (r1 != r1End);
+ : }
+ : else if (r2 != r2End)
+ : {
+ : do
+ : {
+ : MERGERECT(r2);
+ : } while (r2 != r2End);
+ : }
+ :
+ : /* Add current rectangle */
+ 4 0.0044 : NEWRECT(region, pNextRect, x1, y1, x2, y2);
+ :
+ : return TRUE;
+ 2 0.0022 :}
+ :
+ :/* Convenience function for performing union of region with a
+ : * single rectangle
+ : */
+ :pixman_bool_t
+ :pixman_region_union_rect (pixman_region16_t *dest,
+ : pixman_region16_t *source,
+ : int x, int y,
+ : unsigned int width, unsigned int height)
+ :{
+ : pixman_region16_t region;
+ :
+ : if (!width || !height)
+ : return pixman_region_copy (dest, source);
+ : region.data = NULL;
+ : region.extents.x1 = x;
+ : region.extents.y1 = y;
+ : region.extents.x2 = x + width;
+ : region.extents.y2 = y + height;
+ :
+ : return pixman_region_union (dest, source, ®ion);
+ :}
+ :
+ :pixman_bool_t
+ :pixman_region_union (pixman_region16_t *newReg,
+ : pixman_region16_t *reg1,
+ : pixman_region16_t *reg2)
+ 17 0.0185 :{ /* pixman_region_union total: 87 0.0948 */
+ : int overlap; /* result ignored */
+ :
+ : /* Return TRUE if some overlap
+ : * between reg1, reg2
+ : */
+ : good(reg1);
+ : good(reg2);
+ : good(newReg);
+ : /* checks all the simple cases */
+ :
+ : /*
+ : * Region 1 and 2 are the same
+ : */
+ : if (reg1 == reg2)
+ : {
+ : return pixman_region_copy(newReg, reg1);
+ : }
+ :
+ : /*
+ : * Region 1 is empty
+ : */
+ 7 0.0076 : if (PIXREGION_NIL(reg1))
+ : {
+ : if (PIXREGION_NAR(reg1))
+ : return pixman_break (newReg);
+ 1 0.0011 : if (newReg != reg2)
+ 1 0.0011 : return pixman_region_copy(newReg, reg2);
+ : return TRUE;
+ : }
+ :
+ : /*
+ : * Region 2 is empty
+ : */
+ 9 0.0098 : if (PIXREGION_NIL(reg2))
+ : {
+ : if (PIXREGION_NAR(reg2))
+ : return pixman_break (newReg);
+ : if (newReg != reg1)
+ : return pixman_region_copy(newReg, reg1);
+ : return TRUE;
+ : }
+ :
+ : /*
+ : * Region 1 completely subsumes region 2
+ : */
+ 8 0.0087 : if (!reg1->data && SUBSUMES(®1->extents, ®2->extents))
+ : {
+ 7 0.0076 : if (newReg != reg1)
+ : return pixman_region_copy(newReg, reg1);
+ : return TRUE;
+ : }
+ :
+ : /*
+ : * Region 2 completely subsumes region 1
+ : */
+ 2 0.0022 : if (!reg2->data && SUBSUMES(®2->extents, ®1->extents))
+ : {
+ : if (newReg != reg2)
+ 1 0.0011 : return pixman_region_copy(newReg, reg2);
+ : return TRUE;
+ : }
+ :
+ 3 0.0033 : if (!pixman_op(newReg, reg1, reg2, pixman_region_unionO, TRUE, TRUE, &overlap))
+ : return FALSE;
+ :
+ 1 0.0011 : newReg->extents.x1 = MIN(reg1->extents.x1, reg2->extents.x1);
+ 3 0.0033 : newReg->extents.y1 = MIN(reg1->extents.y1, reg2->extents.y1);
+ 7 0.0076 : newReg->extents.x2 = MAX(reg1->extents.x2, reg2->extents.x2);
+ 8 0.0087 : newReg->extents.y2 = MAX(reg1->extents.y2, reg2->extents.y2);
+ : good(newReg);
+ 5 0.0054 : return TRUE;
+ 7 0.0076 :}
+ :
+ :/*======================================================================
+ : * Batch Rectangle Union
+ : *====================================================================*/
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * pixman_region_append --
+ : *
+ : * "Append" the rgn rectangles onto the end of dstrgn, maintaining
+ : * knowledge of YX-banding when it's easy. Otherwise, dstrgn just
+ : * becomes a non-y-x-banded random collection of rectangles, and not
+ : * yet a true region. After a sequence of appends, the caller must
+ : * call pixman_region_validate to ensure that a valid region is
+ : * constructed.
+ : *
+ : * Results:
+ : * TRUE if successful.
+ : *
+ : * Side Effects:
+ : * dstrgn is modified if rgn has rectangles.
+ : *
+ : */
+ :pixman_bool_t
+ :pixman_region_append (pixman_region16_t * dstrgn,
+ : pixman_region16_t * rgn)
+ :{
+ : int numRects, dnumRects, size;
+ : pixman_box16_t *new, *old;
+ : int prepend;
+ :
+ : if (PIXREGION_NAR(rgn))
+ : return pixman_break (dstrgn);
+ :
+ : if (!rgn->data && (dstrgn->data == pixman_region_emptyData))
+ : {
+ : dstrgn->extents = rgn->extents;
+ : dstrgn->data = (pixman_region16_data_t *)NULL;
+ : return TRUE;
+ : }
+ :
+ : numRects = PIXREGION_NUM_RECTS(rgn);
+ : if (!numRects)
+ : return TRUE;
+ : prepend = FALSE;
+ : size = numRects;
+ : dnumRects = PIXREGION_NUM_RECTS(dstrgn);
+ : if (!dnumRects && (size < 200))
+ : size = 200; /* XXX pick numbers out of a hat */
+ : RECTALLOC(dstrgn, size);
+ : old = PIXREGION_RECTS(rgn);
+ : if (!dnumRects)
+ : dstrgn->extents = rgn->extents;
+ : else if (dstrgn->extents.x2 > dstrgn->extents.x1)
+ : {
+ : pixman_box16_t *first, *last;
+ :
+ : first = old;
+ : last = PIXREGION_BOXPTR(dstrgn) + (dnumRects - 1);
+ : if ((first->y1 > last->y2) ||
+ : ((first->y1 == last->y1) && (first->y2 == last->y2) &&
+ : (first->x1 > last->x2)))
+ : {
+ : if (rgn->extents.x1 < dstrgn->extents.x1)
+ : dstrgn->extents.x1 = rgn->extents.x1;
+ : if (rgn->extents.x2 > dstrgn->extents.x2)
+ : dstrgn->extents.x2 = rgn->extents.x2;
+ : dstrgn->extents.y2 = rgn->extents.y2;
+ : }
+ : else
+ : {
+ : first = PIXREGION_BOXPTR(dstrgn);
+ : last = old + (numRects - 1);
+ : if ((first->y1 > last->y2) ||
+ : ((first->y1 == last->y1) && (first->y2 == last->y2) &&
+ : (first->x1 > last->x2)))
+ : {
+ : prepend = TRUE;
+ : if (rgn->extents.x1 < dstrgn->extents.x1)
+ : dstrgn->extents.x1 = rgn->extents.x1;
+ : if (rgn->extents.x2 > dstrgn->extents.x2)
+ : dstrgn->extents.x2 = rgn->extents.x2;
+ : dstrgn->extents.y1 = rgn->extents.y1;
+ : }
+ : else
+ : dstrgn->extents.x2 = dstrgn->extents.x1;
+ : }
+ : }
+ : if (prepend)
+ : {
+ : new = PIXREGION_BOX(dstrgn, numRects);
+ : if (dnumRects == 1)
+ : *new = *PIXREGION_BOXPTR(dstrgn);
+ : else
+ : memmove((char *)new,(char *)PIXREGION_BOXPTR(dstrgn),
+ : dnumRects * sizeof(pixman_box16_t));
+ : new = PIXREGION_BOXPTR(dstrgn);
+ : }
+ : else
+ : new = PIXREGION_BOXPTR(dstrgn) + dnumRects;
+ : if (numRects == 1)
+ : *new = *old;
+ : else
+ : memmove((char *)new, (char *)old, numRects * sizeof(pixman_box16_t));
+ : dstrgn->data->numRects += numRects;
+ : return TRUE;
+ :}
+ :
+ :#define ExchangeRects(a, b) \
+ :{ \
+ : pixman_box16_t t; \
+ : t = rects[a]; \
+ : rects[a] = rects[b]; \
+ : rects[b] = t; \
+ :}
+ :
+ :static void
+ :QuickSortRects(
+ : pixman_box16_t rects[],
+ : int numRects)
+ :{
+ : int y1;
+ : int x1;
+ : int i, j;
+ : pixman_box16_t *r;
+ :
+ : /* Always called with numRects > 1 */
+ :
+ : do
+ : {
+ : if (numRects == 2)
+ : {
+ : if (rects[0].y1 > rects[1].y1 ||
+ : (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1))
+ : ExchangeRects(0, 1);
+ : return;
+ : }
+ :
+ : /* Choose partition element, stick in location 0 */
+ : ExchangeRects(0, numRects >> 1);
+ : y1 = rects[0].y1;
+ : x1 = rects[0].x1;
+ :
+ : /* Partition array */
+ : i = 0;
+ : j = numRects;
+ : do
+ : {
+ : r = &(rects[i]);
+ : do
+ : {
+ : r++;
+ : i++;
+ : } while (i != numRects &&
+ : (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1)));
+ : r = &(rects[j]);
+ : do
+ : {
+ : r--;
+ : j--;
+ : } while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1));
+ : if (i < j)
+ : ExchangeRects(i, j);
+ : } while (i < j);
+ :
+ : /* Move partition element back to middle */
+ : ExchangeRects(0, j);
+ :
+ : /* Recurse */
+ : if (numRects-j-1 > 1)
+ : QuickSortRects(&rects[j+1], numRects-j-1);
+ : numRects = j;
+ : } while (numRects > 1);
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * pixman_region_validate --
+ : *
+ : * Take a ``region'' which is a non-y-x-banded random collection of
+ : * rectangles, and compute a nice region which is the union of all the
+ : * rectangles.
+ : *
+ : * Results:
+ : * TRUE if successful.
+ : *
+ : * Side Effects:
+ : * The passed-in ``region'' may be modified.
+ : * pOverlap set to TRUE if any retangles overlapped,
+ : * else FALSE;
+ : *
+ : * Strategy:
+ : * Step 1. Sort the rectangles into ascending order with primary key y1
+ : * and secondary key x1.
+ : *
+ : * Step 2. Split the rectangles into the minimum number of proper y-x
+ : * banded regions. This may require horizontally merging
+ : * rectangles, and vertically coalescing bands. With any luck,
+ : * this step in an identity transformation (ala the Box widget),
+ : * or a coalescing into 1 box (ala Menus).
+ : *
+ : * Step 3. Merge the separate regions down to a single region by calling
+ : * pixman_region_union. Maximize the work each pixman_region_union call does by using
+ : * a binary merge.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :
+ :pixman_bool_t
+ :pixman_region_validate(pixman_region16_t * badreg,
+ : int *pOverlap)
+ :{
+ : /* Descriptor for regions under construction in Step 2. */
+ : typedef struct {
+ : pixman_region16_t reg;
+ : int prevBand;
+ : int curBand;
+ : } RegionInfo;
+ :
+ : int numRects; /* Original numRects for badreg */
+ : RegionInfo *ri; /* Array of current regions */
+ : int numRI; /* Number of entries used in ri */
+ : int sizeRI; /* Number of entries available in ri */
+ : int i; /* Index into rects */
+ : int j; /* Index into ri */
+ : RegionInfo *rit; /* &ri[j] */
+ : pixman_region16_t * reg; /* ri[j].reg */
+ : pixman_box16_t * box; /* Current box in rects */
+ : pixman_box16_t * riBox; /* Last box in ri[j].reg */
+ : pixman_region16_t * hreg; /* ri[j_half].reg */
+ : pixman_bool_t ret = TRUE;
+ :
+ : *pOverlap = FALSE;
+ : if (!badreg->data)
+ : {
+ : good(badreg);
+ : return TRUE;
+ : }
+ : numRects = badreg->data->numRects;
+ : if (!numRects)
+ : {
+ : if (PIXREGION_NAR(badreg))
+ : return FALSE;
+ : good(badreg);
+ : return TRUE;
+ : }
+ : if (badreg->extents.x1 < badreg->extents.x2)
+ : {
+ : if ((numRects) == 1)
+ : {
+ : freeData(badreg);
+ : badreg->data = (pixman_region16_data_t *) NULL;
+ : }
+ : else
+ : {
+ : DOWNSIZE(badreg, numRects);
+ : }
+ : good(badreg);
+ : return TRUE;
+ : }
+ :
+ : /* Step 1: Sort the rects array into ascending (y1, x1) order */
+ : QuickSortRects(PIXREGION_BOXPTR(badreg), numRects);
+ :
+ : /* Step 2: Scatter the sorted array into the minimum number of regions */
+ :
+ : /* Set up the first region to be the first rectangle in badreg */
+ : /* Note that step 2 code will never overflow the ri[0].reg rects array */
+ : ri = (RegionInfo *) malloc(4 * sizeof(RegionInfo));
+ : if (!ri)
+ : return pixman_break (badreg);
+ : sizeRI = 4;
+ : numRI = 1;
+ : ri[0].prevBand = 0;
+ : ri[0].curBand = 0;
+ : ri[0].reg = *badreg;
+ : box = PIXREGION_BOXPTR(&ri[0].reg);
+ : ri[0].reg.extents = *box;
+ : ri[0].reg.data->numRects = 1;
+ :
+ : /* Now scatter rectangles into the minimum set of valid regions. If the
+ : next rectangle to be added to a region would force an existing rectangle
+ : in the region to be split up in order to maintain y-x banding, just
+ : forget it. Try the next region. If it doesn't fit cleanly into any
+ : region, make a new one. */
+ :
+ : for (i = numRects; --i > 0;)
+ : {
+ : box++;
+ : /* Look for a region to append box to */
+ : for (j = numRI, rit = ri; --j >= 0; rit++)
+ : {
+ : reg = &rit->reg;
+ : riBox = PIXREGION_END(reg);
+ :
+ : if (box->y1 == riBox->y1 && box->y2 == riBox->y2)
+ : {
+ : /* box is in same band as riBox. Merge or append it */
+ : if (box->x1 <= riBox->x2)
+ : {
+ : /* Merge it with riBox */
+ : if (box->x1 < riBox->x2) *pOverlap = TRUE;
+ : if (box->x2 > riBox->x2) riBox->x2 = box->x2;
+ : }
+ : else
+ : {
+ : RECTALLOC_BAIL(reg, 1, bail);
+ : *PIXREGION_TOP(reg) = *box;
+ : reg->data->numRects++;
+ : }
+ : goto NextRect; /* So sue me */
+ : }
+ : else if (box->y1 >= riBox->y2)
+ : {
+ : /* Put box into new band */
+ : if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
+ : if (reg->extents.x1 > box->x1) reg->extents.x1 = box->x1;
+ : Coalesce(reg, rit->prevBand, rit->curBand);
+ : rit->curBand = reg->data->numRects;
+ : RECTALLOC_BAIL(reg, 1, bail);
+ : *PIXREGION_TOP(reg) = *box;
+ : reg->data->numRects++;
+ : goto NextRect;
+ : }
+ : /* Well, this region was inappropriate. Try the next one. */
+ : } /* for j */
+ :
+ : /* Uh-oh. No regions were appropriate. Create a new one. */
+ : if (sizeRI == numRI)
+ : {
+ : /* Oops, allocate space for new region information */
+ : sizeRI <<= 1;
+ : rit = (RegionInfo *) realloc(ri, sizeRI * sizeof(RegionInfo));
+ : if (!rit)
+ : goto bail;
+ : ri = rit;
+ : rit = &ri[numRI];
+ : }
+ : numRI++;
+ : rit->prevBand = 0;
+ : rit->curBand = 0;
+ : rit->reg.extents = *box;
+ : rit->reg.data = (pixman_region16_data_t *)NULL;
+ : if (!pixman_rect_alloc(&rit->reg, (i+numRI) / numRI)) /* MUST force allocation */
+ : goto bail;
+ :NextRect: ;
+ : } /* for i */
+ :
+ : /* Make a final pass over each region in order to Coalesce and set
+ : extents.x2 and extents.y2 */
+ :
+ : for (j = numRI, rit = ri; --j >= 0; rit++)
+ : {
+ : reg = &rit->reg;
+ : riBox = PIXREGION_END(reg);
+ : reg->extents.y2 = riBox->y2;
+ : if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
+ : Coalesce(reg, rit->prevBand, rit->curBand);
+ : if (reg->data->numRects == 1) /* keep unions happy below */
+ : {
+ : freeData(reg);
+ : reg->data = (pixman_region16_data_t *)NULL;
+ : }
+ : }
+ :
+ : /* Step 3: Union all regions into a single region */
+ : while (numRI > 1)
+ : {
+ : int half = numRI/2;
+ : for (j = numRI & 1; j < (half + (numRI & 1)); j++)
+ : {
+ : reg = &ri[j].reg;
+ : hreg = &ri[j+half].reg;
+ : if (!pixman_op(reg, reg, hreg, pixman_region_unionO, TRUE, TRUE, pOverlap))
+ : ret = FALSE;
+ : if (hreg->extents.x1 < reg->extents.x1)
+ : reg->extents.x1 = hreg->extents.x1;
+ : if (hreg->extents.y1 < reg->extents.y1)
+ : reg->extents.y1 = hreg->extents.y1;
+ : if (hreg->extents.x2 > reg->extents.x2)
+ : reg->extents.x2 = hreg->extents.x2;
+ : if (hreg->extents.y2 > reg->extents.y2)
+ : reg->extents.y2 = hreg->extents.y2;
+ : freeData(hreg);
+ : }
+ : numRI -= half;
+ : }
+ : *badreg = ri[0].reg;
+ : free(ri);
+ : good(badreg);
+ : return ret;
+ :bail:
+ : for (i = 0; i < numRI; i++)
+ : freeData(&ri[i].reg);
+ : free (ri);
+ : return pixman_break (badreg);
+ :}
+ :
+ :/*======================================================================
+ : * Region Subtraction
+ : *====================================================================*/
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * pixman_region_subtractO --
+ : * Overlapping band subtraction. x1 is the left-most point not yet
+ : * checked.
+ : *
+ : * Results:
+ : * TRUE if successful.
+ : *
+ : * Side Effects:
+ : * region may have rectangles added to it.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :/*ARGSUSED*/
+ :static pixman_bool_t
+ :pixman_region_subtractO (
+ : pixman_region16_t * region,
+ : pixman_box16_t * r1,
+ : pixman_box16_t * r1End,
+ : pixman_box16_t * r2,
+ : pixman_box16_t * r2End,
+ : short y1,
+ : short y2,
+ : int *pOverlap)
+ :{
+ : pixman_box16_t * pNextRect;
+ : int x1;
+ :
+ : x1 = r1->x1;
+ :
+ : assert(y1<y2);
+ : assert(r1 != r1End && r2 != r2End);
+ :
+ : pNextRect = PIXREGION_TOP(region);
+ :
+ : do
+ : {
+ : if (r2->x2 <= x1)
+ : {
+ : /*
+ : * Subtrahend entirely to left of minuend: go to next subtrahend.
+ : */
+ : r2++;
+ : }
+ : else if (r2->x1 <= x1)
+ : {
+ : /*
+ : * Subtrahend preceeds minuend: nuke left edge of minuend.
+ : */
+ : x1 = r2->x2;
+ : if (x1 >= r1->x2)
+ : {
+ : /*
+ : * Minuend completely covered: advance to next minuend and
+ : * reset left fence to edge of new minuend.
+ : */
+ : r1++;
+ : if (r1 != r1End)
+ : x1 = r1->x1;
+ : }
+ : else
+ : {
+ : /*
+ : * Subtrahend now used up since it doesn't extend beyond
+ : * minuend
+ : */
+ : r2++;
+ : }
+ : }
+ : else if (r2->x1 < r1->x2)
+ : {
+ : /*
+ : * Left part of subtrahend covers part of minuend: add uncovered
+ : * part of minuend to region and skip to next subtrahend.
+ : */
+ : assert(x1<r2->x1);
+ : NEWRECT(region, pNextRect, x1, y1, r2->x1, y2);
+ :
+ : x1 = r2->x2;
+ : if (x1 >= r1->x2)
+ : {
+ : /*
+ : * Minuend used up: advance to new...
+ : */
+ : r1++;
+ : if (r1 != r1End)
+ : x1 = r1->x1;
+ : }
+ : else
+ : {
+ : /*
+ : * Subtrahend used up
+ : */
+ : r2++;
+ : }
+ : }
+ : else
+ : {
+ : /*
+ : * Minuend used up: add any remaining piece before advancing.
+ : */
+ : if (r1->x2 > x1)
+ : NEWRECT(region, pNextRect, x1, y1, r1->x2, y2);
+ : r1++;
+ : if (r1 != r1End)
+ : x1 = r1->x1;
+ : }
+ : } while ((r1 != r1End) && (r2 != r2End));
+ :
+ : /*
+ : * Add remaining minuend rectangles to region.
+ : */
+ : while (r1 != r1End)
+ : {
+ : assert(x1<r1->x2);
+ : NEWRECT(region, pNextRect, x1, y1, r1->x2, y2);
+ : r1++;
+ : if (r1 != r1End)
+ : x1 = r1->x1;
+ : }
+ : return TRUE;
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * pixman_region_subtract --
+ : * Subtract regS from regM and leave the result in regD.
+ : * S stands for subtrahend, M for minuend and D for difference.
+ : *
+ : * Results:
+ : * TRUE if successful.
+ : *
+ : * Side Effects:
+ : * regD is overwritten.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :pixman_bool_t
+ :pixman_region_subtract(pixman_region16_t * regD,
+ : pixman_region16_t * regM,
+ : pixman_region16_t * regS)
+ :{
+ : int overlap; /* result ignored */
+ :
+ : good(regM);
+ : good(regS);
+ : good(regD);
+ : /* check for trivial rejects */
+ : if (PIXREGION_NIL(regM) || PIXREGION_NIL(regS) ||
+ : !EXTENTCHECK(®M->extents, ®S->extents))
+ : {
+ : if (PIXREGION_NAR (regS))
+ : return pixman_break (regD);
+ : return pixman_region_copy(regD, regM);
+ : }
+ : else if (regM == regS)
+ : {
+ : freeData(regD);
+ : regD->extents.x2 = regD->extents.x1;
+ : regD->extents.y2 = regD->extents.y1;
+ : regD->data = pixman_region_emptyData;
+ : return TRUE;
+ : }
+ :
+ : /* Add those rectangles in region 1 that aren't in region 2,
+ : do yucky substraction for overlaps, and
+ : just throw away rectangles in region 2 that aren't in region 1 */
+ : if (!pixman_op(regD, regM, regS, pixman_region_subtractO, TRUE, FALSE, &overlap))
+ : return FALSE;
+ :
+ : /*
+ : * Can't alter RegD's extents before we call pixman_op because
+ : * it might be one of the source regions and pixman_op depends
+ : * on the extents of those regions being unaltered. Besides, this
+ : * way there's no checking against rectangles that will be nuked
+ : * due to coalescing, so we have to examine fewer rectangles.
+ : */
+ : pixman_set_extents(regD);
+ : good(regD);
+ : return TRUE;
+ :}
+ :
+ :/*======================================================================
+ : * Region Inversion
+ : *====================================================================*/
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * pixman_region_inverse --
+ : * Take a region and a box and return a region that is everything
+ : * in the box but not in the region. The careful reader will note
+ : * that this is the same as subtracting the region from the box...
+ : *
+ : * Results:
+ : * TRUE.
+ : *
+ : * Side Effects:
+ : * newReg is overwritten.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :pixman_bool_t
+ :pixman_region_inverse(pixman_region16_t * newReg, /* Destination region */
+ : pixman_region16_t * reg1, /* Region to invert */
+ : pixman_box16_t * invRect) /* Bounding box for inversion */
+ :{
+ : pixman_region16_t invReg; /* Quick and dirty region made from the
+ : * bounding box */
+ : int overlap; /* result ignored */
+ :
+ : good(reg1);
+ : good(newReg);
+ : /* check for trivial rejects */
+ : if (PIXREGION_NIL(reg1) || !EXTENTCHECK(invRect, ®1->extents))
+ : {
+ : if (PIXREGION_NAR(reg1))
+ : return pixman_break (newReg);
+ : newReg->extents = *invRect;
+ : freeData(newReg);
+ : newReg->data = (pixman_region16_data_t *)NULL;
+ : return TRUE;
+ : }
+ :
+ : /* Add those rectangles in region 1 that aren't in region 2,
+ : do yucky substraction for overlaps, and
+ : just throw away rectangles in region 2 that aren't in region 1 */
+ : invReg.extents = *invRect;
+ : invReg.data = (pixman_region16_data_t *)NULL;
+ : if (!pixman_op(newReg, &invReg, reg1, pixman_region_subtractO, TRUE, FALSE, &overlap))
+ : return FALSE;
+ :
+ : /*
+ : * Can't alter newReg's extents before we call pixman_op because
+ : * it might be one of the source regions and pixman_op depends
+ : * on the extents of those regions being unaltered. Besides, this
+ : * way there's no checking against rectangles that will be nuked
+ : * due to coalescing, so we have to examine fewer rectangles.
+ : */
+ : pixman_set_extents(newReg);
+ : good(newReg);
+ : return TRUE;
+ :}
+ :
+ :/*
+ : * RectIn(region, rect)
+ : * This routine takes a pointer to a region and a pointer to a box
+ : * and determines if the box is outside/inside/partly inside the region.
+ : *
+ : * The idea is to travel through the list of rectangles trying to cover the
+ : * passed box with them. Anytime a piece of the rectangle isn't covered
+ : * by a band of rectangles, partOut is set TRUE. Any time a rectangle in
+ : * the region covers part of the box, partIn is set TRUE. The process ends
+ : * when either the box has been completely covered (we reached a band that
+ : * doesn't overlap the box, partIn is TRUE and partOut is false), the
+ : * box has been partially covered (partIn == partOut == TRUE -- because of
+ : * the banding, the first time this is true we know the box is only
+ : * partially in the region) or is outside the region (we reached a band
+ : * that doesn't overlap the box at all and partIn is false)
+ : */
+ :
+ :pixman_region_overlap_t
+ :pixman_region_contains_rectangle(pixman_region16_t * region,
+ : pixman_box16_t * prect)
+ :{
+ : int x;
+ : int y;
+ : pixman_box16_t * pbox;
+ : pixman_box16_t * pboxEnd;
+ : int partIn, partOut;
+ : int numRects;
+ :
+ : good(region);
+ : numRects = PIXREGION_NUM_RECTS(region);
+ : /* useful optimization */
+ : if (!numRects || !EXTENTCHECK(®ion->extents, prect))
+ : return(PIXMAN_REGION_OUT);
+ :
+ : if (numRects == 1)
+ : {
+ : /* We know that it must be PIXMAN_REGION_IN or PIXMAN_REGION_PART */
+ : if (SUBSUMES(®ion->extents, prect))
+ : return(PIXMAN_REGION_IN);
+ : else
+ : return(PIXMAN_REGION_PART);
+ : }
+ :
+ : partOut = FALSE;
+ : partIn = FALSE;
+ :
+ : /* (x,y) starts at upper left of rect, moving to the right and down */
+ : x = prect->x1;
+ : y = prect->y1;
+ :
+ : /* can stop when both partOut and partIn are TRUE, or we reach prect->y2 */
+ : for (pbox = PIXREGION_BOXPTR(region), pboxEnd = pbox + numRects;
+ : pbox != pboxEnd;
+ : pbox++)
+ : {
+ :
+ : if (pbox->y2 <= y)
+ : continue; /* getting up to speed or skipping remainder of band */
+ :
+ : if (pbox->y1 > y)
+ : {
+ : partOut = TRUE; /* missed part of rectangle above */
+ : if (partIn || (pbox->y1 >= prect->y2))
+ : break;
+ : y = pbox->y1; /* x guaranteed to be == prect->x1 */
+ : }
+ :
+ : if (pbox->x2 <= x)
+ : continue; /* not far enough over yet */
+ :
+ : if (pbox->x1 > x)
+ : {
+ : partOut = TRUE; /* missed part of rectangle to left */
+ : if (partIn)
+ : break;
+ : }
+ :
+ : if (pbox->x1 < prect->x2)
+ : {
+ : partIn = TRUE; /* definitely overlap */
+ : if (partOut)
+ : break;
+ : }
+ :
+ : if (pbox->x2 >= prect->x2)
+ : {
+ : y = pbox->y2; /* finished with this band */
+ : if (y >= prect->y2)
+ : break;
+ : x = prect->x1; /* reset x out to left again */
+ : }
+ : else
+ : {
+ : /*
+ : * Because boxes in a band are maximal width, if the first box
+ : * to overlap the rectangle doesn't completely cover it in that
+ : * band, the rectangle must be partially out, since some of it
+ : * will be uncovered in that band. partIn will have been set true
+ : * by now...
+ : */
+ : partOut = TRUE;
+ : break;
+ : }
+ : }
+ :
+ : if (partIn)
+ : {
+ : if (y < prect->y2)
+ : return PIXMAN_REGION_PART;
+ : else
+ : return PIXMAN_REGION_IN;
+ : }
+ : else
+ : {
+ : return PIXMAN_REGION_OUT;
+ : }
+ :}
+ :
+ :/* pixman_region_translate (region, x, y)
+ : translates in place
+ :*/
+ :
+ :void
+ :pixman_region_translate (pixman_region16_t * region, int x, int y)
+ 1 0.0011 :{ /* pixman_region_translate total: 7 0.0076 */
+ : int x1, x2, y1, y2;
+ : int nbox;
+ : pixman_box16_t * pbox;
+ :
+ : good(region);
+ : region->extents.x1 = x1 = region->extents.x1 + x;
+ 1 0.0011 : region->extents.y1 = y1 = region->extents.y1 + y;
+ : region->extents.x2 = x2 = region->extents.x2 + x;
+ 1 0.0011 : region->extents.y2 = y2 = region->extents.y2 + y;
+ 1 0.0011 : if (((x1 - SHRT_MIN)|(y1 - SHRT_MIN)|(SHRT_MAX - x2)|(SHRT_MAX - y2)) >= 0)
+ : {
+ 1 0.0011 : if (region->data && (nbox = region->data->numRects))
+ : {
+ : for (pbox = PIXREGION_BOXPTR(region); nbox--; pbox++)
+ : {
+ : pbox->x1 += x;
+ : pbox->y1 += y;
+ : pbox->x2 += x;
+ : pbox->y2 += y;
+ : }
+ : }
+ : return;
+ : }
+ : if (((x2 - SHRT_MIN)|(y2 - SHRT_MIN)|(SHRT_MAX - x1)|(SHRT_MAX - y1)) <= 0)
+ : {
+ : region->extents.x2 = region->extents.x1;
+ : region->extents.y2 = region->extents.y1;
+ : freeData(region);
+ : region->data = pixman_region_emptyData;
+ : return;
+ : }
+ : if (x1 < SHRT_MIN)
+ : region->extents.x1 = SHRT_MIN;
+ : else if (x2 > SHRT_MAX)
+ : region->extents.x2 = SHRT_MAX;
+ : if (y1 < SHRT_MIN)
+ : region->extents.y1 = SHRT_MIN;
+ : else if (y2 > SHRT_MAX)
+ : region->extents.y2 = SHRT_MAX;
+ : if (region->data && (nbox = region->data->numRects))
+ : {
+ : pixman_box16_t * pboxout;
+ :
+ : for (pboxout = pbox = PIXREGION_BOXPTR(region); nbox--; pbox++)
+ : {
+ : pboxout->x1 = x1 = pbox->x1 + x;
+ : pboxout->y1 = y1 = pbox->y1 + y;
+ : pboxout->x2 = x2 = pbox->x2 + x;
+ : pboxout->y2 = y2 = pbox->y2 + y;
+ : if (((x2 - SHRT_MIN)|(y2 - SHRT_MIN)|
+ : (SHRT_MAX - x1)|(SHRT_MAX - y1)) <= 0)
+ : {
+ : region->data->numRects--;
+ : continue;
+ : }
+ : if (x1 < SHRT_MIN)
+ : pboxout->x1 = SHRT_MIN;
+ : else if (x2 > SHRT_MAX)
+ : pboxout->x2 = SHRT_MAX;
+ : if (y1 < SHRT_MIN)
+ : pboxout->y1 = SHRT_MIN;
+ : else if (y2 > SHRT_MAX)
+ : pboxout->y2 = SHRT_MAX;
+ : pboxout++;
+ : }
+ : if (pboxout != pbox)
+ : {
+ : if (region->data->numRects == 1)
+ : {
+ : region->extents = *PIXREGION_BOXPTR(region);
+ : freeData(region);
+ : region->data = (pixman_region16_data_t *)NULL;
+ : }
+ : else
+ : pixman_set_extents(region);
+ : }
+ : }
+ 2 0.0022 :}
+ :
+ :/* XXX: Do we need this?
+ :static pixman_bool_t
+ :pixman_region16_data_copy(pixman_region16_t * dst, pixman_region16_t * src)
+ :{
+ : good(dst);
+ : good(src);
+ : if (dst->data)
+ : return TRUE;
+ : if (dst == src)
+ : return TRUE;
+ : if (!src->data || !src->data->size)
+ : {
+ : freeData(dst);
+ : dst->data = (pixman_region16_data_t *)NULL;
+ : return TRUE;
+ : }
+ : if (!dst->data || (dst->data->size < src->data->numRects))
+ : {
+ : freeData(dst);
+ : dst->data = allocData(src->data->numRects);
+ : if (!dst->data)
+ : return pixman_break (dst);
+ : }
+ : dst->data->size = src->data->size;
+ : dst->data->numRects = src->data->numRects;
+ : return TRUE;
+ :}
+ :*/
+ :
+ :void
+ :pixman_region_reset(pixman_region16_t *region, pixman_box16_t *box)
+ :{
+ : good(region);
+ : assert(box->x1<=box->x2);
+ : assert(box->y1<=box->y2);
+ : region->extents = *box;
+ : freeData(region);
+ : region->data = (pixman_region16_data_t *)NULL;
+ :}
+ :
+ :/* box is "return" value */
+ :int
+ :pixman_region_contains_point(pixman_region16_t * region,
+ : int x, int y,
+ : pixman_box16_t * box)
+ :{
+ : pixman_box16_t *pbox, *pboxEnd;
+ : int numRects;
+ :
+ : good(region);
+ : numRects = PIXREGION_NUM_RECTS(region);
+ : if (!numRects || !INBOX(®ion->extents, x, y))
+ : return(FALSE);
+ : if (numRects == 1)
+ : {
+ : *box = region->extents;
+ : return(TRUE);
+ : }
+ : for (pbox = PIXREGION_BOXPTR(region), pboxEnd = pbox + numRects;
+ : pbox != pboxEnd;
+ : pbox++)
+ : {
+ : if (y >= pbox->y2)
+ : continue; /* not there yet */
+ : if ((y < pbox->y1) || (x < pbox->x1))
+ : break; /* missed it */
+ : if (x >= pbox->x2)
+ : continue; /* not there yet */
+ : *box = *pbox;
+ : return(TRUE);
+ : }
+ : return(FALSE);
+ :}
+ :
+ :int
+ :pixman_region_not_empty(pixman_region16_t * region)
+ 9 0.0098 :{ /* pixman_region_not_empty total: 17 0.0185 */
+ : good(region);
+ 5 0.0054 : return(!PIXREGION_NIL(region));
+ 3 0.0033 :}
+ :
+ :/* XXX: Do we need this?
+ :static int
+ :pixman_region16_broken(pixman_region16_t * region)
+ :{
+ : good(region);
+ : return (PIXREGION_NAR(region));
+ :}
+ :*/
+ :
+ :void
+ :pixman_region_empty(pixman_region16_t * region)
+ :{
+ : good(region);
+ : freeData(region);
+ : region->extents.x2 = region->extents.x1;
+ : region->extents.y2 = region->extents.y1;
+ : region->data = pixman_region_emptyData;
+ :}
+ :
+ :pixman_box16_t *
+ :pixman_region_extents(pixman_region16_t * region)
+ :{
+ : good(region);
+ : return(®ion->extents);
+ :}
+ :
+ :#define ExchangeSpans(a, b) \
+ :{ \
+ : pixman_region16_point_t tpt; \
+ : int tw; \
+ : \
+ : tpt = spans[a]; spans[a] = spans[b]; spans[b] = tpt; \
+ : tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \
+ :}
+ :
+ :/* ||| I should apply the merge sort code to rectangle sorting above, and see
+ : if mapping time can be improved. But right now I've been at work 12 hours,
+ : so forget it.
+ :*/
+ :
+ :static void QuickSortSpans(
+ : pixman_region16_point_t spans[],
+ : int widths[],
+ : int numSpans)
+ :{
+ : int y;
+ : int i, j, m;
+ : pixman_region16_point_t *r;
+ :
+ : /* Always called with numSpans > 1 */
+ : /* Sorts only by y, doesn't bother to sort by x */
+ :
+ : do
+ : {
+ : if (numSpans < 9)
+ : {
+ : /* Do insertion sort */
+ : int yprev;
+ :
+ : yprev = spans[0].y;
+ : i = 1;
+ : do
+ : { /* while i != numSpans */
+ : y = spans[i].y;
+ : if (yprev > y)
+ : {
+ : /* spans[i] is out of order. Move into proper location. */
+ : pixman_region16_point_t tpt;
+ : int tw, k;
+ :
+ : for (j = 0; y >= spans[j].y; j++) {}
+ : tpt = spans[i];
+ : tw = widths[i];
+ : for (k = i; k != j; k--)
+ : {
+ : spans[k] = spans[k-1];
+ : widths[k] = widths[k-1];
+ : }
+ : spans[j] = tpt;
+ : widths[j] = tw;
+ : y = spans[i].y;
+ : } /* if out of order */
+ : yprev = y;
+ : i++;
+ : } while (i != numSpans);
+ : return;
+ : }
+ :
+ : /* Choose partition element, stick in location 0 */
+ : m = numSpans / 2;
+ : if (spans[m].y > spans[0].y) ExchangeSpans(m, 0);
+ : if (spans[m].y > spans[numSpans-1].y) ExchangeSpans(m, numSpans-1);
+ : if (spans[m].y > spans[0].y) ExchangeSpans(m, 0);
+ : y = spans[0].y;
+ :
+ : /* Partition array */
+ : i = 0;
+ : j = numSpans;
+ : do
+ : {
+ : r = &(spans[i]);
+ : do
+ : {
+ : r++;
+ : i++;
+ : } while (i != numSpans && r->y < y);
+ : r = &(spans[j]);
+ : do
+ : {
+ : r--;
+ : j--;
+ : } while (y < r->y);
+ : if (i < j)
+ : ExchangeSpans(i, j);
+ : } while (i < j);
+ :
+ : /* Move partition element back to middle */
+ : ExchangeSpans(0, j);
+ :
+ : /* Recurse */
+ : if (numSpans-j-1 > 1)
+ : QuickSortSpans(&spans[j+1], &widths[j+1], numSpans-j-1);
+ : numSpans = j;
+ : } while (numSpans > 1);
+ :}
+ :
+ :#define NextBand() \
+ :{ \
+ : clipy1 = pboxBandStart->y1; \
+ : clipy2 = pboxBandStart->y2; \
+ : pboxBandEnd = pboxBandStart + 1; \
+ : while (pboxBandEnd != pboxLast && pboxBandEnd->y1 == clipy1) { \
+ : pboxBandEnd++; \
+ : } \
+ : for (; ppt != pptLast && ppt->y < clipy1; ppt++, pwidth++) {} \
+ :}
+ :
+ :/*
+ : Clip a list of scanlines to a region. The caller has allocated the
+ : space. FSorted is non-zero if the scanline origins are in ascending
+ : order.
+ : returns the number of new, clipped scanlines.
+ :*/
+ :
+ :#ifdef XXX_DO_WE_NEED_THIS
+ :static int
+ :pixman_region16_clip_spans(
+ : pixman_region16_t *prgnDst,
+ : pixman_region16_point_t *ppt,
+ : int *pwidth,
+ : int nspans,
+ : pixman_region16_point_t *pptNew,
+ : int *pwidthNew,
+ : int fSorted)
+ :{
+ : pixman_region16_point_t *pptLast;
+ : int *pwidthNewStart; /* the vengeance of Xerox! */
+ : int y, x1, x2;
+ : int numRects;
+ :
+ : good(prgnDst);
+ : pptLast = ppt + nspans;
+ : pwidthNewStart = pwidthNew;
+ :
+ : if (!prgnDst->data)
+ : {
+ : /* Do special fast code with clip boundaries in registers(?) */
+ : /* It doesn't pay much to make use of fSorted in this case,
+ : so we lump everything together. */
+ :
+ : int clipx1, clipx2, clipy1, clipy2;
+ :
+ : clipx1 = prgnDst->extents.x1;
+ : clipy1 = prgnDst->extents.y1;
+ : clipx2 = prgnDst->extents.x2;
+ : clipy2 = prgnDst->extents.y2;
+ :
+ : for (; ppt != pptLast; ppt++, pwidth++)
+ : {
+ : y = ppt->y;
+ : x1 = ppt->x;
+ : if (clipy1 <= y && y < clipy2)
+ : {
+ : x2 = x1 + *pwidth;
+ : if (x1 < clipx1) x1 = clipx1;
+ : if (x2 > clipx2) x2 = clipx2;
+ : if (x1 < x2)
+ : {
+ : /* part of span in clip rectangle */
+ : pptNew->x = x1;
+ : pptNew->y = y;
+ : *pwidthNew = x2 - x1;
+ : pptNew++;
+ : pwidthNew++;
+ : }
+ : }
+ : } /* end for */
+ :
+ : }
+ : else if ((numRects = prgnDst->data->numRects))
+ : {
+ : /* Have to clip against many boxes */
+ : pixman_box16_t *pboxBandStart, *pboxBandEnd;
+ : pixman_box16_t *pbox;
+ : pixman_box16_t *pboxLast;
+ : int clipy1, clipy2;
+ :
+ : /* In this case, taking advantage of sorted spans gains more than
+ : the sorting costs. */
+ : if ((! fSorted) && (nspans > 1))
+ : QuickSortSpans(ppt, pwidth, nspans);
+ :
+ : pboxBandStart = PIXREGION_BOXPTR(prgnDst);
+ : pboxLast = pboxBandStart + numRects;
+ :
+ : NextBand();
+ :
+ : for (; ppt != pptLast; )
+ : {
+ : y = ppt->y;
+ : if (y < clipy2)
+ : {
+ : /* span is in the current band */
+ : pbox = pboxBandStart;
+ : x1 = ppt->x;
+ : x2 = x1 + *pwidth;
+ : do
+ : { /* For each box in band */
+ : int newx1, newx2;
+ :
+ : newx1 = x1;
+ : newx2 = x2;
+ : if (newx1 < pbox->x1) newx1 = pbox->x1;
+ : if (newx2 > pbox->x2) newx2 = pbox->x2;
+ : if (newx1 < newx2)
+ : {
+ : /* Part of span in clip rectangle */
+ : pptNew->x = newx1;
+ : pptNew->y = y;
+ : *pwidthNew = newx2 - newx1;
+ : pptNew++;
+ : pwidthNew++;
+ : }
+ : pbox++;
+ : } while (pbox != pboxBandEnd);
+ : ppt++;
+ : pwidth++;
+ : }
+ : else
+ : {
+ : /* Move to next band, adjust ppt as needed */
+ : pboxBandStart = pboxBandEnd;
+ : if (pboxBandStart == pboxLast)
+ : break; /* We're completely done */
+ : NextBand();
+ : }
+ : }
+ : }
+ : return (pwidthNew - pwidthNewStart);
+ :}
+ :
+ :/* find the band in a region with the most rectangles */
+ :static int
+ :pixman_region16_find_max_band(pixman_region16_t * prgn)
+ :{
+ : int nbox;
+ : pixman_box16_t * pbox;
+ : int nThisBand;
+ : int nMaxBand = 0;
+ : short yThisBand;
+ :
+ : good(prgn);
+ : nbox = PIXREGION_NUM_RECTS(prgn);
+ : pbox = PIXREGION_RECTS(prgn);
+ :
+ : while(nbox > 0)
+ : {
+ : yThisBand = pbox->y1;
+ : nThisBand = 0;
+ : while((nbox > 0) && (pbox->y1 == yThisBand))
+ : {
+ : nbox--;
+ : pbox++;
+ : nThisBand++;
+ : }
+ : if (nThisBand > nMaxBand)
+ : nMaxBand = nThisBand;
+ : }
+ : return (nMaxBand);
+ :}
+ :#endif /* XXX_DO_WE_NEED_THIS */
+ :
+ :
+ :pixman_bool_t
+ :pixman_region_selfcheck (reg)
+ : pixman_region16_t * reg;
+ :{
+ : int i, numRects;
+ :
+ : if ((reg->extents.x1 > reg->extents.x2) ||
+ : (reg->extents.y1 > reg->extents.y2))
+ : return FALSE;
+ : numRects = PIXREGION_NUM_RECTS(reg);
+ : if (!numRects)
+ : return ((reg->extents.x1 == reg->extents.x2) &&
+ : (reg->extents.y1 == reg->extents.y2) &&
+ : (reg->data->size || (reg->data == pixman_region_emptyData)));
+ : else if (numRects == 1)
+ : return (!reg->data);
+ : else
+ : {
+ : pixman_box16_t * pboxP, * pboxN;
+ : pixman_box16_t box;
+ :
+ : pboxP = PIXREGION_RECTS(reg);
+ : box = *pboxP;
+ : box.y2 = pboxP[numRects-1].y2;
+ : pboxN = pboxP + 1;
+ : for (i = numRects; --i > 0; pboxP++, pboxN++)
+ : {
+ : if ((pboxN->x1 >= pboxN->x2) ||
+ : (pboxN->y1 >= pboxN->y2))
+ : return FALSE;
+ : if (pboxN->x1 < box.x1)
+ : box.x1 = pboxN->x1;
+ : if (pboxN->x2 > box.x2)
+ : box.x2 = pboxN->x2;
+ : if ((pboxN->y1 < pboxP->y1) ||
+ : ((pboxN->y1 == pboxP->y1) &&
+ : ((pboxN->x1 < pboxP->x2) || (pboxN->y2 != pboxP->y2))))
+ : return FALSE;
+ : }
+ : return ((box.x1 == reg->extents.x1) &&
+ : (box.x2 == reg->extents.x2) &&
+ : (box.y1 == reg->extents.y1) &&
+ : (box.y2 == reg->extents.y2));
+ : }
+ :}
+ :
+ :pixman_bool_t
+ :pixman_region_init_rects (pixman_region16_t *region,
+ : pixman_box16_t *boxes, int count)
+ :{
+ : int overlap;
+ :
+ : if (count == 1) {
+ : pixman_region_init_rect(region,
+ : boxes[0].x1,
+ : boxes[0].y1,
+ : boxes[0].x2 - boxes[0].x1,
+ : boxes[0].y2 - boxes[0].y1);
+ : return TRUE;
+ : }
+ :
+ : pixman_region_init(region);
+ : if (!pixman_rect_alloc(region, count))
+ : return FALSE;
+ :
+ : /* Copy in the rects */
+ : memcpy (PIXREGION_RECTS(region), boxes, sizeof(pixman_box16_t) * count);
+ : region->data->numRects = count;
+ :
+ : /* Validate */
+ : region->extents.x1 = region->extents.x2 = 0;
+ : return pixman_region_validate (region, &overlap);
+ :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/exa/exa_migration.c"
+ *
+ * 335 0.3649
+ */
+
+
+ :/*
+ : * Copyright © 2006 Intel Corporation
+ : *
+ : * Permission is hereby granted, free of charge, to any person obtaining a
+ : * copy of this software and associated documentation files (the "Software"),
+ : * to deal in the Software without restriction, including without limitation
+ : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ : * and/or sell copies of the Software, and to permit persons to whom the
+ : * Software is furnished to do so, subject to the following conditions:
+ : *
+ : * The above copyright notice and this permission notice (including the next
+ : * paragraph) shall be included in all copies or substantial portions of the
+ : * Software.
+ : *
+ : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ : * SOFTWARE.
+ : *
+ : * Authors:
+ : * Eric Anholt <eric@anholt.net>
+ : * Michel Dänzer <michel@tungstengraphics.com>
+ : *
+ : */
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include <string.h>
+ :
+ :#include "exa_priv.h"
+ :#include <X11/fonts/fontstruct.h>
+ :#include "dixfontstr.h"
+ :#include "exa.h"
+ :#include "cw.h"
+ :
+ :#if DEBUG_MIGRATE
+ :#define DBG_MIGRATE(a) ErrorF a
+ :#else
+ :#define DBG_MIGRATE(a)
+ :#endif
+ :
+ :/**
+ : * Returns TRUE if the pixmap is not movable. This is the case where it's a
+ : * fake pixmap for the frontbuffer (no pixmap private) or it's a scratch
+ : * pixmap created by some other X Server internals (the score says it's
+ : * pinned).
+ : */
+ :static Bool
+ :exaPixmapIsPinned (PixmapPtr pPix)
+ 11 0.0120 :{ /* exaPixmapIsPinned total: 45 0.0490 */
+ 7 0.0076 : ExaPixmapPriv (pPix);
+ :
+ 25 0.0272 : return pExaPixmap == NULL || pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED;
+ 2 0.0022 :}
+ :
+ :/**
+ : * The fallback path for UTS/DFS failing is to just memcpy. exaCopyDirtyToSys
+ : * and exaCopyDirtyToFb both needed to do this loop.
+ : */
+ :static void
+ :exaMemcpyBox (PixmapPtr pPixmap, BoxPtr pbox, CARD8 *src, int src_pitch,
+ : CARD8 *dst, int dst_pitch)
+ : {
+ : int i, cpp = pPixmap->drawable.bitsPerPixel / 8;
+ : int bytes = (pbox->x2 - pbox->x1) * cpp;
+ :
+ : src += pbox->y1 * src_pitch + pbox->x1 * cpp;
+ : dst += pbox->y1 * dst_pitch + pbox->x1 * cpp;
+ :
+ : for (i = pbox->y2 - pbox->y1; i; i--) {
+ : memcpy (dst, src, bytes);
+ : src += src_pitch;
+ : dst += dst_pitch;
+ : }
+ :}
+ :
+ :/**
+ : * Returns TRUE if the pixmap is dirty (has been modified in its current
+ : * location compared to the other), or lacks a private for tracking
+ : * dirtiness.
+ : */
+ :static Bool
+ :exaPixmapIsDirty (PixmapPtr pPix)
+ :{
+ : ExaPixmapPriv (pPix);
+ :
+ : return pExaPixmap == NULL ||
+ : REGION_NOTEMPTY (pScreen, DamageRegion(pExaPixmap->pDamage));
+ :}
+ :
+ :/**
+ : * Returns TRUE if the pixmap is either pinned in FB, or has a sufficient score
+ : * to be considered "should be in framebuffer". That's just anything that has
+ : * had more acceleration than fallbacks, or has no score yet.
+ : *
+ : * Only valid if using a migration scheme that tracks score.
+ : */
+ :static Bool
+ :exaPixmapShouldBeInFB (PixmapPtr pPix)
+ :{
+ : ExaPixmapPriv (pPix);
+ :
+ : if (exaPixmapIsPinned (pPix))
+ : return TRUE;
+ :
+ : return pExaPixmap->score >= 0;
+ :}
+ :
+ :/**
+ : * If the pixmap is currently dirty, this copies at least the dirty area from
+ : * the framebuffer memory copy to the system memory copy. Both areas must be
+ : * allocated.
+ : */
+ :static void
+ :exaCopyDirtyToSys (PixmapPtr pPixmap)
+ :{
+ : ExaScreenPriv (pPixmap->drawable.pScreen);
+ : ExaPixmapPriv (pPixmap);
+ : RegionPtr pRegion = DamageRegion (pExaPixmap->pDamage);
+ : CARD8 *save_ptr;
+ : int save_pitch;
+ : BoxPtr pBox = REGION_RECTS(pRegion);
+ : int nbox = REGION_NUM_RECTS(pRegion);
+ : Bool do_sync = FALSE;
+ :
+ : save_ptr = pPixmap->devPrivate.ptr;
+ : save_pitch = pPixmap->devKind;
+ : pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
+ : pPixmap->devKind = pExaPixmap->fb_pitch;
+ :
+ : while (nbox--) {
+ : pBox->x1 = max(pBox->x1, 0);
+ : pBox->y1 = max(pBox->y1, 0);
+ : pBox->x2 = min(pBox->x2, pPixmap->drawable.width);
+ : pBox->y2 = min(pBox->y2, pPixmap->drawable.height);
+ :
+ : if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2)
+ : continue;
+ :
+ : if (pExaScr->info->DownloadFromScreen == NULL ||
+ : !pExaScr->info->DownloadFromScreen (pPixmap,
+ : pBox->x1, pBox->y1,
+ : pBox->x2 - pBox->x1,
+ : pBox->y2 - pBox->y1,
+ : pExaPixmap->sys_ptr
+ : + pBox->y1 * pExaPixmap->sys_pitch
+ : + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8,
+ : pExaPixmap->sys_pitch))
+ : {
+ : exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
+ : exaMemcpyBox (pPixmap, pBox,
+ : pExaPixmap->fb_ptr, pExaPixmap->fb_pitch,
+ : pExaPixmap->sys_ptr, pExaPixmap->sys_pitch);
+ : exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
+ : }
+ : else
+ : do_sync = TRUE;
+ :
+ : pBox++;
+ : }
+ :
+ : /* Make sure the bits have actually landed, since we don't necessarily sync
+ : * when accessing pixmaps in system memory.
+ : */
+ : if (do_sync)
+ : exaWaitSync (pPixmap->drawable.pScreen);
+ :
+ : pPixmap->devPrivate.ptr = save_ptr;
+ : pPixmap->devKind = save_pitch;
+ :
+ : /* The previously damaged bits are now no longer damaged but valid */
+ : REGION_UNION(pPixmap->drawable.pScreen,
+ : &pExaPixmap->validReg, &pExaPixmap->validReg, pRegion);
+ : DamageEmpty (pExaPixmap->pDamage);
+ :}
+ :
+ :/**
+ : * If the pixmap is currently dirty, this copies at least the dirty area from
+ : * the system memory copy to the framebuffer memory copy. Both areas must be
+ : * allocated.
+ : */
+ :static void
+ :exaCopyDirtyToFb (PixmapPtr pPixmap)
+ :{
+ : ExaScreenPriv (pPixmap->drawable.pScreen);
+ : ExaPixmapPriv (pPixmap);
+ : RegionPtr pRegion = DamageRegion (pExaPixmap->pDamage);
+ : CARD8 *save_ptr;
+ : int save_pitch;
+ : BoxPtr pBox = REGION_RECTS(pRegion);
+ : int nbox = REGION_NUM_RECTS(pRegion);
+ : Bool do_sync = FALSE;
+ :
+ : save_ptr = pPixmap->devPrivate.ptr;
+ : save_pitch = pPixmap->devKind;
+ : pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
+ : pPixmap->devKind = pExaPixmap->fb_pitch;
+ :
+ : while (nbox--) {
+ : pBox->x1 = max(pBox->x1, 0);
+ : pBox->y1 = max(pBox->y1, 0);
+ : pBox->x2 = min(pBox->x2, pPixmap->drawable.width);
+ : pBox->y2 = min(pBox->y2, pPixmap->drawable.height);
+ :
+ : if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2)
+ : continue;
+ :
+ : if (pExaScr->info->UploadToScreen == NULL ||
+ : !pExaScr->info->UploadToScreen (pPixmap,
+ : pBox->x1, pBox->y1,
+ : pBox->x2 - pBox->x1,
+ : pBox->y2 - pBox->y1,
+ : pExaPixmap->sys_ptr
+ : + pBox->y1 * pExaPixmap->sys_pitch
+ : + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8,
+ : pExaPixmap->sys_pitch))
+ : {
+ : exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_DEST);
+ : exaMemcpyBox (pPixmap, pBox,
+ : pExaPixmap->sys_ptr, pExaPixmap->sys_pitch,
+ : pExaPixmap->fb_ptr, pExaPixmap->fb_pitch);
+ : exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_DEST);
+ : }
+ : else
+ : do_sync = TRUE;
+ :
+ : pBox++;
+ : }
+ :
+ : if (do_sync)
+ : exaMarkSync (pPixmap->drawable.pScreen);
+ :
+ : pPixmap->devPrivate.ptr = save_ptr;
+ : pPixmap->devKind = save_pitch;
+ :
+ : /* The previously damaged bits are now no longer damaged but valid */
+ : REGION_UNION(pPixmap->drawable.pScreen,
+ : &pExaPixmap->validReg, &pExaPixmap->validReg, pRegion);
+ : DamageEmpty (pExaPixmap->pDamage);
+ :}
+ :
+ :/**
+ : * Copies out important pixmap data and removes references to framebuffer area.
+ : * Called when the memory manager decides it's time to kick the pixmap out of
+ : * framebuffer entirely.
+ : */
+ :void
+ :exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area)
+ :{
+ : PixmapPtr pPixmap = area->privData;
+ : ExaPixmapPriv(pPixmap);
+ : RegionPtr pDamageReg = DamageRegion(pExaPixmap->pDamage);
+ :
+ : DBG_MIGRATE (("Save %p (%p) (%dx%d) (%c)\n", pPixmap,
+ : (void*)(ExaGetPixmapPriv(pPixmap)->area ?
+ : ExaGetPixmapPriv(pPixmap)->area->offset : 0),
+ : pPixmap->drawable.width,
+ : pPixmap->drawable.height,
+ : exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
+ :
+ : if (exaPixmapIsOffscreen(pPixmap)) {
+ : exaCopyDirtyToSys (pPixmap);
+ : pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
+ : pPixmap->devKind = pExaPixmap->sys_pitch;
+ : pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ : }
+ :
+ : pExaPixmap->fb_ptr = NULL;
+ : pExaPixmap->area = NULL;
+ :
+ : /* Mark all valid bits as damaged, so they'll get copied to FB next time */
+ : REGION_UNION(pPixmap->drawable.pScreen, pDamageReg, pDamageReg,
+ : &pExaPixmap->validReg);
+ :}
+ :
+ :/**
+ : * Allocates a framebuffer copy of the pixmap if necessary, and then copies
+ : * any necessary pixmap data into the framebuffer copy and points the pixmap at
+ : * it.
+ : *
+ : * Note that when first allocated, a pixmap will have FALSE dirty flag.
+ : * This is intentional because pixmap data starts out undefined. So if we move
+ : * it in due to the first operation against it being accelerated, it will have
+ : * undefined framebuffer contents that we didn't have to upload. If we do
+ : * moveouts (and moveins) after the first movein, then we will only have to copy
+ : * back and forth if the pixmap was written to after the last synchronization of
+ : * the two copies. Then, at exaPixmapSave (when the framebuffer copy goes away)
+ : * we mark the pixmap dirty, so that the next exaMoveInPixmap will actually move
+ : * all the data, since it's almost surely all valid now.
+ : */
+ :void
+ :exaMoveInPixmap (PixmapPtr pPixmap)
+ 30 0.0327 :{ /* exaMoveInPixmap total: 133 0.1449 */
+ 4 0.0044 : ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ 23 0.0251 : ExaScreenPriv (pScreen);
+ 23 0.0251 : ExaPixmapPriv (pPixmap);
+ :
+ : /* If we're VT-switched away, no touching card memory allowed. */
+ 16 0.0174 : if (pExaScr->swappedOut)
+ : return;
+ :
+ : /* If we're already in FB, our work is done. */
+ 12 0.0131 : if (exaPixmapIsOffscreen(pPixmap))
+ : return;
+ :
+ : /* If we're not allowed to move, then fail. */
+ : if (exaPixmapIsPinned(pPixmap))
+ : return;
+ :
+ : /* Don't migrate in pixmaps which are less than 8bpp. This avoids a lot of
+ : * fragility in EXA, and <8bpp is probably not used enough any more to care
+ : * (at least, not in acceleratd paths).
+ : */
+ 1 0.0011 : if (pPixmap->drawable.bitsPerPixel < 8)
+ : return;
+ :
+ : if (pExaPixmap->area == NULL) {
+ 2 0.0022 : pExaPixmap->area =
+ : exaOffscreenAlloc (pScreen, pExaPixmap->fb_size,
+ : pExaScr->info->pixmapOffsetAlign, FALSE,
+ : exaPixmapSave, (pointer) pPixmap);
+ : if (pExaPixmap->area == NULL)
+ : return;
+ :
+ : pExaPixmap->fb_ptr = (CARD8 *) pExaScr->info->memoryBase +
+ : pExaPixmap->area->offset;
+ : }
+ :
+ : DBG_MIGRATE (("-> %p (0x%x) (%dx%d) (%c)\n", pPixmap,
+ : (ExaGetPixmapPriv(pPixmap)->area ?
+ : ExaGetPixmapPriv(pPixmap)->area->offset : 0),
+ : pPixmap->drawable.width,
+ : pPixmap->drawable.height,
+ : exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
+ :
+ : exaCopyDirtyToFb (pPixmap);
+ :
+ : if (pExaScr->hideOffscreenPixmapData)
+ : pPixmap->devPrivate.ptr = NULL;
+ : else
+ 1 0.0011 : pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
+ 1 0.0011 : pPixmap->devKind = pExaPixmap->fb_pitch;
+ 2 0.0022 : pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ 9 0.0098 :}
+ :
+ :/**
+ : * Switches the current active location of the pixmap to system memory, copying
+ : * updated data out if necessary.
+ : */
+ :void
+ :exaMoveOutPixmap (PixmapPtr pPixmap)
+ :{
+ : ExaPixmapPriv (pPixmap);
+ :
+ : if (exaPixmapIsPinned(pPixmap))
+ : return;
+ :
+ : if (exaPixmapIsOffscreen(pPixmap)) {
+ :
+ : DBG_MIGRATE (("<- %p (%p) (%dx%d) (%c)\n", pPixmap,
+ : (void*)(ExaGetPixmapPriv(pPixmap)->area ?
+ : ExaGetPixmapPriv(pPixmap)->area->offset : 0),
+ : pPixmap->drawable.width,
+ : pPixmap->drawable.height,
+ : exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
+ :
+ : exaCopyDirtyToSys (pPixmap);
+ :
+ : pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
+ : pPixmap->devKind = pExaPixmap->sys_pitch;
+ : pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ : }
+ :}
+ :
+ :/**
+ : * For the "greedy" migration scheme, pushes the pixmap toward being located in
+ : * framebuffer memory.
+ : */
+ :static void
+ :exaMigrateTowardFb (PixmapPtr pPixmap)
+ :{
+ : ExaPixmapPriv (pPixmap);
+ :
+ : if (pExaPixmap == NULL) {
+ : DBG_MIGRATE(("UseScreen: ignoring exa-uncontrolled pixmap %p (%s)\n",
+ : (pointer)pPixmap,
+ : exaPixmapIsOffscreen(pPixmap) ? "s" : "m"));
+ : return;
+ : }
+ :
+ : if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) {
+ : DBG_MIGRATE(("UseScreen: not migrating pinned pixmap %p\n",
+ : (pointer)pPixmap));
+ : return;
+ : }
+ :
+ : DBG_MIGRATE(("UseScreen %p score %d\n",
+ : (pointer)pPixmap, pExaPixmap->score));
+ :
+ : if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) {
+ : exaMoveInPixmap(pPixmap);
+ : pExaPixmap->score = 0;
+ : }
+ :
+ : if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX)
+ : pExaPixmap->score++;
+ :
+ : if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN &&
+ : !exaPixmapIsOffscreen(pPixmap))
+ : {
+ : exaMoveInPixmap (pPixmap);
+ : }
+ :
+ : ExaOffscreenMarkUsed (pPixmap);
+ :}
+ :
+ :/**
+ : * For the "greedy" migration scheme, pushes the pixmap toward being located in
+ : * system memory.
+ : */
+ :static void
+ :exaMigrateTowardSys (PixmapPtr pPixmap)
+ :{
+ : ExaPixmapPriv (pPixmap);
+ :
+ : if (pExaPixmap == NULL) {
+ : DBG_MIGRATE(("UseMem: ignoring exa-uncontrolled pixmap %p (%s)\n",
+ : (pointer)pPixmap,
+ : exaPixmapIsOffscreen(pPixmap) ? "s" : "m"));
+ : return;
+ : }
+ :
+ : DBG_MIGRATE(("UseMem: %p score %d\n", (pointer)pPixmap, pExaPixmap->score));
+ :
+ : if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED)
+ : return;
+ :
+ : if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT)
+ : pExaPixmap->score = 0;
+ :
+ : if (pExaPixmap->score > EXA_PIXMAP_SCORE_MIN)
+ : pExaPixmap->score--;
+ :
+ : if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area)
+ : exaMoveOutPixmap (pPixmap);
+ :}
+ :
+ :/**
+ : * If the pixmap has both a framebuffer and system memory copy, this function
+ : * asserts that both of them are the same.
+ : */
+ :static Bool
+ :exaAssertNotDirty (PixmapPtr pPixmap)
+ :{
+ : ExaPixmapPriv (pPixmap);
+ : CARD8 *dst, *src;
+ : RegionPtr pValidReg = &pExaPixmap->validReg;
+ : int dst_pitch, src_pitch, cpp, y, nbox = REGION_NUM_RECTS(pValidReg);
+ : BoxPtr pBox = REGION_RECTS(pValidReg);
+ : Bool ret = TRUE;
+ :
+ : if (!nbox || exaPixmapIsPinned(pPixmap) || pExaPixmap->fb_ptr == NULL)
+ : return ret;
+ :
+ : dst_pitch = pExaPixmap->sys_pitch;
+ : src_pitch = pExaPixmap->fb_pitch;
+ : cpp = pPixmap->drawable.bitsPerPixel / 8;
+ :
+ : exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
+ : while (nbox--) {
+ : int rowbytes;
+ :
+ : pBox->x1 = max(pBox->x1, 0);
+ : pBox->y1 = max(pBox->y1, 0);
+ : pBox->x2 = min(pBox->x2, pPixmap->drawable.width);
+ : pBox->y2 = min(pBox->y2, pPixmap->drawable.height);
+ :
+ : if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2)
+ : continue;
+ :
+ : rowbytes = (pBox->x2 - pBox->x1) * cpp;
+ : src = pExaPixmap->fb_ptr + pBox->y1 * src_pitch + pBox->x1 * cpp;
+ : dst = pExaPixmap->sys_ptr + pBox->y1 * dst_pitch + pBox->x1 * cpp;
+ :
+ : for (y = pBox->y1; y < pBox->y2;
+ : y++, src += src_pitch, dst += dst_pitch) {
+ : if (memcmp(dst, src, rowbytes) != 0) {
+ : ret = FALSE;
+ : exaPixmapDirty(pPixmap, pBox->x1, pBox->y1, pBox->x2,
+ : pBox->y2);
+ : break;
+ : }
+ : }
+ : }
+ : exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
+ :
+ : return ret;
+ :}
+ :
+ :/**
+ : * Performs migration of the pixmaps according to the operation information
+ : * provided in pixmaps and can_accel and the migration scheme chosen in the
+ : * config file.
+ : */
+ :void
+ :exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
+ 12 0.0131 :{ /* exaDoMigration total: 166 0.1808 */
+ : ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen;
+ 17 0.0185 : ExaScreenPriv(pScreen);
+ : int i, j;
+ :
+ 3 0.0033 : if (! can_accel)
+ : return;
+ :
+ : /* If this debugging flag is set, check each pixmap for whether it is marked
+ : * as clean, and if so, actually check if that's the case. This should help
+ : * catch issues with failing to mark a drawable as dirty. While it will
+ : * catch them late (after the operation happened), it at least explains what
+ : * went wrong, and instrumenting the code to find what operation happened
+ : * to the pixmap last shouldn't be hard.
+ : */
+ 9 0.0098 : if (pExaScr->checkDirtyCorrectness) {
+ 1 0.0011 : for (i = 0; i < npixmaps; i++) {
+ : if (!exaPixmapIsDirty (pixmaps[i].pPix) &&
+ : !exaAssertNotDirty (pixmaps[i].pPix))
+ : ErrorF("%s: Pixmap %d dirty but not marked as such!\n", __func__, i);
+ : }
+ : }
+ : /* If anything is pinned in system memory, we won't be able to
+ : * accelerate.
+ : */
+ 16 0.0174 : for (i = 0; i < npixmaps; i++) {
+ 22 0.0240 : if (exaPixmapIsPinned (pixmaps[i].pPix) &&
+ : !exaPixmapIsOffscreen (pixmaps[i].pPix))
+ : {
+ : return;
+ : EXA_FALLBACK(("Pixmap %p (%dx%d) pinned in sys\n", pixmaps[i].pPix,
+ : pixmaps[i].pPix->drawable.width,
+ : pixmaps[i].pPix->drawable.height));
+ : can_accel = FALSE;
+ : break;
+ : }
+ : }
+ :
+ 2 0.0022 : if (pExaScr->migration == ExaMigrationSmart) {
+ : /* If we've got something as a destination that we shouldn't cause to
+ : * become newly dirtied, take the unaccelerated route.
+ : */
+ : for (i = 0; i < npixmaps; i++) {
+ : if (pixmaps[i].as_dst && !exaPixmapShouldBeInFB (pixmaps[i].pPix) &&
+ : !exaPixmapIsDirty (pixmaps[i].pPix))
+ : {
+ : for (i = 0; i < npixmaps; i++) {
+ : if (!exaPixmapIsDirty (pixmaps[i].pPix))
+ : exaMoveOutPixmap (pixmaps[i].pPix);
+ : }
+ : return;
+ : }
+ : }
+ :
+ : /* If we aren't going to accelerate, then we migrate everybody toward
+ : * system memory, and kick out if it's free.
+ : */
+ : if (!can_accel) {
+ : for (i = 0; i < npixmaps; i++) {
+ : exaMigrateTowardSys (pixmaps[i].pPix);
+ : if (!exaPixmapIsDirty (pixmaps[i].pPix))
+ : exaMoveOutPixmap (pixmaps[i].pPix);
+ : }
+ : return;
+ : }
+ :
+ : /* Finally, the acceleration path. Move them all in. */
+ : for (i = 0; i < npixmaps; i++) {
+ : exaMigrateTowardFb(pixmaps[i].pPix);
+ : exaMoveInPixmap(pixmaps[i].pPix);
+ : }
+ : } else if (pExaScr->migration == ExaMigrationGreedy) {
+ : /* If we can't accelerate, either because the driver can't or because one of
+ : * the pixmaps is pinned in system memory, then we migrate everybody toward
+ : * system memory.
+ : *
+ : * We also migrate toward system if all pixmaps involved are currently in
+ : * system memory -- this can mitigate thrashing when there are significantly
+ : * more pixmaps active than would fit in memory.
+ : *
+ : * If not, then we migrate toward FB so that hopefully acceleration can
+ : * happen.
+ : */
+ : if (!can_accel) {
+ : for (i = 0; i < npixmaps; i++)
+ : exaMigrateTowardSys (pixmaps[i].pPix);
+ : return;
+ : }
+ :
+ : for (i = 0; i < npixmaps; i++) {
+ : if (exaPixmapIsOffscreen(pixmaps[i].pPix)) {
+ : /* Found one in FB, so move all to FB. */
+ : for (j = 0; j < npixmaps; j++)
+ : exaMigrateTowardFb(pixmaps[j].pPix);
+ : return;
+ : }
+ : }
+ :
+ : /* Nobody's in FB, so move all away from FB. */
+ : for (i = 0; i < npixmaps; i++)
+ : exaMigrateTowardSys(pixmaps[i].pPix);
+ 3 0.0033 : } else if (pExaScr->migration == ExaMigrationAlways) {
+ : /* Always move the pixmaps out if we can't accelerate. If we can
+ : * accelerate, try to move them all in. If that fails, then move them
+ : * back out.
+ : */
+ : if (!can_accel) {
+ : for (i = 0; i < npixmaps; i++)
+ : exaMoveOutPixmap(pixmaps[i].pPix);
+ : return;
+ : }
+ :
+ : /* Now, try to move them all into FB */
+ 21 0.0229 : for (i = 0; i < npixmaps; i++) {
+ 18 0.0196 : exaMoveInPixmap(pixmaps[i].pPix);
+ 11 0.0120 : ExaOffscreenMarkUsed (pixmaps[i].pPix);
+ : }
+ :
+ : /* If we couldn't fit everything in, then kick back out */
+ 6 0.0065 : for (i = 0; i < npixmaps; i++) {
+ 17 0.0185 : if (!exaPixmapIsOffscreen(pixmaps[i].pPix)) {
+ : return;
+ : EXA_FALLBACK(("Pixmap %p (%dx%d) not in fb\n", pixmaps[i].pPix,
+ : pixmaps[i].pPix->drawable.width,
+ : pixmaps[i].pPix->drawable.height));
+ : for (j = 0; j < npixmaps; j++)
+ : exaMoveOutPixmap(pixmaps[j].pPix);
+ : break;
+ : }
+ : }
+ : }
+ 8 0.0087 :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/render/mipict.c"
+ *
+ * 267 0.2909
+ */
+
+
+ :/*
+ : *
+ : * Copyright © 1999 Keith Packard
+ : *
+ : * 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 Keith Packard not be used in
+ : * advertising or publicity pertaining to distribution of the software without
+ : * specific, written prior permission. Keith Packard makes no
+ : * representations about the suitability of this software for any purpose. It
+ : * is provided "as is" without express or implied warranty.
+ : *
+ : * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ : * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ : * EVENT SHALL KEITH PACKARD 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.
+ : */
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include "scrnintstr.h"
+ :#include "gcstruct.h"
+ :#include "pixmapstr.h"
+ :#include "windowstr.h"
+ :#include "mi.h"
+ :#include "picturestr.h"
+ :#include "mipict.h"
+ :
+ :#ifndef __GNUC__
+ :#define __inline
+ :#endif
+ :
+ :int
+ :miCreatePicture (PicturePtr pPicture)
+ 1 0.0011 :{ /* miCreatePicture total: 2 0.0022 */
+ : return Success;
+ 1 0.0011 :}
+ :
+ :void
+ :miDestroyPicture (PicturePtr pPicture)
+ 3 0.0033 :{ /* miDestroyPicture total: 4 0.0044 */
+ : if (pPicture->freeCompClip)
+ 1 0.0011 : REGION_DESTROY(pPicture->pDrawable->pScreen, pPicture->pCompositeClip);
+ :}
+ :
+ :void
+ :miDestroyPictureClip (PicturePtr pPicture)
+ :{
+ : switch (pPicture->clientClipType) {
+ : case CT_NONE:
+ : return;
+ : case CT_PIXMAP:
+ : (*pPicture->pDrawable->pScreen->DestroyPixmap) ((PixmapPtr) (pPicture->clientClip));
+ : break;
+ : default:
+ : /*
+ : * we know we'll never have a list of rectangles, since ChangeClip
+ : * immediately turns them into a region
+ : */
+ : REGION_DESTROY(pPicture->pDrawable->pScreen, pPicture->clientClip);
+ : break;
+ : }
+ : pPicture->clientClip = NULL;
+ : pPicture->clientClipType = CT_NONE;
+ :}
+ :
+ :int
+ :miChangePictureClip (PicturePtr pPicture,
+ : int type,
+ : pointer value,
+ : int n)
+ :{ /* miChangePictureClip total: 1 0.0011 */
+ : ScreenPtr pScreen = pPicture->pDrawable->pScreen;
+ 1 0.0011 : PictureScreenPtr ps = GetPictureScreen(pScreen);
+ : pointer clientClip;
+ : int clientClipType;
+ :
+ : switch (type) {
+ : case CT_PIXMAP:
+ : /* convert the pixmap to a region */
+ : clientClip = (pointer) BITMAP_TO_REGION(pScreen, (PixmapPtr) value);
+ : if (!clientClip)
+ : return BadAlloc;
+ : clientClipType = CT_REGION;
+ : (*pScreen->DestroyPixmap) ((PixmapPtr) value);
+ : break;
+ : case CT_REGION:
+ : clientClip = value;
+ : clientClipType = CT_REGION;
+ : break;
+ : case CT_NONE:
+ : clientClip = 0;
+ : clientClipType = CT_NONE;
+ : break;
+ : default:
+ : clientClip = (pointer) RECTS_TO_REGION(pScreen, n,
+ : (xRectangle *) value,
+ : type);
+ : if (!clientClip)
+ : return BadAlloc;
+ : clientClipType = CT_REGION;
+ : xfree(value);
+ : break;
+ : }
+ : (*ps->DestroyPictureClip) (pPicture);
+ : pPicture->clientClip = clientClip;
+ : pPicture->clientClipType = clientClipType;
+ : pPicture->stateChanges |= CPClipMask;
+ : return Success;
+ :}
+ :
+ :void
+ :miChangePicture (PicturePtr pPicture,
+ : Mask mask)
+ :{ /* miChangePicture total: 1 0.0011 */
+ : return;
+ 1 0.0011 :}
+ :
+ :void
+ :miValidatePicture (PicturePtr pPicture,
+ : Mask mask)
+ 3 0.0033 :{ /* miValidatePicture total: 9 0.0098 */
+ : DrawablePtr pDrawable = pPicture->pDrawable;
+ :
+ : if ((mask & (CPClipXOrigin|CPClipYOrigin|CPClipMask|CPSubwindowMode)) ||
+ : (pDrawable->serialNumber != (pPicture->serialNumber & DRAWABLE_SERIAL_BITS)))
+ : {
+ 1 0.0011 : if (pDrawable->type == DRAWABLE_WINDOW)
+ : {
+ : WindowPtr pWin = (WindowPtr) pDrawable;
+ : RegionPtr pregWin;
+ : Bool freeTmpClip, freeCompClip;
+ :
+ : if (pPicture->subWindowMode == IncludeInferiors)
+ : {
+ : pregWin = NotClippedByChildren(pWin);
+ : freeTmpClip = TRUE;
+ : }
+ : else
+ : {
+ : pregWin = &pWin->clipList;
+ : freeTmpClip = FALSE;
+ : }
+ : freeCompClip = pPicture->freeCompClip;
+ :
+ : /*
+ : * if there is no client clip, we can get by with just keeping the
+ : * pointer we got, and remembering whether or not should destroy
+ : * (or maybe re-use) it later. this way, we avoid unnecessary
+ : * copying of regions. (this wins especially if many clients clip
+ : * by children and have no client clip.)
+ : */
+ : if (pPicture->clientClipType == CT_NONE)
+ : {
+ : if (freeCompClip)
+ : REGION_DESTROY(pScreen, pPicture->pCompositeClip);
+ : pPicture->pCompositeClip = pregWin;
+ : pPicture->freeCompClip = freeTmpClip;
+ : }
+ : else
+ : {
+ : /*
+ : * we need one 'real' region to put into the composite clip. if
+ : * pregWin the current composite clip are real, we can get rid of
+ : * one. if pregWin is real and the current composite clip isn't,
+ : * use pregWin for the composite clip. if the current composite
+ : * clip is real and pregWin isn't, use the current composite
+ : * clip. if neither is real, create a new region.
+ : */
+ :
+ : REGION_TRANSLATE(pScreen, pPicture->clientClip,
+ : pDrawable->x + pPicture->clipOrigin.x,
+ : pDrawable->y + pPicture->clipOrigin.y);
+ :
+ : if (freeCompClip)
+ : {
+ : REGION_INTERSECT(pScreen, pPicture->pCompositeClip,
+ : pregWin, pPicture->clientClip);
+ : if (freeTmpClip)
+ : REGION_DESTROY(pScreen, pregWin);
+ : }
+ : else if (freeTmpClip)
+ : {
+ : REGION_INTERSECT(pScreen, pregWin, pregWin, pPicture->clientClip);
+ : pPicture->pCompositeClip = pregWin;
+ : }
+ : else
+ : {
+ : pPicture->pCompositeClip = REGION_CREATE(pScreen, NullBox, 0);
+ : REGION_INTERSECT(pScreen, pPicture->pCompositeClip,
+ : pregWin, pPicture->clientClip);
+ : }
+ : pPicture->freeCompClip = TRUE;
+ : REGION_TRANSLATE(pScreen, pPicture->clientClip,
+ : -(pDrawable->x + pPicture->clipOrigin.x),
+ : -(pDrawable->y + pPicture->clipOrigin.y));
+ : }
+ : } /* end of composite clip for a window */
+ : else
+ : {
+ : BoxRec pixbounds;
+ :
+ : /* XXX should we translate by drawable.x/y here ? */
+ : /* If you want pixmaps in offscreen memory, yes */
+ 1 0.0011 : pixbounds.x1 = pDrawable->x;
+ : pixbounds.y1 = pDrawable->y;
+ : pixbounds.x2 = pDrawable->x + pDrawable->width;
+ : pixbounds.y2 = pDrawable->y + pDrawable->height;
+ :
+ : if (pPicture->freeCompClip)
+ : {
+ : REGION_RESET(pScreen, pPicture->pCompositeClip, &pixbounds);
+ : }
+ : else
+ : {
+ : pPicture->freeCompClip = TRUE;
+ 3 0.0033 : pPicture->pCompositeClip = REGION_CREATE(pScreen, &pixbounds, 1);
+ : }
+ :
+ : if (pPicture->clientClipType == CT_REGION)
+ : {
+ : if(pDrawable->x || pDrawable->y) {
+ : REGION_TRANSLATE(pScreen, pPicture->clientClip,
+ : pDrawable->x + pPicture->clipOrigin.x,
+ : pDrawable->y + pPicture->clipOrigin.y);
+ : REGION_INTERSECT(pScreen, pPicture->pCompositeClip,
+ : pPicture->pCompositeClip, pPicture->clientClip);
+ : REGION_TRANSLATE(pScreen, pPicture->clientClip,
+ : -(pDrawable->x + pPicture->clipOrigin.x),
+ : -(pDrawable->y + pPicture->clipOrigin.y));
+ : } else {
+ : REGION_TRANSLATE(pScreen, pPicture->pCompositeClip,
+ : -pPicture->clipOrigin.x, -pPicture->clipOrigin.y);
+ : REGION_INTERSECT(pScreen, pPicture->pCompositeClip,
+ : pPicture->pCompositeClip, pPicture->clientClip);
+ : REGION_TRANSLATE(pScreen, pPicture->pCompositeClip,
+ : pPicture->clipOrigin.x, pPicture->clipOrigin.y);
+ : }
+ : }
+ : } /* end of composite clip for pixmap */
+ : }
+ 1 0.0011 :}
+ :
+ :int
+ :miChangePictureTransform (PicturePtr pPicture,
+ : PictTransform *transform)
+ 1 0.0011 :{ /* miChangePictureTransform total: 1 0.0011 */
+ : return Success;
+ :}
+ :
+ :int
+ :miChangePictureFilter (PicturePtr pPicture,
+ : int filter,
+ : xFixed *params,
+ : int nparams)
+ 1 0.0011 :{ /* miChangePictureFilter total: 1 0.0011 */
+ : return Success;
+ :}
+ :
+ :#define BOUND(v) (INT16) ((v) < MINSHORT ? MINSHORT : (v) > MAXSHORT ? MAXSHORT : (v))
+ :
+ :static inline pixman_bool_t
+ :miClipPictureReg (pixman_region16_t * pRegion,
+ : pixman_region16_t * pClip,
+ : int dx,
+ : int dy)
+ :{
+ : if (pixman_region_n_rects(pRegion) == 1 &&
+ : pixman_region_n_rects(pClip) == 1)
+ : {
+ : pixman_box16_t * pRbox = pixman_region_rectangles(pRegion, NULL);
+ : pixman_box16_t * pCbox = pixman_region_rectangles(pClip, NULL);
+ : int v;
+ :
+ : if (pRbox->x1 < (v = pCbox->x1 + dx))
+ : pRbox->x1 = BOUND(v);
+ : if (pRbox->x2 > (v = pCbox->x2 + dx))
+ : pRbox->x2 = BOUND(v);
+ : if (pRbox->y1 < (v = pCbox->y1 + dy))
+ : pRbox->y1 = BOUND(v);
+ : if (pRbox->y2 > (v = pCbox->y2 + dy))
+ : pRbox->y2 = BOUND(v);
+ : if (pRbox->x1 >= pRbox->x2 ||
+ : pRbox->y1 >= pRbox->y2)
+ : {
+ : pixman_region_init (pRegion);
+ : }
+ : }
+ : else if (!pixman_region_not_empty (pClip))
+ : return FALSE;
+ : else
+ : {
+ : if (dx || dy)
+ : pixman_region_translate (pRegion, -dx, -dy);
+ : if (!pixman_region_intersect (pRegion, pRegion, pClip))
+ : return FALSE;
+ : if (dx || dy)
+ : pixman_region_translate(pRegion, dx, dy);
+ : }
+ : return pixman_region_not_empty(pRegion);
+ :}
+ :
+ :static __inline Bool
+ :miClipPictureSrc (RegionPtr pRegion,
+ : PicturePtr pPicture,
+ : int dx,
+ : int dy)
+ :{
+ : /* XXX what to do with clipping from transformed pictures? */
+ : if (pPicture->transform || !pPicture->pDrawable)
+ : return TRUE;
+ : if (pPicture->repeat)
+ : {
+ : if (pPicture->clientClipType != CT_NONE)
+ : {
+ : pixman_region_translate ( pRegion,
+ : dx - pPicture->clipOrigin.x,
+ : dy - pPicture->clipOrigin.y);
+ : if (!REGION_INTERSECT (pScreen, pRegion, pRegion,
+ : (RegionPtr) pPicture->pCompositeClip)) // clientClip))
+ : return FALSE;
+ : pixman_region_translate ( pRegion,
+ : - (dx - pPicture->clipOrigin.x),
+ : - (dy - pPicture->clipOrigin.y));
+ : }
+ : return TRUE;
+ : }
+ : else
+ : {
+ : return miClipPictureReg (pRegion,
+ : pPicture->pCompositeClip,
+ : dx,
+ : dy);
+ : }
+ :}
+ :
+ :void
+ :miCompositeSourceValidate (PicturePtr pPicture,
+ : INT16 x,
+ : INT16 y,
+ : CARD16 width,
+ : CARD16 height)
+ 31 0.0338 :{ /* miCompositeSourceValidate total: 106 0.1155 */
+ 8 0.0087 : DrawablePtr pDrawable = pPicture->pDrawable;
+ : ScreenPtr pScreen;
+ :
+ 4 0.0044 : if (!pDrawable)
+ : return;
+ :
+ 11 0.0120 : pScreen = pDrawable->pScreen;
+ :
+ 18 0.0196 : if (pScreen->SourceValidate)
+ : {
+ : x -= pPicture->pDrawable->x;
+ 12 0.0131 : y -= pPicture->pDrawable->y;
+ 3 0.0033 : if (pPicture->transform)
+ : {
+ : xPoint points[4];
+ : int i;
+ : int xmin, ymin, xmax, ymax;
+ :
+ :#define VectorSet(i,_x,_y) { points[i].x = _x; points[i].y = _y; }
+ : VectorSet (0, x, y);
+ : VectorSet (1, x + width, y);
+ : VectorSet (2, x, y + height);
+ : VectorSet (3, x + width, y + height);
+ : xmin = ymin = 32767;
+ : xmax = ymax = -32737;
+ : for (i = 0; i < 4; i++)
+ : {
+ : PictVector t;
+ : t.vector[0] = IntToxFixed (points[i].x);
+ : t.vector[1] = IntToxFixed (points[i].y);
+ : t.vector[2] = xFixed1;
+ : if (PictureTransformPoint (pPicture->transform, &t))
+ : {
+ : int tx = xFixedToInt (t.vector[0]);
+ : int ty = xFixedToInt (t.vector[1]);
+ : if (tx < xmin) xmin = tx;
+ : if (tx > xmax) xmax = tx;
+ : if (ty < ymin) ymin = ty;
+ : if (ty > ymax) ymax = ty;
+ : }
+ : }
+ : x = xmin;
+ : y = ymin;
+ : width = xmax - xmin;
+ : height = ymax - ymin;
+ : }
+ 10 0.0109 : (*pScreen->SourceValidate) (pDrawable, x, y, width, height);
+ : }
+ 9 0.0098 :}
+ :
+ :/*
+ : * returns FALSE if the final region is empty. Indistinguishable from
+ : * an allocation failure, but rendering ignores those anyways.
+ : */
+ :
+ :_X_EXPORT Bool
+ :miComputeCompositeRegion (RegionPtr pRegion,
+ : PicturePtr pSrc,
+ : PicturePtr pMask,
+ : PicturePtr pDst,
+ : INT16 xSrc,
+ : INT16 ySrc,
+ : INT16 xMask,
+ : INT16 yMask,
+ : INT16 xDst,
+ : INT16 yDst,
+ : CARD16 width,
+ : CARD16 height)
+ 28 0.0305 :{ /* miComputeCompositeRegion total: 296 0.3225 */
+ :
+ : int v;
+ :
+ 2 0.0022 : pRegion->extents.x1 = xDst;
+ 9 0.0098 : v = xDst + width;
+ 10 0.0109 : pRegion->extents.x2 = BOUND(v);
+ : pRegion->extents.y1 = yDst;
+ 4 0.0044 : v = yDst + height;
+ 9 0.0098 : pRegion->extents.y2 = BOUND(v);
+ 2 0.0022 : pRegion->data = 0;
+ : /* Check for empty operation */
+ 8 0.0087 : if (pRegion->extents.x1 >= pRegion->extents.x2 ||
+ : pRegion->extents.y1 >= pRegion->extents.y2)
+ : {
+ 1 0.0011 : pixman_region_init (pRegion);
+ : return FALSE;
+ : }
+ : /* clip against dst */
+ 8 0.0087 : if (!miClipPictureReg (pRegion, pDst->pCompositeClip, 0, 0))
+ : {
+ : pixman_region_fini (pRegion);
+ : return FALSE;
+ : }
+ : if (pDst->alphaMap)
+ : {
+ : if (!miClipPictureReg (pRegion, pDst->alphaMap->pCompositeClip,
+ : -pDst->alphaOrigin.x,
+ : -pDst->alphaOrigin.y))
+ : {
+ : pixman_region_fini (pRegion);
+ : return FALSE;
+ : }
+ : }
+ : /* clip against src */
+ 10 0.0109 : if (!miClipPictureSrc (pRegion, pSrc, xDst - xSrc, yDst - ySrc))
+ : {
+ : pixman_region_fini (pRegion);
+ : return FALSE;
+ : }
+ 5 0.0054 : if (pSrc->alphaMap)
+ : {
+ : if (!miClipPictureSrc (pRegion, pSrc->alphaMap,
+ : xDst - (xSrc + pSrc->alphaOrigin.x),
+ : yDst - (ySrc + pSrc->alphaOrigin.y)))
+ : {
+ : pixman_region_fini (pRegion);
+ : return FALSE;
+ : }
+ : }
+ : /* clip against mask */
+ 5 0.0054 : if (pMask)
+ : {
+ 2 0.0022 : if (!miClipPictureSrc (pRegion, pMask, xDst - xMask, yDst - yMask))
+ : {
+ : pixman_region_fini (pRegion);
+ : return FALSE;
+ : }
+ 3 0.0033 : if (pMask->alphaMap)
+ : {
+ : if (!miClipPictureSrc (pRegion, pMask->alphaMap,
+ : xDst - (xMask + pMask->alphaOrigin.x),
+ : yDst - (yMask + pMask->alphaOrigin.y)))
+ : {
+ : pixman_region_fini (pRegion);
+ : return FALSE;
+ : }
+ : }
+ : }
+ :
+ :
+ 23 0.0251 : miCompositeSourceValidate (pSrc, xSrc, ySrc, width, height);
+ : if (pMask)
+ 7 0.0076 : miCompositeSourceValidate (pMask, xMask, yMask, width, height);
+ :
+ : return TRUE;
+ 1 0.0011 :}
+ :
+ :void
+ :miRenderColorToPixel (PictFormatPtr format,
+ : xRenderColor *color,
+ : CARD32 *pixel)
+ :{ /* miRenderColorToPixel total: 5 0.0054 */
+ : CARD32 r, g, b, a;
+ : miIndexedPtr pIndexed;
+ :
+ 1 0.0011 : switch (format->type) {
+ : case PictTypeDirect:
+ 1 0.0011 : r = color->red >> (16 - Ones (format->direct.redMask));
+ 1 0.0011 : g = color->green >> (16 - Ones (format->direct.greenMask));
+ : b = color->blue >> (16 - Ones (format->direct.blueMask));
+ : a = color->alpha >> (16 - Ones (format->direct.alphaMask));
+ : r = r << format->direct.red;
+ : g = g << format->direct.green;
+ : b = b << format->direct.blue;
+ : a = a << format->direct.alpha;
+ 2 0.0022 : *pixel = r|g|b|a;
+ : break;
+ : case PictTypeIndexed:
+ : pIndexed = (miIndexedPtr) (format->index.devPrivate);
+ : if (pIndexed->color)
+ : {
+ : r = color->red >> 11;
+ : g = color->green >> 11;
+ : b = color->blue >> 11;
+ : *pixel = miIndexToEnt15 (pIndexed, (r << 10) | (g << 5) | b);
+ : }
+ : else
+ : {
+ : r = color->red >> 8;
+ : g = color->green >> 8;
+ : b = color->blue >> 8;
+ : *pixel = miIndexToEntY24 (pIndexed, (r << 16) | (g << 8) | b);
+ : }
+ : break;
+ : }
+ :}
+ :
+ :static CARD16
+ :miFillColor (CARD32 pixel, int bits)
+ :{
+ : while (bits < 16)
+ : {
+ : pixel |= pixel << bits;
+ : bits <<= 1;
+ : }
+ : return (CARD16) pixel;
+ :}
+ :
+ :Bool
+ :miIsSolidAlpha (PicturePtr pSrc)
+ :{
+ : ScreenPtr pScreen;
+ : char line[1];
+ :
+ : if (!pSrc->pDrawable)
+ : return FALSE;
+ :
+ : pScreen = pSrc->pDrawable->pScreen;
+ :
+ : /* Alpha-only */
+ : if (PICT_FORMAT_TYPE (pSrc->format) != PICT_TYPE_A)
+ : return FALSE;
+ : /* repeat */
+ : if (!pSrc->repeat)
+ : return FALSE;
+ : /* 1x1 */
+ : if (pSrc->pDrawable->width != 1 || pSrc->pDrawable->height != 1)
+ : return FALSE;
+ : line[0] = 1;
+ : (*pScreen->GetImage) (pSrc->pDrawable, 0, 0, 1, 1, ZPixmap, ~0L, line);
+ : switch (pSrc->pDrawable->bitsPerPixel) {
+ : case 1:
+ : return (CARD8) line[0] == 1 || (CARD8) line[0] == 0x80;
+ : case 4:
+ : return (CARD8) line[0] == 0xf || (CARD8) line[0] == 0xf0;
+ : case 8:
+ : return (CARD8) line[0] == 0xff;
+ : default:
+ : return FALSE;
+ : }
+ :}
+ :
+ :void
+ :miRenderPixelToColor (PictFormatPtr format,
+ : CARD32 pixel,
+ : xRenderColor *color)
+ :{
+ : CARD32 r, g, b, a;
+ : miIndexedPtr pIndexed;
+ :
+ : switch (format->type) {
+ : case PictTypeDirect:
+ : r = (pixel >> format->direct.red) & format->direct.redMask;
+ : g = (pixel >> format->direct.green) & format->direct.greenMask;
+ : b = (pixel >> format->direct.blue) & format->direct.blueMask;
+ : a = (pixel >> format->direct.alpha) & format->direct.alphaMask;
+ : color->red = miFillColor (r, Ones (format->direct.redMask));
+ : color->green = miFillColor (g, Ones (format->direct.greenMask));
+ : color->blue = miFillColor (b, Ones (format->direct.blueMask));
+ : color->alpha = miFillColor (a, Ones (format->direct.alphaMask));
+ : break;
+ : case PictTypeIndexed:
+ : pIndexed = (miIndexedPtr) (format->index.devPrivate);
+ : pixel = pIndexed->rgba[pixel & (MI_MAX_INDEXED-1)];
+ : r = (pixel >> 16) & 0xff;
+ : g = (pixel >> 8) & 0xff;
+ : b = (pixel ) & 0xff;
+ : color->red = miFillColor (r, 8);
+ : color->green = miFillColor (g, 8);
+ : color->blue = miFillColor (b, 8);
+ : color->alpha = 0xffff;
+ : break;
+ : }
+ :}
+ :
+ :_X_EXPORT Bool
+ :miPictureInit (ScreenPtr pScreen, PictFormatPtr formats, int nformats)
+ :{
+ : PictureScreenPtr ps;
+ :
+ : if (!PictureInit (pScreen, formats, nformats))
+ : return FALSE;
+ : ps = GetPictureScreen(pScreen);
+ : ps->CreatePicture = miCreatePicture;
+ : ps->DestroyPicture = miDestroyPicture;
+ : ps->ChangePictureClip = miChangePictureClip;
+ : ps->DestroyPictureClip = miDestroyPictureClip;
+ : ps->ChangePicture = miChangePicture;
+ : ps->ValidatePicture = miValidatePicture;
+ : ps->InitIndexed = miInitIndexed;
+ : ps->CloseIndexed = miCloseIndexed;
+ : ps->UpdateIndexed = miUpdateIndexed;
+ : ps->ChangePictureTransform = miChangePictureTransform;
+ : ps->ChangePictureFilter = miChangePictureFilter;
+ : ps->RealizeGlyph = miRealizeGlyph;
+ : ps->UnrealizeGlyph = miUnrealizeGlyph;
+ :
+ : /* MI rendering routines */
+ : ps->Composite = 0; /* requires DDX support */
+ : ps->Glyphs = miGlyphs;
+ : ps->CompositeRects = miCompositeRects;
+ : ps->Trapezoids = miTrapezoids;
+ : ps->Triangles = miTriangles;
+ : ps->TriStrip = miTriStrip;
+ : ps->TriFan = miTriFan;
+ :
+ : ps->RasterizeTrapezoid = 0; /* requires DDX support */
+ : ps->AddTraps = 0; /* requires DDX support */
+ : ps->AddTriangles = 0; /* requires DDX support */
+ :
+ : return TRUE;
+ :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/driver/xf86-video-intel/src/i830_exa.c"
+ *
+ * 254 0.2767
+ */
+
+
+ :/**************************************************************************
+ :
+ :Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+ :All Rights Reserved.
+ :Copyright (c) 2005 Jesse Barnes <jbarnes@virtuousgeek.org>
+ : Based on code from i830_xaa.c.
+ :
+ :Permission is hereby granted, free of charge, to any person obtaining a
+ :copy of this software and associated documentation files (the
+ :"Software"), to deal in the Software without restriction, including
+ :without limitation the rights to use, copy, modify, merge, publish,
+ :distribute, sub license, and/or sell copies of the Software, and to
+ :permit persons to whom the Software is furnished to do so, subject to
+ :the following conditions:
+ :
+ :The above copyright notice and this permission notice (including the
+ :next paragraph) shall be included in all copies or substantial portions
+ :of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ :OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ :MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ :IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ :ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ :TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ :SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :**************************************************************************/
+ :
+ :#ifdef HAVE_CONFIG_H
+ :#include "config.h"
+ :#endif
+ :
+ :#include "xf86.h"
+ :#include "xaarop.h"
+ :#include "i830.h"
+ :#include "i810_reg.h"
+ :#include "i830_reg.h"
+ :#include <string.h>
+ :
+ :#ifdef I830DEBUG
+ :#define DEBUG_I830FALLBACK 1
+ :#endif
+ :
+ :#define ALWAYS_SYNC 0
+ :
+ :#ifdef DEBUG_I830FALLBACK
+ :#define I830FALLBACK(s, arg...) \
+ :do { \
+ : DPRINTF(PFX, "EXA fallback: " s "\n", ##arg); \
+ : return FALSE; \
+ :} while(0)
+ :#else
+ :#define I830FALLBACK(s, arg...) \
+ :do { \
+ : return FALSE; \
+ :} while(0)
+ :#endif
+ :
+ :const int I830CopyROP[16] =
+ :{
+ : ROP_0, /* GXclear */
+ : ROP_DSa, /* GXand */
+ : ROP_SDna, /* GXandReverse */
+ : ROP_S, /* GXcopy */
+ : ROP_DSna, /* GXandInverted */
+ : ROP_D, /* GXnoop */
+ : ROP_DSx, /* GXxor */
+ : ROP_DSo, /* GXor */
+ : ROP_DSon, /* GXnor */
+ : ROP_DSxn, /* GXequiv */
+ : ROP_Dn, /* GXinvert*/
+ : ROP_SDno, /* GXorReverse */
+ : ROP_Sn, /* GXcopyInverted */
+ : ROP_DSno, /* GXorInverted */
+ : ROP_DSan, /* GXnand */
+ : ROP_1 /* GXset */
+ :};
+ :
+ :const int I830PatternROP[16] =
+ :{
+ : ROP_0,
+ : ROP_DPa,
+ : ROP_PDna,
+ : ROP_P,
+ : ROP_DPna,
+ : ROP_D,
+ : ROP_DPx,
+ : ROP_DPo,
+ : ROP_DPon,
+ : ROP_PDxn,
+ : ROP_Dn,
+ : ROP_PDno,
+ : ROP_Pn,
+ : ROP_DPno,
+ : ROP_DPan,
+ : ROP_1
+ :};
+ :
+ :/**
+ : * I830EXASync - wait for a command to finish
+ : * @pScreen: current screen
+ : * @marker: marker command to wait for
+ : *
+ : * Wait for the command specified by @marker to finish, then return. We don't
+ : * actually do marker waits, though we might in the future. For now, just
+ : * wait for a full idle.
+ : */
+ :static void
+ :I830EXASync(ScreenPtr pScreen, int marker)
+ 4 0.0044 :{ /* I830EXASync total: 19 0.0207 */
+ : ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ :
+ 3 0.0033 : I830Sync(pScrn);
+ 12 0.0131 :}
+ :
+ :/**
+ : * I830EXAPrepareSolid - prepare for a Solid operation, if possible
+ : */
+ :static Bool
+ :I830EXAPrepareSolid(PixmapPtr pPixmap, int alu, Pixel planemask, Pixel fg)
+ :{ /* I830EXAPrepareSolid total: 10 0.0109 */
+ : ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
+ 2 0.0022 : I830Ptr pI830 = I830PTR(pScrn);
+ : unsigned long offset, pitch;
+ :
+ 1 0.0011 : if (!EXA_PM_IS_SOLID(&pPixmap->drawable, planemask))
+ : I830FALLBACK("planemask is not solid");
+ :
+ : if (pPixmap->drawable.bitsPerPixel == 24)
+ : I830FALLBACK("solid 24bpp unsupported!\n");
+ :
+ : offset = exaGetPixmapOffset(pPixmap);
+ : pitch = exaGetPixmapPitch(pPixmap);
+ :
+ 4 0.0044 : if ( offset % pI830->EXADriverPtr->pixmapOffsetAlign != 0)
+ : I830FALLBACK("pixmap offset not aligned");
+ 1 0.0011 : if ( pitch % pI830->EXADriverPtr->pixmapPitchAlign != 0)
+ : I830FALLBACK("pixmap pitch not aligned");
+ :
+ 1 0.0011 : pI830->BR[13] = (pitch & 0xffff);
+ : switch (pPixmap->drawable.bitsPerPixel) {
+ : case 8:
+ : break;
+ : case 16:
+ : /* RGB565 */
+ : pI830->BR[13] |= (1 << 24);
+ : break;
+ : case 32:
+ : /* RGB8888 */
+ 1 0.0011 : pI830->BR[13] |= ((1 << 24) | (1 << 25));
+ : break;
+ : }
+ : pI830->BR[13] |= (I830PatternROP[alu] & 0xff) << 16 ;
+ : pI830->BR[16] = fg;
+ : return TRUE;
+ :}
+ :
+ :static void
+ :I830EXASolid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
+ 2 0.0022 :{ /* I830EXASolid total: 38 0.0414 */
+ : ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : unsigned long offset;
+ :
+ 1 0.0011 : offset = exaGetPixmapOffset(pPixmap);
+ :
+ : {
+ 1 0.0011 : BEGIN_LP_RING(6);
+ : if (pPixmap->drawable.bitsPerPixel == 32)
+ 4 0.0044 : OUT_RING(XY_COLOR_BLT_CMD | XY_COLOR_BLT_WRITE_ALPHA
+ : | XY_COLOR_BLT_WRITE_RGB);
+ : else
+ : OUT_RING(XY_COLOR_BLT_CMD);
+ :
+ 1 0.0011 : OUT_RING(pI830->BR[13]);
+ 3 0.0033 : OUT_RING((y1 << 16) | (x1 & 0xffff));
+ : OUT_RING((y2 << 16) | (x2 & 0xffff));
+ : OUT_RING(offset);
+ : OUT_RING(pI830->BR[16]);
+ 3 0.0033 : ADVANCE_LP_RING();
+ : }
+ 23 0.0251 :}
+ :
+ :static void
+ :I830EXADoneSolid(PixmapPtr pPixmap)
+ :{
+ :#if ALWAYS_SYNC
+ : ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
+ :
+ : I830Sync(pScrn);
+ :#endif
+ :}
+ :
+ :/**
+ : * TODO:
+ : * - support planemask using FULL_BLT_CMD?
+ : */
+ :static Bool
+ :I830EXAPrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir,
+ : int ydir, int alu, Pixel planemask)
+ :{
+ : ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
+ : I830Ptr pI830 = I830PTR(pScrn);
+ :
+ : if (!EXA_PM_IS_SOLID(&pSrcPixmap->drawable, planemask))
+ : I830FALLBACK("planemask is not solid");
+ :
+ : pI830->copy_src_pitch = exaGetPixmapPitch(pSrcPixmap);
+ : pI830->copy_src_off = exaGetPixmapOffset(pSrcPixmap);
+ :
+ : pI830->BR[13] = exaGetPixmapPitch(pDstPixmap);
+ : pI830->BR[13] |= I830CopyROP[alu] << 16;
+ :
+ : switch (pSrcPixmap->drawable.bitsPerPixel) {
+ : case 8:
+ : break;
+ : case 16:
+ : pI830->BR[13] |= (1 << 24);
+ : break;
+ : case 32:
+ : pI830->BR[13] |= ((1 << 25) | (1 << 24));
+ : break;
+ : }
+ : return TRUE;
+ :}
+ :
+ :static void
+ :I830EXACopy(PixmapPtr pDstPixmap, int src_x1, int src_y1, int dst_x1,
+ : int dst_y1, int w, int h)
+ :{
+ : ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : int dst_x2, dst_y2;
+ : unsigned int dst_off;
+ :
+ : dst_x2 = dst_x1 + w;
+ : dst_y2 = dst_y1 + h;
+ :
+ : dst_off = exaGetPixmapOffset(pDstPixmap);
+ :
+ : {
+ : BEGIN_LP_RING(8);
+ :
+ : if (pDstPixmap->drawable.bitsPerPixel == 32)
+ : OUT_RING(XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
+ : XY_SRC_COPY_BLT_WRITE_RGB);
+ : else
+ : OUT_RING(XY_SRC_COPY_BLT_CMD);
+ :
+ : OUT_RING(pI830->BR[13]);
+ : OUT_RING((dst_y1 << 16) | (dst_x1 & 0xffff));
+ : OUT_RING((dst_y2 << 16) | (dst_x2 & 0xffff));
+ : OUT_RING(dst_off);
+ : OUT_RING((src_y1 << 16) | (src_x1 & 0xffff));
+ : OUT_RING(pI830->copy_src_pitch);
+ : OUT_RING(pI830->copy_src_off);
+ :
+ : ADVANCE_LP_RING();
+ : }
+ :}
+ :
+ :static void
+ :I830EXADoneCopy(PixmapPtr pDstPixmap)
+ :{
+ :#if ALWAYS_SYNC
+ : ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
+ :
+ : I830Sync(pScrn);
+ :#endif
+ :}
+ :
+ :#define xFixedToFloat(val) \
+ : ((float)xFixedToInt(val) + ((float)xFixedFrac(val) / 65536.0))
+ :
+ :/**
+ : * Returns the floating-point coordinates transformed by the given transform.
+ : *
+ : * transform may be null.
+ : */
+ :void
+ :i830_get_transformed_coordinates(int x, int y, PictTransformPtr transform,
+ : float *x_out, float *y_out)
+ 68 0.0741 :{ /* i830_get_transformed_coordinates total: 187 0.2037 */
+ 13 0.0142 : if (transform == NULL) {
+ 39 0.0425 : *x_out = x;
+ 35 0.0381 : *y_out = y;
+ : } else {
+ : PictVector v;
+ :
+ : v.vector[0] = IntToxFixed(x);
+ : v.vector[1] = IntToxFixed(y);
+ : v.vector[2] = xFixed1;
+ : PictureTransformPoint(transform, &v);
+ : *x_out = xFixedToFloat(v.vector[0]);
+ : *y_out = xFixedToFloat(v.vector[1]);
+ : }
+ 32 0.0349 :}
+ :
+ :/**
+ : * Uploads data from system memory to the framebuffer using a series of
+ : * 8x8 pattern blits.
+ : */
+ :static Bool
+ :i830_upload_to_screen(PixmapPtr pDst, int x, int y, int w, int h, char *src,
+ : int src_pitch)
+ :{
+ : ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : const int uts_width_max = 16, uts_height_max = 16;
+ : int cpp = pDst->drawable.bitsPerPixel / 8;
+ : int sub_x, sub_y;
+ : CARD32 br13;
+ : CARD32 offset;
+ :
+ : if (w > uts_width_max || h > uts_height_max)
+ : I830FALLBACK("too large for upload to screen (%d,%d)", w, h);
+ :
+ : offset = exaGetPixmapOffset(pDst);
+ :
+ : br13 = exaGetPixmapPitch(pDst);
+ : br13 |= ((I830PatternROP[GXcopy] & 0xff) << 16);
+ : switch (pDst->drawable.bitsPerPixel) {
+ : case 16:
+ : br13 |= 1 << 24;
+ : break;
+ : case 32:
+ : br13 |= 3 << 24;
+ : break;
+ : }
+ :
+ : for (sub_y = 0; sub_y < uts_height_max && sub_y < h; sub_y += 8) {
+ : int sub_height;
+ :
+ : if (sub_y + 8 > h)
+ : sub_height = h - sub_y;
+ : else
+ : sub_height = 8;
+ :
+ : for (sub_x = 0; sub_x < uts_width_max && sub_x < w; sub_x += 8) {
+ : int sub_width, line;
+ : char *src_line = src + sub_y * src_pitch + sub_x * cpp;
+ :
+ : if (sub_x + 8 > w)
+ : sub_width = w - sub_x;
+ : else
+ : sub_width = 8;
+ :
+ : BEGIN_LP_RING(6 + (cpp * 8 * 8 / 4));
+ :
+ : /* XXX We may need a pattern offset here for {x,y} % 8 != 0*/
+ : OUT_RING(XY_PAT_BLT_IMMEDIATE |
+ : XY_SRC_COPY_BLT_WRITE_ALPHA |
+ : XY_SRC_COPY_BLT_WRITE_RGB |
+ : (3 + cpp * 8 * 8 / 4));
+ : OUT_RING(br13);
+ : OUT_RING(((y + sub_y) << 16) | (x + sub_x));
+ : OUT_RING(((y + sub_y + sub_height) << 16) |
+ : (x + sub_x + sub_width));
+ : OUT_RING(offset);
+ :
+ : /* Write out the lines with valid data, followed by any needed
+ : * padding
+ : */
+ : for (line = 0; line < sub_height; line++) {
+ : OUT_RING_COPY(sub_width * cpp, src_line);
+ : src_line += src_pitch;
+ : if (sub_width != 8)
+ : OUT_RING_PAD((8 - sub_width) * cpp);
+ : }
+ : /* Write out any full padding lines to follow */
+ : if (sub_height != 8)
+ : OUT_RING_PAD(8 * cpp * (8 - sub_height));
+ :
+ : OUT_RING(MI_NOOP);
+ : ADVANCE_LP_RING();
+ : }
+ : }
+ :
+ : exaMarkSync(pDst->drawable.pScreen);
+ : /* exaWaitSync(pDst->drawable.pScreen); */
+ :
+ : return TRUE;
+ :}
+ :
+ :
+ :/*
+ : * TODO:
+ : * - Dual head?
+ : */
+ :Bool
+ :I830EXAInit(ScreenPtr pScreen)
+ :{
+ : ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ : I830Ptr pI830 = I830PTR(pScrn);
+ :
+ : pI830->EXADriverPtr = exaDriverAlloc();
+ : if (pI830->EXADriverPtr == NULL) {
+ : pI830->noAccel = TRUE;
+ : return FALSE;
+ : }
+ : memset(pI830->EXADriverPtr, 0, sizeof(*pI830->EXADriverPtr));
+ :
+ : pI830->bufferOffset = 0;
+ : pI830->EXADriverPtr->exa_major = 2;
+ : pI830->EXADriverPtr->exa_minor = 1;
+ : pI830->EXADriverPtr->memoryBase = pI830->FbBase;
+ : pI830->EXADriverPtr->offScreenBase = pI830->exa_offscreen->offset;
+ : pI830->EXADriverPtr->memorySize = pI830->exa_offscreen->offset +
+ : pI830->exa_offscreen->size;
+ : pI830->EXADriverPtr->flags = EXA_OFFSCREEN_PIXMAPS;
+ :
+ : DPRINTF(PFX, "EXA Mem: memoryBase 0x%x, end 0x%x, offscreen base 0x%x, memorySize 0x%x\n",
+ : pI830->EXADriverPtr->memoryBase,
+ : pI830->EXADriverPtr->memoryBase + pI830->EXADriverPtr->memorySize,
+ : pI830->EXADriverPtr->offScreenBase,
+ : pI830->EXADriverPtr->memorySize);
+ :
+ :
+ : /* Limits are described in the BLT engine chapter under Graphics Data Size
+ : * Limitations, and the descriptions of SURFACE_STATE, 3DSTATE_BUFFER_INFO,
+ : * 3DSTATE_DRAWING_RECTANGLE, 3DSTATE_MAP_INFO, and 3DSTATE_MAP_INFO.
+ : *
+ : * i845 through i965 limits 2D rendering to 65536 lines and pitch of 32768.
+ : *
+ : * i965 limits 3D surface to (2*element size)-aligned offset if un-tiled.
+ : * i965 limits 3D surface to 4kB-aligned offset if tiled.
+ : * i965 limits 3D surfaces to w,h of ?,8192.
+ : * i965 limits 3D surface to pitch of 1B - 128kB.
+ : * i965 limits 3D surface pitch alignment to 1 or 2 times the element size.
+ : * i965 limits 3D surface pitch alignment to 512B if tiled.
+ : * i965 limits 3D destination drawing rect to w,h of 8192,8192.
+ : *
+ : * i915 limits 3D textures to 4B-aligned offset if un-tiled.
+ : * i915 limits 3D textures to ~4kB-aligned offset if tiled.
+ : * i915 limits 3D textures to width,height of 2048,2048.
+ : * i915 limits 3D textures to pitch of 16B - 8kB, in dwords.
+ : * i915 limits 3D destination to ~4kB-aligned offset if tiled.
+ : * i915 limits 3D destination to pitch of 16B - 8kB, in dwords, if un-tiled.
+ : * i915 limits 3D destination to pitch of 512B - 8kB, in tiles, if tiled.
+ : * i915 limits 3D destination to POT aligned pitch if tiled.
+ : * i915 limits 3D destination drawing rect to w,h of 2048,2048.
+ : *
+ : * i845 limits 3D textures to 4B-aligned offset if un-tiled.
+ : * i845 limits 3D textures to ~4kB-aligned offset if tiled.
+ : * i845 limits 3D textures to width,height of 2048,2048.
+ : * i845 limits 3D textures to pitch of 4B - 8kB, in dwords.
+ : * i845 limits 3D destination to 4B-aligned offset if un-tiled.
+ : * i845 limits 3D destination to ~4kB-aligned offset if tiled.
+ : * i845 limits 3D destination to pitch of 8B - 8kB, in dwords.
+ : * i845 limits 3D destination drawing rect to w,h of 2048,2048.
+ : *
+ : * For the tiled issues, the only tiled buffer we draw to should be
+ : * the front, which will have an appropriate pitch/offset already set up,
+ : * so EXA doesn't need to worry.
+ : */
+ : if (IS_I965G(pI830)) {
+ : pI830->EXADriverPtr->pixmapOffsetAlign = 4 * 2;
+ : pI830->EXADriverPtr->pixmapPitchAlign = 16;
+ : pI830->EXADriverPtr->maxX = 8192;
+ : pI830->EXADriverPtr->maxY = 8192;
+ : } else {
+ : pI830->EXADriverPtr->pixmapOffsetAlign = 4;
+ : pI830->EXADriverPtr->pixmapPitchAlign = 16;
+ : pI830->EXADriverPtr->maxX = 2048;
+ : pI830->EXADriverPtr->maxY = 2048;
+ : }
+ :
+ : /* Sync */
+ : pI830->EXADriverPtr->WaitMarker = I830EXASync;
+ :
+ : /* Solid fill */
+ : pI830->EXADriverPtr->PrepareSolid = I830EXAPrepareSolid;
+ : pI830->EXADriverPtr->Solid = I830EXASolid;
+ : pI830->EXADriverPtr->DoneSolid = I830EXADoneSolid;
+ :
+ : /* Copy */
+ : pI830->EXADriverPtr->PrepareCopy = I830EXAPrepareCopy;
+ : pI830->EXADriverPtr->Copy = I830EXACopy;
+ : pI830->EXADriverPtr->DoneCopy = I830EXADoneCopy;
+ :
+ : /* Composite */
+ : if (!IS_I9XX(pI830)) {
+ : pI830->EXADriverPtr->CheckComposite = i830_check_composite;
+ : pI830->EXADriverPtr->PrepareComposite = i830_prepare_composite;
+ : pI830->EXADriverPtr->Composite = i830_composite;
+ : pI830->EXADriverPtr->DoneComposite = i830_done_composite;
+ : } else if (IS_I915G(pI830) || IS_I915GM(pI830) ||
+ : IS_I945G(pI830) || IS_I945GM(pI830) || IS_G33CLASS(pI830))
+ : {
+ : pI830->EXADriverPtr->CheckComposite = i915_check_composite;
+ : pI830->EXADriverPtr->PrepareComposite = i915_prepare_composite;
+ : pI830->EXADriverPtr->Composite = i830_composite;
+ : pI830->EXADriverPtr->DoneComposite = i830_done_composite;
+ : } else {
+ : pI830->EXADriverPtr->CheckComposite = i965_check_composite;
+ : pI830->EXADriverPtr->PrepareComposite = i965_prepare_composite;
+ : pI830->EXADriverPtr->Composite = i965_composite;
+ : pI830->EXADriverPtr->DoneComposite = i830_done_composite;
+ : }
+ :
+ : /* UploadToScreen/DownloadFromScreen */
+ : if (0)
+ : pI830->EXADriverPtr->UploadToScreen = i830_upload_to_screen;
+ :
+ : if(!exaDriverInit(pScreen, pI830->EXADriverPtr)) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ : "EXA initialization failed; trying older version\n");
+ : pI830->EXADriverPtr->exa_minor = 0;
+ : if(!exaDriverInit(pScreen, pI830->EXADriverPtr)) {
+ : xfree(pI830->EXADriverPtr);
+ : pI830->noAccel = TRUE;
+ : return FALSE;
+ : }
+ : }
+ :
+ : I830SelectBuffer(pScrn, I830_SELECT_FRONT);
+ :
+ : return TRUE;
+ :}
+ :
+ :#ifdef XF86DRI
+ :
+ :#ifndef ExaOffscreenMarkUsed
+ :extern void ExaOffscreenMarkUsed(PixmapPtr);
+ :#endif
+ :
+ :unsigned long long
+ :I830TexOffsetStart(PixmapPtr pPix)
+ :{
+ : exaMoveInPixmap(pPix);
+ : ExaOffscreenMarkUsed(pPix);
+ :
+ : return exaGetPixmapOffset(pPix);
+ :}
+ :#endif
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/miext/damage/damage.c"
+ *
+ * 191 0.2081
+ */
+
+
+ :/*
+ : * Copyright © 2003 Keith Packard
+ : *
+ : * 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 Keith Packard not be used in
+ : * advertising or publicity pertaining to distribution of the software without
+ : * specific, written prior permission. Keith Packard makes no
+ : * representations about the suitability of this software for any purpose. It
+ : * is provided "as is" without express or implied warranty.
+ : *
+ : * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ : * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ : * EVENT SHALL KEITH PACKARD 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.
+ : */
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include <stdlib.h>
+ :
+ :#include <X11/X.h>
+ :#include "scrnintstr.h"
+ :#include "windowstr.h"
+ :#include <X11/fonts/font.h>
+ :#include "dixfontstr.h"
+ :#include <X11/fonts/fontstruct.h>
+ :#include "mi.h"
+ :#include "regionstr.h"
+ :#include "globals.h"
+ :#include "gcstruct.h"
+ :#include "damage.h"
+ :#include "damagestr.h"
+ :#ifdef COMPOSITE
+ :#include "cw.h"
+ :#endif
+ :
+ :#define wrap(priv, real, mem, func) {\
+ : priv->mem = real->mem; \
+ : real->mem = func; \
+ :}
+ :
+ :#define unwrap(priv, real, mem) {\
+ : real->mem = priv->mem; \
+ :}
+ :
+ :#define BOX_SAME(a,b) \
+ : ((a)->x1 == (b)->x1 && \
+ : (a)->y1 == (b)->y1 && \
+ : (a)->x2 == (b)->x2 && \
+ : (a)->y2 == (b)->y2)
+ :
+ :#define DAMAGE_VALIDATE_ENABLE 0
+ :#define DAMAGE_DEBUG_ENABLE 0
+ :#if DAMAGE_DEBUG_ENABLE
+ :#define DAMAGE_DEBUG(x) ErrorF x
+ :#else
+ :#define DAMAGE_DEBUG(x)
+ :#endif
+ :
+ :#define getPixmapDamageRef(pPixmap) \
+ : ((DamagePtr *) &(pPixmap->devPrivates[damagePixPrivateIndex].ptr))
+ :
+ :#define pixmapDamage(pPixmap) damagePixPriv(pPixmap)
+ :
+ :static int damageScrPrivateIndex;
+ :static int damagePixPrivateIndex;
+ :static int damageGCPrivateIndex;
+ :static int damageWinPrivateIndex;
+ :static int damageGeneration;
+ :
+ :static DamagePtr *
+ :getDrawableDamageRef (DrawablePtr pDrawable)
+ 2 0.0022 :{ /* getDrawableDamageRef total: 6 0.0065 */
+ : PixmapPtr pPixmap;
+ :
+ : if (pDrawable->type == DRAWABLE_WINDOW)
+ : {
+ : ScreenPtr pScreen = pDrawable->pScreen;
+ :
+ : pPixmap = 0;
+ : if (pScreen->GetWindowPixmap
+ :#ifdef ROOTLESS_WORKAROUND
+ : && ((WindowPtr)pDrawable)->viewable
+ :#endif
+ : )
+ : pPixmap = (*pScreen->GetWindowPixmap) ((WindowPtr)pDrawable);
+ :
+ : if (!pPixmap)
+ : {
+ : damageScrPriv(pScreen);
+ :
+ : return &pScrPriv->pScreenDamage;
+ : }
+ : }
+ : else
+ : pPixmap = (PixmapPtr) pDrawable;
+ : return getPixmapDamageRef (pPixmap);
+ 4 0.0044 :}
+ :
+ :#define getDrawableDamage(pDrawable) (*getDrawableDamageRef (pDrawable))
+ :#define getWindowDamage(pWin) getDrawableDamage(&(pWin)->drawable)
+ :
+ :#define drawableDamage(pDrawable) \
+ : DamagePtr pDamage = getDrawableDamage(pDrawable)
+ :
+ :#define windowDamage(pWin) drawableDamage(&(pWin)->drawable)
+ :
+ :#define winDamageRef(pWindow) \
+ : DamagePtr *pPrev = (DamagePtr *) \
+ : &(pWindow->devPrivates[damageWinPrivateIndex].ptr)
+ :
+ :static void
+ :DamageReportDamage (DamagePtr pDamage, RegionPtr pDamageRegion)
+ 1 0.0011 :{ /* DamageReportDamage total: 4 0.0044 */
+ : BoxRec tmpBox;
+ : RegionRec tmpRegion;
+ : Bool was_empty;
+ :
+ : switch (pDamage->damageLevel) {
+ : case DamageReportRawRegion:
+ : (*pDamage->damageReport) (pDamage, pDamageRegion, pDamage->closure);
+ : break;
+ : case DamageReportDeltaRegion:
+ : REGION_NULL (pScreen, &tmpRegion);
+ : REGION_SUBTRACT (pScreen, &tmpRegion, pDamageRegion, &pDamage->damage);
+ : if (REGION_NOTEMPTY (pScreen, &tmpRegion)) {
+ : REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage,
+ : pDamageRegion);
+ : (*pDamage->damageReport) (pDamage, &tmpRegion, pDamage->closure);
+ : }
+ : REGION_UNINIT(pScreen, &tmpRegion);
+ : break;
+ : case DamageReportBoundingBox:
+ : tmpBox = *REGION_EXTENTS (pScreen, &pDamage->damage);
+ : REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage,
+ : pDamageRegion);
+ : if (!BOX_SAME (&tmpBox, REGION_EXTENTS (pScreen, &pDamage->damage))) {
+ : (*pDamage->damageReport) (pDamage, &pDamage->damage,
+ : pDamage->closure);
+ : }
+ : break;
+ : case DamageReportNonEmpty:
+ : was_empty = !REGION_NOTEMPTY(pScreen, &pDamage->damage);
+ 1 0.0011 : REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage,
+ : pDamageRegion);
+ : if (was_empty && REGION_NOTEMPTY(pScreen, &pDamage->damage)) {
+ : (*pDamage->damageReport) (pDamage, &pDamage->damage,
+ : pDamage->closure);
+ : }
+ : break;
+ : case DamageReportNone:
+ : REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage,
+ : pDamageRegion);
+ : break;
+ : }
+ 2 0.0022 :}
+ :
+ :#if DAMAGE_DEBUG_ENABLE
+ :static void
+ :_damageDamageRegion (DrawablePtr pDrawable, RegionPtr pRegion, Bool clip, int subWindowMode, const char *where)
+ :#define damageDamageRegion(d,r,c,m) _damageDamageRegion(d,r,c,m,__FUNCTION__)
+ :#else
+ :static void
+ :damageDamageRegion (DrawablePtr pDrawable, RegionPtr pRegion, Bool clip,
+ : int subWindowMode)
+ :#endif
+ 1 0.0011 :{ /* damageDamageRegion total: 21 0.0229 */
+ : ScreenPtr pScreen = pDrawable->pScreen;
+ : damageScrPriv(pScreen);
+ : drawableDamage(pDrawable);
+ : DamagePtr pNext;
+ : RegionRec clippedRec;
+ : RegionPtr pDamageRegion;
+ : RegionRec pixClip;
+ : int draw_x, draw_y;
+ :#ifdef COMPOSITE
+ : int screen_x = 0, screen_y = 0;
+ :#endif
+ :
+ : /* short circuit for empty regions */
+ 1 0.0011 : if (!REGION_NOTEMPTY(pScreen, pRegion))
+ : return;
+ :
+ :#ifdef COMPOSITE
+ : /*
+ : * When drawing to a pixmap which is storing window contents,
+ : * the region presented is in pixmap relative coordinates which
+ : * need to be converted to screen relative coordinates
+ : */
+ : if (pDrawable->type != DRAWABLE_WINDOW)
+ : {
+ : screen_x = ((PixmapPtr) pDrawable)->screen_x - pDrawable->x;
+ 2 0.0022 : screen_y = ((PixmapPtr) pDrawable)->screen_y - pDrawable->y;
+ : }
+ 2 0.0022 : if (screen_x || screen_y)
+ : REGION_TRANSLATE (pScreen, pRegion, screen_x, screen_y);
+ :#endif
+ :
+ : if (pDrawable->type == DRAWABLE_WINDOW &&
+ : ((WindowPtr)(pDrawable))->backingStore == NotUseful)
+ : {
+ : if (subWindowMode == ClipByChildren)
+ : {
+ : REGION_INTERSECT(pScreen, pRegion, pRegion,
+ : &((WindowPtr)(pDrawable))->clipList);
+ : }
+ : else if (subWindowMode == IncludeInferiors)
+ : {
+ : RegionPtr pTempRegion =
+ : NotClippedByChildren((WindowPtr)(pDrawable));
+ : REGION_INTERSECT(pScreen, pRegion, pRegion, pTempRegion);
+ : REGION_DESTROY(pScreen, pTempRegion);
+ : }
+ : /* If subWindowMode is set to an invalid value, don't perform
+ : * any drawable-based clipping. */
+ : }
+ :
+ :
+ 2 0.0022 : REGION_NULL (pScreen, &clippedRec);
+ 1 0.0011 : for (; pDamage; pDamage = pNext)
+ : {
+ 1 0.0011 : pNext = pDamage->pNext;
+ : /*
+ : * Check for internal damage and don't send events
+ : */
+ 1 0.0011 : if (pScrPriv->internalLevel > 0 && !pDamage->isInternal)
+ : {
+ : DAMAGE_DEBUG (("non internal damage, skipping at %d\n",
+ : pScrPriv->internalLevel));
+ : continue;
+ : }
+ : /*
+ : * Check for unrealized windows
+ : */
+ 1 0.0011 : if (pDamage->pDrawable->type == DRAWABLE_WINDOW &&
+ : !((WindowPtr) (pDamage->pDrawable))->realized)
+ : {
+ :#if 0
+ : DAMAGE_DEBUG (("damage while window unrealized\n"));
+ :#endif
+ : continue;
+ : }
+ :
+ 1 0.0011 : draw_x = pDamage->pDrawable->x;
+ : draw_y = pDamage->pDrawable->y;
+ :#ifdef COMPOSITE
+ : /*
+ : * Need to move everyone to screen coordinates
+ : * XXX what about off-screen pixmaps with non-zero x/y?
+ : */
+ : if (pDamage->pDrawable->type != DRAWABLE_WINDOW)
+ : {
+ : draw_x += ((PixmapPtr) pDamage->pDrawable)->screen_x;
+ : draw_y += ((PixmapPtr) pDamage->pDrawable)->screen_y;
+ : }
+ :#endif
+ :
+ : /*
+ : * Clip against border or pixmap bounds
+ : */
+ :
+ : pDamageRegion = pRegion;
+ : if (clip || pDamage->pDrawable != pDrawable)
+ : {
+ : pDamageRegion = &clippedRec;
+ : if (pDamage->pDrawable->type == DRAWABLE_WINDOW) {
+ : REGION_INTERSECT (pScreen, pDamageRegion, pRegion,
+ : &((WindowPtr)(pDamage->pDrawable))->borderClip);
+ : } else {
+ : BoxRec box;
+ : box.x1 = draw_x;
+ : box.y1 = draw_y;
+ : box.x2 = draw_x + pDamage->pDrawable->width;
+ : box.y2 = draw_y + pDamage->pDrawable->height;
+ 1 0.0011 : REGION_INIT(pScreen, &pixClip, &box, 1);
+ : REGION_INTERSECT (pScreen, pDamageRegion, pRegion, &pixClip);
+ 2 0.0022 : REGION_UNINIT(pScreen, &pixClip);
+ : }
+ : /*
+ : * Short circuit empty results
+ : */
+ : if (!REGION_NOTEMPTY(pScreen, pDamageRegion))
+ : continue;
+ : }
+ :
+ : DAMAGE_DEBUG (("%s %d x %d +%d +%d (target 0x%lx monitor 0x%lx)\n",
+ : where,
+ : pDamageRegion->extents.x2 - pDamageRegion->extents.x1,
+ : pDamageRegion->extents.y2 - pDamageRegion->extents.y1,
+ : pDamageRegion->extents.x1, pDamageRegion->extents.y1,
+ : pDrawable->id, pDamage->pDrawable->id));
+ :
+ : /*
+ : * Move region to target coordinate space
+ : */
+ : if (draw_x || draw_y)
+ : REGION_TRANSLATE (pScreen, pDamageRegion, -draw_x, -draw_y);
+ :
+ : /* If the damage rec has been flagged to report damage after the op has
+ : * completed, then union it into the delayed damage region, which will
+ : * be used for reporting after calling down, and skip the reporting
+ : */
+ 1 0.0011 : if (!pDamage->reportAfter) {
+ : DamageReportDamage (pDamage, pDamageRegion);
+ : } else {
+ 1 0.0011 : REGION_UNION(pScreen, &pDamage->pendingDamage,
+ : &pDamage->pendingDamage, pDamageRegion);
+ : }
+ :
+ : /*
+ : * translate original region back
+ : */
+ 1 0.0011 : if (pDamageRegion == pRegion && (draw_x || draw_y))
+ : REGION_TRANSLATE (pScreen, pDamageRegion, draw_x, draw_y);
+ : }
+ :#ifdef COMPOSITE
+ : if (screen_x || screen_y)
+ : REGION_TRANSLATE (pScreen, pRegion, -screen_x, -screen_y);
+ :#endif
+ :
+ : REGION_UNINIT (pScreen, &clippedRec);
+ 2 0.0022 :}
+ :
+ :static void
+ :damageReportPostOp (DrawablePtr pDrawable)
+ :{ /* damageReportPostOp total: 3 0.0033 */
+ : drawableDamage(pDrawable);
+ :
+ : for (; pDamage != NULL; pDamage = pDamage->pNext)
+ : {
+ 2 0.0022 : if (pDamage->reportAfter) {
+ : DamageReportDamage (pDamage, &pDamage->pendingDamage);
+ 1 0.0011 : REGION_EMPTY (pScreen, &pDamage->pendingDamage);
+ : }
+ : }
+ :
+ :}
+ :
+ :#if DAMAGE_DEBUG_ENABLE
+ :#define damageDamageBox(d,b,m) _damageDamageBox(d,b,m,__FUNCTION__)
+ :static void
+ :_damageDamageBox (DrawablePtr pDrawable, BoxPtr pBox, int subWindowMode, const char *where)
+ :#else
+ :static void
+ :damageDamageBox (DrawablePtr pDrawable, BoxPtr pBox, int subWindowMode)
+ :#endif
+ 2 0.0022 :{ /* damageDamageBox total: 3 0.0033 */
+ : RegionRec region;
+ :
+ : REGION_INIT (pDrawable->pScreen, ®ion, pBox, 1);
+ :#if DAMAGE_DEBUG_ENABLE
+ : _damageDamageRegion (pDrawable, ®ion, TRUE, subWindowMode, where);
+ :#else
+ 1 0.0011 : damageDamageRegion (pDrawable, ®ion, TRUE, subWindowMode);
+ :#endif
+ : REGION_UNINIT (pDrawable->pScreen, ®ion);
+ :}
+ :
+ :static void damageValidateGC(GCPtr, unsigned long, DrawablePtr);
+ :static void damageChangeGC(GCPtr, unsigned long);
+ :static void damageCopyGC(GCPtr, unsigned long, GCPtr);
+ :static void damageDestroyGC(GCPtr);
+ :static void damageChangeClip(GCPtr, int, pointer, int);
+ :static void damageDestroyClip(GCPtr);
+ :static void damageCopyClip(GCPtr, GCPtr);
+ :
+ :static GCFuncs damageGCFuncs = {
+ : damageValidateGC, damageChangeGC, damageCopyGC, damageDestroyGC,
+ : damageChangeClip, damageDestroyClip, damageCopyClip
+ :};
+ :
+ :static GCOps damageGCOps;
+ :
+ :static Bool
+ :damageCreateGC(GCPtr pGC)
+ :{
+ : ScreenPtr pScreen = pGC->pScreen;
+ : damageScrPriv(pScreen);
+ : damageGCPriv(pGC);
+ : Bool ret;
+ :
+ : pGC->pCompositeClip = 0;
+ : unwrap (pScrPriv, pScreen, CreateGC);
+ : if((ret = (*pScreen->CreateGC) (pGC))) {
+ : pGCPriv->ops = NULL;
+ : pGCPriv->funcs = pGC->funcs;
+ : pGC->funcs = &damageGCFuncs;
+ : }
+ : wrap (pScrPriv, pScreen, CreateGC, damageCreateGC);
+ :
+ : return ret;
+ :}
+ :
+ :#ifdef NOTUSED
+ :static void
+ :damageWrapGC (GCPtr pGC)
+ :{
+ : damageGCPriv(pGC);
+ :
+ : pGCPriv->ops = NULL;
+ : pGCPriv->funcs = pGC->funcs;
+ : pGC->funcs = &damageGCFuncs;
+ :}
+ :
+ :static void
+ :damageUnwrapGC (GCPtr pGC)
+ :{
+ : damageGCPriv(pGC);
+ :
+ : pGC->funcs = pGCPriv->funcs;
+ : if (pGCPriv->ops)
+ : pGC->ops = pGCPriv->ops;
+ :}
+ :#endif
+ :
+ :#define DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable) \
+ : damageGCPriv(pGC); \
+ : GCFuncs *oldFuncs = pGC->funcs; \
+ : unwrap(pGCPriv, pGC, funcs); \
+ : unwrap(pGCPriv, pGC, ops); \
+ :
+ :#define DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable) \
+ : wrap(pGCPriv, pGC, funcs, oldFuncs); \
+ : wrap(pGCPriv, pGC, ops, &damageGCOps)
+ :
+ :#define DAMAGE_GC_FUNC_PROLOGUE(pGC) \
+ : damageGCPriv(pGC); \
+ : unwrap(pGCPriv, pGC, funcs); \
+ : if (pGCPriv->ops) unwrap(pGCPriv, pGC, ops)
+ :
+ :#define DAMAGE_GC_FUNC_EPILOGUE(pGC) \
+ : wrap(pGCPriv, pGC, funcs, &damageGCFuncs); \
+ : if (pGCPriv->ops) wrap(pGCPriv, pGC, ops, &damageGCOps)
+ :
+ :static void
+ :damageValidateGC(GCPtr pGC,
+ : unsigned long changes,
+ : DrawablePtr pDrawable)
+ 2 0.0022 :{ /* damageValidateGC total: 7 0.0076 */
+ 1 0.0011 : DAMAGE_GC_FUNC_PROLOGUE (pGC);
+ 1 0.0011 : (*pGC->funcs->ValidateGC)(pGC, changes, pDrawable);
+ : pGCPriv->ops = pGC->ops; /* just so it's not NULL */
+ 3 0.0033 : DAMAGE_GC_FUNC_EPILOGUE (pGC);
+ :}
+ :
+ :static void
+ :damageDestroyGC(GCPtr pGC)
+ :{
+ : DAMAGE_GC_FUNC_PROLOGUE (pGC);
+ : (*pGC->funcs->DestroyGC)(pGC);
+ : DAMAGE_GC_FUNC_EPILOGUE (pGC);
+ :}
+ :
+ :static void
+ :damageChangeGC (GCPtr pGC,
+ : unsigned long mask)
+ 2 0.0022 :{ /* damageChangeGC total: 9 0.0098 */
+ 4 0.0044 : DAMAGE_GC_FUNC_PROLOGUE (pGC);
+ 1 0.0011 : (*pGC->funcs->ChangeGC) (pGC, mask);
+ 2 0.0022 : DAMAGE_GC_FUNC_EPILOGUE (pGC);
+ :}
+ :
+ :static void
+ :damageCopyGC (GCPtr pGCSrc,
+ : unsigned long mask,
+ : GCPtr pGCDst)
+ :{
+ : DAMAGE_GC_FUNC_PROLOGUE (pGCDst);
+ : (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
+ : DAMAGE_GC_FUNC_EPILOGUE (pGCDst);
+ :}
+ :
+ :static void
+ :damageChangeClip (GCPtr pGC,
+ : int type,
+ : pointer pvalue,
+ : int nrects)
+ 1 0.0011 :{ /* damageChangeClip total: 1 0.0011 */
+ : DAMAGE_GC_FUNC_PROLOGUE (pGC);
+ : (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
+ : DAMAGE_GC_FUNC_EPILOGUE (pGC);
+ :}
+ :
+ :static void
+ :damageCopyClip(GCPtr pgcDst, GCPtr pgcSrc)
+ :{
+ : DAMAGE_GC_FUNC_PROLOGUE (pgcDst);
+ : (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
+ : DAMAGE_GC_FUNC_EPILOGUE (pgcDst);
+ :}
+ :
+ :static void
+ :damageDestroyClip(GCPtr pGC)
+ :{
+ : DAMAGE_GC_FUNC_PROLOGUE (pGC);
+ : (* pGC->funcs->DestroyClip)(pGC);
+ : DAMAGE_GC_FUNC_EPILOGUE (pGC);
+ :}
+ :
+ :#define TRIM_BOX(box, pGC) if (pGC->pCompositeClip) { \
+ : BoxPtr extents = &pGC->pCompositeClip->extents;\
+ : if(box.x1 < extents->x1) box.x1 = extents->x1; \
+ : if(box.x2 > extents->x2) box.x2 = extents->x2; \
+ : if(box.y1 < extents->y1) box.y1 = extents->y1; \
+ : if(box.y2 > extents->y2) box.y2 = extents->y2; \
+ : }
+ :
+ :#define TRANSLATE_BOX(box, pDrawable) { \
+ : box.x1 += pDrawable->x; \
+ : box.x2 += pDrawable->x; \
+ : box.y1 += pDrawable->y; \
+ : box.y2 += pDrawable->y; \
+ : }
+ :
+ :#define TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC) { \
+ : TRANSLATE_BOX(box, pDrawable); \
+ : TRIM_BOX(box, pGC); \
+ : }
+ :
+ :#define BOX_NOT_EMPTY(box) \
+ : (((box.x2 - box.x1) > 0) && ((box.y2 - box.y1) > 0))
+ :
+ :#define checkGCDamage(d,g) (getDrawableDamage(d) && \
+ : (!g->pCompositeClip ||\
+ : REGION_NOTEMPTY(d->pScreen, \
+ : g->pCompositeClip)))
+ :
+ :#ifdef RENDER
+ :
+ :#define TRIM_PICTURE_BOX(box, pDst) { \
+ : BoxPtr extents = &pDst->pCompositeClip->extents;\
+ : if(box.x1 < extents->x1) box.x1 = extents->x1; \
+ : if(box.x2 > extents->x2) box.x2 = extents->x2; \
+ : if(box.y1 < extents->y1) box.y1 = extents->y1; \
+ : if(box.y2 > extents->y2) box.y2 = extents->y2; \
+ : }
+ :
+ :#define checkPictureDamage(p) (getDrawableDamage(p->pDrawable) && \
+ : REGION_NOTEMPTY(pScreen, p->pCompositeClip))
+ :
+ :static void
+ :damageComposite (CARD8 op,
+ : PicturePtr pSrc,
+ : PicturePtr pMask,
+ : PicturePtr pDst,
+ : INT16 xSrc,
+ : INT16 ySrc,
+ : INT16 xMask,
+ : INT16 yMask,
+ : INT16 xDst,
+ : INT16 yDst,
+ : CARD16 width,
+ : CARD16 height)
+ 1 0.0011 :{ /* damageComposite total: 6 0.0065 */
+ : ScreenPtr pScreen = pDst->pDrawable->pScreen;
+ : PictureScreenPtr ps = GetPictureScreen(pScreen);
+ : damageScrPriv(pScreen);
+ :
+ 1 0.0011 : if (checkPictureDamage (pDst))
+ : {
+ : BoxRec box;
+ :
+ : box.x1 = xDst + pDst->pDrawable->x;
+ : box.y1 = yDst + pDst->pDrawable->y;
+ : box.x2 = box.x1 + width;
+ : box.y2 = box.y1 + height;
+ : TRIM_PICTURE_BOX(box, pDst);
+ : if (BOX_NOT_EMPTY(box))
+ 1 0.0011 : damageDamageBox (pDst->pDrawable, &box, pDst->subWindowMode);
+ : }
+ : unwrap (pScrPriv, ps, Composite);
+ : (*ps->Composite) (op,
+ : pSrc,
+ : pMask,
+ : pDst,
+ : xSrc,
+ : ySrc,
+ : xMask,
+ : yMask,
+ : xDst,
+ : yDst,
+ : width,
+ : height);
+ 3 0.0033 : damageReportPostOp (pDst->pDrawable);
+ : wrap (pScrPriv, ps, Composite, damageComposite);
+ :}
+ :
+ :static void
+ :damageGlyphs (CARD8 op,
+ : PicturePtr pSrc,
+ : PicturePtr pDst,
+ : PictFormatPtr maskFormat,
+ : INT16 xSrc,
+ : INT16 ySrc,
+ : int nlist,
+ : GlyphListPtr list,
+ : GlyphPtr *glyphs)
+ :{ /* damageGlyphs total: 61 0.0665 */
+ : ScreenPtr pScreen = pDst->pDrawable->pScreen;
+ : PictureScreenPtr ps = GetPictureScreen(pScreen);
+ : damageScrPriv(pScreen);
+ :
+ : if (checkPictureDamage (pDst))
+ : {
+ : int nlistTmp = nlist;
+ : GlyphListPtr listTmp = list;
+ : GlyphPtr *glyphsTmp = glyphs;
+ : int x, y;
+ : int n;
+ : GlyphPtr glyph;
+ : BoxRec box;
+ : int x1, y1, x2, y2;
+ :
+ : box.x1 = 32767;
+ : box.y1 = 32767;
+ : box.x2 = -32767;
+ : box.y2 = -32767;
+ : x = pDst->pDrawable->x;
+ : y = pDst->pDrawable->y;
+ 1 0.0011 : while (nlistTmp--)
+ : {
+ 1 0.0011 : x += listTmp->xOff;
+ : y += listTmp->yOff;
+ : n = listTmp->len;
+ 1 0.0011 : while (n--)
+ : {
+ 2 0.0022 : glyph = *glyphsTmp++;
+ 31 0.0338 : x1 = x - glyph->info.x;
+ 3 0.0033 : y1 = y - glyph->info.y;
+ 1 0.0011 : x2 = x1 + glyph->info.width;
+ 1 0.0011 : y2 = y1 + glyph->info.height;
+ : if (x1 < box.x1)
+ : box.x1 = x1;
+ 1 0.0011 : if (y1 < box.y1)
+ : box.y1 = y1;
+ 5 0.0054 : if (x2 > box.x2)
+ 2 0.0022 : box.x2 = x2;
+ 2 0.0022 : if (y2 > box.y2)
+ 1 0.0011 : box.y2 = y2;
+ 2 0.0022 : x += glyph->info.xOff;
+ 2 0.0022 : y += glyph->info.yOff;
+ : }
+ : listTmp++;
+ : }
+ 1 0.0011 : TRIM_PICTURE_BOX (box, pDst);
+ : if (BOX_NOT_EMPTY(box))
+ 1 0.0011 : damageDamageBox (pDst->pDrawable, &box, pDst->subWindowMode);
+ : }
+ 1 0.0011 : unwrap (pScrPriv, ps, Glyphs);
+ 1 0.0011 : (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
+ : damageReportPostOp (pDst->pDrawable);
+ : wrap (pScrPriv, ps, Glyphs, damageGlyphs);
+ 1 0.0011 :}
+ :#endif
+ :
+ :/**********************************************************/
+ :
+ :
+ :static void
+ :damageFillSpans(DrawablePtr pDrawable,
+ : GC *pGC,
+ : int npt,
+ : DDXPointPtr ppt,
+ : int *pwidth,
+ : int fSorted)
+ :{
+ : DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
+ :
+ : if (npt && checkGCDamage (pDrawable, pGC))
+ : {
+ : int nptTmp = npt;
+ : DDXPointPtr pptTmp = ppt;
+ : int *pwidthTmp = pwidth;
+ : BoxRec box;
+ :
+ : box.x1 = pptTmp->x;
+ : box.x2 = box.x1 + *pwidthTmp;
+ : box.y2 = box.y1 = pptTmp->y;
+ :
+ : while(--nptTmp)
+ : {
+ : pptTmp++;
+ : pwidthTmp++;
+ : if(box.x1 > pptTmp->x) box.x1 = pptTmp->x;
+ : if(box.x2 < (pptTmp->x + *pwidthTmp))
+ : box.x2 = pptTmp->x + *pwidthTmp;
+ : if(box.y1 > pptTmp->y) box.y1 = pptTmp->y;
+ : else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y;
+ : }
+ :
+ : box.y2++;
+ :
+ : if(!pGC->miTranslate) {
+ : TRANSLATE_BOX(box, pDrawable);
+ : }
+ : TRIM_BOX(box, pGC);
+ :
+ : if(BOX_NOT_EMPTY(box))
+ : damageDamageBox (pDrawable, &box, pGC->subWindowMode);
+ : }
+ :
+ : (*pGC->ops->FillSpans)(pDrawable, pGC, npt, ppt, pwidth, fSorted);
+ :
+ : damageReportPostOp (pDrawable);
+ : DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
+ :}
+ :
+ :static void
+ :damageSetSpans(DrawablePtr pDrawable,
+ : GCPtr pGC,
+ : char *pcharsrc,
+ : DDXPointPtr ppt,
+ : int *pwidth,
+ : int npt,
+ : int fSorted)
+ :{
+ : DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
+ :
+ : if (npt && checkGCDamage (pDrawable, pGC))
+ : {
+ : DDXPointPtr pptTmp = ppt;
+ : int *pwidthTmp = pwidth;
+ : int nptTmp = npt;
+ : BoxRec box;
+ :
+ : box.x1 = pptTmp->x;
+ : box.x2 = box.x1 + *pwidthTmp;
+ : box.y2 = box.y1 = pptTmp->y;
+ :
+ : while(--nptTmp)
+ : {
+ : pptTmp++;
+ : pwidthTmp++;
+ : if(box.x1 > pptTmp->x) box.x1 = pptTmp->x;
+ : if(box.x2 < (pptTmp->x + *pwidthTmp))
+ : box.x2 = pptTmp->x + *pwidthTmp;
+ : if(box.y1 > pptTmp->y) box.y1 = pptTmp->y;
+ : else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y;
+ : }
+ :
+ : box.y2++;
+ :
+ : if(!pGC->miTranslate) {
+ : TRANSLATE_BOX(box, pDrawable);
+ : }
+ : TRIM_BOX(box, pGC);
+ :
+ : if(BOX_NOT_EMPTY(box))
+ : damageDamageBox (pDrawable, &box, pGC->subWindowMode);
+ : }
+ : (*pGC->ops->SetSpans)(pDrawable, pGC, pcharsrc, ppt, pwidth, npt, fSorted);
+ : damageReportPostOp (pDrawable);
+ : DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
+ :}
+ :
+ :static void
+ :damagePutImage(DrawablePtr pDrawable,
+ : GCPtr pGC,
+ : int depth,
+ : int x,
+ : int y,
+ : int w,
+ : int h,
+ : int leftPad,
+ : int format,
+ : char *pImage)
+ :{
+ : DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
+ : if (checkGCDamage (pDrawable, pGC))
+ : {
+ : BoxRec box;
+ :
+ : box.x1 = x + pDrawable->x;
+ : box.x2 = box.x1 + w;
+ : box.y1 = y + pDrawable->y;
+ : box.y2 = box.y1 + h;
+ :
+ : TRIM_BOX(box, pGC);
+ : if(BOX_NOT_EMPTY(box))
+ : damageDamageBox (pDrawable, &box, pGC->subWindowMode);
+ : }
+ : (*pGC->ops->PutImage)(pDrawable, pGC, depth, x, y, w, h,
+ : leftPad, format, pImage);
+ : damageReportPostOp (pDrawable);
+ : DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
+ :}
+ :
+ :static RegionPtr
+ :damageCopyArea(DrawablePtr pSrc,
+ : DrawablePtr pDst,
+ : GC *pGC,
+ : int srcx,
+ : int srcy,
+ : int width,
+ : int height,
+ : int dstx,
+ : int dsty)
+ :{
+ : RegionPtr ret;
+ : DAMAGE_GC_OP_PROLOGUE(pGC, pDst);
+ :
+ : /* The driver will only call SourceValidate() when pSrc != pDst,
+ : * but the software sprite (misprite.c) always need to know when a
+ : * drawable is copied so it can remove the sprite. See #1030. */
+ : if ((pSrc == pDst) && pSrc->pScreen->SourceValidate &&
+ : pSrc->type == DRAWABLE_WINDOW &&
+ : ((WindowPtr)pSrc)->viewable)
+ : {
+ : (*pSrc->pScreen->SourceValidate) (pSrc, srcx, srcy, width, height);
+ : }
+ :
+ : if (checkGCDamage (pDst, pGC))
+ : {
+ : BoxRec box;
+ :
+ : box.x1 = dstx + pDst->x;
+ : box.x2 = box.x1 + width;
+ : box.y1 = dsty + pDst->y;
+ : box.y2 = box.y1 + height;
+ :
+ : TRIM_BOX(box, pGC);
+ : if(BOX_NOT_EMPTY(box))
+ : damageDamageBox (pDst, &box, pGC->subWindowMode);
+ : }
+ :
+ : ret = (*pGC->ops->CopyArea)(pSrc, pDst,
+ : pGC, srcx, srcy, width, height, dstx, dsty);
+ : damageReportPostOp (pDst);
+ : DAMAGE_GC_OP_EPILOGUE(pGC, pDst);
+ : return ret;
+ :}
+ :
+ :static RegionPtr
+ :damageCopyPlane(DrawablePtr pSrc,
+ : DrawablePtr pDst,
+ : GCPtr pGC,
+ : int srcx,
+ : int srcy,
+ : int width,
+ : int height,
+ : int dstx,
+ : int dsty,
+ : unsigned long bitPlane)
+ :{
+ : RegionPtr ret;
+ : DAMAGE_GC_OP_PROLOGUE(pGC, pDst);
+ :
+ : /* The driver will only call SourceValidate() when pSrc != pDst,
+ : * but the software sprite (misprite.c) always need to know when a
+ : * drawable is copied so it can remove the sprite. See #1030. */
+ : if ((pSrc == pDst) && pSrc->pScreen->SourceValidate &&
+ : pSrc->type == DRAWABLE_WINDOW &&
+ : ((WindowPtr)pSrc)->viewable)
+ : {
+ : (*pSrc->pScreen->SourceValidate) (pSrc, srcx, srcy, width, height);
+ : }
+ :
+ : if (checkGCDamage (pDst, pGC))
+ : {
+ : BoxRec box;
+ :
+ : box.x1 = dstx + pDst->x;
+ : box.x2 = box.x1 + width;
+ : box.y1 = dsty + pDst->y;
+ : box.y2 = box.y1 + height;
+ :
+ : TRIM_BOX(box, pGC);
+ : if(BOX_NOT_EMPTY(box))
+ : damageDamageBox (pDst, &box, pGC->subWindowMode);
+ : }
+ :
+ : ret = (*pGC->ops->CopyPlane)(pSrc, pDst,
+ : pGC, srcx, srcy, width, height, dstx, dsty, bitPlane);
+ : damageReportPostOp (pDst);
+ : DAMAGE_GC_OP_EPILOGUE(pGC, pDst);
+ : return ret;
+ :}
+ :
+ :static void
+ :damagePolyPoint(DrawablePtr pDrawable,
+ : GCPtr pGC,
+ : int mode,
+ : int npt,
+ : xPoint *ppt)
+ :{
+ : DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
+ :
+ : if (npt && checkGCDamage (pDrawable, pGC))
+ : {
+ : BoxRec box;
+ : int nptTmp = npt;
+ : xPoint *pptTmp = ppt;
+ :
+ : box.x2 = box.x1 = pptTmp->x;
+ : box.y2 = box.y1 = pptTmp->y;
+ :
+ : /* this could be slow if the points were spread out */
+ :
+ : while(--nptTmp)
+ : {
+ : pptTmp++;
+ : if(box.x1 > pptTmp->x) box.x1 = pptTmp->x;
+ : else if(box.x2 < pptTmp->x) box.x2 = pptTmp->x;
+ : if(box.y1 > pptTmp->y) box.y1 = pptTmp->y;
+ : else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y;
+ : }
+ :
+ : box.x2++;
+ : box.y2++;
+ :
+ : TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
+ : if(BOX_NOT_EMPTY(box))
+ : damageDamageBox (pDrawable, &box, pGC->subWindowMode);
+ : }
+ : (*pGC->ops->PolyPoint)(pDrawable, pGC, mode, npt, ppt);
+ : damageReportPostOp (pDrawable);
+ : DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
+ :}
+ :
+ :static void
+ :damagePolylines(DrawablePtr pDrawable,
+ : GCPtr pGC,
+ : int mode,
+ : int npt,
+ : DDXPointPtr ppt)
+ :{
+ : DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
+ :
+ : if (npt && checkGCDamage (pDrawable, pGC))
+ : {
+ : int nptTmp = npt;
+ : DDXPointPtr pptTmp = ppt;
+ : BoxRec box;
+ : int extra = pGC->lineWidth >> 1;
+ :
+ : box.x2 = box.x1 = pptTmp->x;
+ : box.y2 = box.y1 = pptTmp->y;
+ :
+ : if(nptTmp > 1)
+ : {
+ : if(pGC->joinStyle == JoinMiter)
+ : extra = 6 * pGC->lineWidth;
+ : else if(pGC->capStyle == CapProjecting)
+ : extra = pGC->lineWidth;
+ : }
+ :
+ : if(mode == CoordModePrevious)
+ : {
+ : int x = box.x1;
+ : int y = box.y1;
+ : while(--nptTmp)
+ : {
+ : pptTmp++;
+ : x += pptTmp->x;
+ : y += pptTmp->y;
+ : if(box.x1 > x) box.x1 = x;
+ : else if(box.x2 < x) box.x2 = x;
+ : if(box.y1 > y) box.y1 = y;
+ : else if(box.y2 < y) box.y2 = y;
+ : }
+ : }
+ : else
+ : {
+ : while(--nptTmp)
+ : {
+ : pptTmp++;
+ : if(box.x1 > pptTmp->x) box.x1 = pptTmp->x;
+ : else if(box.x2 < pptTmp->x) box.x2 = pptTmp->x;
+ : if(box.y1 > pptTmp->y) box.y1 = pptTmp->y;
+ : else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y;
+ : }
+ : }
+ :
+ : box.x2++;
+ : box.y2++;
+ :
+ : if(extra)
+ : {
+ : box.x1 -= extra;
+ : box.x2 += extra;
+ : box.y1 -= extra;
+ : box.y2 += extra;
+ : }
+ :
+ : TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
+ : if(BOX_NOT_EMPTY(box))
+ : damageDamageBox (pDrawable, &box, pGC->subWindowMode);
+ : }
+ : (*pGC->ops->Polylines)(pDrawable, pGC, mode, npt, ppt);
+ : damageReportPostOp (pDrawable);
+ : DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
+ :}
+ :
+ :static void
+ :damagePolySegment(DrawablePtr pDrawable,
+ : GCPtr pGC,
+ : int nSeg,
+ : xSegment *pSeg)
+ :{ /* damagePolySegment total: 1 0.0011 */
+ : DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
+ :
+ : if (nSeg && checkGCDamage (pDrawable, pGC))
+ : {
+ : BoxRec box;
+ : int extra = pGC->lineWidth;
+ : int nsegTmp = nSeg;
+ : xSegment *pSegTmp = pSeg;
+ :
+ : if(pGC->capStyle != CapProjecting)
+ : extra >>= 1;
+ :
+ : if(pSegTmp->x2 > pSegTmp->x1) {
+ : box.x1 = pSegTmp->x1;
+ : box.x2 = pSegTmp->x2;
+ : } else {
+ : box.x2 = pSegTmp->x1;
+ : box.x1 = pSegTmp->x2;
+ : }
+ :
+ : if(pSegTmp->y2 > pSegTmp->y1) {
+ : box.y1 = pSegTmp->y1;
+ : box.y2 = pSegTmp->y2;
+ : } else {
+ : box.y2 = pSegTmp->y1;
+ : box.y1 = pSegTmp->y2;
+ : }
+ :
+ : while(--nsegTmp)
+ : {
+ : pSegTmp++;
+ : if(pSegTmp->x2 > pSegTmp->x1)
+ : {
+ : if(pSegTmp->x1 < box.x1) box.x1 = pSegTmp->x1;
+ : if(pSegTmp->x2 > box.x2) box.x2 = pSegTmp->x2;
+ : }
+ : else
+ : {
+ : if(pSegTmp->x2 < box.x1) box.x1 = pSegTmp->x2;
+ : if(pSegTmp->x1 > box.x2) box.x2 = pSegTmp->x1;
+ : }
+ : if(pSegTmp->y2 > pSegTmp->y1)
+ : {
+ : if(pSegTmp->y1 < box.y1) box.y1 = pSegTmp->y1;
+ : if(pSegTmp->y2 > box.y2) box.y2 = pSegTmp->y2;
+ : }
+ : else
+ : {
+ : if(pSegTmp->y2 < box.y1) box.y1 = pSegTmp->y2;
+ : if(pSegTmp->y1 > box.y2) box.y2 = pSegTmp->y1;
+ : }
+ : }
+ :
+ : box.x2++;
+ : box.y2++;
+ :
+ : if(extra)
+ : {
+ : box.x1 -= extra;
+ : box.x2 += extra;
+ : box.y1 -= extra;
+ : box.y2 += extra;
+ : }
+ :
+ 1 0.0011 : TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
+ : if(BOX_NOT_EMPTY(box))
+ : damageDamageBox (pDrawable, &box, pGC->subWindowMode);
+ : }
+ : (*pGC->ops->PolySegment)(pDrawable, pGC, nSeg, pSeg);
+ : damageReportPostOp (pDrawable);
+ : DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
+ :}
+ :
+ :static void
+ :damagePolyRectangle(DrawablePtr pDrawable,
+ : GCPtr pGC,
+ : int nRects,
+ : xRectangle *pRects)
+ :{
+ : DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
+ :
+ : if (nRects && checkGCDamage (pDrawable, pGC))
+ : {
+ : BoxRec box;
+ : int offset1, offset2, offset3;
+ : int nRectsTmp = nRects;
+ : xRectangle *pRectsTmp = pRects;
+ :
+ : offset2 = pGC->lineWidth;
+ : if(!offset2) offset2 = 1;
+ : offset1 = offset2 >> 1;
+ : offset3 = offset2 - offset1;
+ :
+ : while(nRectsTmp--)
+ : {
+ : box.x1 = pRectsTmp->x - offset1;
+ : box.y1 = pRectsTmp->y - offset1;
+ : box.x2 = box.x1 + pRectsTmp->width + offset2;
+ : box.y2 = box.y1 + offset2;
+ : TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
+ : if(BOX_NOT_EMPTY(box))
+ : damageDamageBox (pDrawable, &box, pGC->subWindowMode);
+ :
+ : box.x1 = pRectsTmp->x - offset1;
+ : box.y1 = pRectsTmp->y + offset3;
+ : box.x2 = box.x1 + offset2;
+ : box.y2 = box.y1 + pRectsTmp->height - offset2;
+ : TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
+ : if(BOX_NOT_EMPTY(box))
+ : damageDamageBox (pDrawable, &box, pGC->subWindowMode);
+ :
+ : box.x1 = pRectsTmp->x + pRectsTmp->width - offset1;
+ : box.y1 = pRectsTmp->y + offset3;
+ : box.x2 = box.x1 + offset2;
+ : box.y2 = box.y1 + pRectsTmp->height - offset2;
+ : TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
+ : if(BOX_NOT_EMPTY(box))
+ : damageDamageBox (pDrawable, &box, pGC->subWindowMode);
+ :
+ : box.x1 = pRectsTmp->x - offset1;
+ : box.y1 = pRectsTmp->y + pRectsTmp->height - offset1;
+ : box.x2 = box.x1 + pRectsTmp->width + offset2;
+ : box.y2 = box.y1 + offset2;
+ : TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
+ : if(BOX_NOT_EMPTY(box))
+ : damageDamageBox (pDrawable, &box, pGC->subWindowMode);
+ :
+ : pRectsTmp++;
+ : }
+ : }
+ : (*pGC->ops->PolyRectangle)(pDrawable, pGC, nRects, pRects);
+ : damageReportPostOp (pDrawable);
+ : DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
+ :}
+ :
+ :static void
+ :damagePolyArc(DrawablePtr pDrawable,
+ : GCPtr pGC,
+ : int nArcs,
+ : xArc *pArcs)
+ :{
+ : DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
+ :
+ : if (nArcs && checkGCDamage (pDrawable, pGC))
+ : {
+ : int extra = pGC->lineWidth >> 1;
+ : BoxRec box;
+ : int nArcsTmp = nArcs;
+ : xArc *pArcsTmp = pArcs;
+ :
+ : box.x1 = pArcsTmp->x;
+ : box.x2 = box.x1 + pArcsTmp->width;
+ : box.y1 = pArcsTmp->y;
+ : box.y2 = box.y1 + pArcsTmp->height;
+ :
+ : while(--nArcsTmp)
+ : {
+ : pArcsTmp++;
+ : if(box.x1 > pArcsTmp->x)
+ : box.x1 = pArcsTmp->x;
+ : if(box.x2 < (pArcsTmp->x + pArcsTmp->width))
+ : box.x2 = pArcsTmp->x + pArcsTmp->width;
+ : if(box.y1 > pArcsTmp->y)
+ : box.y1 = pArcsTmp->y;
+ : if(box.y2 < (pArcsTmp->y + pArcsTmp->height))
+ : box.y2 = pArcsTmp->y + pArcsTmp->height;
+ : }
+ :
+ : if(extra)
+ : {
+ : box.x1 -= extra;
+ : box.x2 += extra;
+ : box.y1 -= extra;
+ : box.y2 += extra;
+ : }
+ :
+ : box.x2++;
+ : box.y2++;
+ :
+ : TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
+ : if(BOX_NOT_EMPTY(box))
+ : damageDamageBox (pDrawable, &box, pGC->subWindowMode);
+ : }
+ : (*pGC->ops->PolyArc)(pDrawable, pGC, nArcs, pArcs);
+ : damageReportPostOp (pDrawable);
+ : DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
+ :}
+ :
+ :static void
+ :damageFillPolygon(DrawablePtr pDrawable,
+ : GCPtr pGC,
+ : int shape,
+ : int mode,
+ : int npt,
+ : DDXPointPtr ppt)
+ :{
+ : DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
+ :
+ : if (npt > 2 && checkGCDamage (pDrawable, pGC))
+ : {
+ : DDXPointPtr pptTmp = ppt;
+ : int nptTmp = npt;
+ : BoxRec box;
+ :
+ : box.x2 = box.x1 = pptTmp->x;
+ : box.y2 = box.y1 = pptTmp->y;
+ :
+ : if(mode != CoordModeOrigin)
+ : {
+ : int x = box.x1;
+ : int y = box.y1;
+ : while(--nptTmp)
+ : {
+ : pptTmp++;
+ : x += pptTmp->x;
+ : y += pptTmp->y;
+ : if(box.x1 > x) box.x1 = x;
+ : else if(box.x2 < x) box.x2 = x;
+ : if(box.y1 > y) box.y1 = y;
+ : else if(box.y2 < y) box.y2 = y;
+ : }
+ : }
+ : else
+ : {
+ : while(--nptTmp)
+ : {
+ : pptTmp++;
+ : if(box.x1 > pptTmp->x) box.x1 = pptTmp->x;
+ : else if(box.x2 < pptTmp->x) box.x2 = pptTmp->x;
+ : if(box.y1 > pptTmp->y) box.y1 = pptTmp->y;
+ : else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y;
+ : }
+ : }
+ :
+ : box.x2++;
+ : box.y2++;
+ :
+ : TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
+ : if(BOX_NOT_EMPTY(box))
+ : damageDamageBox (pDrawable, &box, pGC->subWindowMode);
+ : }
+ :
+ : (*pGC->ops->FillPolygon)(pDrawable, pGC, shape, mode, npt, ppt);
+ : damageReportPostOp (pDrawable);
+ : DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
+ :}
+ :
+ :
+ :static void
+ :damagePolyFillRect(DrawablePtr pDrawable,
+ : GCPtr pGC,
+ : int nRects,
+ : xRectangle *pRects)
+ 2 0.0022 :{ /* damagePolyFillRect total: 17 0.0185 */
+ 2 0.0022 : DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
+ 2 0.0022 : if (nRects && checkGCDamage (pDrawable, pGC))
+ : {
+ : BoxRec box;
+ : xRectangle *pRectsTmp = pRects;
+ : int nRectsTmp = nRects;
+ :
+ : box.x1 = pRectsTmp->x;
+ : box.x2 = box.x1 + pRectsTmp->width;
+ : box.y1 = pRectsTmp->y;
+ : box.y2 = box.y1 + pRectsTmp->height;
+ :
+ 2 0.0022 : while(--nRectsTmp)
+ : {
+ : pRectsTmp++;
+ : if(box.x1 > pRectsTmp->x) box.x1 = pRectsTmp->x;
+ : if(box.x2 < (pRectsTmp->x + pRectsTmp->width))
+ : box.x2 = pRectsTmp->x + pRectsTmp->width;
+ 1 0.0011 : if(box.y1 > pRectsTmp->y) box.y1 = pRectsTmp->y;
+ : if(box.y2 < (pRectsTmp->y + pRectsTmp->height))
+ : box.y2 = pRectsTmp->y + pRectsTmp->height;
+ : }
+ :
+ 4 0.0044 : TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
+ 1 0.0011 : if(BOX_NOT_EMPTY(box))
+ 1 0.0011 : damageDamageBox (pDrawable, &box, pGC->subWindowMode);
+ : }
+ 1 0.0011 : (*pGC->ops->PolyFillRect)(pDrawable, pGC, nRects, pRects);
+ 1 0.0011 : damageReportPostOp (pDrawable);
+ : DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
+ :}
+ :
+ :
+ :static void
+ :damagePolyFillArc(DrawablePtr pDrawable,
+ : GCPtr pGC,
+ : int nArcs,
+ : xArc *pArcs)
+ :{
+ : DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
+ :
+ : if (nArcs && checkGCDamage (pDrawable, pGC))
+ : {
+ : BoxRec box;
+ : int nArcsTmp = nArcs;
+ : xArc *pArcsTmp = pArcs;
+ :
+ : box.x1 = pArcsTmp->x;
+ : box.x2 = box.x1 + pArcsTmp->width;
+ : box.y1 = pArcsTmp->y;
+ : box.y2 = box.y1 + pArcsTmp->height;
+ :
+ : while(--nArcsTmp)
+ : {
+ : pArcsTmp++;
+ : if(box.x1 > pArcsTmp->x)
+ : box.x1 = pArcsTmp->x;
+ : if(box.x2 < (pArcsTmp->x + pArcsTmp->width))
+ : box.x2 = pArcsTmp->x + pArcsTmp->width;
+ : if(box.y1 > pArcsTmp->y)
+ : box.y1 = pArcsTmp->y;
+ : if(box.y2 < (pArcsTmp->y + pArcsTmp->height))
+ : box.y2 = pArcsTmp->y + pArcsTmp->height;
+ : }
+ :
+ : TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
+ : if(BOX_NOT_EMPTY(box))
+ : damageDamageBox (pDrawable, &box, pGC->subWindowMode);
+ : }
+ : (*pGC->ops->PolyFillArc)(pDrawable, pGC, nArcs, pArcs);
+ : damageReportPostOp (pDrawable);
+ : DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
+ :}
+ :
+ :/*
+ : * general Poly/Image text function. Extract glyph information,
+ : * compute bounding box and remove cursor if it is overlapped.
+ : */
+ :
+ :static void
+ :damageDamageChars (DrawablePtr pDrawable,
+ : FontPtr font,
+ : int x,
+ : int y,
+ : unsigned int n,
+ : CharInfoPtr *charinfo,
+ : Bool imageblt,
+ : int subWindowMode)
+ :{
+ : ExtentInfoRec extents;
+ : BoxRec box;
+ :
+ : QueryGlyphExtents(font, charinfo, n, &extents);
+ : if (imageblt)
+ : {
+ : if (extents.overallWidth > extents.overallRight)
+ : extents.overallRight = extents.overallWidth;
+ : if (extents.overallWidth < extents.overallLeft)
+ : extents.overallLeft = extents.overallWidth;
+ : if (extents.overallLeft > 0)
+ : extents.overallLeft = 0;
+ : if (extents.fontAscent > extents.overallAscent)
+ : extents.overallAscent = extents.fontAscent;
+ : if (extents.fontDescent > extents.overallDescent)
+ : extents.overallDescent = extents.fontDescent;
+ : }
+ : box.x1 = x + extents.overallLeft;
+ : box.y1 = y - extents.overallAscent;
+ : box.x2 = x + extents.overallRight;
+ : box.y2 = y + extents.overallDescent;
+ : damageDamageBox (pDrawable, &box, subWindowMode);
+ :}
+ :
+ :/*
+ : * values for textType:
+ : */
+ :#define TT_POLY8 0
+ :#define TT_IMAGE8 1
+ :#define TT_POLY16 2
+ :#define TT_IMAGE16 3
+ :
+ :static int
+ :damageText (DrawablePtr pDrawable,
+ : GCPtr pGC,
+ : int x,
+ : int y,
+ : unsigned long count,
+ : char *chars,
+ : FontEncoding fontEncoding,
+ : Bool textType)
+ :{
+ : CharInfoPtr *charinfo;
+ : CharInfoPtr *info;
+ : unsigned long i;
+ : unsigned int n;
+ : int w;
+ : Bool imageblt;
+ :
+ : imageblt = (textType == TT_IMAGE8) || (textType == TT_IMAGE16);
+ :
+ : charinfo = (CharInfoPtr *) ALLOCATE_LOCAL(count * sizeof(CharInfoPtr));
+ : if (!charinfo)
+ : return x;
+ :
+ : GetGlyphs(pGC->font, count, (unsigned char *)chars,
+ : fontEncoding, &i, charinfo);
+ : n = (unsigned int)i;
+ : w = 0;
+ : if (!imageblt)
+ : for (info = charinfo; i--; info++)
+ : w += (*info)->metrics.characterWidth;
+ :
+ : if (n != 0) {
+ : damageDamageChars (pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y, n,
+ : charinfo, imageblt, pGC->subWindowMode);
+ : if (imageblt)
+ : (*pGC->ops->ImageGlyphBlt)(pDrawable, pGC, x, y, n, charinfo,
+ : FONTGLYPHS(pGC->font));
+ : else
+ : (*pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, n, charinfo,
+ : FONTGLYPHS(pGC->font));
+ : }
+ : DEALLOCATE_LOCAL(charinfo);
+ : return x + w;
+ :}
+ :
+ :static int
+ :damagePolyText8(DrawablePtr pDrawable,
+ : GCPtr pGC,
+ : int x,
+ : int y,
+ : int count,
+ : char *chars)
+ :{
+ : DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
+ :
+ : if (checkGCDamage (pDrawable, pGC))
+ : x = damageText (pDrawable, pGC, x, y, (unsigned long) count, chars,
+ : Linear8Bit, TT_POLY8);
+ : else
+ : x = (*pGC->ops->PolyText8)(pDrawable, pGC, x, y, count, chars);
+ : damageReportPostOp (pDrawable);
+ : DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
+ : return x;
+ :}
+ :
+ :static int
+ :damagePolyText16(DrawablePtr pDrawable,
+ : GCPtr pGC,
+ : int x,
+ : int y,
+ : int count,
+ : unsigned short *chars)
+ :{
+ : DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
+ :
+ : if (checkGCDamage (pDrawable, pGC))
+ : x = damageText (pDrawable, pGC, x, y, (unsigned long) count, (char *) chars,
+ : FONTLASTROW(pGC->font) == 0 ? Linear16Bit : TwoD16Bit,
+ : TT_POLY16);
+ : else
+ : x = (*pGC->ops->PolyText16)(pDrawable, pGC, x, y, count, chars);
+ : damageReportPostOp (pDrawable);
+ : DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
+ : return x;
+ :}
+ :
+ :static void
+ :damageImageText8(DrawablePtr pDrawable,
+ : GCPtr pGC,
+ : int x,
+ : int y,
+ : int count,
+ : char *chars)
+ :{
+ : DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
+ :
+ : if (checkGCDamage (pDrawable, pGC))
+ : damageText (pDrawable, pGC, x, y, (unsigned long) count, chars,
+ : Linear8Bit, TT_IMAGE8);
+ : else
+ : (*pGC->ops->ImageText8)(pDrawable, pGC, x, y, count, chars);
+ : damageReportPostOp (pDrawable);
+ : DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
+ :}
+ :
+ :static void
+ :damageImageText16(DrawablePtr pDrawable,
+ : GCPtr pGC,
+ : int x,
+ : int y,
+ : int count,
+ : unsigned short *chars)
+ :{
+ : DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
+ :
+ : if (checkGCDamage (pDrawable, pGC))
+ : damageText (pDrawable, pGC, x, y, (unsigned long) count, (char *) chars,
+ : FONTLASTROW(pGC->font) == 0 ? Linear16Bit : TwoD16Bit,
+ : TT_IMAGE16);
+ : else
+ : (*pGC->ops->ImageText16)(pDrawable, pGC, x, y, count, chars);
+ : damageReportPostOp (pDrawable);
+ : DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
+ :}
+ :
+ :
+ :static void
+ :damageImageGlyphBlt(DrawablePtr pDrawable,
+ : GCPtr pGC,
+ : int x,
+ : int y,
+ : unsigned int nglyph,
+ : CharInfoPtr *ppci,
+ : pointer pglyphBase)
+ :{
+ : DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
+ : damageDamageChars (pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y,
+ : nglyph, ppci, TRUE, pGC->subWindowMode);
+ : (*pGC->ops->ImageGlyphBlt)(pDrawable, pGC, x, y, nglyph,
+ : ppci, pglyphBase);
+ : damageReportPostOp (pDrawable);
+ : DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
+ :}
+ :
+ :static void
+ :damagePolyGlyphBlt(DrawablePtr pDrawable,
+ : GCPtr pGC,
+ : int x,
+ : int y,
+ : unsigned int nglyph,
+ : CharInfoPtr *ppci,
+ : pointer pglyphBase)
+ :{
+ : DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
+ : damageDamageChars (pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y,
+ : nglyph, ppci, FALSE, pGC->subWindowMode);
+ : (*pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, nglyph,
+ : ppci, pglyphBase);
+ : damageReportPostOp (pDrawable);
+ : DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
+ :}
+ :
+ :static void
+ :damagePushPixels(GCPtr pGC,
+ : PixmapPtr pBitMap,
+ : DrawablePtr pDrawable,
+ : int dx,
+ : int dy,
+ : int xOrg,
+ : int yOrg)
+ :{
+ : DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
+ : if(checkGCDamage (pDrawable, pGC))
+ : {
+ : BoxRec box;
+ :
+ : box.x1 = xOrg;
+ : box.y1 = yOrg;
+ :
+ : if(!pGC->miTranslate) {
+ : box.x1 += pDrawable->x;
+ : box.y1 += pDrawable->y;
+ : }
+ :
+ : box.x2 = box.x1 + dx;
+ : box.y2 = box.y1 + dy;
+ :
+ : TRIM_BOX(box, pGC);
+ : if(BOX_NOT_EMPTY(box))
+ : damageDamageBox (pDrawable, &box, pGC->subWindowMode);
+ : }
+ : (*pGC->ops->PushPixels)(pGC, pBitMap, pDrawable, dx, dy, xOrg, yOrg);
+ : damageReportPostOp (pDrawable);
+ : DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
+ :}
+ :
+ :static void
+ :damageRemoveDamage (DamagePtr *pPrev, DamagePtr pDamage)
+ 1 0.0011 :{ /* damageRemoveDamage total: 2 0.0022 */
+ : while (*pPrev)
+ : {
+ : if (*pPrev == pDamage)
+ : {
+ : *pPrev = pDamage->pNext;
+ : return;
+ : }
+ : pPrev = &(*pPrev)->pNext;
+ : }
+ :#if DAMAGE_VALIDATE_ENABLE
+ : ErrorF ("Damage not on list\n");
+ : abort ();
+ :#endif
+ 1 0.0011 :}
+ :
+ :static void
+ :damageInsertDamage (DamagePtr *pPrev, DamagePtr pDamage)
+ 1 0.0011 :{ /* damageInsertDamage total: 1 0.0011 */
+ :#if DAMAGE_VALIDATE_ENABLE
+ : DamagePtr pOld;
+ :
+ : for (pOld = *pPrev; pOld; pOld = pOld->pNext)
+ : if (pOld == pDamage) {
+ : ErrorF ("Damage already on list\n");
+ : abort ();
+ : }
+ :#endif
+ : pDamage->pNext = *pPrev;
+ : *pPrev = pDamage;
+ :}
+ :
+ :static Bool
+ :damageDestroyPixmap (PixmapPtr pPixmap)
+ 3 0.0033 :{ /* damageDestroyPixmap total: 15 0.0163 */
+ : ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ 2 0.0022 : damageScrPriv(pScreen);
+ :
+ : if (pPixmap->refcnt == 1)
+ : {
+ 1 0.0011 : DamagePtr *pPrev = getPixmapDamageRef (pPixmap);
+ : DamagePtr pDamage;
+ :
+ : while ((pDamage = *pPrev))
+ : {
+ : damageRemoveDamage (pPrev, pDamage);
+ : if (!pDamage->isWindow)
+ : DamageDestroy (pDamage);
+ : }
+ : }
+ 3 0.0033 : unwrap (pScrPriv, pScreen, DestroyPixmap);
+ 2 0.0022 : (*pScreen->DestroyPixmap) (pPixmap);
+ 3 0.0033 : wrap (pScrPriv, pScreen, DestroyPixmap, damageDestroyPixmap);
+ : return TRUE;
+ 1 0.0011 :}
+ :
+ :static void
+ :damagePaintWindow(WindowPtr pWindow,
+ : RegionPtr prgn,
+ : int what)
+ :{
+ : ScreenPtr pScreen = pWindow->drawable.pScreen;
+ : damageScrPriv(pScreen);
+ :
+ : /*
+ : * Painting background none doesn't actually *do* anything, so
+ : * no damage is recorded
+ : */
+ : if ((what != PW_BACKGROUND || pWindow->backgroundState != None) &&
+ : getWindowDamage (pWindow))
+ : damageDamageRegion (&pWindow->drawable, prgn, FALSE, -1);
+ : if(what == PW_BACKGROUND) {
+ : unwrap (pScrPriv, pScreen, PaintWindowBackground);
+ : (*pScreen->PaintWindowBackground) (pWindow, prgn, what);
+ : damageReportPostOp (&pWindow->drawable);
+ : wrap (pScrPriv, pScreen, PaintWindowBackground, damagePaintWindow);
+ : } else {
+ : unwrap (pScrPriv, pScreen, PaintWindowBorder);
+ : (*pScreen->PaintWindowBorder) (pWindow, prgn, what);
+ : damageReportPostOp (&pWindow->drawable);
+ : wrap (pScrPriv, pScreen, PaintWindowBorder, damagePaintWindow);
+ : }
+ :}
+ :
+ :
+ :static void
+ :damageCopyWindow(WindowPtr pWindow,
+ : DDXPointRec ptOldOrg,
+ : RegionPtr prgnSrc)
+ :{
+ : ScreenPtr pScreen = pWindow->drawable.pScreen;
+ : damageScrPriv(pScreen);
+ :
+ : if (getWindowDamage (pWindow))
+ : {
+ : int dx = pWindow->drawable.x - ptOldOrg.x;
+ : int dy = pWindow->drawable.y - ptOldOrg.y;
+ :
+ : /*
+ : * The region comes in source relative, but the damage occurs
+ : * at the destination location. Translate back and forth.
+ : */
+ : REGION_TRANSLATE (pScreen, prgnSrc, dx, dy);
+ : damageDamageRegion (&pWindow->drawable, prgnSrc, FALSE, -1);
+ : REGION_TRANSLATE (pScreen, prgnSrc, -dx, -dy);
+ : }
+ : unwrap (pScrPriv, pScreen, CopyWindow);
+ : (*pScreen->CopyWindow) (pWindow, ptOldOrg, prgnSrc);
+ : damageReportPostOp (&pWindow->drawable);
+ : wrap (pScrPriv, pScreen, CopyWindow, damageCopyWindow);
+ :}
+ :
+ :static GCOps damageGCOps = {
+ : damageFillSpans, damageSetSpans,
+ : damagePutImage, damageCopyArea,
+ : damageCopyPlane, damagePolyPoint,
+ : damagePolylines, damagePolySegment,
+ : damagePolyRectangle, damagePolyArc,
+ : damageFillPolygon, damagePolyFillRect,
+ : damagePolyFillArc, damagePolyText8,
+ : damagePolyText16, damageImageText8,
+ : damageImageText16, damageImageGlyphBlt,
+ : damagePolyGlyphBlt, damagePushPixels,
+ : {NULL} /* devPrivate */
+ :};
+ :
+ :static void
+ :damageRestoreAreas (PixmapPtr pPixmap,
+ : RegionPtr prgn,
+ : int xorg,
+ : int yorg,
+ : WindowPtr pWindow)
+ :{
+ : ScreenPtr pScreen = pWindow->drawable.pScreen;
+ : damageScrPriv(pScreen);
+ :
+ : damageDamageRegion (&pWindow->drawable, prgn, FALSE, -1);
+ : unwrap (pScrPriv, pScreen, BackingStoreFuncs.RestoreAreas);
+ : (*pScreen->BackingStoreFuncs.RestoreAreas) (pPixmap, prgn,
+ : xorg, yorg, pWindow);
+ : damageReportPostOp (&pWindow->drawable);
+ : wrap (pScrPriv, pScreen, BackingStoreFuncs.RestoreAreas,
+ : damageRestoreAreas);
+ :}
+ :
+ :static void
+ :damageSetWindowPixmap (WindowPtr pWindow, PixmapPtr pPixmap)
+ :{
+ : DamagePtr pDamage;
+ : ScreenPtr pScreen = pWindow->drawable.pScreen;
+ : damageScrPriv(pScreen);
+ :
+ : if ((pDamage = damageGetWinPriv(pWindow)))
+ : {
+ : PixmapPtr pOldPixmap = (*pScreen->GetWindowPixmap) (pWindow);
+ : DamagePtr *pPrev = getPixmapDamageRef(pOldPixmap);
+ :
+ : while (pDamage)
+ : {
+ : damageRemoveDamage (pPrev, pDamage);
+ : pDamage = pDamage->pNextWin;
+ : }
+ : }
+ : unwrap (pScrPriv, pScreen, SetWindowPixmap);
+ : (*pScreen->SetWindowPixmap) (pWindow, pPixmap);
+ : wrap (pScrPriv, pScreen, SetWindowPixmap, damageSetWindowPixmap);
+ : if ((pDamage = damageGetWinPriv(pWindow)))
+ : {
+ : DamagePtr *pPrev = getPixmapDamageRef(pPixmap);
+ :
+ : while (pDamage)
+ : {
+ : damageInsertDamage (pPrev, pDamage);
+ : pDamage = pDamage->pNextWin;
+ : }
+ : }
+ :}
+ :
+ :static Bool
+ :damageDestroyWindow (WindowPtr pWindow)
+ :{
+ : DamagePtr pDamage;
+ : ScreenPtr pScreen = pWindow->drawable.pScreen;
+ : Bool ret;
+ : damageScrPriv(pScreen);
+ :
+ : while ((pDamage = damageGetWinPriv(pWindow)))
+ : {
+ : DamageUnregister (&pWindow->drawable, pDamage);
+ : DamageDestroy (pDamage);
+ : }
+ : unwrap (pScrPriv, pScreen, DestroyWindow);
+ : ret = (*pScreen->DestroyWindow) (pWindow);
+ : wrap (pScrPriv, pScreen, DestroyWindow, damageDestroyWindow);
+ : return ret;
+ :}
+ :
+ :static Bool
+ :damageCloseScreen (int i, ScreenPtr pScreen)
+ :{
+ : damageScrPriv(pScreen);
+ :
+ : unwrap (pScrPriv, pScreen, DestroyPixmap);
+ : unwrap (pScrPriv, pScreen, CreateGC);
+ : unwrap (pScrPriv, pScreen, PaintWindowBackground);
+ : unwrap (pScrPriv, pScreen, PaintWindowBorder);
+ : unwrap (pScrPriv, pScreen, CopyWindow);
+ : unwrap (pScrPriv, pScreen, CloseScreen);
+ : unwrap (pScrPriv, pScreen, BackingStoreFuncs.RestoreAreas);
+ : xfree (pScrPriv);
+ : return (*pScreen->CloseScreen) (i, pScreen);
+ :}
+ :
+ :Bool
+ :DamageSetup (ScreenPtr pScreen)
+ :{
+ : DamageScrPrivPtr pScrPriv;
+ :#ifdef RENDER
+ : PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
+ :#endif
+ :
+ : if (damageGeneration != serverGeneration)
+ : {
+ : damageScrPrivateIndex = AllocateScreenPrivateIndex ();
+ : if (damageScrPrivateIndex == -1)
+ : return FALSE;
+ : damageGCPrivateIndex = AllocateGCPrivateIndex ();
+ : if (damageGCPrivateIndex == -1)
+ : return FALSE;
+ : damagePixPrivateIndex = AllocatePixmapPrivateIndex ();
+ : if (damagePixPrivateIndex == -1)
+ : return FALSE;
+ : damageWinPrivateIndex = AllocateWindowPrivateIndex ();
+ : if (damageWinPrivateIndex == -1)
+ : return FALSE;
+ : damageGeneration = serverGeneration;
+ : }
+ : if (pScreen->devPrivates[damageScrPrivateIndex].ptr)
+ : return TRUE;
+ :
+ : if (!AllocateGCPrivate (pScreen, damageGCPrivateIndex, sizeof (DamageGCPrivRec)))
+ : return FALSE;
+ : if (!AllocatePixmapPrivate (pScreen, damagePixPrivateIndex, 0))
+ : return FALSE;
+ : if (!AllocateWindowPrivate (pScreen, damageWinPrivateIndex, 0))
+ : return FALSE;
+ :
+ : pScrPriv = (DamageScrPrivPtr) xalloc (sizeof (DamageScrPrivRec));
+ : if (!pScrPriv)
+ : return FALSE;
+ :
+ : pScrPriv->internalLevel = 0;
+ : pScrPriv->pScreenDamage = 0;
+ :
+ : wrap (pScrPriv, pScreen, DestroyPixmap, damageDestroyPixmap);
+ : wrap (pScrPriv, pScreen, CreateGC, damageCreateGC);
+ : wrap (pScrPriv, pScreen, PaintWindowBackground, damagePaintWindow);
+ : wrap (pScrPriv, pScreen, PaintWindowBorder, damagePaintWindow);
+ : wrap (pScrPriv, pScreen, DestroyWindow, damageDestroyWindow);
+ : wrap (pScrPriv, pScreen, SetWindowPixmap, damageSetWindowPixmap);
+ : wrap (pScrPriv, pScreen, CopyWindow, damageCopyWindow);
+ : wrap (pScrPriv, pScreen, CloseScreen, damageCloseScreen);
+ : wrap (pScrPriv, pScreen, BackingStoreFuncs.RestoreAreas,
+ : damageRestoreAreas);
+ :#ifdef RENDER
+ : if (ps) {
+ : wrap (pScrPriv, ps, Glyphs, damageGlyphs);
+ : wrap (pScrPriv, ps, Composite, damageComposite);
+ : }
+ :#endif
+ :
+ : pScreen->devPrivates[damageScrPrivateIndex].ptr = (pointer) pScrPriv;
+ : return TRUE;
+ :}
+ :
+ :DamagePtr
+ :DamageCreate (DamageReportFunc damageReport,
+ : DamageDestroyFunc damageDestroy,
+ : DamageReportLevel damageLevel,
+ : Bool isInternal,
+ : ScreenPtr pScreen,
+ : void *closure)
+ 2 0.0022 :{ /* DamageCreate total: 12 0.0131 */
+ : DamagePtr pDamage;
+ :
+ 4 0.0044 : pDamage = xalloc (sizeof (DamageRec));
+ 1 0.0011 : if (!pDamage)
+ : return 0;
+ : pDamage->pNext = 0;
+ : pDamage->pNextWin = 0;
+ 3 0.0033 : REGION_NULL(pScreen, &pDamage->damage);
+ : REGION_NULL(pScreen, &pDamage->pendingDamage);
+ :
+ : pDamage->damageLevel = damageLevel;
+ 1 0.0011 : pDamage->isInternal = isInternal;
+ : pDamage->closure = closure;
+ : pDamage->isWindow = FALSE;
+ : pDamage->pDrawable = 0;
+ : pDamage->reportAfter = FALSE;
+ :
+ : pDamage->damageReport = damageReport;
+ : pDamage->damageDestroy = damageDestroy;
+ : return pDamage;
+ 1 0.0011 :}
+ :
+ :void
+ :DamageRegister (DrawablePtr pDrawable,
+ : DamagePtr pDamage)
+ 1 0.0011 :{ /* DamageRegister total: 1 0.0011 */
+ : if (pDrawable->type == DRAWABLE_WINDOW)
+ : {
+ : WindowPtr pWindow = (WindowPtr) pDrawable;
+ : winDamageRef(pWindow);
+ :
+ :#if DAMAGE_VALIDATE_ENABLE
+ : DamagePtr pOld;
+ :
+ : for (pOld = *pPrev; pOld; pOld = pOld->pNextWin)
+ : if (pOld == pDamage) {
+ : ErrorF ("Damage already on window list\n");
+ : abort ();
+ : }
+ :#endif
+ : pDamage->pNextWin = *pPrev;
+ : *pPrev = pDamage;
+ : pDamage->isWindow = TRUE;
+ : }
+ : else
+ : pDamage->isWindow = FALSE;
+ : pDamage->pDrawable = pDrawable;
+ : damageInsertDamage (getDrawableDamageRef (pDrawable), pDamage);
+ :}
+ :
+ :void
+ :DamageDrawInternal (ScreenPtr pScreen, Bool enable)
+ :{
+ : damageScrPriv (pScreen);
+ :
+ : pScrPriv->internalLevel += enable ? 1 : -1;
+ :}
+ :
+ :void
+ :DamageUnregister (DrawablePtr pDrawable,
+ : DamagePtr pDamage)
+ :{
+ : if (pDrawable->type == DRAWABLE_WINDOW)
+ : {
+ : WindowPtr pWindow = (WindowPtr) pDrawable;
+ : winDamageRef (pWindow);
+ :#if DAMAGE_VALIDATE_ENABLE
+ : int found = 0;
+ :#endif
+ :
+ : while (*pPrev)
+ : {
+ : if (*pPrev == pDamage)
+ : {
+ : *pPrev = pDamage->pNextWin;
+ :#if DAMAGE_VALIDATE_ENABLE
+ : found = 1;
+ :#endif
+ : break;
+ : }
+ : pPrev = &(*pPrev)->pNextWin;
+ : }
+ :#if DAMAGE_VALIDATE_ENABLE
+ : if (!found) {
+ : ErrorF ("Damage not on window list\n");
+ : abort ();
+ : }
+ :#endif
+ : }
+ : pDamage->pDrawable = 0;
+ : damageRemoveDamage (getDrawableDamageRef (pDrawable), pDamage);
+ :}
+ :
+ :void
+ :DamageDestroy (DamagePtr pDamage)
+ 1 0.0011 :{ /* DamageDestroy total: 3 0.0033 */
+ : if (pDamage->damageDestroy)
+ : (*pDamage->damageDestroy) (pDamage, pDamage->closure);
+ 2 0.0022 : REGION_UNINIT (pDamage->pDrawable->pScreen, &pDamage->damage);
+ : REGION_UNINIT (pDamage->pDrawable->pScreen, &pDamage->pendingDamage);
+ : xfree (pDamage);
+ :}
+ :
+ :Bool
+ :DamageSubtract (DamagePtr pDamage,
+ : const RegionPtr pRegion)
+ :{
+ : RegionPtr pClip;
+ : RegionRec pixmapClip;
+ : DrawablePtr pDrawable = pDamage->pDrawable;
+ :
+ : REGION_SUBTRACT (pDrawable->pScreen, &pDamage->damage, &pDamage->damage, pRegion);
+ : if (pDrawable)
+ : {
+ : if (pDrawable->type == DRAWABLE_WINDOW)
+ : pClip = &((WindowPtr) pDrawable)->borderClip;
+ : else
+ : {
+ : BoxRec box;
+ :
+ : box.x1 = pDrawable->x;
+ : box.y1 = pDrawable->y;
+ : box.x2 = pDrawable->x + pDrawable->width;
+ : box.y2 = pDrawable->y + pDrawable->height;
+ : REGION_INIT (pDrawable->pScreen, &pixmapClip, &box, 1);
+ : pClip = &pixmapClip;
+ : }
+ : REGION_TRANSLATE (pDrawable->pScreen, &pDamage->damage, pDrawable->x, pDrawable->y);
+ : REGION_INTERSECT (pDrawable->pScreen, &pDamage->damage, &pDamage->damage, pClip);
+ : REGION_TRANSLATE (pDrawable->pScreen, &pDamage->damage, -pDrawable->x, -pDrawable->y);
+ : if (pDrawable->type != DRAWABLE_WINDOW)
+ : REGION_UNINIT(pDrawable->pScreen, &pixmapClip);
+ : }
+ : return REGION_NOTEMPTY (pDrawable->pScreen, &pDamage->damage);
+ :}
+ :
+ :void
+ :DamageEmpty (DamagePtr pDamage)
+ 1 0.0011 :{ /* DamageEmpty total: 3 0.0033 */
+ 1 0.0011 : REGION_EMPTY (pDamage->pDrawable->pScreen, &pDamage->damage);
+ 1 0.0011 :}
+ :
+ :RegionPtr
+ :DamageRegion (DamagePtr pDamage)
+ 7 0.0076 :{ /* DamageRegion total: 10 0.0109 */
+ : return &pDamage->damage;
+ 3 0.0033 :}
+ :
+ :_X_EXPORT void
+ :DamageDamageRegion (DrawablePtr pDrawable,
+ : RegionPtr pRegion)
+ :{
+ : damageDamageRegion (pDrawable, pRegion, FALSE, -1);
+ :
+ : /* Go back and report this damage for DamagePtrs with reportAfter set, since
+ : * this call isn't part of an in-progress drawing op in the call chain and
+ : * the DDX probably just wants to know about it right away.
+ : */
+ : damageReportPostOp (pDrawable);
+ :}
+ :
+ :void
+ :DamageSetReportAfterOp (DamagePtr pDamage, Bool reportAfter)
+ 4 0.0044 :{ /* DamageSetReportAfterOp total: 5 0.0054 */
+ : pDamage->reportAfter = reportAfter;
+ 1 0.0011 :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/driver/xf86-video-intel/src/i830_driver.c"
+ *
+ * 154 0.1678
+ */
+
+
+ :/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i830_driver.c,v 1.50 2004/02/20 00:06:00 alanh Exp $ */
+ :/**************************************************************************
+ :
+ :Copyright 2001 VA Linux Systems Inc., Fremont, California.
+ :Copyright © 2002 by David Dawes
+ :
+ :All Rights Reserved.
+ :
+ :Permission is hereby granted, free of charge, to any person obtaining a
+ :copy of this software and associated documentation files (the "Software"),
+ :to deal in the Software without restriction, including without limitation
+ :on the rights to use, copy, modify, merge, publish, distribute, sub
+ :license, and/or sell copies of the Software, and to permit persons to whom
+ :the Software is furnished to do so, subject to the following conditions:
+ :
+ :The above copyright notice and this permission notice (including the next
+ :paragraph) shall be included in all copies or substantial portions of the
+ :Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ :IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ :FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ :THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ :DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ :OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ :USE OR OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :**************************************************************************/
+ :
+ :/*
+ : * Reformatted with GNU indent (2.2.8), using the following options:
+ : *
+ : * -bad -bap -c41 -cd0 -ncdb -ci6 -cli0 -cp0 -ncs -d0 -di3 -i3 -ip3 -l78
+ : * -lp -npcs -psl -sob -ss -br -ce -sc -hnl
+ : *
+ : * This provides a good match with the original i810 code and preferred
+ : * XFree86 formatting conventions.
+ : *
+ : * When editing this driver, please follow the existing formatting, and edit
+ : * with <TAB> characters expanded at 8-column intervals.
+ : */
+ :
+ :/*
+ : * Authors: Jeff Hartmann <jhartmann@valinux.com>
+ : * Abraham van der Merwe <abraham@2d3d.co.za>
+ : * David Dawes <dawes@xfree86.org>
+ : * Alan Hourihane <alanh@tungstengraphics.com>
+ : */
+ :
+ :/*
+ : * Mode handling is based on the VESA driver written by:
+ : * Paulo César Pereira de Andrade <pcpa@conectiva.com.br>
+ : */
+ :
+ :/*
+ : * Changes:
+ : *
+ : * 23/08/2001 Abraham van der Merwe <abraham@2d3d.co.za>
+ : * - Fixed display timing bug (mode information for some
+ : * modes were not initialized correctly)
+ : * - Added workarounds for GTT corruptions (I don't adjust
+ : * the pitches for 1280x and 1600x modes so we don't
+ : * need extra memory)
+ : * - The code will now default to 60Hz if LFP is connected
+ : * - Added different refresh rate setting code to work
+ : * around 0x4f02 BIOS bug
+ : * - BIOS workaround for some mode sets (I use legacy BIOS
+ : * calls for setting those)
+ : * - Removed 0x4f04, 0x01 (save state) BIOS call which causes
+ : * LFP to malfunction (do some house keeping and restore
+ : * modes ourselves instead - not perfect, but at least the
+ : * LFP is working now)
+ : * - Several other smaller bug fixes
+ : *
+ : * 06/09/2001 Abraham van der Merwe <abraham@2d3d.co.za>
+ : * - Preliminary local memory support (works without agpgart)
+ : * - DGA fixes (the code were still using i810 mode sets, etc.)
+ : * - agpgart fixes
+ : *
+ : * 18/09/2001
+ : * - Proper local memory support (should work correctly now
+ : * with/without agpgart module)
+ : * - more agpgart fixes
+ : * - got rid of incorrect GTT adjustments
+ : *
+ : * 09/10/2001
+ : * - Changed the DPRINTF() variadic macro to an ANSI C compatible
+ : * version
+ : *
+ : * 10/10/2001
+ : * - Fixed DPRINTF_stub(). I forgot the __...__ macros in there
+ : * instead of the function arguments :P
+ : * - Added a workaround for the 1600x1200 bug (Text mode corrupts
+ : * when you exit from any 1600x1200 mode and 1280x1024@85Hz. I
+ : * suspect this is a BIOS bug (hence the 1280x1024@85Hz case)).
+ : * For now I'm switching to 800x600@60Hz then to 80x25 text mode
+ : * and then restoring the registers - very ugly indeed.
+ : *
+ : * 15/10/2001
+ : * - Improved 1600x1200 mode set workaround. The previous workaround
+ : * was causing mode set problems later on.
+ : *
+ : * 18/10/2001
+ : * - Fixed a bug in I830BIOSLeaveVT() which caused a bug when you
+ : * switched VT's
+ : */
+ :/*
+ : * 07/2002 David Dawes
+ : * - Add Intel(R) 855GM/852GM support.
+ : */
+ :/*
+ : * 07/2002 David Dawes
+ : * - Cleanup code formatting.
+ : * - Improve VESA mode selection, and fix refresh rate selection.
+ : * - Don't duplicate functions provided in 4.2 vbe modules.
+ : * - Don't duplicate functions provided in the vgahw module.
+ : * - Rewrite memory allocation.
+ : * - Rewrite initialisation and save/restore state handling.
+ : * - Decouple the i810 support from i830 and later.
+ : * - Remove various unnecessary hacks and workarounds.
+ : * - Fix an 845G problem with the ring buffer not in pre-allocated
+ : * memory.
+ : * - Fix screen blanking.
+ : * - Clear the screen at startup so you don't see the previous session.
+ : * - Fix some HW cursor glitches, and turn HW cursor off at VT switch
+ : * and exit.
+ : *
+ : * 08/2002 Keith Whitwell
+ : * - Fix DRI initialisation.
+ : *
+ : *
+ : * 08/2002 Alan Hourihane and David Dawes
+ : * - Add XVideo support.
+ : *
+ : *
+ : * 10/2002 David Dawes
+ : * - Add Intel(R) 865G support.
+ : *
+ : *
+ : * 01/2004 Alan Hourihane
+ : * - Add Intel(R) 915G support.
+ : * - Add Dual Head and Clone capabilities.
+ : * - Add lid status checking
+ : * - Fix Xvideo with high-res LFP's
+ : * - Add ARGB HW cursor support
+ : *
+ : * 05/2005 Alan Hourihane
+ : * - Add Intel(R) 945G support.
+ : *
+ : * 09/2005 Alan Hourihane
+ : * - Add Intel(R) 945GM support.
+ : *
+ : * 10/2005 Alan Hourihane, Keith Whitwell, Brian Paul
+ : * - Added Rotation support
+ : *
+ : * 12/2005 Alan Hourihane, Keith Whitwell
+ : * - Add Intel(R) 965G support.
+ : */
+ :
+ :#ifdef HAVE_CONFIG_H
+ :#include "config.h"
+ :#endif
+ :
+ :#ifndef PRINT_MODE_INFO
+ :#define PRINT_MODE_INFO 0
+ :#endif
+ :
+ :#include <assert.h>
+ :#include <string.h>
+ :#include <stdio.h>
+ :#include <unistd.h>
+ :#include <stdlib.h>
+ :#include <stdio.h>
+ :
+ :#include "xf86.h"
+ :#include "xf86_OSproc.h"
+ :#include "xf86Resources.h"
+ :#include "xf86RAC.h"
+ :#include "xf86cmap.h"
+ :#include "compiler.h"
+ :#include "mibstore.h"
+ :#include "vgaHW.h"
+ :#include "mipointer.h"
+ :#include "micmap.h"
+ :#include "shadowfb.h"
+ :#include <X11/extensions/randr.h>
+ :#include "fb.h"
+ :#include "miscstruct.h"
+ :#include "dixstruct.h"
+ :#include "xf86xv.h"
+ :#include <X11/extensions/Xv.h>
+ :#include "vbe.h"
+ :#include "shadow.h"
+ :#include "i830.h"
+ :#include "i830_display.h"
+ :#include "i830_debug.h"
+ :#include "i830_bios.h"
+ :
+ :#ifdef XF86DRI
+ :#include "dri.h"
+ :#include <sys/ioctl.h>
+ :#include <errno.h>
+ :#endif
+ :
+ :#ifdef I830_USE_EXA
+ :const char *I830exaSymbols[] = {
+ : "exaGetVersion",
+ : "exaDriverInit",
+ : "exaDriverFini",
+ : "exaOffscreenAlloc",
+ : "exaOffscreenFree",
+ : "exaWaitSync",
+ : NULL
+ :};
+ :#endif
+ :
+ :#define BIT(x) (1 << (x))
+ :#define MAX(a,b) ((a) > (b) ? (a) : (b))
+ :#define NB_OF(x) (sizeof (x) / sizeof (*x))
+ :
+ :/* *INDENT-OFF* */
+ :static SymTabRec I830Chipsets[] = {
+ : {PCI_CHIP_I830_M, "i830"},
+ : {PCI_CHIP_845_G, "845G"},
+ : {PCI_CHIP_I855_GM, "852GM/855GM"},
+ : {PCI_CHIP_I865_G, "865G"},
+ : {PCI_CHIP_I915_G, "915G"},
+ : {PCI_CHIP_E7221_G, "E7221 (i915)"},
+ : {PCI_CHIP_I915_GM, "915GM"},
+ : {PCI_CHIP_I945_G, "945G"},
+ : {PCI_CHIP_I945_GM, "945GM"},
+ : {PCI_CHIP_I945_GME, "945GME"},
+ : {PCI_CHIP_I965_G, "965G"},
+ : {PCI_CHIP_I965_G_1, "965G"},
+ : {PCI_CHIP_I965_Q, "965Q"},
+ : {PCI_CHIP_I946_GZ, "946GZ"},
+ : {PCI_CHIP_I965_GM, "965GM"},
+ : {PCI_CHIP_I965_GME, "965GME/GLE"},
+ : {PCI_CHIP_G33_G, "G33"},
+ : {PCI_CHIP_Q35_G, "Q35"},
+ : {PCI_CHIP_Q33_G, "Q33"},
+ : {-1, NULL}
+ :};
+ :
+ :static PciChipsets I830PciChipsets[] = {
+ : {PCI_CHIP_I830_M, PCI_CHIP_I830_M, RES_SHARED_VGA},
+ : {PCI_CHIP_845_G, PCI_CHIP_845_G, RES_SHARED_VGA},
+ : {PCI_CHIP_I855_GM, PCI_CHIP_I855_GM, RES_SHARED_VGA},
+ : {PCI_CHIP_I865_G, PCI_CHIP_I865_G, RES_SHARED_VGA},
+ : {PCI_CHIP_I915_G, PCI_CHIP_I915_G, RES_SHARED_VGA},
+ : {PCI_CHIP_E7221_G, PCI_CHIP_E7221_G, RES_SHARED_VGA},
+ : {PCI_CHIP_I915_GM, PCI_CHIP_I915_GM, RES_SHARED_VGA},
+ : {PCI_CHIP_I945_G, PCI_CHIP_I945_G, RES_SHARED_VGA},
+ : {PCI_CHIP_I945_GM, PCI_CHIP_I945_GM, RES_SHARED_VGA},
+ : {PCI_CHIP_I945_GME, PCI_CHIP_I945_GME, RES_SHARED_VGA},
+ : {PCI_CHIP_I965_G, PCI_CHIP_I965_G, RES_SHARED_VGA},
+ : {PCI_CHIP_I965_G_1, PCI_CHIP_I965_G_1, RES_SHARED_VGA},
+ : {PCI_CHIP_I965_Q, PCI_CHIP_I965_Q, RES_SHARED_VGA},
+ : {PCI_CHIP_I946_GZ, PCI_CHIP_I946_GZ, RES_SHARED_VGA},
+ : {PCI_CHIP_I965_GM, PCI_CHIP_I965_GM, RES_SHARED_VGA},
+ : {PCI_CHIP_I965_GME, PCI_CHIP_I965_GME, RES_SHARED_VGA},
+ : {PCI_CHIP_G33_G, PCI_CHIP_G33_G, RES_SHARED_VGA},
+ : {PCI_CHIP_Q35_G, PCI_CHIP_Q35_G, RES_SHARED_VGA},
+ : {PCI_CHIP_Q33_G, PCI_CHIP_Q33_G, RES_SHARED_VGA},
+ : {-1, -1, RES_UNDEFINED}
+ :};
+ :
+ :/*
+ : * Note: "ColorKey" is provided for compatibility with the i810 driver.
+ : * However, the correct option name is "VideoKey". "ColorKey" usually
+ : * refers to the tranparency key for 8+24 overlays, not for video overlays.
+ : */
+ :
+ :typedef enum {
+ :#if defined(I830_USE_XAA) && defined(I830_USE_EXA)
+ : OPTION_ACCELMETHOD,
+ :#endif
+ : OPTION_NOACCEL,
+ : OPTION_SW_CURSOR,
+ : OPTION_CACHE_LINES,
+ : OPTION_DRI,
+ : OPTION_PAGEFLIP,
+ : OPTION_XVIDEO,
+ : OPTION_VIDEO_KEY,
+ : OPTION_COLOR_KEY,
+ : OPTION_CHECKDEVICES,
+ : OPTION_MODEDEBUG,
+ :#ifdef XF86DRI_MM
+ : OPTION_INTELTEXPOOL,
+ : OPTION_INTELMMSIZE,
+ :#endif
+ : OPTION_TRIPLEBUFFER,
+ :} I830Opts;
+ :
+ :static OptionInfoRec I830Options[] = {
+ :#if defined(I830_USE_XAA) && defined(I830_USE_EXA)
+ : {OPTION_ACCELMETHOD, "AccelMethod", OPTV_ANYSTR, {0}, FALSE},
+ :#endif
+ : {OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE},
+ : {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE},
+ : {OPTION_CACHE_LINES, "CacheLines", OPTV_INTEGER, {0}, FALSE},
+ : {OPTION_DRI, "DRI", OPTV_BOOLEAN, {0}, TRUE},
+ : {OPTION_PAGEFLIP, "PageFlip", OPTV_BOOLEAN, {0}, FALSE},
+ : {OPTION_XVIDEO, "XVideo", OPTV_BOOLEAN, {0}, TRUE},
+ : {OPTION_COLOR_KEY, "ColorKey", OPTV_INTEGER, {0}, FALSE},
+ : {OPTION_VIDEO_KEY, "VideoKey", OPTV_INTEGER, {0}, FALSE},
+ : {OPTION_CHECKDEVICES, "CheckDevices",OPTV_BOOLEAN, {0}, FALSE},
+ : {OPTION_MODEDEBUG, "ModeDebug", OPTV_BOOLEAN, {0}, FALSE},
+ :#ifdef XF86DRI_MM
+ : {OPTION_INTELTEXPOOL,"Legacy3D", OPTV_BOOLEAN, {0}, FALSE},
+ : {OPTION_INTELMMSIZE, "AperTexSize", OPTV_INTEGER, {0}, FALSE},
+ :#endif
+ : {OPTION_TRIPLEBUFFER, "TripleBuffer", OPTV_BOOLEAN, {0}, FALSE},
+ : {-1, NULL, OPTV_NONE, {0}, FALSE}
+ :};
+ :/* *INDENT-ON* */
+ :
+ :const char *i830_output_type_names[] = {
+ : "Unused",
+ : "Analog",
+ : "DVO",
+ : "SDVO",
+ : "LVDS",
+ : "TVOUT",
+ :};
+ :
+ :static void i830AdjustFrame(int scrnIndex, int x, int y, int flags);
+ :static Bool I830CloseScreen(int scrnIndex, ScreenPtr pScreen);
+ :static Bool I830EnterVT(int scrnIndex, int flags);
+ :static CARD32 I830CheckDevicesTimer(OsTimerPtr timer, CARD32 now, pointer arg);
+ :static Bool SaveHWState(ScrnInfoPtr pScrn);
+ :static Bool RestoreHWState(ScrnInfoPtr pScrn);
+ :
+ :/* temporary */
+ :extern void xf86SetCursor(ScreenPtr pScreen, CursorPtr pCurs, int x, int y);
+ :
+ :#ifdef I830DEBUG
+ :void
+ :I830DPRINTF_stub(const char *filename, int line, const char *function,
+ : const char *fmt, ...)
+ :{
+ : va_list ap;
+ :
+ : ErrorF("\n##############################################\n"
+ : "*** In function %s, on line %d, in file %s ***\n",
+ : function, line, filename);
+ : va_start(ap, fmt);
+ : VErrorF(fmt, ap);
+ : va_end(ap);
+ : ErrorF("##############################################\n\n");
+ :}
+ :#else /* #ifdef I830DEBUG */
+ :void
+ :I830DPRINTF_stub(const char *filename, int line, const char *function,
+ : const char *fmt, ...)
+ :{
+ : /* do nothing */
+ :}
+ :#endif /* #ifdef I830DEBUG */
+ :
+ :/* Export I830 options to i830 driver where necessary */
+ :const OptionInfoRec *
+ :I830AvailableOptions(int chipid, int busid)
+ :{
+ : int i;
+ :
+ : for (i = 0; I830PciChipsets[i].PCIid > 0; i++) {
+ : if (chipid == I830PciChipsets[i].PCIid)
+ : return I830Options;
+ : }
+ : return NULL;
+ :}
+ :
+ :static Bool
+ :I830GetRec(ScrnInfoPtr pScrn)
+ :{
+ : I830Ptr pI830;
+ :
+ : if (pScrn->driverPrivate)
+ : return TRUE;
+ : pI830 = pScrn->driverPrivate = xnfcalloc(sizeof(I830Rec), 1);
+ : return TRUE;
+ :}
+ :
+ :static void
+ :I830FreeRec(ScrnInfoPtr pScrn)
+ :{
+ : I830Ptr pI830;
+ :
+ : if (!pScrn)
+ : return;
+ : if (!pScrn->driverPrivate)
+ : return;
+ :
+ : pI830 = I830PTR(pScrn);
+ :
+ : xfree(pScrn->driverPrivate);
+ : pScrn->driverPrivate = NULL;
+ :}
+ :
+ :static void
+ :I830ProbeDDC(ScrnInfoPtr pScrn, int index)
+ :{
+ : vbeInfoPtr pVbe;
+ :
+ : /* The vbe module gets loaded in PreInit(), so no need to load it here. */
+ :
+ : pVbe = VBEInit(NULL, index);
+ : ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
+ :}
+ :
+ :static int
+ :I830DetectMemory(ScrnInfoPtr pScrn)
+ :{
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : PCITAG bridge;
+ : CARD16 gmch_ctrl;
+ : int memsize = 0, gtt_size;
+ : int range;
+ :#if 0
+ : VbeInfoBlock *vbeInfo;
+ :#endif
+ :
+ : bridge = pciTag(0, 0, 0); /* This is always the host bridge */
+ : gmch_ctrl = pciReadWord(bridge, I830_GMCH_CTRL);
+ :
+ : if (IS_I965G(pI830)) {
+ : /* The 965 may have a GTT that is actually larger than is necessary
+ : * to cover the aperture, so check the hardware's reporting of the
+ : * GTT size.
+ : */
+ : switch (INREG(PGETBL_CTL) & PGETBL_SIZE_MASK) {
+ : case PGETBL_SIZE_512KB:
+ : gtt_size = 512;
+ : break;
+ : case PGETBL_SIZE_256KB:
+ : gtt_size = 256;
+ : break;
+ : case PGETBL_SIZE_128KB:
+ : gtt_size = 128;
+ : break;
+ : default:
+ : FatalError("Unknown GTT size value: %08x\n", (int)INREG(PGETBL_CTL));
+ : }
+ : } else if (IS_G33CLASS(pI830)) {
+ : /* G33's GTT size is detect in GMCH_CTRL */
+ : switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) {
+ : case G33_PGETBL_SIZE_1M:
+ : gtt_size = 1024;
+ : break;
+ : case G33_PGETBL_SIZE_2M:
+ : gtt_size = 2048;
+ : break;
+ : default:
+ : FatalError("Unknown GTT size value: %08x\n",
+ : (int)(gmch_ctrl & G33_PGETBL_SIZE_MASK));
+ : }
+ : } else {
+ : /* Older chipsets only had GTT appropriately sized for the aperture. */
+ : gtt_size = pI830->FbMapSize / (1024*1024);
+ : }
+ :
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO, "detected %d kB GTT.\n", gtt_size);
+ :
+ : /* The stolen memory has the GTT at the top, and the 4KB popup below that.
+ : * Everything else can be freely used by the graphics driver.
+ : */
+ : range = gtt_size + 4;
+ :
+ : if (IS_I85X(pI830) || IS_I865G(pI830) || IS_I9XX(pI830)) {
+ : switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
+ : case I855_GMCH_GMS_STOLEN_1M:
+ : memsize = MB(1) - KB(range);
+ : break;
+ : case I855_GMCH_GMS_STOLEN_4M:
+ : memsize = MB(4) - KB(range);
+ : break;
+ : case I855_GMCH_GMS_STOLEN_8M:
+ : memsize = MB(8) - KB(range);
+ : break;
+ : case I855_GMCH_GMS_STOLEN_16M:
+ : memsize = MB(16) - KB(range);
+ : break;
+ : case I855_GMCH_GMS_STOLEN_32M:
+ : memsize = MB(32) - KB(range);
+ : break;
+ : case I915G_GMCH_GMS_STOLEN_48M:
+ : if (IS_I9XX(pI830))
+ : memsize = MB(48) - KB(range);
+ : break;
+ : case I915G_GMCH_GMS_STOLEN_64M:
+ : if (IS_I9XX(pI830))
+ : memsize = MB(64) - KB(range);
+ : break;
+ : case G33_GMCH_GMS_STOLEN_128M:
+ : if (IS_G33CLASS(pI830))
+ : memsize = MB(128) - KB(range);
+ : break;
+ : case G33_GMCH_GMS_STOLEN_256M:
+ : if (IS_G33CLASS(pI830))
+ : memsize = MB(256) - KB(range);
+ : break;
+ : }
+ : } else {
+ : switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
+ : case I830_GMCH_GMS_STOLEN_512:
+ : memsize = KB(512) - KB(range);
+ : break;
+ : case I830_GMCH_GMS_STOLEN_1024:
+ : memsize = MB(1) - KB(range);
+ : break;
+ : case I830_GMCH_GMS_STOLEN_8192:
+ : memsize = MB(8) - KB(range);
+ : break;
+ : case I830_GMCH_GMS_LOCAL:
+ : memsize = 0;
+ : xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ : "Local memory found, but won't be used.\n");
+ : break;
+ : }
+ : }
+ :
+ :#if 0
+ : /* And 64KB page aligned */
+ : memsize &= ~0xFFFF;
+ :#endif
+ :
+ : if (memsize > 0) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ : "detected %d kB stolen memory.\n", memsize / 1024);
+ : } else {
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO, "no video memory detected.\n");
+ : }
+ :
+ : return memsize;
+ :}
+ :
+ :static Bool
+ :I830MapMMIO(ScrnInfoPtr pScrn)
+ :{
+ : int mmioFlags;
+ : I830Ptr pI830 = I830PTR(pScrn);
+ :
+ :#if !defined(__alpha__)
+ : mmioFlags = VIDMEM_MMIO | VIDMEM_READSIDEEFFECT;
+ :#else
+ : mmioFlags = VIDMEM_MMIO | VIDMEM_READSIDEEFFECT | VIDMEM_SPARSE;
+ :#endif
+ :
+ : pI830->MMIOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags,
+ : pI830->PciTag,
+ : pI830->MMIOAddr, I810_REG_SIZE);
+ : if (!pI830->MMIOBase)
+ : return FALSE;
+ :
+ : /* Set up the GTT mapping for the various places it has been moved over
+ : * time.
+ : */
+ : if (IS_I9XX(pI830)) {
+ : if (IS_I965G(pI830)) {
+ : pI830->GTTBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags,
+ : pI830->PciTag,
+ : pI830->MMIOAddr + (512 * 1024),
+ : 512 * 1024);
+ : if (pI830->GTTBase == NULL)
+ : return FALSE;
+ : } else {
+ : CARD32 gttaddr = pI830->PciInfo->memBase[3] & 0xFFFFFF00;
+ :
+ : pI830->GTTBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags,
+ : pI830->PciTag,
+ : gttaddr,
+ : pI830->FbMapSize / 1024);
+ : if (pI830->GTTBase == NULL)
+ : return FALSE;
+ : }
+ : } else {
+ : /* The GTT aperture on i830 is write-only. We could probably map the
+ : * actual physical pages that back it, but leave it alone for now.
+ : */
+ : pI830->GTTBase = NULL;
+ : }
+ :
+ : return TRUE;
+ :}
+ :
+ :static Bool
+ :I830MapMem(ScrnInfoPtr pScrn)
+ :{
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : long i;
+ :
+ : for (i = 2; i < pI830->FbMapSize; i <<= 1) ;
+ : pI830->FbMapSize = i;
+ :
+ : if (!I830MapMMIO(pScrn))
+ : return FALSE;
+ :
+ : pI830->FbBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
+ : pI830->PciTag,
+ : pI830->LinearAddr, pI830->FbMapSize);
+ : if (!pI830->FbBase)
+ : return FALSE;
+ :
+ : if (I830IsPrimary(pScrn) && pI830->LpRing->mem != NULL) {
+ : pI830->LpRing->virtual_start =
+ : pI830->FbBase + pI830->LpRing->mem->offset;
+ : }
+ :
+ : return TRUE;
+ :}
+ :
+ :static void
+ :I830UnmapMMIO(ScrnInfoPtr pScrn)
+ :{
+ : I830Ptr pI830 = I830PTR(pScrn);
+ :
+ : xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pI830->MMIOBase,
+ : I810_REG_SIZE);
+ : pI830->MMIOBase = NULL;
+ :
+ : if (IS_I9XX(pI830)) {
+ : if (IS_I965G(pI830))
+ : xf86UnMapVidMem(pScrn->scrnIndex, pI830->GTTBase, 512 * 1024);
+ : else {
+ : xf86UnMapVidMem(pScrn->scrnIndex, pI830->GTTBase,
+ : pI830->FbMapSize / 1024);
+ : }
+ : }
+ :}
+ :
+ :static Bool
+ :I830UnmapMem(ScrnInfoPtr pScrn)
+ :{
+ : I830Ptr pI830 = I830PTR(pScrn);
+ :
+ : xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pI830->FbBase,
+ : pI830->FbMapSize);
+ : pI830->FbBase = NULL;
+ : I830UnmapMMIO(pScrn);
+ : return TRUE;
+ :}
+ :
+ :static void
+ :I830LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
+ : LOCO * colors, VisualPtr pVisual)
+ :{
+ : xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+ : int i,j, index;
+ : int p;
+ : CARD16 lut_r[256], lut_g[256], lut_b[256];
+ :
+ : DPRINTF(PFX, "I830LoadPalette: numColors: %d\n", numColors);
+ :
+ : for(p = 0; p < xf86_config->num_crtc; p++) {
+ : xf86CrtcPtr crtc = xf86_config->crtc[p];
+ : I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+ :
+ : /* Initialize to the old lookup table values. */
+ : for (i = 0; i < 256; i++) {
+ : lut_r[i] = intel_crtc->lut_r[i] << 8;
+ : lut_g[i] = intel_crtc->lut_g[i] << 8;
+ : lut_b[i] = intel_crtc->lut_b[i] << 8;
+ : }
+ :
+ : switch(pScrn->depth) {
+ : case 15:
+ : for (i = 0; i < numColors; i++) {
+ : index = indices[i];
+ : for (j = 0; j < 8; j++) {
+ : lut_r[index * 8 + j] = colors[index].red << 8;
+ : lut_g[index * 8 + j] = colors[index].green << 8;
+ : lut_b[index * 8 + j] = colors[index].blue << 8;
+ : }
+ : }
+ : break;
+ : case 16:
+ : for (i = 0; i < numColors; i++) {
+ : index = indices[i];
+ :
+ : if (index <= 31) {
+ : for (j = 0; j < 8; j++) {
+ : lut_r[index * 8 + j] = colors[index].red << 8;
+ : lut_b[index * 8 + j] = colors[index].blue << 8;
+ : }
+ : }
+ :
+ : for (j = 0; j < 4; j++) {
+ : lut_g[index * 4 + j] = colors[index].green << 8;
+ : }
+ : }
+ : break;
+ : default:
+ : for (i = 0; i < numColors; i++) {
+ : index = indices[i];
+ : lut_r[index] = colors[index].red << 8;
+ : lut_g[index] = colors[index].green << 8;
+ : lut_b[index] = colors[index].blue << 8;
+ : }
+ : break;
+ : }
+ :
+ : /* Make the change through RandR */
+ :#ifdef RANDR_12_INTERFACE
+ : RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
+ :#else
+ : crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256);
+ :#endif
+ : }
+ :}
+ :
+ :int
+ :i830_output_clones (ScrnInfoPtr pScrn, int type_mask)
+ :{
+ : xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR (pScrn);
+ : int o;
+ : int index_mask = 0;
+ :
+ : for (o = 0; o < config->num_output; o++)
+ : {
+ : xf86OutputPtr output = config->output[o];
+ : I830OutputPrivatePtr intel_output = output->driver_private;
+ : if (type_mask & (1 << intel_output->type))
+ : index_mask |= (1 << o);
+ : }
+ : return index_mask;
+ :}
+ :
+ :/**
+ : * Set up the outputs according to what type of chip we are.
+ : *
+ : * Some outputs may not initialize, due to allocation failure or because a
+ : * controller chip isn't found.
+ : */
+ :static void
+ :I830SetupOutputs(ScrnInfoPtr pScrn)
+ :{
+ : xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR (pScrn);
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : int o;
+ :
+ : /* everyone has at least a single analog output */
+ : i830_crt_init(pScrn);
+ :
+ : /* Set up integrated LVDS */
+ : if (IS_MOBILE(pI830) && !IS_I830(pI830))
+ : i830_lvds_init(pScrn);
+ :
+ : if (IS_I9XX(pI830)) {
+ : i830_sdvo_init(pScrn, SDVOB);
+ : i830_sdvo_init(pScrn, SDVOC);
+ : } else {
+ : i830_dvo_init(pScrn);
+ : }
+ : if (IS_I9XX(pI830) && !IS_I915G(pI830))
+ : i830_tv_init(pScrn);
+ :
+ : for (o = 0; o < config->num_output; o++)
+ : {
+ : xf86OutputPtr output = config->output[o];
+ : I830OutputPrivatePtr intel_output = output->driver_private;
+ : int crtc_mask;
+ : int c;
+ :
+ : crtc_mask = 0;
+ : for (c = 0; c < config->num_crtc; c++)
+ : {
+ : xf86CrtcPtr crtc = config->crtc[c];
+ : I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+ :
+ : if (intel_output->pipe_mask & (1 << intel_crtc->pipe))
+ : crtc_mask |= (1 << c);
+ : }
+ : output->possible_crtcs = crtc_mask;
+ : output->possible_clones = i830_output_clones (pScrn, intel_output->clone_mask);
+ : }
+ :}
+ :
+ :/**
+ : * Setup the CRTCs
+ : */
+ :
+ :
+ :static void
+ :I830PreInitDDC(ScrnInfoPtr pScrn)
+ :{
+ : I830Ptr pI830 = I830PTR(pScrn);
+ :
+ : if (!xf86LoadSubModule(pScrn, "ddc")) {
+ : pI830->ddc2 = FALSE;
+ : } else {
+ : xf86LoaderReqSymLists(I810ddcSymbols, NULL);
+ : pI830->ddc2 = TRUE;
+ : }
+ :
+ : /* DDC can use I2C bus */
+ : /* Load I2C if we have the code to use it */
+ : if (pI830->ddc2) {
+ : if (xf86LoadSubModule(pScrn, "i2c")) {
+ : xf86LoaderReqSymLists(I810i2cSymbols, NULL);
+ :
+ : pI830->ddc2 = TRUE;
+ : } else {
+ : pI830->ddc2 = FALSE;
+ : }
+ : }
+ :}
+ :
+ :static void
+ :PreInitCleanup(ScrnInfoPtr pScrn)
+ :{
+ : I830Ptr pI830 = I830PTR(pScrn);
+ :
+ : if (I830IsPrimary(pScrn)) {
+ : if (pI830->entityPrivate)
+ : pI830->entityPrivate->pScrn_1 = NULL;
+ : } else {
+ : if (pI830->entityPrivate)
+ : pI830->entityPrivate->pScrn_2 = NULL;
+ : }
+ : if (pI830->swfSaved) {
+ : OUTREG(SWF0, pI830->saveSWF0);
+ : OUTREG(SWF4, pI830->saveSWF4);
+ : }
+ : if (pI830->MMIOBase)
+ : I830UnmapMMIO(pScrn);
+ : I830FreeRec(pScrn);
+ :}
+ :
+ :Bool
+ :I830IsPrimary(ScrnInfoPtr pScrn)
+ :{
+ : I830Ptr pI830 = I830PTR(pScrn);
+ :
+ : if (xf86IsEntityShared(pScrn->entityList[0])) {
+ : if (pI830->init == 0) return TRUE;
+ : else return FALSE;
+ : }
+ :
+ : return TRUE;
+ :}
+ :
+ :static Bool
+ :i830_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
+ :{
+ : scrn->virtualX = width;
+ : scrn->virtualY = height;
+ : return TRUE;
+ :}
+ :
+ :static const xf86CrtcConfigFuncsRec i830_xf86crtc_config_funcs = {
+ : i830_xf86crtc_resize
+ :};
+ :
+ :#define HOTKEY_BIOS_SWITCH 0
+ :#define HOTKEY_DRIVER_NOTIFY 1
+ :
+ :/**
+ : * Controls the BIOS's behavior on hotkey switch.
+ : *
+ : * If the mode is HOTKEY_BIOS_SWITCH, the BIOS will be set to do a mode switch
+ : * on its own and update the state in the scratch register.
+ : * If the mode is HOTKEY_DRIVER_NOTIFY, the BIOS won't do a mode switch and
+ : * will just update the state to represent what it would have been switched to.
+ : */
+ :static void
+ :i830SetHotkeyControl(ScrnInfoPtr pScrn, int mode)
+ :{
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : CARD8 gr18;
+ :
+ : gr18 = pI830->readControl(pI830, GRX, 0x18);
+ : if (mode == HOTKEY_BIOS_SWITCH)
+ : gr18 &= ~HOTKEY_VBIOS_SWITCH_BLOCK;
+ : else
+ : gr18 |= HOTKEY_VBIOS_SWITCH_BLOCK;
+ : pI830->writeControl(pI830, GRX, 0x18, gr18);
+ :}
+ :
+ :/**
+ : * This is called per zaphod head (so usually just once) to do initialization
+ : * before the Screen is created.
+ : *
+ : * This code generally covers probing, module loading, option handling
+ : * card mapping, and RandR setup.
+ : */
+ :static Bool
+ :I830PreInit(ScrnInfoPtr pScrn, int flags)
+ :{
+ : xf86CrtcConfigPtr xf86_config;
+ : vgaHWPtr hwp;
+ : I830Ptr pI830;
+ : MessageType from = X_PROBED;
+ : rgb defaultWeight = { 0, 0, 0 };
+ : EntityInfoPtr pEnt;
+ : I830EntPtr pI830Ent = NULL;
+ : int flags24;
+ : int i;
+ : char *s;
+ : pointer pVBEModule = NULL;
+ : const char *chipname;
+ : int num_pipe;
+ : int max_width, max_height;
+ :
+ : if (pScrn->numEntities != 1)
+ : return FALSE;
+ :
+ : /* Load int10 module */
+ : if (!xf86LoadSubModule(pScrn, "int10"))
+ : return FALSE;
+ : xf86LoaderReqSymLists(I810int10Symbols, NULL);
+ :
+ : /* Load vbe module */
+ : if (!(pVBEModule = xf86LoadSubModule(pScrn, "vbe")))
+ : return FALSE;
+ : xf86LoaderReqSymLists(I810vbeSymbols, NULL);
+ :
+ : pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
+ :
+ : if (flags & PROBE_DETECT) {
+ : I830ProbeDDC(pScrn, pEnt->index);
+ : return TRUE;
+ : }
+ :
+ : /* The vgahw module should be loaded here when needed */
+ : if (!xf86LoadSubModule(pScrn, "vgahw"))
+ : return FALSE;
+ : xf86LoaderReqSymLists(I810vgahwSymbols, NULL);
+ :
+ : /* Allocate a vgaHWRec */
+ : if (!vgaHWGetHWRec(pScrn))
+ : return FALSE;
+ :
+ : /* Allocate driverPrivate */
+ : if (!I830GetRec(pScrn))
+ : return FALSE;
+ :
+ : pI830 = I830PTR(pScrn);
+ : pI830->SaveGeneration = -1;
+ : pI830->pEnt = pEnt;
+ :
+ : pScrn->displayWidth = 640; /* default it */
+ :
+ : if (pI830->pEnt->location.type != BUS_PCI)
+ : return FALSE;
+ :
+ : pI830->PciInfo = xf86GetPciInfoForEntity(pI830->pEnt->index);
+ : pI830->PciTag = pciTag(pI830->PciInfo->bus, pI830->PciInfo->device,
+ : pI830->PciInfo->func);
+ :
+ : /* Allocate an entity private if necessary */
+ : if (xf86IsEntityShared(pScrn->entityList[0])) {
+ : pI830Ent = xf86GetEntityPrivate(pScrn->entityList[0],
+ : I830EntityIndex)->ptr;
+ : pI830->entityPrivate = pI830Ent;
+ : } else
+ : pI830->entityPrivate = NULL;
+ :
+ : if (xf86RegisterResources(pI830->pEnt->index, NULL, ResNone)) {
+ : PreInitCleanup(pScrn);
+ : return FALSE;
+ : }
+ :
+ : if (xf86IsEntityShared(pScrn->entityList[0])) {
+ : if (xf86IsPrimInitDone(pScrn->entityList[0])) {
+ : pI830->init = 1;
+ :
+ : if (!pI830Ent->pScrn_1) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ : "Failed to setup second head due to primary head failure.\n");
+ : return FALSE;
+ : }
+ : } else {
+ : xf86SetPrimInitDone(pScrn->entityList[0]);
+ : pI830->init = 0;
+ : }
+ : }
+ :
+ : if (xf86IsEntityShared(pScrn->entityList[0])) {
+ : if (!I830IsPrimary(pScrn)) {
+ : pI830Ent->pScrn_2 = pScrn;
+ : } else {
+ : pI830Ent->pScrn_1 = pScrn;
+ : pI830Ent->pScrn_2 = NULL;
+ : }
+ : }
+ :
+ : pScrn->racMemFlags = RAC_FB | RAC_COLORMAP;
+ : pScrn->monitor = pScrn->confScreen->monitor;
+ : pScrn->progClock = TRUE;
+ : pScrn->rgbBits = 8;
+ :
+ : flags24 = Support32bppFb | PreferConvert24to32 | SupportConvert24to32;
+ :
+ : if (!xf86SetDepthBpp(pScrn, 0, 0, 0, flags24))
+ : return FALSE;
+ :
+ : switch (pScrn->depth) {
+ : case 8:
+ : case 15:
+ : case 16:
+ : case 24:
+ : break;
+ : default:
+ : xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ : "Given depth (%d) is not supported by I830 driver\n",
+ : pScrn->depth);
+ : return FALSE;
+ : }
+ : xf86PrintDepthBpp(pScrn);
+ :
+ : if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight))
+ : return FALSE;
+ : if (!xf86SetDefaultVisual(pScrn, -1))
+ : return FALSE;
+ :
+ : hwp = VGAHWPTR(pScrn);
+ : pI830->cpp = pScrn->bitsPerPixel / 8;
+ :
+ : pI830->preinit = TRUE;
+ :
+ : /* Process the options */
+ : xf86CollectOptions(pScrn, NULL);
+ : if (!(pI830->Options = xalloc(sizeof(I830Options))))
+ : return FALSE;
+ : memcpy(pI830->Options, I830Options, sizeof(I830Options));
+ : xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pI830->Options);
+ :
+ : if (xf86ReturnOptValBool(pI830->Options, OPTION_MODEDEBUG, FALSE)) {
+ : pI830->debug_modes = TRUE;
+ : } else {
+ : pI830->debug_modes = FALSE;
+ : }
+ :
+ : /* We have to use PIO to probe, because we haven't mapped yet. */
+ : I830SetPIOAccess(pI830);
+ :
+ : switch (pI830->PciInfo->chipType) {
+ : case PCI_CHIP_I830_M:
+ : chipname = "830M";
+ : break;
+ : case PCI_CHIP_845_G:
+ : chipname = "845G";
+ : break;
+ : case PCI_CHIP_I855_GM:
+ : /* Check capid register to find the chipset variant */
+ : pI830->variant = (pciReadLong(pI830->PciTag, I85X_CAPID)
+ : >> I85X_VARIANT_SHIFT) & I85X_VARIANT_MASK;
+ : switch (pI830->variant) {
+ : case I855_GM:
+ : chipname = "855GM";
+ : break;
+ : case I855_GME:
+ : chipname = "855GME";
+ : break;
+ : case I852_GM:
+ : chipname = "852GM";
+ : break;
+ : case I852_GME:
+ : chipname = "852GME";
+ : break;
+ : default:
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ : "Unknown 852GM/855GM variant: 0x%x)\n", pI830->variant);
+ : chipname = "852GM/855GM (unknown variant)";
+ : break;
+ : }
+ : break;
+ : case PCI_CHIP_I865_G:
+ : chipname = "865G";
+ : break;
+ : case PCI_CHIP_I915_G:
+ : chipname = "915G";
+ : break;
+ : case PCI_CHIP_E7221_G:
+ : chipname = "E7221 (i915)";
+ : break;
+ : case PCI_CHIP_I915_GM:
+ : chipname = "915GM";
+ : break;
+ : case PCI_CHIP_I945_G:
+ : chipname = "945G";
+ : break;
+ : case PCI_CHIP_I945_GM:
+ : chipname = "945GM";
+ : break;
+ : case PCI_CHIP_I945_GME:
+ : chipname = "945GME";
+ : break;
+ : case PCI_CHIP_I965_G:
+ : case PCI_CHIP_I965_G_1:
+ : chipname = "965G";
+ : break;
+ : case PCI_CHIP_I965_Q:
+ : chipname = "965Q";
+ : break;
+ : case PCI_CHIP_I946_GZ:
+ : chipname = "946GZ";
+ : break;
+ : case PCI_CHIP_I965_GM:
+ : chipname = "965GM";
+ : break;
+ : case PCI_CHIP_I965_GME:
+ : chipname = "965GME/GLE";
+ : break;
+ : case PCI_CHIP_G33_G:
+ : chipname = "G33";
+ : break;
+ : case PCI_CHIP_Q35_G:
+ : chipname = "Q35";
+ : break;
+ : case PCI_CHIP_Q33_G:
+ : chipname = "Q33";
+ : break;
+ : default:
+ : chipname = "unknown chipset";
+ : break;
+ : }
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ : "Integrated Graphics Chipset: Intel(R) %s\n", chipname);
+ :
+ : /* Set the Chipset and ChipRev, allowing config file entries to override. */
+ : if (pI830->pEnt->device->chipset && *pI830->pEnt->device->chipset) {
+ : pScrn->chipset = pI830->pEnt->device->chipset;
+ : from = X_CONFIG;
+ : } else if (pI830->pEnt->device->chipID >= 0) {
+ : pScrn->chipset = (char *)xf86TokenToString(I830Chipsets,
+ : pI830->pEnt->device->chipID);
+ : from = X_CONFIG;
+ : xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
+ : pI830->pEnt->device->chipID);
+ : pI830->PciInfo->chipType = pI830->pEnt->device->chipID;
+ : } else {
+ : from = X_PROBED;
+ : pScrn->chipset = (char *)xf86TokenToString(I830Chipsets,
+ : pI830->PciInfo->chipType);
+ : }
+ :
+ : if (pI830->pEnt->device->chipRev >= 0) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
+ : pI830->pEnt->device->chipRev);
+ : }
+ :
+ : xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n",
+ : (pScrn->chipset != NULL) ? pScrn->chipset : "Unknown i8xx");
+ :
+ : if (pI830->pEnt->device->MemBase != 0) {
+ : pI830->LinearAddr = pI830->pEnt->device->MemBase;
+ : from = X_CONFIG;
+ : } else {
+ : if (IS_I9XX(pI830)) {
+ : pI830->LinearAddr = pI830->PciInfo->memBase[2] & 0xFF000000;
+ : from = X_PROBED;
+ : } else if (pI830->PciInfo->memBase[1] != 0) {
+ : /* XXX Check mask. */
+ : pI830->LinearAddr = pI830->PciInfo->memBase[0] & 0xFF000000;
+ : from = X_PROBED;
+ : } else {
+ : xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ : "No valid FB address in PCI config space\n");
+ : PreInitCleanup(pScrn);
+ : return FALSE;
+ : }
+ : }
+ :
+ : xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n",
+ : (unsigned long)pI830->LinearAddr);
+ :
+ : if (pI830->pEnt->device->IOBase != 0) {
+ : pI830->MMIOAddr = pI830->pEnt->device->IOBase;
+ : from = X_CONFIG;
+ : } else {
+ : if (IS_I9XX(pI830)) {
+ : pI830->MMIOAddr = pI830->PciInfo->memBase[0] & 0xFFF80000;
+ : from = X_PROBED;
+ : } else if (pI830->PciInfo->memBase[1]) {
+ : pI830->MMIOAddr = pI830->PciInfo->memBase[1] & 0xFFF80000;
+ : from = X_PROBED;
+ : } else {
+ : xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ : "No valid MMIO address in PCI config space\n");
+ : PreInitCleanup(pScrn);
+ : return FALSE;
+ : }
+ : }
+ :
+ : xf86DrvMsg(pScrn->scrnIndex, from, "IO registers at addr 0x%lX\n",
+ : (unsigned long)pI830->MMIOAddr);
+ :
+ : /* Allocate an xf86CrtcConfig */
+ : xf86CrtcConfigInit (pScrn, &i830_xf86crtc_config_funcs);
+ : xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+ :
+ : /* See i830_exa.c comments for why we limit the framebuffer size like this.
+ : */
+ : if (IS_I965G(pI830)) {
+ : max_width = 8192;
+ : max_height = 8192;
+ : } else {
+ : max_width = 2048;
+ : max_height = 2048;
+ : }
+ : xf86CrtcSetSizeRange (pScrn, 320, 200, max_width, max_height);
+ :
+ : if (IS_I830(pI830) || IS_845G(pI830)) {
+ : PCITAG bridge;
+ : CARD16 gmch_ctrl;
+ :
+ : bridge = pciTag(0, 0, 0); /* This is always the host bridge */
+ : gmch_ctrl = pciReadWord(bridge, I830_GMCH_CTRL);
+ : if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
+ : pI830->FbMapSize = 0x8000000;
+ : } else {
+ : pI830->FbMapSize = 0x4000000; /* 64MB - has this been tested ?? */
+ : }
+ : } else {
+ : if (IS_I9XX(pI830)) {
+ : pI830->FbMapSize = 1UL << pciGetBaseSize(pI830->PciTag, 2, TRUE,
+ : NULL);
+ : } else {
+ : /* 128MB aperture for later i8xx series. */
+ : pI830->FbMapSize = 0x8000000;
+ : }
+ : }
+ :
+ : /* Some of the probing needs MMIO access, so map it here. */
+ : I830MapMMIO(pScrn);
+ :
+ : if (pI830->debug_modes) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Hardware state on X startup:\n");
+ : i830DumpRegs (pScrn);
+ : }
+ :
+ : i830TakeRegSnapshot(pScrn);
+ :
+ :#if 1
+ : pI830->saveSWF0 = INREG(SWF0);
+ : pI830->saveSWF4 = INREG(SWF4);
+ : pI830->swfSaved = TRUE;
+ :
+ : /* Set "extended desktop" */
+ : OUTREG(SWF0, pI830->saveSWF0 | (1 << 21));
+ :
+ : /* Set "driver loaded", "OS unknown", "APM 1.2" */
+ : OUTREG(SWF4, (pI830->saveSWF4 & ~((3 << 19) | (7 << 16))) |
+ : (1 << 23) | (2 << 16));
+ :#endif
+ :
+ : if (pI830->PciInfo->chipType == PCI_CHIP_E7221_G)
+ : num_pipe = 1;
+ : else
+ : if (IS_MOBILE(pI830) || IS_I9XX(pI830))
+ : num_pipe = 2;
+ : else
+ : num_pipe = 1;
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%d display pipe%s available.\n",
+ : num_pipe, num_pipe > 1 ? "s" : "");
+ :
+ : if (xf86ReturnOptValBool(pI830->Options, OPTION_NOACCEL, FALSE)) {
+ : pI830->noAccel = TRUE;
+ : }
+ :
+ : /*
+ : * The ugliness below:
+ : * If either XAA or EXA (exclusive) is compiled in, default to it.
+ : *
+ : * If both are compiled in, and the user didn't specify noAccel, use the
+ : * config option AccelMethod to determine which to use, defaulting to XAA
+ : * if none is specified, or if the string was unrecognized.
+ : *
+ : * All this *could* go away if we removed XAA support from this driver,
+ : * for example. :)
+ : */
+ : if (!pI830->noAccel) {
+ :#if (defined(I830_USE_EXA) && defined(I830_USE_XAA)) || !defined(I830_USE_EXA)
+ : pI830->useEXA = FALSE;
+ :#else
+ : pI830->useEXA = TRUE;
+ :#endif
+ :#if defined(I830_USE_XAA) && defined(I830_USE_EXA)
+ : int from = X_DEFAULT;
+ : if ((s = (char *)xf86GetOptValString(pI830->Options,
+ : OPTION_ACCELMETHOD))) {
+ : if (!xf86NameCmp(s, "EXA")) {
+ : from = X_CONFIG;
+ : pI830->useEXA = TRUE;
+ : }
+ : else if (!xf86NameCmp(s, "XAA")) {
+ : from = X_CONFIG;
+ : pI830->useEXA = FALSE;
+ : }
+ : }
+ :#endif
+ : xf86DrvMsg(pScrn->scrnIndex, from, "Using %s for acceleration\n",
+ : pI830->useEXA ? "EXA" : "XAA");
+ : }
+ :
+ : if (xf86ReturnOptValBool(pI830->Options, OPTION_SW_CURSOR, FALSE)) {
+ : pI830->SWCursor = TRUE;
+ : }
+ :
+ : pI830->directRenderingDisabled =
+ : !xf86ReturnOptValBool(pI830->Options, OPTION_DRI, TRUE);
+ :
+ :#ifdef XF86DRI
+ : if (!pI830->directRenderingDisabled) {
+ : if (pI830->noAccel || pI830->SWCursor) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "DRI is disabled because it "
+ : "needs HW cursor and 2D acceleration.\n");
+ : pI830->directRenderingDisabled = TRUE;
+ : } else if (pScrn->depth != 16 && pScrn->depth != 24) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "DRI is disabled because it "
+ : "runs only at depths 16 and 24.\n");
+ : pI830->directRenderingDisabled = TRUE;
+ : }
+ :
+ : pI830->mmModeFlags = 0;
+ :
+ : if (!pI830->directRenderingDisabled) {
+ : pI830->mmModeFlags = I830_KERNEL_TEX;
+ :#ifdef XF86DRI_MM
+ : Bool tmp = FALSE;
+ :
+ : if (!IS_I965G(pI830))
+ : pI830->mmModeFlags |= I830_KERNEL_MM;
+ :#endif
+ :
+ : from = X_PROBED;
+ :
+ :#ifdef XF86DRI_MM
+ : if (xf86GetOptValBool(pI830->Options,
+ : OPTION_INTELTEXPOOL, &tmp)) {
+ : from = X_CONFIG;
+ : if (tmp) {
+ : pI830->mmModeFlags |= I830_KERNEL_TEX;
+ : pI830->mmModeFlags &= ~I830_KERNEL_MM;
+ : } else {
+ : pI830->mmModeFlags &= ~I830_KERNEL_TEX;
+ : pI830->mmModeFlags |= I830_KERNEL_MM;
+ : }
+ : }
+ :#endif
+ :
+ : xf86DrvMsg(pScrn->scrnIndex, from,
+ : "Will %stry to allocate texture pool "
+ : "for old Mesa 3D driver.\n",
+ : (pI830->mmModeFlags & I830_KERNEL_TEX) ?
+ : "" : "not ");
+ :
+ :#ifdef XF86DRI_MM
+ : pI830->mmSize = I830_MM_MAXSIZE;
+ : from = X_INFO;
+ : if (xf86GetOptValInteger(pI830->Options, OPTION_INTELMMSIZE,
+ : &(pI830->mmSize))) {
+ : from = X_CONFIG;
+ : }
+ : xf86DrvMsg(pScrn->scrnIndex, from,
+ : "Will try to reserve %d kiB of AGP aperture space\n"
+ : "\tfor the DRM memory manager.\n",
+ : pI830->mmSize);
+ :#endif
+ : }
+ : }
+ :
+ :#endif
+ :
+ : I830PreInitDDC(pScrn);
+ : for (i = 0; i < num_pipe; i++) {
+ : i830_crtc_init(pScrn, i);
+ : }
+ : I830SetupOutputs(pScrn);
+ :
+ : SaveHWState(pScrn);
+ : if (!xf86InitialConfiguration (pScrn, FALSE))
+ : {
+ : xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n");
+ : RestoreHWState(pScrn);
+ : PreInitCleanup(pScrn);
+ : return FALSE;
+ : }
+ : RestoreHWState(pScrn);
+ :
+ : /* XXX This should go away, replaced by xf86Crtc.c support for it */
+ : pI830->rotation = RR_Rotate_0;
+ :
+ : /*
+ : * Let's setup the mobile systems to check the lid status
+ : */
+ : if (IS_MOBILE(pI830)) {
+ : pI830->checkDevices = TRUE;
+ :
+ : if (!xf86ReturnOptValBool(pI830->Options, OPTION_CHECKDEVICES, TRUE)) {
+ : pI830->checkDevices = FALSE;
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Monitoring connected displays disabled\n");
+ : } else
+ : if (pI830->entityPrivate && !I830IsPrimary(pScrn) &&
+ : !I830PTR(pI830->entityPrivate->pScrn_1)->checkDevices) {
+ : /* If checklid is off, on the primary head, then
+ : * turn it off on the secondary*/
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Monitoring connected displays disabled\n");
+ : pI830->checkDevices = FALSE;
+ : } else
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Monitoring connected displays enabled\n");
+ : } else
+ : pI830->checkDevices = FALSE;
+ :
+ : pI830->stolen_size = I830DetectMemory(pScrn);
+ :
+ : pI830->XvDisabled =
+ : !xf86ReturnOptValBool(pI830->Options, OPTION_XVIDEO, TRUE);
+ :
+ :#ifdef I830_XV
+ : if (xf86GetOptValInteger(pI830->Options, OPTION_VIDEO_KEY,
+ : &(pI830->colorKey))) {
+ : from = X_CONFIG;
+ : } else if (xf86GetOptValInteger(pI830->Options, OPTION_COLOR_KEY,
+ : &(pI830->colorKey))) {
+ : from = X_CONFIG;
+ : } else {
+ : pI830->colorKey = (1 << pScrn->offset.red) |
+ : (1 << pScrn->offset.green) |
+ : (((pScrn->mask.blue >> pScrn->offset.blue) - 1) <<
+ : pScrn->offset.blue);
+ : from = X_DEFAULT;
+ : }
+ : xf86DrvMsg(pScrn->scrnIndex, from, "video overlay key set to 0x%x\n",
+ : pI830->colorKey);
+ :#endif
+ :
+ :#ifdef XF86DRI
+ : pI830->allowPageFlip = FALSE;
+ : from = (!pI830->directRenderingDisabled &&
+ : xf86GetOptValBool(pI830->Options, OPTION_PAGEFLIP,
+ : &pI830->allowPageFlip)) ? X_CONFIG : X_DEFAULT;
+ :
+ : xf86DrvMsg(pScrn->scrnIndex, from, "Will%s try to enable page flipping\n",
+ : pI830->allowPageFlip ? "" : " not");
+ :#endif
+ :
+ :#ifdef XF86DRI
+ : pI830->TripleBuffer = FALSE;
+ : from = (!pI830->directRenderingDisabled &&
+ : xf86GetOptValBool(pI830->Options, OPTION_TRIPLEBUFFER,
+ : &pI830->TripleBuffer)) ? X_CONFIG : X_DEFAULT;
+ :
+ : xf86DrvMsg(pScrn->scrnIndex, from, "Triple buffering %sabled\n",
+ : pI830->TripleBuffer ? "en" : "dis");
+ :#endif
+ :
+ : /*
+ : * If the driver can do gamma correction, it should call xf86SetGamma() here.
+ : */
+ :
+ : {
+ : Gamma zeros = { 0.0, 0.0, 0.0 };
+ :
+ : if (!xf86SetGamma(pScrn, zeros)) {
+ : PreInitCleanup(pScrn);
+ : return FALSE;
+ : }
+ : }
+ :
+ : /* Check if the HW cursor needs physical address. */
+ : if (IS_MOBILE(pI830) || IS_I9XX(pI830))
+ : pI830->CursorNeedsPhysical = TRUE;
+ : else
+ : pI830->CursorNeedsPhysical = FALSE;
+ :
+ : if (IS_I965G(pI830) || IS_G33CLASS(pI830))
+ : pI830->CursorNeedsPhysical = FALSE;
+ :
+ : /*
+ : * XXX If we knew the pre-initialised GTT format for certain, we could
+ : * probably figure out the physical address even in the StolenOnly case.
+ : */
+ : if (!I830IsPrimary(pScrn)) {
+ : I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1);
+ : if (!pI8301->SWCursor) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+ : "Using HW Cursor because it's enabled on primary head.\n");
+ : pI830->SWCursor = FALSE;
+ : }
+ : } else
+ : if (pI830->StolenOnly && pI830->CursorNeedsPhysical && !pI830->SWCursor) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+ : "HW Cursor disabled because it needs agpgart memory.\n");
+ : pI830->SWCursor = TRUE;
+ : }
+ :
+ : if (pScrn->modes == NULL) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n");
+ : PreInitCleanup(pScrn);
+ : return FALSE;
+ : }
+ : pScrn->currentMode = pScrn->modes;
+ :
+ : if (!IS_I965G(pI830) && pScrn->virtualY > 2048) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Cannot support > 2048 vertical lines. disabling acceleration.\n");
+ : pI830->noAccel = TRUE;
+ : }
+ :
+ : /* Don't need MMIO access anymore. */
+ : if (pI830->swfSaved) {
+ : OUTREG(SWF0, pI830->saveSWF0);
+ : OUTREG(SWF4, pI830->saveSWF4);
+ : }
+ :
+ : /* Set display resolution */
+ : xf86SetDpi(pScrn, 0, 0);
+ :
+ : /* Load the required sub modules */
+ : if (!xf86LoadSubModule(pScrn, "fb")) {
+ : PreInitCleanup(pScrn);
+ : return FALSE;
+ : }
+ :
+ : xf86LoaderReqSymLists(I810fbSymbols, NULL);
+ :
+ :#ifdef I830_USE_XAA
+ : if (!pI830->noAccel && !pI830->useEXA) {
+ : if (!xf86LoadSubModule(pScrn, "xaa")) {
+ : PreInitCleanup(pScrn);
+ : return FALSE;
+ : }
+ : xf86LoaderReqSymLists(I810xaaSymbols, NULL);
+ : }
+ :#endif
+ :
+ :#ifdef I830_USE_EXA
+ : if (!pI830->noAccel && pI830->useEXA) {
+ : XF86ModReqInfo req;
+ : int errmaj, errmin;
+ :
+ : memset(&req, 0, sizeof(req));
+ : req.majorversion = 2;
+ : req.minorversion = 1;
+ : if (!LoadSubModule(pScrn->module, "exa", NULL, NULL, NULL, &req,
+ : &errmaj, &errmin)) {
+ : LoaderErrorMsg(NULL, "exa", errmaj, errmin);
+ : PreInitCleanup(pScrn);
+ : return FALSE;
+ : }
+ : xf86LoaderReqSymLists(I830exaSymbols, NULL);
+ : }
+ :#endif
+ : if (!pI830->SWCursor) {
+ : if (!xf86LoadSubModule(pScrn, "ramdac")) {
+ : PreInitCleanup(pScrn);
+ : return FALSE;
+ : }
+ : xf86LoaderReqSymLists(I810ramdacSymbols, NULL);
+ : }
+ :
+ : i830CompareRegsToSnapshot(pScrn, "After PreInit");
+ :
+ : I830UnmapMMIO(pScrn);
+ :
+ : /* We won't be using the VGA access after the probe. */
+ : I830SetMMIOAccess(pI830);
+ : xf86SetOperatingState(resVgaIo, pI830->pEnt->index, ResUnusedOpr);
+ : xf86SetOperatingState(resVgaMem, pI830->pEnt->index, ResDisableOpr);
+ :
+ :#if 0
+ : if (I830IsPrimary(pScrn)) {
+ : vbeFree(pI830->pVbe);
+ : }
+ : pI830->pVbe = NULL;
+ :#endif
+ :
+ :#if defined(XF86DRI)
+ : /* Load the dri module if requested. */
+ : if (xf86ReturnOptValBool(pI830->Options, OPTION_DRI, FALSE) &&
+ : !pI830->directRenderingDisabled) {
+ : if (xf86LoadSubModule(pScrn, "dri")) {
+ : xf86LoaderReqSymLists(I810driSymbols, I810drmSymbols, NULL);
+ : }
+ : }
+ :#endif
+ :
+ : pI830->preinit = FALSE;
+ :
+ : return TRUE;
+ :}
+ :
+ :/*
+ : * Reset registers that it doesn't make sense to save/restore to a sane state.
+ : * This is basically the ring buffer and fence registers. Restoring these
+ : * doesn't make sense without restoring GTT mappings. This is something that
+ : * whoever gets control next should do.
+ : */
+ :static void
+ :ResetState(ScrnInfoPtr pScrn, Bool flush)
+ :{
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : int i;
+ : unsigned long temp;
+ :
+ : DPRINTF(PFX, "ResetState: flush is %s\n", BOOLTOSTRING(flush));
+ :
+ : if (!I830IsPrimary(pScrn)) return;
+ :
+ : if (pI830->entityPrivate)
+ : pI830->entityPrivate->RingRunning = 0;
+ :
+ : /* Reset the fence registers to 0 */
+ : if (IS_I965G(pI830)) {
+ : for (i = 0; i < FENCE_NEW_NR; i++) {
+ : OUTREG(FENCE_NEW + i * 8, 0);
+ : OUTREG(FENCE_NEW + 4 + i * 8, 0);
+ : }
+ : } else {
+ : for (i = 0; i < FENCE_NR; i++)
+ : OUTREG(FENCE + i * 4, 0);
+ : }
+ : /* Flush the ring buffer (if enabled), then disable it. */
+ : /* God this is ugly */
+ :#define flush_ring() do { \
+ : temp = INREG(LP_RING + RING_LEN); \
+ : if (temp & RING_VALID) { \
+ : I830RefreshRing(pScrn); \
+ : I830Sync(pScrn); \
+ : DO_RING_IDLE(); \
+ : } \
+ : } while(0)
+ :#ifdef I830_USE_XAA
+ : if (!pI830->useEXA && flush && pI830->AccelInfoRec)
+ : flush_ring();
+ :#endif
+ :#ifdef I830_USE_EXA
+ : if (pI830->useEXA && flush && pI830->EXADriverPtr)
+ : flush_ring();
+ :#endif
+ :
+ : OUTREG(LP_RING + RING_LEN, 0);
+ : OUTREG(LP_RING + RING_HEAD, 0);
+ : OUTREG(LP_RING + RING_TAIL, 0);
+ : OUTREG(LP_RING + RING_START, 0);
+ :
+ : xf86_hide_cursors (pScrn);
+ :}
+ :
+ :static void
+ :SetFenceRegs(ScrnInfoPtr pScrn)
+ :{
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : int i;
+ :
+ : DPRINTF(PFX, "SetFenceRegs\n");
+ :
+ : if (!I830IsPrimary(pScrn)) return;
+ :
+ : if (IS_I965G(pI830)) {
+ : for (i = 0; i < FENCE_NEW_NR; i++) {
+ : OUTREG(FENCE_NEW + i * 8, pI830->fence[i]);
+ : OUTREG(FENCE_NEW + 4 + i * 8, pI830->fence[i+FENCE_NEW_NR]);
+ : if (I810_DEBUG & DEBUG_VERBOSE_VGA) {
+ : ErrorF("Fence Start Register : %x\n", pI830->fence[i]);
+ : ErrorF("Fence End Register : %x\n", pI830->fence[i+FENCE_NEW_NR]);
+ : }
+ : }
+ : } else {
+ : for (i = 0; i < FENCE_NR; i++) {
+ : OUTREG(FENCE + i * 4, pI830->fence[i]);
+ : if (I810_DEBUG & DEBUG_VERBOSE_VGA)
+ : ErrorF("Fence Register : %x\n", pI830->fence[i]);
+ : }
+ : }
+ :}
+ :
+ :static void
+ :SetRingRegs(ScrnInfoPtr pScrn)
+ :{
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : unsigned int itemp;
+ :
+ : DPRINTF(PFX, "SetRingRegs\n");
+ :
+ : if (pI830->noAccel)
+ : return;
+ :
+ : if (!I830IsPrimary(pScrn)) return;
+ :
+ : if (pI830->entityPrivate)
+ : pI830->entityPrivate->RingRunning = 1;
+ :
+ : OUTREG(LP_RING + RING_LEN, 0);
+ : OUTREG(LP_RING + RING_TAIL, 0);
+ : OUTREG(LP_RING + RING_HEAD, 0);
+ :
+ : assert((pI830->LpRing->mem->offset & I830_RING_START_MASK) ==
+ : pI830->LpRing->mem->offset);
+ :
+ : /* Don't care about the old value. Reserved bits must be zero anyway. */
+ : itemp = pI830->LpRing->mem->offset;
+ : OUTREG(LP_RING + RING_START, itemp);
+ :
+ : if (((pI830->LpRing->mem->size - 4096) & I830_RING_NR_PAGES) !=
+ : pI830->LpRing->mem->size - 4096) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ : "I830SetRingRegs: Ring buffer size - 4096 (%lx) violates its "
+ : "mask (%x)\n", pI830->LpRing->mem->size - 4096,
+ : I830_RING_NR_PAGES);
+ : }
+ : /* Don't care about the old value. Reserved bits must be zero anyway. */
+ : itemp = (pI830->LpRing->mem->size - 4096) & I830_RING_NR_PAGES;
+ : itemp |= (RING_NO_REPORT | RING_VALID);
+ : OUTREG(LP_RING + RING_LEN, itemp);
+ : I830RefreshRing(pScrn);
+ :}
+ :
+ :/*
+ : * This should be called everytime the X server gains control of the screen,
+ : * before any video modes are programmed (ScreenInit, EnterVT).
+ : */
+ :static void
+ :SetHWOperatingState(ScrnInfoPtr pScrn)
+ :{
+ : I830Ptr pI830 = I830PTR(pScrn);
+ :
+ : DPRINTF(PFX, "SetHWOperatingState\n");
+ :
+ : /* Disable clock gating reported to work incorrectly according to the specs.
+ : */
+ : if (IS_I965GM(pI830)) {
+ : OUTREG(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
+ : } else if (IS_I965G(pI830)) {
+ : OUTREG(RENCLK_GATE_D1,
+ : I965_RCC_CLOCK_GATE_DISABLE | I965_ISC_CLOCK_GATE_DISABLE);
+ : } else if (IS_I855(pI830) || IS_I865G(pI830)) {
+ : OUTREG(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE);
+ : } else if (IS_I830(pI830)) {
+ : OUTREG(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
+ : }
+ :
+ : if (!pI830->noAccel)
+ : SetRingRegs(pScrn);
+ : SetFenceRegs(pScrn);
+ : if (!pI830->SWCursor)
+ : I830InitHWCursor(pScrn);
+ :}
+ :
+ :static Bool
+ :SaveHWState(ScrnInfoPtr pScrn)
+ :{
+ : xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : vgaHWPtr hwp = VGAHWPTR(pScrn);
+ : vgaRegPtr vgaReg = &hwp->SavedReg;
+ : int i;
+ :
+ : /* Save video mode information for native mode-setting. */
+ : pI830->saveDSPACNTR = INREG(DSPACNTR);
+ : pI830->savePIPEACONF = INREG(PIPEACONF);
+ : pI830->savePIPEASRC = INREG(PIPEASRC);
+ : pI830->saveFPA0 = INREG(FPA0);
+ : pI830->saveFPA1 = INREG(FPA1);
+ : pI830->saveDPLL_A = INREG(DPLL_A);
+ : if (IS_I965G(pI830))
+ : pI830->saveDPLL_A_MD = INREG(DPLL_A_MD);
+ : pI830->saveHTOTAL_A = INREG(HTOTAL_A);
+ : pI830->saveHBLANK_A = INREG(HBLANK_A);
+ : pI830->saveHSYNC_A = INREG(HSYNC_A);
+ : pI830->saveVTOTAL_A = INREG(VTOTAL_A);
+ : pI830->saveVBLANK_A = INREG(VBLANK_A);
+ : pI830->saveVSYNC_A = INREG(VSYNC_A);
+ : pI830->saveBCLRPAT_A = INREG(BCLRPAT_A);
+ : pI830->saveDSPASTRIDE = INREG(DSPASTRIDE);
+ : pI830->saveDSPASIZE = INREG(DSPASIZE);
+ : pI830->saveDSPAPOS = INREG(DSPAPOS);
+ : pI830->saveDSPABASE = INREG(DSPABASE);
+ :
+ : for(i= 0; i < 256; i++) {
+ : pI830->savePaletteA[i] = INREG(PALETTE_A + (i << 2));
+ : }
+ :
+ : if(xf86_config->num_crtc == 2) {
+ : pI830->savePIPEBCONF = INREG(PIPEBCONF);
+ : pI830->savePIPEBSRC = INREG(PIPEBSRC);
+ : pI830->saveDSPBCNTR = INREG(DSPBCNTR);
+ : pI830->saveFPB0 = INREG(FPB0);
+ : pI830->saveFPB1 = INREG(FPB1);
+ : pI830->saveDPLL_B = INREG(DPLL_B);
+ : if (IS_I965G(pI830))
+ : pI830->saveDPLL_B_MD = INREG(DPLL_B_MD);
+ : pI830->saveHTOTAL_B = INREG(HTOTAL_B);
+ : pI830->saveHBLANK_B = INREG(HBLANK_B);
+ : pI830->saveHSYNC_B = INREG(HSYNC_B);
+ : pI830->saveVTOTAL_B = INREG(VTOTAL_B);
+ : pI830->saveVBLANK_B = INREG(VBLANK_B);
+ : pI830->saveVSYNC_B = INREG(VSYNC_B);
+ : pI830->saveBCLRPAT_B = INREG(BCLRPAT_B);
+ : pI830->saveDSPBSTRIDE = INREG(DSPBSTRIDE);
+ : pI830->saveDSPBSIZE = INREG(DSPBSIZE);
+ : pI830->saveDSPBPOS = INREG(DSPBPOS);
+ : pI830->saveDSPBBASE = INREG(DSPBBASE);
+ : for(i= 0; i < 256; i++) {
+ : pI830->savePaletteB[i] = INREG(PALETTE_B + (i << 2));
+ : }
+ : }
+ :
+ : if (IS_I965G(pI830)) {
+ : pI830->saveDSPASURF = INREG(DSPASURF);
+ : pI830->saveDSPBSURF = INREG(DSPBSURF);
+ : }
+ :
+ : pI830->saveVCLK_DIVISOR_VGA0 = INREG(VCLK_DIVISOR_VGA0);
+ : pI830->saveVCLK_DIVISOR_VGA1 = INREG(VCLK_DIVISOR_VGA1);
+ : pI830->saveVCLK_POST_DIV = INREG(VCLK_POST_DIV);
+ : pI830->saveVGACNTRL = INREG(VGACNTRL);
+ :
+ : for(i = 0; i < 7; i++) {
+ : pI830->saveSWF[i] = INREG(SWF0 + (i << 2));
+ : pI830->saveSWF[i+7] = INREG(SWF00 + (i << 2));
+ : }
+ : pI830->saveSWF[14] = INREG(SWF30);
+ : pI830->saveSWF[15] = INREG(SWF31);
+ : pI830->saveSWF[16] = INREG(SWF32);
+ :
+ : if (IS_MOBILE(pI830) && !IS_I830(pI830))
+ : pI830->saveLVDS = INREG(LVDS);
+ : pI830->savePFIT_CONTROL = INREG(PFIT_CONTROL);
+ :
+ : for (i = 0; i < xf86_config->num_output; i++) {
+ : xf86OutputPtr output = xf86_config->output[i];
+ : if (output->funcs->save)
+ : (*output->funcs->save) (output);
+ : }
+ :
+ : vgaHWUnlock(hwp);
+ : vgaHWSave(pScrn, vgaReg, VGA_SR_FONTS);
+ :
+ : return TRUE;
+ :}
+ :
+ :static Bool
+ :RestoreHWState(ScrnInfoPtr pScrn)
+ :{
+ : xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : vgaHWPtr hwp = VGAHWPTR(pScrn);
+ : vgaRegPtr vgaReg = &hwp->SavedReg;
+ : int i;
+ :
+ : DPRINTF(PFX, "RestoreHWState\n");
+ :
+ :#ifdef XF86DRI
+ : I830DRISetVBlankInterrupt (pScrn, FALSE);
+ :#endif
+ : /* Disable outputs */
+ : for (i = 0; i < xf86_config->num_output; i++) {
+ : xf86OutputPtr output = xf86_config->output[i];
+ : output->funcs->dpms(output, DPMSModeOff);
+ : }
+ : i830WaitForVblank(pScrn);
+ :
+ : /* Disable pipes */
+ : for (i = 0; i < xf86_config->num_crtc; i++) {
+ : xf86CrtcPtr crtc = xf86_config->crtc[i];
+ : crtc->funcs->dpms(crtc, DPMSModeOff);
+ : }
+ : i830WaitForVblank(pScrn);
+ :
+ : if (IS_MOBILE(pI830) && !IS_I830(pI830))
+ : OUTREG(LVDS, pI830->saveLVDS);
+ :
+ : if (!IS_I830(pI830) && !IS_845G(pI830))
+ : OUTREG(PFIT_CONTROL, pI830->savePFIT_CONTROL);
+ :
+ : if (pI830->saveDPLL_A & DPLL_VCO_ENABLE)
+ : {
+ : OUTREG(DPLL_A, pI830->saveDPLL_A & ~DPLL_VCO_ENABLE);
+ : usleep(150);
+ : }
+ : OUTREG(FPA0, pI830->saveFPA0);
+ : OUTREG(FPA1, pI830->saveFPA1);
+ : OUTREG(DPLL_A, pI830->saveDPLL_A);
+ : usleep(150);
+ : if (IS_I965G(pI830))
+ : OUTREG(DPLL_A_MD, pI830->saveDPLL_A_MD);
+ : else
+ : OUTREG(DPLL_A, pI830->saveDPLL_A);
+ : usleep(150);
+ :
+ : OUTREG(HTOTAL_A, pI830->saveHTOTAL_A);
+ : OUTREG(HBLANK_A, pI830->saveHBLANK_A);
+ : OUTREG(HSYNC_A, pI830->saveHSYNC_A);
+ : OUTREG(VTOTAL_A, pI830->saveVTOTAL_A);
+ : OUTREG(VBLANK_A, pI830->saveVBLANK_A);
+ : OUTREG(VSYNC_A, pI830->saveVSYNC_A);
+ : OUTREG(BCLRPAT_A, pI830->saveBCLRPAT_A);
+ :
+ : OUTREG(DSPASTRIDE, pI830->saveDSPASTRIDE);
+ : OUTREG(DSPASIZE, pI830->saveDSPASIZE);
+ : OUTREG(DSPAPOS, pI830->saveDSPAPOS);
+ : OUTREG(PIPEASRC, pI830->savePIPEASRC);
+ : OUTREG(DSPABASE, pI830->saveDSPABASE);
+ : if (IS_I965G(pI830))
+ : OUTREG(DSPASURF, pI830->saveDSPASURF);
+ : OUTREG(PIPEACONF, pI830->savePIPEACONF);
+ : i830WaitForVblank(pScrn);
+ : OUTREG(DSPACNTR, pI830->saveDSPACNTR);
+ : OUTREG(DSPABASE, INREG(DSPABASE));
+ : i830WaitForVblank(pScrn);
+ :
+ : if(xf86_config->num_crtc == 2)
+ : {
+ : if (pI830->saveDPLL_B & DPLL_VCO_ENABLE)
+ : {
+ : OUTREG(DPLL_B, pI830->saveDPLL_B & ~DPLL_VCO_ENABLE);
+ : usleep(150);
+ : }
+ : OUTREG(FPB0, pI830->saveFPB0);
+ : OUTREG(FPB1, pI830->saveFPB1);
+ : OUTREG(DPLL_B, pI830->saveDPLL_B);
+ : usleep(150);
+ : if (IS_I965G(pI830))
+ : OUTREG(DPLL_B_MD, pI830->saveDPLL_B_MD);
+ : else
+ : OUTREG(DPLL_B, pI830->saveDPLL_B);
+ : usleep(150);
+ :
+ : OUTREG(HTOTAL_B, pI830->saveHTOTAL_B);
+ : OUTREG(HBLANK_B, pI830->saveHBLANK_B);
+ : OUTREG(HSYNC_B, pI830->saveHSYNC_B);
+ : OUTREG(VTOTAL_B, pI830->saveVTOTAL_B);
+ : OUTREG(VBLANK_B, pI830->saveVBLANK_B);
+ : OUTREG(VSYNC_B, pI830->saveVSYNC_B);
+ : OUTREG(BCLRPAT_B, pI830->saveBCLRPAT_B);
+ : OUTREG(DSPBSTRIDE, pI830->saveDSPBSTRIDE);
+ : OUTREG(DSPBSIZE, pI830->saveDSPBSIZE);
+ : OUTREG(DSPBPOS, pI830->saveDSPBPOS);
+ : OUTREG(PIPEBSRC, pI830->savePIPEBSRC);
+ : OUTREG(DSPBBASE, pI830->saveDSPBBASE);
+ : if (IS_I965G(pI830))
+ : OUTREG(DSPBSURF, pI830->saveDSPBSURF);
+ : OUTREG(PIPEBCONF, pI830->savePIPEBCONF);
+ : i830WaitForVblank(pScrn);
+ : OUTREG(DSPBCNTR, pI830->saveDSPBCNTR);
+ : OUTREG(DSPBBASE, INREG(DSPBBASE));
+ : i830WaitForVblank(pScrn);
+ : }
+ :
+ : /* Restore outputs */
+ : for (i = 0; i < xf86_config->num_output; i++) {
+ : xf86OutputPtr output = xf86_config->output[i];
+ : if (output->funcs->restore)
+ : output->funcs->restore(output);
+ : }
+ :
+ : OUTREG(VGACNTRL, pI830->saveVGACNTRL);
+ :
+ : OUTREG(VCLK_DIVISOR_VGA0, pI830->saveVCLK_DIVISOR_VGA0);
+ : OUTREG(VCLK_DIVISOR_VGA1, pI830->saveVCLK_DIVISOR_VGA1);
+ : OUTREG(VCLK_POST_DIV, pI830->saveVCLK_POST_DIV);
+ :
+ : for(i = 0; i < 256; i++) {
+ : OUTREG(PALETTE_A + (i << 2), pI830->savePaletteA[i]);
+ : }
+ :
+ : if(xf86_config->num_crtc == 2) {
+ : for(i= 0; i < 256; i++) {
+ : OUTREG(PALETTE_B + (i << 2), pI830->savePaletteB[i]);
+ : }
+ : }
+ :
+ : for(i = 0; i < 7; i++) {
+ : OUTREG(SWF0 + (i << 2), pI830->saveSWF[i]);
+ : OUTREG(SWF00 + (i << 2), pI830->saveSWF[i+7]);
+ : }
+ :
+ : OUTREG(SWF30, pI830->saveSWF[14]);
+ : OUTREG(SWF31, pI830->saveSWF[15]);
+ : OUTREG(SWF32, pI830->saveSWF[16]);
+ :
+ : vgaHWRestore(pScrn, vgaReg, VGA_SR_FONTS);
+ : vgaHWLock(hwp);
+ :
+ : return TRUE;
+ :}
+ :
+ :static void
+ :I830PointerMoved(int index, int x, int y)
+ :{
+ : ScrnInfoPtr pScrn = xf86Screens[index];
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : int newX = x, newY = y;
+ :
+ : switch (pI830->rotation) {
+ : case RR_Rotate_0:
+ : break;
+ : case RR_Rotate_90:
+ : newX = y;
+ : newY = pScrn->pScreen->width - x - 1;
+ : break;
+ : case RR_Rotate_180:
+ : newX = pScrn->pScreen->width - x - 1;
+ : newY = pScrn->pScreen->height - y - 1;
+ : break;
+ : case RR_Rotate_270:
+ : newX = pScrn->pScreen->height - y - 1;
+ : newY = x;
+ : break;
+ : }
+ :
+ : (*pI830->PointerMoved)(index, newX, newY);
+ :}
+ :
+ :static Bool
+ :I830InitFBManager(
+ : ScreenPtr pScreen,
+ : BoxPtr FullBox
+ :){
+ : ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ : RegionRec ScreenRegion;
+ : RegionRec FullRegion;
+ : BoxRec ScreenBox;
+ : Bool ret;
+ :
+ : ScreenBox.x1 = 0;
+ : ScreenBox.y1 = 0;
+ : ScreenBox.x2 = pScrn->displayWidth;
+ : if (pScrn->virtualX > pScrn->virtualY)
+ : ScreenBox.y2 = pScrn->virtualX;
+ : else
+ : ScreenBox.y2 = pScrn->virtualY;
+ :
+ : if((FullBox->x1 > ScreenBox.x1) || (FullBox->y1 > ScreenBox.y1) ||
+ : (FullBox->x2 < ScreenBox.x2) || (FullBox->y2 < ScreenBox.y2)) {
+ : return FALSE;
+ : }
+ :
+ : if (FullBox->y2 < FullBox->y1) return FALSE;
+ : if (FullBox->x2 < FullBox->x2) return FALSE;
+ :
+ : REGION_INIT(pScreen, &ScreenRegion, &ScreenBox, 1);
+ : REGION_INIT(pScreen, &FullRegion, FullBox, 1);
+ :
+ : REGION_SUBTRACT(pScreen, &FullRegion, &FullRegion, &ScreenRegion);
+ :
+ : ret = xf86InitFBManagerRegion(pScreen, &FullRegion);
+ :
+ : REGION_UNINIT(pScreen, &ScreenRegion);
+ : REGION_UNINIT(pScreen, &FullRegion);
+ :
+ : return ret;
+ :}
+ :
+ :/**
+ : * Intialiazes the hardware for the 3D pipeline use in the 2D driver.
+ : *
+ : * Some state caching is performed to avoid redundant state emits. This
+ : * function is also responsible for marking the state as clobbered for DRI
+ : * clients.
+ : */
+ :void
+ :IntelEmitInvarientState(ScrnInfoPtr pScrn)
+ 3 0.0033 :{ /* IntelEmitInvarientState total: 36 0.0392 */
+ 3 0.0033 : I830Ptr pI830 = I830PTR(pScrn);
+ : CARD32 ctx_addr;
+ :
+ 2 0.0022 : if (pI830->noAccel)
+ : return;
+ :
+ :#ifdef XF86DRI
+ 4 0.0044 : if (pI830->directRenderingEnabled) {
+ 4 0.0044 : drmI830Sarea *sarea = DRIGetSAREAPrivate(pScrn->pScreen);
+ :
+ : /* Mark that the X Server was the last holder of the context */
+ 5 0.0054 : if (sarea)
+ 3 0.0033 : sarea->ctxOwner = DRIGetContext(pScrn->pScreen);
+ : }
+ :#endif
+ :
+ : /* If we've emitted our state since the last clobber by another client,
+ : * skip it.
+ : */
+ 8 0.0087 : if (*pI830->last_3d != LAST_3D_OTHER)
+ : return;
+ :
+ : ctx_addr = pI830->logical_context->offset;
+ : assert((pI830->logical_context->offset & 2047) == 0);
+ : {
+ : BEGIN_LP_RING(2);
+ : OUT_RING(MI_SET_CONTEXT);
+ : OUT_RING(pI830->logical_context->offset |
+ : CTXT_NO_RESTORE |
+ : CTXT_PALETTE_SAVE_DISABLE | CTXT_PALETTE_RESTORE_DISABLE);
+ : ADVANCE_LP_RING();
+ : }
+ :
+ : if (!IS_I965G(pI830))
+ : {
+ : if (IS_I9XX(pI830))
+ : I915EmitInvarientState(pScrn);
+ : else
+ : I830EmitInvarientState(pScrn);
+ : }
+ 4 0.0044 :}
+ :
+ :#ifdef XF86DRI_MM
+ :#ifndef XSERVER_LIBDRM_MM
+ :
+ :static int
+ :I830DrmMMInit(int drmFD, unsigned long pageOffs, unsigned long pageSize,
+ : unsigned memType)
+ :{
+ :
+ : drm_mm_init_arg_t arg;
+ : int ret;
+ :
+ : memset(&arg, 0, sizeof(arg));
+ : arg.req.op = mm_init;
+ : arg.req.p_offset = pageOffs;
+ : arg.req.p_size = pageSize;
+ : arg.req.mem_type = memType;
+ :
+ : ret = ioctl(drmFD, DRM_IOCTL_MM_INIT, &arg);
+ :
+ : if (ret)
+ : return -errno;
+ :
+ : return 0;
+ :
+ :}
+ :
+ :static int
+ :I830DrmMMTakedown(int drmFD, unsigned memType)
+ :{
+ : drm_mm_init_arg_t arg;
+ : int ret = 0;
+ :
+ : memset(&arg, 0, sizeof(arg));
+ : arg.req.op = mm_takedown;
+ : arg.req.mem_type = memType;
+ : if (ioctl(drmFD, DRM_IOCTL_MM_INIT, &arg)) {
+ : ret = -errno;
+ : }
+ :
+ : return ret;
+ :}
+ :
+ :static int I830DrmMMLock(int fd, unsigned memType)
+ :{
+ : drm_mm_init_arg_t arg;
+ : int ret;
+ :
+ : memset(&arg, 0, sizeof(arg));
+ : arg.req.op = mm_lock;
+ : arg.req.mem_type = memType;
+ :
+ : do{
+ : ret = ioctl(fd, DRM_IOCTL_MM_INIT, &arg);
+ : } while (ret && errno == EAGAIN);
+ :
+ : return ret;
+ :}
+ :
+ :static int I830DrmMMUnlock(int fd, unsigned memType)
+ :{
+ : drm_mm_init_arg_t arg;
+ : int ret;
+ :
+ : memset(&arg, 0, sizeof(arg));
+ : arg.req.op = mm_unlock;
+ : arg.req.mem_type = memType;
+ :
+ : do{
+ : ret = ioctl(fd, DRM_IOCTL_MM_INIT, &arg);
+ : } while (ret && errno == EAGAIN);
+ :
+ : return ret;
+ :}
+ :
+ :#endif
+ :#endif /* XF86DRI_MM */
+ :
+ :static Bool
+ :I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
+ :{
+ : ScrnInfoPtr pScrn;
+ : vgaHWPtr hwp;
+ : I830Ptr pI830;
+ : VisualPtr visual;
+ : I830Ptr pI8301 = NULL;
+ : unsigned long sys_mem;
+ : int i;
+ : Bool allocation_done = FALSE;
+ : MessageType from;
+ :#ifdef XF86DRI
+ : Bool driDisabled;
+ :#ifdef XF86DRI_MM
+ : unsigned long savedMMSize;
+ :#endif
+ :#endif
+ :
+ : pScrn = xf86Screens[pScreen->myNum];
+ : pI830 = I830PTR(pScrn);
+ : hwp = VGAHWPTR(pScrn);
+ :
+ : pScrn->displayWidth = (pScrn->virtualX + 63) & ~63;
+ :
+ : /*
+ : * The "VideoRam" config file parameter specifies the maximum amount of
+ : * memory that will be used/allocated. When not present, we allow the
+ : * driver to allocate as much memory as it wishes to satisfy its
+ : * allocations, but if agpgart support isn't available, it gets limited
+ : * to the amount of pre-allocated ("stolen") memory.
+ : *
+ : * Note that in using this value for allocator initialization, we're
+ : * limiting aperture allocation to the VideoRam option, rather than limiting
+ : * actual memory allocation, so alignment and things will cause less than
+ : * VideoRam to be actually used.
+ : */
+ : if (pI830->pEnt->device->videoRam == 0) {
+ : from = X_DEFAULT;
+ : pScrn->videoRam = pI830->FbMapSize / KB(1);
+ : } else {
+ :#if 0
+ : from = X_CONFIG;
+ : pScrn->videoRam = pI830->pEnt->device->videoRam;
+ :#else
+ : /* Disable VideoRam configuration, at least for now. Previously,
+ : * VideoRam was necessary to avoid overly low limits on allocated
+ : * memory, so users created larger, yet still small, fixed allocation
+ : * limits in their config files. Now, the driver wants to allocate more,
+ : * and the old intention of the VideoRam lines that had been entered is
+ : * obsolete.
+ : */
+ : from = X_DEFAULT;
+ : pScrn->videoRam = pI830->FbMapSize / KB(1);
+ :
+ : if (pScrn->videoRam != pI830->pEnt->device->videoRam) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ : "VideoRam configuration found, which is no longer "
+ : "recommended.\n");
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ : "Continuing with default %dkB VideoRam instead of %d "
+ : "kB.\n",
+ : pScrn->videoRam, pI830->pEnt->device->videoRam);
+ : }
+ :#endif
+ : }
+ :
+ : /* Limit videoRam to how much we might be able to allocate from AGP */
+ : sys_mem = I830CheckAvailableMemory(pScrn);
+ : if (sys_mem == -1) {
+ : if (pScrn->videoRam > pI830->stolen_size / KB(1)) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ : "/dev/agpgart is either not available, or no memory "
+ : "is available\nfor allocation. "
+ : "Using pre-allocated memory only.\n");
+ : pScrn->videoRam = pI830->stolen_size / KB(1);
+ : }
+ : pI830->StolenOnly = TRUE;
+ : } else {
+ : if (sys_mem + (pI830->stolen_size / 1024) < pScrn->videoRam) {
+ : pScrn->videoRam = sys_mem + (pI830->stolen_size / 1024);
+ : from = X_PROBED;
+ : if (sys_mem + (pI830->stolen_size / 1024) <
+ : pI830->pEnt->device->videoRam)
+ : {
+ : xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ : "VideoRAM reduced to %d kByte "
+ : "(limited to available sysmem)\n", pScrn->videoRam);
+ : }
+ : }
+ : }
+ :
+ : /* Limit video RAM to the actual aperture size */
+ : if (pScrn->videoRam > pI830->FbMapSize / 1024) {
+ : pScrn->videoRam = pI830->FbMapSize / 1024;
+ : if (pI830->FbMapSize / 1024 < pI830->pEnt->device->videoRam) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ : "VideoRam reduced to %d kByte (limited to aperture "
+ : "size)\n",
+ : pScrn->videoRam);
+ : }
+ : }
+ :
+ : /* Make sure it's on a page boundary */
+ : if (pScrn->videoRam & 3) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "VideoRam reduced to %d KB "
+ : "(page aligned - was %d KB)\n",
+ : pScrn->videoRam & ~3, pScrn->videoRam);
+ : pScrn->videoRam &= ~3;
+ : }
+ :
+ : /* Set up our video memory allocator for the chosen videoRam */
+ : if (!i830_allocator_init(pScrn, 0, pScrn->videoRam * KB(1))) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ : "Couldn't initialize video memory allocator\n");
+ : PreInitCleanup(pScrn);
+ : return FALSE;
+ : }
+ :
+ : xf86DrvMsg(pScrn->scrnIndex,
+ : pI830->pEnt->device->videoRam ? X_CONFIG : X_DEFAULT,
+ : "VideoRam: %d KB\n", pScrn->videoRam);
+ :
+ : if (xf86GetOptValInteger(pI830->Options, OPTION_CACHE_LINES,
+ : &(pI830->CacheLines))) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Requested %d cache lines\n",
+ : pI830->CacheLines);
+ : } else {
+ : pI830->CacheLines = -1;
+ : }
+ :
+ : pI830->disableTiling = FALSE;
+ :
+ : if (I830IsPrimary(pScrn)) {
+ : /* Alloc our pointers for the primary head */
+ : if (!pI830->LpRing)
+ : pI830->LpRing = xcalloc(1, sizeof(I830RingBuffer));
+ : if (!pI830->overlayOn)
+ : pI830->overlayOn = xalloc(sizeof(Bool));
+ : if (!pI830->last_3d)
+ : pI830->last_3d = xalloc(sizeof(enum last_3d));
+ : if (!pI830->LpRing || !pI830->overlayOn || !pI830->last_3d) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ : "Could not allocate primary data structures.\n");
+ : return FALSE;
+ : }
+ : *pI830->last_3d = LAST_3D_OTHER;
+ : *pI830->overlayOn = FALSE;
+ : if (pI830->entityPrivate)
+ : pI830->entityPrivate->XvInUse = -1;
+ : } else {
+ : /* Make our second head point to the first heads structures */
+ : pI8301 = I830PTR(pI830->entityPrivate->pScrn_1);
+ : pI830->LpRing = pI8301->LpRing;
+ : pI830->overlay_regs = pI8301->overlay_regs;
+ : pI830->overlayOn = pI8301->overlayOn;
+ : pI830->last_3d = pI8301->last_3d;
+ : }
+ :
+ : /* Need MMIO mapped to do GTT lookups during memory allocation. */
+ : I830MapMMIO(pScrn);
+ :
+ :#if defined(XF86DRI)
+ : /*
+ : * If DRI is potentially usable, check if there is enough memory available
+ : * for it, and if there's also enough to allow tiling to be enabled.
+ : */
+ :
+ : if (!I830CheckDRIAvailable(pScrn)) {
+ : pI830->directRenderingDisabled = TRUE;
+ :#ifdef XF86DRI_MM
+ : pI830->mmSize = 0;
+ :#endif
+ : }
+ :
+ :#ifdef I830_XV
+ : /*
+ : * Set this so that the overlay allocation is factored in when
+ : * appropriate.
+ : */
+ : pI830->XvEnabled = !pI830->XvDisabled;
+ :#endif
+ :
+ : if (!pI830->directRenderingDisabled) {
+ : int savedDisplayWidth = pScrn->displayWidth;
+ : Bool tiled = FALSE;
+ :
+ : if (IS_I965G(pI830)) {
+ : int tile_pixels = 512 / pI830->cpp;
+ : pScrn->displayWidth = (pScrn->displayWidth + tile_pixels - 1) &
+ : ~(tile_pixels - 1);
+ : tiled = TRUE;
+ : } else {
+ : /* Good pitches to allow tiling. Don't care about pitches < 1024
+ : * pixels.
+ : */
+ : static const int pitches[] = {
+ : 1024,
+ : 2048,
+ : 4096,
+ : 8192,
+ : 0
+ : };
+ :
+ : for (i = 0; pitches[i] != 0; i++) {
+ : if (pitches[i] >= pScrn->displayWidth) {
+ : pScrn->displayWidth = pitches[i];
+ : tiled = TRUE;
+ : break;
+ : }
+ : }
+ : }
+ :
+ : /* Attempt several rounds of allocation to get 2d and 3d memory to fit:
+ : *
+ : * 0: tiled, large memory manager
+ : * 1: tiled, small memory manager
+ : * 2: untiled, large
+ : * 3: untiled, small
+ : */
+ :
+ : pI830->disableTiling = FALSE;
+ :#ifdef XF86DRI_MM
+ : savedMMSize = pI830->mmSize;
+ :#define MM_TURNS 4
+ :#else
+ :#define MM_TURNS 2
+ :#endif
+ : for (i = 0; i < MM_TURNS; i++) {
+ : if (!tiled && i < 2)
+ : continue;
+ :
+ : if (i >= MM_TURNS/2) {
+ : /* For further allocations, disable tiling */
+ : pI830->disableTiling = TRUE;
+ : pScrn->displayWidth = savedDisplayWidth;
+ : if (pI830->allowPageFlip)
+ : xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ : "Couldn't allocate tiled memory, page flipping "
+ : "disabled\n");
+ : pI830->allowPageFlip = FALSE;
+ : }
+ :
+ :#ifdef XF86DRI_MM
+ : if (i & 1) {
+ : /* For this allocation, switch to a smaller DRI memory manager
+ : * size.
+ : */
+ : pI830->mmSize = I830_MM_MINPAGES * GTT_PAGE_SIZE / KB(1);
+ : } else {
+ : pI830->mmSize = savedMMSize;
+ : }
+ :
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ : "Attempting memory allocation with %s buffers and \n"
+ : "\t %s DRI memory manager reservation:\n",
+ : (i & 2) ? "untiled" : "tiled",
+ : (i & 1) ? "small" : "large");
+ :#else
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ : "Attempting memory allocation with %s buffers:\n",
+ : (i & 1) ? "untiled" : "tiled");
+ :#endif
+ :
+ : if (i830_allocate_2d_memory(pScrn) &&
+ : i830_allocate_3d_memory(pScrn))
+ : {
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Success.\n");
+ : if (pScrn->displayWidth != savedDisplayWidth) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ : "Increasing the scanline pitch to allow tiling mode "
+ : "(%d -> %d).\n",
+ : savedDisplayWidth, pScrn->displayWidth);
+ : }
+ : allocation_done = TRUE;
+ : break;
+ : }
+ :
+ : i830_reset_allocations(pScrn);
+ : }
+ :
+ : if (i == MM_TURNS) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ : "Not enough video memory. Disabling DRI.\n");
+ :#ifdef XF86DRI_MM
+ : pI830->mmSize = 0;
+ :#endif
+ : pI830->directRenderingDisabled = TRUE;
+ : }
+ : } else
+ :#endif
+ : pI830->disableTiling = TRUE; /* no DRI - so disableTiling */
+ :
+ : if (!allocation_done) {
+ : if (!i830_allocate_2d_memory(pScrn)) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ : "Couldn't allocate video memory\n");
+ : return FALSE;
+ : }
+ : allocation_done = TRUE;
+ : }
+ :
+ : I830UnmapMMIO(pScrn);
+ :
+ : i830_describe_allocations(pScrn, 1, "");
+ :
+ : if (!IS_I965G(pI830) && pScrn->displayWidth > 2048) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ : "Cannot support DRI with frame buffer width > 2048.\n");
+ : pI830->disableTiling = TRUE;
+ : pI830->directRenderingDisabled = TRUE;
+ : }
+ :
+ : pScrn->displayWidth = pScrn->displayWidth;
+ :
+ :#ifdef HAS_MTRR_SUPPORT
+ : {
+ : int fd;
+ : struct mtrr_gentry gentry;
+ : struct mtrr_sentry sentry;
+ :
+ : if ( ( fd = open ("/proc/mtrr", O_RDONLY, 0) ) != -1 ) {
+ : for (gentry.regnum = 0; ioctl (fd, MTRRIOC_GET_ENTRY, &gentry) == 0;
+ : ++gentry.regnum) {
+ :
+ : if (gentry.size < 1) {
+ : /* DISABLED */
+ : continue;
+ : }
+ :
+ : /* Check the MTRR range is one we like and if not - remove it.
+ : * The Xserver common layer will then setup the right range
+ : * for us.
+ : */
+ : if (gentry.base == pI830->LinearAddr &&
+ : gentry.size < pI830->FbMapSize) {
+ :
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ : "Removing bad MTRR range (base 0x%lx, size 0x%x)\n",
+ : gentry.base, gentry.size);
+ :
+ : sentry.base = gentry.base;
+ : sentry.size = gentry.size;
+ : sentry.type = gentry.type;
+ :
+ : if (ioctl (fd, MTRRIOC_DEL_ENTRY, &sentry) == -1) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ : "Failed to remove bad MTRR range\n");
+ : }
+ : }
+ : }
+ : close(fd);
+ : }
+ : }
+ :#endif
+ :
+ : pI830->starting = TRUE;
+ :
+ : miClearVisualTypes();
+ : if (!miSetVisualTypes(pScrn->depth,
+ : miGetDefaultVisualMask(pScrn->depth),
+ : pScrn->rgbBits, pScrn->defaultVisual))
+ : return FALSE;
+ : if (!miSetPixmapDepths())
+ : return FALSE;
+ :
+ :#ifdef I830_XV
+ : pI830->XvEnabled = !pI830->XvDisabled;
+ : if (pI830->XvEnabled) {
+ : if (!I830IsPrimary(pScrn)) {
+ : if (!pI8301->XvEnabled || pI830->noAccel) {
+ : pI830->XvEnabled = FALSE;
+ : xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Xv is disabled.\n");
+ : }
+ : } else
+ : if (pI830->noAccel || pI830->StolenOnly) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Xv is disabled because it "
+ : "needs 2D accel and AGPGART.\n");
+ : pI830->XvEnabled = FALSE;
+ : }
+ : }
+ :#else
+ : pI830->XvEnabled = FALSE;
+ :#endif
+ :
+ : if (!pI830->noAccel) {
+ : if (pI830->LpRing->mem->size == 0) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ : "Disabling acceleration because the ring buffer "
+ : "allocation failed.\n");
+ : pI830->noAccel = TRUE;
+ : }
+ : }
+ :
+ :#ifdef I830_XV
+ : if (pI830->XvEnabled) {
+ : if (pI830->noAccel) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Disabling Xv because it "
+ : "needs 2D acceleration.\n");
+ : pI830->XvEnabled = FALSE;
+ : }
+ : if (!IS_I9XX(pI830) && pI830->overlay_regs == NULL) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ : "Disabling Xv because the overlay register buffer "
+ : "allocation failed.\n");
+ : pI830->XvEnabled = FALSE;
+ : }
+ : }
+ :#endif
+ :
+ :#ifdef XF86DRI
+ : /*
+ : * pI830->directRenderingDisabled is set once in PreInit. Reinitialise
+ : * pI830->directRenderingEnabled based on it each generation.
+ : */
+ : pI830->directRenderingEnabled = !pI830->directRenderingDisabled;
+ : /*
+ : * Setup DRI after visuals have been established, but before fbScreenInit
+ : * is called. fbScreenInit will eventually call into the drivers
+ : * InitGLXVisuals call back.
+ : */
+ :
+ : if (pI830->directRenderingEnabled) {
+ : if (pI830->noAccel || pI830->SWCursor || (pI830->StolenOnly && I830IsPrimary(pScrn))) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "DRI is disabled because it "
+ : "needs HW cursor, 2D accel and AGPGART.\n");
+ : pI830->directRenderingEnabled = FALSE;
+ : i830_free_3d_memory(pScrn);
+ : }
+ : }
+ :
+ : driDisabled = !pI830->directRenderingEnabled;
+ :
+ : if (pI830->directRenderingEnabled)
+ : pI830->directRenderingEnabled = I830DRIScreenInit(pScreen);
+ :
+ : if (!pI830->directRenderingEnabled) {
+ : i830_free_3d_memory(pScrn);
+ : }
+ :
+ :#else
+ : pI830->directRenderingEnabled = FALSE;
+ :#endif
+ :
+ :#ifdef XF86DRI
+ : if (pI830->directRenderingEnabled)
+ : pI830->directRenderingEnabled = I830DRIDoMappings(pScreen);
+ :
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Page Flipping %sabled\n",
+ : pI830->allowPageFlip ? "en" : "dis");
+ :#endif
+ :
+ : DPRINTF(PFX, "assert( if(!I830MapMem(pScrn)) )\n");
+ : if (!I830MapMem(pScrn))
+ : return FALSE;
+ :
+ : pScrn->memPhysBase = (unsigned long)pI830->FbBase;
+ :
+ : if (I830IsPrimary(pScrn)) {
+ : pScrn->fbOffset = pI830->front_buffer->offset;
+ : } else {
+ : pScrn->fbOffset = pI8301->front_buffer_2->offset;
+ : }
+ :
+ : pI830->xoffset = (pScrn->fbOffset / pI830->cpp) % pScrn->displayWidth;
+ : pI830->yoffset = (pScrn->fbOffset / pI830->cpp) / pScrn->displayWidth;
+ :
+ : vgaHWSetMmioFuncs(hwp, pI830->MMIOBase, 0);
+ : vgaHWGetIOBase(hwp);
+ : DPRINTF(PFX, "assert( if(!vgaHWMapMem(pScrn)) )\n");
+ : if (!vgaHWMapMem(pScrn))
+ : return FALSE;
+ :
+ : DPRINTF(PFX, "assert( if(!I830EnterVT(scrnIndex, 0)) )\n");
+ :
+ : if (!pI830->useEXA) {
+ : if (I830IsPrimary(pScrn)) {
+ : if (!I830InitFBManager(pScreen, &(pI830->FbMemBox))) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ : "Failed to init memory manager\n");
+ : }
+ : } else {
+ : if (!I830InitFBManager(pScreen, &(pI8301->FbMemBox2))) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ : "Failed to init memory manager\n");
+ : }
+ : }
+ : }
+ :
+ : if (pScrn->virtualX > pScrn->displayWidth)
+ : pScrn->displayWidth = pScrn->virtualX;
+ :
+ : DPRINTF(PFX, "assert( if(!fbScreenInit(pScreen, ...) )\n");
+ : if (!fbScreenInit(pScreen, pI830->FbBase + pScrn->fbOffset,
+ : pScrn->virtualX, pScrn->virtualY,
+ : pScrn->xDpi, pScrn->yDpi,
+ : pScrn->displayWidth, pScrn->bitsPerPixel))
+ : return FALSE;
+ :
+ : if (pScrn->bitsPerPixel > 8) {
+ : /* Fixup RGB ordering */
+ : visual = pScreen->visuals + pScreen->numVisuals;
+ : while (--visual >= pScreen->visuals) {
+ : if ((visual->class | DynamicClass) == DirectColor) {
+ : visual->offsetRed = pScrn->offset.red;
+ : visual->offsetGreen = pScrn->offset.green;
+ : visual->offsetBlue = pScrn->offset.blue;
+ : visual->redMask = pScrn->mask.red;
+ : visual->greenMask = pScrn->mask.green;
+ : visual->blueMask = pScrn->mask.blue;
+ : }
+ : }
+ : }
+ :
+ : fbPictureInit(pScreen, NULL, 0);
+ :
+ : xf86SetBlackWhitePixels(pScreen);
+ :
+ : xf86DiDGAInit (pScreen, pI830->LinearAddr + pScrn->fbOffset);
+ :
+ : DPRINTF(PFX,
+ : "assert( if(!I830InitFBManager(pScreen, &(pI830->FbMemBox))) )\n");
+ :
+ : if (!pI830->noAccel) {
+ : if (!I830AccelInit(pScreen)) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ : "Hardware acceleration initialization failed\n");
+ : }
+ : }
+ :
+ : miInitializeBackingStore(pScreen);
+ : xf86SetBackingStore(pScreen);
+ : xf86SetSilkenMouse(pScreen);
+ : miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
+ :
+ : if (!pI830->SWCursor) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Initializing HW Cursor\n");
+ : if (!I830CursorInit(pScreen))
+ : xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ : "Hardware cursor initialization failed\n");
+ : } else
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Initializing SW Cursor!\n");
+ :
+ : if (!I830EnterVT(scrnIndex, 0))
+ : return FALSE;
+ :
+ : DPRINTF(PFX, "assert( if(!miCreateDefColormap(pScreen)) )\n");
+ : if (!miCreateDefColormap(pScreen))
+ : return FALSE;
+ :
+ : DPRINTF(PFX, "assert( if(!xf86HandleColormaps(pScreen, ...)) )\n");
+ : if (!xf86HandleColormaps(pScreen, 256, 8, I830LoadPalette, NULL,
+ : CMAP_RELOAD_ON_MODE_SWITCH |
+ : CMAP_PALETTED_TRUECOLOR)) {
+ : return FALSE;
+ : }
+ :
+ : xf86DPMSInit(pScreen, xf86DPMSSet, 0);
+ :
+ :#ifdef I830_XV
+ : /* Init video */
+ : if (pI830->XvEnabled)
+ : I830InitVideo(pScreen);
+ :#endif
+ :
+ :#ifdef XF86DRI
+ : if (pI830->directRenderingEnabled) {
+ : pI830->directRenderingEnabled = I830DRIFinishScreenInit(pScreen);
+ : }
+ :#endif
+ :
+ : /* Setup 3D engine, needed for rotation too */
+ : IntelEmitInvarientState(pScrn);
+ :
+ :#ifdef XF86DRI
+ : if (pI830->directRenderingEnabled) {
+ : pI830->directRenderingOpen = TRUE;
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO, "direct rendering: Enabled\n");
+ : } else {
+ : if (driDisabled)
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO, "direct rendering: Disabled\n");
+ : else
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO, "direct rendering: Failed\n");
+ : }
+ :#else
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO, "direct rendering: Not available\n");
+ :#endif
+ :
+ : pScreen->SaveScreen = xf86SaveScreen;
+ : pI830->CloseScreen = pScreen->CloseScreen;
+ : pScreen->CloseScreen = I830CloseScreen;
+ :
+ : if (!xf86CrtcScreenInit (pScreen))
+ : return FALSE;
+ :
+ : /* Wrap pointer motion to flip touch screen around */
+ : pI830->PointerMoved = pScrn->PointerMoved;
+ : pScrn->PointerMoved = I830PointerMoved;
+ :
+ : if (serverGeneration == 1)
+ : xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
+ :
+ : if (IS_I965G(pI830)) {
+ : /* turn off clock gating */
+ :#if 0
+ : OUTREG(0x6204, 0x70804000);
+ : OUTREG(0x6208, 0x00000001);
+ :#else
+ : OUTREG(0x6204, 0x70000000);
+ :#endif
+ : /* Enable DAP stateless accesses.
+ : * Required for all i965 steppings.
+ : */
+ : OUTREG(SVG_WORK_CTL, 0x00000010);
+ : }
+ :
+ : pI830->starting = FALSE;
+ : pI830->closing = FALSE;
+ : pI830->suspended = FALSE;
+ :
+ :#ifdef XF86DRI_MM
+ : if (pI830->directRenderingEnabled && (pI830->mmModeFlags & I830_KERNEL_MM))
+ : {
+ : if (pI830->memory_manager == NULL) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ : "Too little AGP aperture space for DRM memory manager.\n"
+ : "\tPlease increase AGP aperture size from BIOS configuration screen.\n"
+ : "\tDisabling DRI.\n");
+ : pI830->directRenderingOpen = FALSE;
+ : I830DRICloseScreen(pScreen);
+ : pI830->directRenderingEnabled = FALSE;
+ : } else {
+ : unsigned long aperEnd = ROUND_DOWN_TO(pI830->memory_manager->offset +
+ : pI830->memory_manager->size,
+ : GTT_PAGE_SIZE) / GTT_PAGE_SIZE;
+ : unsigned long aperStart = ROUND_TO(pI830->memory_manager->offset,
+ : GTT_PAGE_SIZE) / GTT_PAGE_SIZE;
+ :
+ :#ifndef XSERVER_LIBDRM_MM
+ : if (I830DrmMMInit(pI830->drmSubFD, aperStart, aperEnd - aperStart,
+ : DRM_BO_MEM_TT)) {
+ :#else
+ : if (drmMMInit(pI830->drmSubFD, aperStart, aperEnd - aperStart,
+ : DRM_BO_MEM_TT)) {
+ :#endif
+ : xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ : "Could not initialize the DRM memory manager.\n");
+ :
+ : pI830->directRenderingOpen = FALSE;
+ : I830DRICloseScreen(pScreen);
+ : pI830->directRenderingEnabled = FALSE;
+ : }
+ : }
+ : }
+ :#endif /* XF86DRI_MM */
+ :
+ : return TRUE;
+ :}
+ :
+ :static void
+ :i830AdjustFrame(int scrnIndex, int x, int y, int flags)
+ :{
+ : ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ : xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : xf86OutputPtr output = config->output[config->compat_output];
+ : xf86CrtcPtr crtc = output->crtc;
+ :
+ : DPRINTF(PFX, "i830AdjustFrame: y = %d (+ %d), x = %d (+ %d)\n",
+ : x, pI830->xoffset, y, pI830->yoffset);
+ :
+ : if (crtc && crtc->enabled)
+ : {
+ : /* Sync the engine before adjust frame */
+ : i830WaitSync(pScrn);
+ : i830PipeSetBase(crtc, crtc->desiredX + x, crtc->desiredY + y);
+ : crtc->x = output->initial_x + x;
+ : crtc->y = output->initial_y + y;
+ : }
+ :}
+ :
+ :static void
+ :I830FreeScreen(int scrnIndex, int flags)
+ :{
+ : I830FreeRec(xf86Screens[scrnIndex]);
+ : if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
+ : vgaHWFreeHWRec(xf86Screens[scrnIndex]);
+ :}
+ :
+ :static void
+ :I830LeaveVT(int scrnIndex, int flags)
+ :{
+ : ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ : I830Ptr pI830 = I830PTR(pScrn);
+ :
+ : DPRINTF(PFX, "Leave VT\n");
+ :
+ : pI830->leaving = TRUE;
+ :
+ : if (pI830->devicesTimer)
+ : TimerCancel(pI830->devicesTimer);
+ : pI830->devicesTimer = NULL;
+ :
+ : i830SetHotkeyControl(pScrn, HOTKEY_BIOS_SWITCH);
+ :
+ : if (!I830IsPrimary(pScrn)) {
+ : I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1);
+ : if (!pI8301->gtt_acquired) {
+ : return;
+ : }
+ : }
+ :
+ :#ifdef XF86DRI
+ : if (pI830->directRenderingOpen) {
+ : DRILock(screenInfo.screens[pScrn->scrnIndex], 0);
+ :#ifdef XF86DRI_MM
+ : if (pI830->mmModeFlags & I830_KERNEL_MM) {
+ :#ifndef XSERVER_LIBDRM_MM
+ : I830DrmMMLock(pI830->drmSubFD, DRM_BO_MEM_TT);
+ :#else
+ : drmMMLock(pI830->drmSubFD, DRM_BO_MEM_TT);
+ :#endif
+ : }
+ :#endif /* XF86DRI_MM */
+ : I830DRISetVBlankInterrupt (pScrn, FALSE);
+ :
+ : drmCtlUninstHandler(pI830->drmSubFD);
+ : }
+ :#endif
+ :
+ : xf86_hide_cursors (pScrn);
+ :
+ : ResetState(pScrn, TRUE);
+ :
+ : RestoreHWState(pScrn);
+ :
+ : if (pI830->debug_modes) {
+ : i830CompareRegsToSnapshot(pScrn, "After LeaveVT");
+ : i830DumpRegs (pScrn);
+ : }
+ :
+ : if (I830IsPrimary(pScrn))
+ : i830_unbind_all_memory(pScrn);
+ : if (pI830->AccelInfoRec)
+ : pI830->AccelInfoRec->NeedToSync = FALSE;
+ :}
+ :
+ :/*
+ : * This gets called when gaining control of the VT, and from ScreenInit().
+ : */
+ :static Bool
+ :I830EnterVT(int scrnIndex, int flags)
+ :{
+ : ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
+ : int o;
+ :
+ : DPRINTF(PFX, "Enter VT\n");
+ :
+ : /*
+ : * Only save state once per server generation since that's what most
+ : * drivers do. Could change this to save state at each VT enter.
+ : */
+ : if (pI830->SaveGeneration != serverGeneration) {
+ : pI830->SaveGeneration = serverGeneration;
+ : SaveHWState(pScrn);
+ : }
+ :
+ : pI830->leaving = FALSE;
+ :
+ : if (I830IsPrimary(pScrn))
+ : if (!i830_bind_all_memory(pScrn))
+ : return FALSE;
+ :
+ : if (i830_check_error_state(pScrn)) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ : "Existing errors found in hardware state.\n");
+ : }
+ :
+ : ResetState(pScrn, FALSE);
+ : SetHWOperatingState(pScrn);
+ :
+ : /* Clear the framebuffer */
+ : memset(pI830->FbBase + pScrn->fbOffset, 0,
+ : pScrn->virtualY * pScrn->displayWidth * pI830->cpp);
+ :
+ : for (o = 0; o < config->num_output; o++) {
+ : xf86OutputPtr output = config->output[o];
+ : output->funcs->dpms(output, DPMSModeOff);
+ : }
+ :
+ : if (!xf86SetDesiredModes (pScrn))
+ : return FALSE;
+ :
+ : if (pI830->debug_modes) {
+ : xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Hardware state at EnterVT:\n");
+ : i830DumpRegs (pScrn);
+ : }
+ : i830DescribeOutputConfiguration(pScrn);
+ :
+ : ResetState(pScrn, TRUE);
+ : SetHWOperatingState(pScrn);
+ :
+ :#ifdef XF86DRI
+ : if (pI830->directRenderingEnabled) {
+ :
+ : I830DRISetVBlankInterrupt (pScrn, TRUE);
+ :
+ : if (!pI830->starting) {
+ : ScreenPtr pScreen = pScrn->pScreen;
+ : drmI830Sarea *sarea = (drmI830Sarea *) DRIGetSAREAPrivate(pScreen);
+ : int i;
+ :
+ : I830DRIResume(screenInfo.screens[scrnIndex]);
+ :
+ : I830RefreshRing(pScrn);
+ : I830Sync(pScrn);
+ : DO_RING_IDLE();
+ :
+ : sarea->texAge++;
+ : for(i = 0; i < I830_NR_TEX_REGIONS+1 ; i++)
+ : sarea->texList[i].age = sarea->texAge;
+ :
+ :#ifdef XF86DRI_MM
+ : if (pI830->mmModeFlags & I830_KERNEL_MM) {
+ :#ifndef XSERVER_LIBDRM_MM
+ : I830DrmMMUnlock(pI830->drmSubFD, DRM_BO_MEM_TT);
+ :#else
+ : drmMMUnlock(pI830->drmSubFD, DRM_BO_MEM_TT);
+ :#endif
+ : }
+ :#endif /* XF86DRI_MM */
+ :
+ : DPRINTF(PFX, "calling dri unlock\n");
+ : DRIUnlock(screenInfo.screens[pScrn->scrnIndex]);
+ : }
+ : pI830->LockHeld = 0;
+ : }
+ :#endif
+ :
+ : /* Set the hotkey to just notify us. We can check its results periodically
+ : * in the CheckDevicesTimer. Eventually we want the kernel to just hand us
+ : * an input event when someone presses the button, but for now we just have
+ : * to poll.
+ : */
+ : i830SetHotkeyControl(pScrn, HOTKEY_DRIVER_NOTIFY);
+ :
+ : if (pI830->checkDevices)
+ : pI830->devicesTimer = TimerSet(NULL, 0, 1000, I830CheckDevicesTimer, pScrn);
+ :
+ : /* Mark 3D state as being clobbered */
+ : *pI830->last_3d = LAST_3D_OTHER;
+ :
+ : return TRUE;
+ :}
+ :
+ :static Bool
+ :I830SwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
+ :{
+ : ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ : I830Ptr pI830 = I830PTR(pScrn);
+ :
+ : return xf86SetSingleMode (pScrn, mode, pI830->rotation);
+ :}
+ :
+ :static Bool
+ :I830CloseScreen(int scrnIndex, ScreenPtr pScreen)
+ :{
+ : ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ : I830Ptr pI830 = I830PTR(pScrn);
+ :#ifdef I830_USE_XAA
+ : XAAInfoRecPtr infoPtr = pI830->AccelInfoRec;
+ :#endif
+ :
+ : pI830->closing = TRUE;
+ :#ifdef XF86DRI
+ : if (pI830->directRenderingOpen) {
+ :#ifdef DAMAGE
+ : if (pI830->pDamage) {
+ : PixmapPtr pPix = pScreen->GetScreenPixmap(pScreen);
+ :
+ : DamageUnregister(&pPix->drawable, pI830->pDamage);
+ : DamageDestroy(pI830->pDamage);
+ : pI830->pDamage = NULL;
+ : }
+ :#endif
+ :#ifdef XF86DRI_MM
+ : if (pI830->mmModeFlags & I830_KERNEL_MM) {
+ :#ifndef XSERVER_LIBDRM_MM
+ : I830DrmMMTakedown(pI830->drmSubFD, DRM_BO_MEM_TT);
+ :#else
+ : drmMMTakedown(pI830->drmSubFD, DRM_BO_MEM_TT);
+ :#endif
+ : }
+ :#endif /* XF86DRI_MM */
+ : pI830->directRenderingOpen = FALSE;
+ : I830DRICloseScreen(pScreen);
+ : }
+ :#endif
+ :
+ : if (pScrn->vtSema == TRUE) {
+ : I830LeaveVT(scrnIndex, 0);
+ : }
+ :
+ : if (pI830->devicesTimer)
+ : TimerCancel(pI830->devicesTimer);
+ : pI830->devicesTimer = NULL;
+ :
+ : DPRINTF(PFX, "\nUnmapping memory\n");
+ : I830UnmapMem(pScrn);
+ : vgaHWUnmapMem(pScrn);
+ :
+ : if (pI830->ScanlineColorExpandBuffers) {
+ : xfree(pI830->ScanlineColorExpandBuffers);
+ : pI830->ScanlineColorExpandBuffers = NULL;
+ : }
+ :#ifdef I830_USE_XAA
+ : if (infoPtr) {
+ : if (infoPtr->ScanlineColorExpandBuffers)
+ : xfree(infoPtr->ScanlineColorExpandBuffers);
+ : XAADestroyInfoRec(infoPtr);
+ : pI830->AccelInfoRec = NULL;
+ : }
+ :#endif
+ :#ifdef I830_USE_EXA
+ : if (pI830->useEXA && pI830->EXADriverPtr) {
+ : exaDriverFini(pScreen);
+ : xfree(pI830->EXADriverPtr);
+ : pI830->EXADriverPtr = NULL;
+ : }
+ :#endif
+ : xf86_cursors_fini (pScreen);
+ :
+ : i830_reset_allocations(pScrn);
+ :
+ : if (I830IsPrimary(pScrn)) {
+ : xf86GARTCloseScreen(scrnIndex);
+ :
+ : xfree(pI830->LpRing);
+ : pI830->LpRing = NULL;
+ : xfree(pI830->overlayOn);
+ : pI830->overlayOn = NULL;
+ : xfree(pI830->last_3d);
+ : pI830->last_3d = NULL;
+ : }
+ :
+ : pScrn->PointerMoved = pI830->PointerMoved;
+ : pScrn->vtSema = FALSE;
+ : pI830->closing = FALSE;
+ : pScreen->CloseScreen = pI830->CloseScreen;
+ : return (*pScreen->CloseScreen) (scrnIndex, pScreen);
+ :}
+ :
+ :static ModeStatus
+ :I830ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
+ :{
+ : if (mode->Flags & V_INTERLACE) {
+ : if (verbose) {
+ : xf86DrvMsg(scrnIndex, X_PROBED,
+ : "Removing interlaced mode \"%s\"\n", mode->name);
+ : }
+ : return MODE_BAD;
+ : }
+ : return MODE_OK;
+ :}
+ :
+ :#ifndef SUSPEND_SLEEP
+ :#define SUSPEND_SLEEP 0
+ :#endif
+ :#ifndef RESUME_SLEEP
+ :#define RESUME_SLEEP 0
+ :#endif
+ :
+ :/*
+ : * This function is only required if we need to do anything differently from
+ : * DoApmEvent() in common/xf86PM.c, including if we want to see events other
+ : * than suspend/resume.
+ : */
+ :static Bool
+ :I830PMEvent(int scrnIndex, pmEvent event, Bool undo)
+ :{
+ : ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ : I830Ptr pI830 = I830PTR(pScrn);
+ :
+ : DPRINTF(PFX, "Enter VT, event %d, undo: %s\n", event, BOOLTOSTRING(undo));
+ :
+ : switch(event) {
+ : case XF86_APM_SYS_SUSPEND:
+ : case XF86_APM_CRITICAL_SUSPEND: /*do we want to delay a critical suspend?*/
+ : case XF86_APM_USER_SUSPEND:
+ : case XF86_APM_SYS_STANDBY:
+ : case XF86_APM_USER_STANDBY:
+ : if (!undo && !pI830->suspended) {
+ : pScrn->LeaveVT(scrnIndex, 0);
+ : pI830->suspended = TRUE;
+ : sleep(SUSPEND_SLEEP);
+ : } else if (undo && pI830->suspended) {
+ : sleep(RESUME_SLEEP);
+ : pScrn->EnterVT(scrnIndex, 0);
+ : pI830->suspended = FALSE;
+ : }
+ : break;
+ : case XF86_APM_STANDBY_RESUME:
+ : case XF86_APM_NORMAL_RESUME:
+ : case XF86_APM_CRITICAL_RESUME:
+ : if (pI830->suspended) {
+ : sleep(RESUME_SLEEP);
+ : pScrn->EnterVT(scrnIndex, 0);
+ : pI830->suspended = FALSE;
+ : /*
+ : * Turn the screen saver off when resuming. This seems to be
+ : * needed to stop xscreensaver kicking in (when used).
+ : *
+ : * XXX DoApmEvent() should probably call this just like
+ : * xf86VTSwitch() does. Maybe do it here only in 4.2
+ : * compatibility mode.
+ : */
+ : SaveScreens(SCREEN_SAVER_FORCER, ScreenSaverReset);
+ : }
+ : break;
+ : /* This is currently used for ACPI */
+ : case XF86_APM_CAPABILITY_CHANGED:
+ :#if 0
+ : /* If we had status checking turned on, turn it off now */
+ : if (pI830->checkDevices) {
+ : if (pI830->devicesTimer)
+ : TimerCancel(pI830->devicesTimer);
+ : pI830->devicesTimer = NULL;
+ : pI830->checkDevices = FALSE;
+ : }
+ :#endif
+ : if (!I830IsPrimary(pScrn))
+ : return TRUE;
+ :
+ : ErrorF("I830PMEvent: Capability change\n");
+ :
+ : I830CheckDevicesTimer(NULL, 0, pScrn);
+ : SaveScreens(SCREEN_SAVER_FORCER, ScreenSaverReset);
+ : break;
+ : default:
+ : ErrorF("I830PMEvent: received APM event %d\n", event);
+ : }
+ : return TRUE;
+ :}
+ :
+ :#if 0
+ :/**
+ : * This function is used for testing of the screen detect functions from the
+ : * periodic timer.
+ : */
+ :static void
+ :i830MonitorDetectDebugger(ScrnInfoPtr pScrn)
+ :{
+ : Bool found_crt;
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : int start, finish, i;
+ :
+ : if (!pScrn->vtSema)
+ : return 1000;
+ :
+ : for (i = 0; i < xf86_config->num_output; i++) {
+ : enum output_status ret;
+ : char *result;
+ :
+ : start = GetTimeInMillis();
+ : ret = pI830->output[i].detect(pScrn, &pI830->output[i]);
+ : finish = GetTimeInMillis();
+ :
+ : if (ret == OUTPUT_STATUS_CONNECTED)
+ : result = "connected";
+ : else if (ret == OUTPUT_STATUS_DISCONNECTED)
+ : result = "disconnected";
+ : else
+ : result = "unknown";
+ :
+ : xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Detected SDVO as %s in %dms\n",
+ : result, finish - start);
+ : }
+ :}
+ :#endif
+ :
+ :static CARD32
+ :I830CheckDevicesTimer(OsTimerPtr timer, CARD32 now, pointer arg)
+ :{
+ : ScrnInfoPtr pScrn = (ScrnInfoPtr) arg;
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : CARD8 gr18;
+ :
+ : if (!pScrn->vtSema)
+ : return 1000;
+ :
+ :#if 0
+ : i830MonitorDetectDebugger(pScrn);
+ :#endif
+ :
+ : /* Check for a hotkey press report from the BIOS. */
+ : gr18 = pI830->readControl(pI830, GRX, 0x18);
+ : if ((gr18 & (HOTKEY_TOGGLE | HOTKEY_SWITCH)) != 0) {
+ : /* The user has pressed the hotkey requesting a toggle or switch.
+ : * Re-probe our connected displays and turn on whatever we find.
+ : *
+ : * In the future, we want the hotkey to dump down to a user app which
+ : * implements a sensible policy using RandR-1.2. For now, all we get
+ : * is this.
+ : */
+ :
+ : xf86ProbeOutputModes (pScrn, 0, 0);
+ : xf86SetScrnInfoModes (pScrn);
+ : xf86DiDGAReInit (pScrn->pScreen);
+ : xf86SwitchMode(pScrn->pScreen, pScrn->currentMode);
+ :
+ : /* Clear the BIOS's hotkey press flags */
+ : gr18 &= ~(HOTKEY_TOGGLE | HOTKEY_SWITCH);
+ : pI830->writeControl(pI830, GRX, 0x18, gr18);
+ : }
+ :
+ : return 1000;
+ :}
+ :
+ :void
+ :i830WaitSync(ScrnInfoPtr pScrn)
+ 31 0.0338 :{ /* i830WaitSync total: 103 0.1122 */
+ 1 0.0011 : I830Ptr pI830 = I830PTR(pScrn);
+ :
+ :#ifdef I830_USE_XAA
+ 15 0.0163 : if (!pI830->noAccel && !pI830->useEXA && pI830->AccelInfoRec
+ : && pI830->AccelInfoRec->NeedToSync) {
+ : (*pI830->AccelInfoRec->Sync)(pScrn);
+ : pI830->AccelInfoRec->NeedToSync = FALSE;
+ : }
+ :#endif
+ :#ifdef I830_USE_EXA
+ 6 0.0065 : if (!pI830->noAccel && pI830->useEXA && pI830->EXADriverPtr) {
+ : ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
+ 21 0.0229 : exaWaitSync(pScreen);
+ : }
+ :#endif
+ 29 0.0316 :}
+ :
+ :void
+ :i830MarkSync(ScrnInfoPtr pScrn)
+ 7 0.0076 :{ /* i830MarkSync total: 15 0.0163 */
+ : I830Ptr pI830 = I830PTR(pScrn);
+ :
+ :#ifdef I830_USE_XAA
+ : if (!pI830->useEXA && pI830->AccelInfoRec)
+ : pI830->AccelInfoRec->NeedToSync = TRUE;
+ :#endif
+ :#ifdef I830_USE_EXA
+ 2 0.0022 : if (pI830->useEXA && pI830->EXADriverPtr) {
+ : ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
+ 3 0.0033 : exaMarkSync(pScreen);
+ : }
+ :#endif
+ 3 0.0033 :}
+ :
+ :void
+ :I830InitpScrn(ScrnInfoPtr pScrn)
+ :{
+ : pScrn->PreInit = I830PreInit;
+ : pScrn->ScreenInit = I830ScreenInit;
+ : pScrn->SwitchMode = I830SwitchMode;
+ : pScrn->AdjustFrame = i830AdjustFrame;
+ : pScrn->EnterVT = I830EnterVT;
+ : pScrn->LeaveVT = I830LeaveVT;
+ : pScrn->FreeScreen = I830FreeScreen;
+ : pScrn->ValidMode = I830ValidMode;
+ : pScrn->PMEvent = I830PMEvent;
+ :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/mi/misprite.c"
+ *
+ * 140 0.1525
+ */
+
+
+ :/*
+ : * misprite.c
+ : *
+ : * machine independent software sprite routines
+ : */
+ :
+ :
+ :/*
+ :
+ :Copyright 1989, 1998 The Open Group
+ :
+ :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.
+ :
+ :The above copyright notice and this permission notice shall be included in
+ :all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ :IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ :FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ :OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ :AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ :CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of The Open Group shall not be
+ :used in advertising or otherwise to promote the sale, use or other dealings
+ :in this Software without prior written authorization from The Open Group.
+ :*/
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :# include <X11/X.h>
+ :# include <X11/Xproto.h>
+ :# include "misc.h"
+ :# include "pixmapstr.h"
+ :# include "input.h"
+ :# include "mi.h"
+ :# include "cursorstr.h"
+ :# include <X11/fonts/font.h>
+ :# include "scrnintstr.h"
+ :# include "colormapst.h"
+ :# include "windowstr.h"
+ :# include "gcstruct.h"
+ :# include "mipointer.h"
+ :# include "mispritest.h"
+ :# include "dixfontstr.h"
+ :# include <X11/fonts/fontstruct.h>
+ :
+ :#ifdef RENDER
+ :# include "mipict.h"
+ :#endif
+ :# include "damage.h"
+ :
+ :#define SPRITE_DEBUG_ENABLE 0
+ :#if SPRITE_DEBUG_ENABLE
+ :#define SPRITE_DEBUG(x) ErrorF x
+ :#else
+ :#define SPRITE_DEBUG(x)
+ :#endif
+ :
+ :/*
+ : * screen wrappers
+ : */
+ :
+ :static int miSpriteScreenIndex;
+ :static unsigned long miSpriteGeneration = 0;
+ :
+ :static Bool miSpriteCloseScreen(int i, ScreenPtr pScreen);
+ :static void miSpriteGetImage(DrawablePtr pDrawable, int sx, int sy,
+ : int w, int h, unsigned int format,
+ : unsigned long planemask, char *pdstLine);
+ :static void miSpriteGetSpans(DrawablePtr pDrawable, int wMax,
+ : DDXPointPtr ppt, int *pwidth, int nspans,
+ : char *pdstStart);
+ :static void miSpriteSourceValidate(DrawablePtr pDrawable, int x, int y,
+ : int width, int height);
+ :static void miSpriteCopyWindow (WindowPtr pWindow,
+ : DDXPointRec ptOldOrg,
+ : RegionPtr prgnSrc);
+ :static void miSpriteBlockHandler(int i, pointer blockData,
+ : pointer pTimeout,
+ : pointer pReadMask);
+ :static void miSpriteInstallColormap(ColormapPtr pMap);
+ :static void miSpriteStoreColors(ColormapPtr pMap, int ndef,
+ : xColorItem *pdef);
+ :
+ :static void miSpriteSaveDoomedAreas(WindowPtr pWin,
+ : RegionPtr pObscured, int dx,
+ : int dy);
+ :static void miSpriteComputeSaved(ScreenPtr pScreen);
+ :
+ :#define SCREEN_PROLOGUE(pScreen, field)\
+ : ((pScreen)->field = \
+ : ((miSpriteScreenPtr) (pScreen)->devPrivates[miSpriteScreenIndex].ptr)->field)
+ :
+ :#define SCREEN_EPILOGUE(pScreen, field)\
+ : ((pScreen)->field = miSprite##field)
+ :
+ :/*
+ : * pointer-sprite method table
+ : */
+ :
+ :static Bool miSpriteRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor);
+ :static Bool miSpriteUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor);
+ :static void miSpriteSetCursor(ScreenPtr pScreen, CursorPtr pCursor,
+ : int x, int y);
+ :static void miSpriteMoveCursor(ScreenPtr pScreen, int x, int y);
+ :
+ :_X_EXPORT miPointerSpriteFuncRec miSpritePointerFuncs = {
+ : miSpriteRealizeCursor,
+ : miSpriteUnrealizeCursor,
+ : miSpriteSetCursor,
+ : miSpriteMoveCursor,
+ :};
+ :
+ :/*
+ : * other misc functions
+ : */
+ :
+ :static void miSpriteRemoveCursor(ScreenPtr pScreen);
+ :static void miSpriteRestoreCursor(ScreenPtr pScreen);
+ :
+ :static void
+ :miSpriteReportDamage (DamagePtr pDamage, RegionPtr pRegion, void *closure)
+ :{
+ : ScreenPtr pScreen = closure;
+ : miSpriteScreenPtr pScreenPriv;
+ :
+ : pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
+ :
+ : if (pScreenPriv->isUp &&
+ : RECT_IN_REGION (pScreen, pRegion, &pScreenPriv->saved) != rgnOUT)
+ : {
+ : SPRITE_DEBUG(("Damage remove\n"));
+ : miSpriteRemoveCursor (pScreen);
+ : }
+ :}
+ :
+ :/*
+ : * miSpriteInitialize -- called from device-dependent screen
+ : * initialization proc after all of the function pointers have
+ : * been stored in the screen structure.
+ : */
+ :
+ :Bool
+ :miSpriteInitialize (pScreen, cursorFuncs, screenFuncs)
+ : ScreenPtr pScreen;
+ : miSpriteCursorFuncPtr cursorFuncs;
+ : miPointerScreenFuncPtr screenFuncs;
+ :{
+ : miSpriteScreenPtr pScreenPriv;
+ : VisualPtr pVisual;
+ :
+ : if (!DamageSetup (pScreen))
+ : return FALSE;
+ :
+ : if (miSpriteGeneration != serverGeneration)
+ : {
+ : miSpriteScreenIndex = AllocateScreenPrivateIndex ();
+ : if (miSpriteScreenIndex < 0)
+ : return FALSE;
+ : miSpriteGeneration = serverGeneration;
+ : }
+ :
+ : pScreenPriv = (miSpriteScreenPtr) xalloc (sizeof (miSpriteScreenRec));
+ : if (!pScreenPriv)
+ : return FALSE;
+ :
+ : pScreenPriv->pDamage = DamageCreate (miSpriteReportDamage,
+ : (DamageDestroyFunc) 0,
+ : DamageReportRawRegion,
+ : TRUE,
+ : pScreen,
+ : (void *) pScreen);
+ :
+ : if (!miPointerInitialize (pScreen, &miSpritePointerFuncs, screenFuncs,TRUE))
+ : {
+ : xfree ((pointer) pScreenPriv);
+ : return FALSE;
+ : }
+ : for (pVisual = pScreen->visuals;
+ : pVisual->vid != pScreen->rootVisual;
+ : pVisual++)
+ : ;
+ : pScreenPriv->pVisual = pVisual;
+ : pScreenPriv->CloseScreen = pScreen->CloseScreen;
+ : pScreenPriv->GetImage = pScreen->GetImage;
+ : pScreenPriv->GetSpans = pScreen->GetSpans;
+ : pScreenPriv->SourceValidate = pScreen->SourceValidate;
+ :
+ : pScreenPriv->CopyWindow = pScreen->CopyWindow;
+ :
+ : pScreenPriv->SaveDoomedAreas = pScreen->SaveDoomedAreas;
+ :
+ : pScreenPriv->InstallColormap = pScreen->InstallColormap;
+ : pScreenPriv->StoreColors = pScreen->StoreColors;
+ :
+ : pScreenPriv->BlockHandler = pScreen->BlockHandler;
+ :
+ : pScreenPriv->pCursor = NULL;
+ : pScreenPriv->x = 0;
+ : pScreenPriv->y = 0;
+ : pScreenPriv->isUp = FALSE;
+ : pScreenPriv->shouldBeUp = FALSE;
+ : pScreenPriv->pCacheWin = NullWindow;
+ : pScreenPriv->isInCacheWin = FALSE;
+ : pScreenPriv->checkPixels = TRUE;
+ : pScreenPriv->pInstalledMap = NULL;
+ : pScreenPriv->pColormap = NULL;
+ : pScreenPriv->funcs = cursorFuncs;
+ : pScreenPriv->colors[SOURCE_COLOR].red = 0;
+ : pScreenPriv->colors[SOURCE_COLOR].green = 0;
+ : pScreenPriv->colors[SOURCE_COLOR].blue = 0;
+ : pScreenPriv->colors[MASK_COLOR].red = 0;
+ : pScreenPriv->colors[MASK_COLOR].green = 0;
+ : pScreenPriv->colors[MASK_COLOR].blue = 0;
+ : pScreen->devPrivates[miSpriteScreenIndex].ptr = (pointer) pScreenPriv;
+ :
+ : pScreen->CloseScreen = miSpriteCloseScreen;
+ : pScreen->GetImage = miSpriteGetImage;
+ : pScreen->GetSpans = miSpriteGetSpans;
+ : pScreen->SourceValidate = miSpriteSourceValidate;
+ :
+ : pScreen->CopyWindow = miSpriteCopyWindow;
+ :
+ : pScreen->SaveDoomedAreas = miSpriteSaveDoomedAreas;
+ :
+ : pScreen->InstallColormap = miSpriteInstallColormap;
+ : pScreen->StoreColors = miSpriteStoreColors;
+ :
+ : pScreen->BlockHandler = miSpriteBlockHandler;
+ :
+ : return TRUE;
+ :}
+ :
+ :/*
+ : * Screen wrappers
+ : */
+ :
+ :/*
+ : * CloseScreen wrapper -- unwrap everything, free the private data
+ : * and call the wrapped function
+ : */
+ :
+ :static Bool
+ :miSpriteCloseScreen (i, pScreen)
+ : int i;
+ : ScreenPtr pScreen;
+ :{
+ : miSpriteScreenPtr pScreenPriv;
+ :
+ : pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
+ :
+ : pScreen->CloseScreen = pScreenPriv->CloseScreen;
+ : pScreen->GetImage = pScreenPriv->GetImage;
+ : pScreen->GetSpans = pScreenPriv->GetSpans;
+ : pScreen->SourceValidate = pScreenPriv->SourceValidate;
+ : pScreen->BlockHandler = pScreenPriv->BlockHandler;
+ : pScreen->InstallColormap = pScreenPriv->InstallColormap;
+ : pScreen->StoreColors = pScreenPriv->StoreColors;
+ :
+ : pScreen->SaveDoomedAreas = pScreenPriv->SaveDoomedAreas;
+ : miSpriteIsUpFALSE (pScreen, pScreenPriv);
+ : DamageDestroy (pScreenPriv->pDamage);
+ :
+ : xfree ((pointer) pScreenPriv);
+ :
+ : return (*pScreen->CloseScreen) (i, pScreen);
+ :}
+ :
+ :static void
+ :miSpriteGetImage (pDrawable, sx, sy, w, h, format, planemask, pdstLine)
+ : DrawablePtr pDrawable;
+ : int sx, sy, w, h;
+ : unsigned int format;
+ : unsigned long planemask;
+ : char *pdstLine;
+ :{
+ : ScreenPtr pScreen = pDrawable->pScreen;
+ : miSpriteScreenPtr pScreenPriv;
+ :
+ : SCREEN_PROLOGUE (pScreen, GetImage);
+ :
+ : pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
+ :
+ : if (pDrawable->type == DRAWABLE_WINDOW &&
+ : pScreenPriv->isUp &&
+ : ORG_OVERLAP(&pScreenPriv->saved,pDrawable->x,pDrawable->y, sx, sy, w, h))
+ : {
+ : SPRITE_DEBUG (("GetImage remove\n"));
+ : miSpriteRemoveCursor (pScreen);
+ : }
+ :
+ : (*pScreen->GetImage) (pDrawable, sx, sy, w, h,
+ : format, planemask, pdstLine);
+ :
+ : SCREEN_EPILOGUE (pScreen, GetImage);
+ :}
+ :
+ :static void
+ :miSpriteGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart)
+ : DrawablePtr pDrawable;
+ : int wMax;
+ : DDXPointPtr ppt;
+ : int *pwidth;
+ : int nspans;
+ : char *pdstStart;
+ :{
+ : ScreenPtr pScreen = pDrawable->pScreen;
+ : miSpriteScreenPtr pScreenPriv;
+ :
+ : SCREEN_PROLOGUE (pScreen, GetSpans);
+ :
+ : pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
+ :
+ : if (pDrawable->type == DRAWABLE_WINDOW && pScreenPriv->isUp)
+ : {
+ : DDXPointPtr pts;
+ : int *widths;
+ : int nPts;
+ : int xorg,
+ : yorg;
+ :
+ : xorg = pDrawable->x;
+ : yorg = pDrawable->y;
+ :
+ : for (pts = ppt, widths = pwidth, nPts = nspans;
+ : nPts--;
+ : pts++, widths++)
+ : {
+ : if (SPN_OVERLAP(&pScreenPriv->saved,pts->y+yorg,
+ : pts->x+xorg,*widths))
+ : {
+ : SPRITE_DEBUG (("GetSpans remove\n"));
+ : miSpriteRemoveCursor (pScreen);
+ : break;
+ : }
+ : }
+ : }
+ :
+ : (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
+ :
+ : SCREEN_EPILOGUE (pScreen, GetSpans);
+ :}
+ :
+ :static void
+ :miSpriteSourceValidate (pDrawable, x, y, width, height)
+ : DrawablePtr pDrawable;
+ : int x, y, width, height;
+ 31 0.0338 :{ /* miSpriteSourceValidate total: 140 0.1525 */
+ : ScreenPtr pScreen = pDrawable->pScreen;
+ : miSpriteScreenPtr pScreenPriv;
+ :
+ 55 0.0599 : SCREEN_PROLOGUE (pScreen, SourceValidate);
+ :
+ 7 0.0076 : pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
+ :
+ : if (pDrawable->type == DRAWABLE_WINDOW && pScreenPriv->isUp &&
+ : ORG_OVERLAP(&pScreenPriv->saved, pDrawable->x, pDrawable->y,
+ : x, y, width, height))
+ : {
+ : SPRITE_DEBUG (("SourceValidate remove\n"));
+ : miSpriteRemoveCursor (pScreen);
+ : }
+ :
+ 26 0.0283 : if (pScreen->SourceValidate)
+ : (*pScreen->SourceValidate) (pDrawable, x, y, width, height);
+ :
+ 5 0.0054 : SCREEN_EPILOGUE (pScreen, SourceValidate);
+ 16 0.0174 :}
+ :
+ :static void
+ :miSpriteCopyWindow (WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
+ :{
+ : ScreenPtr pScreen = pWindow->drawable.pScreen;
+ : miSpriteScreenPtr pScreenPriv;
+ :
+ : SCREEN_PROLOGUE (pScreen, CopyWindow);
+ :
+ : pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
+ : /*
+ : * Damage will take care of destination check
+ : */
+ : if (pScreenPriv->isUp &&
+ : RECT_IN_REGION (pScreen, prgnSrc, &pScreenPriv->saved) != rgnOUT)
+ : {
+ : SPRITE_DEBUG (("CopyWindow remove\n"));
+ : miSpriteRemoveCursor (pScreen);
+ : }
+ :
+ : (*pScreen->CopyWindow) (pWindow, ptOldOrg, prgnSrc);
+ : SCREEN_EPILOGUE (pScreen, CopyWindow);
+ :}
+ :
+ :static void
+ :miSpriteBlockHandler (i, blockData, pTimeout, pReadmask)
+ : int i;
+ : pointer blockData;
+ : pointer pTimeout;
+ : pointer pReadmask;
+ :{
+ : ScreenPtr pScreen = screenInfo.screens[i];
+ : miSpriteScreenPtr pPriv;
+ :
+ : pPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
+ :
+ : SCREEN_PROLOGUE(pScreen, BlockHandler);
+ :
+ : (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
+ :
+ : SCREEN_EPILOGUE(pScreen, BlockHandler);
+ :
+ : if (!pPriv->isUp && pPriv->shouldBeUp)
+ : {
+ : SPRITE_DEBUG (("BlockHandler restore\n"));
+ : miSpriteRestoreCursor (pScreen);
+ : }
+ :}
+ :
+ :static void
+ :miSpriteInstallColormap (pMap)
+ : ColormapPtr pMap;
+ :{
+ : ScreenPtr pScreen = pMap->pScreen;
+ : miSpriteScreenPtr pPriv;
+ :
+ : pPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
+ :
+ : SCREEN_PROLOGUE(pScreen, InstallColormap);
+ :
+ : (*pScreen->InstallColormap) (pMap);
+ :
+ : SCREEN_EPILOGUE(pScreen, InstallColormap);
+ :
+ : pPriv->pInstalledMap = pMap;
+ : if (pPriv->pColormap != pMap)
+ : {
+ : pPriv->checkPixels = TRUE;
+ : if (pPriv->isUp)
+ : miSpriteRemoveCursor (pScreen);
+ : }
+ :}
+ :
+ :static void
+ :miSpriteStoreColors (pMap, ndef, pdef)
+ : ColormapPtr pMap;
+ : int ndef;
+ : xColorItem *pdef;
+ :{
+ : ScreenPtr pScreen = pMap->pScreen;
+ : miSpriteScreenPtr pPriv;
+ : int i;
+ : int updated;
+ : VisualPtr pVisual;
+ :
+ : pPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
+ :
+ : SCREEN_PROLOGUE(pScreen, StoreColors);
+ :
+ : (*pScreen->StoreColors) (pMap, ndef, pdef);
+ :
+ : SCREEN_EPILOGUE(pScreen, StoreColors);
+ :
+ : if (pPriv->pColormap == pMap)
+ : {
+ : updated = 0;
+ : pVisual = pMap->pVisual;
+ : if (pVisual->class == DirectColor)
+ : {
+ : /* Direct color - match on any of the subfields */
+ :
+ :#define MaskMatch(a,b,mask) (((a) & (pVisual->mask)) == ((b) & (pVisual->mask)))
+ :
+ :#define UpdateDAC(plane,dac,mask) {\
+ : if (MaskMatch (pPriv->colors[plane].pixel,pdef[i].pixel,mask)) {\
+ : pPriv->colors[plane].dac = pdef[i].dac; \
+ : updated = 1; \
+ : } \
+ :}
+ :
+ :#define CheckDirect(plane) \
+ : UpdateDAC(plane,red,redMask) \
+ : UpdateDAC(plane,green,greenMask) \
+ : UpdateDAC(plane,blue,blueMask)
+ :
+ : for (i = 0; i < ndef; i++)
+ : {
+ : CheckDirect (SOURCE_COLOR)
+ : CheckDirect (MASK_COLOR)
+ : }
+ : }
+ : else
+ : {
+ : /* PseudoColor/GrayScale - match on exact pixel */
+ : for (i = 0; i < ndef; i++)
+ : {
+ : if (pdef[i].pixel == pPriv->colors[SOURCE_COLOR].pixel)
+ : {
+ : pPriv->colors[SOURCE_COLOR] = pdef[i];
+ : if (++updated == 2)
+ : break;
+ : }
+ : if (pdef[i].pixel == pPriv->colors[MASK_COLOR].pixel)
+ : {
+ : pPriv->colors[MASK_COLOR] = pdef[i];
+ : if (++updated == 2)
+ : break;
+ : }
+ : }
+ : }
+ : if (updated)
+ : {
+ : pPriv->checkPixels = TRUE;
+ : if (pPriv->isUp)
+ : miSpriteRemoveCursor (pScreen);
+ : }
+ : }
+ :}
+ :
+ :static void
+ :miSpriteFindColors (ScreenPtr pScreen)
+ :{
+ : miSpriteScreenPtr pScreenPriv = (miSpriteScreenPtr)
+ : pScreen->devPrivates[miSpriteScreenIndex].ptr;
+ : CursorPtr pCursor;
+ : xColorItem *sourceColor, *maskColor;
+ :
+ : pCursor = pScreenPriv->pCursor;
+ : sourceColor = &pScreenPriv->colors[SOURCE_COLOR];
+ : maskColor = &pScreenPriv->colors[MASK_COLOR];
+ : if (pScreenPriv->pColormap != pScreenPriv->pInstalledMap ||
+ : !(pCursor->foreRed == sourceColor->red &&
+ : pCursor->foreGreen == sourceColor->green &&
+ : pCursor->foreBlue == sourceColor->blue &&
+ : pCursor->backRed == maskColor->red &&
+ : pCursor->backGreen == maskColor->green &&
+ : pCursor->backBlue == maskColor->blue))
+ : {
+ : pScreenPriv->pColormap = pScreenPriv->pInstalledMap;
+ : sourceColor->red = pCursor->foreRed;
+ : sourceColor->green = pCursor->foreGreen;
+ : sourceColor->blue = pCursor->foreBlue;
+ : FakeAllocColor (pScreenPriv->pColormap, sourceColor);
+ : maskColor->red = pCursor->backRed;
+ : maskColor->green = pCursor->backGreen;
+ : maskColor->blue = pCursor->backBlue;
+ : FakeAllocColor (pScreenPriv->pColormap, maskColor);
+ : /* "free" the pixels right away, don't let this confuse you */
+ : FakeFreeColor(pScreenPriv->pColormap, sourceColor->pixel);
+ : FakeFreeColor(pScreenPriv->pColormap, maskColor->pixel);
+ : }
+ : pScreenPriv->checkPixels = FALSE;
+ :}
+ :
+ :/*
+ : * BackingStore wrappers
+ : */
+ :
+ :static void
+ :miSpriteSaveDoomedAreas (pWin, pObscured, dx, dy)
+ : WindowPtr pWin;
+ : RegionPtr pObscured;
+ : int dx, dy;
+ :{
+ : ScreenPtr pScreen;
+ : miSpriteScreenPtr pScreenPriv;
+ : BoxRec cursorBox;
+ :
+ : pScreen = pWin->drawable.pScreen;
+ :
+ : SCREEN_PROLOGUE (pScreen, SaveDoomedAreas);
+ :
+ : pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
+ : if (pScreenPriv->isUp)
+ : {
+ : cursorBox = pScreenPriv->saved;
+ :
+ : if (dx || dy)
+ : {
+ : cursorBox.x1 += dx;
+ : cursorBox.y1 += dy;
+ : cursorBox.x2 += dx;
+ : cursorBox.y2 += dy;
+ : }
+ : if (RECT_IN_REGION( pScreen, pObscured, &cursorBox) != rgnOUT)
+ : miSpriteRemoveCursor (pScreen);
+ : }
+ :
+ : (*pScreen->SaveDoomedAreas) (pWin, pObscured, dx, dy);
+ :
+ : SCREEN_EPILOGUE (pScreen, SaveDoomedAreas);
+ :}
+ :
+ :/*
+ : * miPointer interface routines
+ : */
+ :
+ :#define SPRITE_PAD 8
+ :
+ :static Bool
+ :miSpriteRealizeCursor (pScreen, pCursor)
+ : ScreenPtr pScreen;
+ : CursorPtr pCursor;
+ :{
+ : miSpriteScreenPtr pScreenPriv;
+ :
+ : pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
+ : if (pCursor == pScreenPriv->pCursor)
+ : pScreenPriv->checkPixels = TRUE;
+ : return (*pScreenPriv->funcs->RealizeCursor) (pScreen, pCursor);
+ :}
+ :
+ :static Bool
+ :miSpriteUnrealizeCursor (pScreen, pCursor)
+ : ScreenPtr pScreen;
+ : CursorPtr pCursor;
+ :{
+ : miSpriteScreenPtr pScreenPriv;
+ :
+ : pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
+ : return (*pScreenPriv->funcs->UnrealizeCursor) (pScreen, pCursor);
+ :}
+ :
+ :static void
+ :miSpriteSetCursor (pScreen, pCursor, x, y)
+ : ScreenPtr pScreen;
+ : CursorPtr pCursor;
+ : int x;
+ : int y;
+ :{
+ : miSpriteScreenPtr pScreenPriv;
+ :
+ : pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
+ : if (!pCursor)
+ : {
+ : pScreenPriv->shouldBeUp = FALSE;
+ : if (pScreenPriv->isUp)
+ : miSpriteRemoveCursor (pScreen);
+ : pScreenPriv->pCursor = 0;
+ : return;
+ : }
+ : pScreenPriv->shouldBeUp = TRUE;
+ : if (pScreenPriv->x == x &&
+ : pScreenPriv->y == y &&
+ : pScreenPriv->pCursor == pCursor &&
+ : !pScreenPriv->checkPixels)
+ : {
+ : return;
+ : }
+ : pScreenPriv->x = x;
+ : pScreenPriv->y = y;
+ : pScreenPriv->pCacheWin = NullWindow;
+ : if (pScreenPriv->checkPixels || pScreenPriv->pCursor != pCursor)
+ : {
+ : pScreenPriv->pCursor = pCursor;
+ : miSpriteFindColors (pScreen);
+ : }
+ : if (pScreenPriv->isUp) {
+ : int sx, sy;
+ : /*
+ : * check to see if the old saved region
+ : * encloses the new sprite, in which case we use
+ : * the flicker-free MoveCursor primitive.
+ : */
+ : sx = pScreenPriv->x - (int)pCursor->bits->xhot;
+ : sy = pScreenPriv->y - (int)pCursor->bits->yhot;
+ : if (sx + (int) pCursor->bits->width >= pScreenPriv->saved.x1 &&
+ : sx < pScreenPriv->saved.x2 &&
+ : sy + (int) pCursor->bits->height >= pScreenPriv->saved.y1 &&
+ : sy < pScreenPriv->saved.y2 &&
+ : (int) pCursor->bits->width + (2 * SPRITE_PAD) ==
+ : pScreenPriv->saved.x2 - pScreenPriv->saved.x1 &&
+ : (int) pCursor->bits->height + (2 * SPRITE_PAD) ==
+ : pScreenPriv->saved.y2 - pScreenPriv->saved.y1
+ : )
+ : {
+ : DamageDrawInternal (pScreen, TRUE);
+ : miSpriteIsUpFALSE (pScreen, pScreenPriv);
+ : if (!(sx >= pScreenPriv->saved.x1 &&
+ : sx + (int)pCursor->bits->width < pScreenPriv->saved.x2 &&
+ : sy >= pScreenPriv->saved.y1 &&
+ : sy + (int)pCursor->bits->height < pScreenPriv->saved.y2))
+ : {
+ : int oldx1, oldy1, dx, dy;
+ :
+ : oldx1 = pScreenPriv->saved.x1;
+ : oldy1 = pScreenPriv->saved.y1;
+ : dx = oldx1 - (sx - SPRITE_PAD);
+ : dy = oldy1 - (sy - SPRITE_PAD);
+ : pScreenPriv->saved.x1 -= dx;
+ : pScreenPriv->saved.y1 -= dy;
+ : pScreenPriv->saved.x2 -= dx;
+ : pScreenPriv->saved.y2 -= dy;
+ : (void) (*pScreenPriv->funcs->ChangeSave) (pScreen,
+ : pScreenPriv->saved.x1,
+ : pScreenPriv->saved.y1,
+ : pScreenPriv->saved.x2 - pScreenPriv->saved.x1,
+ : pScreenPriv->saved.y2 - pScreenPriv->saved.y1,
+ : dx, dy);
+ : }
+ : (void) (*pScreenPriv->funcs->MoveCursor) (pScreen, pCursor,
+ : pScreenPriv->saved.x1,
+ : pScreenPriv->saved.y1,
+ : pScreenPriv->saved.x2 - pScreenPriv->saved.x1,
+ : pScreenPriv->saved.y2 - pScreenPriv->saved.y1,
+ : sx - pScreenPriv->saved.x1,
+ : sy - pScreenPriv->saved.y1,
+ : pScreenPriv->colors[SOURCE_COLOR].pixel,
+ : pScreenPriv->colors[MASK_COLOR].pixel);
+ : miSpriteIsUpTRUE (pScreen, pScreenPriv);
+ : DamageDrawInternal (pScreen, FALSE);
+ : }
+ : else
+ : {
+ : SPRITE_DEBUG (("SetCursor remove\n"));
+ : miSpriteRemoveCursor (pScreen);
+ : }
+ : }
+ : if (!pScreenPriv->isUp && pScreenPriv->pCursor)
+ : {
+ : SPRITE_DEBUG (("SetCursor restore\n"));
+ : miSpriteRestoreCursor (pScreen);
+ : }
+ :}
+ :
+ :static void
+ :miSpriteMoveCursor (pScreen, x, y)
+ : ScreenPtr pScreen;
+ : int x, y;
+ :{
+ : miSpriteScreenPtr pScreenPriv;
+ :
+ : pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
+ : miSpriteSetCursor (pScreen, pScreenPriv->pCursor, x, y);
+ :}
+ :
+ :/*
+ : * undraw/draw cursor
+ : */
+ :
+ :static void
+ :miSpriteRemoveCursor (pScreen)
+ : ScreenPtr pScreen;
+ :{
+ : miSpriteScreenPtr pScreenPriv;
+ :
+ : DamageDrawInternal (pScreen, TRUE);
+ : pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
+ : miSpriteIsUpFALSE (pScreen, pScreenPriv);
+ : pScreenPriv->pCacheWin = NullWindow;
+ : if (!(*pScreenPriv->funcs->RestoreUnderCursor) (pScreen,
+ : pScreenPriv->saved.x1,
+ : pScreenPriv->saved.y1,
+ : pScreenPriv->saved.x2 - pScreenPriv->saved.x1,
+ : pScreenPriv->saved.y2 - pScreenPriv->saved.y1))
+ : {
+ : miSpriteIsUpTRUE (pScreen, pScreenPriv);
+ : }
+ : DamageDrawInternal (pScreen, FALSE);
+ :}
+ :
+ :/*
+ : * Called from the block handler, restores the cursor
+ : * before waiting for something to do.
+ : */
+ :
+ :static void
+ :miSpriteRestoreCursor (pScreen)
+ : ScreenPtr pScreen;
+ :{
+ : miSpriteScreenPtr pScreenPriv;
+ : int x, y;
+ : CursorPtr pCursor;
+ :
+ : DamageDrawInternal (pScreen, TRUE);
+ : miSpriteComputeSaved (pScreen);
+ : pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
+ : pCursor = pScreenPriv->pCursor;
+ : x = pScreenPriv->x - (int)pCursor->bits->xhot;
+ : y = pScreenPriv->y - (int)pCursor->bits->yhot;
+ : if ((*pScreenPriv->funcs->SaveUnderCursor) (pScreen,
+ : pScreenPriv->saved.x1,
+ : pScreenPriv->saved.y1,
+ : pScreenPriv->saved.x2 - pScreenPriv->saved.x1,
+ : pScreenPriv->saved.y2 - pScreenPriv->saved.y1))
+ : {
+ : if (pScreenPriv->checkPixels)
+ : miSpriteFindColors (pScreen);
+ : if ((*pScreenPriv->funcs->PutUpCursor) (pScreen, pCursor, x, y,
+ : pScreenPriv->colors[SOURCE_COLOR].pixel,
+ : pScreenPriv->colors[MASK_COLOR].pixel))
+ : {
+ : miSpriteIsUpTRUE (pScreen, pScreenPriv);
+ : }
+ : }
+ : DamageDrawInternal (pScreen, FALSE);
+ :}
+ :
+ :/*
+ : * compute the desired area of the screen to save
+ : */
+ :
+ :static void
+ :miSpriteComputeSaved (pScreen)
+ : ScreenPtr pScreen;
+ :{
+ : miSpriteScreenPtr pScreenPriv;
+ : int x, y, w, h;
+ : int wpad, hpad;
+ : CursorPtr pCursor;
+ :
+ : pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
+ : pCursor = pScreenPriv->pCursor;
+ : x = pScreenPriv->x - (int)pCursor->bits->xhot;
+ : y = pScreenPriv->y - (int)pCursor->bits->yhot;
+ : w = pCursor->bits->width;
+ : h = pCursor->bits->height;
+ : wpad = SPRITE_PAD;
+ : hpad = SPRITE_PAD;
+ : pScreenPriv->saved.x1 = x - wpad;
+ : pScreenPriv->saved.y1 = y - hpad;
+ : pScreenPriv->saved.x2 = pScreenPriv->saved.x1 + w + wpad * 2;
+ : pScreenPriv->saved.y2 = pScreenPriv->saved.y1 + h + hpad * 2;
+ :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/fb/fbcopy.c"
+ *
+ * 127 0.1384
+ */
+
+
+ :/*
+ : * Copyright © 1998 Keith Packard
+ : *
+ : * 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 Keith Packard not be used in
+ : * advertising or publicity pertaining to distribution of the software without
+ : * specific, written prior permission. Keith Packard makes no
+ : * representations about the suitability of this software for any purpose. It
+ : * is provided "as is" without express or implied warranty.
+ : *
+ : * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ : * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ : * EVENT SHALL KEITH PACKARD 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.
+ : */
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include <stdlib.h>
+ :
+ :#include "fb.h"
+ :
+ :void
+ :fbCopyNtoN (DrawablePtr pSrcDrawable,
+ : DrawablePtr pDstDrawable,
+ : GCPtr pGC,
+ : BoxPtr pbox,
+ : int nbox,
+ : int dx,
+ : int dy,
+ : Bool reverse,
+ : Bool upsidedown,
+ : Pixel bitplane,
+ : void *closure)
+ :{
+ : CARD8 alu = pGC ? pGC->alu : GXcopy;
+ : FbBits pm = pGC ? fbGetGCPrivate(pGC)->pm : FB_ALLONES;
+ : FbBits *src;
+ : FbStride srcStride;
+ : int srcBpp;
+ : int srcXoff, srcYoff;
+ : FbBits *dst;
+ : FbStride dstStride;
+ : int dstBpp;
+ : int dstXoff, dstYoff;
+ :
+ : fbGetDrawable (pSrcDrawable, src, srcStride, srcBpp, srcXoff, srcYoff);
+ : fbGetDrawable (pDstDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
+ :
+ : while (nbox--)
+ : {
+ :#ifndef FB_ACCESS_WRAPPER /* pixman_blt() doesn't support accessors yet */
+ : if (pm == FB_ALLONES && alu == GXcopy && !reverse &&
+ : !upsidedown)
+ : {
+ : if (!pixman_blt ((uint32_t *)src, (uint32_t *)dst, srcStride, dstStride, srcBpp, dstBpp,
+ : (pbox->x1 + dx + srcXoff),
+ : (pbox->y1 + dy + srcYoff),
+ : (pbox->x1 + srcXoff),
+ : (pbox->y1 + srcYoff),
+ : (pbox->x2 - pbox->x1),
+ : (pbox->y2 - pbox->y1)))
+ : goto fallback;
+ : else
+ : goto next;
+ : }
+ : fallback:
+ :#endif
+ : fbBlt (src + (pbox->y1 + dy + srcYoff) * srcStride,
+ : srcStride,
+ : (pbox->x1 + dx + srcXoff) * srcBpp,
+ :
+ : dst + (pbox->y1 + dstYoff) * dstStride,
+ : dstStride,
+ : (pbox->x1 + dstXoff) * dstBpp,
+ :
+ : (pbox->x2 - pbox->x1) * dstBpp,
+ : (pbox->y2 - pbox->y1),
+ :
+ : alu,
+ : pm,
+ : dstBpp,
+ :
+ : reverse,
+ : upsidedown);
+ :#ifndef FB_ACCESS_WRAPPER
+ : next:
+ :#endif
+ : pbox++;
+ : }
+ : fbFinishAccess (pDstDrawable);
+ : fbFinishAccess (pSrcDrawable);
+ :}
+ :
+ :void
+ :fbCopy1toN (DrawablePtr pSrcDrawable,
+ : DrawablePtr pDstDrawable,
+ : GCPtr pGC,
+ : BoxPtr pbox,
+ : int nbox,
+ : int dx,
+ : int dy,
+ : Bool reverse,
+ : Bool upsidedown,
+ : Pixel bitplane,
+ : void *closure)
+ :{
+ : FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
+ : FbBits *src;
+ : FbStride srcStride;
+ : int srcBpp;
+ : int srcXoff, srcYoff;
+ : FbBits *dst;
+ : FbStride dstStride;
+ : int dstBpp;
+ : int dstXoff, dstYoff;
+ :
+ : fbGetDrawable (pSrcDrawable, src, srcStride, srcBpp, srcXoff, srcYoff);
+ : fbGetDrawable (pDstDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
+ :
+ : while (nbox--)
+ : {
+ : if (dstBpp == 1)
+ : {
+ : fbBlt (src + (pbox->y1 + dy + srcYoff) * srcStride,
+ : srcStride,
+ : (pbox->x1 + dx + srcXoff) * srcBpp,
+ :
+ : dst + (pbox->y1 + dstYoff) * dstStride,
+ : dstStride,
+ : (pbox->x1 + dstXoff) * dstBpp,
+ :
+ : (pbox->x2 - pbox->x1) * dstBpp,
+ : (pbox->y2 - pbox->y1),
+ :
+ : FbOpaqueStipple1Rop(pGC->alu,
+ : pGC->fgPixel,pGC->bgPixel),
+ : pPriv->pm,
+ : dstBpp,
+ :
+ : reverse,
+ : upsidedown);
+ : }
+ : else
+ : {
+ : fbBltOne ((FbStip *) (src + (pbox->y1 + dy + srcYoff) * srcStride),
+ : srcStride*(FB_UNIT/FB_STIP_UNIT),
+ : (pbox->x1 + dx + srcXoff),
+ :
+ : dst + (pbox->y1 + dstYoff) * dstStride,
+ : dstStride,
+ : (pbox->x1 + dstXoff) * dstBpp,
+ : dstBpp,
+ :
+ : (pbox->x2 - pbox->x1) * dstBpp,
+ : (pbox->y2 - pbox->y1),
+ :
+ : pPriv->and, pPriv->xor,
+ : pPriv->bgand, pPriv->bgxor);
+ : }
+ : pbox++;
+ : }
+ :
+ : fbFinishAccess (pDstDrawable);
+ : fbFinishAccess (pSrcDrawable);
+ :}
+ :
+ :void
+ :fbCopyNto1 (DrawablePtr pSrcDrawable,
+ : DrawablePtr pDstDrawable,
+ : GCPtr pGC,
+ : BoxPtr pbox,
+ : int nbox,
+ : int dx,
+ : int dy,
+ : Bool reverse,
+ : Bool upsidedown,
+ : Pixel bitplane,
+ : void *closure)
+ :{
+ : FbGCPrivPtr pPriv = fbGetGCPrivate (pGC);
+ :
+ : while (nbox--)
+ : {
+ : if (pDstDrawable->bitsPerPixel == 1)
+ : {
+ : FbBits *src;
+ : FbStride srcStride;
+ : int srcBpp;
+ : int srcXoff, srcYoff;
+ :
+ : FbStip *dst;
+ : FbStride dstStride;
+ : int dstBpp;
+ : int dstXoff, dstYoff;
+ :
+ : fbGetDrawable (pSrcDrawable, src, srcStride, srcBpp, srcXoff, srcYoff);
+ : fbGetStipDrawable (pDstDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
+ : fbBltPlane (src + (pbox->y1+ dy + srcYoff) * srcStride,
+ : srcStride,
+ : (pbox->x1 + dx + srcXoff) * srcBpp,
+ : srcBpp,
+ :
+ : dst + (pbox->y1 + dstYoff) * dstStride,
+ : dstStride,
+ : (pbox->x1 + dstXoff) * dstBpp,
+ :
+ : (pbox->x2 - pbox->x1) * srcBpp,
+ : (pbox->y2 - pbox->y1),
+ :
+ : (FbStip) pPriv->and, (FbStip) pPriv->xor,
+ : (FbStip) pPriv->bgand, (FbStip) pPriv->bgxor,
+ : bitplane);
+ : fbFinishAccess (pDstDrawable);
+ : fbFinishAccess (pSrcDrawable);
+ : }
+ : else
+ : {
+ : FbBits *src;
+ : FbStride srcStride;
+ : int srcBpp;
+ : int srcXoff, srcYoff;
+ :
+ : FbBits *dst;
+ : FbStride dstStride;
+ : int dstBpp;
+ : int dstXoff, dstYoff;
+ :
+ : FbStip *tmp;
+ : FbStride tmpStride;
+ : int width, height;
+ :
+ : width = pbox->x2 - pbox->x1;
+ : height = pbox->y2 - pbox->y1;
+ :
+ : tmpStride = ((width + FB_STIP_MASK) >> FB_STIP_SHIFT);
+ : tmp = xalloc (tmpStride * height * sizeof (FbStip));
+ : if (!tmp)
+ : return;
+ :
+ : fbGetDrawable (pSrcDrawable, src, srcStride, srcBpp, srcXoff, srcYoff);
+ : fbGetDrawable (pDstDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
+ :
+ : fbBltPlane (src + (pbox->y1+ dy + srcYoff) * srcStride,
+ : srcStride,
+ : (pbox->x1 + dx + srcXoff) * srcBpp,
+ : srcBpp,
+ :
+ : tmp,
+ : tmpStride,
+ : 0,
+ :
+ : width * srcBpp,
+ : height,
+ :
+ : fbAndStip(GXcopy,FB_ALLONES,FB_ALLONES),
+ : fbXorStip(GXcopy,FB_ALLONES,FB_ALLONES),
+ : fbAndStip(GXcopy,0,FB_ALLONES),
+ : fbXorStip(GXcopy,0,FB_ALLONES),
+ : bitplane);
+ : fbBltOne (tmp,
+ : tmpStride,
+ : 0,
+ :
+ : dst + (pbox->y1 + dstYoff) * dstStride,
+ : dstStride,
+ : (pbox->x1 + dstXoff) * dstBpp,
+ : dstBpp,
+ :
+ : width * dstBpp,
+ : height,
+ :
+ : pPriv->and, pPriv->xor,
+ : pPriv->bgand, pPriv->bgxor);
+ : xfree (tmp);
+ :
+ : fbFinishAccess (pDstDrawable);
+ : fbFinishAccess (pSrcDrawable);
+ : }
+ : pbox++;
+ : }
+ :}
+ :
+ :void
+ :fbCopyRegion (DrawablePtr pSrcDrawable,
+ : DrawablePtr pDstDrawable,
+ : GCPtr pGC,
+ : RegionPtr pDstRegion,
+ : int dx,
+ : int dy,
+ : fbCopyProc copyProc,
+ : Pixel bitPlane,
+ : void *closure)
+ 4 0.0044 :{ /* fbCopyRegion total: 27 0.0294 */
+ : int careful;
+ : Bool reverse;
+ : Bool upsidedown;
+ : BoxPtr pbox;
+ : int nbox;
+ : BoxPtr pboxNew1, pboxNew2, pboxBase, pboxNext, pboxTmp;
+ :
+ 8 0.0087 : pbox = REGION_RECTS(pDstRegion);
+ : nbox = REGION_NUM_RECTS(pDstRegion);
+ :
+ : /* XXX we have to err on the side of safety when both are windows,
+ : * because we don't know if IncludeInferiors is being used.
+ : */
+ 2 0.0022 : careful = ((pSrcDrawable == pDstDrawable) ||
+ : ((pSrcDrawable->type == DRAWABLE_WINDOW) &&
+ : (pDstDrawable->type == DRAWABLE_WINDOW)));
+ :
+ : pboxNew1 = NULL;
+ : pboxNew2 = NULL;
+ : if (careful && dy < 0)
+ : {
+ : upsidedown = TRUE;
+ :
+ : if (nbox > 1)
+ : {
+ : /* keep ordering in each band, reverse order of bands */
+ : pboxNew1 = (BoxPtr)ALLOCATE_LOCAL(sizeof(BoxRec) * nbox);
+ : if(!pboxNew1)
+ : return;
+ : pboxBase = pboxNext = pbox+nbox-1;
+ : while (pboxBase >= pbox)
+ : {
+ : while ((pboxNext >= pbox) &&
+ : (pboxBase->y1 == pboxNext->y1))
+ : pboxNext--;
+ : pboxTmp = pboxNext+1;
+ : while (pboxTmp <= pboxBase)
+ : {
+ : *pboxNew1++ = *pboxTmp++;
+ : }
+ : pboxBase = pboxNext;
+ : }
+ : pboxNew1 -= nbox;
+ : pbox = pboxNew1;
+ : }
+ : }
+ : else
+ : {
+ : /* walk source top to bottom */
+ : upsidedown = FALSE;
+ : }
+ :
+ : if (careful && dx < 0)
+ : {
+ : /* walk source right to left */
+ : if (dy <= 0)
+ : reverse = TRUE;
+ : else
+ : reverse = FALSE;
+ :
+ : if (nbox > 1)
+ : {
+ : /* reverse order of rects in each band */
+ : pboxNew2 = (BoxPtr)ALLOCATE_LOCAL(sizeof(BoxRec) * nbox);
+ : if(!pboxNew2)
+ : {
+ : if (pboxNew1)
+ : DEALLOCATE_LOCAL(pboxNew1);
+ : return;
+ : }
+ : pboxBase = pboxNext = pbox;
+ : while (pboxBase < pbox+nbox)
+ : {
+ : while ((pboxNext < pbox+nbox) &&
+ : (pboxNext->y1 == pboxBase->y1))
+ : pboxNext++;
+ : pboxTmp = pboxNext;
+ : while (pboxTmp != pboxBase)
+ : {
+ : *pboxNew2++ = *--pboxTmp;
+ : }
+ : pboxBase = pboxNext;
+ : }
+ 1 0.0011 : pboxNew2 -= nbox;
+ : pbox = pboxNew2;
+ : }
+ : }
+ : else
+ : {
+ : /* walk source left to right */
+ : reverse = FALSE;
+ : }
+ :
+ 8 0.0087 : (*copyProc) (pSrcDrawable,
+ : pDstDrawable,
+ : pGC,
+ : pbox,
+ : nbox,
+ : dx, dy,
+ : reverse, upsidedown, bitPlane, closure);
+ :
+ : if (pboxNew1)
+ : DEALLOCATE_LOCAL (pboxNew1);
+ : if (pboxNew2)
+ : DEALLOCATE_LOCAL (pboxNew2);
+ 4 0.0044 :}
+ :
+ :RegionPtr
+ :fbDoCopy (DrawablePtr pSrcDrawable,
+ : DrawablePtr pDstDrawable,
+ : GCPtr pGC,
+ : int xIn,
+ : int yIn,
+ : int widthSrc,
+ : int heightSrc,
+ : int xOut,
+ : int yOut,
+ : fbCopyProc copyProc,
+ : Pixel bitPlane,
+ : void *closure)
+ 5 0.0054 :{ /* fbDoCopy total: 100 0.1089 */
+ : RegionPtr prgnSrcClip = NULL; /* may be a new region, or just a copy */
+ : Bool freeSrcClip = FALSE;
+ : RegionPtr prgnExposed = NULL;
+ : RegionRec rgnDst;
+ : int dx;
+ : int dy;
+ : int numRects;
+ : int box_x1;
+ : int box_y1;
+ : int box_x2;
+ : int box_y2;
+ : Bool fastSrc = FALSE; /* for fast clipping with pixmap source */
+ : Bool fastDst = FALSE; /* for fast clipping with one rect dest */
+ : Bool fastExpose = FALSE; /* for fast exposures with pixmap source */
+ :
+ : /* Short cut for unmapped windows */
+ :
+ 1 0.0011 : if (pDstDrawable->type == DRAWABLE_WINDOW &&
+ : !((WindowPtr)pDstDrawable)->realized)
+ : {
+ : return NULL;
+ : }
+ :
+ 8 0.0087 : if ((pSrcDrawable != pDstDrawable) &&
+ : pSrcDrawable->pScreen->SourceValidate)
+ : {
+ 1 0.0011 : (*pSrcDrawable->pScreen->SourceValidate) (pSrcDrawable, xIn, yIn, widthSrc, heightSrc);
+ : }
+ :
+ : /* Compute source clip region */
+ 2 0.0022 : if (pSrcDrawable->type == DRAWABLE_PIXMAP)
+ : {
+ 6 0.0065 : if ((pSrcDrawable == pDstDrawable) && (pGC->clientClipType == CT_NONE))
+ : prgnSrcClip = fbGetCompositeClip(pGC);
+ : else
+ : fastSrc = TRUE;
+ : }
+ : else
+ : {
+ : if (pGC->subWindowMode == IncludeInferiors)
+ : {
+ : /*
+ : * XFree86 DDX empties the border clip when the
+ : * VT is inactive, make sure the region isn't empty
+ : */
+ : if (!((WindowPtr) pSrcDrawable)->parent &&
+ : REGION_NOTEMPTY (pSrcDrawable->pScreen,
+ : &((WindowPtr) pSrcDrawable)->borderClip))
+ : {
+ : /*
+ : * special case bitblt from root window in
+ : * IncludeInferiors mode; just like from a pixmap
+ : */
+ : fastSrc = TRUE;
+ : }
+ : else if ((pSrcDrawable == pDstDrawable) &&
+ : (pGC->clientClipType == CT_NONE))
+ : {
+ : prgnSrcClip = fbGetCompositeClip(pGC);
+ : }
+ : else
+ : {
+ : prgnSrcClip = NotClippedByChildren((WindowPtr)pSrcDrawable);
+ : freeSrcClip = TRUE;
+ : }
+ : }
+ : else
+ : {
+ : prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList;
+ : }
+ : }
+ :
+ : xIn += pSrcDrawable->x;
+ 2 0.0022 : yIn += pSrcDrawable->y;
+ :
+ 1 0.0011 : xOut += pDstDrawable->x;
+ 2 0.0022 : yOut += pDstDrawable->y;
+ :
+ : box_x1 = xIn;
+ : box_y1 = yIn;
+ : box_x2 = xIn + widthSrc;
+ 2 0.0022 : box_y2 = yIn + heightSrc;
+ :
+ 2 0.0022 : dx = xIn - xOut;
+ 4 0.0044 : dy = yIn - yOut;
+ :
+ : /* Don't create a source region if we are doing a fast clip */
+ 3 0.0033 : if (fastSrc)
+ : {
+ : RegionPtr cclip;
+ :
+ : fastExpose = TRUE;
+ : /*
+ : * clip the source; if regions extend beyond the source size,
+ : * make sure exposure events get sent
+ : */
+ 4 0.0044 : if (box_x1 < pSrcDrawable->x)
+ : {
+ : box_x1 = pSrcDrawable->x;
+ : fastExpose = FALSE;
+ : }
+ : if (box_y1 < pSrcDrawable->y)
+ : {
+ : box_y1 = pSrcDrawable->y;
+ : fastExpose = FALSE;
+ : }
+ 7 0.0076 : if (box_x2 > pSrcDrawable->x + (int) pSrcDrawable->width)
+ : {
+ : box_x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
+ : fastExpose = FALSE;
+ : }
+ 4 0.0044 : if (box_y2 > pSrcDrawable->y + (int) pSrcDrawable->height)
+ : {
+ : box_y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
+ : fastExpose = FALSE;
+ : }
+ :
+ : /* Translate and clip the dst to the destination composite clip */
+ : box_x1 -= dx;
+ : box_x2 -= dx;
+ 1 0.0011 : box_y1 -= dy;
+ 1 0.0011 : box_y2 -= dy;
+ :
+ : /* If the destination composite clip is one rectangle we can
+ : do the clip directly. Otherwise we have to create a full
+ : blown region and call intersect */
+ :
+ 1 0.0011 : cclip = fbGetCompositeClip(pGC);
+ 2 0.0022 : if (REGION_NUM_RECTS(cclip) == 1)
+ : {
+ 9 0.0098 : BoxPtr pBox = REGION_RECTS(cclip);
+ :
+ : if (box_x1 < pBox->x1) box_x1 = pBox->x1;
+ : if (box_x2 > pBox->x2) box_x2 = pBox->x2;
+ : if (box_y1 < pBox->y1) box_y1 = pBox->y1;
+ 1 0.0011 : if (box_y2 > pBox->y2) box_y2 = pBox->y2;
+ : fastDst = TRUE;
+ : }
+ : }
+ :
+ : /* Check to see if the region is empty */
+ 2 0.0022 : if (box_x1 >= box_x2 || box_y1 >= box_y2)
+ : {
+ 3 0.0033 : REGION_NULL(pGC->pScreen, &rgnDst);
+ : }
+ : else
+ : {
+ : BoxRec box;
+ : box.x1 = box_x1;
+ : box.y1 = box_y1;
+ : box.x2 = box_x2;
+ : box.y2 = box_y2;
+ : REGION_INIT(pGC->pScreen, &rgnDst, &box, 1);
+ : }
+ :
+ : /* Clip against complex source if needed */
+ 2 0.0022 : if (!fastSrc)
+ : {
+ : REGION_INTERSECT(pGC->pScreen, &rgnDst, &rgnDst, prgnSrcClip);
+ : REGION_TRANSLATE(pGC->pScreen, &rgnDst, -dx, -dy);
+ : }
+ :
+ : /* Clip against complex dest if needed */
+ 1 0.0011 : if (!fastDst)
+ : {
+ : REGION_INTERSECT(pGC->pScreen, &rgnDst, &rgnDst,
+ : fbGetCompositeClip(pGC));
+ : }
+ :
+ : /* Do bit blitting */
+ : numRects = REGION_NUM_RECTS(&rgnDst);
+ 1 0.0011 : if (numRects && widthSrc && heightSrc)
+ 16 0.0174 : fbCopyRegion (pSrcDrawable, pDstDrawable, pGC,
+ : &rgnDst, dx, dy, copyProc, bitPlane, closure);
+ :
+ : /* Pixmap sources generate a NoExposed (we return NULL to do this) */
+ : if (!fastExpose && pGC->fExpose)
+ : prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC,
+ : xIn - pSrcDrawable->x,
+ : yIn - pSrcDrawable->y,
+ : widthSrc, heightSrc,
+ : xOut - pDstDrawable->x,
+ : yOut - pDstDrawable->y,
+ : (unsigned long) bitPlane);
+ : REGION_UNINIT(pGC->pScreen, &rgnDst);
+ 1 0.0011 : if (freeSrcClip)
+ : REGION_DESTROY(pGC->pScreen, prgnSrcClip);
+ : fbValidateDrawable (pDstDrawable);
+ : return prgnExposed;
+ 5 0.0054 :}
+ :
+ :RegionPtr
+ :fbCopyArea (DrawablePtr pSrcDrawable,
+ : DrawablePtr pDstDrawable,
+ : GCPtr pGC,
+ : int xIn,
+ : int yIn,
+ : int widthSrc,
+ : int heightSrc,
+ : int xOut,
+ : int yOut)
+ :{
+ : fbCopyProc copy;
+ :
+ :#ifdef FB_24_32BIT
+ : if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel)
+ : copy = fb24_32CopyMtoN;
+ : else
+ :#endif
+ : copy = fbCopyNtoN;
+ : return fbDoCopy (pSrcDrawable, pDstDrawable, pGC, xIn, yIn,
+ : widthSrc, heightSrc, xOut, yOut, copy, 0, 0);
+ :}
+ :
+ :RegionPtr
+ :fbCopyPlane (DrawablePtr pSrcDrawable,
+ : DrawablePtr pDstDrawable,
+ : GCPtr pGC,
+ : int xIn,
+ : int yIn,
+ : int widthSrc,
+ : int heightSrc,
+ : int xOut,
+ : int yOut,
+ : unsigned long bitplane)
+ :{
+ : if (pSrcDrawable->bitsPerPixel > 1)
+ : return fbDoCopy (pSrcDrawable, pDstDrawable, pGC,
+ : xIn, yIn, widthSrc, heightSrc,
+ : xOut, yOut, fbCopyNto1, (Pixel) bitplane, 0);
+ : else if (bitplane & 1)
+ : return fbDoCopy (pSrcDrawable, pDstDrawable, pGC, xIn, yIn,
+ : widthSrc, heightSrc, xOut, yOut, fbCopy1toN,
+ : (Pixel) bitplane, 0);
+ : else
+ : return miHandleExposures(pSrcDrawable, pDstDrawable, pGC,
+ : xIn, yIn,
+ : widthSrc,
+ : heightSrc,
+ : xOut, yOut, bitplane);
+ :}
+/*
+ * Total samples for file : "msort.c"
+ *
+ * 125 0.1362
+ */
+
+<credited to line zero> 125 0.1362 :
+ /* msort_with_tmp total: 125 0.1362 */
+/*
+ * Total samples for file : "i810_hwmc.c"
+ *
+ * 119 0.1296
+ */
+
+<credited to line zero> 119 0.1296 :
+ /* __i686.get_pc_thunk.bx total: 119 0.1296 */
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/dix/resource.c"
+ *
+ * 117 0.1275
+ */
+
+
+ :/************************************************************
+ :
+ :Copyright 1987, 1998 The Open Group
+ :
+ :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.
+ :
+ :The above copyright notice and this permission notice shall be included in
+ :all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ :IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ :FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ :OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ :AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ :CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of The Open Group shall not be
+ :used in advertising or otherwise to promote the sale, use or other dealings
+ :in this Software without prior written authorization from The Open Group.
+ :
+ :
+ :Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+ :
+ : All Rights Reserved
+ :
+ :Permission to use, copy, modify, and distribute this software and its
+ :documentation for any purpose and without fee is hereby granted,
+ :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 Digital not be
+ :used in advertising or publicity pertaining to distribution of the
+ :software without specific, written prior permission.
+ :
+ :DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ :ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ :DIGITAL 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.
+ :
+ :********************************************************/
+ :/* The panoramix components contained the following notice */
+ :/*****************************************************************
+ :
+ :Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
+ :
+ :Permission is hereby granted, free of charge, to any person obtaining a copy
+ :of this software and associated documentation files (the "Software"), to deal
+ :in the Software without restriction, including without limitation the rights
+ :to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ :copies of the Software.
+ :
+ :The above copyright notice and this permission notice shall be included in
+ :all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ :IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ :FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ :DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
+ :BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
+ :WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+ :IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of Digital Equipment Corporation
+ :shall not be used in advertising or otherwise to promote the sale, use or other
+ :dealings in this Software without prior written authorization from Digital
+ :Equipment Corporation.
+ :
+ :******************************************************************/
+ :/* XSERVER_DTRACE additions:
+ : * Copyright 2005-2006 Sun Microsystems, Inc. All rights reserved.
+ : *
+ : * Permission is hereby granted, free of charge, to any person obtaining a
+ : * copy of this software and associated documentation files (the
+ : * "Software"), to deal in the Software without restriction, including
+ : * without limitation the rights to use, copy, modify, merge, publish,
+ : * distribute, and/or sell copies of the Software, and to permit persons
+ : * to whom the Software is furnished to do so, provided that the above
+ : * copyright notice(s) and this permission notice appear in all copies of
+ : * the Software and that both the above copyright notice(s) and this
+ : * permission notice appear in supporting documentation.
+ : *
+ : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+ : * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ : * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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.
+ : *
+ : * Except as contained in this notice, the name of a copyright holder
+ : * shall not be used in advertising or otherwise to promote the sale, use
+ : * or other dealings in this Software without prior written authorization
+ : * of the copyright holder.
+ : */
+ :
+ :/* Routines to manage various kinds of resources:
+ : *
+ : * CreateNewResourceType, CreateNewResourceClass, InitClientResources,
+ : * FakeClientID, AddResource, FreeResource, FreeClientResources,
+ : * FreeAllResources, LookupIDByType, LookupIDByClass, GetXIDRange
+ : */
+ :
+ :/*
+ : * A resource ID is a 32 bit quantity, the upper 2 bits of which are
+ : * off-limits for client-visible resources. The next 8 bits are
+ : * used as client ID, and the low 22 bits come from the client.
+ : * A resource ID is "hashed" by extracting and xoring subfields
+ : * (varying with the size of the hash table).
+ : *
+ : * It is sometimes necessary for the server to create an ID that looks
+ : * like it belongs to a client. This ID, however, must not be one
+ : * the client actually can create, or we have the potential for conflict.
+ : * The 31st bit of the ID is reserved for the server's use for this
+ : * purpose. By setting CLIENT_ID(id) to the client, the SERVER_BIT to
+ : * 1, and an otherwise arbitrary ID in the low 22 bits, we can create a
+ : * resource "owned" by the client.
+ : */
+ :
+ :#define NEED_EVENTS
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include <X11/X.h>
+ :#include "misc.h"
+ :#include "os.h"
+ :#include "resource.h"
+ :#include "dixstruct.h"
+ :#include "opaque.h"
+ :#include "windowstr.h"
+ :#include "dixfont.h"
+ :#include "colormap.h"
+ :#include "inputstr.h"
+ :#include "dixevents.h"
+ :#include "dixgrabs.h"
+ :#include "cursor.h"
+ :#ifdef PANORAMIX
+ :#include "panoramiX.h"
+ :#include "panoramiXsrv.h"
+ :#endif
+ :#include "xace.h"
+ :#include <assert.h>
+ :
+ :#ifdef XSERVER_DTRACE
+ :#include <sys/types.h>
+ :typedef const char *string;
+ :#include "Xserver-dtrace.h"
+ :
+ :#define TypeNameString(t) NameForAtom(ResourceNames[t & TypeMask])
+ :#endif
+ :
+ :static void RebuildTable(
+ : int /*client*/
+ :);
+ :
+ :#define SERVER_MINID 32
+ :
+ :#define INITBUCKETS 64
+ :#define INITHASHSIZE 6
+ :#define MAXHASHSIZE 11
+ :
+ :typedef struct _Resource {
+ : struct _Resource *next;
+ : XID id;
+ : RESTYPE type;
+ : pointer value;
+ :} ResourceRec, *ResourcePtr;
+ :#define NullResource ((ResourcePtr)NULL)
+ :
+ :typedef struct _ClientResource {
+ : ResourcePtr *resources;
+ : int elements;
+ : int buckets;
+ : int hashsize; /* log(2)(buckets) */
+ : XID fakeID;
+ : XID endFakeID;
+ : XID expectID;
+ :} ClientResourceRec;
+ :
+ :_X_EXPORT RESTYPE lastResourceType;
+ :static RESTYPE lastResourceClass;
+ :_X_EXPORT RESTYPE TypeMask;
+ :
+ :static DeleteType *DeleteFuncs = (DeleteType *)NULL;
+ :
+ :#ifdef XResExtension
+ :
+ :_X_EXPORT Atom * ResourceNames = NULL;
+ :
+ :_X_EXPORT void RegisterResourceName (RESTYPE type, char *name)
+ :{
+ : ResourceNames[type & TypeMask] = MakeAtom(name, strlen(name), TRUE);
+ :}
+ :
+ :#endif
+ :
+ :_X_EXPORT RESTYPE
+ :CreateNewResourceType(DeleteType deleteFunc)
+ :{
+ : RESTYPE next = lastResourceType + 1;
+ : DeleteType *funcs;
+ :
+ : if (next & lastResourceClass)
+ : return 0;
+ : funcs = (DeleteType *)xrealloc(DeleteFuncs,
+ : (next + 1) * sizeof(DeleteType));
+ : if (!funcs)
+ : return 0;
+ :
+ :#ifdef XResExtension
+ : {
+ : Atom *newnames;
+ : newnames = xrealloc(ResourceNames, (next + 1) * sizeof(Atom));
+ : if(!newnames)
+ : return 0;
+ : ResourceNames = newnames;
+ : ResourceNames[next] = 0;
+ : }
+ :#endif
+ :
+ : lastResourceType = next;
+ : DeleteFuncs = funcs;
+ : DeleteFuncs[next] = deleteFunc;
+ : return next;
+ :}
+ :
+ :_X_EXPORT RESTYPE
+ :CreateNewResourceClass(void)
+ :{
+ : RESTYPE next = lastResourceClass >> 1;
+ :
+ : if (next & lastResourceType)
+ : return 0;
+ : lastResourceClass = next;
+ : TypeMask = next - 1;
+ : return next;
+ :}
+ :
+ :static ClientResourceRec clientTable[MAXCLIENTS];
+ :
+ :/*****************
+ : * InitClientResources
+ : * When a new client is created, call this to allocate space
+ : * in resource table
+ : *****************/
+ :
+ :Bool
+ :InitClientResources(ClientPtr client)
+ :{
+ : int i, j;
+ :
+ : if (client == serverClient)
+ : {
+ : lastResourceType = RT_LASTPREDEF;
+ : lastResourceClass = RC_LASTPREDEF;
+ : TypeMask = RC_LASTPREDEF - 1;
+ : if (DeleteFuncs)
+ : xfree(DeleteFuncs);
+ : DeleteFuncs = (DeleteType *)xalloc((lastResourceType + 1) *
+ : sizeof(DeleteType));
+ : if (!DeleteFuncs)
+ : return FALSE;
+ : DeleteFuncs[RT_NONE & TypeMask] = (DeleteType)NoopDDA;
+ : DeleteFuncs[RT_WINDOW & TypeMask] = DeleteWindow;
+ : DeleteFuncs[RT_PIXMAP & TypeMask] = dixDestroyPixmap;
+ : DeleteFuncs[RT_GC & TypeMask] = FreeGC;
+ : DeleteFuncs[RT_FONT & TypeMask] = CloseFont;
+ : DeleteFuncs[RT_CURSOR & TypeMask] = FreeCursor;
+ : DeleteFuncs[RT_COLORMAP & TypeMask] = FreeColormap;
+ : DeleteFuncs[RT_CMAPENTRY & TypeMask] = FreeClientPixels;
+ : DeleteFuncs[RT_OTHERCLIENT & TypeMask] = OtherClientGone;
+ : DeleteFuncs[RT_PASSIVEGRAB & TypeMask] = DeletePassiveGrab;
+ :
+ :#ifdef XResExtension
+ : if(ResourceNames)
+ : xfree(ResourceNames);
+ : ResourceNames = xalloc((lastResourceType + 1) * sizeof(Atom));
+ : if(!ResourceNames)
+ : return FALSE;
+ :#endif
+ : }
+ : clientTable[i = client->index].resources =
+ : (ResourcePtr *)xalloc(INITBUCKETS*sizeof(ResourcePtr));
+ : if (!clientTable[i].resources)
+ : return FALSE;
+ : clientTable[i].buckets = INITBUCKETS;
+ : clientTable[i].elements = 0;
+ : clientTable[i].hashsize = INITHASHSIZE;
+ : /* Many IDs allocated from the server client are visible to clients,
+ : * so we don't use the SERVER_BIT for them, but we have to start
+ : * past the magic value constants used in the protocol. For normal
+ : * clients, we can start from zero, with SERVER_BIT set.
+ : */
+ : clientTable[i].fakeID = client->clientAsMask |
+ : (client->index ? SERVER_BIT : SERVER_MINID);
+ : clientTable[i].endFakeID = (clientTable[i].fakeID | RESOURCE_ID_MASK) + 1;
+ : clientTable[i].expectID = client->clientAsMask;
+ : for (j=0; j<INITBUCKETS; j++)
+ : {
+ : clientTable[i].resources[j] = NullResource;
+ : }
+ : return TRUE;
+ :}
+ :
+ :
+ :static int
+ :Hash(int client, XID id)
+ 7 0.0076 :{ /* Hash total: 27 0.0294 */
+ 3 0.0033 : id &= RESOURCE_ID_MASK;
+ 9 0.0098 : switch (clientTable[client].hashsize)
+ : {
+ : case 6:
+ 2 0.0022 : return ((int)(0x03F & (id ^ (id>>6) ^ (id>>12))));
+ : case 7:
+ 6 0.0065 : return ((int)(0x07F & (id ^ (id>>7) ^ (id>>13))));
+ : case 8:
+ : return ((int)(0x0FF & (id ^ (id>>8) ^ (id>>16))));
+ : case 9:
+ : return ((int)(0x1FF & (id ^ (id>>9))));
+ : case 10:
+ : return ((int)(0x3FF & (id ^ (id>>10))));
+ : case 11:
+ : return ((int)(0x7FF & (id ^ (id>>11))));
+ : }
+ : return -1;
+ :}
+ :
+ :static XID
+ :AvailableID(
+ : int client,
+ : XID id,
+ : XID maxid,
+ : XID goodid)
+ :{
+ : ResourcePtr res;
+ :
+ : if ((goodid >= id) && (goodid <= maxid))
+ : return goodid;
+ : for (; id <= maxid; id++)
+ : {
+ : res = clientTable[client].resources[Hash(client, id)];
+ : while (res && (res->id != id))
+ : res = res->next;
+ : if (!res)
+ : return id;
+ : }
+ : return 0;
+ :}
+ :
+ :_X_EXPORT void
+ :GetXIDRange(int client, Bool server, XID *minp, XID *maxp)
+ :{
+ : XID id, maxid;
+ : ResourcePtr *resp;
+ : ResourcePtr res;
+ : int i;
+ : XID goodid;
+ :
+ : id = (Mask)client << CLIENTOFFSET;
+ : if (server)
+ : id |= client ? SERVER_BIT : SERVER_MINID;
+ : maxid = id | RESOURCE_ID_MASK;
+ : goodid = 0;
+ : for (resp = clientTable[client].resources, i = clientTable[client].buckets;
+ : --i >= 0;)
+ : {
+ : for (res = *resp++; res; res = res->next)
+ : {
+ : if ((res->id < id) || (res->id > maxid))
+ : continue;
+ : if (((res->id - id) >= (maxid - res->id)) ?
+ : (goodid = AvailableID(client, id, res->id - 1, goodid)) :
+ : !(goodid = AvailableID(client, res->id + 1, maxid, goodid)))
+ : maxid = res->id - 1;
+ : else
+ : id = res->id + 1;
+ : }
+ : }
+ : if (id > maxid)
+ : id = maxid = 0;
+ : *minp = id;
+ : *maxp = maxid;
+ :}
+ :
+ :/**
+ : * GetXIDList is called by the XC-MISC extension's MiscGetXIDList function.
+ : * This function tries to find count unused XIDs for the given client. It
+ : * puts the IDs in the array pids and returns the number found, which should
+ : * almost always be the number requested.
+ : *
+ : * The circumstances that lead to a call to this function are very rare.
+ : * Xlib must run out of IDs while trying to generate a request that wants
+ : * multiple ID's, like the Multi-buffering CreateImageBuffers request.
+ : *
+ : * No rocket science in the implementation; just iterate over all
+ : * possible IDs for the given client and pick the first count IDs
+ : * that aren't in use. A more efficient algorithm could probably be
+ : * invented, but this will be used so rarely that this should suffice.
+ : */
+ :
+ :_X_EXPORT unsigned int
+ :GetXIDList(ClientPtr pClient, unsigned count, XID *pids)
+ :{
+ : unsigned int found = 0;
+ : XID id = pClient->clientAsMask;
+ : XID maxid;
+ :
+ : maxid = id | RESOURCE_ID_MASK;
+ : while ( (found < count) && (id <= maxid) )
+ : {
+ : if (!LookupIDByClass(id, RC_ANY))
+ : {
+ : pids[found++] = id;
+ : }
+ : id++;
+ : }
+ : return found;
+ :}
+ :
+ :/*
+ : * Return the next usable fake client ID.
+ : *
+ : * Normally this is just the next one in line, but if we've used the last
+ : * in the range, we need to find a new range of safe IDs to avoid
+ : * over-running another client.
+ : */
+ :
+ :_X_EXPORT XID
+ :FakeClientID(int client)
+ :{
+ : XID id, maxid;
+ :
+ : id = clientTable[client].fakeID++;
+ : if (id != clientTable[client].endFakeID)
+ : return id;
+ : GetXIDRange(client, TRUE, &id, &maxid);
+ : if (!id) {
+ : if (!client)
+ : FatalError("FakeClientID: server internal ids exhausted\n");
+ : MarkClientException(clients[client]);
+ : id = ((Mask)client << CLIENTOFFSET) | (SERVER_BIT * 3);
+ : maxid = id | RESOURCE_ID_MASK;
+ : }
+ : clientTable[client].fakeID = id + 1;
+ : clientTable[client].endFakeID = maxid + 1;
+ : return id;
+ :}
+ :
+ :_X_EXPORT Bool
+ :AddResource(XID id, RESTYPE type, pointer value)
+ 2 0.0022 :{ /* AddResource total: 8 0.0087 */
+ : int client;
+ : ClientResourceRec *rrec;
+ : ResourcePtr res, *head;
+ :
+ :#ifdef XSERVER_DTRACE
+ : XSERVER_RESOURCE_ALLOC(id, type, value, TypeNameString(type));
+ :#endif
+ : client = CLIENT_ID(id);
+ 1 0.0011 : rrec = &clientTable[client];
+ 1 0.0011 : if (!rrec->buckets)
+ : {
+ : ErrorF("AddResource(%lx, %lx, %lx), client=%d \n",
+ : (unsigned long)id, type, (unsigned long)value, client);
+ : FatalError("client not in use\n");
+ : }
+ : if ((rrec->elements >= 4*rrec->buckets) &&
+ : (rrec->hashsize < MAXHASHSIZE))
+ : RebuildTable(client);
+ : head = &rrec->resources[Hash(client, id)];
+ : res = (ResourcePtr)xalloc(sizeof(ResourceRec));
+ : if (!res)
+ : {
+ : (*DeleteFuncs[type & TypeMask])(value, id);
+ : return FALSE;
+ : }
+ 1 0.0011 : res->next = *head;
+ : res->id = id;
+ : res->type = type;
+ 1 0.0011 : res->value = value;
+ : *head = res;
+ : rrec->elements++;
+ 2 0.0022 : if (!(id & SERVER_BIT) && (id >= rrec->expectID))
+ : rrec->expectID = id + 1;
+ : return TRUE;
+ :}
+ :
+ :static void
+ :RebuildTable(int client)
+ :{
+ : int j;
+ : ResourcePtr res, next;
+ : ResourcePtr **tails, *resources;
+ : ResourcePtr **tptr, *rptr;
+ :
+ : /*
+ : * For now, preserve insertion order, since some ddx layers depend
+ : * on resources being free in the opposite order they are added.
+ : */
+ :
+ : j = 2 * clientTable[client].buckets;
+ : tails = (ResourcePtr **)ALLOCATE_LOCAL(j * sizeof(ResourcePtr *));
+ : if (!tails)
+ : return;
+ : resources = (ResourcePtr *)xalloc(j * sizeof(ResourcePtr));
+ : if (!resources)
+ : {
+ : DEALLOCATE_LOCAL(tails);
+ : return;
+ : }
+ : for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++)
+ : {
+ : *rptr = NullResource;
+ : *tptr = rptr;
+ : }
+ : clientTable[client].hashsize++;
+ : for (j = clientTable[client].buckets,
+ : rptr = clientTable[client].resources;
+ : --j >= 0;
+ : rptr++)
+ : {
+ : for (res = *rptr; res; res = next)
+ : {
+ : next = res->next;
+ : res->next = NullResource;
+ : tptr = &tails[Hash(client, res->id)];
+ : **tptr = res;
+ : *tptr = &res->next;
+ : }
+ : }
+ : DEALLOCATE_LOCAL(tails);
+ : clientTable[client].buckets *= 2;
+ : xfree(clientTable[client].resources);
+ : clientTable[client].resources = resources;
+ :}
+ :
+ :_X_EXPORT void
+ :FreeResource(XID id, RESTYPE skipDeleteFuncType)
+ 1 0.0011 :{ /* FreeResource total: 27 0.0294 */
+ : int cid;
+ : ResourcePtr res;
+ : ResourcePtr *prev, *head;
+ : int *eltptr;
+ : int elements;
+ : Bool gotOne = FALSE;
+ :
+ 1 0.0011 : if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
+ : {
+ : head = &clientTable[cid].resources[Hash(cid, id)];
+ : eltptr = &clientTable[cid].elements;
+ :
+ : prev = head;
+ 2 0.0022 : while ( (res = *prev) )
+ : {
+ 2 0.0022 : if (res->id == id)
+ : {
+ : RESTYPE rtype = res->type;
+ :
+ :#ifdef XSERVER_DTRACE
+ : XSERVER_RESOURCE_FREE(res->id, res->type,
+ : res->value, TypeNameString(res->type));
+ :#endif
+ : *prev = res->next;
+ : elements = --*eltptr;
+ : if (rtype & RC_CACHED)
+ 1 0.0011 : FlushClientCaches(res->id);
+ 1 0.0011 : if (rtype != skipDeleteFuncType)
+ 6 0.0065 : (*DeleteFuncs[rtype & TypeMask])(res->value, res->id);
+ 1 0.0011 : xfree(res);
+ : if (*eltptr != elements)
+ : prev = head; /* prev may no longer be valid */
+ : gotOne = TRUE;
+ : }
+ : else
+ 11 0.0120 : prev = &res->next;
+ : }
+ 1 0.0011 : if(clients[cid] && (id == clients[cid]->lastDrawableID))
+ : {
+ : clients[cid]->lastDrawable = (DrawablePtr)WindowTable[0];
+ : clients[cid]->lastDrawableID = WindowTable[0]->drawable.id;
+ : }
+ : }
+ : if (!gotOne)
+ : ErrorF("Freeing resource id=%lX which isn't there.\n",
+ : (unsigned long)id);
+ :}
+ :
+ :
+ :_X_EXPORT void
+ :FreeResourceByType(XID id, RESTYPE type, Bool skipFree)
+ :{
+ : int cid;
+ : ResourcePtr res;
+ : ResourcePtr *prev, *head;
+ : if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
+ : {
+ : head = &clientTable[cid].resources[Hash(cid, id)];
+ :
+ : prev = head;
+ : while ( (res = *prev) )
+ : {
+ : if (res->id == id && res->type == type)
+ : {
+ :#ifdef XSERVER_DTRACE
+ : XSERVER_RESOURCE_FREE(res->id, res->type,
+ : res->value, TypeNameString(res->type));
+ :#endif
+ : *prev = res->next;
+ : if (type & RC_CACHED)
+ : FlushClientCaches(res->id);
+ : if (!skipFree)
+ : (*DeleteFuncs[type & TypeMask])(res->value, res->id);
+ : xfree(res);
+ : break;
+ : }
+ : else
+ : prev = &res->next;
+ : }
+ : if(clients[cid] && (id == clients[cid]->lastDrawableID))
+ : {
+ : clients[cid]->lastDrawable = (DrawablePtr)WindowTable[0];
+ : clients[cid]->lastDrawableID = WindowTable[0]->drawable.id;
+ : }
+ : }
+ :}
+ :
+ :/*
+ : * Change the value associated with a resource id. Caller
+ : * is responsible for "doing the right thing" with the old
+ : * data
+ : */
+ :
+ :_X_EXPORT Bool
+ :ChangeResourceValue (XID id, RESTYPE rtype, pointer value)
+ :{
+ : int cid;
+ : ResourcePtr res;
+ :
+ : if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
+ : {
+ : res = clientTable[cid].resources[Hash(cid, id)];
+ :
+ : for (; res; res = res->next)
+ : if ((res->id == id) && (res->type == rtype))
+ : {
+ : if (rtype & RC_CACHED)
+ : FlushClientCaches(res->id);
+ : res->value = value;
+ : return TRUE;
+ : }
+ : }
+ : return FALSE;
+ :}
+ :
+ :/* Note: if func adds or deletes resources, then func can get called
+ : * more than once for some resources. If func adds new resources,
+ : * func might or might not get called for them. func cannot both
+ : * add and delete an equal number of resources!
+ : */
+ :
+ :_X_EXPORT void
+ :FindClientResourcesByType(
+ : ClientPtr client,
+ : RESTYPE type,
+ : FindResType func,
+ : pointer cdata
+ :){
+ : ResourcePtr *resources;
+ : ResourcePtr this, next;
+ : int i, elements;
+ : int *eltptr;
+ :
+ : if (!client)
+ : client = serverClient;
+ :
+ : resources = clientTable[client->index].resources;
+ : eltptr = &clientTable[client->index].elements;
+ : for (i = 0; i < clientTable[client->index].buckets; i++)
+ : {
+ : for (this = resources[i]; this; this = next)
+ : {
+ : next = this->next;
+ : if (!type || this->type == type) {
+ : elements = *eltptr;
+ : (*func)(this->value, this->id, cdata);
+ : if (*eltptr != elements)
+ : next = resources[i]; /* start over */
+ : }
+ : }
+ : }
+ :}
+ :
+ :_X_EXPORT void
+ :FindAllClientResources(
+ : ClientPtr client,
+ : FindAllRes func,
+ : pointer cdata
+ :){
+ : ResourcePtr *resources;
+ : ResourcePtr this, next;
+ : int i, elements;
+ : int *eltptr;
+ :
+ : if (!client)
+ : client = serverClient;
+ :
+ : resources = clientTable[client->index].resources;
+ : eltptr = &clientTable[client->index].elements;
+ : for (i = 0; i < clientTable[client->index].buckets; i++)
+ : {
+ : for (this = resources[i]; this; this = next)
+ : {
+ : next = this->next;
+ : elements = *eltptr;
+ : (*func)(this->value, this->id, this->type, cdata);
+ : if (*eltptr != elements)
+ : next = resources[i]; /* start over */
+ : }
+ : }
+ :}
+ :
+ :
+ :pointer
+ :LookupClientResourceComplex(
+ : ClientPtr client,
+ : RESTYPE type,
+ : FindComplexResType func,
+ : pointer cdata
+ :){
+ : ResourcePtr *resources;
+ : ResourcePtr this;
+ : int i;
+ :
+ : if (!client)
+ : client = serverClient;
+ :
+ : resources = clientTable[client->index].resources;
+ : for (i = 0; i < clientTable[client->index].buckets; i++) {
+ : for (this = resources[i]; this; this = this->next) {
+ : if (!type || this->type == type) {
+ : if((*func)(this->value, this->id, cdata))
+ : return this->value;
+ : }
+ : }
+ : }
+ : return NULL;
+ :}
+ :
+ :
+ :void
+ :FreeClientNeverRetainResources(ClientPtr client)
+ :{
+ : ResourcePtr *resources;
+ : ResourcePtr this;
+ : ResourcePtr *prev;
+ : int j;
+ :
+ : if (!client)
+ : return;
+ :
+ : resources = clientTable[client->index].resources;
+ : for (j=0; j < clientTable[client->index].buckets; j++)
+ : {
+ : prev = &resources[j];
+ : while ( (this = *prev) )
+ : {
+ : RESTYPE rtype = this->type;
+ : if (rtype & RC_NEVERRETAIN)
+ : {
+ :#ifdef XSERVER_DTRACE
+ : XSERVER_RESOURCE_FREE(this->id, this->type,
+ : this->value, TypeNameString(this->type));
+ :#endif
+ : *prev = this->next;
+ : if (rtype & RC_CACHED)
+ : FlushClientCaches(this->id);
+ : (*DeleteFuncs[rtype & TypeMask])(this->value, this->id);
+ : xfree(this);
+ : }
+ : else
+ : prev = &this->next;
+ : }
+ : }
+ :}
+ :
+ :void
+ :FreeClientResources(ClientPtr client)
+ :{
+ : ResourcePtr *resources;
+ : ResourcePtr this;
+ : int j;
+ :
+ : /* This routine shouldn't be called with a null client, but just in
+ : case ... */
+ :
+ : if (!client)
+ : return;
+ :
+ : HandleSaveSet(client);
+ :
+ : resources = clientTable[client->index].resources;
+ : for (j=0; j < clientTable[client->index].buckets; j++)
+ : {
+ : /* It may seem silly to update the head of this resource list as
+ : we delete the members, since the entire list will be deleted any way,
+ : but there are some resource deletion functions "FreeClientPixels" for
+ : one which do a LookupID on another resource id (a Colormap id in this
+ : case), so the resource list must be kept valid up to the point that
+ : it is deleted, so every time we delete a resource, we must update the
+ : head, just like in FreeResource. I hope that this doesn't slow down
+ : mass deletion appreciably. PRH */
+ :
+ : ResourcePtr *head;
+ :
+ : head = &resources[j];
+ :
+ : for (this = *head; this; this = *head)
+ : {
+ : RESTYPE rtype = this->type;
+ :#ifdef XSERVER_DTRACE
+ : XSERVER_RESOURCE_FREE(this->id, this->type,
+ : this->value, TypeNameString(this->type));
+ :#endif
+ : *head = this->next;
+ : if (rtype & RC_CACHED)
+ : FlushClientCaches(this->id);
+ : (*DeleteFuncs[rtype & TypeMask])(this->value, this->id);
+ : xfree(this);
+ : }
+ : }
+ : xfree(clientTable[client->index].resources);
+ : clientTable[client->index].resources = NULL;
+ : clientTable[client->index].buckets = 0;
+ :}
+ :
+ :void
+ :FreeAllResources(void)
+ :{
+ : int i;
+ :
+ : for (i = currentMaxClients; --i >= 0; )
+ : {
+ : if (clientTable[i].buckets)
+ : FreeClientResources(clients[i]);
+ : }
+ :}
+ :
+ :_X_EXPORT Bool
+ :LegalNewID(XID id, ClientPtr client)
+ 3 0.0033 :{ /* LegalNewID total: 7 0.0076 */
+ :
+ :#ifdef PANORAMIX
+ : XID minid, maxid;
+ :
+ 2 0.0022 : if (!noPanoramiXExtension) {
+ : minid = client->clientAsMask | (client->index ?
+ : SERVER_BIT : SERVER_MINID);
+ : maxid = (clientTable[client->index].fakeID | RESOURCE_ID_MASK) + 1;
+ : if ((id >= minid) && (id <= maxid))
+ : return TRUE;
+ : }
+ :#endif /* PANORAMIX */
+ 1 0.0011 : return ((client->clientAsMask == (id & ~RESOURCE_ID_MASK)) &&
+ : ((clientTable[client->index].expectID <= id) ||
+ : !LookupIDByClass(id, RC_ANY)));
+ 1 0.0011 :}
+ :
+ :/* SecurityLookupIDByType and SecurityLookupIDByClass:
+ : * These are the heart of the resource ID security system. They take
+ : * two additional arguments compared to the old LookupID functions:
+ : * the client doing the lookup, and the access mode (see resource.h).
+ : * The resource is returned if it exists and the client is allowed access,
+ : * else NULL is returned.
+ : */
+ :
+ :_X_EXPORT pointer
+ :SecurityLookupIDByType(ClientPtr client, XID id, RESTYPE rtype, Mask mode)
+ 8 0.0087 :{ /* SecurityLookupIDByType total: 40 0.0436 */
+ : int cid;
+ : ResourcePtr res;
+ : pointer retval = NULL;
+ :
+ 11 0.0120 : if (((cid = CLIENT_ID(id)) < MAXCLIENTS) &&
+ : clientTable[cid].buckets)
+ : {
+ 2 0.0022 : res = clientTable[cid].resources[Hash(cid, id)];
+ :
+ 6 0.0065 : for (; res; res = res->next)
+ 7 0.0076 : if ((res->id == id) && (res->type == rtype))
+ : {
+ 1 0.0011 : retval = res->value;
+ : break;
+ : }
+ : }
+ 4 0.0044 : if (retval && client &&
+ : !XaceHook(XACE_RESOURCE_ACCESS, client, id, rtype, mode, retval))
+ : retval = NULL;
+ :
+ : return retval;
+ 1 0.0011 :}
+ :
+ :
+ :_X_EXPORT pointer
+ :SecurityLookupIDByClass(ClientPtr client, XID id, RESTYPE classes, Mask mode)
+ 3 0.0033 :{ /* SecurityLookupIDByClass total: 8 0.0087 */
+ : int cid;
+ : ResourcePtr res = NULL;
+ : pointer retval = NULL;
+ :
+ 1 0.0011 : if (((cid = CLIENT_ID(id)) < MAXCLIENTS) &&
+ : clientTable[cid].buckets)
+ : {
+ : res = clientTable[cid].resources[Hash(cid, id)];
+ :
+ 1 0.0011 : for (; res; res = res->next)
+ 2 0.0022 : if ((res->id == id) && (res->type & classes))
+ : {
+ : retval = res->value;
+ : break;
+ : }
+ : }
+ : if (retval && client &&
+ : !XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type, mode, retval))
+ : retval = NULL;
+ :
+ : return retval;
+ 1 0.0011 :}
+ :
+ :/* We can't replace the LookupIDByType and LookupIDByClass functions with
+ : * macros because of compatibility with loadable servers.
+ : */
+ :
+ :_X_EXPORT pointer
+ :LookupIDByType(XID id, RESTYPE rtype)
+ :{
+ : return SecurityLookupIDByType(NullClient, id, rtype,
+ : DixUnknownAccess);
+ :}
+ :
+ :_X_EXPORT pointer
+ :LookupIDByClass(XID id, RESTYPE classes)
+ :{
+ : return SecurityLookupIDByClass(NullClient, id, classes,
+ : DixUnknownAccess);
+ :}
+/*
+ * Total samples for file : "xkbKillSrv.c"
+ *
+ * 111 0.1209
+ */
+
+<credited to line zero> 111 0.1209 :
+ /* __i686.get_pc_thunk.cx total: 2 0.0022 */
+ /* __i686.get_pc_thunk.bx total: 97 0.1057 */
+ /* __divdi3 total: 12 0.0131 */
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/exa/exa_accel.c"
+ *
+ * 109 0.1187
+ */
+
+
+ :/*
+ : * Copyright © 2001 Keith Packard
+ : *
+ : * Partly based on code that is Copyright © The XFree86 Project Inc.
+ : *
+ : * 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 Keith Packard not be used in
+ : * advertising or publicity pertaining to distribution of the software without
+ : * specific, written prior permission. Keith Packard makes no
+ : * representations about the suitability of this software for any purpose. It
+ : * is provided "as is" without express or implied warranty.
+ : *
+ : * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ : * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ : * EVENT SHALL KEITH PACKARD 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.
+ : *
+ : * Authors:
+ : * Eric Anholt <eric@anholt.net>
+ : * Michel Dänzer <michel@tungstengraphics.com>
+ : *
+ : */
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :#include "exa_priv.h"
+ :#include <X11/fonts/fontstruct.h>
+ :#include "dixfontstr.h"
+ :#include "exa.h"
+ :#include "cw.h"
+ :
+ :static void
+ :exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n,
+ : DDXPointPtr ppt, int *pwidth, int fSorted)
+ :{
+ : ScreenPtr pScreen = pDrawable->pScreen;
+ : ExaScreenPriv (pScreen);
+ : RegionPtr pClip = fbGetCompositeClip(pGC);
+ : PixmapPtr pPixmap;
+ : BoxPtr pextent, pbox;
+ : int nbox;
+ : int extentX1, extentX2, extentY1, extentY2;
+ : int fullX1, fullX2, fullY1;
+ : int partX1, partX2;
+ : int off_x, off_y;
+ : ExaMigrationRec pixmaps[1];
+ :
+ : pixmaps[0].as_dst = TRUE;
+ : pixmaps[0].as_src = FALSE;
+ : pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
+ :
+ : if (pExaScr->swappedOut ||
+ : pGC->fillStyle != FillSolid ||
+ : pPixmap->drawable.width > pExaScr->info->maxX ||
+ : pPixmap->drawable.height > pExaScr->info->maxY)
+ : {
+ : exaDoMigration (pixmaps, 1, FALSE);
+ : ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
+ : return;
+ : } else {
+ : exaDoMigration (pixmaps, 1, TRUE);
+ : }
+ :
+ : if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) ||
+ : !(*pExaScr->info->PrepareSolid) (pPixmap,
+ : pGC->alu,
+ : pGC->planemask,
+ : pGC->fgPixel))
+ : {
+ : exaDoMigration (pixmaps, 1, FALSE);
+ : ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
+ : return;
+ : }
+ :
+ : pextent = REGION_EXTENTS(pGC->pScreen, pClip);
+ : extentX1 = pextent->x1;
+ : extentY1 = pextent->y1;
+ : extentX2 = pextent->x2;
+ : extentY2 = pextent->y2;
+ : while (n--)
+ : {
+ : fullX1 = ppt->x;
+ : fullY1 = ppt->y;
+ : fullX2 = fullX1 + (int) *pwidth;
+ : ppt++;
+ : pwidth++;
+ :
+ : if (fullY1 < extentY1 || extentY2 <= fullY1)
+ : continue;
+ :
+ : if (fullX1 < extentX1)
+ : fullX1 = extentX1;
+ :
+ : if (fullX2 > extentX2)
+ : fullX2 = extentX2;
+ :
+ : if (fullX1 >= fullX2)
+ : continue;
+ :
+ : nbox = REGION_NUM_RECTS (pClip);
+ : if (nbox == 1)
+ : {
+ : (*pExaScr->info->Solid) (pPixmap,
+ : fullX1 + off_x, fullY1 + off_y,
+ : fullX2 + off_x, fullY1 + 1 + off_y);
+ : }
+ : else
+ : {
+ : pbox = REGION_RECTS(pClip);
+ : while(nbox--)
+ : {
+ : if (pbox->y1 <= fullY1 && fullY1 < pbox->y2)
+ : {
+ : partX1 = pbox->x1;
+ : if (partX1 < fullX1)
+ : partX1 = fullX1;
+ : partX2 = pbox->x2;
+ : if (partX2 > fullX2)
+ : partX2 = fullX2;
+ : if (partX2 > partX1) {
+ : (*pExaScr->info->Solid) (pPixmap,
+ : partX1 + off_x, fullY1 + off_y,
+ : partX2 + off_x, fullY1 + 1 + off_y);
+ : }
+ : }
+ : pbox++;
+ : }
+ : }
+ : }
+ : (*pExaScr->info->DoneSolid) (pPixmap);
+ : exaMarkSync(pScreen);
+ :}
+ :
+ :static void
+ :exaPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
+ : int w, int h, int leftPad, int format, char *bits)
+ :{
+ : ExaScreenPriv (pDrawable->pScreen);
+ : PixmapPtr pPix;
+ : ExaMigrationRec pixmaps[1];
+ : RegionPtr pClip;
+ : BoxPtr pbox;
+ : int nbox;
+ : int xoff, yoff;
+ : int src_stride, bpp = pDrawable->bitsPerPixel;
+ :
+ : pixmaps[0].as_dst = TRUE;
+ : pixmaps[0].as_src = FALSE;
+ : pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
+ :
+ : /* Don't bother with under 8bpp, XYPixmaps. */
+ : if (format != ZPixmap || bpp < 8)
+ : goto migrate_and_fallback;
+ :
+ : /* Only accelerate copies: no rop or planemask. */
+ : if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy)
+ : goto migrate_and_fallback;
+ :
+ : if (pExaScr->swappedOut)
+ : goto fallback;
+ :
+ : exaDoMigration (pixmaps, 1, TRUE);
+ :
+ : if (pExaScr->info->UploadToScreen == NULL)
+ : goto fallback;
+ :
+ : pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
+ :
+ : if (pPix == NULL)
+ : goto fallback;
+ :
+ : x += pDrawable->x;
+ : y += pDrawable->y;
+ :
+ : pClip = fbGetCompositeClip(pGC);
+ : src_stride = PixmapBytePad(w, pDrawable->depth);
+ : for (nbox = REGION_NUM_RECTS(pClip),
+ : pbox = REGION_RECTS(pClip);
+ : nbox--;
+ : pbox++)
+ : {
+ : int x1 = x;
+ : int y1 = y;
+ : int x2 = x + w;
+ : int y2 = y + h;
+ : char *src;
+ : Bool ok;
+ :
+ : if (x1 < pbox->x1)
+ : x1 = pbox->x1;
+ : if (y1 < pbox->y1)
+ : y1 = pbox->y1;
+ : if (x2 > pbox->x2)
+ : x2 = pbox->x2;
+ : if (y2 > pbox->y2)
+ : y2 = pbox->y2;
+ : if (x1 >= x2 || y1 >= y2)
+ : continue;
+ :
+ : src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8);
+ : ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff,
+ : x2 - x1, y2 - y1, src, src_stride);
+ : /* If we fail to accelerate the upload, fall back to using unaccelerated
+ : * fb calls.
+ : */
+ : if (!ok) {
+ : FbStip *dst;
+ : FbStride dst_stride;
+ : int dstBpp;
+ : int dstXoff, dstYoff;
+ :
+ : exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
+ :
+ : fbGetStipDrawable(pDrawable, dst, dst_stride, dstBpp,
+ : dstXoff, dstYoff);
+ :
+ : fbBltStip((FbStip *)bits + (y1 - y) * (src_stride / sizeof(FbStip)),
+ : src_stride / sizeof(FbStip),
+ : (x1 - x) * dstBpp,
+ : dst + (y1 + dstYoff) * dst_stride,
+ : dst_stride,
+ : (x1 + dstXoff) * dstBpp,
+ : (x2 - x1) * dstBpp,
+ : y2 - y1,
+ : GXcopy, FB_ALLONES, dstBpp);
+ :
+ : exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
+ : }
+ :
+ : exaPixmapDirty(pPix, x1 + xoff, y1 + yoff, x2 + xoff, y2 + yoff);
+ : }
+ :
+ : return;
+ :
+ :migrate_and_fallback:
+ : exaDoMigration (pixmaps, 1, FALSE);
+ :
+ :fallback:
+ : ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits);
+ :}
+ :
+ :static Bool inline
+ :exaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
+ : GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy)
+ :{
+ : ExaScreenPriv (pDstDrawable->pScreen);
+ : PixmapPtr pSrcPixmap, pDstPixmap;
+ : int src_off_x, src_off_y, dst_off_x, dst_off_y;
+ : int dirsetup;
+ :
+ : /* Need to get both pixmaps to call the driver routines */
+ : pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y);
+ : pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y);
+ : if (!pSrcPixmap || !pDstPixmap)
+ : return FALSE;
+ :
+ : /*
+ : * Now the case of a chip that only supports xdir = ydir = 1 or
+ : * xdir = ydir = -1, but we have xdir != ydir.
+ : */
+ : dirsetup = 0; /* No direction set up yet. */
+ : for (; nbox; pbox++, nbox--) {
+ : if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
+ : /* Do a xdir = ydir = -1 blit instead. */
+ : if (dirsetup != -1) {
+ : if (dirsetup != 0)
+ : pExaScr->info->DoneCopy(pDstPixmap);
+ : dirsetup = -1;
+ : if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
+ : pDstPixmap,
+ : -1, -1,
+ : pGC ? pGC->alu : GXcopy,
+ : pGC ? pGC->planemask :
+ : FB_ALLONES))
+ : return FALSE;
+ : }
+ : (*pExaScr->info->Copy)(pDstPixmap,
+ : src_off_x + pbox->x1 + dx,
+ : src_off_y + pbox->y1 + dy,
+ : dst_off_x + pbox->x1,
+ : dst_off_y + pbox->y1,
+ : pbox->x2 - pbox->x1,
+ : pbox->y2 - pbox->y1);
+ : } else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
+ : /* Do a xdir = ydir = 1 blit instead. */
+ : if (dirsetup != 1) {
+ : if (dirsetup != 0)
+ : pExaScr->info->DoneCopy(pDstPixmap);
+ : dirsetup = 1;
+ : if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
+ : pDstPixmap,
+ : 1, 1,
+ : pGC ? pGC->alu : GXcopy,
+ : pGC ? pGC->planemask :
+ : FB_ALLONES))
+ : return FALSE;
+ : }
+ : (*pExaScr->info->Copy)(pDstPixmap,
+ : src_off_x + pbox->x1 + dx,
+ : src_off_y + pbox->y1 + dy,
+ : dst_off_x + pbox->x1,
+ : dst_off_y + pbox->y1,
+ : pbox->x2 - pbox->x1,
+ : pbox->y2 - pbox->y1);
+ : } else if (dx >= 0) {
+ : /*
+ : * xdir = 1, ydir = -1.
+ : * Perform line-by-line xdir = ydir = 1 blits, going up.
+ : */
+ : int i;
+ : if (dirsetup != 1) {
+ : if (dirsetup != 0)
+ : pExaScr->info->DoneCopy(pDstPixmap);
+ : dirsetup = 1;
+ : if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
+ : pDstPixmap,
+ : 1, 1,
+ : pGC ? pGC->alu : GXcopy,
+ : pGC ? pGC->planemask :
+ : FB_ALLONES))
+ : return FALSE;
+ : }
+ : for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--)
+ : (*pExaScr->info->Copy)(pDstPixmap,
+ : src_off_x + pbox->x1 + dx,
+ : src_off_y + pbox->y1 + dy + i,
+ : dst_off_x + pbox->x1,
+ : dst_off_y + pbox->y1 + i,
+ : pbox->x2 - pbox->x1, 1);
+ : } else {
+ : /*
+ : * xdir = -1, ydir = 1.
+ : * Perform line-by-line xdir = ydir = -1 blits, going down.
+ : */
+ : int i;
+ : if (dirsetup != -1) {
+ : if (dirsetup != 0)
+ : pExaScr->info->DoneCopy(pDstPixmap);
+ : dirsetup = -1;
+ : if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
+ : pDstPixmap,
+ : -1, -1,
+ : pGC ? pGC->alu : GXcopy,
+ : pGC ? pGC->planemask :
+ : FB_ALLONES))
+ : return FALSE;
+ : }
+ : for (i = 0; i < pbox->y2 - pbox->y1; i++)
+ : (*pExaScr->info->Copy)(pDstPixmap,
+ : src_off_x + pbox->x1 + dx,
+ : src_off_y + pbox->y1 + dy + i,
+ : dst_off_x + pbox->x1,
+ : dst_off_y + pbox->y1 + i,
+ : pbox->x2 - pbox->x1, 1);
+ : }
+ : exaPixmapDirty(pDstPixmap, dst_off_x + pbox->x1, dst_off_y + pbox->y1,
+ : dst_off_x + pbox->x2, dst_off_y + pbox->y2);
+ : }
+ : if (dirsetup != 0)
+ : pExaScr->info->DoneCopy(pDstPixmap);
+ : exaMarkSync(pDstDrawable->pScreen);
+ : return TRUE;
+ :}
+ :
+ :void
+ :exaCopyNtoN (DrawablePtr pSrcDrawable,
+ : DrawablePtr pDstDrawable,
+ : GCPtr pGC,
+ : BoxPtr pbox,
+ : int nbox,
+ : int dx,
+ : int dy,
+ : Bool reverse,
+ : Bool upsidedown,
+ : Pixel bitplane,
+ : void *closure)
+ 3 0.0033 :{ /* exaCopyNtoN total: 47 0.0512 */
+ 6 0.0065 : ExaScreenPriv (pDstDrawable->pScreen);
+ : PixmapPtr pSrcPixmap, pDstPixmap;
+ : int src_off_x, src_off_y;
+ : int dst_off_x, dst_off_y;
+ : ExaMigrationRec pixmaps[2];
+ : Bool fallback = FALSE;
+ :
+ : pixmaps[0].as_dst = TRUE;
+ : pixmaps[0].as_src = FALSE;
+ 5 0.0054 : pixmaps[0].pPix = pDstPixmap = exaGetDrawablePixmap (pDstDrawable);
+ 3 0.0033 : pixmaps[1].as_dst = FALSE;
+ 1 0.0011 : pixmaps[1].as_src = TRUE;
+ 7 0.0076 : pixmaps[1].pPix = pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable);
+ :
+ : /* Respect maxX/maxY in a trivial way: don't set up drawing when we might
+ : * violate the limits. The proper solution would be a temporary pixmap
+ : * adjusted so that the drawing happened within limits.
+ : */
+ 11 0.0120 : if (pSrcPixmap->drawable.width > pExaScr->info->maxX ||
+ : pSrcPixmap->drawable.height > pExaScr->info->maxY ||
+ : pDstPixmap->drawable.width > pExaScr->info->maxX ||
+ : pDstPixmap->drawable.height > pExaScr->info->maxY)
+ : {
+ : fallback = TRUE;
+ : } else {
+ 1 0.0011 : exaDoMigration (pixmaps, 2, TRUE);
+ : }
+ :
+ : /* Mixed directions must be handled specially if the card is lame */
+ 2 0.0022 : if (!fallback && (pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) &&
+ : reverse != upsidedown) {
+ : if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
+ : dx, dy))
+ : return;
+ : fallback = TRUE;
+ : }
+ :
+ 2 0.0022 : pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable);
+ : pDstPixmap = exaGetDrawablePixmap (pDstDrawable);
+ :
+ : exaGetDrawableDeltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y);
+ 4 0.0044 : exaGetDrawableDeltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y);
+ :
+ : if (fallback || !exaPixmapIsOffscreen(pSrcPixmap) ||
+ : !exaPixmapIsOffscreen(pDstPixmap) ||
+ : !(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1,
+ : upsidedown ? -1 : 1,
+ : pGC ? pGC->alu : GXcopy,
+ : pGC ? pGC->planemask : FB_ALLONES)) {
+ : fallback = TRUE;
+ : return;
+ : EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable,
+ : exaDrawableLocation(pSrcDrawable),
+ : exaDrawableLocation(pDstDrawable)));
+ : exaDoMigration (pixmaps, 2, FALSE);
+ : exaPrepareAccess (pDstDrawable, EXA_PREPARE_DEST);
+ : exaPrepareAccess (pSrcDrawable, EXA_PREPARE_SRC);
+ : fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC,
+ : pbox, nbox, dx, dy, reverse, upsidedown,
+ : bitplane, closure);
+ : exaFinishAccess (pSrcDrawable, EXA_PREPARE_SRC);
+ : exaFinishAccess (pDstDrawable, EXA_PREPARE_DEST);
+ : }
+ :
+ : while (nbox--)
+ : {
+ : if (!fallback)
+ : (*pExaScr->info->Copy) (pDstPixmap,
+ : pbox->x1 + dx + src_off_x,
+ : pbox->y1 + dy + src_off_y,
+ : pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
+ : pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
+ : exaPixmapDirty (pDstPixmap, pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
+ : pbox->x2 + dst_off_x, pbox->y2 + dst_off_y);
+ : pbox++;
+ : }
+ :
+ : if (fallback)
+ : return;
+ :
+ : (*pExaScr->info->DoneCopy) (pDstPixmap);
+ : exaMarkSync (pDstDrawable->pScreen);
+ 2 0.0022 :}
+ :
+ :RegionPtr
+ :exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
+ : int srcx, int srcy, int width, int height, int dstx, int dsty)
+ 5 0.0054 :{ /* exaCopyArea total: 33 0.0359 */
+ : ExaScreenPriv (pDstDrawable->pScreen);
+ :
+ 9 0.0098 : if (pExaScr->swappedOut) {
+ : return ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC,
+ : srcx, srcy, width, height, dstx, dsty);
+ : }
+ :
+ 14 0.0153 : return fbDoCopy (pSrcDrawable, pDstDrawable, pGC,
+ : srcx, srcy, width, height,
+ : dstx, dsty, exaCopyNtoN, 0, NULL);
+ 5 0.0054 :}
+ :
+ :static void
+ :exaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ : DDXPointPtr ppt)
+ :{
+ : int i;
+ : xRectangle *prect;
+ :
+ : /* If we can't reuse the current GC as is, don't bother accelerating the
+ : * points.
+ : */
+ : if (pGC->fillStyle != FillSolid) {
+ : ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt);
+ : return;
+ : }
+ :
+ : prect = ALLOCATE_LOCAL(sizeof(xRectangle) * npt);
+ : for (i = 0; i < npt; i++) {
+ : prect[i].x = ppt[i].x;
+ : prect[i].y = ppt[i].y;
+ : if (i > 0 && mode == CoordModePrevious) {
+ : prect[i].x += prect[i - 1].x;
+ : prect[i].y += prect[i - 1].y;
+ : }
+ : prect[i].width = 1;
+ : prect[i].height = 1;
+ : }
+ : pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect);
+ : DEALLOCATE_LOCAL(prect);
+ :}
+ :
+ :/**
+ : * exaPolylines() checks if it can accelerate the lines as a group of
+ : * horizontal or vertical lines (rectangles), and uses existing rectangle fill
+ : * acceleration if so.
+ : */
+ :static void
+ :exaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ : DDXPointPtr ppt)
+ :{
+ : xRectangle *prect;
+ : int x1, x2, y1, y2;
+ : int i;
+ :
+ : /* Don't try to do wide lines or non-solid fill style. */
+ : if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
+ : pGC->fillStyle != FillSolid) {
+ : ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
+ : return;
+ : }
+ :
+ : prect = ALLOCATE_LOCAL(sizeof(xRectangle) * (npt - 1));
+ : x1 = ppt[0].x;
+ : y1 = ppt[0].y;
+ : /* If we have any non-horizontal/vertical, fall back. */
+ : for (i = 0; i < npt; i++) {
+ : if (mode == CoordModePrevious) {
+ : x2 = x1 + ppt[i + 1].x;
+ : y2 = y1 + ppt[i + 1].y;
+ : } else {
+ : x2 = ppt[i + 1].x;
+ : y2 = ppt[i + 1].y;
+ : }
+ :
+ : if (x1 != x2 && y1 != y2) {
+ : DEALLOCATE_LOCAL(prect);
+ : ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
+ : return;
+ : }
+ :
+ : if (x1 < x2) {
+ : prect[i].x = x1;
+ : prect[i].width = x2 - x1 + 1;
+ : } else {
+ : prect[i].x = x2;
+ : prect[i].width = x1 - x2 + 1;
+ : }
+ : if (y1 < y2) {
+ : prect[i].y = y1;
+ : prect[i].height = y2 - y1 + 1;
+ : } else {
+ : prect[i].y = y2;
+ : prect[i].height = y1 - y2 + 1;
+ : }
+ :
+ : x1 = x2;
+ : y1 = y2;
+ : }
+ : pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect);
+ : DEALLOCATE_LOCAL(prect);
+ :}
+ :
+ :/**
+ : * exaPolySegment() checks if it can accelerate the lines as a group of
+ : * horizontal or vertical lines (rectangles), and uses existing rectangle fill
+ : * acceleration if so.
+ : */
+ :static void
+ :exaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg,
+ : xSegment *pSeg)
+ 1 0.0011 :{ /* exaPolySegment total: 3 0.0033 */
+ : xRectangle *prect;
+ : int i;
+ :
+ : /* Don't try to do wide lines or non-solid fill style. */
+ : if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
+ : pGC->fillStyle != FillSolid)
+ : {
+ : ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
+ : return;
+ : }
+ :
+ : /* If we have any non-horizontal/vertical, fall back. */
+ : for (i = 0; i < nseg; i++) {
+ : if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) {
+ : ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
+ : return;
+ : }
+ : }
+ :
+ 1 0.0011 : prect = ALLOCATE_LOCAL(sizeof(xRectangle) * nseg);
+ : for (i = 0; i < nseg; i++) {
+ : if (pSeg[i].x1 < pSeg[i].x2) {
+ : prect[i].x = pSeg[i].x1;
+ : prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1;
+ : } else {
+ : prect[i].x = pSeg[i].x2;
+ : prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1;
+ : }
+ : if (pSeg[i].y1 < pSeg[i].y2) {
+ : prect[i].y = pSeg[i].y1;
+ : prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1;
+ : } else {
+ : prect[i].y = pSeg[i].y2;
+ 1 0.0011 : prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1;
+ : }
+ : }
+ : pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect);
+ : DEALLOCATE_LOCAL(prect);
+ :}
+ :
+ :static Bool exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion,
+ : Pixel pixel, CARD32 planemask, CARD32 alu);
+ :
+ :static void
+ :exaPolyFillRect(DrawablePtr pDrawable,
+ : GCPtr pGC,
+ : int nrect,
+ : xRectangle *prect)
+ 1 0.0011 :{ /* exaPolyFillRect total: 19 0.0207 */
+ 1 0.0011 : ExaScreenPriv (pDrawable->pScreen);
+ : RegionPtr pClip = fbGetCompositeClip(pGC);
+ : PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
+ : register BoxPtr pbox;
+ : BoxPtr pextent;
+ : int extentX1, extentX2, extentY1, extentY2;
+ : int fullX1, fullX2, fullY1, fullY2;
+ : int partX1, partX2, partY1, partY2;
+ : int xoff, yoff;
+ : int xorg, yorg;
+ : int n;
+ : ExaMigrationRec pixmaps[2];
+ : RegionPtr pReg = RECTS_TO_REGION(pScreen, nrect, prect, CT_UNSORTED);
+ :
+ : /* Compute intersection of rects and clip region */
+ 1 0.0011 : REGION_TRANSLATE(pScreen, pReg, pDrawable->x, pDrawable->y);
+ : REGION_INTERSECT(pScreen, pReg, pClip, pReg);
+ :
+ : if (!REGION_NUM_RECTS(pReg)) {
+ : goto out;
+ : }
+ :
+ : pixmaps[0].as_dst = TRUE;
+ : pixmaps[0].as_src = FALSE;
+ : pixmaps[0].pPix = pPixmap;
+ :
+ 4 0.0044 : exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
+ :
+ 4 0.0044 : if (pExaScr->swappedOut ||
+ : pPixmap->drawable.width > pExaScr->info->maxX ||
+ : pPixmap->drawable.height > pExaScr->info->maxY)
+ : {
+ : goto fallback;
+ : }
+ :
+ : /* For ROPs where overlaps don't matter, convert rectangles to region and
+ : * call exaFillRegion{Solid,Tiled}.
+ : */
+ 2 0.0022 : if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) &&
+ : (pGC->alu == GXcopy || pGC->alu == GXclear || pGC->alu == GXnoop ||
+ : pGC->alu == GXcopyInverted || pGC->alu == GXset)) {
+ 6 0.0065 : if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) &&
+ : exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ?
+ : pGC->fgPixel : pGC->tile.pixel, pGC->planemask,
+ : pGC->alu)) ||
+ : (pGC->fillStyle == FillTiled && !pGC->tileIsPixel &&
+ : exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg,
+ : pGC->planemask, pGC->alu))) {
+ : goto out;
+ : }
+ : }
+ :
+ : if (pGC->fillStyle != FillSolid &&
+ : !(pGC->tileIsPixel && pGC->fillStyle == FillTiled))
+ : {
+ : goto fallback;
+ : }
+ :
+ : exaDoMigration (pixmaps, 1, TRUE);
+ :
+ : if (!exaPixmapIsOffscreen (pPixmap) ||
+ : !(*pExaScr->info->PrepareSolid) (pPixmap,
+ : pGC->alu,
+ : pGC->planemask,
+ : pGC->fgPixel))
+ : {
+ :fallback:
+ : if (pGC->fillStyle == FillTiled && !pGC->tileIsPixel) {
+ : pixmaps[1].as_dst = FALSE;
+ : pixmaps[1].as_src = TRUE;
+ : pixmaps[1].pPix = pGC->tile.pixmap;
+ : exaDoMigration (pixmaps, 2, FALSE);
+ : } else {
+ : exaDoMigration (pixmaps, 1, FALSE);
+ : }
+ :
+ : ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect);
+ : goto out;
+ : }
+ :
+ : xorg = pDrawable->x;
+ : yorg = pDrawable->y;
+ :
+ : pextent = REGION_EXTENTS(pGC->pScreen, pClip);
+ : extentX1 = pextent->x1;
+ : extentY1 = pextent->y1;
+ : extentX2 = pextent->x2;
+ : extentY2 = pextent->y2;
+ : while (nrect--)
+ : {
+ : fullX1 = prect->x + xorg;
+ : fullY1 = prect->y + yorg;
+ : fullX2 = fullX1 + (int) prect->width;
+ : fullY2 = fullY1 + (int) prect->height;
+ : prect++;
+ :
+ : if (fullX1 < extentX1)
+ : fullX1 = extentX1;
+ :
+ : if (fullY1 < extentY1)
+ : fullY1 = extentY1;
+ :
+ : if (fullX2 > extentX2)
+ : fullX2 = extentX2;
+ :
+ : if (fullY2 > extentY2)
+ : fullY2 = extentY2;
+ :
+ : if ((fullX1 >= fullX2) || (fullY1 >= fullY2))
+ : continue;
+ : n = REGION_NUM_RECTS (pClip);
+ : if (n == 1)
+ : {
+ : (*pExaScr->info->Solid) (pPixmap,
+ : fullX1 + xoff, fullY1 + yoff,
+ : fullX2 + xoff, fullY2 + yoff);
+ : }
+ : else
+ : {
+ : pbox = REGION_RECTS(pClip);
+ : /*
+ : * clip the rectangle to each box in the clip region
+ : * this is logically equivalent to calling Intersect(),
+ : * but rectangles may overlap each other here.
+ : */
+ : while(n--)
+ : {
+ : partX1 = pbox->x1;
+ : if (partX1 < fullX1)
+ : partX1 = fullX1;
+ : partY1 = pbox->y1;
+ : if (partY1 < fullY1)
+ : partY1 = fullY1;
+ : partX2 = pbox->x2;
+ : if (partX2 > fullX2)
+ : partX2 = fullX2;
+ : partY2 = pbox->y2;
+ : if (partY2 > fullY2)
+ : partY2 = fullY2;
+ :
+ : pbox++;
+ :
+ : if (partX1 < partX2 && partY1 < partY2) {
+ : (*pExaScr->info->Solid) (pPixmap,
+ : partX1 + xoff, partY1 + yoff,
+ : partX2 + xoff, partY2 + yoff);
+ : }
+ : }
+ : }
+ : }
+ : (*pExaScr->info->DoneSolid) (pPixmap);
+ : exaMarkSync(pDrawable->pScreen);
+ :
+ :out:
+ : REGION_DESTROY(pScreen, pReg);
+ :}
+ :
+ :static void
+ :exaSolidBoxClipped (DrawablePtr pDrawable,
+ : RegionPtr pClip,
+ : FbBits pm,
+ : FbBits fg,
+ : int x1,
+ : int y1,
+ : int x2,
+ : int y2)
+ :{
+ : ExaScreenPriv (pDrawable->pScreen);
+ : PixmapPtr pPixmap;
+ : BoxPtr pbox;
+ : int nbox;
+ : int xoff, yoff;
+ : int partX1, partX2, partY1, partY2;
+ : ExaMigrationRec pixmaps[1];
+ : Bool fallback = FALSE;
+ :
+ : pixmaps[0].as_dst = TRUE;
+ : pixmaps[0].as_src = FALSE;
+ : pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
+ :
+ : if (pExaScr->swappedOut ||
+ : pPixmap->drawable.width > pExaScr->info->maxX ||
+ : pPixmap->drawable.height > pExaScr->info->maxY)
+ : {
+ : fallback = TRUE;
+ : } else {
+ : exaDoMigration (pixmaps, 1, TRUE);
+ : }
+ :
+ : exaGetDrawableDeltas (pDrawable, pPixmap, &xoff, &yoff);
+ :
+ : if (fallback || !exaPixmapIsOffscreen(pPixmap) ||
+ : !(*pExaScr->info->PrepareSolid) (pPixmap, GXcopy, pm, fg))
+ : {
+ : EXA_FALLBACK(("to %p (%c)\n", pDrawable,
+ : exaDrawableLocation(pDrawable)));
+ : exaDoMigration (pixmaps, 1, FALSE);
+ : fallback = TRUE;
+ : exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
+ : fg = fbReplicatePixel (fg, pDrawable->bitsPerPixel);
+ : fbSolidBoxClipped (pDrawable, pClip, x1, y1, x2, y2,
+ : fbAnd (GXcopy, fg, pm),
+ : fbXor (GXcopy, fg, pm));
+ : exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
+ : }
+ : for (nbox = REGION_NUM_RECTS(pClip), pbox = REGION_RECTS(pClip);
+ : nbox--;
+ : pbox++)
+ : {
+ : partX1 = pbox->x1;
+ : if (partX1 < x1)
+ : partX1 = x1;
+ :
+ : partX2 = pbox->x2;
+ : if (partX2 > x2)
+ : partX2 = x2;
+ :
+ : if (partX2 <= partX1)
+ : continue;
+ :
+ : partY1 = pbox->y1;
+ : if (partY1 < y1)
+ : partY1 = y1;
+ :
+ : partY2 = pbox->y2;
+ : if (partY2 > y2)
+ : partY2 = y2;
+ :
+ : if (partY2 <= partY1)
+ : continue;
+ :
+ : if (!fallback) {
+ : (*pExaScr->info->Solid) (pPixmap,
+ : partX1 + xoff, partY1 + yoff,
+ : partX2 + xoff, partY2 + yoff);
+ : }
+ :
+ : exaPixmapDirty (pPixmap, partX1 + xoff, partY1 + yoff, partX2 + xoff,
+ : partY2 + yoff);
+ : }
+ :
+ : if (fallback)
+ : return;
+ :
+ : (*pExaScr->info->DoneSolid) (pPixmap);
+ : exaMarkSync(pDrawable->pScreen);
+ :}
+ :
+ :static void
+ :exaImageGlyphBlt (DrawablePtr pDrawable,
+ : GCPtr pGC,
+ : int x,
+ : int y,
+ : unsigned int nglyph,
+ : CharInfoPtr *ppciInit,
+ : pointer pglyphBase)
+ :{
+ : FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
+ : CharInfoPtr *ppci;
+ : CharInfoPtr pci;
+ : unsigned char *pglyph; /* pointer bits in glyph */
+ : int gWidth, gHeight; /* width and height of glyph */
+ : FbStride gStride; /* stride of glyph */
+ : Bool opaque;
+ : int n;
+ : int gx, gy;
+ : void (*glyph) (FbBits *,
+ : FbStride,
+ : int,
+ : FbStip *,
+ : FbBits,
+ : int,
+ : int);
+ : FbBits *dst;
+ : FbStride dstStride;
+ : int dstBpp;
+ : int dstXoff, dstYoff;
+ : FbBits depthMask;
+ : PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
+ : ExaMigrationRec pixmaps[1];
+ : int xBack, widthBack, yBack, heightBack;
+ :
+ : for (ppci = ppciInit, n = nglyph, widthBack = 0; n; n--)
+ : widthBack += (*ppci++)->metrics.characterWidth;
+ :
+ : xBack = x;
+ : if (widthBack < 0)
+ : {
+ : xBack += widthBack;
+ : widthBack = -widthBack;
+ : }
+ : yBack = y - FONTASCENT(pGC->font);
+ : heightBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font);
+ :
+ : if (xBack >= pDrawable->width || yBack >= pDrawable->height ||
+ : (xBack + widthBack) <= 0 || (yBack + heightBack) <= 0)
+ : return;
+ :
+ : pixmaps[0].as_dst = TRUE;
+ : pixmaps[0].as_src = TRUE;
+ : pixmaps[0].pPix = pPixmap;
+ :
+ : depthMask = FbFullMask(pDrawable->depth);
+ : if ((pGC->planemask & depthMask) != depthMask)
+ : {
+ : exaDoMigration(pixmaps, 1, FALSE);
+ : ExaCheckImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppciInit, pglyphBase);
+ : goto damage;
+ : }
+ : glyph = NULL;
+ : switch (pDrawable->bitsPerPixel) {
+ : case 8: glyph = fbGlyph8; break;
+ : case 16: glyph = fbGlyph16; break;
+ : case 24: glyph = fbGlyph24; break;
+ : case 32: glyph = fbGlyph32; break;
+ : }
+ :
+ : x += pDrawable->x;
+ : y += pDrawable->y;
+ : xBack += pDrawable->x;
+ : yBack += pDrawable->y;
+ :
+ : if (TERMINALFONT (pGC->font) && !glyph)
+ : {
+ : opaque = TRUE;
+ : }
+ : else
+ : {
+ : exaSolidBoxClipped (pDrawable,
+ : fbGetCompositeClip(pGC),
+ : pGC->planemask,
+ : pGC->bgPixel,
+ : xBack,
+ : yBack,
+ : xBack + widthBack,
+ : yBack + heightBack);
+ : opaque = FALSE;
+ : }
+ :
+ : EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
+ : exaDoMigration(pixmaps, 1, FALSE);
+ : exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
+ : exaPrepareAccessGC (pGC);
+ :
+ : fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
+ :
+ : for (ppci = ppciInit; nglyph; nglyph--, x += pci->metrics.characterWidth)
+ : {
+ : pci = *ppci++;
+ : gWidth = GLYPHWIDTHPIXELS(pci);
+ : gHeight = GLYPHHEIGHTPIXELS(pci);
+ : gx = x + pci->metrics.leftSideBearing;
+ : gy = y - pci->metrics.ascent;
+ :
+ : if (!gWidth || !gHeight || (gx + gWidth) <= xBack ||
+ : (gy + gHeight) <= yBack || gx >= (xBack + widthBack) ||
+ : gy >= (yBack + heightBack))
+ : continue;
+ :
+ : pglyph = FONTGLYPHBITS(pglyphBase, pci);
+ :
+ : if (glyph && gWidth <= sizeof (FbStip) * 8 &&
+ : fbGlyphIn (fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight))
+ : {
+ : (*glyph) (dst + (gy + dstYoff) * dstStride, dstStride, dstBpp,
+ : (FbStip *) pglyph, pPriv->fg, gx + dstXoff, gHeight);
+ : }
+ : else
+ : {
+ : RegionPtr pClip = fbGetCompositeClip(pGC);
+ :
+ : gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof (FbStip);
+ : fbPutXYImage (pDrawable, pClip, pPriv->fg, pPriv->bg, pPriv->pm,
+ : GXcopy, opaque, gx, gy, gWidth, gHeight,
+ : (FbStip *) pglyph, gStride, 0);
+ : }
+ : }
+ : exaFinishAccessGC (pGC);
+ : exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
+ :
+ :damage:
+ : exaGetDrawableDeltas(pDrawable, pPixmap, &dstXoff, &dstYoff);
+ : exaPixmapDirty(pPixmap, xBack + dstXoff, yBack + dstYoff,
+ : xBack + dstXoff + widthBack, yBack + dstYoff + heightBack);
+ :}
+ :
+ :const GCOps exaOps = {
+ : exaFillSpans,
+ : ExaCheckSetSpans,
+ : exaPutImage,
+ : exaCopyArea,
+ : ExaCheckCopyPlane,
+ : exaPolyPoint,
+ : exaPolylines,
+ : exaPolySegment,
+ : miPolyRectangle,
+ : ExaCheckPolyArc,
+ : miFillPolygon,
+ : exaPolyFillRect,
+ : miPolyFillArc,
+ : miPolyText8,
+ : miPolyText16,
+ : miImageText8,
+ : miImageText16,
+ : exaImageGlyphBlt,
+ : ExaCheckPolyGlyphBlt,
+ : ExaCheckPushPixels,
+ :};
+ :
+ :void
+ :exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
+ :{
+ : RegionRec rgnDst;
+ : int dx, dy;
+ : PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
+ :
+ : dx = ptOldOrg.x - pWin->drawable.x;
+ : dy = ptOldOrg.y - pWin->drawable.y;
+ : REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy);
+ :
+ : REGION_INIT (pWin->drawable.pScreen, &rgnDst, NullBox, 0);
+ :
+ : REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip, prgnSrc);
+ :#ifdef COMPOSITE
+ : if (pPixmap->screen_x || pPixmap->screen_y)
+ : REGION_TRANSLATE (pWin->drawable.pScreen, &rgnDst,
+ : -pPixmap->screen_x, -pPixmap->screen_y);
+ :#endif
+ :
+ : fbCopyRegion (&pPixmap->drawable, &pPixmap->drawable,
+ : NULL,
+ : &rgnDst, dx, dy, exaCopyNtoN, 0, NULL);
+ :
+ : REGION_UNINIT(pWin->drawable.pScreen, &rgnDst);
+ :}
+ :
+ :static Bool
+ :exaFillRegionSolid (DrawablePtr pDrawable,
+ : RegionPtr pRegion,
+ : Pixel pixel,
+ : CARD32 planemask,
+ : CARD32 alu)
+ 2 0.0022 :{ /* exaFillRegionSolid total: 7 0.0076 */
+ : ExaScreenPriv(pDrawable->pScreen);
+ : PixmapPtr pPixmap;
+ : int xoff, yoff;
+ : ExaMigrationRec pixmaps[1];
+ : int nbox = REGION_NUM_RECTS (pRegion);
+ : BoxPtr pBox = REGION_RECTS (pRegion);
+ :
+ : pixmaps[0].as_dst = TRUE;
+ : pixmaps[0].as_src = FALSE;
+ 1 0.0011 : pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
+ :
+ 1 0.0011 : if (pPixmap->drawable.width > pExaScr->info->maxX ||
+ : pPixmap->drawable.height > pExaScr->info->maxY)
+ : {
+ : goto fallback;
+ : } else {
+ : exaDoMigration (pixmaps, 1, TRUE);
+ : }
+ :
+ 2 0.0022 : if ((pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) &&
+ : (*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel))
+ : {
+ : while (nbox--)
+ : {
+ : (*pExaScr->info->Solid) (pPixmap,
+ : pBox->x1 + xoff, pBox->y1 + yoff,
+ : pBox->x2 + xoff, pBox->y2 + yoff);
+ : pBox++;
+ : }
+ : (*pExaScr->info->DoneSolid) (pPixmap);
+ 1 0.0011 : exaMarkSync(pDrawable->pScreen);
+ : }
+ : else
+ : {
+ :fallback:
+ : if (alu != GXcopy || planemask != FB_ALLONES)
+ : return FALSE;
+ : return TRUE;
+ : EXA_FALLBACK(("to %p (%c)\n", pDrawable,
+ : exaDrawableLocation(pDrawable)));
+ : exaDoMigration (pixmaps, 1, FALSE);
+ : exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
+ : fbFillRegionSolid (pDrawable, pRegion, 0,
+ : fbReplicatePixel (pixel, pDrawable->bitsPerPixel));
+ : exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
+ : }
+ :
+ : return TRUE;
+ :}
+ :
+ :/* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
+ : * Based on fbFillRegionTiled(), fbTile().
+ : */
+ :Bool
+ :exaFillRegionTiled (DrawablePtr pDrawable,
+ : RegionPtr pRegion,
+ : PixmapPtr pTile,
+ : DDXPointPtr pPatOrg,
+ : CARD32 planemask,
+ : CARD32 alu)
+ :{
+ : ExaScreenPriv(pDrawable->pScreen);
+ : PixmapPtr pPixmap;
+ : int xoff, yoff, tileXoff, tileYoff;
+ : int tileWidth, tileHeight;
+ : ExaMigrationRec pixmaps[2];
+ : int nbox = REGION_NUM_RECTS (pRegion);
+ : BoxPtr pBox = REGION_RECTS (pRegion);
+ :
+ : tileWidth = pTile->drawable.width;
+ : tileHeight = pTile->drawable.height;
+ :
+ : /* If we're filling with a solid color, grab it out and go to
+ : * FillRegionSolid, saving numerous copies.
+ : */
+ : if (tileWidth == 1 && tileHeight == 1)
+ : return exaFillRegionSolid(pDrawable, pRegion,
+ : exaGetPixmapFirstPixel (pTile), planemask,
+ : alu);
+ :
+ : pixmaps[0].as_dst = TRUE;
+ : pixmaps[0].as_src = FALSE;
+ : pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
+ : pixmaps[1].as_dst = FALSE;
+ : pixmaps[1].as_src = TRUE;
+ : pixmaps[1].pPix = pTile;
+ :
+ : if (pPixmap->drawable.width > pExaScr->info->maxX ||
+ : pPixmap->drawable.height > pExaScr->info->maxY ||
+ : tileWidth > pExaScr->info->maxX ||
+ : tileHeight > pExaScr->info->maxY)
+ : {
+ : goto fallback;
+ : } else {
+ : exaDoMigration (pixmaps, 2, TRUE);
+ : }
+ :
+ : pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
+ :
+ : if (!pPixmap)
+ : goto fallback;
+ :
+ : if (!exaPixmapIsOffscreen(pTile))
+ : goto fallback;
+ :
+ : if ((*pExaScr->info->PrepareCopy) (exaGetOffscreenPixmap((DrawablePtr)pTile,
+ : &tileXoff, &tileYoff),
+ : pPixmap, 0, 0, alu, planemask))
+ : {
+ : while (nbox--)
+ : {
+ : int height = pBox->y2 - pBox->y1;
+ : int dstY = pBox->y1;
+ : int tileY;
+ :
+ : tileY = (dstY - pDrawable->y - pPatOrg->y) % tileHeight;
+ : while (height > 0) {
+ : int width = pBox->x2 - pBox->x1;
+ : int dstX = pBox->x1;
+ : int tileX;
+ : int h = tileHeight - tileY;
+ :
+ : if (h > height)
+ : h = height;
+ : height -= h;
+ :
+ : tileX = (dstX - pDrawable->x - pPatOrg->x) % tileWidth;
+ : while (width > 0) {
+ : int w = tileWidth - tileX;
+ : if (w > width)
+ : w = width;
+ : width -= w;
+ :
+ : (*pExaScr->info->Copy) (pPixmap,
+ : tileX + tileXoff, tileY + tileYoff,
+ : dstX + xoff, dstY + yoff,
+ : w, h);
+ : dstX += w;
+ : tileX = 0;
+ : }
+ : dstY += h;
+ : tileY = 0;
+ : }
+ : pBox++;
+ : }
+ : (*pExaScr->info->DoneCopy) (pPixmap);
+ : exaMarkSync(pDrawable->pScreen);
+ : return TRUE;
+ : }
+ :
+ :fallback:
+ : if (alu != GXcopy || planemask != FB_ALLONES)
+ : return FALSE;
+ : EXA_FALLBACK(("from %p to %p (%c,%c)\n", pTile, pDrawable,
+ : exaDrawableLocation(&pTile->drawable),
+ : exaDrawableLocation(pDrawable)));
+ : exaDoMigration (pixmaps, 2, FALSE);
+ : exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
+ : exaPrepareAccess ((DrawablePtr)pTile, EXA_PREPARE_SRC);
+ : fbFillRegionTiled (pDrawable, pRegion, pTile);
+ : exaFinishAccess ((DrawablePtr)pTile, EXA_PREPARE_SRC);
+ : exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
+ :
+ : return TRUE;
+ :}
+ :
+ :void
+ :exaPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what)
+ :{
+ : ExaScreenPriv (pWin->drawable.pScreen);
+ : PixmapPtr pPixmap = exaGetDrawablePixmap((DrawablePtr)pWin);
+ : int xoff, yoff;
+ : BoxPtr pBox;
+ : int nbox = REGION_NUM_RECTS(pRegion);
+ :
+ : if (!nbox)
+ : return;
+ :
+ : if (!pExaScr->swappedOut) {
+ : DDXPointRec zeros = { 0, 0 };
+ :
+ : switch (what) {
+ : case PW_BACKGROUND:
+ : switch (pWin->backgroundState) {
+ : case None:
+ : return;
+ : case ParentRelative:
+ : do {
+ : pWin = pWin->parent;
+ : } while (pWin->backgroundState == ParentRelative);
+ : (*pWin->drawable.pScreen->PaintWindowBackground)(pWin, pRegion,
+ : what);
+ : return;
+ : case BackgroundPixel:
+ : exaFillRegionSolid((DrawablePtr)pWin, pRegion, pWin->background.pixel,
+ : FB_ALLONES, GXcopy);
+ : goto damage;
+ : case BackgroundPixmap:
+ : exaFillRegionTiled((DrawablePtr)pWin, pRegion, pWin->background.pixmap,
+ : &zeros, FB_ALLONES, GXcopy);
+ : goto damage;
+ : }
+ : break;
+ : case PW_BORDER:
+ : if (pWin->borderIsPixel) {
+ : exaFillRegionSolid((DrawablePtr)pWin, pRegion, pWin->border.pixel,
+ : FB_ALLONES, GXcopy);
+ : goto damage;
+ : } else {
+ : exaFillRegionTiled((DrawablePtr)pWin, pRegion, pWin->border.pixmap,
+ : &zeros, FB_ALLONES, GXcopy);
+ : goto damage;
+ : }
+ : break;
+ : }
+ : }
+ : ExaCheckPaintWindow (pWin, pRegion, what);
+ :
+ :damage:
+ : exaGetDrawableDeltas((DrawablePtr)pWin, pPixmap, &xoff, &yoff);
+ :
+ : pBox = REGION_RECTS(pRegion);
+ :
+ : while (nbox--)
+ : {
+ : exaPixmapDirty (pPixmap, pBox->x1 + xoff, pBox->y1 + yoff,
+ : pBox->x2 + xoff, pBox->y2 + yoff);
+ : pBox++;
+ : }
+ :}
+ :
+ :/**
+ : * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
+ : *
+ : * This is probably the only case we actually care about. The rest fall through
+ : * to migration and ExaCheckGetImage, which hopefully will result in migration
+ : * pushing the pixmap out of framebuffer.
+ : */
+ :void
+ :exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h,
+ : unsigned int format, unsigned long planeMask, char *d)
+ :{
+ : ExaScreenPriv (pDrawable->pScreen);
+ : ExaMigrationRec pixmaps[1];
+ : PixmapPtr pPix;
+ : int xoff, yoff;
+ : Bool ok;
+ :
+ : if (pExaScr->swappedOut || (w == 1 && h == 1))
+ : goto fallback;
+ :
+ : if (pExaScr->info->DownloadFromScreen == NULL)
+ : goto migrate_and_fallback;
+ :
+ : /* Only cover the ZPixmap, solid copy case. */
+ : if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask))
+ : goto migrate_and_fallback;
+ :
+ : /* Only try to handle the 8bpp and up cases, since we don't want to think
+ : * about <8bpp.
+ : */
+ : if (pDrawable->bitsPerPixel < 8)
+ : goto migrate_and_fallback;
+ :
+ : pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
+ : if (pPix == NULL)
+ : goto fallback;
+ :
+ : xoff += pDrawable->x;
+ : yoff += pDrawable->y;
+ :
+ : ok = pExaScr->info->DownloadFromScreen(pPix, x + xoff, y + yoff, w, h, d,
+ : PixmapBytePad(w, pDrawable->depth));
+ : if (ok) {
+ : exaWaitSync(pDrawable->pScreen);
+ : return;
+ : }
+ :
+ :migrate_and_fallback:
+ : pixmaps[0].as_dst = FALSE;
+ : pixmaps[0].as_src = TRUE;
+ : pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
+ : exaDoMigration (pixmaps, 1, FALSE);
+ :fallback:
+ : ExaCheckGetImage (pDrawable, x, y, w, h, format, planeMask, d);
+ :}
+ :
+ :/**
+ : * GetSpans isn't accelerated yet, but performs migration so that we'll
+ : * hopefully avoid the read-from-framebuffer cost.
+ : */
+ :void
+ :exaGetSpans (DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, int *pwidth,
+ : int nspans, char *pdstStart)
+ :{
+ : ExaMigrationRec pixmaps[1];
+ :
+ : pixmaps[0].as_dst = FALSE;
+ : pixmaps[0].as_src = TRUE;
+ : pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
+ : exaDoMigration (pixmaps, 1, FALSE);
+ :
+ : ExaCheckGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
+ :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/render/glyph.c"
+ *
+ * 103 0.1122
+ */
+
+
+ :/*
+ : *
+ : * Copyright © 2000 SuSE, Inc.
+ : *
+ : * 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 SuSE not be used in advertising or
+ : * publicity pertaining to distribution of the software without specific,
+ : * written prior permission. SuSE makes no representations about the
+ : * suitability of this software for any purpose. It is provided "as is"
+ : * without express or implied warranty.
+ : *
+ : * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ : * 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: Keith Packard, SuSE, Inc.
+ : */
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include "misc.h"
+ :#include "scrnintstr.h"
+ :#include "os.h"
+ :#include "regionstr.h"
+ :#include "validate.h"
+ :#include "windowstr.h"
+ :#include "input.h"
+ :#include "resource.h"
+ :#include "colormapst.h"
+ :#include "cursorstr.h"
+ :#include "dixstruct.h"
+ :#include "gcstruct.h"
+ :#include "servermd.h"
+ :#include "picturestr.h"
+ :#include "glyphstr.h"
+ :
+ :/*
+ : * From Knuth -- a good choice for hash/rehash values is p, p-2 where
+ : * p and p-2 are both prime. These tables are sized to have an extra 10%
+ : * free to avoid exponential performance degradation as the hash table fills
+ : */
+ :static GlyphHashSetRec glyphHashSets[] = {
+ : { 32, 43, 41 },
+ : { 64, 73, 71 },
+ : { 128, 151, 149 },
+ : { 256, 283, 281 },
+ : { 512, 571, 569 },
+ : { 1024, 1153, 1151 },
+ : { 2048, 2269, 2267 },
+ : { 4096, 4519, 4517 },
+ : { 8192, 9013, 9011 },
+ : { 16384, 18043, 18041 },
+ : { 32768, 36109, 36107 },
+ : { 65536, 72091, 72089 },
+ : { 131072, 144409, 144407 },
+ : { 262144, 288361, 288359 },
+ : { 524288, 576883, 576881 },
+ : { 1048576, 1153459, 1153457 },
+ : { 2097152, 2307163, 2307161 },
+ : { 4194304, 4613893, 4613891 },
+ : { 8388608, 9227641, 9227639 },
+ : { 16777216, 18455029, 18455027 },
+ : { 33554432, 36911011, 36911009 },
+ : { 67108864, 73819861, 73819859 },
+ : { 134217728, 147639589, 147639587 },
+ : { 268435456, 295279081, 295279079 },
+ : { 536870912, 590559793, 590559791 }
+ :};
+ :
+ :#define NGLYPHHASHSETS (sizeof(glyphHashSets)/sizeof(glyphHashSets[0]))
+ :
+ :static const CARD8 glyphDepths[GlyphFormatNum] = { 1, 4, 8, 16, 32 };
+ :
+ :static GlyphHashRec globalGlyphs[GlyphFormatNum];
+ :
+ :static int globalTotalGlyphPrivateSize = 0;
+ :
+ :static int glyphPrivateCount = 0;
+ :
+ :void
+ :ResetGlyphPrivates (void)
+ :{
+ : glyphPrivateCount = 0;
+ :}
+ :
+ :int
+ :AllocateGlyphPrivateIndex (void)
+ :{
+ : return glyphPrivateCount++;
+ :}
+ :
+ :Bool
+ :AllocateGlyphPrivate (ScreenPtr pScreen,
+ : int index2,
+ : unsigned amount)
+ :{
+ : PictureScreenPtr ps;
+ : unsigned oldamount;
+ :
+ : ps = GetPictureScreenIfSet (pScreen);
+ : if (!ps)
+ : return FALSE;
+ :
+ : /* Round up sizes for proper alignment */
+ : amount = ((amount + (sizeof (DevUnion) - 1)) / sizeof (DevUnion)) *
+ : sizeof (DevUnion);
+ :
+ : if (index2 >= ps->glyphPrivateLen)
+ : {
+ : unsigned *nsizes;
+ : nsizes = (unsigned *) xrealloc (ps->glyphPrivateSizes,
+ : (index2 + 1) * sizeof (unsigned));
+ : if (!nsizes)
+ : return FALSE;
+ :
+ : while (ps->glyphPrivateLen <= index2)
+ : {
+ : nsizes[ps->glyphPrivateLen++] = 0;
+ : ps->totalGlyphPrivateSize += sizeof (DevUnion);
+ : }
+ : ps->glyphPrivateSizes = nsizes;
+ : }
+ : oldamount = ps->glyphPrivateSizes[index2];
+ : if (amount > oldamount)
+ : {
+ : ps->glyphPrivateSizes[index2] = amount;
+ : ps->totalGlyphPrivateSize += (amount - oldamount);
+ : }
+ : ps->totalGlyphPrivateSize = BitmapBytePad (ps->totalGlyphPrivateSize * 8);
+ :
+ : return TRUE;
+ :}
+ :
+ :static void
+ :SetGlyphScreenPrivateOffsets (void)
+ :{
+ : PictureScreenPtr ps;
+ : int offset = 0;
+ : int i;
+ :
+ : for (i = 0; i < screenInfo.numScreens; i++)
+ : {
+ : ps = GetPictureScreenIfSet (screenInfo.screens[i]);
+ : if (ps && ps->totalGlyphPrivateSize)
+ : {
+ : ps->glyphPrivateOffset = offset;
+ : offset += ps->totalGlyphPrivateSize / sizeof (DevUnion);
+ : }
+ : }
+ :}
+ :
+ :static void
+ :SetGlyphPrivatePointers (GlyphPtr glyph)
+ :{
+ : PictureScreenPtr ps;
+ : int i;
+ : char *ptr;
+ : DevUnion *ppriv;
+ : unsigned *sizes;
+ : unsigned size;
+ : int len;
+ :
+ : for (i = 0; i < screenInfo.numScreens; i++)
+ : {
+ : ps = GetPictureScreenIfSet (screenInfo.screens[i]);
+ : if (ps && ps->totalGlyphPrivateSize)
+ : {
+ : ppriv = glyph->devPrivates + ps->glyphPrivateOffset;
+ : sizes = ps->glyphPrivateSizes;
+ : ptr = (char *) (ppriv + ps->glyphPrivateLen);
+ : for (len = ps->glyphPrivateLen; --len >= 0; ppriv++, sizes++)
+ : {
+ : if ((size = *sizes) != 0)
+ : {
+ : ppriv->ptr = (pointer) ptr;
+ : ptr += size;
+ : }
+ : else
+ : ppriv->ptr = (pointer) 0;
+ : }
+ : }
+ : }
+ :}
+ :
+ :static Bool
+ :ReallocGlobalGlyphPrivate (GlyphPtr glyph)
+ :{
+ : PictureScreenPtr ps;
+ : DevUnion *devPrivates;
+ : char *ptr;
+ : int i;
+ :
+ : devPrivates = xalloc (globalTotalGlyphPrivateSize);
+ : if (!devPrivates)
+ : return FALSE;
+ :
+ : ptr = (char *) devPrivates;
+ : for (i = 0; i < screenInfo.numScreens; i++)
+ : {
+ : ps = GetPictureScreenIfSet (screenInfo.screens[i]);
+ : if (ps && ps->totalGlyphPrivateSize)
+ : {
+ : if (ps->glyphPrivateOffset != -1)
+ : {
+ : memcpy (ptr, glyph->devPrivates + ps->glyphPrivateOffset,
+ : ps->totalGlyphPrivateSize);
+ : }
+ : else if (ps->totalGlyphPrivateSize)
+ : {
+ : memset (ptr, 0, ps->totalGlyphPrivateSize);
+ : }
+ :
+ : ptr += ps->totalGlyphPrivateSize;
+ : }
+ : }
+ :
+ : if (glyph->devPrivates)
+ : xfree (glyph->devPrivates);
+ :
+ : glyph->devPrivates = devPrivates;
+ :
+ : return TRUE;
+ :}
+ :
+ :Bool
+ :GlyphInit (ScreenPtr pScreen)
+ :{
+ : PictureScreenPtr ps = GetPictureScreen (pScreen);
+ :
+ : ps->totalGlyphPrivateSize = 0;
+ : ps->glyphPrivateSizes = 0;
+ : ps->glyphPrivateLen = 0;
+ : ps->glyphPrivateOffset = -1;
+ :
+ : return TRUE;
+ :}
+ :
+ :Bool
+ :GlyphFinishInit (ScreenPtr pScreen)
+ :{
+ : PictureScreenPtr ps = GetPictureScreen (pScreen);
+ :
+ : if (ps->totalGlyphPrivateSize)
+ : {
+ : GlyphPtr glyph;
+ : int fdepth, i;
+ :
+ : globalTotalGlyphPrivateSize += ps->totalGlyphPrivateSize;
+ :
+ : for (fdepth = 0; fdepth < GlyphFormatNum; fdepth++)
+ : {
+ : if (!globalGlyphs[fdepth].hashSet)
+ : continue;
+ :
+ : for (i = 0; i < globalGlyphs[fdepth].hashSet->size; i++)
+ : {
+ : glyph = globalGlyphs[fdepth].table[i].glyph;
+ : if (glyph && glyph != DeletedGlyph)
+ : {
+ : if (!ReallocGlobalGlyphPrivate (glyph))
+ : return FALSE;
+ : }
+ : }
+ : }
+ :
+ : SetGlyphScreenPrivateOffsets ();
+ :
+ : for (fdepth = 0; fdepth < GlyphFormatNum; fdepth++)
+ : {
+ : if (!globalGlyphs[fdepth].hashSet)
+ : continue;
+ :
+ : for (i = 0; i < globalGlyphs[fdepth].hashSet->size; i++)
+ : {
+ : glyph = globalGlyphs[fdepth].table[i].glyph;
+ : if (glyph && glyph != DeletedGlyph)
+ : {
+ : SetGlyphPrivatePointers (glyph);
+ :
+ : if (!(*ps->RealizeGlyph) (pScreen, glyph))
+ : return FALSE;
+ : }
+ : }
+ : }
+ : }
+ : else
+ : ps->glyphPrivateOffset = 0;
+ :
+ : return TRUE;
+ :}
+ :
+ :void
+ :GlyphUninit (ScreenPtr pScreen)
+ :{
+ : PictureScreenPtr ps = GetPictureScreen (pScreen);
+ : GlyphPtr glyph;
+ : int fdepth, i;
+ :
+ : globalTotalGlyphPrivateSize -= ps->totalGlyphPrivateSize;
+ :
+ : for (fdepth = 0; fdepth < GlyphFormatNum; fdepth++)
+ : {
+ : if (!globalGlyphs[fdepth].hashSet)
+ : continue;
+ :
+ : for (i = 0; i < globalGlyphs[fdepth].hashSet->size; i++)
+ : {
+ : glyph = globalGlyphs[fdepth].table[i].glyph;
+ : if (glyph && glyph != DeletedGlyph)
+ : {
+ : (*ps->UnrealizeGlyph) (pScreen, glyph);
+ :
+ : if (globalTotalGlyphPrivateSize)
+ : {
+ : if (!ReallocGlobalGlyphPrivate (glyph))
+ : return;
+ : }
+ : else
+ : {
+ : if (glyph->devPrivates)
+ : xfree (glyph->devPrivates);
+ : glyph->devPrivates = NULL;
+ : }
+ : }
+ : }
+ : }
+ :
+ : if (globalTotalGlyphPrivateSize)
+ : SetGlyphScreenPrivateOffsets ();
+ :
+ : for (fdepth = 0; fdepth < GlyphFormatNum; fdepth++)
+ : {
+ : if (!globalGlyphs[fdepth].hashSet)
+ : continue;
+ :
+ : for (i = 0; i < globalGlyphs[fdepth].hashSet->size; i++)
+ : {
+ : glyph = globalGlyphs[fdepth].table[i].glyph;
+ : if (glyph && glyph != DeletedGlyph)
+ : {
+ : if (globalTotalGlyphPrivateSize)
+ : SetGlyphPrivatePointers (glyph);
+ : }
+ : }
+ : }
+ :
+ : if (ps->glyphPrivateSizes)
+ : xfree (ps->glyphPrivateSizes);
+ :}
+ :
+ :GlyphHashSetPtr
+ :FindGlyphHashSet (CARD32 filled)
+ :{
+ : int i;
+ :
+ : for (i = 0; i < NGLYPHHASHSETS; i++)
+ : if (glyphHashSets[i].entries >= filled)
+ : return &glyphHashSets[i];
+ : return 0;
+ :}
+ :
+ :static int _GlyphSetPrivateAllocateIndex = 0;
+ :
+ :int
+ :AllocateGlyphSetPrivateIndex (void)
+ :{
+ : return _GlyphSetPrivateAllocateIndex++;
+ :}
+ :
+ :void
+ :ResetGlyphSetPrivateIndex (void)
+ :{
+ : _GlyphSetPrivateAllocateIndex = 0;
+ :}
+ :
+ :Bool
+ :_GlyphSetSetNewPrivate (GlyphSetPtr glyphSet, int n, pointer ptr)
+ :{
+ : pointer *new;
+ :
+ : if (n > glyphSet->maxPrivate) {
+ : if (glyphSet->devPrivates &&
+ : glyphSet->devPrivates != (pointer)(&glyphSet[1])) {
+ : new = (pointer *) xrealloc (glyphSet->devPrivates,
+ : (n + 1) * sizeof (pointer));
+ : if (!new)
+ : return FALSE;
+ : } else {
+ : new = (pointer *) xalloc ((n + 1) * sizeof (pointer));
+ : if (!new)
+ : return FALSE;
+ : if (glyphSet->devPrivates)
+ : memcpy (new,
+ : glyphSet->devPrivates,
+ : (glyphSet->maxPrivate + 1) * sizeof (pointer));
+ : }
+ : glyphSet->devPrivates = new;
+ : /* Zero out new, uninitialize privates */
+ : while (++glyphSet->maxPrivate < n)
+ : glyphSet->devPrivates[glyphSet->maxPrivate] = (pointer)0;
+ : }
+ : glyphSet->devPrivates[n] = ptr;
+ : return TRUE;
+ :}
+ :
+ :GlyphRefPtr
+ :FindGlyphRef (GlyphHashPtr hash, CARD32 signature, Bool match, GlyphPtr compare)
+ 9 0.0098 :{ /* FindGlyphRef total: 88 0.0959 */
+ : CARD32 elt, step, s;
+ : GlyphPtr glyph;
+ : GlyphRefPtr table, gr, del;
+ 2 0.0022 : CARD32 tableSize = hash->hashSet->size;
+ :
+ 1 0.0011 : table = hash->table;
+ 37 0.0403 : elt = signature % tableSize;
+ : step = 0;
+ : del = 0;
+ : for (;;)
+ : {
+ 6 0.0065 : gr = &table[elt];
+ 13 0.0142 : s = gr->signature;
+ 2 0.0022 : glyph = gr->glyph;
+ 5 0.0054 : if (!glyph)
+ : {
+ : if (del)
+ : gr = del;
+ : break;
+ : }
+ : if (glyph == DeletedGlyph)
+ : {
+ : if (!del)
+ : del = gr;
+ : else if (gr == del)
+ : break;
+ : }
+ 2 0.0022 : else if (s == signature &&
+ : (!match ||
+ : memcmp (&compare->info, &glyph->info, compare->size) == 0))
+ : {
+ : break;
+ : }
+ 3 0.0033 : if (!step)
+ : {
+ 1 0.0011 : step = signature % hash->hashSet->rehash;
+ 4 0.0044 : if (!step)
+ : step = 1;
+ : }
+ : elt += step;
+ : if (elt >= tableSize)
+ : elt -= tableSize;
+ : }
+ : return gr;
+ 3 0.0033 :}
+ :
+ :CARD32
+ :HashGlyph (GlyphPtr glyph)
+ :{
+ : CARD32 *bits = (CARD32 *) &(glyph->info);
+ : CARD32 hash;
+ : int n = glyph->size / sizeof (CARD32);
+ :
+ : hash = 0;
+ : while (n--)
+ : hash ^= *bits++;
+ : return hash;
+ :}
+ :
+ :#ifdef CHECK_DUPLICATES
+ :void
+ :DuplicateRef (GlyphPtr glyph, char *where)
+ :{
+ : ErrorF ("Duplicate Glyph 0x%x from %s\n", glyph, where);
+ :}
+ :
+ :void
+ :CheckDuplicates (GlyphHashPtr hash, char *where)
+ :{
+ : GlyphPtr g;
+ : int i, j;
+ :
+ : for (i = 0; i < hash->hashSet->size; i++)
+ : {
+ : g = hash->table[i].glyph;
+ : if (!g || g == DeletedGlyph)
+ : continue;
+ : for (j = i + 1; j < hash->hashSet->size; j++)
+ : if (hash->table[j].glyph == g)
+ : DuplicateRef (g, where);
+ : }
+ :}
+ :#else
+ :#define CheckDuplicates(a,b)
+ :#define DuplicateRef(a,b)
+ :#endif
+ :
+ :void
+ :FreeGlyph (GlyphPtr glyph, int format)
+ :{
+ : CheckDuplicates (&globalGlyphs[format], "FreeGlyph");
+ : if (--glyph->refcnt == 0)
+ : {
+ : PictureScreenPtr ps;
+ : GlyphRefPtr gr;
+ : int i;
+ : int first;
+ :
+ : first = -1;
+ : for (i = 0; i < globalGlyphs[format].hashSet->size; i++)
+ : if (globalGlyphs[format].table[i].glyph == glyph)
+ : {
+ : if (first != -1)
+ : DuplicateRef (glyph, "FreeGlyph check");
+ : first = i;
+ : }
+ :
+ : gr = FindGlyphRef (&globalGlyphs[format],
+ : HashGlyph (glyph), TRUE, glyph);
+ : if (gr - globalGlyphs[format].table != first)
+ : DuplicateRef (glyph, "Found wrong one");
+ : if (gr->glyph && gr->glyph != DeletedGlyph)
+ : {
+ : gr->glyph = DeletedGlyph;
+ : gr->signature = 0;
+ : globalGlyphs[format].tableEntries--;
+ : }
+ :
+ : for (i = 0; i < screenInfo.numScreens; i++)
+ : {
+ : ps = GetPictureScreenIfSet (screenInfo.screens[i]);
+ : if (ps)
+ : (*ps->UnrealizeGlyph) (screenInfo.screens[i], glyph);
+ : }
+ :
+ : if (glyph->devPrivates)
+ : xfree (glyph->devPrivates);
+ : xfree (glyph);
+ : }
+ :}
+ :
+ :void
+ :AddGlyph (GlyphSetPtr glyphSet, GlyphPtr glyph, Glyph id)
+ :{
+ : GlyphRefPtr gr;
+ : CARD32 hash;
+ :
+ : CheckDuplicates (&globalGlyphs[glyphSet->fdepth], "AddGlyph top global");
+ : /* Locate existing matching glyph */
+ : hash = HashGlyph (glyph);
+ : gr = FindGlyphRef (&globalGlyphs[glyphSet->fdepth], hash, TRUE, glyph);
+ : if (gr->glyph && gr->glyph != DeletedGlyph)
+ : {
+ : PictureScreenPtr ps;
+ : int i;
+ :
+ : for (i = 0; i < screenInfo.numScreens; i++)
+ : {
+ : ps = GetPictureScreenIfSet (screenInfo.screens[i]);
+ : if (ps)
+ : (*ps->UnrealizeGlyph) (screenInfo.screens[i], glyph);
+ : }
+ : if (glyph->devPrivates)
+ : xfree (glyph->devPrivates);
+ : xfree (glyph);
+ : glyph = gr->glyph;
+ : }
+ : else
+ : {
+ : gr->glyph = glyph;
+ : gr->signature = hash;
+ : globalGlyphs[glyphSet->fdepth].tableEntries++;
+ : }
+ :
+ : /* Insert/replace glyphset value */
+ : gr = FindGlyphRef (&glyphSet->hash, id, FALSE, 0);
+ : ++glyph->refcnt;
+ : if (gr->glyph && gr->glyph != DeletedGlyph)
+ : FreeGlyph (gr->glyph, glyphSet->fdepth);
+ : else
+ : glyphSet->hash.tableEntries++;
+ : gr->glyph = glyph;
+ : gr->signature = id;
+ : CheckDuplicates (&globalGlyphs[glyphSet->fdepth], "AddGlyph bottom");
+ :}
+ :
+ :Bool
+ :DeleteGlyph (GlyphSetPtr glyphSet, Glyph id)
+ :{
+ : GlyphRefPtr gr;
+ : GlyphPtr glyph;
+ :
+ : gr = FindGlyphRef (&glyphSet->hash, id, FALSE, 0);
+ : glyph = gr->glyph;
+ : if (glyph && glyph != DeletedGlyph)
+ : {
+ : gr->glyph = DeletedGlyph;
+ : glyphSet->hash.tableEntries--;
+ : FreeGlyph (glyph, glyphSet->fdepth);
+ : return TRUE;
+ : }
+ : return FALSE;
+ :}
+ :
+ :GlyphPtr
+ :FindGlyph (GlyphSetPtr glyphSet, Glyph id)
+ 6 0.0065 :{ /* FindGlyph total: 15 0.0163 */
+ : GlyphPtr glyph;
+ :
+ 3 0.0033 : glyph = FindGlyphRef (&glyphSet->hash, id, FALSE, 0)->glyph;
+ 2 0.0022 : if (glyph == DeletedGlyph)
+ : glyph = 0;
+ : return glyph;
+ 4 0.0044 :}
+ :
+ :GlyphPtr
+ :AllocateGlyph (xGlyphInfo *gi, int fdepth)
+ :{
+ : PictureScreenPtr ps;
+ : int size;
+ : GlyphPtr glyph;
+ : int i;
+ :
+ : size = gi->height * PixmapBytePad (gi->width, glyphDepths[fdepth]);
+ : glyph = (GlyphPtr) xalloc (size + sizeof (GlyphRec));
+ : if (!glyph)
+ : return 0;
+ : glyph->refcnt = 0;
+ : glyph->size = size + sizeof (xGlyphInfo);
+ : glyph->info = *gi;
+ :
+ : if (globalTotalGlyphPrivateSize)
+ : {
+ : glyph->devPrivates = xalloc (globalTotalGlyphPrivateSize);
+ : if (!glyph->devPrivates)
+ : return 0;
+ :
+ : SetGlyphPrivatePointers (glyph);
+ : } else
+ : glyph->devPrivates = NULL;
+ :
+ : for (i = 0; i < screenInfo.numScreens; i++)
+ : {
+ : ps = GetPictureScreenIfSet (screenInfo.screens[i]);
+ : if (ps)
+ : {
+ : if (!(*ps->RealizeGlyph) (screenInfo.screens[i], glyph))
+ : {
+ : while (i--)
+ : {
+ : ps = GetPictureScreenIfSet (screenInfo.screens[i]);
+ : if (ps)
+ : (*ps->UnrealizeGlyph) (screenInfo.screens[i], glyph);
+ : }
+ :
+ : if (glyph->devPrivates)
+ : xfree (glyph->devPrivates);
+ : xfree (glyph);
+ : return 0;
+ : }
+ : }
+ : }
+ :
+ : return glyph;
+ :}
+ :
+ :Bool
+ :AllocateGlyphHash (GlyphHashPtr hash, GlyphHashSetPtr hashSet)
+ :{
+ : hash->table = (GlyphRefPtr) xalloc (hashSet->size * sizeof (GlyphRefRec));
+ : if (!hash->table)
+ : return FALSE;
+ : memset (hash->table, 0, hashSet->size * sizeof (GlyphRefRec));
+ : hash->hashSet = hashSet;
+ : hash->tableEntries = 0;
+ : return TRUE;
+ :}
+ :
+ :Bool
+ :ResizeGlyphHash (GlyphHashPtr hash, CARD32 change, Bool global)
+ :{
+ : CARD32 tableEntries;
+ : GlyphHashSetPtr hashSet;
+ : GlyphHashRec newHash;
+ : GlyphRefPtr gr;
+ : GlyphPtr glyph;
+ : int i;
+ : int oldSize;
+ : CARD32 s;
+ :
+ : tableEntries = hash->tableEntries + change;
+ : hashSet = FindGlyphHashSet (tableEntries);
+ : if (hashSet == hash->hashSet)
+ : return TRUE;
+ : if (global)
+ : CheckDuplicates (hash, "ResizeGlyphHash top");
+ : if (!AllocateGlyphHash (&newHash, hashSet))
+ : return FALSE;
+ : if (hash->table)
+ : {
+ : oldSize = hash->hashSet->size;
+ : for (i = 0; i < oldSize; i++)
+ : {
+ : glyph = hash->table[i].glyph;
+ : if (glyph && glyph != DeletedGlyph)
+ : {
+ : s = hash->table[i].signature;
+ : gr = FindGlyphRef (&newHash, s, global, glyph);
+ : gr->signature = s;
+ : gr->glyph = glyph;
+ : ++newHash.tableEntries;
+ : }
+ : }
+ : xfree (hash->table);
+ : }
+ : *hash = newHash;
+ : if (global)
+ : CheckDuplicates (hash, "ResizeGlyphHash bottom");
+ : return TRUE;
+ :}
+ :
+ :Bool
+ :ResizeGlyphSet (GlyphSetPtr glyphSet, CARD32 change)
+ :{
+ : return (ResizeGlyphHash (&glyphSet->hash, change, FALSE) &&
+ : ResizeGlyphHash (&globalGlyphs[glyphSet->fdepth], change, TRUE));
+ :}
+ :
+ :GlyphSetPtr
+ :AllocateGlyphSet (int fdepth, PictFormatPtr format)
+ :{
+ : GlyphSetPtr glyphSet;
+ : int size;
+ :
+ : if (!globalGlyphs[fdepth].hashSet)
+ : {
+ : if (!AllocateGlyphHash (&globalGlyphs[fdepth], &glyphHashSets[0]))
+ : return FALSE;
+ : }
+ :
+ : size = (sizeof (GlyphSetRec) +
+ : (sizeof (pointer) * _GlyphSetPrivateAllocateIndex));
+ : glyphSet = xalloc (size);
+ : if (!glyphSet)
+ : return FALSE;
+ : bzero((char *)glyphSet, size);
+ : glyphSet->maxPrivate = _GlyphSetPrivateAllocateIndex - 1;
+ : if (_GlyphSetPrivateAllocateIndex)
+ : glyphSet->devPrivates = (pointer)(&glyphSet[1]);
+ :
+ : if (!AllocateGlyphHash (&glyphSet->hash, &glyphHashSets[0]))
+ : {
+ : xfree (glyphSet);
+ : return FALSE;
+ : }
+ : glyphSet->refcnt = 1;
+ : glyphSet->fdepth = fdepth;
+ : glyphSet->format = format;
+ : return glyphSet;
+ :}
+ :
+ :int
+ :FreeGlyphSet (pointer value,
+ : XID gid)
+ :{
+ : GlyphSetPtr glyphSet = (GlyphSetPtr) value;
+ :
+ : if (--glyphSet->refcnt == 0)
+ : {
+ : CARD32 i, tableSize = glyphSet->hash.hashSet->size;
+ : GlyphRefPtr table = glyphSet->hash.table;
+ : GlyphPtr glyph;
+ :
+ : for (i = 0; i < tableSize; i++)
+ : {
+ : glyph = table[i].glyph;
+ : if (glyph && glyph != DeletedGlyph)
+ : FreeGlyph (glyph, glyphSet->fdepth);
+ : }
+ : if (!globalGlyphs[glyphSet->fdepth].tableEntries)
+ : {
+ : xfree (globalGlyphs[glyphSet->fdepth].table);
+ : globalGlyphs[glyphSet->fdepth].table = 0;
+ : globalGlyphs[glyphSet->fdepth].hashSet = 0;
+ : }
+ : else
+ : ResizeGlyphHash (&globalGlyphs[glyphSet->fdepth], 0, TRUE);
+ : xfree (table);
+ :
+ : if (glyphSet->devPrivates &&
+ : glyphSet->devPrivates != (pointer)(&glyphSet[1]))
+ : xfree(glyphSet->devPrivates);
+ :
+ : xfree (glyphSet);
+ : }
+ : return Success;
+ :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/Xext/xace.c"
+ *
+ * 101 0.1100
+ */
+
+
+ :/************************************************************
+ :
+ :Author: Eamon Walsh <ewalsh@epoch.ncsc.mil>
+ :
+ :Permission to use, copy, modify, distribute, and sell this software and its
+ :documentation for any purpose is hereby granted without fee, provided that
+ :this permission notice appear in supporting documentation. This permission
+ :notice shall be included in all copies or substantial portions of the
+ :Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ :IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ :FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ :AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ :AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ :CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :********************************************************/
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include <stdarg.h>
+ :#include "windowstr.h"
+ :#include "scrnintstr.h"
+ :#include "gcstruct.h"
+ :#include "xacestr.h"
+ :#include "modinit.h"
+ :
+ :CallbackListPtr XaceHooks[XACE_NUM_HOOKS] = {0};
+ :
+ :/* Proc vectors for untrusted clients, swapped and unswapped versions.
+ : * These are the same as the normal proc vectors except that extensions
+ : * that haven't declared themselves secure will have ProcBadRequest plugged
+ : * in for their major opcode dispatcher. This prevents untrusted clients
+ : * from guessing extension major opcodes and using the extension even though
+ : * the extension can't be listed or queried.
+ : */
+ :static int (*UntrustedProcVector[256])(
+ : ClientPtr /*client*/
+ :);
+ :static int (*SwappedUntrustedProcVector[256])(
+ : ClientPtr /*client*/
+ :);
+ :
+ :/* Entry point for hook functions. Called by Xserver.
+ : */
+ :int XaceHook(int hook, ...)
+ 22 0.0240 :{ /* XaceHook total: 74 0.0806 */
+ : pointer calldata; /* data passed to callback */
+ : int *prv = NULL; /* points to return value from callback */
+ : va_list ap; /* argument list */
+ 8 0.0087 : va_start(ap, hook);
+ :
+ : /* Marshal arguments for passing to callback.
+ : * Each callback has its own case, which sets up a structure to hold
+ : * the arguments and integer return parameter, or in some cases just
+ : * sets calldata directly to a single argument (with no return result)
+ : */
+ 7 0.0076 : switch (hook)
+ : {
+ : case XACE_CORE_DISPATCH: {
+ : XaceCoreDispatchRec rec = {
+ : va_arg(ap, ClientPtr),
+ : TRUE /* default allow */
+ : };
+ : calldata = &rec;
+ : prv = &rec.rval;
+ : break;
+ : }
+ : case XACE_RESOURCE_ACCESS: {
+ : XaceResourceAccessRec rec = {
+ : va_arg(ap, ClientPtr),
+ : va_arg(ap, XID),
+ : va_arg(ap, RESTYPE),
+ : va_arg(ap, Mask),
+ : va_arg(ap, pointer),
+ : TRUE /* default allow */
+ 13 0.0142 : };
+ : calldata = &rec;
+ : prv = &rec.rval;
+ : break;
+ : }
+ : case XACE_DEVICE_ACCESS: {
+ : XaceDeviceAccessRec rec = {
+ : va_arg(ap, ClientPtr),
+ : va_arg(ap, DeviceIntPtr),
+ : va_arg(ap, Bool),
+ : TRUE /* default allow */
+ : };
+ : calldata = &rec;
+ : prv = &rec.rval;
+ : break;
+ : }
+ : case XACE_PROPERTY_ACCESS: {
+ : XacePropertyAccessRec rec = {
+ : va_arg(ap, ClientPtr),
+ : va_arg(ap, WindowPtr),
+ : va_arg(ap, Atom),
+ : va_arg(ap, Mask),
+ : XaceAllowOperation /* default allow */
+ : };
+ : calldata = &rec;
+ : prv = &rec.rval;
+ : break;
+ : }
+ : case XACE_DRAWABLE_ACCESS: {
+ : XaceDrawableAccessRec rec = {
+ : va_arg(ap, ClientPtr),
+ : va_arg(ap, DrawablePtr),
+ : TRUE /* default allow */
+ : };
+ : calldata = &rec;
+ : prv = &rec.rval;
+ : break;
+ : }
+ : case XACE_MAP_ACCESS:
+ : case XACE_BACKGRND_ACCESS: {
+ : XaceMapAccessRec rec = {
+ : va_arg(ap, ClientPtr),
+ : va_arg(ap, WindowPtr),
+ : TRUE /* default allow */
+ : };
+ : calldata = &rec;
+ : prv = &rec.rval;
+ : break;
+ : }
+ : case XACE_EXT_DISPATCH:
+ : case XACE_EXT_ACCESS: {
+ : XaceExtAccessRec rec = {
+ : va_arg(ap, ClientPtr),
+ : va_arg(ap, ExtensionEntry*),
+ : TRUE /* default allow */
+ : };
+ : calldata = &rec;
+ : prv = &rec.rval;
+ : break;
+ : }
+ : case XACE_HOSTLIST_ACCESS: {
+ : XaceHostlistAccessRec rec = {
+ : va_arg(ap, ClientPtr),
+ : va_arg(ap, Mask),
+ : TRUE /* default allow */
+ : };
+ : calldata = &rec;
+ : prv = &rec.rval;
+ : break;
+ : }
+ : case XACE_SITE_POLICY: {
+ : XaceSitePolicyRec rec = {
+ : va_arg(ap, char*),
+ : va_arg(ap, int),
+ : FALSE /* default unrecognized */
+ : };
+ : calldata = &rec;
+ : prv = &rec.rval;
+ : break;
+ : }
+ : case XACE_DECLARE_EXT_SECURE: {
+ : XaceDeclareExtSecureRec rec = {
+ : va_arg(ap, ExtensionEntry*),
+ : va_arg(ap, Bool)
+ : };
+ : calldata = &rec;
+ : break;
+ : }
+ : case XACE_AUTH_AVAIL: {
+ : XaceAuthAvailRec rec = {
+ : va_arg(ap, ClientPtr),
+ : va_arg(ap, XID)
+ : };
+ : calldata = &rec;
+ : break;
+ : }
+ : case XACE_KEY_AVAIL: {
+ : XaceKeyAvailRec rec = {
+ : va_arg(ap, xEventPtr),
+ : va_arg(ap, DeviceIntPtr),
+ : va_arg(ap, int)
+ : };
+ : calldata = &rec;
+ : break;
+ : }
+ : case XACE_WINDOW_INIT: {
+ : XaceWindowRec rec = {
+ : va_arg(ap, ClientPtr),
+ : va_arg(ap, WindowPtr)
+ : };
+ : calldata = &rec;
+ : break;
+ : }
+ : case XACE_AUDIT_BEGIN: {
+ : XaceAuditRec rec = {
+ : va_arg(ap, ClientPtr),
+ : 0
+ 2 0.0022 : };
+ : calldata = &rec;
+ : break;
+ : }
+ : case XACE_AUDIT_END: {
+ : XaceAuditRec rec = {
+ : va_arg(ap, ClientPtr),
+ : va_arg(ap, int)
+ 2 0.0022 : };
+ : calldata = &rec;
+ : break;
+ : }
+ : default: {
+ : va_end(ap);
+ : return 0; /* unimplemented hook number */
+ : }
+ : }
+ : va_end(ap);
+ :
+ : /* call callbacks and return result, if any. */
+ 10 0.0109 : CallCallbacks(&XaceHooks[hook], calldata);
+ 4 0.0044 : return prv ? *prv : 0;
+ 6 0.0065 :}
+ :
+ :static int
+ :ProcXaceDispatch(ClientPtr client)
+ :{
+ : REQUEST(xReq);
+ :
+ : switch (stuff->data)
+ : {
+ : default:
+ : return BadRequest;
+ : }
+ :} /* ProcXaceDispatch */
+ :
+ :static int
+ :SProcXaceDispatch(ClientPtr client)
+ :{
+ : REQUEST(xReq);
+ :
+ : switch (stuff->data)
+ : {
+ : default:
+ : return BadRequest;
+ : }
+ :} /* SProcXaceDispatch */
+ :
+ :
+ :/* XaceResetProc
+ : *
+ : * Arguments:
+ : * extEntry is the extension information for the XACE extension.
+ : *
+ : * Returns: nothing.
+ : *
+ : * Side Effects:
+ : * Performs any cleanup needed by XACE at server shutdown time.
+ : */
+ :static void
+ :XaceResetProc(ExtensionEntry *extEntry)
+ :{
+ : int i;
+ :
+ : for (i=0; i<XACE_NUM_HOOKS; i++)
+ : {
+ : DeleteCallbackList(&XaceHooks[i]);
+ : XaceHooks[i] = NULL;
+ : }
+ :} /* XaceResetProc */
+ :
+ :
+ :static int
+ :XaceCatchDispatchProc(ClientPtr client)
+ :{ /* XaceCatchDispatchProc total: 5 0.0054 */
+ : REQUEST(xReq);
+ : int major = stuff->reqType;
+ :
+ 5 0.0054 : if (!ProcVector[major])
+ : return (BadRequest);
+ :
+ : if (!XaceHook(XACE_CORE_DISPATCH, client))
+ : return (BadAccess);
+ :
+ : return client->swapped ?
+ : (* SwappedProcVector[major])(client) :
+ : (* ProcVector[major])(client);
+ :}
+ :
+ :static int
+ :XaceCatchExtProc(ClientPtr client)
+ 4 0.0044 :{ /* XaceCatchExtProc total: 22 0.0240 */
+ : REQUEST(xReq);
+ : int major = stuff->reqType;
+ 2 0.0022 : ExtensionEntry *ext = GetExtensionEntry(major);
+ :
+ 2 0.0022 : if (!ext || !ProcVector[major])
+ : return (BadRequest);
+ :
+ 1 0.0011 : if (!XaceHook(XACE_EXT_DISPATCH, client, ext))
+ : return (BadRequest); /* pretend extension doesn't exist */
+ :
+ 1 0.0011 : return client->swapped ?
+ : (* SwappedProcVector[major])(client) :
+ : (* ProcVector[major])(client);
+ 12 0.0131 :}
+ :
+ :
+ :/* SecurityClientStateCallback
+ : *
+ : * Arguments:
+ : * pcbl is &ClientStateCallback.
+ : * nullata is NULL.
+ : * calldata is a pointer to a NewClientInfoRec (include/dixstruct.h)
+ : * which contains information about client state changes.
+ : *
+ : * Returns: nothing.
+ : *
+ : * Side Effects:
+ : *
+ : * If a new client is connecting, its authorization ID is copied to
+ : * client->authID. If this is a generated authorization, its reference
+ : * count is bumped, its timer is cancelled if it was running, and its
+ : * trustlevel is copied to TRUSTLEVEL(client).
+ : *
+ : * If a client is disconnecting and the client was using a generated
+ : * authorization, the authorization's reference count is decremented, and
+ : * if it is now zero, the timer for this authorization is started.
+ : */
+ :
+ :static void
+ :XaceClientStateCallback(
+ : CallbackListPtr *pcbl,
+ : pointer nulldata,
+ : pointer calldata)
+ :{
+ : NewClientInfoRec *pci = (NewClientInfoRec *)calldata;
+ : ClientPtr client = pci->client;
+ :
+ : switch (client->clientState)
+ : {
+ : case ClientStateRunning:
+ : {
+ : client->requestVector = client->swapped ?
+ : SwappedUntrustedProcVector : UntrustedProcVector;
+ : break;
+ : }
+ : default: break;
+ : }
+ :} /* XaceClientStateCallback */
+ :
+ :/* XaceExtensionInit
+ : *
+ : * Initialize the XACE Extension
+ : */
+ :void XaceExtensionInit(INITARGS)
+ :{
+ : ExtensionEntry *extEntry;
+ : int i;
+ :
+ : if (!AddCallback(&ClientStateCallback, XaceClientStateCallback, NULL))
+ : return;
+ :
+ : extEntry = AddExtension(XACE_EXTENSION_NAME,
+ : XaceNumberEvents, XaceNumberErrors,
+ : ProcXaceDispatch, SProcXaceDispatch,
+ : XaceResetProc, StandardMinorOpcode);
+ :
+ : /* initialize dispatching intercept functions */
+ : for (i = 0; i < 128; i++)
+ : {
+ : UntrustedProcVector[i] = XaceCatchDispatchProc;
+ : SwappedUntrustedProcVector[i] = XaceCatchDispatchProc;
+ : }
+ : for (i = 128; i < 256; i++)
+ : {
+ : UntrustedProcVector[i] = XaceCatchExtProc;
+ : SwappedUntrustedProcVector[i] = XaceCatchExtProc;
+ : }
+ :}
+ :
+ :/* XaceCensorImage
+ : *
+ : * Called after pScreen->GetImage to prevent pieces or trusted windows from
+ : * being returned in image data from an untrusted window.
+ : *
+ : * Arguments:
+ : * client is the client doing the GetImage.
+ : * pVisibleRegion is the visible region of the window.
+ : * widthBytesLine is the width in bytes of one horizontal line in pBuf.
+ : * pDraw is the source window.
+ : * x, y, w, h is the rectangle of image data from pDraw in pBuf.
+ : * format is the format of the image data in pBuf: ZPixmap or XYPixmap.
+ : * pBuf is the image data.
+ : *
+ : * Returns: nothing.
+ : *
+ : * Side Effects:
+ : * Any part of the rectangle (x, y, w, h) that is outside the visible
+ : * region of the window will be destroyed (overwritten) in pBuf.
+ : */
+ :void
+ :XaceCensorImage(client, pVisibleRegion, widthBytesLine, pDraw, x, y, w, h,
+ : format, pBuf)
+ : ClientPtr client;
+ : RegionPtr pVisibleRegion;
+ : long widthBytesLine;
+ : DrawablePtr pDraw;
+ : int x, y, w, h;
+ : unsigned int format;
+ : char * pBuf;
+ :{
+ : ScreenPtr pScreen;
+ : RegionRec imageRegion; /* region representing x,y,w,h */
+ : RegionRec censorRegion; /* region to obliterate */
+ : BoxRec imageBox;
+ : int nRects;
+ :
+ : pScreen = pDraw->pScreen;
+ :
+ : imageBox.x1 = x;
+ : imageBox.y1 = y;
+ : imageBox.x2 = x + w;
+ : imageBox.y2 = y + h;
+ : REGION_INIT(pScreen, &imageRegion, &imageBox, 1);
+ : REGION_NULL(pScreen, &censorRegion);
+ :
+ : /* censorRegion = imageRegion - visibleRegion */
+ : REGION_SUBTRACT(pScreen, &censorRegion, &imageRegion, pVisibleRegion);
+ : nRects = REGION_NUM_RECTS(&censorRegion);
+ : if (nRects > 0)
+ : { /* we have something to censor */
+ : GCPtr pScratchGC = NULL;
+ : PixmapPtr pPix = NULL;
+ : xRectangle *pRects = NULL;
+ : Bool failed = FALSE;
+ : int depth = 1;
+ : int bitsPerPixel = 1;
+ : int i;
+ : BoxPtr pBox;
+ :
+ : /* convert region to list-of-rectangles for PolyFillRect */
+ :
+ : pRects = (xRectangle *)ALLOCATE_LOCAL(nRects * sizeof(xRectangle *));
+ : if (!pRects)
+ : {
+ : failed = TRUE;
+ : goto failSafe;
+ : }
+ : for (pBox = REGION_RECTS(&censorRegion), i = 0;
+ : i < nRects;
+ : i++, pBox++)
+ : {
+ : pRects[i].x = pBox->x1;
+ : pRects[i].y = pBox->y1 - imageBox.y1;
+ : pRects[i].width = pBox->x2 - pBox->x1;
+ : pRects[i].height = pBox->y2 - pBox->y1;
+ : }
+ :
+ : /* use pBuf as a fake pixmap */
+ :
+ : if (format == ZPixmap)
+ : {
+ : depth = pDraw->depth;
+ : bitsPerPixel = pDraw->bitsPerPixel;
+ : }
+ :
+ : pPix = GetScratchPixmapHeader(pDraw->pScreen, w, h,
+ : depth, bitsPerPixel,
+ : widthBytesLine, (pointer)pBuf);
+ : if (!pPix)
+ : {
+ : failed = TRUE;
+ : goto failSafe;
+ : }
+ :
+ : pScratchGC = GetScratchGC(depth, pPix->drawable.pScreen);
+ : if (!pScratchGC)
+ : {
+ : failed = TRUE;
+ : goto failSafe;
+ : }
+ :
+ : ValidateGC(&pPix->drawable, pScratchGC);
+ : (* pScratchGC->ops->PolyFillRect)(&pPix->drawable,
+ : pScratchGC, nRects, pRects);
+ :
+ : failSafe:
+ : if (failed)
+ : {
+ : /* Censoring was not completed above. To be safe, wipe out
+ : * all the image data so that nothing trusted gets out.
+ : */
+ : bzero(pBuf, (int)(widthBytesLine * h));
+ : }
+ : if (pRects) DEALLOCATE_LOCAL(pRects);
+ : if (pScratchGC) FreeScratchGC(pScratchGC);
+ : if (pPix) FreeScratchPixmapHeader(pPix);
+ : }
+ : REGION_UNINIT(pScreen, &imageRegion);
+ : REGION_UNINIT(pScreen, &censorRegion);
+ :} /* XaceCensorImage */
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/dix/dixutils.c"
+ *
+ * 87 0.0948
+ */
+
+
+ :/***********************************************************
+ :
+ :Copyright 1987, 1998 The Open Group
+ :
+ :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.
+ :
+ :The above copyright notice and this permission notice shall be included in
+ :all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ :IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ :FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ :OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ :AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ :CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of The Open Group shall not be
+ :used in advertising or otherwise to promote the sale, use or other dealings
+ :in this Software without prior written authorization from The Open Group.
+ :
+ :
+ :Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+ :
+ : All Rights Reserved
+ :
+ :Permission to use, copy, modify, and distribute this software and its
+ :documentation for any purpose and without fee is hereby granted,
+ :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 Digital not be
+ :used in advertising or publicity pertaining to distribution of the
+ :software without specific, written prior permission.
+ :
+ :DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ :ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ :DIGITAL 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.
+ :
+ :******************************************************************/
+ :
+ :/*
+ :
+ :(c)Copyright 1988,1991 Adobe Systems Incorporated. All rights reserved.
+ :
+ :Permission to use, copy, modify, distribute, and sublicense this software and its
+ :documentation for any purpose and without fee is hereby granted, provided that
+ :the above copyright notices appear in all copies and that both those copyright
+ :notices and this permission notice appear in supporting documentation and that
+ :the name of Adobe Systems Incorporated not be used in advertising or publicity
+ :pertaining to distribution of the software without specific, written prior
+ :permission. No trademark license to use the Adobe trademarks is hereby
+ :granted. If the Adobe trademark "Display PostScript"(tm) is used to describe
+ :this software, its functionality or for any other purpose, such use shall be
+ :limited to a statement that this software works in conjunction with the Display
+ :PostScript system. Proper trademark attribution to reflect Adobe's ownership
+ :of the trademark shall be given whenever any such reference to the Display
+ :PostScript system is made.
+ :
+ :ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR ANY
+ :PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. ADOBE
+ :DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+ :WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-
+ :INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE TO YOU
+ :OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+ :DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT,NEGLIGENCE, STRICT
+ :LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ :PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT PROVIDE ANY TRAINING OR OTHER
+ :SUPPORT FOR THE SOFTWARE.
+ :
+ :Adobe, PostScript, and Display PostScript are trademarks of Adobe Systems
+ :Incorporated which may be registered in certain jurisdictions.
+ :
+ :Author: Adobe Systems Incorporated
+ :
+ :*/
+ :
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include <X11/X.h>
+ :#include <X11/Xmd.h>
+ :#include "misc.h"
+ :#include "windowstr.h"
+ :#include "dixstruct.h"
+ :#include "pixmapstr.h"
+ :#include "scrnintstr.h"
+ :#define XK_LATIN1
+ :#include <X11/keysymdef.h>
+ :#include "xace.h"
+ :
+ :/*
+ : * CompareTimeStamps returns -1, 0, or +1 depending on if the first
+ : * argument is less than, equal to or greater than the second argument.
+ : */
+ :
+ :_X_EXPORT int
+ :CompareTimeStamps(TimeStamp a, TimeStamp b)
+ :{
+ : if (a.months < b.months)
+ : return EARLIER;
+ : if (a.months > b.months)
+ : return LATER;
+ : if (a.milliseconds < b.milliseconds)
+ : return EARLIER;
+ : if (a.milliseconds > b.milliseconds)
+ : return LATER;
+ : return SAMETIME;
+ :}
+ :
+ :/*
+ : * convert client times to server TimeStamps
+ : */
+ :
+ :#define HALFMONTH ((unsigned long) 1<<31)
+ :_X_EXPORT TimeStamp
+ :ClientTimeToServerTime(CARD32 c)
+ :{
+ : TimeStamp ts;
+ : if (c == CurrentTime)
+ : return currentTime;
+ : ts.months = currentTime.months;
+ : ts.milliseconds = c;
+ : if (c > currentTime.milliseconds)
+ : {
+ : if (((unsigned long) c - currentTime.milliseconds) > HALFMONTH)
+ : ts.months -= 1;
+ : }
+ : else if (c < currentTime.milliseconds)
+ : {
+ : if (((unsigned long)currentTime.milliseconds - c) > HALFMONTH)
+ : ts.months += 1;
+ : }
+ : return ts;
+ :}
+ :
+ :/*
+ : * ISO Latin-1 case conversion routine
+ : *
+ : * this routine always null-terminates the result, so
+ : * beware of too-small buffers
+ : */
+ :
+ :static unsigned char
+ :ISOLatin1ToLower (unsigned char source)
+ :{
+ : unsigned char dest;
+ : if ((source >= XK_A) && (source <= XK_Z))
+ : dest = source + (XK_a - XK_A);
+ : else if ((source >= XK_Agrave) && (source <= XK_Odiaeresis))
+ : dest = source + (XK_agrave - XK_Agrave);
+ : else if ((source >= XK_Ooblique) && (source <= XK_Thorn))
+ : dest = source + (XK_oslash - XK_Ooblique);
+ : else
+ : dest = source;
+ : return dest;
+ :}
+ :
+ :
+ :_X_EXPORT void
+ :CopyISOLatin1Lowered(unsigned char *dest, unsigned char *source, int length)
+ :{
+ : int i;
+ :
+ : for (i = 0; i < length; i++, source++, dest++)
+ : *dest = ISOLatin1ToLower (*source);
+ : *dest = '\0';
+ :}
+ :
+ :int
+ :CompareISOLatin1Lowered(unsigned char *s1, int s1len,
+ : unsigned char *s2, int s2len)
+ 1 0.0011 :{ /* CompareISOLatin1Lowered total: 22 0.0240 */
+ : unsigned char c1, c2;
+ :
+ : for (;;)
+ : {
+ : /* note -- compare against zero so that -1 ignores len */
+ 8 0.0087 : c1 = s1len-- ? *s1++ : '\0';
+ 10 0.0109 : c2 = s2len-- ? *s2++ : '\0';
+ 3 0.0033 : if (!c1 ||
+ : (c1 != c2 &&
+ : (c1 = ISOLatin1ToLower (c1)) != (c2 = ISOLatin1ToLower (c2))))
+ : break;
+ : }
+ : return (int) c1 - (int) c2;
+ :}
+ :
+ :/*
+ : * dixLookupWindow and dixLookupDrawable:
+ : * Look up the window/drawable taking into account the client doing the
+ : * lookup, the type of drawable desired, and the type of access desired.
+ : * Return Success with *pDraw set if the window/drawable exists and the client
+ : * is allowed access, else return an error code with *pDraw set to NULL. The
+ : * access mask values are defined in resource.h. The type mask values are
+ : * defined in pixmap.h, with zero equivalent to M_DRAWABLE.
+ : */
+ :_X_EXPORT int
+ :dixLookupDrawable(DrawablePtr *pDraw, XID id, ClientPtr client,
+ : Mask type, Mask access)
+ 1 0.0011 :{ /* dixLookupDrawable total: 6 0.0065 */
+ : DrawablePtr pTmp;
+ : RESTYPE rtype;
+ : *pDraw = NULL;
+ : client->errorValue = id;
+ :
+ : if (id == INVALID)
+ : return BadDrawable;
+ :
+ : if (id == client->lastDrawableID) {
+ : pTmp = client->lastDrawable;
+ :
+ : /* an access check is required for cached drawables */
+ : rtype = (type & M_WINDOW) ? RT_WINDOW : RT_PIXMAP;
+ : if (!XaceHook(XACE_RESOURCE_ACCESS, client, id, rtype, access, pTmp))
+ : return BadDrawable;
+ : } else
+ : pTmp = (DrawablePtr)SecurityLookupIDByClass(client, id, RC_DRAWABLE,
+ : access);
+ : if (!pTmp)
+ : return BadDrawable;
+ 3 0.0033 : if (!((1 << pTmp->type) & (type ? type : M_DRAWABLE)))
+ : return BadMatch;
+ :
+ : if (type & M_DRAWABLE) {
+ : client->lastDrawable = pTmp;
+ : client->lastDrawableID = id;
+ : client->lastGCID = INVALID;
+ : client->lastGC = (GCPtr)NULL;
+ : }
+ : *pDraw = pTmp;
+ : return Success;
+ 2 0.0022 :}
+ :
+ :_X_EXPORT int
+ :dixLookupWindow(WindowPtr *pWin, XID id, ClientPtr client, Mask access)
+ :{
+ : int rc;
+ : rc = dixLookupDrawable((DrawablePtr*)pWin, id, client, M_WINDOW, access);
+ : return (rc == BadDrawable) ? BadWindow : rc;
+ :}
+ :
+ :_X_EXPORT int
+ :dixLookupGC(GCPtr *pGC, XID id, ClientPtr client, Mask access)
+ 1 0.0011 :{ /* dixLookupGC total: 2 0.0022 */
+ 1 0.0011 : GCPtr pTmp = (GCPtr)SecurityLookupIDByType(client, id, RT_GC, access);
+ : if (pTmp) {
+ : *pGC = pTmp;
+ : return Success;
+ : }
+ : client->errorValue = id;
+ : *pGC = NULL;
+ : return BadGC;
+ :}
+ :
+ :_X_EXPORT int
+ :dixLookupClient(ClientPtr *pClient, XID rid, ClientPtr client, Mask access)
+ :{
+ : pointer pRes = (pointer)SecurityLookupIDByClass(client, rid, RC_ANY,
+ : access);
+ : int clientIndex = CLIENT_ID(rid);
+ : client->errorValue = rid;
+ :
+ : if (clientIndex && pRes && clients[clientIndex] && !(rid & SERVER_BIT)) {
+ : *pClient = clients[clientIndex];
+ : return Success;
+ : }
+ : *pClient = NULL;
+ : return BadValue;
+ :}
+ :
+ :/*
+ : * These are deprecated compatibility functions and will be removed soon!
+ : * Please use the new dixLookup*() functions above.
+ : */
+ :_X_EXPORT _X_DEPRECATED WindowPtr
+ :SecurityLookupWindow(XID id, ClientPtr client, Mask access_mode)
+ :{
+ : WindowPtr pWin;
+ : int i = dixLookupWindow(&pWin, id, client, access_mode);
+ : static int warn = 1;
+ : if (warn-- > 0)
+ : ErrorF("Warning: LookupWindow()/SecurityLookupWindow() "
+ : "are deprecated. Please convert your driver/module "
+ : "to use dixLookupWindow().\n");
+ : return (i == Success) ? pWin : NULL;
+ :}
+ :
+ :_X_EXPORT _X_DEPRECATED WindowPtr
+ :LookupWindow(XID id, ClientPtr client)
+ :{
+ : return SecurityLookupWindow(id, client, DixUnknownAccess);
+ :}
+ :
+ :_X_EXPORT _X_DEPRECATED pointer
+ :SecurityLookupDrawable(XID id, ClientPtr client, Mask access_mode)
+ :{
+ : DrawablePtr pDraw;
+ : int i = dixLookupDrawable(&pDraw, id, client, M_DRAWABLE, access_mode);
+ : static int warn = 1;
+ : if (warn-- > 0)
+ : ErrorF("Warning: LookupDrawable()/SecurityLookupDrawable() "
+ : "are deprecated. Please convert your driver/module "
+ : "to use dixLookupDrawable().\n");
+ : return (i == Success) ? pDraw : NULL;
+ :}
+ :
+ :_X_EXPORT _X_DEPRECATED pointer
+ :LookupDrawable(XID id, ClientPtr client)
+ :{
+ : return SecurityLookupDrawable(id, client, DixUnknownAccess);
+ :}
+ :
+ :_X_EXPORT _X_DEPRECATED ClientPtr
+ :LookupClient(XID id, ClientPtr client)
+ :{
+ : ClientPtr pClient;
+ : int i = dixLookupClient(&pClient, id, client, DixUnknownAccess);
+ : static int warn = 1;
+ : if (warn-- > 0)
+ : ErrorF("Warning: LookupClient() is deprecated. Please convert your "
+ : "driver/module to use dixLookupClient().\n");
+ : return (i == Success) ? pClient : NULL;
+ :}
+ :
+ :/* end deprecated functions */
+ :
+ :int
+ :AlterSaveSetForClient(ClientPtr client, WindowPtr pWin, unsigned mode,
+ : Bool toRoot, Bool remap)
+ :{
+ : int numnow;
+ : SaveSetElt *pTmp = NULL;
+ : int j;
+ :
+ : numnow = client->numSaved;
+ : j = 0;
+ : if (numnow)
+ : {
+ : pTmp = client->saveSet;
+ : while ((j < numnow) && (SaveSetWindow(pTmp[j]) != (pointer)pWin))
+ : j++;
+ : }
+ : if (mode == SetModeInsert)
+ : {
+ : if (j < numnow) /* duplicate */
+ : return(Success);
+ : numnow++;
+ : pTmp = (SaveSetElt *)xrealloc(client->saveSet, sizeof(*pTmp) * numnow);
+ : if (!pTmp)
+ : return(BadAlloc);
+ : client->saveSet = pTmp;
+ : client->numSaved = numnow;
+ : SaveSetAssignWindow(client->saveSet[numnow - 1], pWin);
+ : SaveSetAssignToRoot(client->saveSet[numnow - 1], toRoot);
+ : SaveSetAssignRemap(client->saveSet[numnow - 1], remap);
+ : return(Success);
+ : }
+ : else if ((mode == SetModeDelete) && (j < numnow))
+ : {
+ : while (j < numnow-1)
+ : {
+ : pTmp[j] = pTmp[j+1];
+ : j++;
+ : }
+ : numnow--;
+ : if (numnow)
+ : {
+ : pTmp = (SaveSetElt *)xrealloc(client->saveSet, sizeof(*pTmp) * numnow);
+ : if (pTmp)
+ : client->saveSet = pTmp;
+ : }
+ : else
+ : {
+ : xfree(client->saveSet);
+ : client->saveSet = (SaveSetElt *)NULL;
+ : }
+ : client->numSaved = numnow;
+ : return(Success);
+ : }
+ : return(Success);
+ :}
+ :
+ :void
+ :DeleteWindowFromAnySaveSet(WindowPtr pWin)
+ :{
+ : int i;
+ : ClientPtr client;
+ :
+ : for (i = 0; i< currentMaxClients; i++)
+ : {
+ : client = clients[i];
+ : if (client && client->numSaved)
+ : (void)AlterSaveSetForClient(client, pWin, SetModeDelete, FALSE, TRUE);
+ : }
+ :}
+ :
+ :/* No-op Don't Do Anything : sometimes we need to be able to call a procedure
+ : * that doesn't do anything. For example, on screen with only static
+ : * colormaps, if someone calls install colormap, it's easier to have a dummy
+ : * procedure to call than to check if there's a procedure
+ : */
+ :_X_EXPORT void
+ :NoopDDA(void)
+ :{
+ :}
+ :
+ :typedef struct _BlockHandler {
+ : BlockHandlerProcPtr BlockHandler;
+ : WakeupHandlerProcPtr WakeupHandler;
+ : pointer blockData;
+ : Bool deleted;
+ :} BlockHandlerRec, *BlockHandlerPtr;
+ :
+ :static BlockHandlerPtr handlers;
+ :static int numHandlers;
+ :static int sizeHandlers;
+ :static Bool inHandler;
+ :static Bool handlerDeleted;
+ :
+ :/**
+ : *
+ : * \param pTimeout DIX doesn't want to know how OS represents time
+ : * \param pReadMask nor how it represents the det of descriptors
+ : */
+ :void
+ :BlockHandler(pointer pTimeout, pointer pReadmask)
+ :{
+ : int i, j;
+ :
+ : ++inHandler;
+ : for (i = 0; i < screenInfo.numScreens; i++)
+ : (* screenInfo.screens[i]->BlockHandler)(i,
+ : screenInfo.screens[i]->blockData,
+ : pTimeout, pReadmask);
+ : for (i = 0; i < numHandlers; i++)
+ : (*handlers[i].BlockHandler) (handlers[i].blockData,
+ : pTimeout, pReadmask);
+ : if (handlerDeleted)
+ : {
+ : for (i = 0; i < numHandlers;)
+ : if (handlers[i].deleted)
+ : {
+ : for (j = i; j < numHandlers - 1; j++)
+ : handlers[j] = handlers[j+1];
+ : numHandlers--;
+ : }
+ : else
+ : i++;
+ : handlerDeleted = FALSE;
+ : }
+ : --inHandler;
+ :}
+ :
+ :/**
+ : *
+ : * \param result 32 bits of undefined result from the wait
+ : * \param pReadmask the resulting descriptor mask
+ : */
+ :void
+ :WakeupHandler(int result, pointer pReadmask)
+ :{
+ : int i, j;
+ :
+ : ++inHandler;
+ : for (i = numHandlers - 1; i >= 0; i--)
+ : (*handlers[i].WakeupHandler) (handlers[i].blockData,
+ : result, pReadmask);
+ : for (i = 0; i < screenInfo.numScreens; i++)
+ : (* screenInfo.screens[i]->WakeupHandler)(i,
+ : screenInfo.screens[i]->wakeupData,
+ : result, pReadmask);
+ : if (handlerDeleted)
+ : {
+ : for (i = 0; i < numHandlers;)
+ : if (handlers[i].deleted)
+ : {
+ : for (j = i; j < numHandlers - 1; j++)
+ : handlers[j] = handlers[j+1];
+ : numHandlers--;
+ : }
+ : else
+ : i++;
+ : handlerDeleted = FALSE;
+ : }
+ : --inHandler;
+ :}
+ :
+ :/**
+ : * Reentrant with BlockHandler and WakeupHandler, except wakeup won't
+ : * get called until next time
+ : */
+ :_X_EXPORT Bool
+ :RegisterBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler,
+ : WakeupHandlerProcPtr wakeupHandler,
+ : pointer blockData)
+ :{
+ : BlockHandlerPtr new;
+ :
+ : if (numHandlers >= sizeHandlers)
+ : {
+ : new = (BlockHandlerPtr) xrealloc (handlers, (numHandlers + 1) *
+ : sizeof (BlockHandlerRec));
+ : if (!new)
+ : return FALSE;
+ : handlers = new;
+ : sizeHandlers = numHandlers + 1;
+ : }
+ : handlers[numHandlers].BlockHandler = blockHandler;
+ : handlers[numHandlers].WakeupHandler = wakeupHandler;
+ : handlers[numHandlers].blockData = blockData;
+ : handlers[numHandlers].deleted = FALSE;
+ : numHandlers = numHandlers + 1;
+ : return TRUE;
+ :}
+ :
+ :_X_EXPORT void
+ :RemoveBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler,
+ : WakeupHandlerProcPtr wakeupHandler,
+ : pointer blockData)
+ :{
+ : int i;
+ :
+ : for (i = 0; i < numHandlers; i++)
+ : if (handlers[i].BlockHandler == blockHandler &&
+ : handlers[i].WakeupHandler == wakeupHandler &&
+ : handlers[i].blockData == blockData)
+ : {
+ : if (inHandler)
+ : {
+ : handlerDeleted = TRUE;
+ : handlers[i].deleted = TRUE;
+ : }
+ : else
+ : {
+ : for (; i < numHandlers - 1; i++)
+ : handlers[i] = handlers[i+1];
+ : numHandlers--;
+ : }
+ : break;
+ : }
+ :}
+ :
+ :void
+ :InitBlockAndWakeupHandlers (void)
+ :{
+ : xfree (handlers);
+ : handlers = (BlockHandlerPtr) 0;
+ : numHandlers = 0;
+ : sizeHandlers = 0;
+ :}
+ :
+ :/*
+ : * A general work queue. Perform some task before the server
+ : * sleeps for input.
+ : */
+ :
+ :WorkQueuePtr workQueue;
+ :static WorkQueuePtr *workQueueLast = &workQueue;
+ :
+ :void
+ :ProcessWorkQueue(void)
+ :{
+ : WorkQueuePtr q, *p;
+ :
+ : p = &workQueue;
+ : /*
+ : * Scan the work queue once, calling each function. Those
+ : * which return TRUE are removed from the queue, otherwise
+ : * they will be called again. This must be reentrant with
+ : * QueueWorkProc.
+ : */
+ : while ((q = *p))
+ : {
+ : if ((*q->function) (q->client, q->closure))
+ : {
+ : /* remove q from the list */
+ : *p = q->next; /* don't fetch until after func called */
+ : xfree (q);
+ : }
+ : else
+ : {
+ : p = &q->next; /* don't fetch until after func called */
+ : }
+ : }
+ : workQueueLast = p;
+ :}
+ :
+ :void
+ :ProcessWorkQueueZombies(void)
+ :{
+ : WorkQueuePtr q, *p;
+ :
+ : p = &workQueue;
+ : while ((q = *p))
+ : {
+ : if (q->client && q->client->clientGone)
+ : {
+ : (void) (*q->function) (q->client, q->closure);
+ : /* remove q from the list */
+ : *p = q->next; /* don't fetch until after func called */
+ : xfree (q);
+ : }
+ : else
+ : {
+ : p = &q->next; /* don't fetch until after func called */
+ : }
+ : }
+ : workQueueLast = p;
+ :}
+ :
+ :_X_EXPORT Bool
+ :QueueWorkProc (
+ : Bool (*function)(ClientPtr /* pClient */, pointer /* closure */),
+ : ClientPtr client, pointer closure)
+ :{
+ : WorkQueuePtr q;
+ :
+ : q = (WorkQueuePtr) xalloc (sizeof *q);
+ : if (!q)
+ : return FALSE;
+ : q->function = function;
+ : q->client = client;
+ : q->closure = closure;
+ : q->next = NULL;
+ : *workQueueLast = q;
+ : workQueueLast = &q->next;
+ : return TRUE;
+ :}
+ :
+ :/*
+ : * Manage a queue of sleeping clients, awakening them
+ : * when requested, by using the OS functions IgnoreClient
+ : * and AttendClient. Note that this *ignores* the troubles
+ : * with request data interleaving itself with events, but
+ : * we'll leave that until a later time.
+ : */
+ :
+ :typedef struct _SleepQueue {
+ : struct _SleepQueue *next;
+ : ClientPtr client;
+ : ClientSleepProcPtr function;
+ : pointer closure;
+ :} SleepQueueRec, *SleepQueuePtr;
+ :
+ :static SleepQueuePtr sleepQueue = NULL;
+ :
+ :_X_EXPORT Bool
+ :ClientSleep (ClientPtr client, ClientSleepProcPtr function, pointer closure)
+ :{
+ : SleepQueuePtr q;
+ :
+ : q = (SleepQueuePtr) xalloc (sizeof *q);
+ : if (!q)
+ : return FALSE;
+ :
+ : IgnoreClient (client);
+ : q->next = sleepQueue;
+ : q->client = client;
+ : q->function = function;
+ : q->closure = closure;
+ : sleepQueue = q;
+ : return TRUE;
+ :}
+ :
+ :Bool
+ :ClientSignal (ClientPtr client)
+ :{
+ : SleepQueuePtr q;
+ :
+ : for (q = sleepQueue; q; q = q->next)
+ : if (q->client == client)
+ : {
+ : return QueueWorkProc (q->function, q->client, q->closure);
+ : }
+ : return FALSE;
+ :}
+ :
+ :_X_EXPORT void
+ :ClientWakeup (ClientPtr client)
+ :{
+ : SleepQueuePtr q, *prev;
+ :
+ : prev = &sleepQueue;
+ : while ( (q = *prev) )
+ : {
+ : if (q->client == client)
+ : {
+ : *prev = q->next;
+ : xfree (q);
+ : if (client->clientGone)
+ : /* Oops -- new zombie cleanup code ensures this only
+ : * happens from inside CloseDownClient; don't want to
+ : * recurse here...
+ : */
+ : /* CloseDownClient(client) */;
+ : else
+ : AttendClient (client);
+ : break;
+ : }
+ : prev = &q->next;
+ : }
+ :}
+ :
+ :Bool
+ :ClientIsAsleep (ClientPtr client)
+ :{
+ : SleepQueuePtr q;
+ :
+ : for (q = sleepQueue; q; q = q->next)
+ : if (q->client == client)
+ : return TRUE;
+ : return FALSE;
+ :}
+ :
+ :/*
+ : * Generic Callback Manager
+ : */
+ :
+ :/* ===== Private Procedures ===== */
+ :
+ :static int numCallbackListsToCleanup = 0;
+ :static CallbackListPtr **listsToCleanup = NULL;
+ :
+ :static Bool
+ :_AddCallback(
+ : CallbackListPtr *pcbl,
+ : CallbackProcPtr callback,
+ : pointer data)
+ :{
+ : CallbackPtr cbr;
+ :
+ : cbr = (CallbackPtr) xalloc(sizeof(CallbackRec));
+ : if (!cbr)
+ : return FALSE;
+ : cbr->proc = callback;
+ : cbr->data = data;
+ : cbr->next = (*pcbl)->list;
+ : cbr->deleted = FALSE;
+ : (*pcbl)->list = cbr;
+ : return TRUE;
+ :}
+ :
+ :static Bool
+ :_DeleteCallback(
+ : CallbackListPtr *pcbl,
+ : CallbackProcPtr callback,
+ : pointer data)
+ :{
+ : CallbackListPtr cbl = *pcbl;
+ : CallbackPtr cbr, pcbr;
+ :
+ : for (pcbr = NULL, cbr = cbl->list;
+ : cbr != NULL;
+ : pcbr = cbr, cbr = cbr->next)
+ : {
+ : if ((cbr->proc == callback) && (cbr->data == data))
+ : break;
+ : }
+ : if (cbr != NULL)
+ : {
+ : if (cbl->inCallback)
+ : {
+ : ++(cbl->numDeleted);
+ : cbr->deleted = TRUE;
+ : }
+ : else
+ : {
+ : if (pcbr == NULL)
+ : cbl->list = cbr->next;
+ : else
+ : pcbr->next = cbr->next;
+ : xfree(cbr);
+ : }
+ : return TRUE;
+ : }
+ : return FALSE;
+ :}
+ :
+ :static void
+ :_CallCallbacks(
+ : CallbackListPtr *pcbl,
+ : pointer call_data)
+ 17 0.0185 :{ /* _CallCallbacks total: 30 0.0327 */
+ : CallbackListPtr cbl = *pcbl;
+ : CallbackPtr cbr, pcbr;
+ :
+ 3 0.0033 : ++(cbl->inCallback);
+ 3 0.0033 : for (cbr = cbl->list; cbr != NULL; cbr = cbr->next)
+ : {
+ 6 0.0065 : (*(cbr->proc)) (pcbl, cbr->data, call_data);
+ : }
+ : --(cbl->inCallback);
+ :
+ : if (cbl->inCallback) return;
+ :
+ : /* Was the entire list marked for deletion? */
+ :
+ 1 0.0011 : if (cbl->deleted)
+ : {
+ : DeleteCallbackList(pcbl);
+ : return;
+ : }
+ :
+ : /* Were some individual callbacks on the list marked for deletion?
+ : * If so, do the deletions.
+ : */
+ :
+ : if (cbl->numDeleted)
+ : {
+ : for (pcbr = NULL, cbr = cbl->list; (cbr != NULL) && cbl->numDeleted; )
+ : {
+ : if (cbr->deleted)
+ : {
+ : if (pcbr)
+ : {
+ : cbr = cbr->next;
+ : xfree(pcbr->next);
+ : pcbr->next = cbr;
+ : } else
+ : {
+ : cbr = cbr->next;
+ : xfree(cbl->list);
+ : cbl->list = cbr;
+ : }
+ : cbl->numDeleted--;
+ : }
+ : else /* this one wasn't deleted */
+ : {
+ : pcbr = cbr;
+ : cbr = cbr->next;
+ : }
+ : }
+ : }
+ :}
+ :
+ :static void
+ :_DeleteCallbackList(
+ : CallbackListPtr *pcbl)
+ :{
+ : CallbackListPtr cbl = *pcbl;
+ : CallbackPtr cbr, nextcbr;
+ : int i;
+ :
+ : if (cbl->inCallback)
+ : {
+ : cbl->deleted = TRUE;
+ : return;
+ : }
+ :
+ : for (i = 0; i < numCallbackListsToCleanup; i++)
+ : {
+ : if ((listsToCleanup[i] = pcbl) != 0)
+ : {
+ : listsToCleanup[i] = NULL;
+ : break;
+ : }
+ : }
+ :
+ : for (cbr = cbl->list; cbr != NULL; cbr = nextcbr)
+ : {
+ : nextcbr = cbr->next;
+ : xfree(cbr);
+ : }
+ : xfree(cbl);
+ : *pcbl = NULL;
+ :}
+ :
+ :static CallbackFuncsRec default_cbfuncs =
+ :{
+ : _AddCallback,
+ : _DeleteCallback,
+ : _CallCallbacks,
+ : _DeleteCallbackList
+ :};
+ :
+ :static Bool
+ :CreateCallbackList(CallbackListPtr *pcbl, CallbackFuncsPtr cbfuncs)
+ :{
+ : CallbackListPtr cbl;
+ : int i;
+ :
+ : if (!pcbl) return FALSE;
+ : cbl = (CallbackListPtr) xalloc(sizeof(CallbackListRec));
+ : if (!cbl) return FALSE;
+ : cbl->funcs = cbfuncs ? *cbfuncs : default_cbfuncs;
+ : cbl->inCallback = 0;
+ : cbl->deleted = FALSE;
+ : cbl->numDeleted = 0;
+ : cbl->list = NULL;
+ : *pcbl = cbl;
+ :
+ : for (i = 0; i < numCallbackListsToCleanup; i++)
+ : {
+ : if (!listsToCleanup[i])
+ : {
+ : listsToCleanup[i] = pcbl;
+ : return TRUE;
+ : }
+ : }
+ :
+ : listsToCleanup = (CallbackListPtr **)xnfrealloc(listsToCleanup,
+ : sizeof(CallbackListPtr *) * (numCallbackListsToCleanup+1));
+ : listsToCleanup[numCallbackListsToCleanup] = pcbl;
+ : numCallbackListsToCleanup++;
+ : return TRUE;
+ :}
+ :
+ :/* ===== Public Procedures ===== */
+ :
+ :_X_EXPORT Bool
+ :AddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data)
+ :{
+ : if (!pcbl) return FALSE;
+ : if (!*pcbl)
+ : { /* list hasn't been created yet; go create it */
+ : if (!CreateCallbackList(pcbl, (CallbackFuncsPtr)NULL))
+ : return FALSE;
+ : }
+ : return ((*(*pcbl)->funcs.AddCallback) (pcbl, callback, data));
+ :}
+ :
+ :_X_EXPORT Bool
+ :DeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data)
+ :{
+ : if (!pcbl || !*pcbl) return FALSE;
+ : return ((*(*pcbl)->funcs.DeleteCallback) (pcbl, callback, data));
+ :}
+ :
+ :void
+ :CallCallbacks(CallbackListPtr *pcbl, pointer call_data)
+ 6 0.0065 :{ /* CallCallbacks total: 27 0.0294 */
+ 10 0.0109 : if (!pcbl || !*pcbl) return;
+ 5 0.0054 : (*(*pcbl)->funcs.CallCallbacks) (pcbl, call_data);
+ 6 0.0065 :}
+ :
+ :void
+ :DeleteCallbackList(CallbackListPtr *pcbl)
+ :{
+ : if (!pcbl || !*pcbl) return;
+ : (*(*pcbl)->funcs.DeleteCallbackList) (pcbl);
+ :}
+ :
+ :void
+ :InitCallbackManager(void)
+ :{
+ : int i;
+ :
+ : for (i = 0; i < numCallbackListsToCleanup; i++)
+ : {
+ : DeleteCallbackList(listsToCleanup[i]);
+ : }
+ : if (listsToCleanup) xfree(listsToCleanup);
+ :
+ : numCallbackListsToCleanup = 0;
+ : listsToCleanup = NULL;
+ :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/render/render.c"
+ *
+ * 81 0.0882
+ */
+
+
+ :/*
+ : *
+ : * Copyright © 2000 SuSE, Inc.
+ : *
+ : * 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 SuSE not be used in advertising or
+ : * publicity pertaining to distribution of the software without specific,
+ : * written prior permission. SuSE makes no representations about the
+ : * suitability of this software for any purpose. It is provided "as is"
+ : * without express or implied warranty.
+ : *
+ : * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ : * 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: Keith Packard, SuSE, Inc.
+ : */
+ :
+ :#define NEED_REPLIES
+ :#define NEED_EVENTS
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include <X11/X.h>
+ :#include <X11/Xproto.h>
+ :#include "misc.h"
+ :#include "os.h"
+ :#include "dixstruct.h"
+ :#include "resource.h"
+ :#include "scrnintstr.h"
+ :#include "windowstr.h"
+ :#include "pixmapstr.h"
+ :#include "colormapst.h"
+ :#include "extnsionst.h"
+ :#include "servermd.h"
+ :#include <X11/extensions/render.h>
+ :#include <X11/extensions/renderproto.h>
+ :#include "picturestr.h"
+ :#include "glyphstr.h"
+ :#include <X11/Xfuncproto.h>
+ :#include "cursorstr.h"
+ :
+ :#if HAVE_STDINT_H
+ :#include <stdint.h>
+ :#elif !defined(UINT32_MAX)
+ :#define UINT32_MAX 0xffffffffU
+ :#endif
+ :
+ :static int ProcRenderQueryVersion (ClientPtr pClient);
+ :static int ProcRenderQueryPictFormats (ClientPtr pClient);
+ :static int ProcRenderQueryPictIndexValues (ClientPtr pClient);
+ :static int ProcRenderQueryDithers (ClientPtr pClient);
+ :static int ProcRenderCreatePicture (ClientPtr pClient);
+ :static int ProcRenderChangePicture (ClientPtr pClient);
+ :static int ProcRenderSetPictureClipRectangles (ClientPtr pClient);
+ :static int ProcRenderFreePicture (ClientPtr pClient);
+ :static int ProcRenderComposite (ClientPtr pClient);
+ :static int ProcRenderScale (ClientPtr pClient);
+ :static int ProcRenderTrapezoids (ClientPtr pClient);
+ :static int ProcRenderTriangles (ClientPtr pClient);
+ :static int ProcRenderTriStrip (ClientPtr pClient);
+ :static int ProcRenderTriFan (ClientPtr pClient);
+ :static int ProcRenderColorTrapezoids (ClientPtr pClient);
+ :static int ProcRenderColorTriangles (ClientPtr pClient);
+ :static int ProcRenderTransform (ClientPtr pClient);
+ :static int ProcRenderCreateGlyphSet (ClientPtr pClient);
+ :static int ProcRenderReferenceGlyphSet (ClientPtr pClient);
+ :static int ProcRenderFreeGlyphSet (ClientPtr pClient);
+ :static int ProcRenderAddGlyphs (ClientPtr pClient);
+ :static int ProcRenderAddGlyphsFromPicture (ClientPtr pClient);
+ :static int ProcRenderFreeGlyphs (ClientPtr pClient);
+ :static int ProcRenderCompositeGlyphs (ClientPtr pClient);
+ :static int ProcRenderFillRectangles (ClientPtr pClient);
+ :static int ProcRenderCreateCursor (ClientPtr pClient);
+ :static int ProcRenderSetPictureTransform (ClientPtr pClient);
+ :static int ProcRenderQueryFilters (ClientPtr pClient);
+ :static int ProcRenderSetPictureFilter (ClientPtr pClient);
+ :static int ProcRenderCreateAnimCursor (ClientPtr pClient);
+ :static int ProcRenderAddTraps (ClientPtr pClient);
+ :static int ProcRenderCreateSolidFill (ClientPtr pClient);
+ :static int ProcRenderCreateLinearGradient (ClientPtr pClient);
+ :static int ProcRenderCreateRadialGradient (ClientPtr pClient);
+ :static int ProcRenderCreateConicalGradient (ClientPtr pClient);
+ :
+ :static int ProcRenderDispatch (ClientPtr pClient);
+ :
+ :static int SProcRenderQueryVersion (ClientPtr pClient);
+ :static int SProcRenderQueryPictFormats (ClientPtr pClient);
+ :static int SProcRenderQueryPictIndexValues (ClientPtr pClient);
+ :static int SProcRenderQueryDithers (ClientPtr pClient);
+ :static int SProcRenderCreatePicture (ClientPtr pClient);
+ :static int SProcRenderChangePicture (ClientPtr pClient);
+ :static int SProcRenderSetPictureClipRectangles (ClientPtr pClient);
+ :static int SProcRenderFreePicture (ClientPtr pClient);
+ :static int SProcRenderComposite (ClientPtr pClient);
+ :static int SProcRenderScale (ClientPtr pClient);
+ :static int SProcRenderTrapezoids (ClientPtr pClient);
+ :static int SProcRenderTriangles (ClientPtr pClient);
+ :static int SProcRenderTriStrip (ClientPtr pClient);
+ :static int SProcRenderTriFan (ClientPtr pClient);
+ :static int SProcRenderColorTrapezoids (ClientPtr pClient);
+ :static int SProcRenderColorTriangles (ClientPtr pClient);
+ :static int SProcRenderTransform (ClientPtr pClient);
+ :static int SProcRenderCreateGlyphSet (ClientPtr pClient);
+ :static int SProcRenderReferenceGlyphSet (ClientPtr pClient);
+ :static int SProcRenderFreeGlyphSet (ClientPtr pClient);
+ :static int SProcRenderAddGlyphs (ClientPtr pClient);
+ :static int SProcRenderAddGlyphsFromPicture (ClientPtr pClient);
+ :static int SProcRenderFreeGlyphs (ClientPtr pClient);
+ :static int SProcRenderCompositeGlyphs (ClientPtr pClient);
+ :static int SProcRenderFillRectangles (ClientPtr pClient);
+ :static int SProcRenderCreateCursor (ClientPtr pClient);
+ :static int SProcRenderSetPictureTransform (ClientPtr pClient);
+ :static int SProcRenderQueryFilters (ClientPtr pClient);
+ :static int SProcRenderSetPictureFilter (ClientPtr pClient);
+ :static int SProcRenderCreateAnimCursor (ClientPtr pClient);
+ :static int SProcRenderAddTraps (ClientPtr pClient);
+ :static int SProcRenderCreateSolidFill (ClientPtr pClient);
+ :static int SProcRenderCreateLinearGradient (ClientPtr pClient);
+ :static int SProcRenderCreateRadialGradient (ClientPtr pClient);
+ :static int SProcRenderCreateConicalGradient (ClientPtr pClient);
+ :
+ :static int SProcRenderDispatch (ClientPtr pClient);
+ :
+ :int (*ProcRenderVector[RenderNumberRequests])(ClientPtr) = {
+ : ProcRenderQueryVersion,
+ : ProcRenderQueryPictFormats,
+ : ProcRenderQueryPictIndexValues,
+ : ProcRenderQueryDithers,
+ : ProcRenderCreatePicture,
+ : ProcRenderChangePicture,
+ : ProcRenderSetPictureClipRectangles,
+ : ProcRenderFreePicture,
+ : ProcRenderComposite,
+ : ProcRenderScale,
+ : ProcRenderTrapezoids,
+ : ProcRenderTriangles,
+ : ProcRenderTriStrip,
+ : ProcRenderTriFan,
+ : ProcRenderColorTrapezoids,
+ : ProcRenderColorTriangles,
+ : ProcRenderTransform,
+ : ProcRenderCreateGlyphSet,
+ : ProcRenderReferenceGlyphSet,
+ : ProcRenderFreeGlyphSet,
+ : ProcRenderAddGlyphs,
+ : ProcRenderAddGlyphsFromPicture,
+ : ProcRenderFreeGlyphs,
+ : ProcRenderCompositeGlyphs,
+ : ProcRenderCompositeGlyphs,
+ : ProcRenderCompositeGlyphs,
+ : ProcRenderFillRectangles,
+ : ProcRenderCreateCursor,
+ : ProcRenderSetPictureTransform,
+ : ProcRenderQueryFilters,
+ : ProcRenderSetPictureFilter,
+ : ProcRenderCreateAnimCursor,
+ : ProcRenderAddTraps,
+ : ProcRenderCreateSolidFill,
+ : ProcRenderCreateLinearGradient,
+ : ProcRenderCreateRadialGradient,
+ : ProcRenderCreateConicalGradient
+ :};
+ :
+ :int (*SProcRenderVector[RenderNumberRequests])(ClientPtr) = {
+ : SProcRenderQueryVersion,
+ : SProcRenderQueryPictFormats,
+ : SProcRenderQueryPictIndexValues,
+ : SProcRenderQueryDithers,
+ : SProcRenderCreatePicture,
+ : SProcRenderChangePicture,
+ : SProcRenderSetPictureClipRectangles,
+ : SProcRenderFreePicture,
+ : SProcRenderComposite,
+ : SProcRenderScale,
+ : SProcRenderTrapezoids,
+ : SProcRenderTriangles,
+ : SProcRenderTriStrip,
+ : SProcRenderTriFan,
+ : SProcRenderColorTrapezoids,
+ : SProcRenderColorTriangles,
+ : SProcRenderTransform,
+ : SProcRenderCreateGlyphSet,
+ : SProcRenderReferenceGlyphSet,
+ : SProcRenderFreeGlyphSet,
+ : SProcRenderAddGlyphs,
+ : SProcRenderAddGlyphsFromPicture,
+ : SProcRenderFreeGlyphs,
+ : SProcRenderCompositeGlyphs,
+ : SProcRenderCompositeGlyphs,
+ : SProcRenderCompositeGlyphs,
+ : SProcRenderFillRectangles,
+ : SProcRenderCreateCursor,
+ : SProcRenderSetPictureTransform,
+ : SProcRenderQueryFilters,
+ : SProcRenderSetPictureFilter,
+ : SProcRenderCreateAnimCursor,
+ : SProcRenderAddTraps,
+ : SProcRenderCreateSolidFill,
+ : SProcRenderCreateLinearGradient,
+ : SProcRenderCreateRadialGradient,
+ : SProcRenderCreateConicalGradient
+ :};
+ :
+ :static void
+ :RenderResetProc (ExtensionEntry *extEntry);
+ :
+ :#if 0
+ :static CARD8 RenderReqCode;
+ :#endif
+ :int RenderErrBase;
+ :int RenderClientPrivateIndex;
+ :
+ :typedef struct _RenderClient {
+ : int major_version;
+ : int minor_version;
+ :} RenderClientRec, *RenderClientPtr;
+ :
+ :#define GetRenderClient(pClient) ((RenderClientPtr) (pClient)->devPrivates[RenderClientPrivateIndex].ptr)
+ :
+ :static void
+ :RenderClientCallback (CallbackListPtr *list,
+ : pointer closure,
+ : pointer data)
+ :{
+ : NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
+ : ClientPtr pClient = clientinfo->client;
+ : RenderClientPtr pRenderClient = GetRenderClient (pClient);
+ :
+ : pRenderClient->major_version = 0;
+ : pRenderClient->minor_version = 0;
+ :}
+ :
+ :void
+ :RenderExtensionInit (void)
+ :{
+ : ExtensionEntry *extEntry;
+ :
+ : if (!PictureType)
+ : return;
+ : if (!PictureFinishInit ())
+ : return;
+ : RenderClientPrivateIndex = AllocateClientPrivateIndex ();
+ : if (!AllocateClientPrivate (RenderClientPrivateIndex,
+ : sizeof (RenderClientRec)))
+ : return;
+ : if (!AddCallback (&ClientStateCallback, RenderClientCallback, 0))
+ : return;
+ :
+ : extEntry = AddExtension (RENDER_NAME, 0, RenderNumberErrors,
+ : ProcRenderDispatch, SProcRenderDispatch,
+ : RenderResetProc, StandardMinorOpcode);
+ : if (!extEntry)
+ : return;
+ :#if 0
+ : RenderReqCode = (CARD8) extEntry->base;
+ :#endif
+ : RenderErrBase = extEntry->errorBase;
+ :}
+ :
+ :static void
+ :RenderResetProc (ExtensionEntry *extEntry)
+ :{
+ : ResetPicturePrivateIndex();
+ : ResetGlyphSetPrivateIndex();
+ :}
+ :
+ :static int
+ :ProcRenderQueryVersion (ClientPtr client)
+ :{
+ : RenderClientPtr pRenderClient = GetRenderClient (client);
+ : xRenderQueryVersionReply rep;
+ : register int n;
+ : REQUEST(xRenderQueryVersionReq);
+ :
+ : pRenderClient->major_version = stuff->majorVersion;
+ : pRenderClient->minor_version = stuff->minorVersion;
+ :
+ : REQUEST_SIZE_MATCH(xRenderQueryVersionReq);
+ : rep.type = X_Reply;
+ : rep.length = 0;
+ : rep.sequenceNumber = client->sequence;
+ : rep.majorVersion = RENDER_MAJOR;
+ : rep.minorVersion = RENDER_MINOR;
+ : if (client->swapped) {
+ : swaps(&rep.sequenceNumber, n);
+ : swapl(&rep.length, n);
+ : swapl(&rep.majorVersion, n);
+ : swapl(&rep.minorVersion, n);
+ : }
+ : WriteToClient(client, sizeof(xRenderQueryVersionReply), (char *)&rep);
+ : return (client->noClientException);
+ :}
+ :
+ :#if 0
+ :static int
+ :VisualDepth (ScreenPtr pScreen, VisualPtr pVisual)
+ :{
+ : DepthPtr pDepth;
+ : int d, v;
+ :
+ : for (d = 0; d < pScreen->numDepths; d++)
+ : {
+ : pDepth = pScreen->allowedDepths + d;
+ : for (v = 0; v < pDepth->numVids; v++)
+ : {
+ : if (pDepth->vids[v] == pVisual->vid)
+ : return pDepth->depth;
+ : }
+ : }
+ : return 0;
+ :}
+ :#endif
+ :
+ :static VisualPtr
+ :findVisual (ScreenPtr pScreen, VisualID vid)
+ :{
+ : VisualPtr pVisual;
+ : int v;
+ :
+ : for (v = 0; v < pScreen->numVisuals; v++)
+ : {
+ : pVisual = pScreen->visuals + v;
+ : if (pVisual->vid == vid)
+ : return pVisual;
+ : }
+ : return 0;
+ :}
+ :
+ :extern char *ConnectionInfo;
+ :
+ :static int
+ :ProcRenderQueryPictFormats (ClientPtr client)
+ :{
+ : RenderClientPtr pRenderClient = GetRenderClient (client);
+ : xRenderQueryPictFormatsReply *reply;
+ : xPictScreen *pictScreen;
+ : xPictDepth *pictDepth;
+ : xPictVisual *pictVisual;
+ : xPictFormInfo *pictForm;
+ : CARD32 *pictSubpixel;
+ : ScreenPtr pScreen;
+ : VisualPtr pVisual;
+ : DepthPtr pDepth;
+ : int v, d;
+ : PictureScreenPtr ps;
+ : PictFormatPtr pFormat;
+ : int nformat;
+ : int ndepth;
+ : int nvisual;
+ : int rlength;
+ : int s;
+ : int n;
+ : int numScreens;
+ : int numSubpixel;
+ :/* REQUEST(xRenderQueryPictFormatsReq); */
+ :
+ : REQUEST_SIZE_MATCH(xRenderQueryPictFormatsReq);
+ :
+ :#ifdef PANORAMIX
+ : if (noPanoramiXExtension)
+ : numScreens = screenInfo.numScreens;
+ : else
+ : numScreens = ((xConnSetup *)ConnectionInfo)->numRoots;
+ :#else
+ : numScreens = screenInfo.numScreens;
+ :#endif
+ : ndepth = nformat = nvisual = 0;
+ : for (s = 0; s < numScreens; s++)
+ : {
+ : pScreen = screenInfo.screens[s];
+ : for (d = 0; d < pScreen->numDepths; d++)
+ : {
+ : pDepth = pScreen->allowedDepths + d;
+ : ++ndepth;
+ :
+ : for (v = 0; v < pDepth->numVids; v++)
+ : {
+ : pVisual = findVisual (pScreen, pDepth->vids[v]);
+ : if (pVisual && PictureMatchVisual (pScreen, pDepth->depth, pVisual))
+ : ++nvisual;
+ : }
+ : }
+ : ps = GetPictureScreenIfSet(pScreen);
+ : if (ps)
+ : nformat += ps->nformats;
+ : }
+ : if (pRenderClient->major_version == 0 && pRenderClient->minor_version < 6)
+ : numSubpixel = 0;
+ : else
+ : numSubpixel = numScreens;
+ :
+ : rlength = (sizeof (xRenderQueryPictFormatsReply) +
+ : nformat * sizeof (xPictFormInfo) +
+ : numScreens * sizeof (xPictScreen) +
+ : ndepth * sizeof (xPictDepth) +
+ : nvisual * sizeof (xPictVisual) +
+ : numSubpixel * sizeof (CARD32));
+ : reply = (xRenderQueryPictFormatsReply *) xalloc (rlength);
+ : if (!reply)
+ : return BadAlloc;
+ : reply->type = X_Reply;
+ : reply->sequenceNumber = client->sequence;
+ : reply->length = (rlength - sizeof(xGenericReply)) >> 2;
+ : reply->numFormats = nformat;
+ : reply->numScreens = numScreens;
+ : reply->numDepths = ndepth;
+ : reply->numVisuals = nvisual;
+ : reply->numSubpixel = numSubpixel;
+ :
+ : pictForm = (xPictFormInfo *) (reply + 1);
+ :
+ : for (s = 0; s < numScreens; s++)
+ : {
+ : pScreen = screenInfo.screens[s];
+ : ps = GetPictureScreenIfSet(pScreen);
+ : if (ps)
+ : {
+ : for (nformat = 0, pFormat = ps->formats;
+ : nformat < ps->nformats;
+ : nformat++, pFormat++)
+ : {
+ : pictForm->id = pFormat->id;
+ : pictForm->type = pFormat->type;
+ : pictForm->depth = pFormat->depth;
+ : pictForm->direct.red = pFormat->direct.red;
+ : pictForm->direct.redMask = pFormat->direct.redMask;
+ : pictForm->direct.green = pFormat->direct.green;
+ : pictForm->direct.greenMask = pFormat->direct.greenMask;
+ : pictForm->direct.blue = pFormat->direct.blue;
+ : pictForm->direct.blueMask = pFormat->direct.blueMask;
+ : pictForm->direct.alpha = pFormat->direct.alpha;
+ : pictForm->direct.alphaMask = pFormat->direct.alphaMask;
+ : if (pFormat->type == PictTypeIndexed && pFormat->index.pColormap)
+ : pictForm->colormap = pFormat->index.pColormap->mid;
+ : else
+ : pictForm->colormap = None;
+ : if (client->swapped)
+ : {
+ : swapl (&pictForm->id, n);
+ : swaps (&pictForm->direct.red, n);
+ : swaps (&pictForm->direct.redMask, n);
+ : swaps (&pictForm->direct.green, n);
+ : swaps (&pictForm->direct.greenMask, n);
+ : swaps (&pictForm->direct.blue, n);
+ : swaps (&pictForm->direct.blueMask, n);
+ : swaps (&pictForm->direct.alpha, n);
+ : swaps (&pictForm->direct.alphaMask, n);
+ : swapl (&pictForm->colormap, n);
+ : }
+ : pictForm++;
+ : }
+ : }
+ : }
+ :
+ : pictScreen = (xPictScreen *) pictForm;
+ : for (s = 0; s < numScreens; s++)
+ : {
+ : pScreen = screenInfo.screens[s];
+ : pictDepth = (xPictDepth *) (pictScreen + 1);
+ : ndepth = 0;
+ : for (d = 0; d < pScreen->numDepths; d++)
+ : {
+ : pictVisual = (xPictVisual *) (pictDepth + 1);
+ : pDepth = pScreen->allowedDepths + d;
+ :
+ : nvisual = 0;
+ : for (v = 0; v < pDepth->numVids; v++)
+ : {
+ : pVisual = findVisual (pScreen, pDepth->vids[v]);
+ : if (pVisual && (pFormat = PictureMatchVisual (pScreen,
+ : pDepth->depth,
+ : pVisual)))
+ : {
+ : pictVisual->visual = pVisual->vid;
+ : pictVisual->format = pFormat->id;
+ : if (client->swapped)
+ : {
+ : swapl (&pictVisual->visual, n);
+ : swapl (&pictVisual->format, n);
+ : }
+ : pictVisual++;
+ : nvisual++;
+ : }
+ : }
+ : pictDepth->depth = pDepth->depth;
+ : pictDepth->nPictVisuals = nvisual;
+ : if (client->swapped)
+ : {
+ : swaps (&pictDepth->nPictVisuals, n);
+ : }
+ : ndepth++;
+ : pictDepth = (xPictDepth *) pictVisual;
+ : }
+ : pictScreen->nDepth = ndepth;
+ : ps = GetPictureScreenIfSet(pScreen);
+ : if (ps)
+ : pictScreen->fallback = ps->fallback->id;
+ : else
+ : pictScreen->fallback = 0;
+ : if (client->swapped)
+ : {
+ : swapl (&pictScreen->nDepth, n);
+ : swapl (&pictScreen->fallback, n);
+ : }
+ : pictScreen = (xPictScreen *) pictDepth;
+ : }
+ : pictSubpixel = (CARD32 *) pictScreen;
+ :
+ : for (s = 0; s < numSubpixel; s++)
+ : {
+ : pScreen = screenInfo.screens[s];
+ : ps = GetPictureScreenIfSet(pScreen);
+ : if (ps)
+ : *pictSubpixel = ps->subpixel;
+ : else
+ : *pictSubpixel = SubPixelUnknown;
+ : if (client->swapped)
+ : {
+ : swapl (pictSubpixel, n);
+ : }
+ : ++pictSubpixel;
+ : }
+ :
+ : if (client->swapped)
+ : {
+ : swaps (&reply->sequenceNumber, n);
+ : swapl (&reply->length, n);
+ : swapl (&reply->numFormats, n);
+ : swapl (&reply->numScreens, n);
+ : swapl (&reply->numDepths, n);
+ : swapl (&reply->numVisuals, n);
+ : swapl (&reply->numSubpixel, n);
+ : }
+ : WriteToClient(client, rlength, (char *) reply);
+ : xfree (reply);
+ : return client->noClientException;
+ :}
+ :
+ :static int
+ :ProcRenderQueryPictIndexValues (ClientPtr client)
+ :{
+ : PictFormatPtr pFormat;
+ : int num;
+ : int rlength;
+ : int i, n;
+ : REQUEST(xRenderQueryPictIndexValuesReq);
+ : xRenderQueryPictIndexValuesReply *reply;
+ : xIndexValue *values;
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderQueryPictIndexValuesReq);
+ :
+ : pFormat = (PictFormatPtr) SecurityLookupIDByType (client,
+ : stuff->format,
+ : PictFormatType,
+ : DixReadAccess);
+ :
+ : if (!pFormat)
+ : {
+ : client->errorValue = stuff->format;
+ : return RenderErrBase + BadPictFormat;
+ : }
+ : if (pFormat->type != PictTypeIndexed)
+ : {
+ : client->errorValue = stuff->format;
+ : return BadMatch;
+ : }
+ : num = pFormat->index.nvalues;
+ : rlength = (sizeof (xRenderQueryPictIndexValuesReply) +
+ : num * sizeof(xIndexValue));
+ : reply = (xRenderQueryPictIndexValuesReply *) xalloc (rlength);
+ : if (!reply)
+ : return BadAlloc;
+ :
+ : reply->type = X_Reply;
+ : reply->sequenceNumber = client->sequence;
+ : reply->length = (rlength - sizeof(xGenericReply)) >> 2;
+ : reply->numIndexValues = num;
+ :
+ : values = (xIndexValue *) (reply + 1);
+ :
+ : memcpy (reply + 1, pFormat->index.pValues, num * sizeof (xIndexValue));
+ :
+ : if (client->swapped)
+ : {
+ : for (i = 0; i < num; i++)
+ : {
+ : swapl (&values[i].pixel, n);
+ : swaps (&values[i].red, n);
+ : swaps (&values[i].green, n);
+ : swaps (&values[i].blue, n);
+ : swaps (&values[i].alpha, n);
+ : }
+ : swaps (&reply->sequenceNumber, n);
+ : swapl (&reply->length, n);
+ : swapl (&reply->numIndexValues, n);
+ : }
+ :
+ : WriteToClient(client, rlength, (char *) reply);
+ : xfree(reply);
+ : return (client->noClientException);
+ :}
+ :
+ :static int
+ :ProcRenderQueryDithers (ClientPtr client)
+ :{
+ : return BadImplementation;
+ :}
+ :
+ :static int
+ :ProcRenderCreatePicture (ClientPtr client)
+ 6 0.0065 :{ /* ProcRenderCreatePicture total: 14 0.0153 */
+ : PicturePtr pPicture;
+ : DrawablePtr pDrawable;
+ : PictFormatPtr pFormat;
+ : int len, error, rc;
+ : REQUEST(xRenderCreatePictureReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderCreatePictureReq);
+ :
+ 1 0.0011 : LEGAL_NEW_RESOURCE(stuff->pid, client);
+ 2 0.0022 : rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
+ : DixWriteAccess);
+ : if (rc != Success)
+ : return rc;
+ :
+ 1 0.0011 : pFormat = (PictFormatPtr) SecurityLookupIDByType (client,
+ : stuff->format,
+ : PictFormatType,
+ : DixReadAccess);
+ : if (!pFormat)
+ : {
+ : client->errorValue = stuff->format;
+ : return RenderErrBase + BadPictFormat;
+ : }
+ : if (pFormat->depth != pDrawable->depth)
+ : return BadMatch;
+ : len = client->req_len - (sizeof(xRenderCreatePictureReq) >> 2);
+ : if (Ones(stuff->mask) != len)
+ : return BadLength;
+ :
+ : pPicture = CreatePicture (stuff->pid,
+ : pDrawable,
+ : pFormat,
+ : stuff->mask,
+ : (XID *) (stuff + 1),
+ : client,
+ : &error);
+ : if (!pPicture)
+ : return error;
+ 4 0.0044 : if (!AddResource (stuff->pid, PictureType, (pointer)pPicture))
+ : return BadAlloc;
+ : return Success;
+ :}
+ :
+ :static int
+ :ProcRenderChangePicture (ClientPtr client)
+ 6 0.0065 :{ /* ProcRenderChangePicture total: 7 0.0076 */
+ : PicturePtr pPicture;
+ : REQUEST(xRenderChangePictureReq);
+ : int len;
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderChangePictureReq);
+ 1 0.0011 : VERIFY_PICTURE (pPicture, stuff->picture, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ :
+ : len = client->req_len - (sizeof(xRenderChangePictureReq) >> 2);
+ : if (Ones(stuff->mask) != len)
+ : return BadLength;
+ :
+ : return ChangePicture (pPicture, stuff->mask, (XID *) (stuff + 1),
+ : (DevUnion *) 0, client);
+ :}
+ :
+ :static int
+ :ProcRenderSetPictureClipRectangles (ClientPtr client)
+ 1 0.0011 :{ /* ProcRenderSetPictureClipRectangles total: 1 0.0011 */
+ : REQUEST(xRenderSetPictureClipRectanglesReq);
+ : PicturePtr pPicture;
+ : int nr;
+ : int result;
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderSetPictureClipRectanglesReq);
+ : VERIFY_PICTURE (pPicture, stuff->picture, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ : if (!pPicture->pDrawable)
+ : return BadDrawable;
+ :
+ : nr = (client->req_len << 2) - sizeof(xRenderChangePictureReq);
+ : if (nr & 4)
+ : return BadLength;
+ : nr >>= 3;
+ : result = SetPictureClipRects (pPicture,
+ : stuff->xOrigin, stuff->yOrigin,
+ : nr, (xRectangle *) &stuff[1]);
+ : if (client->noClientException != Success)
+ : return(client->noClientException);
+ : else
+ : return(result);
+ :}
+ :
+ :static int
+ :ProcRenderFreePicture (ClientPtr client)
+ 1 0.0011 :{ /* ProcRenderFreePicture total: 2 0.0022 */
+ : PicturePtr pPicture;
+ : REQUEST(xRenderFreePictureReq);
+ :
+ 1 0.0011 : REQUEST_SIZE_MATCH(xRenderFreePictureReq);
+ :
+ : VERIFY_PICTURE (pPicture, stuff->picture, client, DixDestroyAccess,
+ : RenderErrBase + BadPicture);
+ : FreeResource (stuff->picture, RT_NONE);
+ : return(client->noClientException);
+ :}
+ :
+ :static Bool
+ :PictOpValid (CARD8 op)
+ :{
+ : if (/*PictOpMinimum <= op && */ op <= PictOpMaximum)
+ : return TRUE;
+ : if (PictOpDisjointMinimum <= op && op <= PictOpDisjointMaximum)
+ : return TRUE;
+ : if (PictOpConjointMinimum <= op && op <= PictOpConjointMaximum)
+ : return TRUE;
+ : return FALSE;
+ :}
+ :
+ :static int
+ :ProcRenderComposite (ClientPtr client)
+ 1 0.0011 :{ /* ProcRenderComposite total: 1 0.0011 */
+ : PicturePtr pSrc, pMask, pDst;
+ : REQUEST(xRenderCompositeReq);
+ :
+ : REQUEST_SIZE_MATCH(xRenderCompositeReq);
+ : if (!PictOpValid (stuff->op))
+ : {
+ : client->errorValue = stuff->op;
+ : return BadValue;
+ : }
+ : VERIFY_PICTURE (pDst, stuff->dst, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ : if (!pDst->pDrawable)
+ : return BadDrawable;
+ : VERIFY_PICTURE (pSrc, stuff->src, client, DixReadAccess,
+ : RenderErrBase + BadPicture);
+ : VERIFY_ALPHA (pMask, stuff->mask, client, DixReadAccess,
+ : RenderErrBase + BadPicture);
+ : if ((pSrc->pDrawable && pSrc->pDrawable->pScreen != pDst->pDrawable->pScreen) ||
+ : (pMask && pMask->pDrawable && pDst->pDrawable->pScreen != pMask->pDrawable->pScreen))
+ : return BadMatch;
+ : CompositePicture (stuff->op,
+ : pSrc,
+ : pMask,
+ : pDst,
+ : stuff->xSrc,
+ : stuff->ySrc,
+ : stuff->xMask,
+ : stuff->yMask,
+ : stuff->xDst,
+ : stuff->yDst,
+ : stuff->width,
+ : stuff->height);
+ : return Success;
+ :}
+ :
+ :static int
+ :ProcRenderScale (ClientPtr client)
+ :{
+ : return BadImplementation;
+ :}
+ :
+ :static int
+ :ProcRenderTrapezoids (ClientPtr client)
+ :{
+ : int ntraps;
+ : PicturePtr pSrc, pDst;
+ : PictFormatPtr pFormat;
+ : REQUEST(xRenderTrapezoidsReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderTrapezoidsReq);
+ : if (!PictOpValid (stuff->op))
+ : {
+ : client->errorValue = stuff->op;
+ : return BadValue;
+ : }
+ : VERIFY_PICTURE (pSrc, stuff->src, client, DixReadAccess,
+ : RenderErrBase + BadPicture);
+ : VERIFY_PICTURE (pDst, stuff->dst, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ : if (!pDst->pDrawable)
+ : return BadDrawable;
+ : if (pSrc->pDrawable && pSrc->pDrawable->pScreen != pDst->pDrawable->pScreen)
+ : return BadMatch;
+ : if (stuff->maskFormat)
+ : {
+ : pFormat = (PictFormatPtr) SecurityLookupIDByType (client,
+ : stuff->maskFormat,
+ : PictFormatType,
+ : DixReadAccess);
+ : if (!pFormat)
+ : {
+ : client->errorValue = stuff->maskFormat;
+ : return RenderErrBase + BadPictFormat;
+ : }
+ : }
+ : else
+ : pFormat = 0;
+ : ntraps = (client->req_len << 2) - sizeof (xRenderTrapezoidsReq);
+ : if (ntraps % sizeof (xTrapezoid))
+ : return BadLength;
+ : ntraps /= sizeof (xTrapezoid);
+ : if (ntraps)
+ : CompositeTrapezoids (stuff->op, pSrc, pDst, pFormat,
+ : stuff->xSrc, stuff->ySrc,
+ : ntraps, (xTrapezoid *) &stuff[1]);
+ : return client->noClientException;
+ :}
+ :
+ :static int
+ :ProcRenderTriangles (ClientPtr client)
+ :{
+ : int ntris;
+ : PicturePtr pSrc, pDst;
+ : PictFormatPtr pFormat;
+ : REQUEST(xRenderTrianglesReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderTrianglesReq);
+ : if (!PictOpValid (stuff->op))
+ : {
+ : client->errorValue = stuff->op;
+ : return BadValue;
+ : }
+ : VERIFY_PICTURE (pSrc, stuff->src, client, DixReadAccess,
+ : RenderErrBase + BadPicture);
+ : VERIFY_PICTURE (pDst, stuff->dst, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ : if (!pDst->pDrawable)
+ : return BadDrawable;
+ : if (pSrc->pDrawable && pSrc->pDrawable->pScreen != pDst->pDrawable->pScreen)
+ : return BadMatch;
+ : if (stuff->maskFormat)
+ : {
+ : pFormat = (PictFormatPtr) SecurityLookupIDByType (client,
+ : stuff->maskFormat,
+ : PictFormatType,
+ : DixReadAccess);
+ : if (!pFormat)
+ : {
+ : client->errorValue = stuff->maskFormat;
+ : return RenderErrBase + BadPictFormat;
+ : }
+ : }
+ : else
+ : pFormat = 0;
+ : ntris = (client->req_len << 2) - sizeof (xRenderTrianglesReq);
+ : if (ntris % sizeof (xTriangle))
+ : return BadLength;
+ : ntris /= sizeof (xTriangle);
+ : if (ntris)
+ : CompositeTriangles (stuff->op, pSrc, pDst, pFormat,
+ : stuff->xSrc, stuff->ySrc,
+ : ntris, (xTriangle *) &stuff[1]);
+ : return client->noClientException;
+ :}
+ :
+ :static int
+ :ProcRenderTriStrip (ClientPtr client)
+ :{
+ : int npoints;
+ : PicturePtr pSrc, pDst;
+ : PictFormatPtr pFormat;
+ : REQUEST(xRenderTrianglesReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderTrianglesReq);
+ : if (!PictOpValid (stuff->op))
+ : {
+ : client->errorValue = stuff->op;
+ : return BadValue;
+ : }
+ : VERIFY_PICTURE (pSrc, stuff->src, client, DixReadAccess,
+ : RenderErrBase + BadPicture);
+ : VERIFY_PICTURE (pDst, stuff->dst, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ : if (!pDst->pDrawable)
+ : return BadDrawable;
+ : if (pSrc->pDrawable && pSrc->pDrawable->pScreen != pDst->pDrawable->pScreen)
+ : return BadMatch;
+ : if (stuff->maskFormat)
+ : {
+ : pFormat = (PictFormatPtr) SecurityLookupIDByType (client,
+ : stuff->maskFormat,
+ : PictFormatType,
+ : DixReadAccess);
+ : if (!pFormat)
+ : {
+ : client->errorValue = stuff->maskFormat;
+ : return RenderErrBase + BadPictFormat;
+ : }
+ : }
+ : else
+ : pFormat = 0;
+ : npoints = ((client->req_len << 2) - sizeof (xRenderTriStripReq));
+ : if (npoints & 4)
+ : return(BadLength);
+ : npoints >>= 3;
+ : if (npoints >= 3)
+ : CompositeTriStrip (stuff->op, pSrc, pDst, pFormat,
+ : stuff->xSrc, stuff->ySrc,
+ : npoints, (xPointFixed *) &stuff[1]);
+ : return client->noClientException;
+ :}
+ :
+ :static int
+ :ProcRenderTriFan (ClientPtr client)
+ :{
+ : int npoints;
+ : PicturePtr pSrc, pDst;
+ : PictFormatPtr pFormat;
+ : REQUEST(xRenderTrianglesReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderTrianglesReq);
+ : if (!PictOpValid (stuff->op))
+ : {
+ : client->errorValue = stuff->op;
+ : return BadValue;
+ : }
+ : VERIFY_PICTURE (pSrc, stuff->src, client, DixReadAccess,
+ : RenderErrBase + BadPicture);
+ : VERIFY_PICTURE (pDst, stuff->dst, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ : if (!pDst->pDrawable)
+ : return BadDrawable;
+ : if (pSrc->pDrawable && pSrc->pDrawable->pScreen != pDst->pDrawable->pScreen)
+ : return BadMatch;
+ : if (stuff->maskFormat)
+ : {
+ : pFormat = (PictFormatPtr) SecurityLookupIDByType (client,
+ : stuff->maskFormat,
+ : PictFormatType,
+ : DixReadAccess);
+ : if (!pFormat)
+ : {
+ : client->errorValue = stuff->maskFormat;
+ : return RenderErrBase + BadPictFormat;
+ : }
+ : }
+ : else
+ : pFormat = 0;
+ : npoints = ((client->req_len << 2) - sizeof (xRenderTriStripReq));
+ : if (npoints & 4)
+ : return(BadLength);
+ : npoints >>= 3;
+ : if (npoints >= 3)
+ : CompositeTriFan (stuff->op, pSrc, pDst, pFormat,
+ : stuff->xSrc, stuff->ySrc,
+ : npoints, (xPointFixed *) &stuff[1]);
+ : return client->noClientException;
+ :}
+ :
+ :static int
+ :ProcRenderColorTrapezoids (ClientPtr client)
+ :{
+ : return BadImplementation;
+ :}
+ :
+ :static int
+ :ProcRenderColorTriangles (ClientPtr client)
+ :{
+ : return BadImplementation;
+ :}
+ :
+ :static int
+ :ProcRenderTransform (ClientPtr client)
+ :{
+ : return BadImplementation;
+ :}
+ :
+ :static int
+ :ProcRenderCreateGlyphSet (ClientPtr client)
+ :{
+ : GlyphSetPtr glyphSet;
+ : PictFormatPtr format;
+ : int f;
+ : REQUEST(xRenderCreateGlyphSetReq);
+ :
+ : REQUEST_SIZE_MATCH(xRenderCreateGlyphSetReq);
+ :
+ : LEGAL_NEW_RESOURCE(stuff->gsid, client);
+ : format = (PictFormatPtr) SecurityLookupIDByType (client,
+ : stuff->format,
+ : PictFormatType,
+ : DixReadAccess);
+ : if (!format)
+ : {
+ : client->errorValue = stuff->format;
+ : return RenderErrBase + BadPictFormat;
+ : }
+ : switch (format->depth) {
+ : case 1:
+ : f = GlyphFormat1;
+ : break;
+ : case 4:
+ : f = GlyphFormat4;
+ : break;
+ : case 8:
+ : f = GlyphFormat8;
+ : break;
+ : case 16:
+ : f = GlyphFormat16;
+ : break;
+ : case 32:
+ : f = GlyphFormat32;
+ : break;
+ : default:
+ : return BadMatch;
+ : }
+ : if (format->type != PictTypeDirect)
+ : return BadMatch;
+ : glyphSet = AllocateGlyphSet (f, format);
+ : if (!glyphSet)
+ : return BadAlloc;
+ : if (!AddResource (stuff->gsid, GlyphSetType, (pointer)glyphSet))
+ : return BadAlloc;
+ : return Success;
+ :}
+ :
+ :static int
+ :ProcRenderReferenceGlyphSet (ClientPtr client)
+ :{
+ : GlyphSetPtr glyphSet;
+ : REQUEST(xRenderReferenceGlyphSetReq);
+ :
+ : REQUEST_SIZE_MATCH(xRenderReferenceGlyphSetReq);
+ :
+ : LEGAL_NEW_RESOURCE(stuff->gsid, client);
+ :
+ : glyphSet = (GlyphSetPtr) SecurityLookupIDByType (client,
+ : stuff->existing,
+ : GlyphSetType,
+ : DixWriteAccess);
+ : if (!glyphSet)
+ : {
+ : client->errorValue = stuff->existing;
+ : return RenderErrBase + BadGlyphSet;
+ : }
+ : glyphSet->refcnt++;
+ : if (!AddResource (stuff->gsid, GlyphSetType, (pointer)glyphSet))
+ : return BadAlloc;
+ : return client->noClientException;
+ :}
+ :
+ :#define NLOCALDELTA 64
+ :#define NLOCALGLYPH 256
+ :
+ :static int
+ :ProcRenderFreeGlyphSet (ClientPtr client)
+ :{
+ : GlyphSetPtr glyphSet;
+ : REQUEST(xRenderFreeGlyphSetReq);
+ :
+ : REQUEST_SIZE_MATCH(xRenderFreeGlyphSetReq);
+ : glyphSet = (GlyphSetPtr) SecurityLookupIDByType (client,
+ : stuff->glyphset,
+ : GlyphSetType,
+ : DixDestroyAccess);
+ : if (!glyphSet)
+ : {
+ : client->errorValue = stuff->glyphset;
+ : return RenderErrBase + BadGlyphSet;
+ : }
+ : FreeResource (stuff->glyphset, RT_NONE);
+ : return client->noClientException;
+ :}
+ :
+ :typedef struct _GlyphNew {
+ : Glyph id;
+ : GlyphPtr glyph;
+ :} GlyphNewRec, *GlyphNewPtr;
+ :
+ :static int
+ :ProcRenderAddGlyphs (ClientPtr client)
+ :{
+ : GlyphSetPtr glyphSet;
+ : REQUEST(xRenderAddGlyphsReq);
+ : GlyphNewRec glyphsLocal[NLOCALGLYPH];
+ : GlyphNewPtr glyphsBase, glyphs;
+ : GlyphPtr glyph;
+ : int remain, nglyphs;
+ : CARD32 *gids;
+ : xGlyphInfo *gi;
+ : CARD8 *bits;
+ : int size;
+ : int err = BadAlloc;
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderAddGlyphsReq);
+ : glyphSet = (GlyphSetPtr) SecurityLookupIDByType (client,
+ : stuff->glyphset,
+ : GlyphSetType,
+ : DixWriteAccess);
+ : if (!glyphSet)
+ : {
+ : client->errorValue = stuff->glyphset;
+ : return RenderErrBase + BadGlyphSet;
+ : }
+ :
+ : nglyphs = stuff->nglyphs;
+ : if (nglyphs > UINT32_MAX / sizeof(GlyphNewRec))
+ : return BadAlloc;
+ :
+ : if (nglyphs <= NLOCALGLYPH)
+ : glyphsBase = glyphsLocal;
+ : else
+ : {
+ : glyphsBase = (GlyphNewPtr) Xalloc (nglyphs * sizeof (GlyphNewRec));
+ : if (!glyphsBase)
+ : return BadAlloc;
+ : }
+ :
+ : remain = (client->req_len << 2) - sizeof (xRenderAddGlyphsReq);
+ :
+ : glyphs = glyphsBase;
+ :
+ : gids = (CARD32 *) (stuff + 1);
+ : gi = (xGlyphInfo *) (gids + nglyphs);
+ : bits = (CARD8 *) (gi + nglyphs);
+ : remain -= (sizeof (CARD32) + sizeof (xGlyphInfo)) * nglyphs;
+ : while (remain >= 0 && nglyphs)
+ : {
+ : glyph = AllocateGlyph (gi, glyphSet->fdepth);
+ : if (!glyph)
+ : {
+ : err = BadAlloc;
+ : goto bail;
+ : }
+ :
+ : glyphs->glyph = glyph;
+ : glyphs->id = *gids;
+ :
+ : size = glyph->size - sizeof (xGlyphInfo);
+ : if (remain < size)
+ : break;
+ : memcpy ((CARD8 *) (glyph + 1), bits, size);
+ :
+ : if (size & 3)
+ : size += 4 - (size & 3);
+ : bits += size;
+ : remain -= size;
+ : gi++;
+ : gids++;
+ : glyphs++;
+ : nglyphs--;
+ : }
+ : if (nglyphs || remain)
+ : {
+ : err = BadLength;
+ : goto bail;
+ : }
+ : nglyphs = stuff->nglyphs;
+ : if (!ResizeGlyphSet (glyphSet, nglyphs))
+ : {
+ : err = BadAlloc;
+ : goto bail;
+ : }
+ : glyphs = glyphsBase;
+ : while (nglyphs--) {
+ : AddGlyph (glyphSet, glyphs->glyph, glyphs->id);
+ : glyphs++;
+ : }
+ :
+ : if (glyphsBase != glyphsLocal)
+ : Xfree (glyphsBase);
+ : return client->noClientException;
+ :bail:
+ : while (glyphs != glyphsBase)
+ : {
+ : --glyphs;
+ : xfree (glyphs->glyph);
+ : }
+ : if (glyphsBase != glyphsLocal)
+ : Xfree (glyphsBase);
+ : return err;
+ :}
+ :
+ :static int
+ :ProcRenderAddGlyphsFromPicture (ClientPtr client)
+ :{
+ : return BadImplementation;
+ :}
+ :
+ :static int
+ :ProcRenderFreeGlyphs (ClientPtr client)
+ :{
+ : REQUEST(xRenderFreeGlyphsReq);
+ : GlyphSetPtr glyphSet;
+ : int nglyph;
+ : CARD32 *gids;
+ : CARD32 glyph;
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderFreeGlyphsReq);
+ : glyphSet = (GlyphSetPtr) SecurityLookupIDByType (client,
+ : stuff->glyphset,
+ : GlyphSetType,
+ : DixWriteAccess);
+ : if (!glyphSet)
+ : {
+ : client->errorValue = stuff->glyphset;
+ : return RenderErrBase + BadGlyphSet;
+ : }
+ : nglyph = ((client->req_len << 2) - sizeof (xRenderFreeGlyphsReq)) >> 2;
+ : gids = (CARD32 *) (stuff + 1);
+ : while (nglyph-- > 0)
+ : {
+ : glyph = *gids++;
+ : if (!DeleteGlyph (glyphSet, glyph))
+ : {
+ : client->errorValue = glyph;
+ : return RenderErrBase + BadGlyph;
+ : }
+ : }
+ : return client->noClientException;
+ :}
+ :
+ :static int
+ :ProcRenderCompositeGlyphs (ClientPtr client)
+ 4 0.0044 :{ /* ProcRenderCompositeGlyphs total: 30 0.0327 */
+ : GlyphSetPtr glyphSet;
+ : GlyphSet gs;
+ : PicturePtr pSrc, pDst;
+ : PictFormatPtr pFormat;
+ : GlyphListRec listsLocal[NLOCALDELTA];
+ : GlyphListPtr lists, listsBase;
+ : GlyphPtr glyphsLocal[NLOCALGLYPH];
+ : Glyph glyph;
+ : GlyphPtr *glyphs, *glyphsBase;
+ : xGlyphElt *elt;
+ : CARD8 *buffer, *end;
+ : int nglyph;
+ : int nlist;
+ : int space;
+ : int size;
+ : int n;
+ :
+ : REQUEST(xRenderCompositeGlyphsReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderCompositeGlyphsReq);
+ :
+ : switch (stuff->renderReqType) {
+ : default: size = 1; break;
+ : case X_RenderCompositeGlyphs16: size = 2; break;
+ : case X_RenderCompositeGlyphs32: size = 4; break;
+ : }
+ :
+ : if (!PictOpValid (stuff->op))
+ : {
+ : client->errorValue = stuff->op;
+ : return BadValue;
+ : }
+ : VERIFY_PICTURE (pSrc, stuff->src, client, DixReadAccess,
+ : RenderErrBase + BadPicture);
+ : VERIFY_PICTURE (pDst, stuff->dst, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ : if (!pDst->pDrawable)
+ : return BadDrawable;
+ : if (pSrc->pDrawable && pSrc->pDrawable->pScreen != pDst->pDrawable->pScreen)
+ : return BadMatch;
+ : if (stuff->maskFormat)
+ : {
+ 1 0.0011 : pFormat = (PictFormatPtr) SecurityLookupIDByType (client,
+ : stuff->maskFormat,
+ : PictFormatType,
+ : DixReadAccess);
+ : if (!pFormat)
+ : {
+ : client->errorValue = stuff->maskFormat;
+ : return RenderErrBase + BadPictFormat;
+ : }
+ : }
+ : else
+ : pFormat = 0;
+ :
+ 1 0.0011 : glyphSet = (GlyphSetPtr) SecurityLookupIDByType (client,
+ : stuff->glyphset,
+ : GlyphSetType,
+ : DixReadAccess);
+ : if (!glyphSet)
+ : {
+ : client->errorValue = stuff->glyphset;
+ : return RenderErrBase + BadGlyphSet;
+ : }
+ :
+ : buffer = (CARD8 *) (stuff + 1);
+ 2 0.0022 : end = (CARD8 *) stuff + (client->req_len << 2);
+ : nglyph = 0;
+ : nlist = 0;
+ : while (buffer + sizeof (xGlyphElt) < end)
+ : {
+ : elt = (xGlyphElt *) buffer;
+ : buffer += sizeof (xGlyphElt);
+ :
+ : if (elt->len == 0xff)
+ : {
+ : buffer += 4;
+ : }
+ : else
+ : {
+ 1 0.0011 : nlist++;
+ : nglyph += elt->len;
+ : space = size * elt->len;
+ : if (space & 3)
+ : space += 4 - (space & 3);
+ : buffer += space;
+ : }
+ : }
+ : if (nglyph <= NLOCALGLYPH)
+ : glyphsBase = glyphsLocal;
+ : else
+ : {
+ : glyphsBase = (GlyphPtr *) ALLOCATE_LOCAL (nglyph * sizeof (GlyphPtr));
+ : if (!glyphsBase)
+ : return BadAlloc;
+ : }
+ : if (nlist <= NLOCALDELTA)
+ : listsBase = listsLocal;
+ : else
+ : {
+ : listsBase = (GlyphListPtr) ALLOCATE_LOCAL (nlist * sizeof (GlyphListRec));
+ : if (!listsBase)
+ : return BadAlloc;
+ : }
+ : buffer = (CARD8 *) (stuff + 1);
+ : glyphs = glyphsBase;
+ : lists = listsBase;
+ 1 0.0011 : while (buffer + sizeof (xGlyphElt) < end)
+ : {
+ : elt = (xGlyphElt *) buffer;
+ : buffer += sizeof (xGlyphElt);
+ :
+ : if (elt->len == 0xff)
+ : {
+ : if (buffer + sizeof (GlyphSet) < end)
+ : {
+ : memcpy(&gs, buffer, sizeof(GlyphSet));
+ : glyphSet = (GlyphSetPtr) SecurityLookupIDByType (client,
+ : gs,
+ : GlyphSetType,
+ : DixReadAccess);
+ : if (!glyphSet)
+ : {
+ : client->errorValue = gs;
+ : if (glyphsBase != glyphsLocal)
+ : DEALLOCATE_LOCAL (glyphsBase);
+ : if (listsBase != listsLocal)
+ : DEALLOCATE_LOCAL (listsBase);
+ : return RenderErrBase + BadGlyphSet;
+ : }
+ : }
+ : buffer += 4;
+ : }
+ : else
+ : {
+ : lists->xOff = elt->deltax;
+ : lists->yOff = elt->deltay;
+ 1 0.0011 : lists->format = glyphSet->format;
+ : lists->len = 0;
+ : n = elt->len;
+ 3 0.0033 : while (n--)
+ : {
+ : if (buffer + size <= end)
+ : {
+ : switch (size) {
+ : case 1:
+ 7 0.0076 : glyph = *((CARD8 *)buffer); break;
+ : case 2:
+ : glyph = *((CARD16 *)buffer); break;
+ : case 4:
+ : default:
+ : glyph = *((CARD32 *)buffer); break;
+ : }
+ 5 0.0054 : if ((*glyphs = FindGlyph (glyphSet, glyph)))
+ : {
+ 2 0.0022 : lists->len++;
+ : glyphs++;
+ : }
+ : }
+ : buffer += size;
+ : }
+ : space = size * elt->len;
+ : if (space & 3)
+ 1 0.0011 : buffer += 4 - (space & 3);
+ : lists++;
+ : }
+ : }
+ : if (buffer > end)
+ : return BadLength;
+ :
+ 1 0.0011 : CompositeGlyphs (stuff->op,
+ : pSrc,
+ : pDst,
+ : pFormat,
+ : stuff->xSrc,
+ : stuff->ySrc,
+ : nlist,
+ : listsBase,
+ : glyphsBase);
+ :
+ : if (glyphsBase != glyphsLocal)
+ : DEALLOCATE_LOCAL (glyphsBase);
+ : if (listsBase != listsLocal)
+ : DEALLOCATE_LOCAL (listsBase);
+ :
+ : return client->noClientException;
+ :}
+ :
+ :static int
+ :ProcRenderFillRectangles (ClientPtr client)
+ 4 0.0044 :{ /* ProcRenderFillRectangles total: 10 0.0109 */
+ : PicturePtr pDst;
+ : int things;
+ : REQUEST(xRenderFillRectanglesReq);
+ :
+ : REQUEST_AT_LEAST_SIZE (xRenderFillRectanglesReq);
+ 1 0.0011 : if (!PictOpValid (stuff->op))
+ : {
+ : client->errorValue = stuff->op;
+ : return BadValue;
+ : }
+ : VERIFY_PICTURE (pDst, stuff->dst, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ : if (!pDst->pDrawable)
+ : return BadDrawable;
+ :
+ : things = (client->req_len << 2) - sizeof(xRenderFillRectanglesReq);
+ : if (things & 4)
+ : return(BadLength);
+ : things >>= 3;
+ :
+ 2 0.0022 : CompositeRects (stuff->op,
+ : pDst,
+ : &stuff->color,
+ : things,
+ : (xRectangle *) &stuff[1]);
+ :
+ 1 0.0011 : return client->noClientException;
+ 2 0.0022 :}
+ :
+ :static void
+ :SetBit (unsigned char *line, int x, int bit)
+ :{
+ : unsigned char mask;
+ :
+ : if (screenInfo.bitmapBitOrder == LSBFirst)
+ : mask = (1 << (x & 7));
+ : else
+ : mask = (0x80 >> (x & 7));
+ : /* XXX assumes byte order is host byte order */
+ : line += (x >> 3);
+ : if (bit)
+ : *line |= mask;
+ : else
+ : *line &= ~mask;
+ :}
+ :
+ :#define DITHER_DIM 2
+ :
+ :static CARD32 orderedDither[DITHER_DIM][DITHER_DIM] = {
+ : { 1, 3, },
+ : { 4, 2, },
+ :};
+ :
+ :#define DITHER_SIZE ((sizeof orderedDither / sizeof orderedDither[0][0]) + 1)
+ :
+ :static int
+ :ProcRenderCreateCursor (ClientPtr client)
+ :{
+ : REQUEST(xRenderCreateCursorReq);
+ : PicturePtr pSrc;
+ : ScreenPtr pScreen;
+ : unsigned short width, height;
+ : CARD32 *argbbits, *argb;
+ : unsigned char *srcbits, *srcline;
+ : unsigned char *mskbits, *mskline;
+ : int stride;
+ : int x, y;
+ : int nbytes_mono;
+ : CursorMetricRec cm;
+ : CursorPtr pCursor;
+ : CARD32 twocolor[3];
+ : int ncolor;
+ :
+ : REQUEST_SIZE_MATCH (xRenderCreateCursorReq);
+ : LEGAL_NEW_RESOURCE(stuff->cid, client);
+ :
+ : VERIFY_PICTURE (pSrc, stuff->src, client, DixReadAccess,
+ : RenderErrBase + BadPicture);
+ : if (!pSrc->pDrawable)
+ : return BadDrawable;
+ : pScreen = pSrc->pDrawable->pScreen;
+ : width = pSrc->pDrawable->width;
+ : height = pSrc->pDrawable->height;
+ : if ( stuff->x > width
+ : || stuff->y > height )
+ : return (BadMatch);
+ : argbbits = xalloc (width * height * sizeof (CARD32));
+ : if (!argbbits)
+ : return (BadAlloc);
+ :
+ : stride = BitmapBytePad(width);
+ : nbytes_mono = stride*height;
+ : srcbits = (unsigned char *)xalloc(nbytes_mono);
+ : if (!srcbits)
+ : {
+ : xfree (argbbits);
+ : return (BadAlloc);
+ : }
+ : mskbits = (unsigned char *)xalloc(nbytes_mono);
+ : if (!mskbits)
+ : {
+ : xfree(argbbits);
+ : xfree(srcbits);
+ : return (BadAlloc);
+ : }
+ : bzero ((char *) mskbits, nbytes_mono);
+ : bzero ((char *) srcbits, nbytes_mono);
+ :
+ : if (pSrc->format == PICT_a8r8g8b8)
+ : {
+ : (*pScreen->GetImage) (pSrc->pDrawable,
+ : 0, 0, width, height, ZPixmap,
+ : 0xffffffff, (pointer) argbbits);
+ : }
+ : else
+ : {
+ : PixmapPtr pPixmap;
+ : PicturePtr pPicture;
+ : PictFormatPtr pFormat;
+ : int error;
+ :
+ : pFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8);
+ : if (!pFormat)
+ : {
+ : xfree (argbbits);
+ : xfree (srcbits);
+ : xfree (mskbits);
+ : return (BadImplementation);
+ : }
+ : pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, 32);
+ : if (!pPixmap)
+ : {
+ : xfree (argbbits);
+ : xfree (srcbits);
+ : xfree (mskbits);
+ : return (BadAlloc);
+ : }
+ : pPicture = CreatePicture (0, &pPixmap->drawable, pFormat, 0, 0,
+ : client, &error);
+ : if (!pPicture)
+ : {
+ : xfree (argbbits);
+ : xfree (srcbits);
+ : xfree (mskbits);
+ : return error;
+ : }
+ : (*pScreen->DestroyPixmap) (pPixmap);
+ : CompositePicture (PictOpSrc,
+ : pSrc, 0, pPicture,
+ : 0, 0, 0, 0, 0, 0, width, height);
+ : (*pScreen->GetImage) (pPicture->pDrawable,
+ : 0, 0, width, height, ZPixmap,
+ : 0xffffffff, (pointer) argbbits);
+ : FreePicture (pPicture, 0);
+ : }
+ : /*
+ : * Check whether the cursor can be directly supported by
+ : * the core cursor code
+ : */
+ : ncolor = 0;
+ : argb = argbbits;
+ : for (y = 0; ncolor <= 2 && y < height; y++)
+ : {
+ : for (x = 0; ncolor <= 2 && x < width; x++)
+ : {
+ : CARD32 p = *argb++;
+ : CARD32 a = (p >> 24);
+ :
+ : if (a == 0) /* transparent */
+ : continue;
+ : if (a == 0xff) /* opaque */
+ : {
+ : int n;
+ : for (n = 0; n < ncolor; n++)
+ : if (p == twocolor[n])
+ : break;
+ : if (n == ncolor)
+ : twocolor[ncolor++] = p;
+ : }
+ : else
+ : ncolor = 3;
+ : }
+ : }
+ :
+ : /*
+ : * Convert argb image to two plane cursor
+ : */
+ : srcline = srcbits;
+ : mskline = mskbits;
+ : argb = argbbits;
+ : for (y = 0; y < height; y++)
+ : {
+ : for (x = 0; x < width; x++)
+ : {
+ : CARD32 p = *argb++;
+ :
+ : if (ncolor <= 2)
+ : {
+ : CARD32 a = ((p >> 24));
+ :
+ : SetBit (mskline, x, a != 0);
+ : SetBit (srcline, x, a != 0 && p == twocolor[0]);
+ : }
+ : else
+ : {
+ : CARD32 a = ((p >> 24) * DITHER_SIZE + 127) / 255;
+ : CARD32 i = ((CvtR8G8B8toY15(p) >> 7) * DITHER_SIZE + 127) / 255;
+ : CARD32 d = orderedDither[y&(DITHER_DIM-1)][x&(DITHER_DIM-1)];
+ : /* Set mask from dithered alpha value */
+ : SetBit(mskline, x, a > d);
+ : /* Set src from dithered intensity value */
+ : SetBit(srcline, x, a > d && i <= d);
+ : }
+ : }
+ : srcline += stride;
+ : mskline += stride;
+ : }
+ : /*
+ : * Dither to white and black if the cursor has more than two colors
+ : */
+ : if (ncolor > 2)
+ : {
+ : twocolor[0] = 0xff000000;
+ : twocolor[1] = 0xffffffff;
+ : }
+ : else
+ : {
+ : xfree (argbbits);
+ : argbbits = 0;
+ : }
+ :
+ :#define GetByte(p,s) (((p) >> (s)) & 0xff)
+ :#define GetColor(p,s) (GetByte(p,s) | (GetByte(p,s) << 8))
+ :
+ : cm.width = width;
+ : cm.height = height;
+ : cm.xhot = stuff->x;
+ : cm.yhot = stuff->y;
+ : pCursor = AllocCursorARGB (srcbits, mskbits, argbbits, &cm,
+ : GetColor(twocolor[0], 16),
+ : GetColor(twocolor[0], 8),
+ : GetColor(twocolor[0], 0),
+ : GetColor(twocolor[1], 16),
+ : GetColor(twocolor[1], 8),
+ : GetColor(twocolor[1], 0));
+ : if (pCursor && AddResource(stuff->cid, RT_CURSOR, (pointer)pCursor))
+ : return (client->noClientException);
+ : return BadAlloc;
+ :}
+ :
+ :static int
+ :ProcRenderSetPictureTransform (ClientPtr client)
+ :{ /* ProcRenderSetPictureTransform total: 2 0.0022 */
+ : REQUEST(xRenderSetPictureTransformReq);
+ : PicturePtr pPicture;
+ : int result;
+ :
+ 1 0.0011 : REQUEST_SIZE_MATCH(xRenderSetPictureTransformReq);
+ : VERIFY_PICTURE (pPicture, stuff->picture, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ : result = SetPictureTransform (pPicture, (PictTransform *) &stuff->transform);
+ : if (client->noClientException != Success)
+ : return(client->noClientException);
+ : else
+ : return(result);
+ 1 0.0011 :}
+ :
+ :static int
+ :ProcRenderQueryFilters (ClientPtr client)
+ :{
+ : REQUEST (xRenderQueryFiltersReq);
+ : DrawablePtr pDrawable;
+ : xRenderQueryFiltersReply *reply;
+ : int nbytesName;
+ : int nnames;
+ : ScreenPtr pScreen;
+ : PictureScreenPtr ps;
+ : int i, j, len, total_bytes, rc;
+ : INT16 *aliases;
+ : char *names;
+ :
+ : REQUEST_SIZE_MATCH(xRenderQueryFiltersReq);
+ : rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
+ : DixReadAccess);
+ : if (rc != Success)
+ : return rc;
+ :
+ : pScreen = pDrawable->pScreen;
+ : nbytesName = 0;
+ : nnames = 0;
+ : ps = GetPictureScreenIfSet(pScreen);
+ : if (ps)
+ : {
+ : for (i = 0; i < ps->nfilters; i++)
+ : nbytesName += 1 + strlen (ps->filters[i].name);
+ : for (i = 0; i < ps->nfilterAliases; i++)
+ : nbytesName += 1 + strlen (ps->filterAliases[i].alias);
+ : nnames = ps->nfilters + ps->nfilterAliases;
+ : }
+ : len = ((nnames + 1) >> 1) + ((nbytesName + 3) >> 2);
+ : total_bytes = sizeof (xRenderQueryFiltersReply) + (len << 2);
+ : reply = (xRenderQueryFiltersReply *) xalloc (total_bytes);
+ : if (!reply)
+ : return BadAlloc;
+ : aliases = (INT16 *) (reply + 1);
+ : names = (char *) (aliases + ((nnames + 1) & ~1));
+ :
+ : reply->type = X_Reply;
+ : reply->sequenceNumber = client->sequence;
+ : reply->length = len;
+ : reply->numAliases = nnames;
+ : reply->numFilters = nnames;
+ : if (ps)
+ : {
+ :
+ : /* fill in alias values */
+ : for (i = 0; i < ps->nfilters; i++)
+ : aliases[i] = FilterAliasNone;
+ : for (i = 0; i < ps->nfilterAliases; i++)
+ : {
+ : for (j = 0; j < ps->nfilters; j++)
+ : if (ps->filterAliases[i].filter_id == ps->filters[j].id)
+ : break;
+ : if (j == ps->nfilters)
+ : {
+ : for (j = 0; j < ps->nfilterAliases; j++)
+ : if (ps->filterAliases[i].filter_id ==
+ : ps->filterAliases[j].alias_id)
+ : {
+ : break;
+ : }
+ : if (j == ps->nfilterAliases)
+ : j = FilterAliasNone;
+ : else
+ : j = j + ps->nfilters;
+ : }
+ : aliases[i + ps->nfilters] = j;
+ : }
+ :
+ : /* fill in filter names */
+ : for (i = 0; i < ps->nfilters; i++)
+ : {
+ : j = strlen (ps->filters[i].name);
+ : *names++ = j;
+ : strncpy (names, ps->filters[i].name, j);
+ : names += j;
+ : }
+ :
+ : /* fill in filter alias names */
+ : for (i = 0; i < ps->nfilterAliases; i++)
+ : {
+ : j = strlen (ps->filterAliases[i].alias);
+ : *names++ = j;
+ : strncpy (names, ps->filterAliases[i].alias, j);
+ : names += j;
+ : }
+ : }
+ :
+ : if (client->swapped)
+ : {
+ : register int n;
+ :
+ : for (i = 0; i < reply->numAliases; i++)
+ : {
+ : swaps (&aliases[i], n);
+ : }
+ : swaps(&reply->sequenceNumber, n);
+ : swapl(&reply->length, n);
+ : swapl(&reply->numAliases, n);
+ : swapl(&reply->numFilters, n);
+ : }
+ : WriteToClient(client, total_bytes, (char *) reply);
+ : xfree (reply);
+ :
+ : return(client->noClientException);
+ :}
+ :
+ :static int
+ :ProcRenderSetPictureFilter (ClientPtr client)
+ :{ /* ProcRenderSetPictureFilter total: 4 0.0044 */
+ : REQUEST (xRenderSetPictureFilterReq);
+ : PicturePtr pPicture;
+ : int result;
+ : xFixed *params;
+ : int nparams;
+ : char *name;
+ :
+ 1 0.0011 : REQUEST_AT_LEAST_SIZE (xRenderSetPictureFilterReq);
+ 2 0.0022 : VERIFY_PICTURE (pPicture, stuff->picture, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ : name = (char *) (stuff + 1);
+ : params = (xFixed *) (name + ((stuff->nbytes + 3) & ~3));
+ : nparams = ((xFixed *) stuff + client->req_len) - params;
+ 1 0.0011 : result = SetPictureFilter (pPicture, name, stuff->nbytes, params, nparams);
+ : return result;
+ :}
+ :
+ :static int
+ :ProcRenderCreateAnimCursor (ClientPtr client)
+ :{
+ : REQUEST(xRenderCreateAnimCursorReq);
+ : CursorPtr *cursors;
+ : CARD32 *deltas;
+ : CursorPtr pCursor;
+ : int ncursor;
+ : xAnimCursorElt *elt;
+ : int i;
+ : int ret;
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderCreateAnimCursorReq);
+ : LEGAL_NEW_RESOURCE(stuff->cid, client);
+ : if (client->req_len & 1)
+ : return BadLength;
+ : ncursor = (client->req_len - (SIZEOF(xRenderCreateAnimCursorReq) >> 2)) >> 1;
+ : cursors = xalloc (ncursor * (sizeof (CursorPtr) + sizeof (CARD32)));
+ : if (!cursors)
+ : return BadAlloc;
+ : deltas = (CARD32 *) (cursors + ncursor);
+ : elt = (xAnimCursorElt *) (stuff + 1);
+ : for (i = 0; i < ncursor; i++)
+ : {
+ : cursors[i] = (CursorPtr)SecurityLookupIDByType(client, elt->cursor,
+ : RT_CURSOR, DixReadAccess);
+ : if (!cursors[i])
+ : {
+ : xfree (cursors);
+ : client->errorValue = elt->cursor;
+ : return BadCursor;
+ : }
+ : deltas[i] = elt->delay;
+ : elt++;
+ : }
+ : ret = AnimCursorCreate (cursors, deltas, ncursor, &pCursor);
+ : xfree (cursors);
+ : if (ret != Success)
+ : return ret;
+ :
+ : if (AddResource (stuff->cid, RT_CURSOR, (pointer)pCursor))
+ : return client->noClientException;
+ : return BadAlloc;
+ :}
+ :
+ :static int
+ :ProcRenderAddTraps (ClientPtr client)
+ :{
+ : int ntraps;
+ : PicturePtr pPicture;
+ : REQUEST(xRenderAddTrapsReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderAddTrapsReq);
+ : VERIFY_PICTURE (pPicture, stuff->picture, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ : if (!pPicture->pDrawable)
+ : return BadDrawable;
+ : ntraps = (client->req_len << 2) - sizeof (xRenderAddTrapsReq);
+ : if (ntraps % sizeof (xTrap))
+ : return BadLength;
+ : ntraps /= sizeof (xTrap);
+ : if (ntraps)
+ : AddTraps (pPicture,
+ : stuff->xOff, stuff->yOff,
+ : ntraps, (xTrap *) &stuff[1]);
+ : return client->noClientException;
+ :}
+ :
+ :static int ProcRenderCreateSolidFill(ClientPtr client)
+ :{
+ : PicturePtr pPicture;
+ : int error = 0;
+ : REQUEST(xRenderCreateSolidFillReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderCreateSolidFillReq);
+ :
+ : LEGAL_NEW_RESOURCE(stuff->pid, client);
+ :
+ : pPicture = CreateSolidPicture(stuff->pid, &stuff->color, &error);
+ : if (!pPicture)
+ : return error;
+ : if (!AddResource (stuff->pid, PictureType, (pointer)pPicture))
+ : return BadAlloc;
+ : return Success;
+ :}
+ :
+ :static int ProcRenderCreateLinearGradient (ClientPtr client)
+ :{
+ : PicturePtr pPicture;
+ : int len;
+ : int error = 0;
+ : xFixed *stops;
+ : xRenderColor *colors;
+ : REQUEST(xRenderCreateLinearGradientReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderCreateLinearGradientReq);
+ :
+ : LEGAL_NEW_RESOURCE(stuff->pid, client);
+ :
+ : len = (client->req_len << 2) - sizeof(xRenderCreateLinearGradientReq);
+ : if (len != stuff->nStops*(sizeof(xFixed) + sizeof(xRenderColor)))
+ : return BadLength;
+ :
+ : stops = (xFixed *)(stuff + 1);
+ : colors = (xRenderColor *)(stops + stuff->nStops);
+ :
+ : pPicture = CreateLinearGradientPicture (stuff->pid, &stuff->p1, &stuff->p2,
+ : stuff->nStops, stops, colors, &error);
+ : if (!pPicture)
+ : return error;
+ : if (!AddResource (stuff->pid, PictureType, (pointer)pPicture))
+ : return BadAlloc;
+ : return Success;
+ :}
+ :
+ :static int ProcRenderCreateRadialGradient (ClientPtr client)
+ :{
+ : PicturePtr pPicture;
+ : int len;
+ : int error = 0;
+ : xFixed *stops;
+ : xRenderColor *colors;
+ : REQUEST(xRenderCreateRadialGradientReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderCreateRadialGradientReq);
+ :
+ : LEGAL_NEW_RESOURCE(stuff->pid, client);
+ :
+ : len = (client->req_len << 2) - sizeof(xRenderCreateRadialGradientReq);
+ : if (len != stuff->nStops*(sizeof(xFixed) + sizeof(xRenderColor)))
+ : return BadLength;
+ :
+ : stops = (xFixed *)(stuff + 1);
+ : colors = (xRenderColor *)(stops + stuff->nStops);
+ :
+ : pPicture = CreateRadialGradientPicture (stuff->pid, &stuff->inner, &stuff->outer,
+ : stuff->inner_radius, stuff->outer_radius,
+ : stuff->nStops, stops, colors, &error);
+ : if (!pPicture)
+ : return error;
+ : if (!AddResource (stuff->pid, PictureType, (pointer)pPicture))
+ : return BadAlloc;
+ : return Success;
+ :}
+ :
+ :static int ProcRenderCreateConicalGradient (ClientPtr client)
+ :{
+ : PicturePtr pPicture;
+ : int len;
+ : int error = 0;
+ : xFixed *stops;
+ : xRenderColor *colors;
+ : REQUEST(xRenderCreateConicalGradientReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderCreateConicalGradientReq);
+ :
+ : LEGAL_NEW_RESOURCE(stuff->pid, client);
+ :
+ : len = (client->req_len << 2) - sizeof(xRenderCreateConicalGradientReq);
+ : if (len != stuff->nStops*(sizeof(xFixed) + sizeof(xRenderColor)))
+ : return BadLength;
+ :
+ : stops = (xFixed *)(stuff + 1);
+ : colors = (xRenderColor *)(stops + stuff->nStops);
+ :
+ : pPicture = CreateConicalGradientPicture (stuff->pid, &stuff->center, stuff->angle,
+ : stuff->nStops, stops, colors, &error);
+ : if (!pPicture)
+ : return error;
+ : if (!AddResource (stuff->pid, PictureType, (pointer)pPicture))
+ : return BadAlloc;
+ : return Success;
+ :}
+ :
+ :
+ :static int
+ :ProcRenderDispatch (ClientPtr client)
+ 8 0.0087 :{ /* ProcRenderDispatch total: 10 0.0109 */
+ : REQUEST(xReq);
+ :
+ 1 0.0011 : if (stuff->data < RenderNumberRequests)
+ : return (*ProcRenderVector[stuff->data]) (client);
+ : else
+ : return BadRequest;
+ 1 0.0011 :}
+ :
+ :static int
+ :SProcRenderQueryVersion (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST(xRenderQueryVersionReq);
+ :
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->majorVersion, n);
+ : swapl(&stuff->minorVersion, n);
+ : return (*ProcRenderVector[stuff->renderReqType])(client);
+ :}
+ :
+ :static int
+ :SProcRenderQueryPictFormats (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST(xRenderQueryPictFormatsReq);
+ : swaps(&stuff->length, n);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderQueryPictIndexValues (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST(xRenderQueryPictIndexValuesReq);
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->format, n);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderQueryDithers (ClientPtr client)
+ :{
+ : return BadImplementation;
+ :}
+ :
+ :static int
+ :SProcRenderCreatePicture (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST(xRenderCreatePictureReq);
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->pid, n);
+ : swapl(&stuff->drawable, n);
+ : swapl(&stuff->format, n);
+ : swapl(&stuff->mask, n);
+ : SwapRestL(stuff);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderChangePicture (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST(xRenderChangePictureReq);
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->picture, n);
+ : swapl(&stuff->mask, n);
+ : SwapRestL(stuff);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderSetPictureClipRectangles (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST(xRenderSetPictureClipRectanglesReq);
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->picture, n);
+ : swaps(&stuff->xOrigin, n);
+ : swaps(&stuff->yOrigin, n);
+ : SwapRestS(stuff);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderFreePicture (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST(xRenderFreePictureReq);
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->picture, n);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderComposite (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST(xRenderCompositeReq);
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->src, n);
+ : swapl(&stuff->mask, n);
+ : swapl(&stuff->dst, n);
+ : swaps(&stuff->xSrc, n);
+ : swaps(&stuff->ySrc, n);
+ : swaps(&stuff->xMask, n);
+ : swaps(&stuff->yMask, n);
+ : swaps(&stuff->xDst, n);
+ : swaps(&stuff->yDst, n);
+ : swaps(&stuff->width, n);
+ : swaps(&stuff->height, n);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderScale (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST(xRenderScaleReq);
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->src, n);
+ : swapl(&stuff->dst, n);
+ : swapl(&stuff->colorScale, n);
+ : swapl(&stuff->alphaScale, n);
+ : swaps(&stuff->xSrc, n);
+ : swaps(&stuff->ySrc, n);
+ : swaps(&stuff->xDst, n);
+ : swaps(&stuff->yDst, n);
+ : swaps(&stuff->width, n);
+ : swaps(&stuff->height, n);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderTrapezoids (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST(xRenderTrapezoidsReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderTrapezoidsReq);
+ : swaps (&stuff->length, n);
+ : swapl (&stuff->src, n);
+ : swapl (&stuff->dst, n);
+ : swapl (&stuff->maskFormat, n);
+ : swaps (&stuff->xSrc, n);
+ : swaps (&stuff->ySrc, n);
+ : SwapRestL(stuff);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderTriangles (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST(xRenderTrianglesReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderTrianglesReq);
+ : swaps (&stuff->length, n);
+ : swapl (&stuff->src, n);
+ : swapl (&stuff->dst, n);
+ : swapl (&stuff->maskFormat, n);
+ : swaps (&stuff->xSrc, n);
+ : swaps (&stuff->ySrc, n);
+ : SwapRestL(stuff);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderTriStrip (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST(xRenderTriStripReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderTriStripReq);
+ : swaps (&stuff->length, n);
+ : swapl (&stuff->src, n);
+ : swapl (&stuff->dst, n);
+ : swapl (&stuff->maskFormat, n);
+ : swaps (&stuff->xSrc, n);
+ : swaps (&stuff->ySrc, n);
+ : SwapRestL(stuff);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderTriFan (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST(xRenderTriFanReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderTriFanReq);
+ : swaps (&stuff->length, n);
+ : swapl (&stuff->src, n);
+ : swapl (&stuff->dst, n);
+ : swapl (&stuff->maskFormat, n);
+ : swaps (&stuff->xSrc, n);
+ : swaps (&stuff->ySrc, n);
+ : SwapRestL(stuff);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderColorTrapezoids (ClientPtr client)
+ :{
+ : return BadImplementation;
+ :}
+ :
+ :static int
+ :SProcRenderColorTriangles (ClientPtr client)
+ :{
+ : return BadImplementation;
+ :}
+ :
+ :static int
+ :SProcRenderTransform (ClientPtr client)
+ :{
+ : return BadImplementation;
+ :}
+ :
+ :static int
+ :SProcRenderCreateGlyphSet (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST(xRenderCreateGlyphSetReq);
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->gsid, n);
+ : swapl(&stuff->format, n);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderReferenceGlyphSet (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST(xRenderReferenceGlyphSetReq);
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->gsid, n);
+ : swapl(&stuff->existing, n);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderFreeGlyphSet (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST(xRenderFreeGlyphSetReq);
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->glyphset, n);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderAddGlyphs (ClientPtr client)
+ :{
+ : register int n;
+ : register int i;
+ : CARD32 *gids;
+ : void *end;
+ : xGlyphInfo *gi;
+ : REQUEST(xRenderAddGlyphsReq);
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->glyphset, n);
+ : swapl(&stuff->nglyphs, n);
+ : if (stuff->nglyphs & 0xe0000000)
+ : return BadLength;
+ : end = (CARD8 *) stuff + (client->req_len << 2);
+ : gids = (CARD32 *) (stuff + 1);
+ : gi = (xGlyphInfo *) (gids + stuff->nglyphs);
+ : if ((char *) end - (char *) (gids + stuff->nglyphs) < 0)
+ : return BadLength;
+ : if ((char *) end - (char *) (gi + stuff->nglyphs) < 0)
+ : return BadLength;
+ : for (i = 0; i < stuff->nglyphs; i++)
+ : {
+ : swapl (&gids[i], n);
+ : swaps (&gi[i].width, n);
+ : swaps (&gi[i].height, n);
+ : swaps (&gi[i].x, n);
+ : swaps (&gi[i].y, n);
+ : swaps (&gi[i].xOff, n);
+ : swaps (&gi[i].yOff, n);
+ : }
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderAddGlyphsFromPicture (ClientPtr client)
+ :{
+ : return BadImplementation;
+ :}
+ :
+ :static int
+ :SProcRenderFreeGlyphs (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST(xRenderFreeGlyphsReq);
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->glyphset, n);
+ : SwapRestL(stuff);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderCompositeGlyphs (ClientPtr client)
+ :{
+ : register int n;
+ : xGlyphElt *elt;
+ : CARD8 *buffer;
+ : CARD8 *end;
+ : int space;
+ : int i;
+ : int size;
+ :
+ : REQUEST(xRenderCompositeGlyphsReq);
+ :
+ : switch (stuff->renderReqType) {
+ : default: size = 1; break;
+ : case X_RenderCompositeGlyphs16: size = 2; break;
+ : case X_RenderCompositeGlyphs32: size = 4; break;
+ : }
+ :
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->src, n);
+ : swapl(&stuff->dst, n);
+ : swapl(&stuff->maskFormat, n);
+ : swapl(&stuff->glyphset, n);
+ : swaps(&stuff->xSrc, n);
+ : swaps(&stuff->ySrc, n);
+ : buffer = (CARD8 *) (stuff + 1);
+ : end = (CARD8 *) stuff + (client->req_len << 2);
+ : while (buffer + sizeof (xGlyphElt) < end)
+ : {
+ : elt = (xGlyphElt *) buffer;
+ : buffer += sizeof (xGlyphElt);
+ :
+ : swaps (&elt->deltax, n);
+ : swaps (&elt->deltay, n);
+ :
+ : i = elt->len;
+ : if (i == 0xff)
+ : {
+ : swapl (buffer, n);
+ : buffer += 4;
+ : }
+ : else
+ : {
+ : space = size * i;
+ : switch (size) {
+ : case 1:
+ : buffer += i;
+ : break;
+ : case 2:
+ : while (i--)
+ : {
+ : swaps (buffer, n);
+ : buffer += 2;
+ : }
+ : break;
+ : case 4:
+ : while (i--)
+ : {
+ : swapl (buffer, n);
+ : buffer += 4;
+ : }
+ : break;
+ : }
+ : if (space & 3)
+ : buffer += 4 - (space & 3);
+ : }
+ : }
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderFillRectangles (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST(xRenderFillRectanglesReq);
+ :
+ : REQUEST_AT_LEAST_SIZE (xRenderFillRectanglesReq);
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->dst, n);
+ : swaps(&stuff->color.red, n);
+ : swaps(&stuff->color.green, n);
+ : swaps(&stuff->color.blue, n);
+ : swaps(&stuff->color.alpha, n);
+ : SwapRestS(stuff);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderCreateCursor (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST(xRenderCreateCursorReq);
+ : REQUEST_SIZE_MATCH (xRenderCreateCursorReq);
+ :
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->cid, n);
+ : swapl(&stuff->src, n);
+ : swaps(&stuff->x, n);
+ : swaps(&stuff->y, n);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderSetPictureTransform (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST(xRenderSetPictureTransformReq);
+ : REQUEST_SIZE_MATCH(xRenderSetPictureTransformReq);
+ :
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->picture, n);
+ : swapl(&stuff->transform.matrix11, n);
+ : swapl(&stuff->transform.matrix12, n);
+ : swapl(&stuff->transform.matrix13, n);
+ : swapl(&stuff->transform.matrix21, n);
+ : swapl(&stuff->transform.matrix22, n);
+ : swapl(&stuff->transform.matrix23, n);
+ : swapl(&stuff->transform.matrix31, n);
+ : swapl(&stuff->transform.matrix32, n);
+ : swapl(&stuff->transform.matrix33, n);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderQueryFilters (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST (xRenderQueryFiltersReq);
+ : REQUEST_SIZE_MATCH (xRenderQueryFiltersReq);
+ :
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->drawable, n);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderSetPictureFilter (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST (xRenderSetPictureFilterReq);
+ : REQUEST_AT_LEAST_SIZE (xRenderSetPictureFilterReq);
+ :
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->picture, n);
+ : swaps(&stuff->nbytes, n);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderCreateAnimCursor (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST (xRenderCreateAnimCursorReq);
+ : REQUEST_AT_LEAST_SIZE (xRenderCreateAnimCursorReq);
+ :
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->cid, n);
+ : SwapRestL(stuff);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderAddTraps (ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST (xRenderAddTrapsReq);
+ : REQUEST_AT_LEAST_SIZE (xRenderAddTrapsReq);
+ :
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->picture, n);
+ : swaps(&stuff->xOff, n);
+ : swaps(&stuff->yOff, n);
+ : SwapRestL(stuff);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderCreateSolidFill(ClientPtr client)
+ :{
+ : register int n;
+ : REQUEST (xRenderCreateSolidFillReq);
+ : REQUEST_AT_LEAST_SIZE (xRenderCreateSolidFillReq);
+ :
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->pid, n);
+ : swaps(&stuff->color.alpha, n);
+ : swaps(&stuff->color.red, n);
+ : swaps(&stuff->color.green, n);
+ : swaps(&stuff->color.blue, n);
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static void swapStops(void *stuff, int n)
+ :{
+ : int i;
+ : CARD32 *stops;
+ : CARD16 *colors;
+ : stops = (CARD32 *)(stuff);
+ : for (i = 0; i < n; ++i) {
+ : swapl(stops, n);
+ : ++stops;
+ : }
+ : colors = (CARD16 *)(stops);
+ : for (i = 0; i < 4*n; ++i) {
+ : swaps(stops, n);
+ : ++stops;
+ : }
+ :}
+ :
+ :static int
+ :SProcRenderCreateLinearGradient (ClientPtr client)
+ :{
+ : register int n;
+ : int len;
+ : REQUEST (xRenderCreateLinearGradientReq);
+ : REQUEST_AT_LEAST_SIZE (xRenderCreateLinearGradientReq);
+ :
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->pid, n);
+ : swapl(&stuff->p1.x, n);
+ : swapl(&stuff->p1.y, n);
+ : swapl(&stuff->p2.x, n);
+ : swapl(&stuff->p2.y, n);
+ : swapl(&stuff->nStops, n);
+ :
+ : len = (client->req_len << 2) - sizeof(xRenderCreateLinearGradientReq);
+ : if (len != stuff->nStops*(sizeof(xFixed) + sizeof(xRenderColor)))
+ : return BadLength;
+ :
+ : swapStops(stuff+1, stuff->nStops);
+ :
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderCreateRadialGradient (ClientPtr client)
+ :{
+ : register int n;
+ : int len;
+ : REQUEST (xRenderCreateRadialGradientReq);
+ : REQUEST_AT_LEAST_SIZE (xRenderCreateRadialGradientReq);
+ :
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->pid, n);
+ : swapl(&stuff->inner.x, n);
+ : swapl(&stuff->inner.y, n);
+ : swapl(&stuff->outer.x, n);
+ : swapl(&stuff->outer.y, n);
+ : swapl(&stuff->inner_radius, n);
+ : swapl(&stuff->outer_radius, n);
+ : swapl(&stuff->nStops, n);
+ :
+ : len = (client->req_len << 2) - sizeof(xRenderCreateRadialGradientReq);
+ : if (len != stuff->nStops*(sizeof(xFixed) + sizeof(xRenderColor)))
+ : return BadLength;
+ :
+ : swapStops(stuff+1, stuff->nStops);
+ :
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderCreateConicalGradient (ClientPtr client)
+ :{
+ : register int n;
+ : int len;
+ : REQUEST (xRenderCreateConicalGradientReq);
+ : REQUEST_AT_LEAST_SIZE (xRenderCreateConicalGradientReq);
+ :
+ : swaps(&stuff->length, n);
+ : swapl(&stuff->pid, n);
+ : swapl(&stuff->center.x, n);
+ : swapl(&stuff->center.y, n);
+ : swapl(&stuff->angle, n);
+ : swapl(&stuff->nStops, n);
+ :
+ : len = (client->req_len << 2) - sizeof(xRenderCreateConicalGradientReq);
+ : if (len != stuff->nStops*(sizeof(xFixed) + sizeof(xRenderColor)))
+ : return BadLength;
+ :
+ : swapStops(stuff+1, stuff->nStops);
+ :
+ : return (*ProcRenderVector[stuff->renderReqType]) (client);
+ :}
+ :
+ :static int
+ :SProcRenderDispatch (ClientPtr client)
+ :{
+ : REQUEST(xReq);
+ :
+ : if (stuff->data < RenderNumberRequests)
+ : return (*SProcRenderVector[stuff->data]) (client);
+ : else
+ : return BadRequest;
+ :}
+ :
+ :#ifdef PANORAMIX
+ :#include "panoramiX.h"
+ :#include "panoramiXsrv.h"
+ :
+ :#define VERIFY_XIN_PICTURE(pPicture, pid, client, mode, err) {\
+ : pPicture = SecurityLookupIDByType(client, pid, XRT_PICTURE, mode);\
+ : if (!pPicture) { \
+ : client->errorValue = pid; \
+ : return err; \
+ : } \
+ :}
+ :
+ :#define VERIFY_XIN_ALPHA(pPicture, pid, client, mode, err) {\
+ : if (pid == None) \
+ : pPicture = 0; \
+ : else { \
+ : VERIFY_XIN_PICTURE(pPicture, pid, client, mode, err); \
+ : } \
+ :} \
+ :
+ :int (*PanoramiXSaveRenderVector[RenderNumberRequests])(ClientPtr);
+ :
+ :unsigned long XRT_PICTURE;
+ :
+ :static int
+ :PanoramiXRenderCreatePicture (ClientPtr client)
+ :{
+ : REQUEST(xRenderCreatePictureReq);
+ : PanoramiXRes *refDraw, *newPict;
+ : int result = Success, j;
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderCreatePictureReq);
+ : if(!(refDraw = (PanoramiXRes *)SecurityLookupIDByClass(
+ : client, stuff->drawable, XRC_DRAWABLE, DixWriteAccess)))
+ : return BadDrawable;
+ : if(!(newPict = (PanoramiXRes *) xalloc(sizeof(PanoramiXRes))))
+ : return BadAlloc;
+ : newPict->type = XRT_PICTURE;
+ : newPict->info[0].id = stuff->pid;
+ :
+ : if (refDraw->type == XRT_WINDOW &&
+ : stuff->drawable == WindowTable[0]->drawable.id)
+ : {
+ : newPict->u.pict.root = TRUE;
+ : }
+ : else
+ : newPict->u.pict.root = FALSE;
+ :
+ : for(j = 1; j < PanoramiXNumScreens; j++)
+ : newPict->info[j].id = FakeClientID(client->index);
+ :
+ : FOR_NSCREENS_BACKWARD(j) {
+ : stuff->pid = newPict->info[j].id;
+ : stuff->drawable = refDraw->info[j].id;
+ : result = (*PanoramiXSaveRenderVector[X_RenderCreatePicture]) (client);
+ : if(result != Success) break;
+ : }
+ :
+ : if (result == Success)
+ : AddResource(newPict->info[0].id, XRT_PICTURE, newPict);
+ : else
+ : xfree(newPict);
+ :
+ : return (result);
+ :}
+ :
+ :static int
+ :PanoramiXRenderChangePicture (ClientPtr client)
+ :{
+ : PanoramiXRes *pict;
+ : int result = Success, j;
+ : REQUEST(xRenderChangePictureReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xChangeWindowAttributesReq);
+ :
+ : VERIFY_XIN_PICTURE(pict, stuff->picture, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ :
+ : FOR_NSCREENS_BACKWARD(j) {
+ : stuff->picture = pict->info[j].id;
+ : result = (*PanoramiXSaveRenderVector[X_RenderChangePicture]) (client);
+ : if(result != Success) break;
+ : }
+ :
+ : return (result);
+ :}
+ :
+ :static int
+ :PanoramiXRenderSetPictureClipRectangles (ClientPtr client)
+ :{
+ : REQUEST(xRenderSetPictureClipRectanglesReq);
+ : int result = Success, j;
+ : PanoramiXRes *pict;
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderSetPictureClipRectanglesReq);
+ :
+ : VERIFY_XIN_PICTURE(pict, stuff->picture, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ :
+ : FOR_NSCREENS_BACKWARD(j) {
+ : stuff->picture = pict->info[j].id;
+ : result = (*PanoramiXSaveRenderVector[X_RenderSetPictureClipRectangles]) (client);
+ : if(result != Success) break;
+ : }
+ :
+ : return (result);
+ :}
+ :
+ :static int
+ :PanoramiXRenderSetPictureTransform (ClientPtr client)
+ :{
+ : REQUEST(xRenderSetPictureTransformReq);
+ : int result = Success, j;
+ : PanoramiXRes *pict;
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderSetPictureTransformReq);
+ :
+ : VERIFY_XIN_PICTURE(pict, stuff->picture, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ :
+ : FOR_NSCREENS_BACKWARD(j) {
+ : stuff->picture = pict->info[j].id;
+ : result = (*PanoramiXSaveRenderVector[X_RenderSetPictureTransform]) (client);
+ : if(result != Success) break;
+ : }
+ :
+ : return (result);
+ :}
+ :
+ :static int
+ :PanoramiXRenderSetPictureFilter (ClientPtr client)
+ :{
+ : REQUEST(xRenderSetPictureFilterReq);
+ : int result = Success, j;
+ : PanoramiXRes *pict;
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderSetPictureFilterReq);
+ :
+ : VERIFY_XIN_PICTURE(pict, stuff->picture, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ :
+ : FOR_NSCREENS_BACKWARD(j) {
+ : stuff->picture = pict->info[j].id;
+ : result = (*PanoramiXSaveRenderVector[X_RenderSetPictureFilter]) (client);
+ : if(result != Success) break;
+ : }
+ :
+ : return (result);
+ :}
+ :
+ :static int
+ :PanoramiXRenderFreePicture (ClientPtr client)
+ :{
+ : PanoramiXRes *pict;
+ : int result = Success, j;
+ : REQUEST(xRenderFreePictureReq);
+ :
+ : REQUEST_SIZE_MATCH(xRenderFreePictureReq);
+ :
+ : client->errorValue = stuff->picture;
+ :
+ : VERIFY_XIN_PICTURE(pict, stuff->picture, client, DixDestroyAccess,
+ : RenderErrBase + BadPicture);
+ :
+ :
+ : FOR_NSCREENS_BACKWARD(j) {
+ : stuff->picture = pict->info[j].id;
+ : result = (*PanoramiXSaveRenderVector[X_RenderFreePicture]) (client);
+ : if(result != Success) break;
+ : }
+ :
+ : /* Since ProcRenderFreePicture is using FreeResource, it will free
+ : our resource for us on the last pass through the loop above */
+ :
+ : return (result);
+ :}
+ :
+ :static int
+ :PanoramiXRenderComposite (ClientPtr client)
+ :{
+ : PanoramiXRes *src, *msk, *dst;
+ : int result = Success, j;
+ : xRenderCompositeReq orig;
+ : REQUEST(xRenderCompositeReq);
+ :
+ : REQUEST_SIZE_MATCH(xRenderCompositeReq);
+ :
+ : VERIFY_XIN_PICTURE (src, stuff->src, client, DixReadAccess,
+ : RenderErrBase + BadPicture);
+ : VERIFY_XIN_ALPHA (msk, stuff->mask, client, DixReadAccess,
+ : RenderErrBase + BadPicture);
+ : VERIFY_XIN_PICTURE (dst, stuff->dst, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ :
+ : orig = *stuff;
+ :
+ : FOR_NSCREENS_FORWARD(j) {
+ : stuff->src = src->info[j].id;
+ : if (src->u.pict.root)
+ : {
+ : stuff->xSrc = orig.xSrc - panoramiXdataPtr[j].x;
+ : stuff->ySrc = orig.ySrc - panoramiXdataPtr[j].y;
+ : }
+ : stuff->dst = dst->info[j].id;
+ : if (dst->u.pict.root)
+ : {
+ : stuff->xDst = orig.xDst - panoramiXdataPtr[j].x;
+ : stuff->yDst = orig.yDst - panoramiXdataPtr[j].y;
+ : }
+ : if (msk)
+ : {
+ : stuff->mask = msk->info[j].id;
+ : if (msk->u.pict.root)
+ : {
+ : stuff->xMask = orig.xMask - panoramiXdataPtr[j].x;
+ : stuff->yMask = orig.yMask - panoramiXdataPtr[j].y;
+ : }
+ : }
+ : result = (*PanoramiXSaveRenderVector[X_RenderComposite]) (client);
+ : if(result != Success) break;
+ : }
+ :
+ : return result;
+ :}
+ :
+ :static int
+ :PanoramiXRenderCompositeGlyphs (ClientPtr client)
+ :{
+ : PanoramiXRes *src, *dst;
+ : int result = Success, j;
+ : REQUEST(xRenderCompositeGlyphsReq);
+ : xGlyphElt origElt, *elt;
+ : INT16 xSrc, ySrc;
+ :
+ : REQUEST_AT_LEAST_SIZE(xRenderCompositeGlyphsReq);
+ : VERIFY_XIN_PICTURE (src, stuff->src, client, DixReadAccess,
+ : RenderErrBase + BadPicture);
+ : VERIFY_XIN_PICTURE (dst, stuff->dst, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ :
+ : if (client->req_len << 2 >= (sizeof (xRenderCompositeGlyphsReq) +
+ : sizeof (xGlyphElt)))
+ : {
+ : elt = (xGlyphElt *) (stuff + 1);
+ : origElt = *elt;
+ : xSrc = stuff->xSrc;
+ : ySrc = stuff->ySrc;
+ : FOR_NSCREENS_FORWARD(j) {
+ : stuff->src = src->info[j].id;
+ : if (src->u.pict.root)
+ : {
+ : stuff->xSrc = xSrc - panoramiXdataPtr[j].x;
+ : stuff->ySrc = ySrc - panoramiXdataPtr[j].y;
+ : }
+ : stuff->dst = dst->info[j].id;
+ : if (dst->u.pict.root)
+ : {
+ : elt->deltax = origElt.deltax - panoramiXdataPtr[j].x;
+ : elt->deltay = origElt.deltay - panoramiXdataPtr[j].y;
+ : }
+ : result = (*PanoramiXSaveRenderVector[stuff->renderReqType]) (client);
+ : if(result != Success) break;
+ : }
+ : }
+ :
+ : return result;
+ :}
+ :
+ :static int
+ :PanoramiXRenderFillRectangles (ClientPtr client)
+ :{
+ : PanoramiXRes *dst;
+ : int result = Success, j;
+ : REQUEST(xRenderFillRectanglesReq);
+ : char *extra;
+ : int extra_len;
+ :
+ : REQUEST_AT_LEAST_SIZE (xRenderFillRectanglesReq);
+ : VERIFY_XIN_PICTURE (dst, stuff->dst, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ : extra_len = (client->req_len << 2) - sizeof (xRenderFillRectanglesReq);
+ : if (extra_len &&
+ : (extra = (char *) ALLOCATE_LOCAL (extra_len)))
+ : {
+ : memcpy (extra, stuff + 1, extra_len);
+ : FOR_NSCREENS_FORWARD(j) {
+ : if (j) memcpy (stuff + 1, extra, extra_len);
+ : if (dst->u.pict.root)
+ : {
+ : int x_off = panoramiXdataPtr[j].x;
+ : int y_off = panoramiXdataPtr[j].y;
+ :
+ : if(x_off || y_off) {
+ : xRectangle *rects = (xRectangle *) (stuff + 1);
+ : int i = extra_len / sizeof (xRectangle);
+ :
+ : while (i--)
+ : {
+ : rects->x -= x_off;
+ : rects->y -= y_off;
+ : rects++;
+ : }
+ : }
+ : }
+ : stuff->dst = dst->info[j].id;
+ : result = (*PanoramiXSaveRenderVector[X_RenderFillRectangles]) (client);
+ : if(result != Success) break;
+ : }
+ : DEALLOCATE_LOCAL(extra);
+ : }
+ :
+ : return result;
+ :}
+ :
+ :static int
+ :PanoramiXRenderTrapezoids(ClientPtr client)
+ :{
+ : PanoramiXRes *src, *dst;
+ : int result = Success, j;
+ : REQUEST(xRenderTrapezoidsReq);
+ : char *extra;
+ : int extra_len;
+ :
+ : REQUEST_AT_LEAST_SIZE (xRenderTrapezoidsReq);
+ :
+ : VERIFY_XIN_PICTURE (src, stuff->src, client, DixReadAccess,
+ : RenderErrBase + BadPicture);
+ : VERIFY_XIN_PICTURE (dst, stuff->dst, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ :
+ : extra_len = (client->req_len << 2) - sizeof (xRenderTrapezoidsReq);
+ :
+ : if (extra_len &&
+ : (extra = (char *) ALLOCATE_LOCAL (extra_len))) {
+ : memcpy (extra, stuff + 1, extra_len);
+ :
+ : FOR_NSCREENS_FORWARD(j) {
+ : if (j) memcpy (stuff + 1, extra, extra_len);
+ : if (dst->u.pict.root) {
+ : int x_off = panoramiXdataPtr[j].x;
+ : int y_off = panoramiXdataPtr[j].y;
+ :
+ : if(x_off || y_off) {
+ : xTrapezoid *trap = (xTrapezoid *) (stuff + 1);
+ : int i = extra_len / sizeof (xTrapezoid);
+ :
+ : while (i--) {
+ : trap->top -= y_off;
+ : trap->bottom -= y_off;
+ : trap->left.p1.x -= x_off;
+ : trap->left.p1.y -= y_off;
+ : trap->left.p2.x -= x_off;
+ : trap->left.p2.y -= y_off;
+ : trap->right.p1.x -= x_off;
+ : trap->right.p1.y -= y_off;
+ : trap->right.p2.x -= x_off;
+ : trap->right.p2.y -= y_off;
+ : trap++;
+ : }
+ : }
+ : }
+ :
+ : stuff->src = src->info[j].id;
+ : stuff->dst = dst->info[j].id;
+ : result =
+ : (*PanoramiXSaveRenderVector[X_RenderTrapezoids]) (client);
+ :
+ : if(result != Success) break;
+ : }
+ :
+ : DEALLOCATE_LOCAL(extra);
+ : }
+ :
+ : return result;
+ :}
+ :
+ :static int
+ :PanoramiXRenderTriangles(ClientPtr client)
+ :{
+ : PanoramiXRes *src, *dst;
+ : int result = Success, j;
+ : REQUEST(xRenderTrianglesReq);
+ : char *extra;
+ : int extra_len;
+ :
+ : REQUEST_AT_LEAST_SIZE (xRenderTrianglesReq);
+ :
+ : VERIFY_XIN_PICTURE (src, stuff->src, client, DixReadAccess,
+ : RenderErrBase + BadPicture);
+ : VERIFY_XIN_PICTURE (dst, stuff->dst, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ :
+ : extra_len = (client->req_len << 2) - sizeof (xRenderTrianglesReq);
+ :
+ : if (extra_len &&
+ : (extra = (char *) ALLOCATE_LOCAL (extra_len))) {
+ : memcpy (extra, stuff + 1, extra_len);
+ :
+ : FOR_NSCREENS_FORWARD(j) {
+ : if (j) memcpy (stuff + 1, extra, extra_len);
+ : if (dst->u.pict.root) {
+ : int x_off = panoramiXdataPtr[j].x;
+ : int y_off = panoramiXdataPtr[j].y;
+ :
+ : if(x_off || y_off) {
+ : xTriangle *tri = (xTriangle *) (stuff + 1);
+ : int i = extra_len / sizeof (xTriangle);
+ :
+ : while (i--) {
+ : tri->p1.x -= x_off;
+ : tri->p1.y -= y_off;
+ : tri->p2.x -= x_off;
+ : tri->p2.y -= y_off;
+ : tri->p3.x -= x_off;
+ : tri->p3.y -= y_off;
+ : tri++;
+ : }
+ : }
+ : }
+ :
+ : stuff->src = src->info[j].id;
+ : stuff->dst = dst->info[j].id;
+ : result =
+ : (*PanoramiXSaveRenderVector[X_RenderTriangles]) (client);
+ :
+ : if(result != Success) break;
+ : }
+ :
+ : DEALLOCATE_LOCAL(extra);
+ : }
+ :
+ : return result;
+ :}
+ :
+ :static int
+ :PanoramiXRenderTriStrip(ClientPtr client)
+ :{
+ : PanoramiXRes *src, *dst;
+ : int result = Success, j;
+ : REQUEST(xRenderTriStripReq);
+ : char *extra;
+ : int extra_len;
+ :
+ : REQUEST_AT_LEAST_SIZE (xRenderTriStripReq);
+ :
+ : VERIFY_XIN_PICTURE (src, stuff->src, client, DixReadAccess,
+ : RenderErrBase + BadPicture);
+ : VERIFY_XIN_PICTURE (dst, stuff->dst, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ :
+ : extra_len = (client->req_len << 2) - sizeof (xRenderTriStripReq);
+ :
+ : if (extra_len &&
+ : (extra = (char *) ALLOCATE_LOCAL (extra_len))) {
+ : memcpy (extra, stuff + 1, extra_len);
+ :
+ : FOR_NSCREENS_FORWARD(j) {
+ : if (j) memcpy (stuff + 1, extra, extra_len);
+ : if (dst->u.pict.root) {
+ : int x_off = panoramiXdataPtr[j].x;
+ : int y_off = panoramiXdataPtr[j].y;
+ :
+ : if(x_off || y_off) {
+ : xPointFixed *fixed = (xPointFixed *) (stuff + 1);
+ : int i = extra_len / sizeof (xPointFixed);
+ :
+ : while (i--) {
+ : fixed->x -= x_off;
+ : fixed->y -= y_off;
+ : fixed++;
+ : }
+ : }
+ : }
+ :
+ : stuff->src = src->info[j].id;
+ : stuff->dst = dst->info[j].id;
+ : result =
+ : (*PanoramiXSaveRenderVector[X_RenderTriStrip]) (client);
+ :
+ : if(result != Success) break;
+ : }
+ :
+ : DEALLOCATE_LOCAL(extra);
+ : }
+ :
+ : return result;
+ :}
+ :
+ :static int
+ :PanoramiXRenderTriFan(ClientPtr client)
+ :{
+ : PanoramiXRes *src, *dst;
+ : int result = Success, j;
+ : REQUEST(xRenderTriFanReq);
+ : char *extra;
+ : int extra_len;
+ :
+ : REQUEST_AT_LEAST_SIZE (xRenderTriFanReq);
+ :
+ : VERIFY_XIN_PICTURE (src, stuff->src, client, DixReadAccess,
+ : RenderErrBase + BadPicture);
+ : VERIFY_XIN_PICTURE (dst, stuff->dst, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ :
+ : extra_len = (client->req_len << 2) - sizeof (xRenderTriFanReq);
+ :
+ : if (extra_len &&
+ : (extra = (char *) ALLOCATE_LOCAL (extra_len))) {
+ : memcpy (extra, stuff + 1, extra_len);
+ :
+ : FOR_NSCREENS_FORWARD(j) {
+ : if (j) memcpy (stuff + 1, extra, extra_len);
+ : if (dst->u.pict.root) {
+ : int x_off = panoramiXdataPtr[j].x;
+ : int y_off = panoramiXdataPtr[j].y;
+ :
+ : if(x_off || y_off) {
+ : xPointFixed *fixed = (xPointFixed *) (stuff + 1);
+ : int i = extra_len / sizeof (xPointFixed);
+ :
+ : while (i--) {
+ : fixed->x -= x_off;
+ : fixed->y -= y_off;
+ : fixed++;
+ : }
+ : }
+ : }
+ :
+ : stuff->src = src->info[j].id;
+ : stuff->dst = dst->info[j].id;
+ : result =
+ : (*PanoramiXSaveRenderVector[X_RenderTriFan]) (client);
+ :
+ : if(result != Success) break;
+ : }
+ :
+ : DEALLOCATE_LOCAL(extra);
+ : }
+ :
+ : return result;
+ :}
+ :
+ :#if 0 /* Not implemented yet */
+ :
+ :static int
+ :PanoramiXRenderColorTrapezoids(ClientPtr client)
+ :{
+ : PanoramiXRes *src, *dst;
+ : int result = Success, j;
+ : REQUEST(xRenderColorTrapezoidsReq);
+ : char *extra;
+ : int extra_len;
+ :
+ : REQUEST_AT_LEAST_SIZE (xRenderColorTrapezoidsReq);
+ :
+ : VERIFY_XIN_PICTURE (dst, stuff->dst, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ :
+ : extra_len = (client->req_len << 2) - sizeof (xRenderColorTrapezoidsReq);
+ :
+ : if (extra_len &&
+ : (extra = (char *) ALLOCATE_LOCAL (extra_len))) {
+ : memcpy (extra, stuff + 1, extra_len);
+ :
+ : FOR_NSCREENS_FORWARD(j) {
+ : if (j) memcpy (stuff + 1, extra, extra_len);
+ : if (dst->u.pict.root) {
+ : int x_off = panoramiXdataPtr[j].x;
+ : int y_off = panoramiXdataPtr[j].y;
+ :
+ : if(x_off || y_off) {
+ : ....;
+ : }
+ : }
+ :
+ : stuff->dst = dst->info[j].id;
+ : result =
+ : (*PanoramiXSaveRenderVector[X_RenderColorTrapezoids]) (client);
+ :
+ : if(result != Success) break;
+ : }
+ :
+ : DEALLOCATE_LOCAL(extra);
+ : }
+ :
+ : return result;
+ :}
+ :
+ :static int
+ :PanoramiXRenderColorTriangles(ClientPtr client)
+ :{
+ : PanoramiXRes *src, *dst;
+ : int result = Success, j;
+ : REQUEST(xRenderColorTrianglesReq);
+ : char *extra;
+ : int extra_len;
+ :
+ : REQUEST_AT_LEAST_SIZE (xRenderColorTrianglesReq);
+ :
+ : VERIFY_XIN_PICTURE (dst, stuff->dst, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ :
+ : extra_len = (client->req_len << 2) - sizeof (xRenderColorTrianglesReq);
+ :
+ : if (extra_len &&
+ : (extra = (char *) ALLOCATE_LOCAL (extra_len))) {
+ : memcpy (extra, stuff + 1, extra_len);
+ :
+ : FOR_NSCREENS_FORWARD(j) {
+ : if (j) memcpy (stuff + 1, extra, extra_len);
+ : if (dst->u.pict.root) {
+ : int x_off = panoramiXdataPtr[j].x;
+ : int y_off = panoramiXdataPtr[j].y;
+ :
+ : if(x_off || y_off) {
+ : ....;
+ : }
+ : }
+ :
+ : stuff->dst = dst->info[j].id;
+ : result =
+ : (*PanoramiXSaveRenderVector[X_RenderColorTriangles]) (client);
+ :
+ : if(result != Success) break;
+ : }
+ :
+ : DEALLOCATE_LOCAL(extra);
+ : }
+ :
+ : return result;
+ :}
+ :
+ :#endif
+ :
+ :static int
+ :PanoramiXRenderAddTraps (ClientPtr client)
+ :{
+ : PanoramiXRes *picture;
+ : int result = Success, j;
+ : REQUEST(xRenderAddTrapsReq);
+ : char *extra;
+ : int extra_len;
+ : INT16 x_off, y_off;
+ :
+ : REQUEST_AT_LEAST_SIZE (xRenderAddTrapsReq);
+ : VERIFY_XIN_PICTURE (picture, stuff->picture, client, DixWriteAccess,
+ : RenderErrBase + BadPicture);
+ : extra_len = (client->req_len << 2) - sizeof (xRenderAddTrapsReq);
+ : if (extra_len &&
+ : (extra = (char *) ALLOCATE_LOCAL (extra_len)))
+ : {
+ : memcpy (extra, stuff + 1, extra_len);
+ : x_off = stuff->xOff;
+ : y_off = stuff->yOff;
+ : FOR_NSCREENS_FORWARD(j) {
+ : if (j) memcpy (stuff + 1, extra, extra_len);
+ : stuff->picture = picture->info[j].id;
+ :
+ : if (picture->u.pict.root)
+ : {
+ : stuff->xOff = x_off + panoramiXdataPtr[j].x;
+ : stuff->yOff = y_off + panoramiXdataPtr[j].y;
+ : }
+ : result = (*PanoramiXSaveRenderVector[X_RenderAddTraps]) (client);
+ : if(result != Success) break;
+ : }
+ : DEALLOCATE_LOCAL(extra);
+ : }
+ :
+ : return result;
+ :}
+ :
+ :void
+ :PanoramiXRenderInit (void)
+ :{
+ : int i;
+ :
+ : XRT_PICTURE = CreateNewResourceType (XineramaDeleteResource);
+ : for (i = 0; i < RenderNumberRequests; i++)
+ : PanoramiXSaveRenderVector[i] = ProcRenderVector[i];
+ : /*
+ : * Stuff in Xinerama aware request processing hooks
+ : */
+ : ProcRenderVector[X_RenderCreatePicture] = PanoramiXRenderCreatePicture;
+ : ProcRenderVector[X_RenderChangePicture] = PanoramiXRenderChangePicture;
+ : ProcRenderVector[X_RenderSetPictureTransform] = PanoramiXRenderSetPictureTransform;
+ : ProcRenderVector[X_RenderSetPictureFilter] = PanoramiXRenderSetPictureFilter;
+ : ProcRenderVector[X_RenderSetPictureClipRectangles] = PanoramiXRenderSetPictureClipRectangles;
+ : ProcRenderVector[X_RenderFreePicture] = PanoramiXRenderFreePicture;
+ : ProcRenderVector[X_RenderComposite] = PanoramiXRenderComposite;
+ : ProcRenderVector[X_RenderCompositeGlyphs8] = PanoramiXRenderCompositeGlyphs;
+ : ProcRenderVector[X_RenderCompositeGlyphs16] = PanoramiXRenderCompositeGlyphs;
+ : ProcRenderVector[X_RenderCompositeGlyphs32] = PanoramiXRenderCompositeGlyphs;
+ : ProcRenderVector[X_RenderFillRectangles] = PanoramiXRenderFillRectangles;
+ :
+ : ProcRenderVector[X_RenderTrapezoids] = PanoramiXRenderTrapezoids;
+ : ProcRenderVector[X_RenderTriangles] = PanoramiXRenderTriangles;
+ : ProcRenderVector[X_RenderTriStrip] = PanoramiXRenderTriStrip;
+ : ProcRenderVector[X_RenderTriFan] = PanoramiXRenderTriFan;
+ : ProcRenderVector[X_RenderAddTraps] = PanoramiXRenderAddTraps;
+ :}
+ :
+ :void
+ :PanoramiXRenderReset (void)
+ :{
+ : int i;
+ : for (i = 0; i < RenderNumberRequests; i++)
+ : ProcRenderVector[i] = PanoramiXSaveRenderVector[i];
+ :}
+ :
+ :#endif /* PANORAMIX */
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/render/picture.c"
+ *
+ * 74 0.0806
+ */
+
+
+ :/*
+ : *
+ : * Copyright © 2000 SuSE, Inc.
+ : *
+ : * 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 SuSE not be used in advertising or
+ : * publicity pertaining to distribution of the software without specific,
+ : * written prior permission. SuSE makes no representations about the
+ : * suitability of this software for any purpose. It is provided "as is"
+ : * without express or implied warranty.
+ : *
+ : * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ : * 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: Keith Packard, SuSE, Inc.
+ : */
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include "misc.h"
+ :#include "scrnintstr.h"
+ :#include "os.h"
+ :#include "regionstr.h"
+ :#include "validate.h"
+ :#include "windowstr.h"
+ :#include "input.h"
+ :#include "resource.h"
+ :#include "colormapst.h"
+ :#include "cursorstr.h"
+ :#include "dixstruct.h"
+ :#include "gcstruct.h"
+ :#include "servermd.h"
+ :#include "picturestr.h"
+ :
+ :_X_EXPORT int PictureScreenPrivateIndex = -1;
+ :int PictureWindowPrivateIndex;
+ :static int PictureGeneration;
+ :RESTYPE PictureType;
+ :RESTYPE PictFormatType;
+ :RESTYPE GlyphSetType;
+ :int PictureCmapPolicy = PictureCmapPolicyDefault;
+ :
+ :/* Picture Private machinery */
+ :
+ :static int picturePrivateCount;
+ :
+ :void
+ :ResetPicturePrivateIndex (void)
+ :{
+ : picturePrivateCount = 0;
+ :}
+ :
+ :int
+ :AllocatePicturePrivateIndex (void)
+ :{
+ : return picturePrivateCount++;
+ :}
+ :
+ :Bool
+ :AllocatePicturePrivate (ScreenPtr pScreen, int index2, unsigned int amount)
+ :{
+ : PictureScreenPtr ps = GetPictureScreen(pScreen);
+ : unsigned int oldamount;
+ :
+ : /* Round up sizes for proper alignment */
+ : amount = ((amount + (sizeof(long) - 1)) / sizeof(long)) * sizeof(long);
+ :
+ : if (index2 >= ps->PicturePrivateLen)
+ : {
+ : unsigned int *nsizes;
+ :
+ : nsizes = (unsigned int *)xrealloc(ps->PicturePrivateSizes,
+ : (index2 + 1) * sizeof(unsigned int));
+ : if (!nsizes)
+ : return FALSE;
+ : while (ps->PicturePrivateLen <= index2)
+ : {
+ : nsizes[ps->PicturePrivateLen++] = 0;
+ : ps->totalPictureSize += sizeof(DevUnion);
+ : }
+ : ps->PicturePrivateSizes = nsizes;
+ : }
+ : oldamount = ps->PicturePrivateSizes[index2];
+ : if (amount > oldamount)
+ : {
+ : ps->PicturePrivateSizes[index2] = amount;
+ : ps->totalPictureSize += (amount - oldamount);
+ : }
+ :
+ : return TRUE;
+ :}
+ :
+ :
+ :Bool
+ :PictureDestroyWindow (WindowPtr pWindow)
+ :{
+ : ScreenPtr pScreen = pWindow->drawable.pScreen;
+ : PicturePtr pPicture;
+ : PictureScreenPtr ps = GetPictureScreen(pScreen);
+ : Bool ret;
+ :
+ : while ((pPicture = GetPictureWindow(pWindow)))
+ : {
+ : SetPictureWindow(pWindow, pPicture->pNext);
+ : if (pPicture->id)
+ : FreeResource (pPicture->id, PictureType);
+ : FreePicture ((pointer) pPicture, pPicture->id);
+ : }
+ : pScreen->DestroyWindow = ps->DestroyWindow;
+ : ret = (*pScreen->DestroyWindow) (pWindow);
+ : ps->DestroyWindow = pScreen->DestroyWindow;
+ : pScreen->DestroyWindow = PictureDestroyWindow;
+ : return ret;
+ :}
+ :
+ :Bool
+ :PictureCloseScreen (int index, ScreenPtr pScreen)
+ :{
+ : PictureScreenPtr ps = GetPictureScreen(pScreen);
+ : Bool ret;
+ : int n;
+ :
+ : pScreen->CloseScreen = ps->CloseScreen;
+ : ret = (*pScreen->CloseScreen) (index, pScreen);
+ : PictureResetFilters (pScreen);
+ : for (n = 0; n < ps->nformats; n++)
+ : if (ps->formats[n].type == PictTypeIndexed)
+ : (*ps->CloseIndexed) (pScreen, &ps->formats[n]);
+ : GlyphUninit (pScreen);
+ : SetPictureScreen(pScreen, 0);
+ : if (ps->PicturePrivateSizes)
+ : xfree (ps->PicturePrivateSizes);
+ : xfree (ps->formats);
+ : xfree (ps);
+ : return ret;
+ :}
+ :
+ :void
+ :PictureStoreColors (ColormapPtr pColormap, int ndef, xColorItem *pdef)
+ :{
+ : ScreenPtr pScreen = pColormap->pScreen;
+ : PictureScreenPtr ps = GetPictureScreen(pScreen);
+ :
+ : pScreen->StoreColors = ps->StoreColors;
+ : (*pScreen->StoreColors) (pColormap, ndef, pdef);
+ : ps->StoreColors = pScreen->StoreColors;
+ : pScreen->StoreColors = PictureStoreColors;
+ :
+ : if (pColormap->class == PseudoColor || pColormap->class == GrayScale)
+ : {
+ : PictFormatPtr format = ps->formats;
+ : int nformats = ps->nformats;
+ :
+ : while (nformats--)
+ : {
+ : if (format->type == PictTypeIndexed &&
+ : format->index.pColormap == pColormap)
+ : {
+ : (*ps->UpdateIndexed) (pScreen, format, ndef, pdef);
+ : break;
+ : }
+ : format++;
+ : }
+ : }
+ :}
+ :
+ :static int
+ :visualDepth (ScreenPtr pScreen, VisualPtr pVisual)
+ :{
+ : int d, v;
+ : DepthPtr pDepth;
+ :
+ : for (d = 0; d < pScreen->numDepths; d++)
+ : {
+ : pDepth = &pScreen->allowedDepths[d];
+ : for (v = 0; v < pDepth->numVids; v++)
+ : if (pDepth->vids[v] == pVisual->vid)
+ : return pDepth->depth;
+ : }
+ : return 0;
+ :}
+ :
+ :typedef struct _formatInit {
+ : CARD32 format;
+ : CARD8 depth;
+ :} FormatInitRec, *FormatInitPtr;
+ :
+ :static int
+ :addFormat (FormatInitRec formats[256],
+ : int nformat,
+ : CARD32 format,
+ : CARD8 depth)
+ :{
+ : int n;
+ :
+ : for (n = 0; n < nformat; n++)
+ : if (formats[n].format == format && formats[n].depth == depth)
+ : return nformat;
+ : formats[nformat].format = format;
+ : formats[nformat].depth = depth;
+ : return ++nformat;
+ :}
+ :
+ :#define Mask(n) ((n) == 32 ? 0xffffffff : ((1 << (n))-1))
+ :
+ :PictFormatPtr
+ :PictureCreateDefaultFormats (ScreenPtr pScreen, int *nformatp)
+ :{
+ : int nformats, f;
+ : PictFormatPtr pFormats;
+ : FormatInitRec formats[1024];
+ : CARD32 format;
+ : CARD8 depth;
+ : VisualPtr pVisual;
+ : int v;
+ : int bpp;
+ : int type;
+ : int r, g, b;
+ : int d;
+ : DepthPtr pDepth;
+ :
+ : nformats = 0;
+ : /* formats required by protocol */
+ : formats[nformats].format = PICT_a1;
+ : formats[nformats].depth = 1;
+ : nformats++;
+ : formats[nformats].format = PICT_FORMAT(BitsPerPixel(8),
+ : PICT_TYPE_A,
+ : 8, 0, 0, 0);
+ : formats[nformats].depth = 8;
+ : nformats++;
+ : formats[nformats].format = PICT_FORMAT(BitsPerPixel(4),
+ : PICT_TYPE_A,
+ : 4, 0, 0, 0);
+ : formats[nformats].depth = 4;
+ : nformats++;
+ : formats[nformats].format = PICT_a8r8g8b8;
+ : formats[nformats].depth = 32;
+ : nformats++;
+ : formats[nformats].format = PICT_x8r8g8b8;
+ : formats[nformats].depth = 32;
+ : nformats++;
+ :
+ : /* now look through the depths and visuals adding other formats */
+ : for (v = 0; v < pScreen->numVisuals; v++)
+ : {
+ : pVisual = &pScreen->visuals[v];
+ : depth = visualDepth (pScreen, pVisual);
+ : if (!depth)
+ : continue;
+ : bpp = BitsPerPixel (depth);
+ : switch (pVisual->class) {
+ : case DirectColor:
+ : case TrueColor:
+ : r = Ones (pVisual->redMask);
+ : g = Ones (pVisual->greenMask);
+ : b = Ones (pVisual->blueMask);
+ : type = PICT_TYPE_OTHER;
+ : /*
+ : * Current rendering code supports only two direct formats,
+ : * fields must be packed together at the bottom of the pixel
+ : * and must be either RGB or BGR
+ : */
+ : if (pVisual->offsetBlue == 0 &&
+ : pVisual->offsetGreen == b &&
+ : pVisual->offsetRed == b + g)
+ : {
+ : type = PICT_TYPE_ARGB;
+ : }
+ : else if (pVisual->offsetRed == 0 &&
+ : pVisual->offsetGreen == r &&
+ : pVisual->offsetBlue == r + g)
+ : {
+ : type = PICT_TYPE_ABGR;
+ : }
+ : if (type != PICT_TYPE_OTHER)
+ : {
+ : format = PICT_FORMAT(bpp, type, 0, r, g, b);
+ : nformats = addFormat (formats, nformats, format, depth);
+ : }
+ : break;
+ : case StaticColor:
+ : case PseudoColor:
+ : format = PICT_VISFORMAT (bpp, PICT_TYPE_COLOR, v);
+ : nformats = addFormat (formats, nformats, format, depth);
+ : break;
+ : case StaticGray:
+ : case GrayScale:
+ : format = PICT_VISFORMAT (bpp, PICT_TYPE_GRAY, v);
+ : nformats = addFormat (formats, nformats, format, depth);
+ : break;
+ : }
+ : }
+ : /*
+ : * Walk supported depths and add useful Direct formats
+ : */
+ : for (d = 0; d < pScreen->numDepths; d++)
+ : {
+ : pDepth = &pScreen->allowedDepths[d];
+ : bpp = BitsPerPixel (pDepth->depth);
+ : format = 0;
+ : switch (bpp) {
+ : case 16:
+ : /* depth 12 formats */
+ : if (pDepth->depth >= 12)
+ : {
+ : nformats = addFormat (formats, nformats,
+ : PICT_x4r4g4b4, pDepth->depth);
+ : nformats = addFormat (formats, nformats,
+ : PICT_x4b4g4r4, pDepth->depth);
+ : }
+ : /* depth 15 formats */
+ : if (pDepth->depth >= 15)
+ : {
+ : nformats = addFormat (formats, nformats,
+ : PICT_x1r5g5b5, pDepth->depth);
+ : nformats = addFormat (formats, nformats,
+ : PICT_x1b5g5r5, pDepth->depth);
+ : }
+ : /* depth 16 formats */
+ : if (pDepth->depth >= 16)
+ : {
+ : nformats = addFormat (formats, nformats,
+ : PICT_a1r5g5b5, pDepth->depth);
+ : nformats = addFormat (formats, nformats,
+ : PICT_a1b5g5r5, pDepth->depth);
+ : nformats = addFormat (formats, nformats,
+ : PICT_r5g6b5, pDepth->depth);
+ : nformats = addFormat (formats, nformats,
+ : PICT_b5g6r5, pDepth->depth);
+ : nformats = addFormat (formats, nformats,
+ : PICT_a4r4g4b4, pDepth->depth);
+ : nformats = addFormat (formats, nformats,
+ : PICT_a4b4g4r4, pDepth->depth);
+ : }
+ : break;
+ : case 24:
+ : if (pDepth->depth >= 24)
+ : {
+ : nformats = addFormat (formats, nformats,
+ : PICT_r8g8b8, pDepth->depth);
+ : nformats = addFormat (formats, nformats,
+ : PICT_b8g8r8, pDepth->depth);
+ : }
+ : break;
+ : case 32:
+ : if (pDepth->depth >= 24)
+ : {
+ : nformats = addFormat (formats, nformats,
+ : PICT_x8r8g8b8, pDepth->depth);
+ : nformats = addFormat (formats, nformats,
+ : PICT_x8b8g8r8, pDepth->depth);
+ : }
+ : break;
+ : }
+ : }
+ :
+ :
+ : pFormats = (PictFormatPtr) xalloc (nformats * sizeof (PictFormatRec));
+ : if (!pFormats)
+ : return 0;
+ : memset (pFormats, '\0', nformats * sizeof (PictFormatRec));
+ : for (f = 0; f < nformats; f++)
+ : {
+ : pFormats[f].id = FakeClientID (0);
+ : pFormats[f].depth = formats[f].depth;
+ : format = formats[f].format;
+ : pFormats[f].format = format;
+ : switch (PICT_FORMAT_TYPE(format)) {
+ : case PICT_TYPE_ARGB:
+ : pFormats[f].type = PictTypeDirect;
+ :
+ : pFormats[f].direct.alphaMask = Mask(PICT_FORMAT_A(format));
+ : if (pFormats[f].direct.alphaMask)
+ : pFormats[f].direct.alpha = (PICT_FORMAT_R(format) +
+ : PICT_FORMAT_G(format) +
+ : PICT_FORMAT_B(format));
+ :
+ : pFormats[f].direct.redMask = Mask(PICT_FORMAT_R(format));
+ : pFormats[f].direct.red = (PICT_FORMAT_G(format) +
+ : PICT_FORMAT_B(format));
+ :
+ : pFormats[f].direct.greenMask = Mask(PICT_FORMAT_G(format));
+ : pFormats[f].direct.green = PICT_FORMAT_B(format);
+ :
+ : pFormats[f].direct.blueMask = Mask(PICT_FORMAT_B(format));
+ : pFormats[f].direct.blue = 0;
+ : break;
+ :
+ : case PICT_TYPE_ABGR:
+ : pFormats[f].type = PictTypeDirect;
+ :
+ : pFormats[f].direct.alphaMask = Mask(PICT_FORMAT_A(format));
+ : if (pFormats[f].direct.alphaMask)
+ : pFormats[f].direct.alpha = (PICT_FORMAT_B(format) +
+ : PICT_FORMAT_G(format) +
+ : PICT_FORMAT_R(format));
+ :
+ : pFormats[f].direct.blueMask = Mask(PICT_FORMAT_B(format));
+ : pFormats[f].direct.blue = (PICT_FORMAT_G(format) +
+ : PICT_FORMAT_R(format));
+ :
+ : pFormats[f].direct.greenMask = Mask(PICT_FORMAT_G(format));
+ : pFormats[f].direct.green = PICT_FORMAT_R(format);
+ :
+ : pFormats[f].direct.redMask = Mask(PICT_FORMAT_R(format));
+ : pFormats[f].direct.red = 0;
+ : break;
+ :
+ : case PICT_TYPE_A:
+ : pFormats[f].type = PictTypeDirect;
+ :
+ : pFormats[f].direct.alpha = 0;
+ : pFormats[f].direct.alphaMask = Mask(PICT_FORMAT_A(format));
+ :
+ : /* remaining fields already set to zero */
+ : break;
+ :
+ : case PICT_TYPE_COLOR:
+ : case PICT_TYPE_GRAY:
+ : pFormats[f].type = PictTypeIndexed;
+ : pFormats[f].index.vid = pScreen->visuals[PICT_FORMAT_VIS(format)].vid;
+ : break;
+ : }
+ : }
+ : *nformatp = nformats;
+ : return pFormats;
+ :}
+ :
+ :static VisualPtr
+ :PictureFindVisual (ScreenPtr pScreen, VisualID visual)
+ :{
+ : int i;
+ : VisualPtr pVisual;
+ : for (i = 0, pVisual = pScreen->visuals;
+ : i < pScreen->numVisuals;
+ : i++, pVisual++)
+ : {
+ : if (pVisual->vid == visual)
+ : return pVisual;
+ : }
+ : return 0;
+ :}
+ :
+ :Bool
+ :PictureInitIndexedFormats (ScreenPtr pScreen)
+ :{
+ : PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
+ : PictFormatPtr format;
+ : int nformat;
+ :
+ : if (!ps)
+ : return FALSE;
+ : format = ps->formats;
+ : nformat = ps->nformats;
+ : while (nformat--)
+ : {
+ : if (format->type == PictTypeIndexed && !format->index.pColormap)
+ : {
+ : if (format->index.vid == pScreen->rootVisual)
+ : format->index.pColormap = (ColormapPtr) LookupIDByType(pScreen->defColormap,
+ : RT_COLORMAP);
+ : else
+ : {
+ : VisualPtr pVisual;
+ :
+ : pVisual = PictureFindVisual (pScreen, format->index.vid);
+ : if (CreateColormap (FakeClientID (0), pScreen,
+ : pVisual,
+ : &format->index.pColormap, AllocNone,
+ : 0) != Success)
+ : {
+ : return FALSE;
+ : }
+ : }
+ : if (!(*ps->InitIndexed) (pScreen, format))
+ : return FALSE;
+ : }
+ : format++;
+ : }
+ : return TRUE;
+ :}
+ :
+ :Bool
+ :PictureFinishInit (void)
+ :{
+ : int s;
+ :
+ : for (s = 0; s < screenInfo.numScreens; s++)
+ : {
+ : if (!GlyphFinishInit (screenInfo.screens[s]))
+ : return FALSE;
+ : if (!PictureInitIndexedFormats (screenInfo.screens[s]))
+ : return FALSE;
+ : (void) AnimCurInit (screenInfo.screens[s]);
+ : }
+ :
+ : return TRUE;
+ :}
+ :
+ :_X_EXPORT Bool
+ :PictureSetSubpixelOrder (ScreenPtr pScreen, int subpixel)
+ :{
+ : PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
+ :
+ : if (!ps)
+ : return FALSE;
+ : ps->subpixel = subpixel;
+ : return TRUE;
+ :
+ :}
+ :
+ :_X_EXPORT int
+ :PictureGetSubpixelOrder (ScreenPtr pScreen)
+ :{
+ : PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
+ :
+ : if (!ps)
+ : return SubPixelUnknown;
+ : return ps->subpixel;
+ :}
+ :
+ :PictFormatPtr
+ :PictureMatchVisual (ScreenPtr pScreen, int depth, VisualPtr pVisual)
+ :{
+ : PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
+ : PictFormatPtr format;
+ : int nformat;
+ : int type;
+ :
+ : if (!ps)
+ : return 0;
+ : format = ps->formats;
+ : nformat = ps->nformats;
+ : switch (pVisual->class) {
+ : case StaticGray:
+ : case GrayScale:
+ : case StaticColor:
+ : case PseudoColor:
+ : type = PictTypeIndexed;
+ : break;
+ : case TrueColor:
+ : case DirectColor:
+ : type = PictTypeDirect;
+ : break;
+ : default:
+ : return 0;
+ : }
+ : while (nformat--)
+ : {
+ : if (format->depth == depth && format->type == type)
+ : {
+ : if (type == PictTypeIndexed)
+ : {
+ : if (format->index.vid == pVisual->vid)
+ : return format;
+ : }
+ : else
+ : {
+ : if (format->direct.redMask << format->direct.red ==
+ : pVisual->redMask &&
+ : format->direct.greenMask << format->direct.green ==
+ : pVisual->greenMask &&
+ : format->direct.blueMask << format->direct.blue ==
+ : pVisual->blueMask)
+ : {
+ : return format;
+ : }
+ : }
+ : }
+ : format++;
+ : }
+ : return 0;
+ :}
+ :
+ :PictFormatPtr
+ :PictureMatchFormat (ScreenPtr pScreen, int depth, CARD32 f)
+ :{
+ : PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
+ : PictFormatPtr format;
+ : int nformat;
+ :
+ : if (!ps)
+ : return 0;
+ : format = ps->formats;
+ : nformat = ps->nformats;
+ : while (nformat--)
+ : {
+ : if (format->depth == depth && format->format == (f & 0xffffff))
+ : return format;
+ : format++;
+ : }
+ : return 0;
+ :}
+ :
+ :int
+ :PictureParseCmapPolicy (const char *name)
+ :{
+ : if ( strcmp (name, "default" ) == 0)
+ : return PictureCmapPolicyDefault;
+ : else if ( strcmp (name, "mono" ) == 0)
+ : return PictureCmapPolicyMono;
+ : else if ( strcmp (name, "gray" ) == 0)
+ : return PictureCmapPolicyGray;
+ : else if ( strcmp (name, "color" ) == 0)
+ : return PictureCmapPolicyColor;
+ : else if ( strcmp (name, "all" ) == 0)
+ : return PictureCmapPolicyAll;
+ : else
+ : return PictureCmapPolicyInvalid;
+ :}
+ :
+ :_X_EXPORT Bool
+ :PictureInit (ScreenPtr pScreen, PictFormatPtr formats, int nformats)
+ :{
+ : PictureScreenPtr ps;
+ : int n;
+ : CARD32 type, a, r, g, b;
+ :
+ : if (PictureGeneration != serverGeneration)
+ : {
+ : PictureType = CreateNewResourceType (FreePicture);
+ : if (!PictureType)
+ : return FALSE;
+ : PictFormatType = CreateNewResourceType (FreePictFormat);
+ : if (!PictFormatType)
+ : return FALSE;
+ : GlyphSetType = CreateNewResourceType (FreeGlyphSet);
+ : if (!GlyphSetType)
+ : return FALSE;
+ : PictureScreenPrivateIndex = AllocateScreenPrivateIndex();
+ : if (PictureScreenPrivateIndex < 0)
+ : return FALSE;
+ : PictureWindowPrivateIndex = AllocateWindowPrivateIndex();
+ : PictureGeneration = serverGeneration;
+ :#ifdef XResExtension
+ : RegisterResourceName (PictureType, "PICTURE");
+ : RegisterResourceName (PictFormatType, "PICTFORMAT");
+ : RegisterResourceName (GlyphSetType, "GLYPHSET");
+ :#endif
+ : }
+ : if (!AllocateWindowPrivate (pScreen, PictureWindowPrivateIndex, 0))
+ : return FALSE;
+ :
+ : if (!formats)
+ : {
+ : formats = PictureCreateDefaultFormats (pScreen, &nformats);
+ : if (!formats)
+ : return FALSE;
+ : }
+ : for (n = 0; n < nformats; n++)
+ : {
+ : if (!AddResource (formats[n].id, PictFormatType, (pointer) (formats+n)))
+ : {
+ : xfree (formats);
+ : return FALSE;
+ : }
+ : if (formats[n].type == PictTypeIndexed)
+ : {
+ : VisualPtr pVisual = PictureFindVisual (pScreen, formats[n].index.vid);
+ : if ((pVisual->class | DynamicClass) == PseudoColor)
+ : type = PICT_TYPE_COLOR;
+ : else
+ : type = PICT_TYPE_GRAY;
+ : a = r = g = b = 0;
+ : }
+ : else
+ : {
+ : if ((formats[n].direct.redMask|
+ : formats[n].direct.blueMask|
+ : formats[n].direct.greenMask) == 0)
+ : type = PICT_TYPE_A;
+ : else if (formats[n].direct.red > formats[n].direct.blue)
+ : type = PICT_TYPE_ARGB;
+ : else
+ : type = PICT_TYPE_ABGR;
+ : a = Ones (formats[n].direct.alphaMask);
+ : r = Ones (formats[n].direct.redMask);
+ : g = Ones (formats[n].direct.greenMask);
+ : b = Ones (formats[n].direct.blueMask);
+ : }
+ : formats[n].format = PICT_FORMAT(0,type,a,r,g,b);
+ : }
+ : ps = (PictureScreenPtr) xalloc (sizeof (PictureScreenRec));
+ : if (!ps)
+ : {
+ : xfree (formats);
+ : return FALSE;
+ : }
+ : SetPictureScreen(pScreen, ps);
+ : if (!GlyphInit (pScreen))
+ : {
+ : SetPictureScreen(pScreen, 0);
+ : xfree (formats);
+ : xfree (ps);
+ : return FALSE;
+ : }
+ :
+ : ps->totalPictureSize = sizeof (PictureRec);
+ : ps->PicturePrivateSizes = 0;
+ : ps->PicturePrivateLen = 0;
+ :
+ : ps->formats = formats;
+ : ps->fallback = formats;
+ : ps->nformats = nformats;
+ :
+ : ps->filters = 0;
+ : ps->nfilters = 0;
+ : ps->filterAliases = 0;
+ : ps->nfilterAliases = 0;
+ :
+ : ps->subpixel = SubPixelUnknown;
+ :
+ : ps->CloseScreen = pScreen->CloseScreen;
+ : ps->DestroyWindow = pScreen->DestroyWindow;
+ : ps->StoreColors = pScreen->StoreColors;
+ : pScreen->DestroyWindow = PictureDestroyWindow;
+ : pScreen->CloseScreen = PictureCloseScreen;
+ : pScreen->StoreColors = PictureStoreColors;
+ :
+ : if (!PictureSetDefaultFilters (pScreen))
+ : {
+ : PictureResetFilters (pScreen);
+ : SetPictureScreen(pScreen, 0);
+ : xfree (formats);
+ : xfree (ps);
+ : return FALSE;
+ : }
+ :
+ : return TRUE;
+ :}
+ :
+ :void
+ :SetPictureToDefaults (PicturePtr pPicture)
+ :{ /* SetPictureToDefaults total: 8 0.0087 */
+ : pPicture->refcnt = 1;
+ : pPicture->repeat = 0;
+ : pPicture->graphicsExposures = FALSE;
+ : pPicture->subWindowMode = ClipByChildren;
+ : pPicture->polyEdge = PolyEdgeSharp;
+ : pPicture->polyMode = PolyModePrecise;
+ : pPicture->freeCompClip = FALSE;
+ : pPicture->clientClipType = CT_NONE;
+ : pPicture->componentAlpha = FALSE;
+ : pPicture->repeatType = RepeatNone;
+ :
+ : pPicture->alphaMap = 0;
+ : pPicture->alphaOrigin.x = 0;
+ : pPicture->alphaOrigin.y = 0;
+ :
+ : pPicture->clipOrigin.x = 0;
+ 1 0.0011 : pPicture->clipOrigin.y = 0;
+ : pPicture->clientClip = 0;
+ :
+ : pPicture->transform = 0;
+ :
+ : pPicture->dither = None;
+ 4 0.0044 : pPicture->filter = PictureGetFilterId (FilterNearest, -1, TRUE);
+ : pPicture->filter_params = 0;
+ : pPicture->filter_nparams = 0;
+ :
+ : pPicture->serialNumber = GC_CHANGE_SERIAL_BIT;
+ 1 0.0011 : pPicture->stateChanges = (1 << (CPLastBit+1)) - 1;
+ 1 0.0011 : pPicture->pSourcePict = 0;
+ 1 0.0011 :}
+ :
+ :PicturePtr
+ :AllocatePicture (ScreenPtr pScreen)
+ :{ /* AllocatePicture total: 4 0.0044 */
+ : PictureScreenPtr ps = GetPictureScreen(pScreen);
+ : PicturePtr pPicture;
+ : char *ptr;
+ : DevUnion *ppriv;
+ : unsigned int *sizes;
+ : unsigned int size;
+ : int i;
+ :
+ 3 0.0033 : pPicture = (PicturePtr) xalloc (ps->totalPictureSize);
+ : if (!pPicture)
+ : return 0;
+ : ppriv = (DevUnion *)(pPicture + 1);
+ : pPicture->devPrivates = ppriv;
+ : sizes = ps->PicturePrivateSizes;
+ : ptr = (char *)(ppriv + ps->PicturePrivateLen);
+ : for (i = ps->PicturePrivateLen; --i >= 0; ppriv++, sizes++)
+ : {
+ : if ( (size = *sizes) )
+ : {
+ : ppriv->ptr = (pointer)ptr;
+ : ptr += size;
+ : }
+ : else
+ : ppriv->ptr = (pointer)NULL;
+ : }
+ : return pPicture;
+ 1 0.0011 :}
+ :
+ :PicturePtr
+ :CreatePicture (Picture pid,
+ : DrawablePtr pDrawable,
+ : PictFormatPtr pFormat,
+ : Mask vmask,
+ : XID *vlist,
+ : ClientPtr client,
+ : int *error)
+ 2 0.0022 :{ /* CreatePicture total: 12 0.0131 */
+ : PicturePtr pPicture;
+ 2 0.0022 : PictureScreenPtr ps = GetPictureScreen(pDrawable->pScreen);
+ :
+ : pPicture = AllocatePicture (pDrawable->pScreen);
+ : if (!pPicture)
+ : {
+ : *error = BadAlloc;
+ : return 0;
+ : }
+ :
+ : pPicture->id = pid;
+ : pPicture->pDrawable = pDrawable;
+ : pPicture->pFormat = pFormat;
+ 1 0.0011 : pPicture->format = pFormat->format | (pDrawable->bitsPerPixel << 24);
+ 1 0.0011 : if (pDrawable->type == DRAWABLE_PIXMAP)
+ : {
+ : ++((PixmapPtr)pDrawable)->refcnt;
+ : pPicture->pNext = 0;
+ : }
+ : else
+ : {
+ : pPicture->pNext = GetPictureWindow(((WindowPtr) pDrawable));
+ : SetPictureWindow(((WindowPtr) pDrawable), pPicture);
+ : }
+ :
+ : SetPictureToDefaults (pPicture);
+ :
+ : if (vmask)
+ : *error = ChangePicture (pPicture, vmask, vlist, 0, client);
+ : else
+ : *error = Success;
+ : if (*error == Success)
+ 4 0.0044 : *error = (*ps->CreatePicture) (pPicture);
+ 1 0.0011 : if (*error != Success)
+ : {
+ : FreePicture (pPicture, (XID) 0);
+ : pPicture = 0;
+ : }
+ : return pPicture;
+ 1 0.0011 :}
+ :
+ :static CARD32 xRenderColorToCard32(xRenderColor c)
+ :{
+ : return
+ : (c.alpha >> 8 << 24) |
+ : (c.red >> 8 << 16) |
+ : (c.green & 0xff00) |
+ : (c.blue >> 8);
+ :}
+ :
+ :static unsigned int premultiply(unsigned int x)
+ :{
+ : unsigned int a = x >> 24;
+ : unsigned int t = (x & 0xff00ff) * a + 0x800080;
+ : t = (t + ((t >> 8) & 0xff00ff)) >> 8;
+ : t &= 0xff00ff;
+ :
+ : x = ((x >> 8) & 0xff) * a + 0x80;
+ : x = (x + ((x >> 8) & 0xff));
+ : x &= 0xff00;
+ : x |= t | (a << 24);
+ : return x;
+ :}
+ :
+ :static unsigned int INTERPOLATE_PIXEL_256(unsigned int x, unsigned int a,
+ : unsigned int y, unsigned int b)
+ :{
+ : CARD32 t = (x & 0xff00ff) * a + (y & 0xff00ff) * b;
+ : t >>= 8;
+ : t &= 0xff00ff;
+ :
+ : x = ((x >> 8) & 0xff00ff) * a + ((y >> 8) & 0xff00ff) * b;
+ : x &= 0xff00ff00;
+ : x |= t;
+ : return x;
+ :}
+ :
+ :CARD32
+ :PictureGradientColor (PictGradientStopPtr stop1,
+ : PictGradientStopPtr stop2,
+ : CARD32 x)
+ :{
+ : CARD32 current_color, next_color;
+ : int dist, idist;
+ :
+ : current_color = xRenderColorToCard32 (stop1->color);
+ : next_color = xRenderColorToCard32 (stop2->color);
+ :
+ : dist = (int) (256 * (x - stop1->x) / (stop2->x - stop1->x));
+ : idist = 256 - dist;
+ :
+ : return premultiply (INTERPOLATE_PIXEL_256 (current_color, idist,
+ : next_color, dist));
+ :}
+ :
+ :static void initGradient(SourcePictPtr pGradient, int stopCount,
+ : xFixed *stopPoints, xRenderColor *stopColors, int *error)
+ :{
+ : int i;
+ : xFixed dpos;
+ :
+ : if (stopCount <= 0) {
+ : *error = BadValue;
+ : return;
+ : }
+ :
+ : dpos = -1;
+ : for (i = 0; i < stopCount; ++i) {
+ : if (stopPoints[i] < dpos || stopPoints[i] > (1<<16)) {
+ : *error = BadValue;
+ : return;
+ : }
+ : dpos = stopPoints[i];
+ : }
+ :
+ : pGradient->gradient.stops = xalloc(stopCount*sizeof(PictGradientStop));
+ : if (!pGradient->gradient.stops) {
+ : *error = BadAlloc;
+ : return;
+ : }
+ :
+ : pGradient->gradient.nstops = stopCount;
+ :
+ : for (i = 0; i < stopCount; ++i) {
+ : pGradient->gradient.stops[i].x = stopPoints[i];
+ : pGradient->gradient.stops[i].color = stopColors[i];
+ : }
+ :
+ : pGradient->gradient.class = SourcePictClassUnknown;
+ : pGradient->gradient.stopRange = 0xffff;
+ : pGradient->gradient.colorTable = NULL;
+ : pGradient->gradient.colorTableSize = 0;
+ :}
+ :
+ :static PicturePtr createSourcePicture(void)
+ :{
+ : PicturePtr pPicture;
+ : pPicture = (PicturePtr) xalloc(sizeof(PictureRec));
+ : pPicture->pDrawable = 0;
+ : pPicture->pFormat = 0;
+ : pPicture->pNext = 0;
+ : pPicture->format = PICT_a8r8g8b8;
+ : pPicture->devPrivates = 0;
+ :
+ : SetPictureToDefaults(pPicture);
+ : return pPicture;
+ :}
+ :
+ :PicturePtr
+ :CreateSolidPicture (Picture pid, xRenderColor *color, int *error)
+ :{
+ : PicturePtr pPicture;
+ : pPicture = createSourcePicture();
+ : if (!pPicture) {
+ : *error = BadAlloc;
+ : return 0;
+ : }
+ :
+ : pPicture->id = pid;
+ : pPicture->pSourcePict = (SourcePictPtr) xalloc(sizeof(PictSolidFill));
+ : if (!pPicture->pSourcePict) {
+ : *error = BadAlloc;
+ : xfree(pPicture);
+ : return 0;
+ : }
+ : pPicture->pSourcePict->type = SourcePictTypeSolidFill;
+ : pPicture->pSourcePict->solidFill.color = xRenderColorToCard32(*color);
+ : return pPicture;
+ :}
+ :
+ :PicturePtr
+ :CreateLinearGradientPicture (Picture pid, xPointFixed *p1, xPointFixed *p2,
+ : int nStops, xFixed *stops, xRenderColor *colors, int *error)
+ :{
+ : PicturePtr pPicture;
+ :
+ : if (nStops < 2) {
+ : *error = BadValue;
+ : return 0;
+ : }
+ :
+ : pPicture = createSourcePicture();
+ : if (!pPicture) {
+ : *error = BadAlloc;
+ : return 0;
+ : }
+ :
+ : pPicture->id = pid;
+ : pPicture->pSourcePict = (SourcePictPtr) xalloc(sizeof(PictLinearGradient));
+ : if (!pPicture->pSourcePict) {
+ : *error = BadAlloc;
+ : xfree(pPicture);
+ : return 0;
+ : }
+ :
+ : pPicture->pSourcePict->linear.type = SourcePictTypeLinear;
+ : pPicture->pSourcePict->linear.p1 = *p1;
+ : pPicture->pSourcePict->linear.p2 = *p2;
+ :
+ : initGradient(pPicture->pSourcePict, nStops, stops, colors, error);
+ : if (*error) {
+ : xfree(pPicture);
+ : return 0;
+ : }
+ : return pPicture;
+ :}
+ :
+ :#define FixedToDouble(x) ((x)/65536.)
+ :
+ :PicturePtr
+ :CreateRadialGradientPicture (Picture pid, xPointFixed *inner, xPointFixed *outer,
+ : xFixed innerRadius, xFixed outerRadius,
+ : int nStops, xFixed *stops, xRenderColor *colors, int *error)
+ :{
+ : PicturePtr pPicture;
+ : PictRadialGradient *radial;
+ :
+ : if (nStops < 2) {
+ : *error = BadValue;
+ : return 0;
+ : }
+ :
+ : pPicture = createSourcePicture();
+ : if (!pPicture) {
+ : *error = BadAlloc;
+ : return 0;
+ : }
+ :
+ : pPicture->id = pid;
+ : pPicture->pSourcePict = (SourcePictPtr) xalloc(sizeof(PictRadialGradient));
+ : if (!pPicture->pSourcePict) {
+ : *error = BadAlloc;
+ : xfree(pPicture);
+ : return 0;
+ : }
+ : radial = &pPicture->pSourcePict->radial;
+ :
+ : radial->type = SourcePictTypeRadial;
+ : radial->c1.x = inner->x;
+ : radial->c1.y = inner->y;
+ : radial->c1.radius = innerRadius;
+ : radial->c2.x = outer->x;
+ : radial->c2.y = outer->y;
+ : radial->c2.radius = outerRadius;
+ : radial->cdx = (radial->c2.x - radial->c1.x) / 65536.;
+ : radial->cdy = (radial->c2.y - radial->c1.y) / 65536.;
+ : radial->dr = (radial->c2.radius - radial->c1.radius) / 65536.;
+ : radial->A = ( radial->cdx * radial->cdx
+ : + radial->cdy * radial->cdy
+ : - radial->dr * radial->dr);
+ :
+ : initGradient(pPicture->pSourcePict, nStops, stops, colors, error);
+ : if (*error) {
+ : xfree(pPicture);
+ : return 0;
+ : }
+ : return pPicture;
+ :}
+ :
+ :PicturePtr
+ :CreateConicalGradientPicture (Picture pid, xPointFixed *center, xFixed angle,
+ : int nStops, xFixed *stops, xRenderColor *colors, int *error)
+ :{
+ : PicturePtr pPicture;
+ :
+ : if (nStops < 2) {
+ : *error = BadValue;
+ : return 0;
+ : }
+ :
+ : pPicture = createSourcePicture();
+ : if (!pPicture) {
+ : *error = BadAlloc;
+ : return 0;
+ : }
+ :
+ : pPicture->id = pid;
+ : pPicture->pSourcePict = (SourcePictPtr) xalloc(sizeof(PictConicalGradient));
+ : if (!pPicture->pSourcePict) {
+ : *error = BadAlloc;
+ : xfree(pPicture);
+ : return 0;
+ : }
+ :
+ : pPicture->pSourcePict->conical.type = SourcePictTypeConical;
+ : pPicture->pSourcePict->conical.center = *center;
+ : pPicture->pSourcePict->conical.angle = angle;
+ :
+ : initGradient(pPicture->pSourcePict, nStops, stops, colors, error);
+ : if (*error) {
+ : xfree(pPicture);
+ : return 0;
+ : }
+ : return pPicture;
+ :}
+ :
+ :#define NEXT_VAL(_type) (vlist ? (_type) *vlist++ : (_type) ulist++->val)
+ :
+ :#define NEXT_PTR(_type) ((_type) ulist++->ptr)
+ :
+ :int
+ :ChangePicture (PicturePtr pPicture,
+ : Mask vmask,
+ : XID *vlist,
+ : DevUnion *ulist,
+ : ClientPtr client)
+ 4 0.0044 :{ /* ChangePicture total: 16 0.0174 */
+ : ScreenPtr pScreen = pPicture->pDrawable ? pPicture->pDrawable->pScreen : 0;
+ 4 0.0044 : PictureScreenPtr ps = pScreen ? GetPictureScreen(pScreen) : 0;
+ : BITS32 index2;
+ : int error = 0;
+ : BITS32 maskQ;
+ :
+ : pPicture->serialNumber |= GC_CHANGE_SERIAL_BIT;
+ : maskQ = vmask;
+ 1 0.0011 : while (vmask && !error)
+ : {
+ : index2 = (BITS32) lowbit (vmask);
+ 1 0.0011 : vmask &= ~index2;
+ : pPicture->stateChanges |= index2;
+ 1 0.0011 : switch (index2)
+ : {
+ : case CPRepeat:
+ : {
+ : unsigned int newr;
+ 1 0.0011 : newr = NEXT_VAL(unsigned int);
+ : if (newr <= RepeatReflect)
+ : {
+ 1 0.0011 : pPicture->repeat = (newr != RepeatNone);
+ 1 0.0011 : pPicture->repeatType = newr;
+ : }
+ : else
+ : {
+ : client->errorValue = newr;
+ : error = BadValue;
+ : }
+ : }
+ : break;
+ : case CPAlphaMap:
+ : {
+ : PicturePtr pAlpha;
+ :
+ : if (vlist)
+ : {
+ : Picture pid = NEXT_VAL(Picture);
+ :
+ : if (pid == None)
+ : pAlpha = 0;
+ : else
+ : {
+ : pAlpha = (PicturePtr) SecurityLookupIDByType(client,
+ : pid,
+ : PictureType,
+ : DixWriteAccess|DixReadAccess);
+ : if (!pAlpha)
+ : {
+ : client->errorValue = pid;
+ : error = BadPixmap;
+ : break;
+ : }
+ : if (pAlpha->pDrawable == NULL ||
+ : pAlpha->pDrawable->type != DRAWABLE_PIXMAP)
+ : {
+ : client->errorValue = pid;
+ : error = BadMatch;
+ : break;
+ : }
+ : }
+ : }
+ : else
+ : pAlpha = NEXT_PTR(PicturePtr);
+ : if (!error)
+ : {
+ : if (pAlpha && pAlpha->pDrawable->type == DRAWABLE_PIXMAP)
+ : pAlpha->refcnt++;
+ : if (pPicture->alphaMap)
+ : FreePicture ((pointer) pPicture->alphaMap, (XID) 0);
+ : pPicture->alphaMap = pAlpha;
+ : }
+ : }
+ : break;
+ : case CPAlphaXOrigin:
+ : pPicture->alphaOrigin.x = NEXT_VAL(INT16);
+ : break;
+ : case CPAlphaYOrigin:
+ : pPicture->alphaOrigin.y = NEXT_VAL(INT16);
+ : break;
+ : case CPClipXOrigin:
+ : pPicture->clipOrigin.x = NEXT_VAL(INT16);
+ : break;
+ : case CPClipYOrigin:
+ : pPicture->clipOrigin.y = NEXT_VAL(INT16);
+ : break;
+ : case CPClipMask:
+ : {
+ : Pixmap pid;
+ : PixmapPtr pPixmap;
+ : int clipType;
+ : if (!pScreen)
+ : return BadDrawable;
+ :
+ : if (vlist)
+ : {
+ : pid = NEXT_VAL(Pixmap);
+ : if (pid == None)
+ : {
+ : clipType = CT_NONE;
+ : pPixmap = NullPixmap;
+ : }
+ : else
+ : {
+ : clipType = CT_PIXMAP;
+ : pPixmap = (PixmapPtr)SecurityLookupIDByType(client,
+ : pid,
+ : RT_PIXMAP,
+ : DixReadAccess);
+ : if (!pPixmap)
+ : {
+ : client->errorValue = pid;
+ : error = BadPixmap;
+ : break;
+ : }
+ : }
+ : }
+ : else
+ : {
+ : pPixmap = NEXT_PTR(PixmapPtr);
+ : if (pPixmap)
+ : clipType = CT_PIXMAP;
+ : else
+ : clipType = CT_NONE;
+ : }
+ :
+ : if (pPixmap)
+ : {
+ : if ((pPixmap->drawable.depth != 1) ||
+ : (pPixmap->drawable.pScreen != pScreen))
+ : {
+ : error = BadMatch;
+ : break;
+ : }
+ : else
+ : {
+ : clipType = CT_PIXMAP;
+ : pPixmap->refcnt++;
+ : }
+ : }
+ : error = (*ps->ChangePictureClip)(pPicture, clipType,
+ : (pointer)pPixmap, 0);
+ : break;
+ : }
+ : case CPGraphicsExposure:
+ : {
+ : unsigned int newe;
+ : newe = NEXT_VAL(unsigned int);
+ : if (newe <= xTrue)
+ : pPicture->graphicsExposures = newe;
+ : else
+ : {
+ : client->errorValue = newe;
+ : error = BadValue;
+ : }
+ : }
+ : break;
+ : case CPSubwindowMode:
+ : {
+ : unsigned int news;
+ : news = NEXT_VAL(unsigned int);
+ : if (news == ClipByChildren || news == IncludeInferiors)
+ : pPicture->subWindowMode = news;
+ : else
+ : {
+ : client->errorValue = news;
+ : error = BadValue;
+ : }
+ : }
+ : break;
+ : case CPPolyEdge:
+ : {
+ : unsigned int newe;
+ : newe = NEXT_VAL(unsigned int);
+ : if (newe == PolyEdgeSharp || newe == PolyEdgeSmooth)
+ : pPicture->polyEdge = newe;
+ : else
+ : {
+ : client->errorValue = newe;
+ : error = BadValue;
+ : }
+ : }
+ : break;
+ : case CPPolyMode:
+ : {
+ : unsigned int newm;
+ : newm = NEXT_VAL(unsigned int);
+ : if (newm == PolyModePrecise || newm == PolyModeImprecise)
+ : pPicture->polyMode = newm;
+ : else
+ : {
+ : client->errorValue = newm;
+ : error = BadValue;
+ : }
+ : }
+ : break;
+ : case CPDither:
+ : pPicture->dither = NEXT_VAL(Atom);
+ : break;
+ : case CPComponentAlpha:
+ : {
+ : unsigned int newca;
+ :
+ 1 0.0011 : newca = NEXT_VAL (unsigned int);
+ : if (newca <= xTrue)
+ : pPicture->componentAlpha = newca;
+ : else
+ : {
+ : client->errorValue = newca;
+ : error = BadValue;
+ : }
+ : }
+ : break;
+ : default:
+ : client->errorValue = maskQ;
+ : error = BadValue;
+ : break;
+ : }
+ : }
+ : if (ps)
+ : (*ps->ChangePicture) (pPicture, maskQ);
+ : return error;
+ 1 0.0011 :}
+ :
+ :int
+ :SetPictureClipRects (PicturePtr pPicture,
+ : int xOrigin,
+ : int yOrigin,
+ : int nRect,
+ : xRectangle *rects)
+ :{
+ : ScreenPtr pScreen = pPicture->pDrawable->pScreen;
+ : PictureScreenPtr ps = GetPictureScreen(pScreen);
+ : RegionPtr clientClip;
+ : int result;
+ :
+ : clientClip = RECTS_TO_REGION(pScreen,
+ : nRect, rects, CT_UNSORTED);
+ : if (!clientClip)
+ : return BadAlloc;
+ : result =(*ps->ChangePictureClip) (pPicture, CT_REGION,
+ : (pointer) clientClip, 0);
+ : if (result == Success)
+ : {
+ : pPicture->clipOrigin.x = xOrigin;
+ : pPicture->clipOrigin.y = yOrigin;
+ : pPicture->stateChanges |= CPClipXOrigin|CPClipYOrigin|CPClipMask;
+ : pPicture->serialNumber |= GC_CHANGE_SERIAL_BIT;
+ : }
+ : return result;
+ :}
+ :
+ :int
+ :SetPictureClipRegion (PicturePtr pPicture,
+ : int xOrigin,
+ : int yOrigin,
+ : RegionPtr pRegion)
+ :{
+ : ScreenPtr pScreen = pPicture->pDrawable->pScreen;
+ : PictureScreenPtr ps = GetPictureScreen(pScreen);
+ : RegionPtr clientClip;
+ : int result;
+ : int type;
+ :
+ : if (pRegion)
+ : {
+ : type = CT_REGION;
+ : clientClip = REGION_CREATE (pScreen,
+ : REGION_EXTENTS(pScreen, pRegion),
+ : REGION_NUM_RECTS(pRegion));
+ : if (!clientClip)
+ : return BadAlloc;
+ : if (!REGION_COPY (pSCreen, clientClip, pRegion))
+ : {
+ : REGION_DESTROY (pScreen, clientClip);
+ : return BadAlloc;
+ : }
+ : }
+ : else
+ : {
+ : type = CT_NONE;
+ : clientClip = 0;
+ : }
+ :
+ : result =(*ps->ChangePictureClip) (pPicture, type,
+ : (pointer) clientClip, 0);
+ : if (result == Success)
+ : {
+ : pPicture->clipOrigin.x = xOrigin;
+ : pPicture->clipOrigin.y = yOrigin;
+ : pPicture->stateChanges |= CPClipXOrigin|CPClipYOrigin|CPClipMask;
+ : pPicture->serialNumber |= GC_CHANGE_SERIAL_BIT;
+ : }
+ : return result;
+ :}
+ :
+ :static Bool
+ :transformIsIdentity(PictTransform *t)
+ :{
+ : return ((t->matrix[0][0] == t->matrix[1][1]) &&
+ : (t->matrix[0][0] == t->matrix[2][2]) &&
+ : (t->matrix[0][0] != 0) &&
+ : (t->matrix[0][1] == 0) &&
+ : (t->matrix[0][2] == 0) &&
+ : (t->matrix[1][0] == 0) &&
+ : (t->matrix[1][2] == 0) &&
+ : (t->matrix[2][0] == 0) &&
+ : (t->matrix[2][1] == 0));
+ :}
+ :
+ :int
+ :SetPictureTransform (PicturePtr pPicture,
+ : PictTransform *transform)
+ 2 0.0022 :{ /* SetPictureTransform total: 10 0.0109 */
+ : if (transform && transformIsIdentity (transform))
+ : transform = 0;
+ :
+ : if (transform)
+ : {
+ : if (!pPicture->transform)
+ : {
+ : pPicture->transform = (PictTransform *) xalloc (sizeof (PictTransform));
+ : if (!pPicture->transform)
+ : return BadAlloc;
+ : }
+ : *pPicture->transform = *transform;
+ : }
+ : else
+ : {
+ : if (pPicture->transform)
+ : {
+ : xfree (pPicture->transform);
+ : pPicture->transform = 0;
+ : }
+ : }
+ : pPicture->serialNumber |= GC_CHANGE_SERIAL_BIT;
+ :
+ 5 0.0054 : if (pPicture->pDrawable != NULL) {
+ : int result;
+ : PictureScreenPtr ps = GetPictureScreen(pPicture->pDrawable->pScreen);
+ :
+ 1 0.0011 : result = (*ps->ChangePictureTransform) (pPicture, transform);
+ :
+ : return result;
+ : }
+ :
+ : return Success;
+ :}
+ :
+ :void
+ :CopyPicture (PicturePtr pSrc,
+ : Mask mask,
+ : PicturePtr pDst)
+ :{
+ : PictureScreenPtr ps = GetPictureScreen(pSrc->pDrawable->pScreen);
+ : Mask origMask = mask;
+ :
+ : pDst->serialNumber |= GC_CHANGE_SERIAL_BIT;
+ : pDst->stateChanges |= mask;
+ :
+ : while (mask) {
+ : Mask bit = lowbit(mask);
+ :
+ : switch (bit)
+ : {
+ : case CPRepeat:
+ : pDst->repeat = pSrc->repeat;
+ : pDst->repeatType = pSrc->repeatType;
+ : break;
+ : case CPAlphaMap:
+ : if (pSrc->alphaMap && pSrc->alphaMap->pDrawable->type == DRAWABLE_PIXMAP)
+ : pSrc->alphaMap->refcnt++;
+ : if (pDst->alphaMap)
+ : FreePicture ((pointer) pDst->alphaMap, (XID) 0);
+ : pDst->alphaMap = pSrc->alphaMap;
+ : break;
+ : case CPAlphaXOrigin:
+ : pDst->alphaOrigin.x = pSrc->alphaOrigin.x;
+ : break;
+ : case CPAlphaYOrigin:
+ : pDst->alphaOrigin.y = pSrc->alphaOrigin.y;
+ : break;
+ : case CPClipXOrigin:
+ : pDst->clipOrigin.x = pSrc->clipOrigin.x;
+ : break;
+ : case CPClipYOrigin:
+ : pDst->clipOrigin.y = pSrc->clipOrigin.y;
+ : break;
+ : case CPClipMask:
+ : switch (pSrc->clientClipType) {
+ : case CT_NONE:
+ : (*ps->ChangePictureClip)(pDst, CT_NONE, NULL, 0);
+ : break;
+ : case CT_REGION:
+ : if (!pSrc->clientClip) {
+ : (*ps->ChangePictureClip)(pDst, CT_NONE, NULL, 0);
+ : } else {
+ : RegionPtr clientClip;
+ : RegionPtr srcClientClip = (RegionPtr)pSrc->clientClip;
+ :
+ : clientClip = REGION_CREATE(pSrc->pDrawable->pScreen,
+ : REGION_EXTENTS(pSrc->pDrawable->pScreen, srcClientClip),
+ : REGION_NUM_RECTS(srcClientClip));
+ : (*ps->ChangePictureClip)(pDst, CT_REGION, clientClip, 0);
+ : }
+ : break;
+ : default:
+ : /* XXX: CT_PIXMAP unimplemented */
+ : break;
+ : }
+ : break;
+ : case CPGraphicsExposure:
+ : pDst->graphicsExposures = pSrc->graphicsExposures;
+ : break;
+ : case CPPolyEdge:
+ : pDst->polyEdge = pSrc->polyEdge;
+ : break;
+ : case CPPolyMode:
+ : pDst->polyMode = pSrc->polyMode;
+ : break;
+ : case CPDither:
+ : pDst->dither = pSrc->dither;
+ : break;
+ : case CPComponentAlpha:
+ : pDst->componentAlpha = pSrc->componentAlpha;
+ : break;
+ : }
+ : mask &= ~bit;
+ : }
+ :
+ : (*ps->ChangePicture)(pDst, origMask);
+ :}
+ :
+ :static void
+ :ValidateOnePicture (PicturePtr pPicture)
+ 5 0.0054 :{ /* ValidateOnePicture total: 10 0.0109 */
+ 1 0.0011 : if (pPicture->pDrawable && pPicture->serialNumber != pPicture->pDrawable->serialNumber)
+ : {
+ : PictureScreenPtr ps = GetPictureScreen(pPicture->pDrawable->pScreen);
+ :
+ 4 0.0044 : (*ps->ValidatePicture) (pPicture, pPicture->stateChanges);
+ : pPicture->stateChanges = 0;
+ : pPicture->serialNumber = pPicture->pDrawable->serialNumber;
+ : }
+ :}
+ :
+ :void
+ :ValidatePicture(PicturePtr pPicture)
+ 1 0.0011 :{ /* ValidatePicture total: 3 0.0033 */
+ : ValidateOnePicture (pPicture);
+ 1 0.0011 : if (pPicture->alphaMap)
+ : ValidateOnePicture (pPicture->alphaMap);
+ 1 0.0011 :}
+ :
+ :int
+ :FreePicture (pointer value,
+ : XID pid)
+ 3 0.0033 :{ /* FreePicture total: 8 0.0087 */
+ : PicturePtr pPicture = (PicturePtr) value;
+ :
+ 2 0.0022 : if (--pPicture->refcnt == 0)
+ : {
+ : if (pPicture->transform)
+ : xfree (pPicture->transform);
+ :
+ : if (pPicture->pSourcePict)
+ : {
+ : if (pPicture->pSourcePict->type != SourcePictTypeSolidFill)
+ : xfree(pPicture->pSourcePict->linear.stops);
+ :
+ : xfree(pPicture->pSourcePict);
+ : }
+ :
+ : if (pPicture->pDrawable)
+ : {
+ : ScreenPtr pScreen = pPicture->pDrawable->pScreen;
+ 2 0.0022 : PictureScreenPtr ps = GetPictureScreen(pScreen);
+ :
+ : if (pPicture->alphaMap)
+ : FreePicture ((pointer) pPicture->alphaMap, (XID) 0);
+ : (*ps->DestroyPicture) (pPicture);
+ : (*ps->DestroyPictureClip) (pPicture);
+ : if (pPicture->pDrawable->type == DRAWABLE_WINDOW)
+ : {
+ : WindowPtr pWindow = (WindowPtr) pPicture->pDrawable;
+ : PicturePtr *pPrev;
+ :
+ : for (pPrev = (PicturePtr *) &((pWindow)->devPrivates[PictureWindowPrivateIndex].ptr);
+ : *pPrev;
+ : pPrev = &(*pPrev)->pNext)
+ : {
+ : if (*pPrev == pPicture)
+ : {
+ : *pPrev = pPicture->pNext;
+ : break;
+ : }
+ : }
+ : }
+ 1 0.0011 : else if (pPicture->pDrawable->type == DRAWABLE_PIXMAP)
+ : {
+ : (*pScreen->DestroyPixmap) ((PixmapPtr)pPicture->pDrawable);
+ : }
+ : }
+ : xfree (pPicture);
+ : }
+ : return Success;
+ :}
+ :
+ :int
+ :FreePictFormat (pointer pPictFormat,
+ : XID pid)
+ :{
+ : return Success;
+ :}
+ :
+ :/**
+ : * ReduceCompositeOp is used to choose simpler ops for cases where alpha
+ : * channels are always one and so math on the alpha channel per pixel becomes
+ : * unnecessary. It may also avoid destination reads sometimes if apps aren't
+ : * being careful to avoid these cases.
+ : */
+ :static Bool
+ :ReduceCompositeOp (CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst)
+ :{
+ : Bool no_src_alpha, no_dst_alpha;
+ :
+ : no_src_alpha = PICT_FORMAT_COLOR(pSrc->format) &&
+ : PICT_FORMAT_A(pSrc->format) == 0 &&
+ : pSrc->alphaMap == NULL &&
+ : pMask == NULL;
+ : no_dst_alpha = PICT_FORMAT_COLOR(pDst->format) &&
+ : PICT_FORMAT_A(pDst->format) == 0 &&
+ : pDst->alphaMap == NULL;
+ :
+ : /* TODO, maybe: Conjoint and Disjoint op reductions? */
+ :
+ : /* Deal with simplifications where the source alpha is always 1. */
+ : if (no_src_alpha)
+ : {
+ : switch (op) {
+ : case PictOpOver:
+ : op = PictOpSrc;
+ : break;
+ : case PictOpInReverse:
+ : op = PictOpDst;
+ : break;
+ : case PictOpOutReverse:
+ : op = PictOpClear;
+ : break;
+ : case PictOpAtop:
+ : op = PictOpIn;
+ : break;
+ : case PictOpAtopReverse:
+ : op = PictOpOverReverse;
+ : break;
+ : case PictOpXor:
+ : op = PictOpOut;
+ : break;
+ : default:
+ : break;
+ : }
+ : }
+ :
+ : /* Deal with simplifications when the destination alpha is always 1 */
+ : if (no_dst_alpha)
+ : {
+ : switch (op) {
+ : case PictOpOverReverse:
+ : op = PictOpDst;
+ : break;
+ : case PictOpIn:
+ : op = PictOpSrc;
+ : break;
+ : case PictOpOut:
+ : op = PictOpClear;
+ : break;
+ : case PictOpAtop:
+ : op = PictOpOver;
+ : break;
+ : case PictOpXor:
+ : op = PictOpOutReverse;
+ : break;
+ : default:
+ : break;
+ : }
+ : }
+ :
+ : /* Reduce some con/disjoint ops to the basic names. */
+ : switch (op) {
+ : case PictOpDisjointClear:
+ : case PictOpConjointClear:
+ : op = PictOpClear;
+ : break;
+ : case PictOpDisjointSrc:
+ : case PictOpConjointSrc:
+ : op = PictOpSrc;
+ : break;
+ : case PictOpDisjointDst:
+ : case PictOpConjointDst:
+ : op = PictOpDst;
+ : break;
+ : default:
+ : break;
+ : }
+ :
+ : return op;
+ :}
+ :
+ :void
+ :CompositePicture (CARD8 op,
+ : PicturePtr pSrc,
+ : PicturePtr pMask,
+ : PicturePtr pDst,
+ : INT16 xSrc,
+ : INT16 ySrc,
+ : INT16 xMask,
+ : INT16 yMask,
+ : INT16 xDst,
+ : INT16 yDst,
+ : CARD16 width,
+ : CARD16 height)
+ 1 0.0011 :{ /* CompositePicture total: 4 0.0044 */
+ : PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen);
+ :
+ : ValidatePicture (pSrc);
+ : if (pMask)
+ : ValidatePicture (pMask);
+ 2 0.0022 : ValidatePicture (pDst);
+ :
+ : op = ReduceCompositeOp (op, pSrc, pMask, pDst);
+ : if (op == PictOpDst)
+ : return;
+ :
+ : (*ps->Composite) (op,
+ : pSrc,
+ : pMask,
+ : pDst,
+ : xSrc,
+ : ySrc,
+ : xMask,
+ : yMask,
+ : xDst,
+ : yDst,
+ : width,
+ : height);
+ :}
+ :
+ :void
+ :CompositeGlyphs (CARD8 op,
+ : PicturePtr pSrc,
+ : PicturePtr pDst,
+ : PictFormatPtr maskFormat,
+ : INT16 xSrc,
+ : INT16 ySrc,
+ : int nlist,
+ : GlyphListPtr lists,
+ : GlyphPtr *glyphs)
+ 1 0.0011 :{ /* CompositeGlyphs total: 1 0.0011 */
+ : PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen);
+ :
+ : ValidatePicture (pSrc);
+ : ValidatePicture (pDst);
+ : (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, lists, glyphs);
+ :}
+ :
+ :void
+ :CompositeRects (CARD8 op,
+ : PicturePtr pDst,
+ : xRenderColor *color,
+ : int nRect,
+ : xRectangle *rects)
+ :{ /* CompositeRects total: 1 0.0011 */
+ 1 0.0011 : PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen);
+ :
+ : ValidatePicture (pDst);
+ : (*ps->CompositeRects) (op, pDst, color, nRect, rects);
+ :}
+ :
+ :void
+ :CompositeTrapezoids (CARD8 op,
+ : PicturePtr pSrc,
+ : PicturePtr pDst,
+ : PictFormatPtr maskFormat,
+ : INT16 xSrc,
+ : INT16 ySrc,
+ : int ntrap,
+ : xTrapezoid *traps)
+ :{
+ : PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen);
+ :
+ : ValidatePicture (pSrc);
+ : ValidatePicture (pDst);
+ : (*ps->Trapezoids) (op, pSrc, pDst, maskFormat, xSrc, ySrc, ntrap, traps);
+ :}
+ :
+ :void
+ :CompositeTriangles (CARD8 op,
+ : PicturePtr pSrc,
+ : PicturePtr pDst,
+ : PictFormatPtr maskFormat,
+ : INT16 xSrc,
+ : INT16 ySrc,
+ : int ntriangles,
+ : xTriangle *triangles)
+ :{
+ : PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen);
+ :
+ : ValidatePicture (pSrc);
+ : ValidatePicture (pDst);
+ : (*ps->Triangles) (op, pSrc, pDst, maskFormat, xSrc, ySrc, ntriangles, triangles);
+ :}
+ :
+ :void
+ :CompositeTriStrip (CARD8 op,
+ : PicturePtr pSrc,
+ : PicturePtr pDst,
+ : PictFormatPtr maskFormat,
+ : INT16 xSrc,
+ : INT16 ySrc,
+ : int npoints,
+ : xPointFixed *points)
+ :{
+ : PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen);
+ :
+ : ValidatePicture (pSrc);
+ : ValidatePicture (pDst);
+ : (*ps->TriStrip) (op, pSrc, pDst, maskFormat, xSrc, ySrc, npoints, points);
+ :}
+ :
+ :void
+ :CompositeTriFan (CARD8 op,
+ : PicturePtr pSrc,
+ : PicturePtr pDst,
+ : PictFormatPtr maskFormat,
+ : INT16 xSrc,
+ : INT16 ySrc,
+ : int npoints,
+ : xPointFixed *points)
+ :{
+ : PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen);
+ :
+ : ValidatePicture (pSrc);
+ : ValidatePicture (pDst);
+ : (*ps->TriFan) (op, pSrc, pDst, maskFormat, xSrc, ySrc, npoints, points);
+ :}
+ :
+ :void
+ :AddTraps (PicturePtr pPicture,
+ : INT16 xOff,
+ : INT16 yOff,
+ : int ntrap,
+ : xTrap *traps)
+ :{
+ : PictureScreenPtr ps = GetPictureScreen(pPicture->pDrawable->pScreen);
+ :
+ : ValidatePicture (pPicture);
+ : (*ps->AddTraps) (pPicture, xOff, yOff, ntrap, traps);
+ :}
+ :
+ :_X_EXPORT Bool
+ :PictureTransformPoint3d (PictTransformPtr transform,
+ : PictVectorPtr vector)
+ :{
+ : PictVector result;
+ : int i, j;
+ : xFixed_32_32 partial;
+ : xFixed_48_16 v;
+ :
+ : for (j = 0; j < 3; j++)
+ : {
+ : v = 0;
+ : for (i = 0; i < 3; i++)
+ : {
+ : partial = ((xFixed_48_16) transform->matrix[j][i] *
+ : (xFixed_48_16) vector->vector[i]);
+ : v += partial >> 16;
+ : }
+ : if (v > MAX_FIXED_48_16 || v < MIN_FIXED_48_16)
+ : return FALSE;
+ : result.vector[j] = (xFixed) v;
+ : }
+ : if (!result.vector[2])
+ : return FALSE;
+ : *vector = result;
+ : return TRUE;
+ :}
+ :
+ :
+ :_X_EXPORT Bool
+ :PictureTransformPoint (PictTransformPtr transform,
+ : PictVectorPtr vector)
+ :{
+ : PictVector result;
+ : int i, j;
+ : xFixed_32_32 partial;
+ : xFixed_48_16 v;
+ :
+ : for (j = 0; j < 3; j++)
+ : {
+ : v = 0;
+ : for (i = 0; i < 3; i++)
+ : {
+ : partial = ((xFixed_48_16) transform->matrix[j][i] *
+ : (xFixed_48_16) vector->vector[i]);
+ : v += partial >> 16;
+ : }
+ : if (v > MAX_FIXED_48_16 || v < MIN_FIXED_48_16)
+ : return FALSE;
+ : result.vector[j] = (xFixed) v;
+ : }
+ : if (!result.vector[2])
+ : return FALSE;
+ : for (j = 0; j < 2; j++)
+ : {
+ : partial = (xFixed_48_16) result.vector[j] << 16;
+ : v = partial / result.vector[2];
+ : if (v > MAX_FIXED_48_16 || v < MIN_FIXED_48_16)
+ : return FALSE;
+ : vector->vector[j] = (xFixed) v;
+ : }
+ : vector->vector[2] = xFixed1;
+ : return TRUE;
+ :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/mi/miscrinit.c"
+ *
+ * 66 0.0719
+ */
+
+
+ :/*
+ :
+ :Copyright 1990, 1998 The Open Group
+ :
+ :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.
+ :
+ :The above copyright notice and this permission notice shall be included
+ :in all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ :OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ :MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ :IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ :OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ :ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ :OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of The Open Group shall
+ :not be used in advertising or otherwise to promote the sale, use or
+ :other dealings in this Software without prior written authorization
+ :from The Open Group.
+ :
+ :*/
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include <X11/X.h>
+ :#include "servermd.h"
+ :#include "misc.h"
+ :#include "mi.h"
+ :#include "scrnintstr.h"
+ :#include "pixmapstr.h"
+ :#include "dix.h"
+ :#include "miline.h"
+ :#ifdef MITSHM
+ :#define _XSHM_SERVER_
+ :#include <X11/extensions/XShm.h>
+ :#endif
+ :
+ :/* We use this structure to propogate some information from miScreenInit to
+ : * miCreateScreenResources. miScreenInit allocates the structure, fills it
+ : * in, and puts it into pScreen->devPrivate. miCreateScreenResources
+ : * extracts the info and frees the structure. We could've accomplished the
+ : * same thing by adding fields to the screen structure, but they would have
+ : * ended up being redundant, and would have exposed this mi implementation
+ : * detail to the whole server.
+ : */
+ :
+ :typedef struct
+ :{
+ : pointer pbits; /* pointer to framebuffer */
+ : int width; /* delta to add to a framebuffer addr to move one row down */
+ :} miScreenInitParmsRec, *miScreenInitParmsPtr;
+ :
+ :
+ :/* this plugs into pScreen->ModifyPixmapHeader */
+ :_X_EXPORT Bool
+ :miModifyPixmapHeader(pPixmap, width, height, depth, bitsPerPixel, devKind,
+ : pPixData)
+ : PixmapPtr pPixmap;
+ : int width;
+ : int height;
+ : int depth;
+ : int bitsPerPixel;
+ : int devKind;
+ : pointer pPixData;
+ 12 0.0131 :{ /* miModifyPixmapHeader total: 66 0.0719 */
+ 2 0.0022 : if (!pPixmap)
+ : return FALSE;
+ :
+ : /*
+ : * If all arguments are specified, reinitialize everything (including
+ : * validated state).
+ : */
+ 7 0.0076 : if ((width > 0) && (height > 0) && (depth > 0) && (bitsPerPixel > 0) &&
+ : (devKind > 0) && pPixData) {
+ : pPixmap->drawable.depth = depth;
+ : pPixmap->drawable.bitsPerPixel = bitsPerPixel;
+ : pPixmap->drawable.id = 0;
+ : pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ : pPixmap->drawable.x = 0;
+ : pPixmap->drawable.y = 0;
+ : pPixmap->drawable.width = width;
+ : pPixmap->drawable.height = height;
+ : pPixmap->devKind = devKind;
+ : pPixmap->refcnt = 1;
+ : pPixmap->devPrivate.ptr = pPixData;
+ : } else {
+ : /*
+ : * Only modify specified fields, keeping all others intact.
+ : */
+ :
+ 3 0.0033 : if (width > 0)
+ : pPixmap->drawable.width = width;
+ :
+ 5 0.0054 : if (height > 0)
+ 1 0.0011 : pPixmap->drawable.height = height;
+ :
+ 1 0.0011 : if (depth > 0)
+ : pPixmap->drawable.depth = depth;
+ :
+ 8 0.0087 : if (bitsPerPixel > 0)
+ : pPixmap->drawable.bitsPerPixel = bitsPerPixel;
+ 1 0.0011 : else if ((bitsPerPixel < 0) && (depth > 0))
+ : pPixmap->drawable.bitsPerPixel = BitsPerPixel(depth);
+ :
+ : /*
+ : * CAVEAT: Non-SI DDXen may use devKind and devPrivate fields for
+ : * other purposes.
+ : */
+ 1 0.0011 : if (devKind > 0)
+ : pPixmap->devKind = devKind;
+ : else if ((devKind < 0) && ((width > 0) || (depth > 0)))
+ 14 0.0153 : pPixmap->devKind = PixmapBytePad(pPixmap->drawable.width,
+ : pPixmap->drawable.depth);
+ :
+ 4 0.0044 : if (pPixData)
+ 2 0.0022 : pPixmap->devPrivate.ptr = pPixData;
+ : }
+ : return TRUE;
+ 5 0.0054 :}
+ :
+ :static Bool
+ :miCloseScreen (int iScreen, ScreenPtr pScreen)
+ :{
+ : return ((*pScreen->DestroyPixmap)((PixmapPtr)pScreen->devPrivate));
+ :}
+ :
+ :/* With the introduction of pixmap privates, the "screen pixmap" can no
+ : * longer be created in miScreenInit, since all the modules that could
+ : * possibly ask for pixmap private space have not been initialized at
+ : * that time. pScreen->CreateScreenResources is called after all
+ : * possible private-requesting modules have been inited; we create the
+ : * screen pixmap here.
+ : */
+ :_X_EXPORT Bool
+ :miCreateScreenResources(pScreen)
+ : ScreenPtr pScreen;
+ :{
+ : miScreenInitParmsPtr pScrInitParms;
+ : pointer value;
+ :
+ : pScrInitParms = (miScreenInitParmsPtr)pScreen->devPrivate;
+ :
+ : /* if width is non-zero, pScreen->devPrivate will be a pixmap
+ : * else it will just take the value pbits
+ : */
+ : if (pScrInitParms->width)
+ : {
+ : PixmapPtr pPixmap;
+ :
+ : /* create a pixmap with no data, then redirect it to point to
+ : * the screen
+ : */
+ : pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth);
+ : if (!pPixmap)
+ : return FALSE;
+ :
+ : if (!(*pScreen->ModifyPixmapHeader)(pPixmap, pScreen->width,
+ : pScreen->height, pScreen->rootDepth,
+ : BitsPerPixel(pScreen->rootDepth),
+ : PixmapBytePad(pScrInitParms->width, pScreen->rootDepth),
+ : pScrInitParms->pbits))
+ : return FALSE;
+ : value = (pointer)pPixmap;
+ : }
+ : else
+ : {
+ : value = pScrInitParms->pbits;
+ : }
+ : xfree(pScreen->devPrivate); /* freeing miScreenInitParmsRec */
+ : pScreen->devPrivate = value; /* pPixmap or pbits */
+ : return TRUE;
+ :}
+ :
+ :Bool
+ :miScreenDevPrivateInit(pScreen, width, pbits)
+ : ScreenPtr pScreen;
+ : int width;
+ : pointer pbits;
+ :{
+ : miScreenInitParmsPtr pScrInitParms;
+ :
+ : /* Stash pbits and width in a short-lived miScreenInitParmsRec attached
+ : * to the screen, until CreateScreenResources can put them in the
+ : * screen pixmap.
+ : */
+ : pScrInitParms = (miScreenInitParmsPtr)xalloc(sizeof(miScreenInitParmsRec));
+ : if (!pScrInitParms)
+ : return FALSE;
+ : pScrInitParms->pbits = pbits;
+ : pScrInitParms->width = width;
+ : pScreen->devPrivate = (pointer)pScrInitParms;
+ : return TRUE;
+ :}
+ :
+ :_X_EXPORT Bool
+ :miScreenInit(pScreen, pbits, xsize, ysize, dpix, dpiy, width,
+ : rootDepth, numDepths, depths, rootVisual, numVisuals, visuals)
+ : ScreenPtr pScreen;
+ : pointer pbits; /* pointer to screen bits */
+ : int xsize, ysize; /* in pixels */
+ : int dpix, dpiy; /* dots per inch */
+ : int width; /* pixel width of frame buffer */
+ : int rootDepth; /* depth of root window */
+ : int numDepths; /* number of depths supported */
+ : DepthRec *depths; /* supported depths */
+ : VisualID rootVisual; /* root visual */
+ : int numVisuals; /* number of visuals supported */
+ : VisualRec *visuals; /* supported visuals */
+ :{
+ : pScreen->width = xsize;
+ : pScreen->height = ysize;
+ : pScreen->mmWidth = (xsize * 254 + dpix * 5) / (dpix * 10);
+ : pScreen->mmHeight = (ysize * 254 + dpiy * 5) / (dpiy * 10);
+ : pScreen->numDepths = numDepths;
+ : pScreen->rootDepth = rootDepth;
+ : pScreen->allowedDepths = depths;
+ : pScreen->rootVisual = rootVisual;
+ : /* defColormap */
+ : pScreen->minInstalledCmaps = 1;
+ : pScreen->maxInstalledCmaps = 1;
+ : pScreen->backingStoreSupport = NotUseful;
+ : pScreen->saveUnderSupport = NotUseful;
+ : /* whitePixel, blackPixel */
+ : pScreen->ModifyPixmapHeader = miModifyPixmapHeader;
+ : pScreen->CreateScreenResources = miCreateScreenResources;
+ : pScreen->GetScreenPixmap = miGetScreenPixmap;
+ : pScreen->SetScreenPixmap = miSetScreenPixmap;
+ : pScreen->numVisuals = numVisuals;
+ : pScreen->visuals = visuals;
+ : if (width)
+ : {
+ :#ifdef MITSHM
+ : ShmRegisterFbFuncs(pScreen);
+ :#endif
+ : pScreen->CloseScreen = miCloseScreen;
+ : }
+ : /* else CloseScreen */
+ : /* QueryBestSize, SaveScreen, GetImage, GetSpans */
+ : pScreen->PointerNonInterestBox = (PointerNonInterestBoxProcPtr) 0;
+ : pScreen->SourceValidate = (SourceValidateProcPtr) 0;
+ : /* CreateWindow, DestroyWindow, PositionWindow, ChangeWindowAttributes */
+ : /* RealizeWindow, UnrealizeWindow */
+ : pScreen->ValidateTree = miValidateTree;
+ : pScreen->PostValidateTree = (PostValidateTreeProcPtr) 0;
+ : pScreen->WindowExposures = miWindowExposures;
+ : /* PaintWindowBackground, PaintWindowBorder, CopyWindow */
+ : pScreen->ClearToBackground = miClearToBackground;
+ : pScreen->ClipNotify = (ClipNotifyProcPtr) 0;
+ : pScreen->RestackWindow = (RestackWindowProcPtr) 0;
+ : /* CreatePixmap, DestroyPixmap */
+ : /* RealizeFont, UnrealizeFont */
+ : /* CreateGC */
+ : /* CreateColormap, DestroyColormap, InstallColormap, UninstallColormap */
+ : /* ListInstalledColormaps, StoreColors, ResolveColor */
+ : /* BitmapToRegion */
+ : pScreen->SendGraphicsExpose = miSendGraphicsExpose;
+ : pScreen->BlockHandler = (ScreenBlockHandlerProcPtr)NoopDDA;
+ : pScreen->WakeupHandler = (ScreenWakeupHandlerProcPtr)NoopDDA;
+ : pScreen->blockData = (pointer)0;
+ : pScreen->wakeupData = (pointer)0;
+ : pScreen->MarkWindow = miMarkWindow;
+ : pScreen->MarkOverlappedWindows = miMarkOverlappedWindows;
+ : pScreen->ChangeSaveUnder = miChangeSaveUnder;
+ : pScreen->PostChangeSaveUnder = miPostChangeSaveUnder;
+ : pScreen->MoveWindow = miMoveWindow;
+ : pScreen->ResizeWindow = miSlideAndSizeWindow;
+ : pScreen->GetLayerWindow = miGetLayerWindow;
+ : pScreen->HandleExposures = miHandleValidateExposures;
+ : pScreen->ReparentWindow = (ReparentWindowProcPtr) 0;
+ : pScreen->ChangeBorderWidth = miChangeBorderWidth;
+ :#ifdef SHAPE
+ : pScreen->SetShape = miSetShape;
+ :#endif
+ : pScreen->MarkUnrealizedWindow = miMarkUnrealizedWindow;
+ :
+ : pScreen->SaveDoomedAreas = 0;
+ : pScreen->RestoreAreas = 0;
+ : pScreen->ExposeCopy = 0;
+ : pScreen->TranslateBackingStore = 0;
+ : pScreen->ClearBackingStore = 0;
+ : pScreen->DrawGuarantee = 0;
+ :
+ : miSetZeroLineBias(pScreen, DEFAULTZEROLINEBIAS);
+ :
+ : return miScreenDevPrivateInit(pScreen, width, pbits);
+ :}
+ :
+ :_X_EXPORT int
+ :miAllocateGCPrivateIndex()
+ :{
+ : static int privateIndex = -1;
+ : static unsigned long miGeneration = 0;
+ :
+ : if (miGeneration != serverGeneration)
+ : {
+ : privateIndex = AllocateGCPrivateIndex();
+ : miGeneration = serverGeneration;
+ : }
+ : return privateIndex;
+ :}
+ :
+ :_X_EXPORT int miZeroLineScreenIndex;
+ :static unsigned int miZeroLineGeneration = 0;
+ :
+ :_X_EXPORT void
+ :miSetZeroLineBias(pScreen, bias)
+ : ScreenPtr pScreen;
+ : unsigned int bias;
+ :{
+ : if (miZeroLineGeneration != serverGeneration)
+ : {
+ : miZeroLineScreenIndex = AllocateScreenPrivateIndex();
+ : miZeroLineGeneration = serverGeneration;
+ : }
+ : if (miZeroLineScreenIndex >= 0)
+ : pScreen->devPrivates[miZeroLineScreenIndex].uval = bias;
+ :}
+ :
+ :_X_EXPORT PixmapPtr
+ :miGetScreenPixmap(pScreen)
+ : ScreenPtr pScreen;
+ :{
+ : return (PixmapPtr)(pScreen->devPrivate);
+ :}
+ :
+ :_X_EXPORT void
+ :miSetScreenPixmap(pPix)
+ : PixmapPtr pPix;
+ :{
+ : if (pPix)
+ : pPix->drawable.pScreen->devPrivate = (pointer)pPix;
+ :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/mi/miregion.c"
+ *
+ * 66 0.0719
+ */
+
+
+ :/***********************************************************
+ :
+ :Copyright 1987, 1988, 1989, 1998 The Open Group
+ :
+ :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.
+ :
+ :The above copyright notice and this permission notice shall be included in
+ :all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ :IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ :FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ :OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ :AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ :CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of The Open Group shall not be
+ :used in advertising or otherwise to promote the sale, use or other dealings
+ :in this Software without prior written authorization from The Open Group.
+ :
+ :
+ :Copyright 1987, 1988, 1989 by
+ :Digital Equipment Corporation, Maynard, Massachusetts.
+ :
+ : All Rights Reserved
+ :
+ :Permission to use, copy, modify, and distribute this software and its
+ :documentation for any purpose and without fee is hereby granted,
+ :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 Digital not be
+ :used in advertising or publicity pertaining to distribution of the
+ :software without specific, written prior permission.
+ :
+ :DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ :ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ :DIGITAL 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.
+ :
+ :******************************************************************/
+ :
+ :/* The panoramix components contained the following notice */
+ :/*****************************************************************
+ :
+ :Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
+ :
+ :Permission is hereby granted, free of charge, to any person obtaining a copy
+ :of this software and associated documentation files (the "Software"), to deal
+ :in the Software without restriction, including without limitation the rights
+ :to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ :copies of the Software.
+ :
+ :The above copyright notice and this permission notice shall be included in
+ :all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ :IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ :FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ :DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
+ :BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
+ :WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+ :IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of Digital Equipment Corporation
+ :shall not be used in advertising or otherwise to promote the sale, use or other
+ :dealings in this Software without prior written authorization from Digital
+ :Equipment Corporation.
+ :
+ :******************************************************************/
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include "regionstr.h"
+ :#include <X11/Xprotostr.h>
+ :#include <X11/Xfuncproto.h>
+ :#include "gc.h"
+ :#include "mi.h"
+ :#include "mispans.h"
+ :#include <pixman/pixman.h>
+ :
+ :#undef assert
+ :#ifdef DEBUG
+ :#define assert(expr) {if (!(expr)) \
+ : FatalError("Assertion failed file %s, line %d: expr\n", \
+ : __FILE__, __LINE__); }
+ :#else
+ :#define assert(expr)
+ :#endif
+ :
+ :#define good(reg) assert(miValidRegion(reg))
+ :
+ :/*
+ : * The functions in this file implement the Region abstraction used extensively
+ : * throughout the X11 sample server. A Region is simply a set of disjoint
+ : * (non-overlapping) rectangles, plus an "extent" rectangle which is the
+ : * smallest single rectangle that contains all the non-overlapping rectangles.
+ : *
+ : * A Region is implemented as a "y-x-banded" array of rectangles. This array
+ : * imposes two degrees of order. First, all rectangles are sorted by top side
+ : * y coordinate first (y1), and then by left side x coordinate (x1).
+ : *
+ : * Furthermore, the rectangles are grouped into "bands". Each rectangle in a
+ : * band has the same top y coordinate (y1), and each has the same bottom y
+ : * coordinate (y2). Thus all rectangles in a band differ only in their left
+ : * and right side (x1 and x2). Bands are implicit in the array of rectangles:
+ : * there is no separate list of band start pointers.
+ : *
+ : * The y-x band representation does not minimize rectangles. In particular,
+ : * if a rectangle vertically crosses a band (the rectangle has scanlines in
+ : * the y1 to y2 area spanned by the band), then the rectangle may be broken
+ : * down into two or more smaller rectangles stacked one atop the other.
+ : *
+ : * ----------- -----------
+ : * | | | | band 0
+ : * | | -------- ----------- --------
+ : * | | | | in y-x banded | | | | band 1
+ : * | | | | form is | | | |
+ : * ----------- | | ----------- --------
+ : * | | | | band 2
+ : * -------- --------
+ : *
+ : * An added constraint on the rectangles is that they must cover as much
+ : * horizontal area as possible: no two rectangles within a band are allowed
+ : * to touch.
+ : *
+ : * Whenever possible, bands will be merged together to cover a greater vertical
+ : * distance (and thus reduce the number of rectangles). Two bands can be merged
+ : * only if the bottom of one touches the top of the other and they have
+ : * rectangles in the same places (of the same width, of course).
+ : *
+ : * Adam de Boor wrote most of the original region code. Joel McCormack
+ : * substantially modified or rewrote most of the core arithmetic routines,
+ : * and added miRegionValidate in order to support several speed improvements
+ : * to miValidateTree. Bob Scheifler changed the representation to be more
+ : * compact when empty or a single rectangle, and did a bunch of gratuitous
+ : * reformatting.
+ : */
+ :
+ :/* true iff two Boxes overlap */
+ :#define EXTENTCHECK(r1,r2) \
+ : (!( ((r1)->x2 <= (r2)->x1) || \
+ : ((r1)->x1 >= (r2)->x2) || \
+ : ((r1)->y2 <= (r2)->y1) || \
+ : ((r1)->y1 >= (r2)->y2) ) )
+ :
+ :/* true iff (x,y) is in Box */
+ :#define INBOX(r,x,y) \
+ : ( ((r)->x2 > x) && \
+ : ((r)->x1 <= x) && \
+ : ((r)->y2 > y) && \
+ : ((r)->y1 <= y) )
+ :
+ :/* true iff Box r1 contains Box r2 */
+ :#define SUBSUMES(r1,r2) \
+ : ( ((r1)->x1 <= (r2)->x1) && \
+ : ((r1)->x2 >= (r2)->x2) && \
+ : ((r1)->y1 <= (r2)->y1) && \
+ : ((r1)->y2 >= (r2)->y2) )
+ :
+ :#define xallocData(n) (RegDataPtr)xalloc(REGION_SZOF(n))
+ :#define xfreeData(reg) if ((reg)->data && (reg)->data->size) xfree((reg)->data)
+ :
+ :#define RECTALLOC_BAIL(pReg,n,bail) \
+ :if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
+ : if (!miRectAlloc(pReg, n)) { goto bail; }
+ :
+ :#define RECTALLOC(pReg,n) \
+ :if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
+ : if (!miRectAlloc(pReg, n)) { return FALSE; }
+ :
+ :#define ADDRECT(pNextRect,nx1,ny1,nx2,ny2) \
+ :{ \
+ : pNextRect->x1 = nx1; \
+ : pNextRect->y1 = ny1; \
+ : pNextRect->x2 = nx2; \
+ : pNextRect->y2 = ny2; \
+ : pNextRect++; \
+ :}
+ :
+ :#define NEWRECT(pReg,pNextRect,nx1,ny1,nx2,ny2) \
+ :{ \
+ : if (!(pReg)->data || ((pReg)->data->numRects == (pReg)->data->size))\
+ : { \
+ : if (!miRectAlloc(pReg, 1)) \
+ : return FALSE; \
+ : pNextRect = REGION_TOP(pReg); \
+ : } \
+ : ADDRECT(pNextRect,nx1,ny1,nx2,ny2); \
+ : pReg->data->numRects++; \
+ : assert(pReg->data->numRects<=pReg->data->size); \
+ :}
+ :
+ :
+ :#define DOWNSIZE(reg,numRects) \
+ :if (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) \
+ :{ \
+ : RegDataPtr NewData; \
+ : NewData = (RegDataPtr)xrealloc((reg)->data, REGION_SZOF(numRects)); \
+ : if (NewData) \
+ : { \
+ : NewData->size = (numRects); \
+ : (reg)->data = NewData; \
+ : } \
+ :}
+ :
+ :
+ :_X_EXPORT BoxRec miEmptyBox = {0, 0, 0, 0};
+ :_X_EXPORT RegDataRec miEmptyData = {0, 0};
+ :
+ :RegDataRec miBrokenData = {0, 0};
+ :static RegionRec miBrokenRegion = { { 0, 0, 0, 0 }, &miBrokenData };
+ :
+ :extern void
+ :InitRegions (void)
+ :{
+ : pixman_region_set_static_pointers (&miEmptyBox, &miEmptyData, &miBrokenData);
+ :}
+ :
+ :/*****************************************************************
+ : * RegionCreate(rect, size)
+ : * This routine does a simple malloc to make a structure of
+ : * REGION of "size" number of rectangles.
+ : *****************************************************************/
+ :
+ :_X_EXPORT RegionPtr
+ :miRegionCreate(rect, size)
+ : BoxPtr rect;
+ : int size;
+ 3 0.0033 :{ /* miRegionCreate total: 5 0.0054 */
+ : RegionPtr pReg;
+ :
+ : pReg = (RegionPtr)xalloc(sizeof(RegionRec));
+ 1 0.0011 : if (!pReg)
+ : return &miBrokenRegion;
+ :
+ 1 0.0011 : miRegionInit (pReg, rect, size);
+ :
+ : return(pReg);
+ :}
+ :
+ :_X_EXPORT void
+ :miRegionDestroy(pReg)
+ : RegionPtr pReg;
+ 3 0.0033 :{ /* miRegionDestroy total: 5 0.0054 */
+ : pixman_region_fini (pReg);
+ : if (pReg != &miBrokenRegion)
+ 1 0.0011 : xfree(pReg);
+ 1 0.0011 :}
+ :
+ :_X_EXPORT void
+ :miPrintRegion(rgn)
+ : RegionPtr rgn;
+ :{
+ : int num, size;
+ : int i;
+ : BoxPtr rects;
+ :
+ : num = REGION_NUM_RECTS(rgn);
+ : size = REGION_SIZE(rgn);
+ : rects = REGION_RECTS(rgn);
+ : ErrorF("num: %d size: %d\n", num, size);
+ : ErrorF("extents: %d %d %d %d\n",
+ : rgn->extents.x1, rgn->extents.y1, rgn->extents.x2, rgn->extents.y2);
+ : for (i = 0; i < num; i++)
+ : ErrorF("%d %d %d %d \n",
+ : rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2);
+ : ErrorF("\n");
+ :}
+ :
+ :_X_EXPORT Bool
+ :miRegionEqual(reg1, reg2)
+ : RegionPtr reg1;
+ : RegionPtr reg2;
+ :{
+ : return pixman_region_equal (reg1, reg2);
+ :}
+ :
+ :#ifdef DEBUG
+ :Bool
+ :miValidRegion(reg)
+ : RegionPtr reg;
+ :{
+ : int i, numRects;
+ :
+ : if ((reg->extents.x1 > reg->extents.x2) ||
+ : (reg->extents.y1 > reg->extents.y2))
+ : return FALSE;
+ : numRects = REGION_NUM_RECTS(reg);
+ : if (!numRects)
+ : return ((reg->extents.x1 == reg->extents.x2) &&
+ : (reg->extents.y1 == reg->extents.y2) &&
+ : (reg->data->size || (reg->data == &miEmptyData)));
+ : else if (numRects == 1)
+ : return (!reg->data);
+ : else
+ : {
+ : BoxPtr pboxP, pboxN;
+ : BoxRec box;
+ :
+ : pboxP = REGION_RECTS(reg);
+ : box = *pboxP;
+ : box.y2 = pboxP[numRects-1].y2;
+ : pboxN = pboxP + 1;
+ : for (i = numRects; --i > 0; pboxP++, pboxN++)
+ : {
+ : if ((pboxN->x1 >= pboxN->x2) ||
+ : (pboxN->y1 >= pboxN->y2))
+ : return FALSE;
+ : if (pboxN->x1 < box.x1)
+ : box.x1 = pboxN->x1;
+ : if (pboxN->x2 > box.x2)
+ : box.x2 = pboxN->x2;
+ : if ((pboxN->y1 < pboxP->y1) ||
+ : ((pboxN->y1 == pboxP->y1) &&
+ : ((pboxN->x1 < pboxP->x2) || (pboxN->y2 != pboxP->y2))))
+ : return FALSE;
+ : }
+ : return ((box.x1 == reg->extents.x1) &&
+ : (box.x2 == reg->extents.x2) &&
+ : (box.y1 == reg->extents.y1) &&
+ : (box.y2 == reg->extents.y2));
+ : }
+ :}
+ :#endif /* DEBUG */
+ :
+ :/*****************************************************************
+ : * RegionInit(pReg, rect, size)
+ : * Outer region rect is statically allocated.
+ : *****************************************************************/
+ :
+ :_X_EXPORT void
+ :miRegionInit(pReg, rect, size)
+ : RegionPtr pReg;
+ : BoxPtr rect;
+ : int size;
+ 3 0.0033 :{ /* miRegionInit total: 5 0.0054 */
+ : if (rect)
+ : pixman_region_init_with_extents (pReg, rect);
+ : else
+ : pixman_region_init (pReg);
+ 2 0.0022 :}
+ :
+ :_X_EXPORT void
+ :miRegionUninit(pReg)
+ : RegionPtr pReg;
+ :{
+ : pixman_region_fini (pReg);
+ :}
+ :
+ :Bool
+ :miRegionBreak (pReg)
+ : RegionPtr pReg;
+ :{
+ : xfreeData (pReg);
+ : pReg->extents = miEmptyBox;
+ : pReg->data = &miBrokenData;
+ : return FALSE;
+ :}
+ :
+ :_X_EXPORT Bool
+ :miRectAlloc(
+ : RegionPtr pRgn,
+ : int n)
+ :{
+ : RegDataPtr data;
+ :
+ : if (!pRgn->data)
+ : {
+ : n++;
+ : pRgn->data = xallocData(n);
+ : if (!pRgn->data)
+ : return miRegionBreak (pRgn);
+ : pRgn->data->numRects = 1;
+ : *REGION_BOXPTR(pRgn) = pRgn->extents;
+ : }
+ : else if (!pRgn->data->size)
+ : {
+ : pRgn->data = xallocData(n);
+ : if (!pRgn->data)
+ : return miRegionBreak (pRgn);
+ : pRgn->data->numRects = 0;
+ : }
+ : else
+ : {
+ : if (n == 1)
+ : {
+ : n = pRgn->data->numRects;
+ : if (n > 500) /* XXX pick numbers out of a hat */
+ : n = 250;
+ : }
+ : n += pRgn->data->numRects;
+ : data = (RegDataPtr)xrealloc(pRgn->data, REGION_SZOF(n));
+ : if (!data)
+ : return miRegionBreak (pRgn);
+ : pRgn->data = data;
+ : }
+ : pRgn->data->size = n;
+ : return TRUE;
+ :}
+ :
+ :_X_EXPORT Bool
+ :miRegionCopy(dst, src)
+ : RegionPtr dst;
+ : RegionPtr src;
+ 1 0.0011 :{ /* miRegionCopy total: 1 0.0011 */
+ : return pixman_region_copy (dst, src);
+ :}
+ :
+ :/*======================================================================
+ : * Generic Region Operator
+ : *====================================================================*/
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miCoalesce --
+ : * Attempt to merge the boxes in the current band with those in the
+ : * previous one. We are guaranteed that the current band extends to
+ : * the end of the rects array. Used only by miRegionOp.
+ : *
+ : * Results:
+ : * The new index for the previous band.
+ : *
+ : * Side Effects:
+ : * If coalescing takes place:
+ : * - rectangles in the previous band will have their y2 fields
+ : * altered.
+ : * - pReg->data->numRects will be decreased.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :_X_INLINE static int
+ :miCoalesce (
+ : RegionPtr pReg, /* Region to coalesce */
+ : int prevStart, /* Index of start of previous band */
+ : int curStart) /* Index of start of current band */
+ :{
+ : BoxPtr pPrevBox; /* Current box in previous band */
+ : BoxPtr pCurBox; /* Current box in current band */
+ : int numRects; /* Number rectangles in both bands */
+ : int y2; /* Bottom of current band */
+ : /*
+ : * Figure out how many rectangles are in the band.
+ : */
+ : numRects = curStart - prevStart;
+ : assert(numRects == pReg->data->numRects - curStart);
+ :
+ : if (!numRects) return curStart;
+ :
+ : /*
+ : * The bands may only be coalesced if the bottom of the previous
+ : * matches the top scanline of the current.
+ : */
+ : pPrevBox = REGION_BOX(pReg, prevStart);
+ : pCurBox = REGION_BOX(pReg, curStart);
+ : if (pPrevBox->y2 != pCurBox->y1) return curStart;
+ :
+ : /*
+ : * Make sure the bands have boxes in the same places. This
+ : * assumes that boxes have been added in such a way that they
+ : * cover the most area possible. I.e. two boxes in a band must
+ : * have some horizontal space between them.
+ : */
+ : y2 = pCurBox->y2;
+ :
+ : do {
+ : if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) {
+ : return (curStart);
+ : }
+ : pPrevBox++;
+ : pCurBox++;
+ : numRects--;
+ : } while (numRects);
+ :
+ : /*
+ : * The bands may be merged, so set the bottom y of each box
+ : * in the previous band to the bottom y of the current band.
+ : */
+ : numRects = curStart - prevStart;
+ : pReg->data->numRects -= numRects;
+ : do {
+ : pPrevBox--;
+ : pPrevBox->y2 = y2;
+ : numRects--;
+ : } while (numRects);
+ : return prevStart;
+ :}
+ :
+ :
+ :/* Quicky macro to avoid trivial reject procedure calls to miCoalesce */
+ :
+ :#define Coalesce(newReg, prevBand, curBand) \
+ : if (curBand - prevBand == newReg->data->numRects - curBand) { \
+ : prevBand = miCoalesce(newReg, prevBand, curBand); \
+ : } else { \
+ : prevBand = curBand; \
+ : }
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miAppendNonO --
+ : * Handle a non-overlapping band for the union and subtract operations.
+ : * Just adds the (top/bottom-clipped) rectangles into the region.
+ : * Doesn't have to check for subsumption or anything.
+ : *
+ : * Results:
+ : * None.
+ : *
+ : * Side Effects:
+ : * pReg->data->numRects is incremented and the rectangles overwritten
+ : * with the rectangles we're passed.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :
+ :_X_INLINE static Bool
+ :miAppendNonO (
+ : RegionPtr pReg,
+ : BoxPtr r,
+ : BoxPtr rEnd,
+ : int y1,
+ : int y2)
+ :{
+ : BoxPtr pNextRect;
+ : int newRects;
+ :
+ : newRects = rEnd - r;
+ :
+ : assert(y1 < y2);
+ : assert(newRects != 0);
+ :
+ : /* Make sure we have enough space for all rectangles to be added */
+ : RECTALLOC(pReg, newRects);
+ : pNextRect = REGION_TOP(pReg);
+ : pReg->data->numRects += newRects;
+ : do {
+ : assert(r->x1 < r->x2);
+ : ADDRECT(pNextRect, r->x1, y1, r->x2, y2);
+ : r++;
+ : } while (r != rEnd);
+ :
+ : return TRUE;
+ :}
+ :
+ :#define FindBand(r, rBandEnd, rEnd, ry1) \
+ :{ \
+ : ry1 = r->y1; \
+ : rBandEnd = r+1; \
+ : while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) { \
+ : rBandEnd++; \
+ : } \
+ :}
+ :
+ :#define AppendRegions(newReg, r, rEnd) \
+ :{ \
+ : int newRects; \
+ : if ((newRects = rEnd - r)) { \
+ : RECTALLOC(newReg, newRects); \
+ : memmove((char *)REGION_TOP(newReg),(char *)r, \
+ : newRects * sizeof(BoxRec)); \
+ : newReg->data->numRects += newRects; \
+ : } \
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miRegionOp --
+ : * Apply an operation to two regions. Called by miUnion, miInverse,
+ : * miSubtract, miIntersect.... Both regions MUST have at least one
+ : * rectangle, and cannot be the same object.
+ : *
+ : * Results:
+ : * TRUE if successful.
+ : *
+ : * Side Effects:
+ : * The new region is overwritten.
+ : * pOverlap set to TRUE if overlapFunc ever returns TRUE.
+ : *
+ : * Notes:
+ : * The idea behind this function is to view the two regions as sets.
+ : * Together they cover a rectangle of area that this function divides
+ : * into horizontal bands where points are covered only by one region
+ : * or by both. For the first case, the nonOverlapFunc is called with
+ : * each the band and the band's upper and lower extents. For the
+ : * second, the overlapFunc is called to process the entire band. It
+ : * is responsible for clipping the rectangles in the band, though
+ : * this function provides the boundaries.
+ : * At the end of each band, the new region is coalesced, if possible,
+ : * to reduce the number of rectangles in the region.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :
+ :typedef Bool (*OverlapProcPtr)(
+ : RegionPtr pReg,
+ : BoxPtr r1,
+ : BoxPtr r1End,
+ : BoxPtr r2,
+ : BoxPtr r2End,
+ : short y1,
+ : short y2,
+ : Bool *pOverlap);
+ :
+ :static Bool
+ :miRegionOp(
+ : RegionPtr newReg, /* Place to store result */
+ : RegionPtr reg1, /* First region in operation */
+ : RegionPtr reg2, /* 2d region in operation */
+ : OverlapProcPtr overlapFunc, /* Function to call for over-
+ : * lapping bands */
+ : Bool appendNon1, /* Append non-overlapping bands */
+ : /* in region 1 ? */
+ : Bool appendNon2, /* Append non-overlapping bands */
+ : /* in region 2 ? */
+ : Bool *pOverlap)
+ :{
+ : BoxPtr r1; /* Pointer into first region */
+ : BoxPtr r2; /* Pointer into 2d region */
+ : BoxPtr r1End; /* End of 1st region */
+ : BoxPtr r2End; /* End of 2d region */
+ : short ybot; /* Bottom of intersection */
+ : short ytop; /* Top of intersection */
+ : RegDataPtr oldData; /* Old data for newReg */
+ : int prevBand; /* Index of start of
+ : * previous band in newReg */
+ : int curBand; /* Index of start of current
+ : * band in newReg */
+ : BoxPtr r1BandEnd; /* End of current band in r1 */
+ : BoxPtr r2BandEnd; /* End of current band in r2 */
+ : short top; /* Top of non-overlapping band */
+ : short bot; /* Bottom of non-overlapping band*/
+ : int r1y1; /* Temps for r1->y1 and r2->y1 */
+ : int r2y1;
+ : int newSize;
+ : int numRects;
+ :
+ : /*
+ : * Break any region computed from a broken region
+ : */
+ : if (REGION_NAR (reg1) || REGION_NAR(reg2))
+ : return miRegionBreak (newReg);
+ :
+ : /*
+ : * Initialization:
+ : * set r1, r2, r1End and r2End appropriately, save the rectangles
+ : * of the destination region until the end in case it's one of
+ : * the two source regions, then mark the "new" region empty, allocating
+ : * another array of rectangles for it to use.
+ : */
+ :
+ : r1 = REGION_RECTS(reg1);
+ : newSize = REGION_NUM_RECTS(reg1);
+ : r1End = r1 + newSize;
+ : numRects = REGION_NUM_RECTS(reg2);
+ : r2 = REGION_RECTS(reg2);
+ : r2End = r2 + numRects;
+ : assert(r1 != r1End);
+ : assert(r2 != r2End);
+ :
+ : oldData = (RegDataPtr)NULL;
+ : if (((newReg == reg1) && (newSize > 1)) ||
+ : ((newReg == reg2) && (numRects > 1)))
+ : {
+ : oldData = newReg->data;
+ : newReg->data = &miEmptyData;
+ : }
+ : /* guess at new size */
+ : if (numRects > newSize)
+ : newSize = numRects;
+ : newSize <<= 1;
+ : if (!newReg->data)
+ : newReg->data = &miEmptyData;
+ : else if (newReg->data->size)
+ : newReg->data->numRects = 0;
+ : if (newSize > newReg->data->size)
+ : if (!miRectAlloc(newReg, newSize))
+ : return FALSE;
+ :
+ : /*
+ : * Initialize ybot.
+ : * In the upcoming loop, ybot and ytop serve different functions depending
+ : * on whether the band being handled is an overlapping or non-overlapping
+ : * band.
+ : * In the case of a non-overlapping band (only one of the regions
+ : * has points in the band), ybot is the bottom of the most recent
+ : * intersection and thus clips the top of the rectangles in that band.
+ : * ytop is the top of the next intersection between the two regions and
+ : * serves to clip the bottom of the rectangles in the current band.
+ : * For an overlapping band (where the two regions intersect), ytop clips
+ : * the top of the rectangles of both regions and ybot clips the bottoms.
+ : */
+ :
+ : ybot = min(r1->y1, r2->y1);
+ :
+ : /*
+ : * prevBand serves to mark the start of the previous band so rectangles
+ : * can be coalesced into larger rectangles. qv. miCoalesce, above.
+ : * In the beginning, there is no previous band, so prevBand == curBand
+ : * (curBand is set later on, of course, but the first band will always
+ : * start at index 0). prevBand and curBand must be indices because of
+ : * the possible expansion, and resultant moving, of the new region's
+ : * array of rectangles.
+ : */
+ : prevBand = 0;
+ :
+ : do {
+ : /*
+ : * This algorithm proceeds one source-band (as opposed to a
+ : * destination band, which is determined by where the two regions
+ : * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
+ : * rectangle after the last one in the current band for their
+ : * respective regions.
+ : */
+ : assert(r1 != r1End);
+ : assert(r2 != r2End);
+ :
+ : FindBand(r1, r1BandEnd, r1End, r1y1);
+ : FindBand(r2, r2BandEnd, r2End, r2y1);
+ :
+ : /*
+ : * First handle the band that doesn't intersect, if any.
+ : *
+ : * Note that attention is restricted to one band in the
+ : * non-intersecting region at once, so if a region has n
+ : * bands between the current position and the next place it overlaps
+ : * the other, this entire loop will be passed through n times.
+ : */
+ : if (r1y1 < r2y1) {
+ : if (appendNon1) {
+ : top = max(r1y1, ybot);
+ : bot = min(r1->y2, r2y1);
+ : if (top != bot) {
+ : curBand = newReg->data->numRects;
+ : miAppendNonO(newReg, r1, r1BandEnd, top, bot);
+ : Coalesce(newReg, prevBand, curBand);
+ : }
+ : }
+ : ytop = r2y1;
+ : } else if (r2y1 < r1y1) {
+ : if (appendNon2) {
+ : top = max(r2y1, ybot);
+ : bot = min(r2->y2, r1y1);
+ : if (top != bot) {
+ : curBand = newReg->data->numRects;
+ : miAppendNonO(newReg, r2, r2BandEnd, top, bot);
+ : Coalesce(newReg, prevBand, curBand);
+ : }
+ : }
+ : ytop = r1y1;
+ : } else {
+ : ytop = r1y1;
+ : }
+ :
+ : /*
+ : * Now see if we've hit an intersecting band. The two bands only
+ : * intersect if ybot > ytop
+ : */
+ : ybot = min(r1->y2, r2->y2);
+ : if (ybot > ytop) {
+ : curBand = newReg->data->numRects;
+ : (* overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot,
+ : pOverlap);
+ : Coalesce(newReg, prevBand, curBand);
+ : }
+ :
+ : /*
+ : * If we've finished with a band (y2 == ybot) we skip forward
+ : * in the region to the next band.
+ : */
+ : if (r1->y2 == ybot) r1 = r1BandEnd;
+ : if (r2->y2 == ybot) r2 = r2BandEnd;
+ :
+ : } while (r1 != r1End && r2 != r2End);
+ :
+ : /*
+ : * Deal with whichever region (if any) still has rectangles left.
+ : *
+ : * We only need to worry about banding and coalescing for the very first
+ : * band left. After that, we can just group all remaining boxes,
+ : * regardless of how many bands, into one final append to the list.
+ : */
+ :
+ : if ((r1 != r1End) && appendNon1) {
+ : /* Do first nonOverlap1Func call, which may be able to coalesce */
+ : FindBand(r1, r1BandEnd, r1End, r1y1);
+ : curBand = newReg->data->numRects;
+ : miAppendNonO(newReg, r1, r1BandEnd, max(r1y1, ybot), r1->y2);
+ : Coalesce(newReg, prevBand, curBand);
+ : /* Just append the rest of the boxes */
+ : AppendRegions(newReg, r1BandEnd, r1End);
+ :
+ : } else if ((r2 != r2End) && appendNon2) {
+ : /* Do first nonOverlap2Func call, which may be able to coalesce */
+ : FindBand(r2, r2BandEnd, r2End, r2y1);
+ : curBand = newReg->data->numRects;
+ : miAppendNonO(newReg, r2, r2BandEnd, max(r2y1, ybot), r2->y2);
+ : Coalesce(newReg, prevBand, curBand);
+ : /* Append rest of boxes */
+ : AppendRegions(newReg, r2BandEnd, r2End);
+ : }
+ :
+ : if (oldData)
+ : xfree(oldData);
+ :
+ : if (!(numRects = newReg->data->numRects))
+ : {
+ : xfreeData(newReg);
+ : newReg->data = &miEmptyData;
+ : }
+ : else if (numRects == 1)
+ : {
+ : newReg->extents = *REGION_BOXPTR(newReg);
+ : xfreeData(newReg);
+ : newReg->data = (RegDataPtr)NULL;
+ : }
+ : else
+ : {
+ : DOWNSIZE(newReg, numRects);
+ : }
+ :
+ : return TRUE;
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miSetExtents --
+ : * Reset the extents of a region to what they should be. Called by
+ : * miSubtract and miIntersect as they can't figure it out along the
+ : * way or do so easily, as miUnion can.
+ : *
+ : * Results:
+ : * None.
+ : *
+ : * Side Effects:
+ : * The region's 'extents' structure is overwritten.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :miSetExtents (RegionPtr pReg)
+ :{
+ : BoxPtr pBox, pBoxEnd;
+ :
+ : if (!pReg->data)
+ : return;
+ : if (!pReg->data->size)
+ : {
+ : pReg->extents.x2 = pReg->extents.x1;
+ : pReg->extents.y2 = pReg->extents.y1;
+ : return;
+ : }
+ :
+ : pBox = REGION_BOXPTR(pReg);
+ : pBoxEnd = REGION_END(pReg);
+ :
+ : /*
+ : * Since pBox is the first rectangle in the region, it must have the
+ : * smallest y1 and since pBoxEnd is the last rectangle in the region,
+ : * it must have the largest y2, because of banding. Initialize x1 and
+ : * x2 from pBox and pBoxEnd, resp., as good things to initialize them
+ : * to...
+ : */
+ : pReg->extents.x1 = pBox->x1;
+ : pReg->extents.y1 = pBox->y1;
+ : pReg->extents.x2 = pBoxEnd->x2;
+ : pReg->extents.y2 = pBoxEnd->y2;
+ :
+ : assert(pReg->extents.y1 < pReg->extents.y2);
+ : while (pBox <= pBoxEnd) {
+ : if (pBox->x1 < pReg->extents.x1)
+ : pReg->extents.x1 = pBox->x1;
+ : if (pBox->x2 > pReg->extents.x2)
+ : pReg->extents.x2 = pBox->x2;
+ : pBox++;
+ : };
+ :
+ : assert(pReg->extents.x1 < pReg->extents.x2);
+ :}
+ :
+ :/*======================================================================
+ : * Region Intersection
+ : *====================================================================*/
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miIntersectO --
+ : * Handle an overlapping band for miIntersect.
+ : *
+ : * Results:
+ : * TRUE if successful.
+ : *
+ : * Side Effects:
+ : * Rectangles may be added to the region.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :/*ARGSUSED*/
+ :_X_EXPORT Bool
+ :miIntersect(newReg, reg1, reg2)
+ : RegionPtr newReg; /* destination Region */
+ : RegionPtr reg1;
+ : RegionPtr reg2; /* source regions */
+ 1 0.0011 :{ /* miIntersect total: 6 0.0065 */
+ 2 0.0022 : return pixman_region_intersect (newReg, reg1, reg2);
+ 3 0.0033 :}
+ :
+ :#define MERGERECT(r) \
+ :{ \
+ : if (r->x1 <= x2) { \
+ : /* Merge with current rectangle */ \
+ : if (r->x1 < x2) *pOverlap = TRUE; \
+ : if (x2 < r->x2) x2 = r->x2; \
+ : } else { \
+ : /* Add current rectangle, start new one */ \
+ : NEWRECT(pReg, pNextRect, x1, y1, x2, y2); \
+ : x1 = r->x1; \
+ : x2 = r->x2; \
+ : } \
+ : r++; \
+ :}
+ :
+ :/*======================================================================
+ : * Region Union
+ : *====================================================================*/
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miUnionO --
+ : * Handle an overlapping band for the union operation. Picks the
+ : * left-most rectangle each time and merges it into the region.
+ : *
+ : * Results:
+ : * TRUE if successful.
+ : *
+ : * Side Effects:
+ : * pReg is overwritten.
+ : * pOverlap is set to TRUE if any boxes overlap.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static Bool
+ :miUnionO (
+ : RegionPtr pReg,
+ : BoxPtr r1,
+ : BoxPtr r1End,
+ : BoxPtr r2,
+ : BoxPtr r2End,
+ : short y1,
+ : short y2,
+ : Bool *pOverlap)
+ :{
+ : BoxPtr pNextRect;
+ : int x1; /* left and right side of current union */
+ : int x2;
+ :
+ : assert (y1 < y2);
+ : assert(r1 != r1End && r2 != r2End);
+ :
+ : pNextRect = REGION_TOP(pReg);
+ :
+ : /* Start off current rectangle */
+ : if (r1->x1 < r2->x1)
+ : {
+ : x1 = r1->x1;
+ : x2 = r1->x2;
+ : r1++;
+ : }
+ : else
+ : {
+ : x1 = r2->x1;
+ : x2 = r2->x2;
+ : r2++;
+ : }
+ : while (r1 != r1End && r2 != r2End)
+ : {
+ : if (r1->x1 < r2->x1) MERGERECT(r1) else MERGERECT(r2);
+ : }
+ :
+ : /* Finish off whoever (if any) is left */
+ : if (r1 != r1End)
+ : {
+ : do
+ : {
+ : MERGERECT(r1);
+ : } while (r1 != r1End);
+ : }
+ : else if (r2 != r2End)
+ : {
+ : do
+ : {
+ : MERGERECT(r2);
+ : } while (r2 != r2End);
+ : }
+ :
+ : /* Add current rectangle */
+ : NEWRECT(pReg, pNextRect, x1, y1, x2, y2);
+ :
+ : return TRUE;
+ :}
+ :
+ :_X_EXPORT Bool
+ :miUnion(newReg, reg1, reg2)
+ : RegionPtr newReg; /* destination Region */
+ : RegionPtr reg1;
+ : RegionPtr reg2; /* source regions */
+ 14 0.0153 :{ /* miUnion total: 27 0.0294 */
+ 2 0.0022 : return pixman_region_union (newReg, reg1, reg2);
+ 11 0.0120 :}
+ :
+ :/*======================================================================
+ : * Batch Rectangle Union
+ : *====================================================================*/
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miRegionAppend --
+ : *
+ : * "Append" the rgn rectangles onto the end of dstrgn, maintaining
+ : * knowledge of YX-banding when it's easy. Otherwise, dstrgn just
+ : * becomes a non-y-x-banded random collection of rectangles, and not
+ : * yet a true region. After a sequence of appends, the caller must
+ : * call miRegionValidate to ensure that a valid region is constructed.
+ : *
+ : * Results:
+ : * TRUE if successful.
+ : *
+ : * Side Effects:
+ : * dstrgn is modified if rgn has rectangles.
+ : *
+ : */
+ :_X_EXPORT Bool
+ :miRegionAppend(dstrgn, rgn)
+ : RegionPtr dstrgn;
+ : RegionPtr rgn;
+ :{
+ : int numRects, dnumRects, size;
+ : BoxPtr new, old;
+ : Bool prepend;
+ :
+ : if (REGION_NAR(rgn))
+ : return miRegionBreak (dstrgn);
+ :
+ : if (!rgn->data && (dstrgn->data == &miEmptyData))
+ : {
+ : dstrgn->extents = rgn->extents;
+ : dstrgn->data = (RegDataPtr)NULL;
+ : return TRUE;
+ : }
+ :
+ : numRects = REGION_NUM_RECTS(rgn);
+ : if (!numRects)
+ : return TRUE;
+ : prepend = FALSE;
+ : size = numRects;
+ : dnumRects = REGION_NUM_RECTS(dstrgn);
+ : if (!dnumRects && (size < 200))
+ : size = 200; /* XXX pick numbers out of a hat */
+ : RECTALLOC(dstrgn, size);
+ : old = REGION_RECTS(rgn);
+ : if (!dnumRects)
+ : dstrgn->extents = rgn->extents;
+ : else if (dstrgn->extents.x2 > dstrgn->extents.x1)
+ : {
+ : BoxPtr first, last;
+ :
+ : first = old;
+ : last = REGION_BOXPTR(dstrgn) + (dnumRects - 1);
+ : if ((first->y1 > last->y2) ||
+ : ((first->y1 == last->y1) && (first->y2 == last->y2) &&
+ : (first->x1 > last->x2)))
+ : {
+ : if (rgn->extents.x1 < dstrgn->extents.x1)
+ : dstrgn->extents.x1 = rgn->extents.x1;
+ : if (rgn->extents.x2 > dstrgn->extents.x2)
+ : dstrgn->extents.x2 = rgn->extents.x2;
+ : dstrgn->extents.y2 = rgn->extents.y2;
+ : }
+ : else
+ : {
+ : first = REGION_BOXPTR(dstrgn);
+ : last = old + (numRects - 1);
+ : if ((first->y1 > last->y2) ||
+ : ((first->y1 == last->y1) && (first->y2 == last->y2) &&
+ : (first->x1 > last->x2)))
+ : {
+ : prepend = TRUE;
+ : if (rgn->extents.x1 < dstrgn->extents.x1)
+ : dstrgn->extents.x1 = rgn->extents.x1;
+ : if (rgn->extents.x2 > dstrgn->extents.x2)
+ : dstrgn->extents.x2 = rgn->extents.x2;
+ : dstrgn->extents.y1 = rgn->extents.y1;
+ : }
+ : else
+ : dstrgn->extents.x2 = dstrgn->extents.x1;
+ : }
+ : }
+ : if (prepend)
+ : {
+ : new = REGION_BOX(dstrgn, numRects);
+ : if (dnumRects == 1)
+ : *new = *REGION_BOXPTR(dstrgn);
+ : else
+ : memmove((char *)new,(char *)REGION_BOXPTR(dstrgn),
+ : dnumRects * sizeof(BoxRec));
+ : new = REGION_BOXPTR(dstrgn);
+ : }
+ : else
+ : new = REGION_BOXPTR(dstrgn) + dnumRects;
+ : if (numRects == 1)
+ : *new = *old;
+ : else
+ : memmove((char *)new, (char *)old, numRects * sizeof(BoxRec));
+ : dstrgn->data->numRects += numRects;
+ : return TRUE;
+ :}
+ :
+ :
+ :#define ExchangeRects(a, b) \
+ :{ \
+ : BoxRec t; \
+ : t = rects[a]; \
+ : rects[a] = rects[b]; \
+ : rects[b] = t; \
+ :}
+ :
+ :static void
+ :QuickSortRects(
+ : BoxRec rects[],
+ : int numRects)
+ :{ /* QuickSortRects total: 1 0.0011 */
+ : int y1;
+ : int x1;
+ : int i, j;
+ : BoxPtr r;
+ :
+ : /* Always called with numRects > 1 */
+ :
+ : do
+ : {
+ : if (numRects == 2)
+ : {
+ 1 0.0011 : if (rects[0].y1 > rects[1].y1 ||
+ : (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1))
+ : ExchangeRects(0, 1);
+ : return;
+ : }
+ :
+ : /* Choose partition element, stick in location 0 */
+ : ExchangeRects(0, numRects >> 1);
+ : y1 = rects[0].y1;
+ : x1 = rects[0].x1;
+ :
+ : /* Partition array */
+ : i = 0;
+ : j = numRects;
+ : do
+ : {
+ : r = &(rects[i]);
+ : do
+ : {
+ : r++;
+ : i++;
+ : } while (i != numRects &&
+ : (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1)));
+ : r = &(rects[j]);
+ : do
+ : {
+ : r--;
+ : j--;
+ : } while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1));
+ : if (i < j)
+ : ExchangeRects(i, j);
+ : } while (i < j);
+ :
+ : /* Move partition element back to middle */
+ : ExchangeRects(0, j);
+ :
+ : /* Recurse */
+ : if (numRects-j-1 > 1)
+ : QuickSortRects(&rects[j+1], numRects-j-1);
+ : numRects = j;
+ : } while (numRects > 1);
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miRegionValidate --
+ : *
+ : * Take a ``region'' which is a non-y-x-banded random collection of
+ : * rectangles, and compute a nice region which is the union of all the
+ : * rectangles.
+ : *
+ : * Results:
+ : * TRUE if successful.
+ : *
+ : * Side Effects:
+ : * The passed-in ``region'' may be modified.
+ : * pOverlap set to TRUE if any retangles overlapped, else FALSE;
+ : *
+ : * Strategy:
+ : * Step 1. Sort the rectangles into ascending order with primary key y1
+ : * and secondary key x1.
+ : *
+ : * Step 2. Split the rectangles into the minimum number of proper y-x
+ : * banded regions. This may require horizontally merging
+ : * rectangles, and vertically coalescing bands. With any luck,
+ : * this step in an identity tranformation (ala the Box widget),
+ : * or a coalescing into 1 box (ala Menus).
+ : *
+ : * Step 3. Merge the separate regions down to a single region by calling
+ : * miUnion. Maximize the work each miUnion call does by using
+ : * a binary merge.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :
+ :_X_EXPORT Bool
+ :miRegionValidate(badreg, pOverlap)
+ : RegionPtr badreg;
+ : Bool *pOverlap;
+ 1 0.0011 :{ /* miRegionValidate total: 7 0.0076 */
+ : /* Descriptor for regions under construction in Step 2. */
+ : typedef struct {
+ : RegionRec reg;
+ : int prevBand;
+ : int curBand;
+ : } RegionInfo;
+ :
+ : int numRects; /* Original numRects for badreg */
+ : RegionInfo *ri; /* Array of current regions */
+ : int numRI; /* Number of entries used in ri */
+ : int sizeRI; /* Number of entries available in ri */
+ : int i; /* Index into rects */
+ : int j; /* Index into ri */
+ : RegionInfo *rit; /* &ri[j] */
+ : RegionPtr reg; /* ri[j].reg */
+ : BoxPtr box; /* Current box in rects */
+ : BoxPtr riBox; /* Last box in ri[j].reg */
+ : RegionPtr hreg; /* ri[j_half].reg */
+ : Bool ret = TRUE;
+ :
+ : *pOverlap = FALSE;
+ : if (!badreg->data)
+ : {
+ : good(badreg);
+ : return TRUE;
+ : }
+ : numRects = badreg->data->numRects;
+ : if (!numRects)
+ : {
+ : if (REGION_NAR(badreg))
+ : return FALSE;
+ : good(badreg);
+ : return TRUE;
+ : }
+ 1 0.0011 : if (badreg->extents.x1 < badreg->extents.x2)
+ : {
+ : if ((numRects) == 1)
+ : {
+ : xfreeData(badreg);
+ : badreg->data = (RegDataPtr) NULL;
+ : }
+ : else
+ : {
+ : DOWNSIZE(badreg, numRects);
+ : }
+ : good(badreg);
+ : return TRUE;
+ : }
+ :
+ : /* Step 1: Sort the rects array into ascending (y1, x1) order */
+ : QuickSortRects(REGION_BOXPTR(badreg), numRects);
+ :
+ : /* Step 2: Scatter the sorted array into the minimum number of regions */
+ :
+ : /* Set up the first region to be the first rectangle in badreg */
+ : /* Note that step 2 code will never overflow the ri[0].reg rects array */
+ : ri = (RegionInfo *) xalloc(4 * sizeof(RegionInfo));
+ : if (!ri)
+ : return miRegionBreak (badreg);
+ : sizeRI = 4;
+ : numRI = 1;
+ : ri[0].prevBand = 0;
+ : ri[0].curBand = 0;
+ : ri[0].reg = *badreg;
+ : box = REGION_BOXPTR(&ri[0].reg);
+ : ri[0].reg.extents = *box;
+ : ri[0].reg.data->numRects = 1;
+ :
+ : /* Now scatter rectangles into the minimum set of valid regions. If the
+ : next rectangle to be added to a region would force an existing rectangle
+ : in the region to be split up in order to maintain y-x banding, just
+ : forget it. Try the next region. If it doesn't fit cleanly into any
+ : region, make a new one. */
+ :
+ : for (i = numRects; --i > 0;)
+ : {
+ : box++;
+ : /* Look for a region to append box to */
+ : for (j = numRI, rit = ri; --j >= 0; rit++)
+ : {
+ : reg = &rit->reg;
+ : riBox = REGION_END(reg);
+ :
+ : if (box->y1 == riBox->y1 && box->y2 == riBox->y2)
+ : {
+ : /* box is in same band as riBox. Merge or append it */
+ : if (box->x1 <= riBox->x2)
+ : {
+ : /* Merge it with riBox */
+ : if (box->x1 < riBox->x2) *pOverlap = TRUE;
+ : if (box->x2 > riBox->x2) riBox->x2 = box->x2;
+ : }
+ : else
+ : {
+ : RECTALLOC_BAIL(reg, 1, bail);
+ : *REGION_TOP(reg) = *box;
+ : reg->data->numRects++;
+ : }
+ : goto NextRect; /* So sue me */
+ : }
+ 1 0.0011 : else if (box->y1 >= riBox->y2)
+ : {
+ : /* Put box into new band */
+ : if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
+ : if (reg->extents.x1 > box->x1) reg->extents.x1 = box->x1;
+ : Coalesce(reg, rit->prevBand, rit->curBand);
+ : rit->curBand = reg->data->numRects;
+ : RECTALLOC_BAIL(reg, 1, bail);
+ : *REGION_TOP(reg) = *box;
+ : reg->data->numRects++;
+ : goto NextRect;
+ : }
+ : /* Well, this region was inappropriate. Try the next one. */
+ : } /* for j */
+ :
+ : /* Uh-oh. No regions were appropriate. Create a new one. */
+ 1 0.0011 : if (sizeRI == numRI)
+ : {
+ : /* Oops, allocate space for new region information */
+ : sizeRI <<= 1;
+ : rit = (RegionInfo *) xrealloc(ri, sizeRI * sizeof(RegionInfo));
+ : if (!rit)
+ : goto bail;
+ : ri = rit;
+ : rit = &ri[numRI];
+ : }
+ : numRI++;
+ : rit->prevBand = 0;
+ : rit->curBand = 0;
+ : rit->reg.extents = *box;
+ : rit->reg.data = (RegDataPtr)NULL;
+ : if (!miRectAlloc(&rit->reg, (i+numRI) / numRI)) /* MUST force allocation */
+ : goto bail;
+ :NextRect: ;
+ : } /* for i */
+ :
+ : /* Make a final pass over each region in order to Coalesce and set
+ : extents.x2 and extents.y2 */
+ :
+ : for (j = numRI, rit = ri; --j >= 0; rit++)
+ : {
+ : reg = &rit->reg;
+ : riBox = REGION_END(reg);
+ : reg->extents.y2 = riBox->y2;
+ : if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
+ : Coalesce(reg, rit->prevBand, rit->curBand);
+ : if (reg->data->numRects == 1) /* keep unions happy below */
+ : {
+ : xfreeData(reg);
+ : reg->data = (RegDataPtr)NULL;
+ : }
+ : }
+ :
+ : /* Step 3: Union all regions into a single region */
+ 1 0.0011 : while (numRI > 1)
+ : {
+ : int half = numRI/2;
+ : for (j = numRI & 1; j < (half + (numRI & 1)); j++)
+ : {
+ : reg = &ri[j].reg;
+ : hreg = &ri[j+half].reg;
+ : if (!miRegionOp(reg, reg, hreg, miUnionO, TRUE, TRUE, pOverlap))
+ : ret = FALSE;
+ : if (hreg->extents.x1 < reg->extents.x1)
+ : reg->extents.x1 = hreg->extents.x1;
+ : if (hreg->extents.y1 < reg->extents.y1)
+ : reg->extents.y1 = hreg->extents.y1;
+ : if (hreg->extents.x2 > reg->extents.x2)
+ : reg->extents.x2 = hreg->extents.x2;
+ 1 0.0011 : if (hreg->extents.y2 > reg->extents.y2)
+ : reg->extents.y2 = hreg->extents.y2;
+ : xfreeData(hreg);
+ : }
+ : numRI -= half;
+ : }
+ : *badreg = ri[0].reg;
+ : xfree(ri);
+ : good(badreg);
+ : return ret;
+ :bail:
+ : for (i = 0; i < numRI; i++)
+ : xfreeData(&ri[i].reg);
+ : xfree (ri);
+ : return miRegionBreak (badreg);
+ :}
+ :
+ :_X_EXPORT RegionPtr
+ :miRectsToRegion(nrects, prect, ctype)
+ : int nrects;
+ : xRectangle *prect;
+ : int ctype;
+ 1 0.0011 :{ /* miRectsToRegion total: 8 0.0087 */
+ :
+ : RegionPtr pRgn;
+ : RegDataPtr pData;
+ : BoxPtr pBox;
+ : int i;
+ : int x1, y1, x2, y2;
+ :
+ : pRgn = miRegionCreate(NullBox, 0);
+ : if (REGION_NAR (pRgn))
+ : return pRgn;
+ 4 0.0044 : if (!nrects)
+ : return pRgn;
+ : if (nrects == 1)
+ : {
+ : x1 = prect->x;
+ : y1 = prect->y;
+ 1 0.0011 : if ((x2 = x1 + (int) prect->width) > MAXSHORT)
+ : x2 = MAXSHORT;
+ : if ((y2 = y1 + (int) prect->height) > MAXSHORT)
+ : y2 = MAXSHORT;
+ : if (x1 != x2 && y1 != y2)
+ : {
+ : pRgn->extents.x1 = x1;
+ : pRgn->extents.y1 = y1;
+ : pRgn->extents.x2 = x2;
+ : pRgn->extents.y2 = y2;
+ : pRgn->data = (RegDataPtr)NULL;
+ : }
+ : return pRgn;
+ : }
+ : pData = xallocData(nrects);
+ : if (!pData)
+ : {
+ : miRegionBreak (pRgn);
+ : return pRgn;
+ : }
+ : pBox = (BoxPtr) (pData + 1);
+ : for (i = nrects; --i >= 0; prect++)
+ : {
+ : x1 = prect->x;
+ : y1 = prect->y;
+ : if ((x2 = x1 + (int) prect->width) > MAXSHORT)
+ : x2 = MAXSHORT;
+ : if ((y2 = y1 + (int) prect->height) > MAXSHORT)
+ : y2 = MAXSHORT;
+ : if (x1 != x2 && y1 != y2)
+ : {
+ : pBox->x1 = x1;
+ : pBox->y1 = y1;
+ : pBox->x2 = x2;
+ : pBox->y2 = y2;
+ : pBox++;
+ : }
+ : }
+ 1 0.0011 : if (pBox != (BoxPtr) (pData + 1))
+ : {
+ : pData->size = nrects;
+ : pData->numRects = pBox - (BoxPtr) (pData + 1);
+ : pRgn->data = pData;
+ : if (ctype != CT_YXBANDED)
+ : {
+ : Bool overlap; /* result ignored */
+ : pRgn->extents.x1 = pRgn->extents.x2 = 0;
+ : miRegionValidate(pRgn, &overlap);
+ : }
+ : else
+ : miSetExtents(pRgn);
+ : good(pRgn);
+ : }
+ : else
+ : {
+ : xfree (pData);
+ : }
+ : return pRgn;
+ 1 0.0011 :}
+ :
+ :/*======================================================================
+ : * Region Subtraction
+ : *====================================================================*/
+ :
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miSubtractO --
+ : * Overlapping band subtraction. x1 is the left-most point not yet
+ : * checked.
+ : *
+ : * Results:
+ : * TRUE if successful.
+ : *
+ : * Side Effects:
+ : * pReg may have rectangles added to it.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :/*ARGSUSED*/
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miSubtract --
+ : * Subtract regS from regM and leave the result in regD.
+ : * S stands for subtrahend, M for minuend and D for difference.
+ : *
+ : * Results:
+ : * TRUE if successful.
+ : *
+ : * Side Effects:
+ : * regD is overwritten.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :_X_EXPORT Bool
+ :miSubtract(regD, regM, regS)
+ : RegionPtr regD;
+ : RegionPtr regM;
+ : RegionPtr regS;
+ :{
+ : return pixman_region_subtract (regD, regM, regS);
+ :}
+ :
+ :/*======================================================================
+ : * Region Inversion
+ : *====================================================================*/
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miInverse --
+ : * Take a region and a box and return a region that is everything
+ : * in the box but not in the region. The careful reader will note
+ : * that this is the same as subtracting the region from the box...
+ : *
+ : * Results:
+ : * TRUE.
+ : *
+ : * Side Effects:
+ : * newReg is overwritten.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :_X_EXPORT Bool
+ :miInverse(newReg, reg1, invRect)
+ : RegionPtr newReg; /* Destination region */
+ : RegionPtr reg1; /* Region to invert */
+ : BoxPtr invRect; /* Bounding box for inversion */
+ :{
+ : return pixman_region_inverse (newReg, reg1, invRect);
+ :}
+ :_X_EXPORT int
+ :miRectIn(region, prect)
+ : RegionPtr region;
+ : BoxPtr prect;
+ :{
+ : return pixman_region_contains_rectangle (region, prect);
+ :}
+ :
+ :/* TranslateRegion(pReg, x, y)
+ : translates in place
+ :*/
+ :
+ :_X_EXPORT void
+ :miTranslateRegion(pReg, x, y)
+ : RegionPtr pReg;
+ : int x;
+ : int y;
+ 2 0.0022 :{ /* miTranslateRegion total: 2 0.0022 */
+ : pixman_region_translate (pReg, x, y);
+ :}
+ :
+ :_X_EXPORT void
+ :miRegionReset(pReg, pBox)
+ : RegionPtr pReg;
+ : BoxPtr pBox;
+ :{
+ : pixman_region_reset (pReg, pBox);
+ :}
+ :
+ :_X_EXPORT Bool
+ :miPointInRegion(pReg, x, y, box)
+ : RegionPtr pReg;
+ : int x, y;
+ : BoxPtr box; /* "return" value */
+ :{
+ : return pixman_region_contains_point (pReg, x, y, box);
+ :}
+ :
+ :_X_EXPORT Bool
+ :miRegionNotEmpty(pReg)
+ : RegionPtr pReg;
+ :{
+ : return pixman_region_not_empty (pReg);
+ :}
+ :
+ :Bool
+ :miRegionBroken(RegionPtr pReg)
+ :{
+ : good(pReg);
+ : return (REGION_NAR(pReg));
+ :}
+ :
+ :_X_EXPORT void
+ :miRegionEmpty(pReg)
+ : RegionPtr pReg;
+ :{
+ : good(pReg);
+ : xfreeData(pReg);
+ : pReg->extents.x2 = pReg->extents.x1;
+ : pReg->extents.y2 = pReg->extents.y1;
+ : pReg->data = &miEmptyData;
+ :}
+ :
+ :_X_EXPORT BoxPtr
+ :miRegionExtents(pReg)
+ : RegionPtr pReg;
+ :{
+ : good(pReg);
+ : return(&pReg->extents);
+ :}
+ :
+ :#define ExchangeSpans(a, b) \
+ :{ \
+ : DDXPointRec tpt; \
+ : int tw; \
+ : \
+ : tpt = spans[a]; spans[a] = spans[b]; spans[b] = tpt; \
+ : tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \
+ :}
+ :
+ :/* ||| I should apply the merge sort code to rectangle sorting above, and see
+ : if mapping time can be improved. But right now I've been at work 12 hours,
+ : so forget it.
+ :*/
+ :
+ :static void QuickSortSpans(
+ : DDXPointRec spans[],
+ : int widths[],
+ : int numSpans)
+ :{
+ : int y;
+ : int i, j, m;
+ : DDXPointPtr r;
+ :
+ : /* Always called with numSpans > 1 */
+ : /* Sorts only by y, doesn't bother to sort by x */
+ :
+ : do
+ : {
+ : if (numSpans < 9)
+ : {
+ : /* Do insertion sort */
+ : int yprev;
+ :
+ : yprev = spans[0].y;
+ : i = 1;
+ : do
+ : { /* while i != numSpans */
+ : y = spans[i].y;
+ : if (yprev > y)
+ : {
+ : /* spans[i] is out of order. Move into proper location. */
+ : DDXPointRec tpt;
+ : int tw, k;
+ :
+ : for (j = 0; y >= spans[j].y; j++) {}
+ : tpt = spans[i];
+ : tw = widths[i];
+ : for (k = i; k != j; k--)
+ : {
+ : spans[k] = spans[k-1];
+ : widths[k] = widths[k-1];
+ : }
+ : spans[j] = tpt;
+ : widths[j] = tw;
+ : y = spans[i].y;
+ : } /* if out of order */
+ : yprev = y;
+ : i++;
+ : } while (i != numSpans);
+ : return;
+ : }
+ :
+ : /* Choose partition element, stick in location 0 */
+ : m = numSpans / 2;
+ : if (spans[m].y > spans[0].y) ExchangeSpans(m, 0);
+ : if (spans[m].y > spans[numSpans-1].y) ExchangeSpans(m, numSpans-1);
+ : if (spans[m].y > spans[0].y) ExchangeSpans(m, 0);
+ : y = spans[0].y;
+ :
+ : /* Partition array */
+ : i = 0;
+ : j = numSpans;
+ : do
+ : {
+ : r = &(spans[i]);
+ : do
+ : {
+ : r++;
+ : i++;
+ : } while (i != numSpans && r->y < y);
+ : r = &(spans[j]);
+ : do
+ : {
+ : r--;
+ : j--;
+ : } while (y < r->y);
+ : if (i < j)
+ : ExchangeSpans(i, j);
+ : } while (i < j);
+ :
+ : /* Move partition element back to middle */
+ : ExchangeSpans(0, j);
+ :
+ : /* Recurse */
+ : if (numSpans-j-1 > 1)
+ : QuickSortSpans(&spans[j+1], &widths[j+1], numSpans-j-1);
+ : numSpans = j;
+ : } while (numSpans > 1);
+ :}
+ :
+ :#define NextBand() \
+ :{ \
+ : clipy1 = pboxBandStart->y1; \
+ : clipy2 = pboxBandStart->y2; \
+ : pboxBandEnd = pboxBandStart + 1; \
+ : while (pboxBandEnd != pboxLast && pboxBandEnd->y1 == clipy1) { \
+ : pboxBandEnd++; \
+ : } \
+ : for (; ppt != pptLast && ppt->y < clipy1; ppt++, pwidth++) {} \
+ :}
+ :
+ :/*
+ : Clip a list of scanlines to a region. The caller has allocated the
+ : space. FSorted is non-zero if the scanline origins are in ascending
+ : order.
+ : returns the number of new, clipped scanlines.
+ :*/
+ :
+ :_X_EXPORT int
+ :miClipSpans(
+ : RegionPtr prgnDst,
+ : DDXPointPtr ppt,
+ : int *pwidth,
+ : int nspans,
+ : DDXPointPtr pptNew,
+ : int *pwidthNew,
+ : int fSorted)
+ :{
+ : DDXPointPtr pptLast;
+ : int *pwidthNewStart; /* the vengeance of Xerox! */
+ : int y, x1, x2;
+ : int numRects;
+ :
+ : good(prgnDst);
+ : pptLast = ppt + nspans;
+ : pwidthNewStart = pwidthNew;
+ :
+ : if (!prgnDst->data)
+ : {
+ : /* Do special fast code with clip boundaries in registers(?) */
+ : /* It doesn't pay much to make use of fSorted in this case,
+ : so we lump everything together. */
+ :
+ : int clipx1, clipx2, clipy1, clipy2;
+ :
+ : clipx1 = prgnDst->extents.x1;
+ : clipy1 = prgnDst->extents.y1;
+ : clipx2 = prgnDst->extents.x2;
+ : clipy2 = prgnDst->extents.y2;
+ :
+ : for (; ppt != pptLast; ppt++, pwidth++)
+ : {
+ : y = ppt->y;
+ : x1 = ppt->x;
+ : if (clipy1 <= y && y < clipy2)
+ : {
+ : x2 = x1 + *pwidth;
+ : if (x1 < clipx1) x1 = clipx1;
+ : if (x2 > clipx2) x2 = clipx2;
+ : if (x1 < x2)
+ : {
+ : /* part of span in clip rectangle */
+ : pptNew->x = x1;
+ : pptNew->y = y;
+ : *pwidthNew = x2 - x1;
+ : pptNew++;
+ : pwidthNew++;
+ : }
+ : }
+ : } /* end for */
+ :
+ : }
+ : else if ((numRects = prgnDst->data->numRects))
+ : {
+ : /* Have to clip against many boxes */
+ : BoxPtr pboxBandStart, pboxBandEnd;
+ : BoxPtr pbox;
+ : BoxPtr pboxLast;
+ : int clipy1, clipy2;
+ :
+ : /* In this case, taking advantage of sorted spans gains more than
+ : the sorting costs. */
+ : if ((! fSorted) && (nspans > 1))
+ : QuickSortSpans(ppt, pwidth, nspans);
+ :
+ : pboxBandStart = REGION_BOXPTR(prgnDst);
+ : pboxLast = pboxBandStart + numRects;
+ :
+ : NextBand();
+ :
+ : for (; ppt != pptLast; )
+ : {
+ : y = ppt->y;
+ : if (y < clipy2)
+ : {
+ : /* span is in the current band */
+ : pbox = pboxBandStart;
+ : x1 = ppt->x;
+ : x2 = x1 + *pwidth;
+ : do
+ : { /* For each box in band */
+ : int newx1, newx2;
+ :
+ : newx1 = x1;
+ : newx2 = x2;
+ : if (newx1 < pbox->x1) newx1 = pbox->x1;
+ : if (newx2 > pbox->x2) newx2 = pbox->x2;
+ : if (newx1 < newx2)
+ : {
+ : /* Part of span in clip rectangle */
+ : pptNew->x = newx1;
+ : pptNew->y = y;
+ : *pwidthNew = newx2 - newx1;
+ : pptNew++;
+ : pwidthNew++;
+ : }
+ : pbox++;
+ : } while (pbox != pboxBandEnd);
+ : ppt++;
+ : pwidth++;
+ : }
+ : else
+ : {
+ : /* Move to next band, adjust ppt as needed */
+ : pboxBandStart = pboxBandEnd;
+ : if (pboxBandStart == pboxLast)
+ : break; /* We're completely done */
+ : NextBand();
+ : }
+ : }
+ : }
+ : return (pwidthNew - pwidthNewStart);
+ :}
+ :
+ :/* find the band in a region with the most rectangles */
+ :_X_EXPORT int
+ :miFindMaxBand(prgn)
+ : RegionPtr prgn;
+ :{
+ : int nbox;
+ : BoxPtr pbox;
+ : int nThisBand;
+ : int nMaxBand = 0;
+ : short yThisBand;
+ :
+ : good(prgn);
+ : nbox = REGION_NUM_RECTS(prgn);
+ : pbox = REGION_RECTS(prgn);
+ :
+ : while(nbox > 0)
+ : {
+ : yThisBand = pbox->y1;
+ : nThisBand = 0;
+ : while((nbox > 0) && (pbox->y1 == yThisBand))
+ : {
+ : nbox--;
+ : pbox++;
+ : nThisBand++;
+ : }
+ : if (nThisBand > nMaxBand)
+ : nMaxBand = nThisBand;
+ : }
+ : return (nMaxBand);
+ :}
+/*
+ * Total samples for file : "malloc.c"
+ *
+ * 65 0.0708
+ */
+
+<credited to line zero> 65 0.0708 :
+ /* malloc_consolidate total: 65 0.0708 */
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/os/io.c"
+ *
+ * 60 0.0654
+ */
+
+
+ :/***********************************************************
+ :
+ :Copyright 1987, 1989, 1998 The Open Group
+ :
+ :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.
+ :
+ :The above copyright notice and this permission notice shall be included in
+ :all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ :IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ :FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ :OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ :AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ :CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of The Open Group shall not be
+ :used in advertising or otherwise to promote the sale, use or other dealings
+ :in this Software without prior written authorization from The Open Group.
+ :
+ :
+ :Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
+ :
+ : All Rights Reserved
+ :
+ :Permission to use, copy, modify, and distribute this software and its
+ :documentation for any purpose and without fee is hereby granted,
+ :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 Digital not be
+ :used in advertising or publicity pertaining to distribution of the
+ :software without specific, written prior permission.
+ :
+ :DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ :ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ :DIGITAL 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.
+ :
+ :
+ :******************************************************************/
+ :/*****************************************************************
+ : * i/o functions
+ : *
+ : * WriteToClient, ReadRequestFromClient
+ : * InsertFakeRequest, ResetCurrentRequest
+ : *
+ : *****************************************************************/
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#if 0
+ :#define DEBUG_COMMUNICATION
+ :#endif
+ :#ifdef WIN32
+ :#include <X11/Xwinsock.h>
+ :#endif
+ :#include <stdio.h>
+ :#define XSERV_t
+ :#define TRANS_SERVER
+ :#define TRANS_REOPEN
+ :#include <X11/Xtrans/Xtrans.h>
+ :#include <X11/Xmd.h>
+ :#include <errno.h>
+ :#if !defined(WIN32)
+ :#ifndef Lynx
+ :#include <sys/uio.h>
+ :#else
+ :#include <uio.h>
+ :#endif
+ :#endif
+ :#include <X11/X.h>
+ :#define NEED_REPLIES
+ :#include <X11/Xproto.h>
+ :#include "os.h"
+ :#include "osdep.h"
+ :#include <X11/Xpoll.h>
+ :#include "opaque.h"
+ :#include "dixstruct.h"
+ :#include "misc.h"
+ :
+ :_X_EXPORT CallbackListPtr ReplyCallback;
+ :_X_EXPORT CallbackListPtr FlushCallback;
+ :
+ :static ConnectionInputPtr AllocateInputBuffer(void);
+ :static ConnectionOutputPtr AllocateOutputBuffer(void);
+ :static xReqPtr PeekNextRequest(xReqPtr req, ClientPtr client, Bool readmore);
+ :static void SkipRequests(xReqPtr req, ClientPtr client, int numskipped);
+ :
+ :/* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
+ : * systems are broken and return EWOULDBLOCK when they should return EAGAIN
+ : */
+ :#ifndef WIN32
+ :#if defined(EAGAIN) && defined(EWOULDBLOCK)
+ :#define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK)
+ :#else
+ :#ifdef EAGAIN
+ :#define ETEST(err) (err == EAGAIN)
+ :#else
+ :#define ETEST(err) (err == EWOULDBLOCK)
+ :#endif
+ :#endif
+ :#else /* WIN32 The socket errorcodes differ from the normal errors*/
+ :#define ETEST(err) (err == EAGAIN || err == WSAEWOULDBLOCK)
+ :#endif
+ :
+ :static Bool CriticalOutputPending;
+ :static int timesThisConnection = 0;
+ :static ConnectionInputPtr FreeInputs = (ConnectionInputPtr)NULL;
+ :static ConnectionOutputPtr FreeOutputs = (ConnectionOutputPtr)NULL;
+ :static OsCommPtr AvailableInput = (OsCommPtr)NULL;
+ :
+ :#define get_req_len(req,cli) ((cli)->swapped ? \
+ : lswaps((req)->length) : (req)->length)
+ :
+ :#ifdef BIGREQS
+ :#include <X11/extensions/bigreqstr.h>
+ :
+ :#define get_big_req_len(req,cli) ((cli)->swapped ? \
+ : lswapl(((xBigReq *)(req))->length) : \
+ : ((xBigReq *)(req))->length)
+ :#endif
+ :
+ :#define MAX_TIMES_PER 10
+ :
+ :/*
+ : * A lot of the code in this file manipulates a ConnectionInputPtr:
+ : *
+ : * -----------------------------------------------
+ : * |------- bufcnt ------->| | |
+ : * | |- gotnow ->| | |
+ : * | |-------- needed ------>| |
+ : * |-----------+--------- size --------+---------->|
+ : * -----------------------------------------------
+ : * ^ ^
+ : * | |
+ : * buffer bufptr
+ : *
+ : * buffer is a pointer to the start of the buffer.
+ : * bufptr points to the start of the current request.
+ : * bufcnt counts how many bytes are in the buffer.
+ : * size is the size of the buffer in bytes.
+ : *
+ : * In several of the functions, gotnow and needed are local variables
+ : * that do the following:
+ : *
+ : * gotnow is the number of bytes of the request that we're
+ : * trying to read that are currently in the buffer.
+ : * Typically, gotnow = (buffer + bufcnt) - bufptr
+ : *
+ : * needed = the length of the request that we're trying to
+ : * read. Watch out: needed sometimes counts bytes and sometimes
+ : * counts CARD32's.
+ : */
+ :
+ :
+ :/*****************************************************************
+ : * ReadRequestFromClient
+ : * Returns one request in client->requestBuffer. The request
+ : * length will be in client->req_len. Return status is:
+ : *
+ : * > 0 if successful, specifies length in bytes of the request
+ : * = 0 if entire request is not yet available
+ : * < 0 if client should be terminated
+ : *
+ : * The request returned must be contiguous so that it can be
+ : * cast in the dispatcher to the correct request type. Because requests
+ : * are variable length, ReadRequestFromClient() must look at the first 4
+ : * or 8 bytes of a request to determine the length (the request length is
+ : * in the 3rd and 4th bytes of the request unless it is a Big Request
+ : * (see the Big Request Extension), in which case the 3rd and 4th bytes
+ : * are zero and the following 4 bytes are the request length.
+ : *
+ : * Note: in order to make the server scheduler (WaitForSomething())
+ : * "fair", the ClientsWithInput mask is used. This mask tells which
+ : * clients have FULL requests left in their buffers. Clients with
+ : * partial requests require a read. Basically, client buffers
+ : * are drained before select() is called again. But, we can't keep
+ : * reading from a client that is sending buckets of data (or has
+ : * a partial request) because others clients need to be scheduled.
+ : *****************************************************************/
+ :
+ :#define YieldControl() \
+ : { isItTimeToYield = TRUE; \
+ : timesThisConnection = 0; }
+ :#define YieldControlNoInput() \
+ : { YieldControl(); \
+ : FD_CLR(fd, &ClientsWithInput); }
+ :#define YieldControlDeath() \
+ : { timesThisConnection = 0; }
+ :
+ :int
+ :ReadRequestFromClient(ClientPtr client)
+ 2 0.0022 :{ /* ReadRequestFromClient total: 60 0.0654 */
+ 3 0.0033 : OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ : ConnectionInputPtr oci = oc->input;
+ : int fd = oc->fd;
+ : unsigned int gotnow, needed;
+ : int result;
+ : register xReq *request;
+ : Bool need_header;
+ :#ifdef BIGREQS
+ : Bool move_header;
+ :#endif
+ :
+ : /* If an input buffer was empty, either free it if it is too big
+ : * or link it into our list of free input buffers. This means that
+ : * different clients can share the same input buffer (at different
+ : * times). This was done to save memory.
+ : */
+ :
+ : if (AvailableInput)
+ : {
+ : if (AvailableInput != oc)
+ : {
+ : register ConnectionInputPtr aci = AvailableInput->input;
+ : if (aci->size > BUFWATERMARK)
+ : {
+ : xfree(aci->buffer);
+ : xfree(aci);
+ : }
+ : else
+ : {
+ : aci->next = FreeInputs;
+ : FreeInputs = aci;
+ : }
+ : AvailableInput->input = (ConnectionInputPtr)NULL;
+ : }
+ : AvailableInput = (OsCommPtr)NULL;
+ : }
+ :
+ : /* make sure we have an input buffer */
+ :
+ : if (!oci)
+ : {
+ : if ((oci = FreeInputs))
+ : {
+ : FreeInputs = oci->next;
+ : }
+ : else if (!(oci = AllocateInputBuffer()))
+ : {
+ : YieldControlDeath();
+ : return -1;
+ : }
+ : oc->input = oci;
+ : }
+ :
+ : /* advance to start of next request */
+ :
+ 3 0.0033 : oci->bufptr += oci->lenLastReq;
+ :
+ : need_header = FALSE;
+ :#ifdef BIGREQS
+ : move_header = FALSE;
+ :#endif
+ 6 0.0065 : gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
+ 2 0.0022 : if (gotnow < sizeof(xReq))
+ : {
+ : /* We don't have an entire xReq yet. Can't tell how big
+ : * the request will be until we get the whole xReq.
+ : */
+ : needed = sizeof(xReq);
+ : need_header = TRUE;
+ : }
+ : else
+ : {
+ : /* We have a whole xReq. We can tell how big the whole
+ : * request will be unless it is a Big Request.
+ : */
+ : request = (xReq *)oci->bufptr;
+ 2 0.0022 : needed = get_req_len(request, client);
+ :#ifdef BIGREQS
+ 1 0.0011 : if (!needed && client->big_requests)
+ : {
+ : /* It's a Big Request. */
+ : move_header = TRUE;
+ : if (gotnow < sizeof(xBigReq))
+ : {
+ : /* Still need more data to tell just how big. */
+ : needed = sizeof(xBigReq) >> 2; /* needed is in CARD32s now */
+ : need_header = TRUE;
+ : }
+ : else
+ : needed = get_big_req_len(request, client);
+ : }
+ :#endif
+ 1 0.0011 : client->req_len = needed;
+ : needed <<= 2; /* needed is in bytes now */
+ : }
+ : if (gotnow < needed)
+ : {
+ : /* Need to read more data, either so that we can get a
+ : * complete xReq (if need_header is TRUE), a complete
+ : * xBigReq (if move_header is TRUE), or the rest of the
+ : * request (if need_header and move_header are both FALSE).
+ : */
+ :
+ : oci->lenLastReq = 0;
+ 2 0.0022 : if (needed > MAXBUFSIZE)
+ : {
+ : /* request is too big for us to handle */
+ : YieldControlDeath();
+ : return -1;
+ : }
+ : if ((gotnow == 0) ||
+ : ((oci->bufptr - oci->buffer + needed) > oci->size))
+ : {
+ : /* no data, or the request is too big to fit in the buffer */
+ :
+ : if ((gotnow > 0) && (oci->bufptr != oci->buffer))
+ : /* save the data we've already read */
+ : memmove(oci->buffer, oci->bufptr, gotnow);
+ : if (needed > oci->size)
+ : {
+ : /* make buffer bigger to accomodate request */
+ : char *ibuf;
+ :
+ : ibuf = (char *)xrealloc(oci->buffer, needed);
+ : if (!ibuf)
+ : {
+ : YieldControlDeath();
+ : return -1;
+ : }
+ : oci->size = needed;
+ : oci->buffer = ibuf;
+ : }
+ : oci->bufptr = oci->buffer;
+ : oci->bufcnt = gotnow;
+ : }
+ : /* XXX this is a workaround. This function is sometimes called
+ : * after the trans_conn has been freed. In this case trans_conn
+ : * will be null. Really ought to restructure things so that we
+ : * never get here in those circumstances.
+ : */
+ : if (!oc->trans_conn)
+ : {
+ : /* treat as if an error occured on the read, which is what
+ : * used to happen
+ : */
+ : YieldControlDeath();
+ : return -1;
+ : }
+ : result = _XSERVTransRead(oc->trans_conn, oci->buffer + oci->bufcnt,
+ : oci->size - oci->bufcnt);
+ : if (result <= 0)
+ : {
+ : if ((result < 0) && ETEST(errno))
+ : {
+ :#if defined(SVR4) && defined(i386) && !defined(sun)
+ : if (0)
+ :#endif
+ : {
+ : YieldControlNoInput();
+ : return 0;
+ : }
+ : }
+ : YieldControlDeath();
+ : return -1;
+ : }
+ : oci->bufcnt += result;
+ : gotnow += result;
+ : /* free up some space after huge requests */
+ : if ((oci->size > BUFWATERMARK) &&
+ : (oci->bufcnt < BUFSIZE) && (needed < BUFSIZE))
+ : {
+ : char *ibuf;
+ :
+ : ibuf = (char *)xrealloc(oci->buffer, BUFSIZE);
+ : if (ibuf)
+ : {
+ : oci->size = BUFSIZE;
+ : oci->buffer = ibuf;
+ : oci->bufptr = ibuf + oci->bufcnt - gotnow;
+ : }
+ : }
+ : if (need_header && gotnow >= needed)
+ : {
+ : /* We wanted an xReq, now we've gotten it. */
+ : request = (xReq *)oci->bufptr;
+ : needed = get_req_len(request, client);
+ :#ifdef BIGREQS
+ : if (!needed && client->big_requests)
+ : {
+ : move_header = TRUE;
+ : if (gotnow < sizeof(xBigReq))
+ : needed = sizeof(xBigReq) >> 2;
+ : else
+ : needed = get_big_req_len(request, client);
+ : }
+ :#endif
+ : client->req_len = needed;
+ : needed <<= 2;
+ : }
+ : if (gotnow < needed)
+ : {
+ : /* Still don't have enough; punt. */
+ : YieldControlNoInput();
+ : return 0;
+ : }
+ : }
+ 1 0.0011 : if (needed == 0)
+ : {
+ :#ifdef BIGREQS
+ : if (client->big_requests)
+ : needed = sizeof(xBigReq);
+ : else
+ :#endif
+ : needed = sizeof(xReq);
+ : }
+ 3 0.0033 : oci->lenLastReq = needed;
+ :
+ : /*
+ : * Check to see if client has at least one whole request in the
+ : * buffer beyond the request we're returning to the caller.
+ : * If there is only a partial request, treat like buffer
+ : * is empty so that select() will be called again and other clients
+ : * can get into the queue.
+ : */
+ :
+ 1 0.0011 : gotnow -= needed;
+ : if (gotnow >= sizeof(xReq))
+ : {
+ 1 0.0011 : request = (xReq *)(oci->bufptr + needed);
+ 9 0.0098 : if (gotnow >= (result = (get_req_len(request, client) << 2))
+ :#ifdef BIGREQS
+ : && (result ||
+ : (client->big_requests &&
+ : (gotnow >= sizeof(xBigReq) &&
+ : gotnow >= (get_big_req_len(request, client) << 2))))
+ :#endif
+ : )
+ 11 0.0120 : FD_SET(fd, &ClientsWithInput);
+ : else
+ : {
+ :#ifdef SMART_SCHEDULE
+ 1 0.0011 : if (!SmartScheduleDisable)
+ : FD_CLR(fd, &ClientsWithInput);
+ : else
+ :#endif
+ : YieldControlNoInput();
+ : }
+ : }
+ : else
+ : {
+ : if (!gotnow)
+ : AvailableInput = oc;
+ :#ifdef SMART_SCHEDULE
+ : if (!SmartScheduleDisable)
+ : FD_CLR(fd, &ClientsWithInput);
+ : else
+ :#endif
+ : YieldControlNoInput();
+ : }
+ :#ifdef SMART_SCHEDULE
+ 3 0.0033 : if (SmartScheduleDisable)
+ :#endif
+ : if (++timesThisConnection >= MAX_TIMES_PER)
+ : YieldControl();
+ :#ifdef BIGREQS
+ : if (move_header)
+ : {
+ : request = (xReq *)oci->bufptr;
+ : oci->bufptr += (sizeof(xBigReq) - sizeof(xReq));
+ : *(xReq *)oci->bufptr = *request;
+ : oci->lenLastReq -= (sizeof(xBigReq) - sizeof(xReq));
+ : client->req_len -= (sizeof(xBigReq) - sizeof(xReq)) >> 2;
+ : }
+ :#endif
+ 3 0.0033 : client->requestBuffer = (pointer)oci->bufptr;
+ :#ifdef DEBUG_COMMUNICATION
+ : {
+ : xReq *req = client->requestBuffer;
+ : ErrorF("REQUEST: ClientIDX: %i, type: 0x%x data: 0x%x len: %i\n",
+ : client->index,req->reqType,req->data,req->length);
+ : }
+ :#endif
+ : return needed;
+ 5 0.0054 :}
+ :
+ :/*****************************************************************
+ : * InsertFakeRequest
+ : * Splice a consed up (possibly partial) request in as the next request.
+ : *
+ : **********************/
+ :
+ :Bool
+ :InsertFakeRequest(ClientPtr client, char *data, int count)
+ :{
+ : OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ : ConnectionInputPtr oci = oc->input;
+ : int fd = oc->fd;
+ : int gotnow, moveup;
+ :
+ : if (AvailableInput)
+ : {
+ : if (AvailableInput != oc)
+ : {
+ : ConnectionInputPtr aci = AvailableInput->input;
+ : if (aci->size > BUFWATERMARK)
+ : {
+ : xfree(aci->buffer);
+ : xfree(aci);
+ : }
+ : else
+ : {
+ : aci->next = FreeInputs;
+ : FreeInputs = aci;
+ : }
+ : AvailableInput->input = (ConnectionInputPtr)NULL;
+ : }
+ : AvailableInput = (OsCommPtr)NULL;
+ : }
+ : if (!oci)
+ : {
+ : if ((oci = FreeInputs))
+ : FreeInputs = oci->next;
+ : else if (!(oci = AllocateInputBuffer()))
+ : return FALSE;
+ : oc->input = oci;
+ : }
+ : oci->bufptr += oci->lenLastReq;
+ : oci->lenLastReq = 0;
+ : gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
+ : if ((gotnow + count) > oci->size)
+ : {
+ : char *ibuf;
+ :
+ : ibuf = (char *)xrealloc(oci->buffer, gotnow + count);
+ : if (!ibuf)
+ : return(FALSE);
+ : oci->size = gotnow + count;
+ : oci->buffer = ibuf;
+ : oci->bufptr = ibuf + oci->bufcnt - gotnow;
+ : }
+ : moveup = count - (oci->bufptr - oci->buffer);
+ : if (moveup > 0)
+ : {
+ : if (gotnow > 0)
+ : memmove(oci->bufptr + moveup, oci->bufptr, gotnow);
+ : oci->bufptr += moveup;
+ : oci->bufcnt += moveup;
+ : }
+ : memmove(oci->bufptr - count, data, count);
+ : oci->bufptr -= count;
+ : gotnow += count;
+ : if ((gotnow >= sizeof(xReq)) &&
+ : (gotnow >= (int)(get_req_len((xReq *)oci->bufptr, client) << 2)))
+ : FD_SET(fd, &ClientsWithInput);
+ : else
+ : YieldControlNoInput();
+ : return(TRUE);
+ :}
+ :
+ :/*****************************************************************
+ : * ResetRequestFromClient
+ : * Reset to reexecute the current request, and yield.
+ : *
+ : **********************/
+ :
+ :_X_EXPORT void
+ :ResetCurrentRequest(ClientPtr client)
+ :{
+ : OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ : register ConnectionInputPtr oci = oc->input;
+ : int fd = oc->fd;
+ : register xReq *request;
+ : int gotnow, needed;
+ : if (AvailableInput == oc)
+ : AvailableInput = (OsCommPtr)NULL;
+ : oci->lenLastReq = 0;
+ : gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
+ : if (gotnow < sizeof(xReq))
+ : {
+ : YieldControlNoInput();
+ : }
+ : else
+ : {
+ : request = (xReq *)oci->bufptr;
+ : needed = get_req_len(request, client);
+ :#ifdef BIGREQS
+ : if (!needed && client->big_requests)
+ : {
+ : oci->bufptr -= sizeof(xBigReq) - sizeof(xReq);
+ : *(xReq *)oci->bufptr = *request;
+ : ((xBigReq *)oci->bufptr)->length = client->req_len;
+ : if (client->swapped)
+ : {
+ : char n;
+ : swapl(&((xBigReq *)oci->bufptr)->length, n);
+ : }
+ : }
+ :#endif
+ : if (gotnow >= (needed << 2))
+ : {
+ : if (FD_ISSET(fd, &AllClients))
+ : {
+ : FD_SET(fd, &ClientsWithInput);
+ : }
+ : else
+ : {
+ : FD_SET(fd, &IgnoredClientsWithInput);
+ : }
+ : YieldControl();
+ : }
+ : else
+ : YieldControlNoInput();
+ : }
+ :}
+ :
+ :
+ :
+ :/*****************************************************************
+ : * PeekNextRequest and SkipRequests were implemented to support DBE
+ : * idioms, but can certainly be used outside of DBE. There are two
+ : * related macros in os.h, ReqLen and CastxReq. See the porting
+ : * layer document for more details.
+ : *
+ : **********************/
+ :
+ :
+ :/*****************************************************************
+ : * PeekNextRequest
+ : * lets you look ahead at the unexecuted requests in a
+ : * client's request buffer.
+ : *
+ : * Note: this implementation of PeekNextRequest ignores the
+ : * readmore parameter.
+ : *
+ : **********************/
+ :
+ :static xReqPtr
+ :PeekNextRequest(
+ : xReqPtr req, /* request we're starting from */
+ : ClientPtr client, /* client whose requests we're skipping */
+ : Bool readmore) /* attempt to read more if next request isn't there? */
+ :{
+ : register ConnectionInputPtr oci = ((OsCommPtr)client->osPrivate)->input;
+ : xReqPtr pnextreq;
+ : int needed, gotnow, reqlen;
+ :
+ : if (!oci) return NULL;
+ :
+ : if (!req)
+ : {
+ : /* caller wants the request after the one currently being executed */
+ : pnextreq = (xReqPtr)
+ : (((CARD32 *)client->requestBuffer) + client->req_len);
+ : }
+ : else
+ : {
+ : /* caller wants the request after the one specified by req */
+ : reqlen = get_req_len(req, client);
+ :#ifdef BIGREQS
+ : if (!reqlen) reqlen = get_big_req_len(req, client);
+ :#endif
+ : pnextreq = (xReqPtr)(((char *)req) + (reqlen << 2));
+ : }
+ :
+ : /* see how much of the next request we have available */
+ :
+ : gotnow = oci->bufcnt - (((char *)pnextreq) - oci->buffer);
+ :
+ : if (gotnow < sizeof(xReq))
+ : return NULL;
+ :
+ : needed = get_req_len(pnextreq, client) << 2;
+ :#ifdef BIGREQS
+ : if (!needed)
+ : {
+ : /* it's a big request */
+ : if (gotnow < sizeof(xBigReq))
+ : return NULL;
+ : needed = get_big_req_len(pnextreq, client) << 2;
+ : }
+ :#endif
+ :
+ : /* if we have less than we need, return NULL */
+ :
+ : return (gotnow < needed) ? NULL : pnextreq;
+ :}
+ :
+ :/*****************************************************************
+ : * SkipRequests
+ : * lets you skip over some of the requests in a client's
+ : * request buffer. Presumably the caller has used PeekNextRequest
+ : * to examine the requests being skipped and has performed whatever
+ : * actions they dictate.
+ : *
+ : **********************/
+ :
+ :_X_EXPORT CallbackListPtr SkippedRequestsCallback = NULL;
+ :
+ :static void
+ :SkipRequests(
+ : xReqPtr req, /* last request being skipped */
+ : ClientPtr client, /* client whose requests we're skipping */
+ : int numskipped) /* how many requests we're skipping */
+ :{
+ : OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ : register ConnectionInputPtr oci = oc->input;
+ : int reqlen;
+ :
+ : /* see if anyone wants to snoop the skipped requests */
+ :
+ : if (SkippedRequestsCallback)
+ : {
+ : SkippedRequestInfoRec skipinfo;
+ : skipinfo.req = req;
+ : skipinfo.client = client;
+ : skipinfo.numskipped = numskipped;
+ : CallCallbacks(&SkippedRequestsCallback, &skipinfo);
+ : }
+ :
+ : /* adjust the sequence number */
+ : client->sequence += numskipped;
+ :
+ : /* twiddle the oci to skip over the requests */
+ :
+ : reqlen = get_req_len(req, client);
+ :#ifdef BIGREQS
+ : if (!reqlen) reqlen = get_big_req_len(req, client);
+ :#endif
+ : reqlen <<= 2;
+ : oci->bufptr = (char *)req;
+ : oci->lenLastReq = reqlen;
+ :
+ : /* see if any requests left in the buffer */
+ :
+ : if ( ((char *)req + reqlen) == (oci->buffer + oci->bufcnt) )
+ : {
+ : /* no requests; mark input buffer as available and client
+ : * as having no input
+ : */
+ : int fd = oc->fd;
+ : AvailableInput = oc;
+ : YieldControlNoInput();
+ : }
+ :}
+ :
+ :
+ : /* lookup table for adding padding bytes to data that is read from
+ : or written to the X socket. */
+ :static int padlength[4] = {0, 3, 2, 1};
+ :
+ : /********************
+ : * FlushAllOutput()
+ : * Flush all clients with output. However, if some client still
+ : * has input in the queue (more requests), then don't flush. This
+ : * will prevent the output queue from being flushed every time around
+ : * the round robin queue. Now, some say that it SHOULD be flushed
+ : * every time around, but...
+ : *
+ : **********************/
+ :
+ :void
+ :FlushAllOutput(void)
+ :{
+ : register int index, base;
+ : register fd_mask mask; /* raphael */
+ : OsCommPtr oc;
+ : register ClientPtr client;
+ : Bool newoutput = NewOutputPending;
+ :#if defined(WIN32)
+ : fd_set newOutputPending;
+ :#endif
+ :
+ : if (FlushCallback)
+ : CallCallbacks(&FlushCallback, NULL);
+ :
+ : if (!newoutput)
+ : return;
+ :
+ : /*
+ : * It may be that some client still has critical output pending,
+ : * but he is not yet ready to receive it anyway, so we will
+ : * simply wait for the select to tell us when he's ready to receive.
+ : */
+ : CriticalOutputPending = FALSE;
+ : NewOutputPending = FALSE;
+ :
+ :#ifndef WIN32
+ : for (base = 0; base < howmany(XFD_SETSIZE, NFDBITS); base++)
+ : {
+ : mask = OutputPending.fds_bits[ base ];
+ : OutputPending.fds_bits[ base ] = 0;
+ : while (mask)
+ : {
+ : index = ffs(mask) - 1;
+ : mask &= ~lowbit(mask);
+ : if ((index = ConnectionTranslation[(base * (sizeof(fd_mask)*8)) + index]) == 0)
+ : continue;
+ : client = clients[index];
+ : if (client->clientGone)
+ : continue;
+ : oc = (OsCommPtr)client->osPrivate;
+ : if (FD_ISSET(oc->fd, &ClientsWithInput))
+ : {
+ : FD_SET(oc->fd, &OutputPending); /* set the bit again */
+ : NewOutputPending = TRUE;
+ : }
+ : else
+ : (void)FlushClient(client, oc, (char *)NULL, 0);
+ : }
+ : }
+ :#else /* WIN32 */
+ : FD_ZERO(&newOutputPending);
+ : for (base = 0; base < XFD_SETCOUNT(&OutputPending); base++)
+ : {
+ : index = XFD_FD(&OutputPending, base);
+ : if ((index = GetConnectionTranslation(index)) == 0)
+ : continue;
+ : client = clients[index];
+ : if (client->clientGone)
+ : continue;
+ : oc = (OsCommPtr)client->osPrivate;
+ : if (FD_ISSET(oc->fd, &ClientsWithInput))
+ : {
+ : FD_SET(oc->fd, &newOutputPending); /* set the bit again */
+ : NewOutputPending = TRUE;
+ : }
+ : else
+ : (void)FlushClient(client, oc, (char *)NULL, 0);
+ : }
+ : XFD_COPYSET(&newOutputPending, &OutputPending);
+ :#endif /* WIN32 */
+ :}
+ :
+ :void
+ :FlushIfCriticalOutputPending(void)
+ :{
+ : if (CriticalOutputPending)
+ : FlushAllOutput();
+ :}
+ :
+ :_X_EXPORT void
+ :SetCriticalOutputPending(void)
+ :{
+ : CriticalOutputPending = TRUE;
+ :}
+ :
+ :/*****************
+ : * WriteToClient
+ : * Copies buf into ClientPtr.buf if it fits (with padding), else
+ : * flushes ClientPtr.buf and buf to client. As of this writing,
+ : * every use of WriteToClient is cast to void, and the result
+ : * is ignored. Potentially, this could be used by requests
+ : * that are sending several chunks of data and want to break
+ : * out of a loop on error. Thus, we will leave the type of
+ : * this routine as int.
+ : *****************/
+ :
+ :_X_EXPORT int
+ :WriteToClient (ClientPtr who, int count, char *buf)
+ :{
+ : OsCommPtr oc = (OsCommPtr)who->osPrivate;
+ : ConnectionOutputPtr oco = oc->output;
+ : int padBytes;
+ :#ifdef DEBUG_COMMUNICATION
+ : Bool multicount = FALSE;
+ :#endif
+ : if (!count)
+ : return(0);
+ :#ifdef DEBUG_COMMUNICATION
+ : {
+ : char info[128];
+ : xError *err;
+ : xGenericReply *rep;
+ : xEvent *ev;
+ :
+ : if (!who->replyBytesRemaining) {
+ : switch(buf[0]) {
+ : case X_Reply:
+ : rep = (xGenericReply*)buf;
+ : if (rep->sequenceNumber == who->sequence) {
+ : snprintf(info,127,"Xreply: type: 0x%x data: 0x%x "
+ : "len: %i seq#: 0x%x", rep->type, rep->data1,
+ : rep->length, rep->sequenceNumber);
+ : multicount = TRUE;
+ : }
+ : break;
+ : case X_Error:
+ : err = (xError*)buf;
+ : snprintf(info,127,"Xerror: Code: 0x%x resID: 0x%x maj: 0x%x "
+ : "min: %x", err->errorCode,err->resourceID,
+ : err->minorCode,err->majorCode);
+ : break;
+ : default:
+ : if ((buf[0] & 0x7f) == KeymapNotify)
+ : snprintf(info,127,"KeymapNotifyEvent: %i",buf[0]);
+ : else {
+ : ev = (xEvent*)buf;
+ : snprintf(info,127,"XEvent: type: 0x%x detail: 0x%x "
+ : "seq#: 0x%x", ev->u.u.type, ev->u.u.detail,
+ : ev->u.u.sequenceNumber);
+ : }
+ : }
+ : ErrorF("REPLY: ClientIDX: %i %s\n",who->index, info);
+ : } else
+ : multicount = TRUE;
+ : }
+ :#endif
+ :
+ : if (!oco)
+ : {
+ : if ((oco = FreeOutputs))
+ : {
+ : FreeOutputs = oco->next;
+ : }
+ : else if (!(oco = AllocateOutputBuffer()))
+ : {
+ : if (oc->trans_conn) {
+ : _XSERVTransDisconnect(oc->trans_conn);
+ : _XSERVTransClose(oc->trans_conn);
+ : oc->trans_conn = NULL;
+ : }
+ : MarkClientException(who);
+ : return -1;
+ : }
+ : oc->output = oco;
+ : }
+ :
+ : padBytes = padlength[count & 3];
+ :
+ : if(ReplyCallback)
+ : {
+ : ReplyInfoRec replyinfo;
+ :
+ : replyinfo.client = who;
+ : replyinfo.replyData = buf;
+ : replyinfo.dataLenBytes = count + padBytes;
+ : if (who->replyBytesRemaining)
+ : { /* still sending data of an earlier reply */
+ : who->replyBytesRemaining -= count + padBytes;
+ : replyinfo.startOfReply = FALSE;
+ : replyinfo.bytesRemaining = who->replyBytesRemaining;
+ : CallCallbacks((&ReplyCallback), (pointer)&replyinfo);
+ : }
+ : else if (who->clientState == ClientStateRunning
+ : && buf[0] == X_Reply)
+ : { /* start of new reply */
+ : CARD32 replylen;
+ : unsigned long bytesleft;
+ : char n;
+ :
+ : replylen = ((xGenericReply *)buf)->length;
+ : if (who->swapped)
+ : swapl(&replylen, n);
+ : bytesleft = (replylen * 4) + SIZEOF(xReply) - count - padBytes;
+ : replyinfo.startOfReply = TRUE;
+ : replyinfo.bytesRemaining = who->replyBytesRemaining = bytesleft;
+ : CallCallbacks((&ReplyCallback), (pointer)&replyinfo);
+ : }
+ : }
+ :#ifdef DEBUG_COMMUNICATION
+ : else if (multicount) {
+ : if (who->replyBytesRemaining) {
+ : who->replyBytesRemaining -= (count + padBytes);
+ : } else {
+ : CARD32 replylen;
+ : replylen = ((xGenericReply *)buf)->length;
+ : who->replyBytesRemaining =
+ : (replylen * 4) + SIZEOF(xReply) - count - padBytes;
+ : }
+ : }
+ :#endif
+ : if (oco->count + count + padBytes > oco->size)
+ : {
+ : FD_CLR(oc->fd, &OutputPending);
+ : if(!XFD_ANYSET(&OutputPending)) {
+ : CriticalOutputPending = FALSE;
+ : NewOutputPending = FALSE;
+ : }
+ : return FlushClient(who, oc, buf, count);
+ : }
+ :
+ : NewOutputPending = TRUE;
+ : FD_SET(oc->fd, &OutputPending);
+ : memmove((char *)oco->buf + oco->count, buf, count);
+ : oco->count += count + padBytes;
+ : return(count);
+ :}
+ :
+ : /********************
+ : * FlushClient()
+ : * If the client isn't keeping up with us, then we try to continue
+ : * buffering the data and set the apropriate bit in ClientsWritable
+ : * (which is used by WaitFor in the select). If the connection yields
+ : * a permanent error, or we can't allocate any more space, we then
+ : * close the connection.
+ : *
+ : **********************/
+ :
+ :int
+ :FlushClient(ClientPtr who, OsCommPtr oc, char *extraBuf, int extraCount)
+ :{
+ : ConnectionOutputPtr oco = oc->output;
+ : int connection = oc->fd;
+ : XtransConnInfo trans_conn = oc->trans_conn;
+ : struct iovec iov[3];
+ : static char padBuffer[3];
+ : long written;
+ : long padsize;
+ : long notWritten;
+ : long todo;
+ :
+ : if (!oco)
+ : return 0;
+ : written = 0;
+ : padsize = padlength[extraCount & 3];
+ : notWritten = oco->count + extraCount + padsize;
+ : todo = notWritten;
+ : while (notWritten) {
+ : long before = written; /* amount of whole thing written */
+ : long remain = todo; /* amount to try this time, <= notWritten */
+ : int i = 0;
+ : long len;
+ :
+ : /* You could be very general here and have "in" and "out" iovecs
+ : * and write a loop without using a macro, but what the heck. This
+ : * translates to:
+ : *
+ : * how much of this piece is new?
+ : * if more new then we are trying this time, clamp
+ : * if nothing new
+ : * then bump down amount already written, for next piece
+ : * else put new stuff in iovec, will need all of next piece
+ : *
+ : * Note that todo had better be at least 1 or else we'll end up
+ : * writing 0 iovecs.
+ : */
+ :#define InsertIOV(pointer, length) \
+ : len = (length) - before; \
+ : if (len > remain) \
+ : len = remain; \
+ : if (len <= 0) { \
+ : before = (-len); \
+ : } else { \
+ : iov[i].iov_len = len; \
+ : iov[i].iov_base = (pointer) + before; \
+ : i++; \
+ : remain -= len; \
+ : before = 0; \
+ : }
+ :
+ : InsertIOV ((char *)oco->buf, oco->count)
+ : InsertIOV (extraBuf, extraCount)
+ : InsertIOV (padBuffer, padsize)
+ :
+ : errno = 0;
+ : if (trans_conn && (len = _XSERVTransWritev(trans_conn, iov, i)) >= 0)
+ : {
+ : written += len;
+ : notWritten -= len;
+ : todo = notWritten;
+ : }
+ : else if (ETEST(errno)
+ :#ifdef SUNSYSV /* check for another brain-damaged OS bug */
+ : || (errno == 0)
+ :#endif
+ :#ifdef EMSGSIZE /* check for another brain-damaged OS bug */
+ : || ((errno == EMSGSIZE) && (todo == 1))
+ :#endif
+ : )
+ : {
+ : /* If we've arrived here, then the client is stuffed to the gills
+ : and not ready to accept more. Make a note of it and buffer
+ : the rest. */
+ : FD_SET(connection, &ClientsWriteBlocked);
+ : AnyClientsWriteBlocked = TRUE;
+ :
+ : if (written < oco->count)
+ : {
+ : if (written > 0)
+ : {
+ : oco->count -= written;
+ : memmove((char *)oco->buf,
+ : (char *)oco->buf + written,
+ : oco->count);
+ : written = 0;
+ : }
+ : }
+ : else
+ : {
+ : written -= oco->count;
+ : oco->count = 0;
+ : }
+ :
+ : if (notWritten > oco->size)
+ : {
+ : unsigned char *obuf;
+ :
+ : obuf = (unsigned char *)xrealloc(oco->buf,
+ : notWritten + BUFSIZE);
+ : if (!obuf)
+ : {
+ : _XSERVTransDisconnect(oc->trans_conn);
+ : _XSERVTransClose(oc->trans_conn);
+ : oc->trans_conn = NULL;
+ : MarkClientException(who);
+ : oco->count = 0;
+ : return(-1);
+ : }
+ : oco->size = notWritten + BUFSIZE;
+ : oco->buf = obuf;
+ : }
+ :
+ : /* If the amount written extended into the padBuffer, then the
+ : difference "extraCount - written" may be less than 0 */
+ : if ((len = extraCount - written) > 0)
+ : memmove ((char *)oco->buf + oco->count,
+ : extraBuf + written,
+ : len);
+ :
+ : oco->count = notWritten; /* this will include the pad */
+ : /* return only the amount explicitly requested */
+ : return extraCount;
+ : }
+ :#ifdef EMSGSIZE /* check for another brain-damaged OS bug */
+ : else if (errno == EMSGSIZE)
+ : {
+ : todo >>= 1;
+ : }
+ :#endif
+ : else
+ : {
+ : if (oc->trans_conn)
+ : {
+ : _XSERVTransDisconnect(oc->trans_conn);
+ : _XSERVTransClose(oc->trans_conn);
+ : oc->trans_conn = NULL;
+ : }
+ : MarkClientException(who);
+ : oco->count = 0;
+ : return(-1);
+ : }
+ : }
+ :
+ : /* everything was flushed out */
+ : oco->count = 0;
+ : /* check to see if this client was write blocked */
+ : if (AnyClientsWriteBlocked)
+ : {
+ : FD_CLR(oc->fd, &ClientsWriteBlocked);
+ : if (! XFD_ANYSET(&ClientsWriteBlocked))
+ : AnyClientsWriteBlocked = FALSE;
+ : }
+ : if (oco->size > BUFWATERMARK)
+ : {
+ : xfree(oco->buf);
+ : xfree(oco);
+ : }
+ : else
+ : {
+ : oco->next = FreeOutputs;
+ : FreeOutputs = oco;
+ : }
+ : oc->output = (ConnectionOutputPtr)NULL;
+ : return extraCount; /* return only the amount explicitly requested */
+ :}
+ :
+ :static ConnectionInputPtr
+ :AllocateInputBuffer(void)
+ :{
+ : ConnectionInputPtr oci;
+ :
+ : oci = (ConnectionInputPtr)xalloc(sizeof(ConnectionInput));
+ : if (!oci)
+ : return (ConnectionInputPtr)NULL;
+ : oci->buffer = (char *)xalloc(BUFSIZE);
+ : if (!oci->buffer)
+ : {
+ : xfree(oci);
+ : return (ConnectionInputPtr)NULL;
+ : }
+ : oci->size = BUFSIZE;
+ : oci->bufptr = oci->buffer;
+ : oci->bufcnt = 0;
+ : oci->lenLastReq = 0;
+ : return oci;
+ :}
+ :
+ :static ConnectionOutputPtr
+ :AllocateOutputBuffer(void)
+ :{
+ : ConnectionOutputPtr oco;
+ :
+ : oco = (ConnectionOutputPtr)xalloc(sizeof(ConnectionOutput));
+ : if (!oco)
+ : return (ConnectionOutputPtr)NULL;
+ : oco->buf = (unsigned char *) xalloc(BUFSIZE);
+ : if (!oco->buf)
+ : {
+ : xfree(oco);
+ : return (ConnectionOutputPtr)NULL;
+ : }
+ : oco->size = BUFSIZE;
+ : oco->count = 0;
+ : return oco;
+ :}
+ :
+ :void
+ :FreeOsBuffers(OsCommPtr oc)
+ :{
+ : ConnectionInputPtr oci;
+ : ConnectionOutputPtr oco;
+ :
+ : if (AvailableInput == oc)
+ : AvailableInput = (OsCommPtr)NULL;
+ : if ((oci = oc->input))
+ : {
+ : if (FreeInputs)
+ : {
+ : xfree(oci->buffer);
+ : xfree(oci);
+ : }
+ : else
+ : {
+ : FreeInputs = oci;
+ : oci->next = (ConnectionInputPtr)NULL;
+ : oci->bufptr = oci->buffer;
+ : oci->bufcnt = 0;
+ : oci->lenLastReq = 0;
+ : }
+ : }
+ : if ((oco = oc->output))
+ : {
+ : if (FreeOutputs)
+ : {
+ : xfree(oco->buf);
+ : xfree(oco);
+ : }
+ : else
+ : {
+ : FreeOutputs = oco;
+ : oco->next = (ConnectionOutputPtr)NULL;
+ : oco->count = 0;
+ : }
+ : }
+ :}
+ :
+ :void
+ :ResetOsBuffers(void)
+ :{
+ : ConnectionInputPtr oci;
+ : ConnectionOutputPtr oco;
+ :
+ : while ((oci = FreeInputs))
+ : {
+ : FreeInputs = oci->next;
+ : xfree(oci->buffer);
+ : xfree(oci);
+ : }
+ : while ((oco = FreeOutputs))
+ : {
+ : FreeOutputs = oco->next;
+ : xfree(oco->buf);
+ : xfree(oco);
+ : }
+ :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/dix/dispatch.c"
+ *
+ * 60 0.0654
+ */
+
+
+ :/************************************************************
+ :
+ :Copyright 1987, 1989, 1998 The Open Group
+ :
+ :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.
+ :
+ :The above copyright notice and this permission notice shall be included in
+ :all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ :IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ :FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ :OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ :AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ :CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of The Open Group shall not be
+ :used in advertising or otherwise to promote the sale, use or other dealings
+ :in this Software without prior written authorization from The Open Group.
+ :
+ :
+ :Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
+ :
+ : All Rights Reserved
+ :
+ :Permission to use, copy, modify, and distribute this software and its
+ :documentation for any purpose and without fee is hereby granted,
+ :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 Digital not be
+ :used in advertising or publicity pertaining to distribution of the
+ :software without specific, written prior permission.
+ :
+ :DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ :ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ :DIGITAL 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.
+ :
+ :********************************************************/
+ :
+ :/* The panoramix components contained the following notice */
+ :/*****************************************************************
+ :
+ :Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
+ :
+ :Permission is hereby granted, free of charge, to any person obtaining a copy
+ :of this software and associated documentation files (the "Software"), to deal
+ :in the Software without restriction, including without limitation the rights
+ :to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ :copies of the Software.
+ :
+ :The above copyright notice and this permission notice shall be included in
+ :all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ :IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ :FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ :DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
+ :BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
+ :WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+ :IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of Digital Equipment Corporation
+ :shall not be used in advertising or otherwise to promote the sale, use or other
+ :dealings in this Software without prior written authorization from Digital
+ :Equipment Corporation.
+ :
+ :******************************************************************/
+ :
+ :/* XSERVER_DTRACE additions:
+ : * Copyright 2005-2006 Sun Microsystems, Inc. All rights reserved.
+ : *
+ : * Permission is hereby granted, free of charge, to any person obtaining a
+ : * copy of this software and associated documentation files (the
+ : * "Software"), to deal in the Software without restriction, including
+ : * without limitation the rights to use, copy, modify, merge, publish,
+ : * distribute, and/or sell copies of the Software, and to permit persons
+ : * to whom the Software is furnished to do so, provided that the above
+ : * copyright notice(s) and this permission notice appear in all copies of
+ : * the Software and that both the above copyright notice(s) and this
+ : * permission notice appear in supporting documentation.
+ : *
+ : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+ : * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ : * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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.
+ : *
+ : * Except as contained in this notice, the name of a copyright holder
+ : * shall not be used in advertising or otherwise to promote the sale, use
+ : * or other dealings in this Software without prior written authorization
+ : * of the copyright holder.
+ : */
+ :
+ :
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#ifdef PANORAMIX_DEBUG
+ :#include <stdio.h>
+ :int ProcInitialConnection();
+ :#endif
+ :
+ :#include "windowstr.h"
+ :#include <X11/fonts/fontstruct.h>
+ :#include "dixfontstr.h"
+ :#include "gcstruct.h"
+ :#include "selection.h"
+ :#include "colormapst.h"
+ :#include "cursorstr.h"
+ :#include "scrnintstr.h"
+ :#include "opaque.h"
+ :#include "input.h"
+ :#include "servermd.h"
+ :#include "extnsionst.h"
+ :#include "dixfont.h"
+ :#include "dispatch.h"
+ :#include "swaprep.h"
+ :#include "swapreq.h"
+ :#ifdef PANORAMIX
+ :#include "panoramiX.h"
+ :#include "panoramiXsrv.h"
+ :#endif
+ :#include "xace.h"
+ :#ifdef XAPPGROUP
+ :#include "appgroup.h"
+ :#endif
+ :#ifdef XKB
+ :#ifndef XKB_IN_SERVER
+ :#define XKB_IN_SERVER
+ :#endif
+ :#include "inputstr.h"
+ :#include <xkbsrv.h>
+ :#endif
+ :
+ :#ifdef XSERVER_DTRACE
+ :#include <sys/types.h>
+ :typedef const char *string;
+ :#include "Xserver-dtrace.h"
+ :
+ :char *RequestNames[256];
+ :static void LoadRequestNames(void);
+ :static void FreeRequestNames(void);
+ :#define GetRequestName(i) (RequestNames[i])
+ :#endif
+ :
+ :#define mskcnt ((MAXCLIENTS + 31) / 32)
+ :#define BITMASK(i) (1U << ((i) & 31))
+ :#define MASKIDX(i) ((i) >> 5)
+ :#define MASKWORD(buf, i) buf[MASKIDX(i)]
+ :#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i)
+ :#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i)
+ :#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i))
+ :
+ :extern xConnSetupPrefix connSetupPrefix;
+ :extern char *ConnectionInfo;
+ :
+ :_X_EXPORT Selection *CurrentSelections;
+ :_X_EXPORT int NumCurrentSelections;
+ :CallbackListPtr SelectionCallback = NULL;
+ :
+ :static ClientPtr grabClient;
+ :#define GrabNone 0
+ :#define GrabActive 1
+ :#define GrabKickout 2
+ :static int grabState = GrabNone;
+ :static long grabWaiters[mskcnt];
+ :_X_EXPORT CallbackListPtr ServerGrabCallback = NULL;
+ :HWEventQueuePtr checkForInput[2];
+ :extern int connBlockScreenStart;
+ :
+ :static void KillAllClients(void);
+ :
+ :static void DeleteClientFromAnySelections(ClientPtr client);
+ :
+ :static int nextFreeClientID; /* always MIN free client ID */
+ :
+ :static int nClients; /* number of authorized clients */
+ :
+ :_X_EXPORT CallbackListPtr ClientStateCallback;
+ :
+ :/* dispatchException & isItTimeToYield must be declared volatile since they
+ : * are modified by signal handlers - otherwise optimizer may assume it doesn't
+ : * need to actually check value in memory when used and may miss changes from
+ : * signal handlers.
+ : */
+ :_X_EXPORT volatile char dispatchException = 0;
+ :_X_EXPORT volatile char isItTimeToYield;
+ :
+ :/* Various of the DIX function interfaces were not designed to allow
+ : * the client->errorValue to be set on BadValue and other errors.
+ : * Rather than changing interfaces and breaking untold code we introduce
+ : * a new global that dispatch can use.
+ : */
+ :XID clientErrorValue; /* XXX this is a kludge */
+ :
+ :#define SAME_SCREENS(a, b) (\
+ : (a.pScreen == b.pScreen))
+ :
+ :_X_EXPORT void
+ :SetInputCheck(HWEventQueuePtr c0, HWEventQueuePtr c1)
+ :{
+ : checkForInput[0] = c0;
+ : checkForInput[1] = c1;
+ :}
+ :
+ :_X_EXPORT void
+ :UpdateCurrentTime(void)
+ :{
+ : TimeStamp systime;
+ :
+ : /* To avoid time running backwards, we must call GetTimeInMillis before
+ : * calling ProcessInputEvents.
+ : */
+ : systime.months = currentTime.months;
+ : systime.milliseconds = GetTimeInMillis();
+ : if (systime.milliseconds < currentTime.milliseconds)
+ : systime.months++;
+ : if (*checkForInput[0] != *checkForInput[1])
+ : ProcessInputEvents();
+ : if (CompareTimeStamps(systime, currentTime) == LATER)
+ : currentTime = systime;
+ :}
+ :
+ :/* Like UpdateCurrentTime, but can't call ProcessInputEvents */
+ :_X_EXPORT void
+ :UpdateCurrentTimeIf(void)
+ :{
+ : TimeStamp systime;
+ :
+ : systime.months = currentTime.months;
+ : systime.milliseconds = GetTimeInMillis();
+ : if (systime.milliseconds < currentTime.milliseconds)
+ : systime.months++;
+ : if (*checkForInput[0] == *checkForInput[1])
+ : currentTime = systime;
+ :}
+ :
+ :void
+ :InitSelections(void)
+ :{
+ : if (CurrentSelections)
+ : xfree(CurrentSelections);
+ : CurrentSelections = (Selection *)NULL;
+ : NumCurrentSelections = 0;
+ :}
+ :
+ :void
+ :FlushClientCaches(XID id)
+ :{ /* FlushClientCaches total: 4 0.0044 */
+ : int i;
+ : ClientPtr client;
+ :
+ : client = clients[CLIENT_ID(id)];
+ 1 0.0011 : if (client == NullClient)
+ : return ;
+ 1 0.0011 : for (i=0; i<currentMaxClients; i++)
+ : {
+ : client = clients[i];
+ : if (client != NullClient)
+ : {
+ : if (client->lastDrawableID == id)
+ : {
+ : client->lastDrawableID = WindowTable[0]->drawable.id;
+ : client->lastDrawable = (DrawablePtr)WindowTable[0];
+ : }
+ : else if (client->lastGCID == id)
+ : {
+ : client->lastGCID = INVALID;
+ : client->lastGC = (GCPtr)NULL;
+ : }
+ : }
+ : }
+ 2 0.0022 :}
+ :#ifdef SMART_SCHEDULE
+ :
+ :#undef SMART_DEBUG
+ :
+ :#define SMART_SCHEDULE_DEFAULT_INTERVAL 20 /* ms */
+ :#define SMART_SCHEDULE_MAX_SLICE 200 /* ms */
+ :
+ :Bool SmartScheduleDisable = FALSE;
+ :long SmartScheduleSlice = SMART_SCHEDULE_DEFAULT_INTERVAL;
+ :long SmartScheduleInterval = SMART_SCHEDULE_DEFAULT_INTERVAL;
+ :long SmartScheduleMaxSlice = SMART_SCHEDULE_MAX_SLICE;
+ :long SmartScheduleTime;
+ :static ClientPtr SmartLastClient;
+ :static int SmartLastIndex[SMART_MAX_PRIORITY-SMART_MIN_PRIORITY+1];
+ :
+ :#ifdef SMART_DEBUG
+ :long SmartLastPrint;
+ :#endif
+ :
+ :void Dispatch(void);
+ :void InitProcVectors(void);
+ :
+ :static int
+ :SmartScheduleClient (int *clientReady, int nready)
+ :{
+ : ClientPtr pClient;
+ : int i;
+ : int client;
+ : int bestPrio, best = 0;
+ : int bestRobin, robin;
+ : long now = SmartScheduleTime;
+ : long idle;
+ :
+ : bestPrio = -0x7fffffff;
+ : bestRobin = 0;
+ : idle = 2 * SmartScheduleSlice;
+ : for (i = 0; i < nready; i++)
+ : {
+ : client = clientReady[i];
+ : pClient = clients[client];
+ : /* Praise clients which are idle */
+ : if ((now - pClient->smart_check_tick) >= idle)
+ : {
+ : if (pClient->smart_priority < 0)
+ : pClient->smart_priority++;
+ : }
+ : pClient->smart_check_tick = now;
+ :
+ : /* check priority to select best client */
+ : robin = (pClient->index - SmartLastIndex[pClient->smart_priority-SMART_MIN_PRIORITY]) & 0xff;
+ : if (pClient->smart_priority > bestPrio ||
+ : (pClient->smart_priority == bestPrio && robin > bestRobin))
+ : {
+ : bestPrio = pClient->smart_priority;
+ : bestRobin = robin;
+ : best = client;
+ : }
+ :#ifdef SMART_DEBUG
+ : if ((now - SmartLastPrint) >= 5000)
+ : fprintf (stderr, " %2d: %3d", client, pClient->smart_priority);
+ :#endif
+ : }
+ :#ifdef SMART_DEBUG
+ : if ((now - SmartLastPrint) >= 5000)
+ : {
+ : fprintf (stderr, " use %2d\n", best);
+ : SmartLastPrint = now;
+ : }
+ :#endif
+ : pClient = clients[best];
+ : SmartLastIndex[bestPrio-SMART_MIN_PRIORITY] = pClient->index;
+ : /*
+ : * Set current client pointer
+ : */
+ : if (SmartLastClient != pClient)
+ : {
+ : pClient->smart_start_tick = now;
+ : SmartLastClient = pClient;
+ : }
+ : /*
+ : * Adjust slice
+ : */
+ : if (nready == 1)
+ : {
+ : /*
+ : * If it's been a long time since another client
+ : * has run, bump the slice up to get maximal
+ : * performance from a single client
+ : */
+ : if ((now - pClient->smart_start_tick) > 1000 &&
+ : SmartScheduleSlice < SmartScheduleMaxSlice)
+ : {
+ : SmartScheduleSlice += SmartScheduleInterval;
+ : }
+ : }
+ : else
+ : {
+ : SmartScheduleSlice = SmartScheduleInterval;
+ : }
+ : return best;
+ :}
+ :#endif
+ :
+ :#define MAJOROP ((xReq *)client->requestBuffer)->reqType
+ :
+ :void
+ :Dispatch(void)
+ :{ /* Dispatch total: 37 0.0403 */
+ : int *clientReady; /* array of request ready clients */
+ : int result;
+ : ClientPtr client;
+ : int nready;
+ : HWEventQueuePtr* icheck = checkForInput;
+ :#ifdef SMART_SCHEDULE
+ : long start_tick;
+ :#endif
+ :
+ : nextFreeClientID = 1;
+ : InitSelections();
+ : nClients = 0;
+ :
+ : clientReady = (int *) ALLOCATE_LOCAL(sizeof(int) * MaxClients);
+ : if (!clientReady)
+ : return;
+ :
+ :#ifdef XSERVER_DTRACE
+ : LoadRequestNames();
+ :#endif
+ :
+ : while (!dispatchException)
+ : {
+ : if (*icheck[0] != *icheck[1])
+ : {
+ : ProcessInputEvents();
+ : FlushIfCriticalOutputPending();
+ : }
+ :
+ : nready = WaitForSomething(clientReady);
+ :
+ :#ifdef SMART_SCHEDULE
+ : if (nready && !SmartScheduleDisable)
+ : {
+ : clientReady[0] = SmartScheduleClient (clientReady, nready);
+ : nready = 1;
+ : }
+ :#endif
+ : /*****************
+ : * Handle events in round robin fashion, doing input between
+ : * each round
+ : *****************/
+ :
+ : while (!dispatchException && (--nready >= 0))
+ : {
+ : client = clients[clientReady[nready]];
+ : if (! client)
+ : {
+ : /* KillClient can cause this to happen */
+ : continue;
+ : }
+ : /* GrabServer activation can cause this to be true */
+ : if (grabState == GrabKickout)
+ : {
+ : grabState = GrabActive;
+ : break;
+ : }
+ : isItTimeToYield = FALSE;
+ :
+ : requestingClient = client;
+ :#ifdef SMART_SCHEDULE
+ : start_tick = SmartScheduleTime;
+ :#endif
+ 1 0.0011 : while (!isItTimeToYield)
+ : {
+ 8 0.0087 : if (*icheck[0] != *icheck[1])
+ : {
+ : ProcessInputEvents();
+ : FlushIfCriticalOutputPending();
+ : }
+ :#ifdef SMART_SCHEDULE
+ 6 0.0065 : if (!SmartScheduleDisable &&
+ : (SmartScheduleTime - start_tick) >= SmartScheduleSlice)
+ : {
+ : /* Penalize clients which consume ticks */
+ : if (client->smart_priority > SMART_MIN_PRIORITY)
+ : client->smart_priority--;
+ : break;
+ : }
+ :#endif
+ : /* now, finally, deal with client requests */
+ :
+ 2 0.0022 : result = ReadRequestFromClient(client);
+ 2 0.0022 : if (result <= 0)
+ : {
+ : if (result < 0)
+ : CloseDownClient(client);
+ : break;
+ : }
+ :
+ 2 0.0022 : client->sequence++;
+ :#ifdef DEBUG
+ : if (client->requestLogIndex == MAX_REQUEST_LOG)
+ : client->requestLogIndex = 0;
+ : client->requestLog[client->requestLogIndex] = MAJOROP;
+ : client->requestLogIndex++;
+ :#endif
+ :#ifdef XSERVER_DTRACE
+ : XSERVER_REQUEST_START(GetRequestName(MAJOROP), MAJOROP,
+ : ((xReq *)client->requestBuffer)->length,
+ : client->index, client->requestBuffer);
+ :#endif
+ 4 0.0044 : if (result > (maxBigRequestSize << 2))
+ : result = BadLength;
+ : else {
+ : XaceHook(XACE_AUDIT_BEGIN, client);
+ 3 0.0033 : result = (* client->requestVector[MAJOROP])(client);
+ 8 0.0087 : XaceHook(XACE_AUDIT_END, client, result);
+ : }
+ :#ifdef XSERVER_DTRACE
+ : XSERVER_REQUEST_DONE(GetRequestName(MAJOROP), MAJOROP,
+ : client->sequence, client->index, result);
+ :#endif
+ :
+ 1 0.0011 : if (result != Success)
+ : {
+ : if (client->noClientException != Success)
+ : CloseDownClient(client);
+ : else
+ : SendErrorToClient(client, MAJOROP,
+ : MinorOpcodeOfRequest(client),
+ : client->errorValue, result);
+ : break;
+ : }
+ :#ifdef DAMAGEEXT
+ : FlushIfCriticalOutputPending ();
+ :#endif
+ : }
+ : FlushAllOutput();
+ :#ifdef SMART_SCHEDULE
+ : client = clients[clientReady[nready]];
+ : if (client)
+ : client->smart_stop_tick = SmartScheduleTime;
+ :#endif
+ : requestingClient = NULL;
+ : }
+ : dispatchException &= ~DE_PRIORITYCHANGE;
+ : }
+ :#if defined(DDXBEFORERESET)
+ : ddxBeforeReset ();
+ :#endif
+ : KillAllClients();
+ : DEALLOCATE_LOCAL(clientReady);
+ : dispatchException &= ~DE_RESET;
+ :#ifdef XSERVER_DTRACE
+ : FreeRequestNames();
+ :#endif
+ :}
+ :
+ :#undef MAJOROP
+ :
+ :_X_EXPORT int
+ :ProcBadRequest(ClientPtr client)
+ :{
+ : return (BadRequest);
+ :}
+ :
+ :int
+ :ProcCreateWindow(ClientPtr client)
+ :{
+ : WindowPtr pParent, pWin;
+ : REQUEST(xCreateWindowReq);
+ : int result, len, rc;
+ :
+ : REQUEST_AT_LEAST_SIZE(xCreateWindowReq);
+ :
+ : LEGAL_NEW_RESOURCE(stuff->wid, client);
+ : rc = dixLookupWindow(&pParent, stuff->parent, client, DixWriteAccess);
+ : if (rc != Success)
+ : return rc;
+ : len = client->req_len - (sizeof(xCreateWindowReq) >> 2);
+ : if (Ones(stuff->mask) != len)
+ : return BadLength;
+ : if (!stuff->width || !stuff->height)
+ : {
+ : client->errorValue = 0;
+ : return BadValue;
+ : }
+ : pWin = CreateWindow(stuff->wid, pParent, stuff->x,
+ : stuff->y, stuff->width, stuff->height,
+ : stuff->borderWidth, stuff->class,
+ : stuff->mask, (XID *) &stuff[1],
+ : (int)stuff->depth,
+ : client, stuff->visual, &result);
+ : if (pWin)
+ : {
+ : Mask mask = pWin->eventMask;
+ :
+ : pWin->eventMask = 0; /* subterfuge in case AddResource fails */
+ : if (!AddResource(stuff->wid, RT_WINDOW, (pointer)pWin))
+ : return BadAlloc;
+ : pWin->eventMask = mask;
+ : }
+ : if (client->noClientException != Success)
+ : return(client->noClientException);
+ : else
+ : return(result);
+ :}
+ :
+ :int
+ :ProcChangeWindowAttributes(ClientPtr client)
+ :{
+ : WindowPtr pWin;
+ : REQUEST(xChangeWindowAttributesReq);
+ : int result;
+ : int len, rc;
+ :
+ : REQUEST_AT_LEAST_SIZE(xChangeWindowAttributesReq);
+ : rc = dixLookupWindow(&pWin, stuff->window, client, DixWriteAccess);
+ : if (rc != Success)
+ : return rc;
+ : len = client->req_len - (sizeof(xChangeWindowAttributesReq) >> 2);
+ : if (len != Ones(stuff->valueMask))
+ : return BadLength;
+ : result = ChangeWindowAttributes(pWin,
+ : stuff->valueMask,
+ : (XID *) &stuff[1],
+ : client);
+ : if (client->noClientException != Success)
+ : return(client->noClientException);
+ : else
+ : return(result);
+ :}
+ :
+ :int
+ :ProcGetWindowAttributes(ClientPtr client)
+ :{
+ : WindowPtr pWin;
+ : REQUEST(xResourceReq);
+ : xGetWindowAttributesReply wa;
+ : int rc;
+ :
+ : REQUEST_SIZE_MATCH(xResourceReq);
+ : rc = dixLookupWindow(&pWin, stuff->id, client, DixReadAccess);
+ : if (rc != Success)
+ : return rc;
+ : GetWindowAttributes(pWin, client, &wa);
+ : WriteReplyToClient(client, sizeof(xGetWindowAttributesReply), &wa);
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcDestroyWindow(ClientPtr client)
+ :{
+ : WindowPtr pWin;
+ : REQUEST(xResourceReq);
+ : int rc;
+ :
+ : REQUEST_SIZE_MATCH(xResourceReq);
+ : rc = dixLookupWindow(&pWin, stuff->id, client, DixDestroyAccess);
+ : if (rc != Success)
+ : return rc;
+ : if (pWin->parent)
+ : FreeResource(stuff->id, RT_NONE);
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcDestroySubwindows(ClientPtr client)
+ :{
+ : WindowPtr pWin;
+ : REQUEST(xResourceReq);
+ : int rc;
+ :
+ : REQUEST_SIZE_MATCH(xResourceReq);
+ : rc = dixLookupWindow(&pWin, stuff->id, client, DixDestroyAccess);
+ : if (rc != Success)
+ : return rc;
+ : DestroySubwindows(pWin, client);
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcChangeSaveSet(ClientPtr client)
+ :{
+ : WindowPtr pWin;
+ : REQUEST(xChangeSaveSetReq);
+ : int result, rc;
+ :
+ : REQUEST_SIZE_MATCH(xChangeSaveSetReq);
+ : rc = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess);
+ : if (rc != Success)
+ : return rc;
+ : if (client->clientAsMask == (CLIENT_BITS(pWin->drawable.id)))
+ : return BadMatch;
+ : if ((stuff->mode == SetModeInsert) || (stuff->mode == SetModeDelete))
+ : {
+ : result = AlterSaveSetForClient(client, pWin, stuff->mode, FALSE, TRUE);
+ : if (client->noClientException != Success)
+ : return(client->noClientException);
+ : else
+ : return(result);
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->mode;
+ : return( BadValue );
+ : }
+ :}
+ :
+ :int
+ :ProcReparentWindow(ClientPtr client)
+ :{
+ : WindowPtr pWin, pParent;
+ : REQUEST(xReparentWindowReq);
+ : int result, rc;
+ :
+ : REQUEST_SIZE_MATCH(xReparentWindowReq);
+ : rc = dixLookupWindow(&pWin, stuff->window, client, DixWriteAccess);
+ : if (rc != Success)
+ : return rc;
+ : rc = dixLookupWindow(&pParent, stuff->parent, client, DixWriteAccess);
+ : if (rc != Success)
+ : return rc;
+ : if (SAME_SCREENS(pWin->drawable, pParent->drawable))
+ : {
+ : if ((pWin->backgroundState == ParentRelative) &&
+ : (pParent->drawable.depth != pWin->drawable.depth))
+ : return BadMatch;
+ : if ((pWin->drawable.class != InputOnly) &&
+ : (pParent->drawable.class == InputOnly))
+ : return BadMatch;
+ : result = ReparentWindow(pWin, pParent,
+ : (short)stuff->x, (short)stuff->y, client);
+ : if (client->noClientException != Success)
+ : return(client->noClientException);
+ : else
+ : return(result);
+ : }
+ : else
+ : return (BadMatch);
+ :}
+ :
+ :int
+ :ProcMapWindow(ClientPtr client)
+ :{
+ : WindowPtr pWin;
+ : REQUEST(xResourceReq);
+ : int rc;
+ :
+ : REQUEST_SIZE_MATCH(xResourceReq);
+ : rc = dixLookupWindow(&pWin, stuff->id, client, DixReadAccess);
+ : if (rc != Success)
+ : return rc;
+ : MapWindow(pWin, client);
+ : /* update cache to say it is mapped */
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcMapSubwindows(ClientPtr client)
+ :{
+ : WindowPtr pWin;
+ : REQUEST(xResourceReq);
+ : int rc;
+ :
+ : REQUEST_SIZE_MATCH(xResourceReq);
+ : rc = dixLookupWindow(&pWin, stuff->id, client, DixReadAccess);
+ : if (rc != Success)
+ : return rc;
+ : MapSubwindows(pWin, client);
+ : /* update cache to say it is mapped */
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcUnmapWindow(ClientPtr client)
+ :{
+ : WindowPtr pWin;
+ : REQUEST(xResourceReq);
+ : int rc;
+ :
+ : REQUEST_SIZE_MATCH(xResourceReq);
+ : rc = dixLookupWindow(&pWin, stuff->id, client, DixReadAccess);
+ : if (rc != Success)
+ : return rc;
+ : UnmapWindow(pWin, FALSE);
+ : /* update cache to say it is mapped */
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcUnmapSubwindows(ClientPtr client)
+ :{
+ : WindowPtr pWin;
+ : REQUEST(xResourceReq);
+ : int rc;
+ :
+ : REQUEST_SIZE_MATCH(xResourceReq);
+ : rc = dixLookupWindow(&pWin, stuff->id, client, DixReadAccess);
+ : if (rc != Success)
+ : return rc;
+ : UnmapSubwindows(pWin);
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcConfigureWindow(ClientPtr client)
+ :{
+ : WindowPtr pWin;
+ : REQUEST(xConfigureWindowReq);
+ : int result;
+ : int len, rc;
+ :
+ : REQUEST_AT_LEAST_SIZE(xConfigureWindowReq);
+ : rc = dixLookupWindow(&pWin, stuff->window, client, DixWriteAccess);
+ : if (rc != Success)
+ : return rc;
+ : len = client->req_len - (sizeof(xConfigureWindowReq) >> 2);
+ : if (Ones((Mask)stuff->mask) != len)
+ : return BadLength;
+ : result = ConfigureWindow(pWin, (Mask)stuff->mask, (XID *) &stuff[1],
+ : client);
+ : if (client->noClientException != Success)
+ : return(client->noClientException);
+ : else
+ : return(result);
+ :}
+ :
+ :int
+ :ProcCirculateWindow(ClientPtr client)
+ :{
+ : WindowPtr pWin;
+ : REQUEST(xCirculateWindowReq);
+ : int rc;
+ :
+ : REQUEST_SIZE_MATCH(xCirculateWindowReq);
+ : if ((stuff->direction != RaiseLowest) &&
+ : (stuff->direction != LowerHighest))
+ : {
+ : client->errorValue = stuff->direction;
+ : return BadValue;
+ : }
+ : rc = dixLookupWindow(&pWin, stuff->window, client, DixWriteAccess);
+ : if (rc != Success)
+ : return rc;
+ : CirculateWindow(pWin, (int)stuff->direction, client);
+ : return(client->noClientException);
+ :}
+ :
+ :static int
+ :GetGeometry(ClientPtr client, xGetGeometryReply *rep)
+ :{
+ : DrawablePtr pDraw;
+ : int rc;
+ : REQUEST(xResourceReq);
+ : REQUEST_SIZE_MATCH(xResourceReq);
+ :
+ : rc = dixLookupDrawable(&pDraw, stuff->id, client, M_ANY, DixReadAccess);
+ : if (rc != Success)
+ : return rc;
+ :
+ : rep->type = X_Reply;
+ : rep->length = 0;
+ : rep->sequenceNumber = client->sequence;
+ : rep->root = WindowTable[pDraw->pScreen->myNum]->drawable.id;
+ : rep->depth = pDraw->depth;
+ : rep->width = pDraw->width;
+ : rep->height = pDraw->height;
+ :
+ : /* XXX - Because the pixmap-implementation of the multibuffer extension
+ : * may have the buffer-id's drawable resource value be a pointer
+ : * to the buffer's window instead of the buffer itself
+ : * (this happens if the buffer is the displayed buffer),
+ : * we also have to check that the id matches before we can
+ : * truly say that it is a DRAWABLE_WINDOW.
+ : */
+ :
+ : if ((pDraw->type == UNDRAWABLE_WINDOW) ||
+ : ((pDraw->type == DRAWABLE_WINDOW) && (stuff->id == pDraw->id)))
+ : {
+ : WindowPtr pWin = (WindowPtr)pDraw;
+ : rep->x = pWin->origin.x - wBorderWidth (pWin);
+ : rep->y = pWin->origin.y - wBorderWidth (pWin);
+ : rep->borderWidth = pWin->borderWidth;
+ : }
+ : else /* DRAWABLE_PIXMAP or DRAWABLE_BUFFER */
+ : {
+ : rep->x = rep->y = rep->borderWidth = 0;
+ : }
+ :
+ : return Success;
+ :}
+ :
+ :
+ :int
+ :ProcGetGeometry(ClientPtr client)
+ :{
+ : xGetGeometryReply rep;
+ : int status;
+ :
+ : if ((status = GetGeometry(client, &rep)) != Success)
+ : return status;
+ :
+ : WriteReplyToClient(client, sizeof(xGetGeometryReply), &rep);
+ : return(client->noClientException);
+ :}
+ :
+ :
+ :int
+ :ProcQueryTree(ClientPtr client)
+ :{
+ : xQueryTreeReply reply;
+ : int rc, numChildren = 0;
+ : WindowPtr pChild, pWin, pHead;
+ : Window *childIDs = (Window *)NULL;
+ : REQUEST(xResourceReq);
+ :
+ : REQUEST_SIZE_MATCH(xResourceReq);
+ : rc = dixLookupWindow(&pWin, stuff->id, client, DixReadAccess);
+ : if (rc != Success)
+ : return rc;
+ : reply.type = X_Reply;
+ : reply.root = WindowTable[pWin->drawable.pScreen->myNum]->drawable.id;
+ : reply.sequenceNumber = client->sequence;
+ : if (pWin->parent)
+ : reply.parent = pWin->parent->drawable.id;
+ : else
+ : reply.parent = (Window)None;
+ : pHead = RealChildHead(pWin);
+ : for (pChild = pWin->lastChild; pChild != pHead; pChild = pChild->prevSib)
+ : numChildren++;
+ : if (numChildren)
+ : {
+ : int curChild = 0;
+ :
+ : childIDs = (Window *) ALLOCATE_LOCAL(numChildren * sizeof(Window));
+ : if (!childIDs)
+ : return BadAlloc;
+ : for (pChild = pWin->lastChild; pChild != pHead; pChild = pChild->prevSib)
+ : childIDs[curChild++] = pChild->drawable.id;
+ : }
+ :
+ : reply.nChildren = numChildren;
+ : reply.length = (numChildren * sizeof(Window)) >> 2;
+ :
+ : WriteReplyToClient(client, sizeof(xQueryTreeReply), &reply);
+ : if (numChildren)
+ : {
+ : client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
+ : WriteSwappedDataToClient(client, numChildren * sizeof(Window), childIDs);
+ : DEALLOCATE_LOCAL(childIDs);
+ : }
+ :
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcInternAtom(ClientPtr client)
+ :{
+ : Atom atom;
+ : char *tchar;
+ : REQUEST(xInternAtomReq);
+ :
+ : REQUEST_FIXED_SIZE(xInternAtomReq, stuff->nbytes);
+ : if ((stuff->onlyIfExists != xTrue) && (stuff->onlyIfExists != xFalse))
+ : {
+ : client->errorValue = stuff->onlyIfExists;
+ : return(BadValue);
+ : }
+ : tchar = (char *) &stuff[1];
+ : atom = MakeAtom(tchar, stuff->nbytes, !stuff->onlyIfExists);
+ : if (atom != BAD_RESOURCE)
+ : {
+ : xInternAtomReply reply;
+ : reply.type = X_Reply;
+ : reply.length = 0;
+ : reply.sequenceNumber = client->sequence;
+ : reply.atom = atom;
+ : WriteReplyToClient(client, sizeof(xInternAtomReply), &reply);
+ : return(client->noClientException);
+ : }
+ : else
+ : return (BadAlloc);
+ :}
+ :
+ :int
+ :ProcGetAtomName(ClientPtr client)
+ :{
+ : char *str;
+ : xGetAtomNameReply reply;
+ : int len;
+ : REQUEST(xResourceReq);
+ :
+ : REQUEST_SIZE_MATCH(xResourceReq);
+ : if ( (str = NameForAtom(stuff->id)) )
+ : {
+ : len = strlen(str);
+ : reply.type = X_Reply;
+ : reply.length = (len + 3) >> 2;
+ : reply.sequenceNumber = client->sequence;
+ : reply.nameLength = len;
+ : WriteReplyToClient(client, sizeof(xGetAtomNameReply), &reply);
+ : (void)WriteToClient(client, len, str);
+ : return(client->noClientException);
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->id;
+ : return (BadAtom);
+ : }
+ :}
+ :
+ :int
+ :ProcSetSelectionOwner(ClientPtr client)
+ :{
+ : WindowPtr pWin;
+ : TimeStamp time;
+ : REQUEST(xSetSelectionOwnerReq);
+ :
+ : REQUEST_SIZE_MATCH(xSetSelectionOwnerReq);
+ : UpdateCurrentTime();
+ : time = ClientTimeToServerTime(stuff->time);
+ :
+ : /* If the client's time stamp is in the future relative to the server's
+ : time stamp, do not set the selection, just return success. */
+ : if (CompareTimeStamps(time, currentTime) == LATER)
+ : return Success;
+ : if (stuff->window != None)
+ : {
+ : int rc = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess);
+ : if (rc != Success)
+ : return rc;
+ : }
+ : else
+ : pWin = (WindowPtr)None;
+ : if (ValidAtom(stuff->selection))
+ : {
+ : int i = 0;
+ :
+ : /*
+ : * First, see if the selection is already set...
+ : */
+ : while ((i < NumCurrentSelections) &&
+ : CurrentSelections[i].selection != stuff->selection)
+ : i++;
+ : if (i < NumCurrentSelections)
+ : {
+ : xEvent event;
+ :
+ : /* If the timestamp in client's request is in the past relative
+ : to the time stamp indicating the last time the owner of the
+ : selection was set, do not set the selection, just return
+ : success. */
+ : if (CompareTimeStamps(time, CurrentSelections[i].lastTimeChanged)
+ : == EARLIER)
+ : return Success;
+ : if (CurrentSelections[i].client &&
+ : (!pWin || (CurrentSelections[i].client != client)))
+ : {
+ : event.u.u.type = SelectionClear;
+ : event.u.selectionClear.time = time.milliseconds;
+ : event.u.selectionClear.window = CurrentSelections[i].window;
+ : event.u.selectionClear.atom = CurrentSelections[i].selection;
+ : (void) TryClientEvents (CurrentSelections[i].client, &event, 1,
+ : NoEventMask, NoEventMask /* CantBeFiltered */,
+ : NullGrab);
+ : }
+ : }
+ : else
+ : {
+ : /*
+ : * It doesn't exist, so add it...
+ : */
+ : Selection *newsels;
+ :
+ : if (i == 0)
+ : newsels = (Selection *)xalloc(sizeof(Selection));
+ : else
+ : newsels = (Selection *)xrealloc(CurrentSelections,
+ : (NumCurrentSelections + 1) * sizeof(Selection));
+ : if (!newsels)
+ : return BadAlloc;
+ : NumCurrentSelections++;
+ : CurrentSelections = newsels;
+ : CurrentSelections[i].selection = stuff->selection;
+ : }
+ : CurrentSelections[i].lastTimeChanged = time;
+ : CurrentSelections[i].window = stuff->window;
+ : CurrentSelections[i].pWin = pWin;
+ : CurrentSelections[i].client = (pWin ? client : NullClient);
+ : if (SelectionCallback)
+ : {
+ : SelectionInfoRec info;
+ :
+ : info.selection = &CurrentSelections[i];
+ : info.kind= SelectionSetOwner;
+ : CallCallbacks(&SelectionCallback, &info);
+ : }
+ : return (client->noClientException);
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->selection;
+ : return (BadAtom);
+ : }
+ :}
+ :
+ :int
+ :ProcGetSelectionOwner(ClientPtr client)
+ :{
+ : REQUEST(xResourceReq);
+ :
+ : REQUEST_SIZE_MATCH(xResourceReq);
+ : if (ValidAtom(stuff->id))
+ : {
+ : int i;
+ : xGetSelectionOwnerReply reply;
+ :
+ : i = 0;
+ : while ((i < NumCurrentSelections) &&
+ : CurrentSelections[i].selection != stuff->id) i++;
+ : reply.type = X_Reply;
+ : reply.length = 0;
+ : reply.sequenceNumber = client->sequence;
+ : if (i < NumCurrentSelections)
+ : reply.owner = CurrentSelections[i].window;
+ : else
+ : reply.owner = None;
+ : WriteReplyToClient(client, sizeof(xGetSelectionOwnerReply), &reply);
+ : return(client->noClientException);
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->id;
+ : return (BadAtom);
+ : }
+ :}
+ :
+ :int
+ :ProcConvertSelection(ClientPtr client)
+ :{
+ : Bool paramsOkay;
+ : xEvent event;
+ : WindowPtr pWin;
+ : REQUEST(xConvertSelectionReq);
+ : int rc;
+ :
+ : REQUEST_SIZE_MATCH(xConvertSelectionReq);
+ : rc = dixLookupWindow(&pWin, stuff->requestor, client, DixReadAccess);
+ : if (rc != Success)
+ : return rc;
+ :
+ : paramsOkay = (ValidAtom(stuff->selection) && ValidAtom(stuff->target));
+ : if (stuff->property != None)
+ : paramsOkay &= ValidAtom(stuff->property);
+ : if (paramsOkay)
+ : {
+ : int i;
+ :
+ : i = 0;
+ : while ((i < NumCurrentSelections) &&
+ : CurrentSelections[i].selection != stuff->selection) i++;
+ : if ((i < NumCurrentSelections) &&
+ : (CurrentSelections[i].window != None) &&
+ : XaceHook(XACE_RESOURCE_ACCESS, client,
+ : CurrentSelections[i].window, RT_WINDOW,
+ : DixReadAccess, CurrentSelections[i].pWin))
+ : {
+ : event.u.u.type = SelectionRequest;
+ : event.u.selectionRequest.time = stuff->time;
+ : event.u.selectionRequest.owner =
+ : CurrentSelections[i].window;
+ : event.u.selectionRequest.requestor = stuff->requestor;
+ : event.u.selectionRequest.selection = stuff->selection;
+ : event.u.selectionRequest.target = stuff->target;
+ : event.u.selectionRequest.property = stuff->property;
+ : if (TryClientEvents(
+ : CurrentSelections[i].client, &event, 1, NoEventMask,
+ : NoEventMask /* CantBeFiltered */, NullGrab))
+ : return (client->noClientException);
+ : }
+ : event.u.u.type = SelectionNotify;
+ : event.u.selectionNotify.time = stuff->time;
+ : event.u.selectionNotify.requestor = stuff->requestor;
+ : event.u.selectionNotify.selection = stuff->selection;
+ : event.u.selectionNotify.target = stuff->target;
+ : event.u.selectionNotify.property = None;
+ : (void) TryClientEvents(client, &event, 1, NoEventMask,
+ : NoEventMask /* CantBeFiltered */, NullGrab);
+ : return (client->noClientException);
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->property;
+ : return (BadAtom);
+ : }
+ :}
+ :
+ :int
+ :ProcGrabServer(ClientPtr client)
+ :{
+ : REQUEST_SIZE_MATCH(xReq);
+ : if (grabState != GrabNone && client != grabClient)
+ : {
+ : ResetCurrentRequest(client);
+ : client->sequence--;
+ : BITSET(grabWaiters, client->index);
+ : IgnoreClient(client);
+ : return(client->noClientException);
+ : }
+ : OnlyListenToOneClient(client);
+ : grabState = GrabKickout;
+ : grabClient = client;
+ :
+ : if (ServerGrabCallback)
+ : {
+ : ServerGrabInfoRec grabinfo;
+ : grabinfo.client = client;
+ : grabinfo.grabstate = SERVER_GRABBED;
+ : CallCallbacks(&ServerGrabCallback, (pointer)&grabinfo);
+ : }
+ :
+ : return(client->noClientException);
+ :}
+ :
+ :static void
+ :UngrabServer(ClientPtr client)
+ :{
+ : int i;
+ :
+ : grabState = GrabNone;
+ : ListenToAllClients();
+ : for (i = mskcnt; --i >= 0 && !grabWaiters[i]; )
+ : ;
+ : if (i >= 0)
+ : {
+ : i <<= 5;
+ : while (!GETBIT(grabWaiters, i))
+ : i++;
+ : BITCLEAR(grabWaiters, i);
+ : AttendClient(clients[i]);
+ : }
+ :
+ : if (ServerGrabCallback)
+ : {
+ : ServerGrabInfoRec grabinfo;
+ : grabinfo.client = client;
+ : grabinfo.grabstate = SERVER_UNGRABBED;
+ : CallCallbacks(&ServerGrabCallback, (pointer)&grabinfo);
+ : }
+ :}
+ :
+ :int
+ :ProcUngrabServer(ClientPtr client)
+ :{
+ : REQUEST_SIZE_MATCH(xReq);
+ : UngrabServer(client);
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcTranslateCoords(ClientPtr client)
+ :{
+ : REQUEST(xTranslateCoordsReq);
+ :
+ : WindowPtr pWin, pDst;
+ : xTranslateCoordsReply rep;
+ : int rc;
+ :
+ : REQUEST_SIZE_MATCH(xTranslateCoordsReq);
+ : rc = dixLookupWindow(&pWin, stuff->srcWid, client, DixReadAccess);
+ : if (rc != Success)
+ : return rc;
+ : rc = dixLookupWindow(&pDst, stuff->dstWid, client, DixReadAccess);
+ : if (rc != Success)
+ : return rc;
+ : rep.type = X_Reply;
+ : rep.length = 0;
+ : rep.sequenceNumber = client->sequence;
+ : if (!SAME_SCREENS(pWin->drawable, pDst->drawable))
+ : {
+ : rep.sameScreen = xFalse;
+ : rep.child = None;
+ : rep.dstX = rep.dstY = 0;
+ : }
+ : else
+ : {
+ : INT16 x, y;
+ : rep.sameScreen = xTrue;
+ : rep.child = None;
+ : /* computing absolute coordinates -- adjust to destination later */
+ : x = pWin->drawable.x + stuff->srcX;
+ : y = pWin->drawable.y + stuff->srcY;
+ : pWin = pDst->firstChild;
+ : while (pWin)
+ : {
+ :#ifdef SHAPE
+ : BoxRec box;
+ :#endif
+ : if ((pWin->mapped) &&
+ : (x >= pWin->drawable.x - wBorderWidth (pWin)) &&
+ : (x < pWin->drawable.x + (int)pWin->drawable.width +
+ : wBorderWidth (pWin)) &&
+ : (y >= pWin->drawable.y - wBorderWidth (pWin)) &&
+ : (y < pWin->drawable.y + (int)pWin->drawable.height +
+ : wBorderWidth (pWin))
+ :#ifdef SHAPE
+ : /* When a window is shaped, a further check
+ : * is made to see if the point is inside
+ : * borderSize
+ : */
+ : && (!wBoundingShape(pWin) ||
+ : POINT_IN_REGION(pWin->drawable.pScreen,
+ : &pWin->borderSize, x, y, &box))
+ :
+ : && (!wInputShape(pWin) ||
+ : POINT_IN_REGION(pWin->drawable.pScreen,
+ : wInputShape(pWin),
+ : x - pWin->drawable.x,
+ : y - pWin->drawable.y, &box))
+ :#endif
+ : )
+ : {
+ : rep.child = pWin->drawable.id;
+ : pWin = (WindowPtr) NULL;
+ : }
+ : else
+ : pWin = pWin->nextSib;
+ : }
+ : /* adjust to destination coordinates */
+ : rep.dstX = x - pDst->drawable.x;
+ : rep.dstY = y - pDst->drawable.y;
+ : }
+ : WriteReplyToClient(client, sizeof(xTranslateCoordsReply), &rep);
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcOpenFont(ClientPtr client)
+ :{
+ : int err;
+ : REQUEST(xOpenFontReq);
+ :
+ : REQUEST_FIXED_SIZE(xOpenFontReq, stuff->nbytes);
+ : client->errorValue = stuff->fid;
+ : LEGAL_NEW_RESOURCE(stuff->fid, client);
+ : err = OpenFont(client, stuff->fid, (Mask) 0,
+ : stuff->nbytes, (char *)&stuff[1]);
+ : if (err == Success)
+ : {
+ : return(client->noClientException);
+ : }
+ : else
+ : return err;
+ :}
+ :
+ :int
+ :ProcCloseFont(ClientPtr client)
+ :{
+ : FontPtr pFont;
+ : REQUEST(xResourceReq);
+ :
+ : REQUEST_SIZE_MATCH(xResourceReq);
+ : pFont = (FontPtr)SecurityLookupIDByType(client, stuff->id, RT_FONT,
+ : DixDestroyAccess);
+ : if ( pFont != (FontPtr)NULL) /* id was valid */
+ : {
+ : FreeResource(stuff->id, RT_NONE);
+ : return(client->noClientException);
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->id;
+ : return (BadFont);
+ : }
+ :}
+ :
+ :int
+ :ProcQueryFont(ClientPtr client)
+ :{
+ : xQueryFontReply *reply;
+ : FontPtr pFont;
+ : GC *pGC;
+ : REQUEST(xResourceReq);
+ :
+ : REQUEST_SIZE_MATCH(xResourceReq);
+ : client->errorValue = stuff->id; /* EITHER font or gc */
+ : pFont = (FontPtr)SecurityLookupIDByType(client, stuff->id, RT_FONT,
+ : DixReadAccess);
+ : if (!pFont)
+ : {
+ : pGC = (GC *) SecurityLookupIDByType(client, stuff->id, RT_GC,
+ : DixReadAccess);
+ : if (!pGC)
+ : {
+ : client->errorValue = stuff->id;
+ : return(BadFont); /* procotol spec says only error is BadFont */
+ : }
+ : pFont = pGC->font;
+ : }
+ :
+ : {
+ : xCharInfo *pmax = FONTINKMAX(pFont);
+ : xCharInfo *pmin = FONTINKMIN(pFont);
+ : int nprotoxcistructs;
+ : int rlength;
+ :
+ : nprotoxcistructs = (
+ : pmax->rightSideBearing == pmin->rightSideBearing &&
+ : pmax->leftSideBearing == pmin->leftSideBearing &&
+ : pmax->descent == pmin->descent &&
+ : pmax->ascent == pmin->ascent &&
+ : pmax->characterWidth == pmin->characterWidth) ?
+ : 0 : N2dChars(pFont);
+ :
+ : rlength = sizeof(xQueryFontReply) +
+ : FONTINFONPROPS(FONTCHARSET(pFont)) * sizeof(xFontProp) +
+ : nprotoxcistructs * sizeof(xCharInfo);
+ : reply = (xQueryFontReply *)ALLOCATE_LOCAL(rlength);
+ : if(!reply)
+ : {
+ : return(BadAlloc);
+ : }
+ :
+ : reply->type = X_Reply;
+ : reply->length = (rlength - sizeof(xGenericReply)) >> 2;
+ : reply->sequenceNumber = client->sequence;
+ : QueryFont( pFont, reply, nprotoxcistructs);
+ :
+ : WriteReplyToClient(client, rlength, reply);
+ : DEALLOCATE_LOCAL(reply);
+ : return(client->noClientException);
+ : }
+ :}
+ :
+ :int
+ :ProcQueryTextExtents(ClientPtr client)
+ :{
+ : REQUEST(xQueryTextExtentsReq);
+ : xQueryTextExtentsReply reply;
+ : FontPtr pFont;
+ : GC *pGC;
+ : ExtentInfoRec info;
+ : unsigned long length;
+ :
+ : REQUEST_AT_LEAST_SIZE(xQueryTextExtentsReq);
+ :
+ : pFont = (FontPtr)SecurityLookupIDByType(client, stuff->fid, RT_FONT,
+ : DixReadAccess);
+ : if (!pFont)
+ : {
+ : pGC = (GC *)SecurityLookupIDByType(client, stuff->fid, RT_GC,
+ : DixReadAccess);
+ : if (!pGC)
+ : {
+ : client->errorValue = stuff->fid;
+ : return(BadFont);
+ : }
+ : pFont = pGC->font;
+ : }
+ : length = client->req_len - (sizeof(xQueryTextExtentsReq) >> 2);
+ : length = length << 1;
+ : if (stuff->oddLength)
+ : {
+ : if (length == 0)
+ : return(BadLength);
+ : length--;
+ : }
+ : if (!QueryTextExtents(pFont, length, (unsigned char *)&stuff[1], &info))
+ : return(BadAlloc);
+ : reply.type = X_Reply;
+ : reply.length = 0;
+ : reply.sequenceNumber = client->sequence;
+ : reply.drawDirection = info.drawDirection;
+ : reply.fontAscent = info.fontAscent;
+ : reply.fontDescent = info.fontDescent;
+ : reply.overallAscent = info.overallAscent;
+ : reply.overallDescent = info.overallDescent;
+ : reply.overallWidth = info.overallWidth;
+ : reply.overallLeft = info.overallLeft;
+ : reply.overallRight = info.overallRight;
+ : WriteReplyToClient(client, sizeof(xQueryTextExtentsReply), &reply);
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcListFonts(ClientPtr client)
+ :{
+ : REQUEST(xListFontsReq);
+ :
+ : REQUEST_FIXED_SIZE(xListFontsReq, stuff->nbytes);
+ :
+ : return ListFonts(client, (unsigned char *) &stuff[1], stuff->nbytes,
+ : stuff->maxNames);
+ :}
+ :
+ :int
+ :ProcListFontsWithInfo(ClientPtr client)
+ :{
+ : REQUEST(xListFontsWithInfoReq);
+ :
+ : REQUEST_FIXED_SIZE(xListFontsWithInfoReq, stuff->nbytes);
+ :
+ : return StartListFontsWithInfo(client, stuff->nbytes,
+ : (unsigned char *) &stuff[1], stuff->maxNames);
+ :}
+ :
+ :/**
+ : *
+ : * \param value must conform to DeleteType
+ : */
+ :int
+ :dixDestroyPixmap(pointer value, XID pid)
+ :{
+ : PixmapPtr pPixmap = (PixmapPtr)value;
+ : return (*pPixmap->drawable.pScreen->DestroyPixmap)(pPixmap);
+ :}
+ :
+ :int
+ :ProcCreatePixmap(ClientPtr client)
+ 1 0.0011 :{ /* ProcCreatePixmap total: 9 0.0098 */
+ : PixmapPtr pMap;
+ : DrawablePtr pDraw;
+ : REQUEST(xCreatePixmapReq);
+ : DepthPtr pDepth;
+ : int i, rc;
+ :
+ : REQUEST_SIZE_MATCH(xCreatePixmapReq);
+ : client->errorValue = stuff->pid;
+ 1 0.0011 : LEGAL_NEW_RESOURCE(stuff->pid, client);
+ :
+ 1 0.0011 : rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
+ : DixReadAccess);
+ : if (rc != Success)
+ : return rc;
+ :
+ : if (!stuff->width || !stuff->height)
+ : {
+ : client->errorValue = 0;
+ : return BadValue;
+ : }
+ 1 0.0011 : if (stuff->width > 32767 || stuff->height > 32767)
+ : {
+ : /* It is allowed to try and allocate a pixmap which is larger than
+ : * 32767 in either dimension. However, all of the framebuffer code
+ : * is buggy and does not reliably draw to such big pixmaps, basically
+ : * because the Region data structure operates with signed shorts
+ : * for the rectangles in it.
+ : *
+ : * Furthermore, several places in the X server computes the
+ : * size in bytes of the pixmap and tries to store it in an
+ : * integer. This integer can overflow and cause the allocated size
+ : * to be much smaller.
+ : *
+ : * So, such big pixmaps are rejected here with a BadAlloc
+ : */
+ : return BadAlloc;
+ : }
+ : if (stuff->depth != 1)
+ : {
+ 1 0.0011 : pDepth = pDraw->pScreen->allowedDepths;
+ 1 0.0011 : for (i=0; i<pDraw->pScreen->numDepths; i++, pDepth++)
+ 2 0.0022 : if (pDepth->depth == stuff->depth)
+ : goto CreatePmap;
+ : client->errorValue = stuff->depth;
+ : return BadValue;
+ : }
+ :CreatePmap:
+ 1 0.0011 : pMap = (PixmapPtr)(*pDraw->pScreen->CreatePixmap)
+ : (pDraw->pScreen, stuff->width,
+ : stuff->height, stuff->depth);
+ : if (pMap)
+ : {
+ : pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ : pMap->drawable.id = stuff->pid;
+ : if (AddResource(stuff->pid, RT_PIXMAP, (pointer)pMap))
+ : return(client->noClientException);
+ : }
+ : return (BadAlloc);
+ :}
+ :
+ :int
+ :ProcFreePixmap(ClientPtr client)
+ 1 0.0011 :{ /* ProcFreePixmap total: 6 0.0065 */
+ : PixmapPtr pMap;
+ :
+ : REQUEST(xResourceReq);
+ :
+ 4 0.0044 : REQUEST_SIZE_MATCH(xResourceReq);
+ : pMap = (PixmapPtr)SecurityLookupIDByType(client, stuff->id, RT_PIXMAP,
+ : DixDestroyAccess);
+ : if (pMap)
+ : {
+ 1 0.0011 : FreeResource(stuff->id, RT_NONE);
+ : return(client->noClientException);
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->id;
+ : return (BadPixmap);
+ : }
+ :}
+ :
+ :int
+ :ProcCreateGC(ClientPtr client)
+ :{
+ : int error, rc;
+ : GC *pGC;
+ : DrawablePtr pDraw;
+ : unsigned len;
+ : REQUEST(xCreateGCReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xCreateGCReq);
+ : client->errorValue = stuff->gc;
+ : LEGAL_NEW_RESOURCE(stuff->gc, client);
+ : rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixReadAccess);
+ : if (rc != Success)
+ : return rc;
+ :
+ : len = client->req_len - (sizeof(xCreateGCReq) >> 2);
+ : if (len != Ones(stuff->mask))
+ : return BadLength;
+ : pGC = (GC *)CreateGC(pDraw, stuff->mask,
+ : (XID *) &stuff[1], &error);
+ : if (error != Success)
+ : return error;
+ : if (!AddResource(stuff->gc, RT_GC, (pointer)pGC))
+ : return (BadAlloc);
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcChangeGC(ClientPtr client)
+ 1 0.0011 :{ /* ProcChangeGC total: 1 0.0011 */
+ : GC *pGC;
+ : int result;
+ : unsigned len;
+ : REQUEST(xChangeGCReq);
+ : REQUEST_AT_LEAST_SIZE(xChangeGCReq);
+ :
+ : result = dixLookupGC(&pGC, stuff->gc, client, DixWriteAccess);
+ : if (result != Success)
+ : return result;
+ :
+ : len = client->req_len - (sizeof(xChangeGCReq) >> 2);
+ : if (len != Ones(stuff->mask))
+ : return BadLength;
+ :
+ : result = dixChangeGC(client, pGC, stuff->mask, (CARD32 *) &stuff[1], 0);
+ : if (client->noClientException != Success)
+ : return(client->noClientException);
+ : else
+ : {
+ : client->errorValue = clientErrorValue;
+ : return(result);
+ : }
+ :}
+ :
+ :int
+ :ProcCopyGC(ClientPtr client)
+ :{
+ : GC *dstGC;
+ : GC *pGC;
+ : int result;
+ : REQUEST(xCopyGCReq);
+ : REQUEST_SIZE_MATCH(xCopyGCReq);
+ :
+ : result = dixLookupGC(&pGC, stuff->srcGC, client, DixReadAccess);
+ : if (result != Success)
+ : return result;
+ : result = dixLookupGC(&dstGC, stuff->dstGC, client, DixWriteAccess);
+ : if (result != Success)
+ : return result;
+ : if ((dstGC->pScreen != pGC->pScreen) || (dstGC->depth != pGC->depth))
+ : return (BadMatch);
+ : result = CopyGC(pGC, dstGC, stuff->mask);
+ : if (client->noClientException != Success)
+ : return(client->noClientException);
+ : else
+ : {
+ : client->errorValue = clientErrorValue;
+ : return(result);
+ : }
+ :}
+ :
+ :int
+ :ProcSetDashes(ClientPtr client)
+ :{
+ : GC *pGC;
+ : int result;
+ : REQUEST(xSetDashesReq);
+ :
+ : REQUEST_FIXED_SIZE(xSetDashesReq, stuff->nDashes);
+ : if (stuff->nDashes == 0)
+ : {
+ : client->errorValue = 0;
+ : return BadValue;
+ : }
+ :
+ : result = dixLookupGC(&pGC,stuff->gc, client, DixWriteAccess);
+ : if (result != Success)
+ : return result;
+ :
+ : result = SetDashes(pGC, stuff->dashOffset, stuff->nDashes,
+ : (unsigned char *)&stuff[1]);
+ : if (client->noClientException != Success)
+ : return(client->noClientException);
+ : else
+ : {
+ : client->errorValue = clientErrorValue;
+ : return(result);
+ : }
+ :}
+ :
+ :int
+ :ProcSetClipRectangles(ClientPtr client)
+ :{ /* ProcSetClipRectangles total: 1 0.0011 */
+ : int nr, result;
+ : GC *pGC;
+ : REQUEST(xSetClipRectanglesReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xSetClipRectanglesReq);
+ : if ((stuff->ordering != Unsorted) && (stuff->ordering != YSorted) &&
+ : (stuff->ordering != YXSorted) && (stuff->ordering != YXBanded))
+ : {
+ : client->errorValue = stuff->ordering;
+ : return BadValue;
+ : }
+ 1 0.0011 : result = dixLookupGC(&pGC,stuff->gc, client, DixWriteAccess);
+ : if (result != Success)
+ : return result;
+ :
+ : nr = (client->req_len << 2) - sizeof(xSetClipRectanglesReq);
+ : if (nr & 4)
+ : return(BadLength);
+ : nr >>= 3;
+ : result = SetClipRects(pGC, stuff->xOrigin, stuff->yOrigin,
+ : nr, (xRectangle *)&stuff[1], (int)stuff->ordering);
+ : if (client->noClientException != Success)
+ : return(client->noClientException);
+ : else
+ : return(result);
+ :}
+ :
+ :int
+ :ProcFreeGC(ClientPtr client)
+ :{
+ : GC *pGC;
+ : int rc;
+ : REQUEST(xResourceReq);
+ : REQUEST_SIZE_MATCH(xResourceReq);
+ :
+ : rc = dixLookupGC(&pGC, stuff->id, client, DixDestroyAccess);
+ : if (rc != Success)
+ : return rc;
+ :
+ : FreeResource(stuff->id, RT_NONE);
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcClearToBackground(ClientPtr client)
+ :{
+ : REQUEST(xClearAreaReq);
+ : WindowPtr pWin;
+ : int rc;
+ :
+ : REQUEST_SIZE_MATCH(xClearAreaReq);
+ : rc = dixLookupWindow(&pWin, stuff->window, client, DixWriteAccess);
+ : if (rc != Success)
+ : return rc;
+ : if (pWin->drawable.class == InputOnly)
+ : {
+ : client->errorValue = stuff->window;
+ : return (BadMatch);
+ : }
+ : if ((stuff->exposures != xTrue) && (stuff->exposures != xFalse))
+ : {
+ : client->errorValue = stuff->exposures;
+ : return(BadValue);
+ : }
+ : (*pWin->drawable.pScreen->ClearToBackground)(pWin, stuff->x, stuff->y,
+ : stuff->width, stuff->height,
+ : (Bool)stuff->exposures);
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcCopyArea(ClientPtr client)
+ 1 0.0011 :{ /* ProcCopyArea total: 1 0.0011 */
+ : DrawablePtr pDst;
+ : DrawablePtr pSrc;
+ : GC *pGC;
+ : REQUEST(xCopyAreaReq);
+ : RegionPtr pRgn;
+ : int rc;
+ :
+ : REQUEST_SIZE_MATCH(xCopyAreaReq);
+ :
+ : VALIDATE_DRAWABLE_AND_GC(stuff->dstDrawable, pDst, pGC, client);
+ : if (stuff->dstDrawable != stuff->srcDrawable)
+ : {
+ : rc = dixLookupDrawable(&pSrc, stuff->srcDrawable, client, 0,
+ : DixReadAccess);
+ : if (rc != Success)
+ : return rc;
+ : if ((pDst->pScreen != pSrc->pScreen) || (pDst->depth != pSrc->depth))
+ : {
+ : client->errorValue = stuff->dstDrawable;
+ : return (BadMatch);
+ : }
+ : }
+ : else
+ : pSrc = pDst;
+ :
+ : pRgn = (*pGC->ops->CopyArea)(pSrc, pDst, pGC, stuff->srcX, stuff->srcY,
+ : stuff->width, stuff->height,
+ : stuff->dstX, stuff->dstY);
+ : if (pGC->graphicsExposures)
+ : {
+ : (*pDst->pScreen->SendGraphicsExpose)
+ : (client, pRgn, stuff->dstDrawable, X_CopyArea, 0);
+ : if (pRgn)
+ : REGION_DESTROY(pDst->pScreen, pRgn);
+ : }
+ :
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcCopyPlane(ClientPtr client)
+ :{
+ : DrawablePtr psrcDraw, pdstDraw;
+ : GC *pGC;
+ : REQUEST(xCopyPlaneReq);
+ : RegionPtr pRgn;
+ : int rc;
+ :
+ : REQUEST_SIZE_MATCH(xCopyPlaneReq);
+ :
+ : VALIDATE_DRAWABLE_AND_GC(stuff->dstDrawable, pdstDraw, pGC, client);
+ : if (stuff->dstDrawable != stuff->srcDrawable)
+ : {
+ : rc = dixLookupDrawable(&psrcDraw, stuff->srcDrawable, client, 0,
+ : DixReadAccess);
+ : if (rc != Success)
+ : return rc;
+ :
+ : if (pdstDraw->pScreen != psrcDraw->pScreen)
+ : {
+ : client->errorValue = stuff->dstDrawable;
+ : return (BadMatch);
+ : }
+ : }
+ : else
+ : psrcDraw = pdstDraw;
+ :
+ : /* Check to see if stuff->bitPlane has exactly ONE good bit set */
+ : if(stuff->bitPlane == 0 || (stuff->bitPlane & (stuff->bitPlane - 1)) ||
+ : (stuff->bitPlane > (1L << (psrcDraw->depth - 1))))
+ : {
+ : client->errorValue = stuff->bitPlane;
+ : return(BadValue);
+ : }
+ :
+ : pRgn = (*pGC->ops->CopyPlane)(psrcDraw, pdstDraw, pGC, stuff->srcX, stuff->srcY,
+ : stuff->width, stuff->height,
+ : stuff->dstX, stuff->dstY, stuff->bitPlane);
+ : if (pGC->graphicsExposures)
+ : {
+ : (*pdstDraw->pScreen->SendGraphicsExpose)
+ : (client, pRgn, stuff->dstDrawable, X_CopyPlane, 0);
+ : if (pRgn)
+ : REGION_DESTROY(pdstDraw->pScreen, pRgn);
+ : }
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcPolyPoint(ClientPtr client)
+ :{
+ : int npoint;
+ : GC *pGC;
+ : DrawablePtr pDraw;
+ : REQUEST(xPolyPointReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xPolyPointReq);
+ : if ((stuff->coordMode != CoordModeOrigin) &&
+ : (stuff->coordMode != CoordModePrevious))
+ : {
+ : client->errorValue = stuff->coordMode;
+ : return BadValue;
+ : }
+ : VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client);
+ : npoint = ((client->req_len << 2) - sizeof(xPolyPointReq)) >> 2;
+ : if (npoint)
+ : (*pGC->ops->PolyPoint)(pDraw, pGC, stuff->coordMode, npoint,
+ : (xPoint *) &stuff[1]);
+ : return (client->noClientException);
+ :}
+ :
+ :int
+ :ProcPolyLine(ClientPtr client)
+ :{
+ : int npoint;
+ : GC *pGC;
+ : DrawablePtr pDraw;
+ : REQUEST(xPolyLineReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xPolyLineReq);
+ : if ((stuff->coordMode != CoordModeOrigin) &&
+ : (stuff->coordMode != CoordModePrevious))
+ : {
+ : client->errorValue = stuff->coordMode;
+ : return BadValue;
+ : }
+ : VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client);
+ : npoint = ((client->req_len << 2) - sizeof(xPolyLineReq)) >> 2;
+ : if (npoint > 1)
+ : (*pGC->ops->Polylines)(pDraw, pGC, stuff->coordMode, npoint,
+ : (DDXPointPtr) &stuff[1]);
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcPolySegment(ClientPtr client)
+ :{
+ : int nsegs;
+ : GC *pGC;
+ : DrawablePtr pDraw;
+ : REQUEST(xPolySegmentReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xPolySegmentReq);
+ : VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client);
+ : nsegs = (client->req_len << 2) - sizeof(xPolySegmentReq);
+ : if (nsegs & 4)
+ : return(BadLength);
+ : nsegs >>= 3;
+ : if (nsegs)
+ : (*pGC->ops->PolySegment)(pDraw, pGC, nsegs, (xSegment *) &stuff[1]);
+ : return (client->noClientException);
+ :}
+ :
+ :int
+ :ProcPolyRectangle (ClientPtr client)
+ :{
+ : int nrects;
+ : GC *pGC;
+ : DrawablePtr pDraw;
+ : REQUEST(xPolyRectangleReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xPolyRectangleReq);
+ : VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client);
+ : nrects = (client->req_len << 2) - sizeof(xPolyRectangleReq);
+ : if (nrects & 4)
+ : return(BadLength);
+ : nrects >>= 3;
+ : if (nrects)
+ : (*pGC->ops->PolyRectangle)(pDraw, pGC,
+ : nrects, (xRectangle *) &stuff[1]);
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcPolyArc(ClientPtr client)
+ :{
+ : int narcs;
+ : GC *pGC;
+ : DrawablePtr pDraw;
+ : REQUEST(xPolyArcReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xPolyArcReq);
+ : VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client);
+ : narcs = (client->req_len << 2) - sizeof(xPolyArcReq);
+ : if (narcs % sizeof(xArc))
+ : return(BadLength);
+ : narcs /= sizeof(xArc);
+ : if (narcs)
+ : (*pGC->ops->PolyArc)(pDraw, pGC, narcs, (xArc *) &stuff[1]);
+ : return (client->noClientException);
+ :}
+ :
+ :int
+ :ProcFillPoly(ClientPtr client)
+ :{
+ : int things;
+ : GC *pGC;
+ : DrawablePtr pDraw;
+ : REQUEST(xFillPolyReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xFillPolyReq);
+ : if ((stuff->shape != Complex) && (stuff->shape != Nonconvex) &&
+ : (stuff->shape != Convex))
+ : {
+ : client->errorValue = stuff->shape;
+ : return BadValue;
+ : }
+ : if ((stuff->coordMode != CoordModeOrigin) &&
+ : (stuff->coordMode != CoordModePrevious))
+ : {
+ : client->errorValue = stuff->coordMode;
+ : return BadValue;
+ : }
+ :
+ : VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client);
+ : things = ((client->req_len << 2) - sizeof(xFillPolyReq)) >> 2;
+ : if (things)
+ : (*pGC->ops->FillPolygon) (pDraw, pGC, stuff->shape,
+ : stuff->coordMode, things,
+ : (DDXPointPtr) &stuff[1]);
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcPolyFillRectangle(ClientPtr client)
+ :{ /* ProcPolyFillRectangle total: 1 0.0011 */
+ : int things;
+ : GC *pGC;
+ : DrawablePtr pDraw;
+ : REQUEST(xPolyFillRectangleReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xPolyFillRectangleReq);
+ : VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client);
+ : things = (client->req_len << 2) - sizeof(xPolyFillRectangleReq);
+ : if (things & 4)
+ : return(BadLength);
+ 1 0.0011 : things >>= 3;
+ :
+ : if (things)
+ : (*pGC->ops->PolyFillRect) (pDraw, pGC, things,
+ : (xRectangle *) &stuff[1]);
+ : return (client->noClientException);
+ :}
+ :
+ :int
+ :ProcPolyFillArc(ClientPtr client)
+ :{
+ : int narcs;
+ : GC *pGC;
+ : DrawablePtr pDraw;
+ : REQUEST(xPolyFillArcReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xPolyFillArcReq);
+ : VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client);
+ : narcs = (client->req_len << 2) - sizeof(xPolyFillArcReq);
+ : if (narcs % sizeof(xArc))
+ : return(BadLength);
+ : narcs /= sizeof(xArc);
+ : if (narcs)
+ : (*pGC->ops->PolyFillArc) (pDraw, pGC, narcs, (xArc *) &stuff[1]);
+ : return (client->noClientException);
+ :}
+ :
+ :#ifdef MATCH_CLIENT_ENDIAN
+ :
+ :int
+ :ServerOrder (void)
+ :{
+ : int whichbyte = 1;
+ :
+ : if (*((char *) &whichbyte))
+ : return LSBFirst;
+ : return MSBFirst;
+ :}
+ :
+ :#define ClientOrder(client) ((client)->swapped ? !ServerOrder() : ServerOrder())
+ :
+ :void
+ :ReformatImage (char *base, int nbytes, int bpp, int order)
+ :{
+ : switch (bpp) {
+ : case 1: /* yuck */
+ : if (BITMAP_BIT_ORDER != order)
+ : BitOrderInvert ((unsigned char *) base, nbytes);
+ :#if IMAGE_BYTE_ORDER != BITMAP_BIT_ORDER && BITMAP_SCANLINE_UNIT != 8
+ : ReformatImage (base, nbytes, BITMAP_SCANLINE_UNIT, order);
+ :#endif
+ : break;
+ : case 4:
+ : break; /* yuck */
+ : case 8:
+ : break;
+ : case 16:
+ : if (IMAGE_BYTE_ORDER != order)
+ : TwoByteSwap ((unsigned char *) base, nbytes);
+ : break;
+ : case 32:
+ : if (IMAGE_BYTE_ORDER != order)
+ : FourByteSwap ((unsigned char *) base, nbytes);
+ : break;
+ : }
+ :}
+ :#else
+ :#define ReformatImage(b,n,bpp,o)
+ :#endif
+ :
+ :/* 64-bit server notes: the protocol restricts padding of images to
+ : * 8-, 16-, or 32-bits. We would like to have 64-bits for the server
+ : * to use internally. Removes need for internal alignment checking.
+ : * All of the PutImage functions could be changed individually, but
+ : * as currently written, they call other routines which require things
+ : * to be 64-bit padded on scanlines, so we changed things here.
+ : * If an image would be padded differently for 64- versus 32-, then
+ : * copy each scanline to a 64-bit padded scanline.
+ : * Also, we need to make sure that the image is aligned on a 64-bit
+ : * boundary, even if the scanlines are padded to our satisfaction.
+ : */
+ :int
+ :ProcPutImage(ClientPtr client)
+ :{
+ : GC *pGC;
+ : DrawablePtr pDraw;
+ : long length; /* length of scanline server padded */
+ : long lengthProto; /* length of scanline protocol padded */
+ : char *tmpImage;
+ : REQUEST(xPutImageReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xPutImageReq);
+ : VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client);
+ : if (stuff->format == XYBitmap)
+ : {
+ : if ((stuff->depth != 1) ||
+ : (stuff->leftPad >= (unsigned int)screenInfo.bitmapScanlinePad))
+ : return BadMatch;
+ : length = BitmapBytePad(stuff->width + stuff->leftPad);
+ : }
+ : else if (stuff->format == XYPixmap)
+ : {
+ : if ((pDraw->depth != stuff->depth) ||
+ : (stuff->leftPad >= (unsigned int)screenInfo.bitmapScanlinePad))
+ : return BadMatch;
+ : length = BitmapBytePad(stuff->width + stuff->leftPad);
+ : length *= stuff->depth;
+ : }
+ : else if (stuff->format == ZPixmap)
+ : {
+ : if ((pDraw->depth != stuff->depth) || (stuff->leftPad != 0))
+ : return BadMatch;
+ : length = PixmapBytePad(stuff->width, stuff->depth);
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->format;
+ : return BadValue;
+ : }
+ :
+ : tmpImage = (char *)&stuff[1];
+ : lengthProto = length;
+ :
+ : if (((((lengthProto * stuff->height) + (unsigned)3) >> 2) +
+ : (sizeof(xPutImageReq) >> 2)) != client->req_len)
+ : return BadLength;
+ :
+ : ReformatImage (tmpImage, lengthProto * stuff->height,
+ : stuff->format == ZPixmap ? BitsPerPixel (stuff->depth) : 1,
+ : ClientOrder(client));
+ :
+ : (*pGC->ops->PutImage) (pDraw, pGC, stuff->depth, stuff->dstX, stuff->dstY,
+ : stuff->width, stuff->height,
+ : stuff->leftPad, stuff->format, tmpImage);
+ :
+ : return (client->noClientException);
+ :}
+ :
+ :static int
+ :DoGetImage(ClientPtr client, int format, Drawable drawable,
+ : int x, int y, int width, int height,
+ : Mask planemask, xGetImageReply **im_return)
+ :{
+ : DrawablePtr pDraw;
+ : int nlines, linesPerBuf, rc;
+ : int linesDone;
+ : long widthBytesLine, length;
+ : Mask plane = 0;
+ : char *pBuf;
+ : xGetImageReply xgi;
+ : RegionPtr pVisibleRegion = NULL;
+ :
+ : if ((format != XYPixmap) && (format != ZPixmap))
+ : {
+ : client->errorValue = format;
+ : return(BadValue);
+ : }
+ : rc = dixLookupDrawable(&pDraw, drawable, client, 0, DixReadAccess);
+ : if (rc != Success)
+ : return rc;
+ :
+ : if(pDraw->type == DRAWABLE_WINDOW)
+ : {
+ : if( /* check for being viewable */
+ : !((WindowPtr) pDraw)->realized ||
+ : /* check for being on screen */
+ : pDraw->x + x < 0 ||
+ : pDraw->x + x + width > pDraw->pScreen->width ||
+ : pDraw->y + y < 0 ||
+ : pDraw->y + y + height > pDraw->pScreen->height ||
+ : /* check for being inside of border */
+ : x < - wBorderWidth((WindowPtr)pDraw) ||
+ : x + width > wBorderWidth((WindowPtr)pDraw) + (int)pDraw->width ||
+ : y < -wBorderWidth((WindowPtr)pDraw) ||
+ : y + height > wBorderWidth ((WindowPtr)pDraw) + (int)pDraw->height
+ : )
+ : return(BadMatch);
+ : xgi.visual = wVisual (((WindowPtr) pDraw));
+ : }
+ : else
+ : {
+ : if(x < 0 ||
+ : x+width > (int)pDraw->width ||
+ : y < 0 ||
+ : y+height > (int)pDraw->height
+ : )
+ : return(BadMatch);
+ : xgi.visual = None;
+ : }
+ :
+ : xgi.type = X_Reply;
+ : xgi.sequenceNumber = client->sequence;
+ : xgi.depth = pDraw->depth;
+ : if(format == ZPixmap)
+ : {
+ : widthBytesLine = PixmapBytePad(width, pDraw->depth);
+ : length = widthBytesLine * height;
+ :
+ : }
+ : else
+ : {
+ : widthBytesLine = BitmapBytePad(width);
+ : plane = ((Mask)1) << (pDraw->depth - 1);
+ : /* only planes asked for */
+ : length = widthBytesLine * height *
+ : Ones(planemask & (plane | (plane - 1)));
+ :
+ : }
+ :
+ : xgi.length = length;
+ :
+ : if (im_return) {
+ : pBuf = (char *)xalloc(sz_xGetImageReply + length);
+ : if (!pBuf)
+ : return (BadAlloc);
+ : if (widthBytesLine == 0)
+ : linesPerBuf = 0;
+ : else
+ : linesPerBuf = height;
+ : *im_return = (xGetImageReply *)pBuf;
+ : *(xGetImageReply *)pBuf = xgi;
+ : pBuf += sz_xGetImageReply;
+ : } else {
+ : xgi.length = (xgi.length + 3) >> 2;
+ : if (widthBytesLine == 0 || height == 0)
+ : linesPerBuf = 0;
+ : else if (widthBytesLine >= IMAGE_BUFSIZE)
+ : linesPerBuf = 1;
+ : else
+ : {
+ : linesPerBuf = IMAGE_BUFSIZE / widthBytesLine;
+ : if (linesPerBuf > height)
+ : linesPerBuf = height;
+ : }
+ : length = linesPerBuf * widthBytesLine;
+ : if (linesPerBuf < height)
+ : {
+ : /* we have to make sure intermediate buffers don't need padding */
+ : while ((linesPerBuf > 1) &&
+ : (length & ((1L << LOG2_BYTES_PER_SCANLINE_PAD)-1)))
+ : {
+ : linesPerBuf--;
+ : length -= widthBytesLine;
+ : }
+ : while (length & ((1L << LOG2_BYTES_PER_SCANLINE_PAD)-1))
+ : {
+ : linesPerBuf++;
+ : length += widthBytesLine;
+ : }
+ : }
+ : if(!(pBuf = (char *) ALLOCATE_LOCAL(length)))
+ : return (BadAlloc);
+ : WriteReplyToClient(client, sizeof (xGetImageReply), &xgi);
+ : }
+ :
+ : if (pDraw->type == DRAWABLE_WINDOW &&
+ : !XaceHook(XACE_DRAWABLE_ACCESS, client, pDraw))
+ : {
+ : pVisibleRegion = NotClippedByChildren((WindowPtr)pDraw);
+ : if (pVisibleRegion)
+ : {
+ : REGION_TRANSLATE(pDraw->pScreen, pVisibleRegion,
+ : -pDraw->x, -pDraw->y);
+ : }
+ : }
+ :
+ : if (linesPerBuf == 0)
+ : {
+ : /* nothing to do */
+ : }
+ : else if (format == ZPixmap)
+ : {
+ : linesDone = 0;
+ : while (height - linesDone > 0)
+ : {
+ : nlines = min(linesPerBuf, height - linesDone);
+ : (*pDraw->pScreen->GetImage) (pDraw,
+ : x,
+ : y + linesDone,
+ : width,
+ : nlines,
+ : format,
+ : planemask,
+ : (pointer) pBuf);
+ : if (pVisibleRegion)
+ : XaceCensorImage(client, pVisibleRegion, widthBytesLine,
+ : pDraw, x, y + linesDone, width,
+ : nlines, format, pBuf);
+ :
+ : /* Note that this is NOT a call to WriteSwappedDataToClient,
+ : as we do NOT byte swap */
+ : if (!im_return)
+ : {
+ : ReformatImage (pBuf, (int)(nlines * widthBytesLine),
+ : BitsPerPixel (pDraw->depth),
+ : ClientOrder(client));
+ :
+ :/* Don't split me, gcc pukes when you do */
+ : (void)WriteToClient(client,
+ : (int)(nlines * widthBytesLine),
+ : pBuf);
+ : }
+ : linesDone += nlines;
+ : }
+ : }
+ : else /* XYPixmap */
+ : {
+ : for (; plane; plane >>= 1)
+ : {
+ : if (planemask & plane)
+ : {
+ : linesDone = 0;
+ : while (height - linesDone > 0)
+ : {
+ : nlines = min(linesPerBuf, height - linesDone);
+ : (*pDraw->pScreen->GetImage) (pDraw,
+ : x,
+ : y + linesDone,
+ : width,
+ : nlines,
+ : format,
+ : plane,
+ : (pointer)pBuf);
+ : if (pVisibleRegion)
+ : XaceCensorImage(client, pVisibleRegion,
+ : widthBytesLine,
+ : pDraw, x, y + linesDone, width,
+ : nlines, format, pBuf);
+ :
+ : /* Note: NOT a call to WriteSwappedDataToClient,
+ : as we do NOT byte swap */
+ : if (im_return) {
+ : pBuf += nlines * widthBytesLine;
+ : } else {
+ : ReformatImage (pBuf,
+ : (int)(nlines * widthBytesLine),
+ : 1,
+ : ClientOrder (client));
+ :
+ :/* Don't split me, gcc pukes when you do */
+ : (void)WriteToClient(client,
+ : (int)(nlines * widthBytesLine),
+ : pBuf);
+ : }
+ : linesDone += nlines;
+ : }
+ : }
+ : }
+ : }
+ : if (pVisibleRegion)
+ : REGION_DESTROY(pDraw->pScreen, pVisibleRegion);
+ : if (!im_return)
+ : DEALLOCATE_LOCAL(pBuf);
+ : return (client->noClientException);
+ :}
+ :
+ :int
+ :ProcGetImage(ClientPtr client)
+ :{
+ : REQUEST(xGetImageReq);
+ :
+ : REQUEST_SIZE_MATCH(xGetImageReq);
+ :
+ : return DoGetImage(client, stuff->format, stuff->drawable,
+ : stuff->x, stuff->y,
+ : (int)stuff->width, (int)stuff->height,
+ : stuff->planeMask, (xGetImageReply **)NULL);
+ :}
+ :
+ :int
+ :ProcPolyText(ClientPtr client)
+ :{
+ : int err;
+ : REQUEST(xPolyTextReq);
+ : DrawablePtr pDraw;
+ : GC *pGC;
+ :
+ : REQUEST_AT_LEAST_SIZE(xPolyTextReq);
+ : VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client);
+ :
+ : err = PolyText(client,
+ : pDraw,
+ : pGC,
+ : (unsigned char *)&stuff[1],
+ : ((unsigned char *) stuff) + (client->req_len << 2),
+ : stuff->x,
+ : stuff->y,
+ : stuff->reqType,
+ : stuff->drawable);
+ :
+ : if (err == Success)
+ : {
+ : return(client->noClientException);
+ : }
+ : else
+ : return err;
+ :}
+ :
+ :int
+ :ProcImageText8(ClientPtr client)
+ :{
+ : int err;
+ : DrawablePtr pDraw;
+ : GC *pGC;
+ :
+ : REQUEST(xImageTextReq);
+ :
+ : REQUEST_FIXED_SIZE(xImageTextReq, stuff->nChars);
+ : VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client);
+ :
+ : err = ImageText(client,
+ : pDraw,
+ : pGC,
+ : stuff->nChars,
+ : (unsigned char *)&stuff[1],
+ : stuff->x,
+ : stuff->y,
+ : stuff->reqType,
+ : stuff->drawable);
+ :
+ : if (err == Success)
+ : {
+ : return(client->noClientException);
+ : }
+ : else
+ : return err;
+ :}
+ :
+ :int
+ :ProcImageText16(ClientPtr client)
+ :{
+ : int err;
+ : DrawablePtr pDraw;
+ : GC *pGC;
+ :
+ : REQUEST(xImageTextReq);
+ :
+ : REQUEST_FIXED_SIZE(xImageTextReq, stuff->nChars << 1);
+ : VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client);
+ :
+ : err = ImageText(client,
+ : pDraw,
+ : pGC,
+ : stuff->nChars,
+ : (unsigned char *)&stuff[1],
+ : stuff->x,
+ : stuff->y,
+ : stuff->reqType,
+ : stuff->drawable);
+ :
+ : if (err == Success)
+ : {
+ : return(client->noClientException);
+ : }
+ : else
+ : return err;
+ :}
+ :
+ :
+ :int
+ :ProcCreateColormap(ClientPtr client)
+ :{
+ : VisualPtr pVisual;
+ : ColormapPtr pmap;
+ : Colormap mid;
+ : WindowPtr pWin;
+ : ScreenPtr pScreen;
+ : REQUEST(xCreateColormapReq);
+ : int i, result;
+ :
+ : REQUEST_SIZE_MATCH(xCreateColormapReq);
+ :
+ : if ((stuff->alloc != AllocNone) && (stuff->alloc != AllocAll))
+ : {
+ : client->errorValue = stuff->alloc;
+ : return(BadValue);
+ : }
+ : mid = stuff->mid;
+ : LEGAL_NEW_RESOURCE(mid, client);
+ : result = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess);
+ : if (result != Success)
+ : return result;
+ :
+ : pScreen = pWin->drawable.pScreen;
+ : for (i = 0, pVisual = pScreen->visuals;
+ : i < pScreen->numVisuals;
+ : i++, pVisual++)
+ : {
+ : if (pVisual->vid != stuff->visual)
+ : continue;
+ : result = CreateColormap(mid, pScreen, pVisual, &pmap,
+ : (int)stuff->alloc, client->index);
+ : if (client->noClientException != Success)
+ : return(client->noClientException);
+ : else
+ : return(result);
+ : }
+ : client->errorValue = stuff->visual;
+ : return(BadMatch);
+ :}
+ :
+ :int
+ :ProcFreeColormap(ClientPtr client)
+ :{
+ : ColormapPtr pmap;
+ : REQUEST(xResourceReq);
+ :
+ : REQUEST_SIZE_MATCH(xResourceReq);
+ : pmap = (ColormapPtr )SecurityLookupIDByType(client, stuff->id, RT_COLORMAP,
+ : DixDestroyAccess);
+ : if (pmap)
+ : {
+ : /* Freeing a default colormap is a no-op */
+ : if (!(pmap->flags & IsDefault))
+ : FreeResource(stuff->id, RT_NONE);
+ : return (client->noClientException);
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->id;
+ : return (BadColor);
+ : }
+ :}
+ :
+ :
+ :int
+ :ProcCopyColormapAndFree(ClientPtr client)
+ :{
+ : Colormap mid;
+ : ColormapPtr pSrcMap;
+ : REQUEST(xCopyColormapAndFreeReq);
+ : int result;
+ :
+ : REQUEST_SIZE_MATCH(xCopyColormapAndFreeReq);
+ : mid = stuff->mid;
+ : LEGAL_NEW_RESOURCE(mid, client);
+ : if( (pSrcMap = (ColormapPtr )SecurityLookupIDByType(client, stuff->srcCmap,
+ : RT_COLORMAP, DixReadAccess|DixWriteAccess)) )
+ : {
+ : result = CopyColormapAndFree(mid, pSrcMap, client->index);
+ : if (client->noClientException != Success)
+ : return(client->noClientException);
+ : else
+ : return(result);
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->srcCmap;
+ : return(BadColor);
+ : }
+ :}
+ :
+ :int
+ :ProcInstallColormap(ClientPtr client)
+ :{
+ : ColormapPtr pcmp;
+ : REQUEST(xResourceReq);
+ :
+ : REQUEST_SIZE_MATCH(xResourceReq);
+ : pcmp = (ColormapPtr)SecurityLookupIDByType(client, stuff->id,
+ : RT_COLORMAP, DixReadAccess);
+ : if (pcmp)
+ : {
+ : (*(pcmp->pScreen->InstallColormap)) (pcmp);
+ : return (client->noClientException);
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->id;
+ : return (BadColor);
+ : }
+ :}
+ :
+ :int
+ :ProcUninstallColormap(ClientPtr client)
+ :{
+ : ColormapPtr pcmp;
+ : REQUEST(xResourceReq);
+ :
+ : REQUEST_SIZE_MATCH(xResourceReq);
+ : pcmp = (ColormapPtr)SecurityLookupIDByType(client, stuff->id,
+ : RT_COLORMAP, DixReadAccess);
+ : if (pcmp)
+ : {
+ : if(pcmp->mid != pcmp->pScreen->defColormap)
+ : (*(pcmp->pScreen->UninstallColormap)) (pcmp);
+ : return (client->noClientException);
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->id;
+ : return (BadColor);
+ : }
+ :}
+ :
+ :int
+ :ProcListInstalledColormaps(ClientPtr client)
+ :{
+ : xListInstalledColormapsReply *preply;
+ : int nummaps, rc;
+ : WindowPtr pWin;
+ : REQUEST(xResourceReq);
+ :
+ : REQUEST_SIZE_MATCH(xResourceReq);
+ : rc = dixLookupWindow(&pWin, stuff->id, client, DixReadAccess);
+ : if (rc != Success)
+ : return rc;
+ :
+ : preply = (xListInstalledColormapsReply *)
+ : ALLOCATE_LOCAL(sizeof(xListInstalledColormapsReply) +
+ : pWin->drawable.pScreen->maxInstalledCmaps *
+ : sizeof(Colormap));
+ : if(!preply)
+ : return(BadAlloc);
+ :
+ : preply->type = X_Reply;
+ : preply->sequenceNumber = client->sequence;
+ : nummaps = (*pWin->drawable.pScreen->ListInstalledColormaps)
+ : (pWin->drawable.pScreen, (Colormap *)&preply[1]);
+ : preply->nColormaps = nummaps;
+ : preply->length = nummaps;
+ : WriteReplyToClient(client, sizeof (xListInstalledColormapsReply), preply);
+ : client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
+ : WriteSwappedDataToClient(client, nummaps * sizeof(Colormap), &preply[1]);
+ : DEALLOCATE_LOCAL(preply);
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcAllocColor (ClientPtr client)
+ :{
+ : ColormapPtr pmap;
+ : int retval;
+ : xAllocColorReply acr;
+ : REQUEST(xAllocColorReq);
+ :
+ : REQUEST_SIZE_MATCH(xAllocColorReq);
+ : pmap = (ColormapPtr)SecurityLookupIDByType(client, stuff->cmap,
+ : RT_COLORMAP, DixWriteAccess);
+ : if (pmap)
+ : {
+ : acr.type = X_Reply;
+ : acr.length = 0;
+ : acr.sequenceNumber = client->sequence;
+ : acr.red = stuff->red;
+ : acr.green = stuff->green;
+ : acr.blue = stuff->blue;
+ : acr.pixel = 0;
+ : if( (retval = AllocColor(pmap, &acr.red, &acr.green, &acr.blue,
+ : &acr.pixel, client->index)) )
+ : {
+ : if (client->noClientException != Success)
+ : return(client->noClientException);
+ : else
+ : return (retval);
+ : }
+ :#ifdef PANORAMIX
+ : if (noPanoramiXExtension || !pmap->pScreen->myNum)
+ :#endif
+ : WriteReplyToClient(client, sizeof(xAllocColorReply), &acr);
+ : return (client->noClientException);
+ :
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->cmap;
+ : return (BadColor);
+ : }
+ :}
+ :
+ :int
+ :ProcAllocNamedColor (ClientPtr client)
+ :{
+ : ColormapPtr pcmp;
+ : REQUEST(xAllocNamedColorReq);
+ :
+ : REQUEST_FIXED_SIZE(xAllocNamedColorReq, stuff->nbytes);
+ : pcmp = (ColormapPtr)SecurityLookupIDByType(client, stuff->cmap,
+ : RT_COLORMAP, DixWriteAccess);
+ : if (pcmp)
+ : {
+ : int retval;
+ :
+ : xAllocNamedColorReply ancr;
+ :
+ : ancr.type = X_Reply;
+ : ancr.length = 0;
+ : ancr.sequenceNumber = client->sequence;
+ :
+ : if(OsLookupColor(pcmp->pScreen->myNum, (char *)&stuff[1], stuff->nbytes,
+ : &ancr.exactRed, &ancr.exactGreen, &ancr.exactBlue))
+ : {
+ : ancr.screenRed = ancr.exactRed;
+ : ancr.screenGreen = ancr.exactGreen;
+ : ancr.screenBlue = ancr.exactBlue;
+ : ancr.pixel = 0;
+ : if( (retval = AllocColor(pcmp,
+ : &ancr.screenRed, &ancr.screenGreen, &ancr.screenBlue,
+ : &ancr.pixel, client->index)) )
+ : {
+ : if (client->noClientException != Success)
+ : return(client->noClientException);
+ : else
+ : return(retval);
+ : }
+ :#ifdef PANORAMIX
+ : if (noPanoramiXExtension || !pcmp->pScreen->myNum)
+ :#endif
+ : WriteReplyToClient(client, sizeof (xAllocNamedColorReply), &ancr);
+ : return (client->noClientException);
+ : }
+ : else
+ : return(BadName);
+ :
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->cmap;
+ : return (BadColor);
+ : }
+ :}
+ :
+ :int
+ :ProcAllocColorCells (ClientPtr client)
+ :{
+ : ColormapPtr pcmp;
+ : REQUEST(xAllocColorCellsReq);
+ :
+ : REQUEST_SIZE_MATCH(xAllocColorCellsReq);
+ : pcmp = (ColormapPtr)SecurityLookupIDByType(client, stuff->cmap,
+ : RT_COLORMAP, DixWriteAccess);
+ : if (pcmp)
+ : {
+ : xAllocColorCellsReply accr;
+ : int npixels, nmasks, retval;
+ : long length;
+ : Pixel *ppixels, *pmasks;
+ :
+ : npixels = stuff->colors;
+ : if (!npixels)
+ : {
+ : client->errorValue = npixels;
+ : return (BadValue);
+ : }
+ : if (stuff->contiguous != xTrue && stuff->contiguous != xFalse)
+ : {
+ : client->errorValue = stuff->contiguous;
+ : return (BadValue);
+ : }
+ : nmasks = stuff->planes;
+ : length = ((long)npixels + (long)nmasks) * sizeof(Pixel);
+ : ppixels = (Pixel *)ALLOCATE_LOCAL(length);
+ : if(!ppixels)
+ : return(BadAlloc);
+ : pmasks = ppixels + npixels;
+ :
+ : if( (retval = AllocColorCells(client->index, pcmp, npixels, nmasks,
+ : (Bool)stuff->contiguous, ppixels, pmasks)) )
+ : {
+ : DEALLOCATE_LOCAL(ppixels);
+ : if (client->noClientException != Success)
+ : return(client->noClientException);
+ : else
+ : return(retval);
+ : }
+ :#ifdef PANORAMIX
+ : if (noPanoramiXExtension || !pcmp->pScreen->myNum)
+ :#endif
+ : {
+ : accr.type = X_Reply;
+ : accr.length = length >> 2;
+ : accr.sequenceNumber = client->sequence;
+ : accr.nPixels = npixels;
+ : accr.nMasks = nmasks;
+ : WriteReplyToClient(client, sizeof (xAllocColorCellsReply), &accr);
+ : client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
+ : WriteSwappedDataToClient(client, length, ppixels);
+ : }
+ : DEALLOCATE_LOCAL(ppixels);
+ : return (client->noClientException);
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->cmap;
+ : return (BadColor);
+ : }
+ :}
+ :
+ :int
+ :ProcAllocColorPlanes(ClientPtr client)
+ :{
+ : ColormapPtr pcmp;
+ : REQUEST(xAllocColorPlanesReq);
+ :
+ : REQUEST_SIZE_MATCH(xAllocColorPlanesReq);
+ : pcmp = (ColormapPtr)SecurityLookupIDByType(client, stuff->cmap,
+ : RT_COLORMAP, DixWriteAccess);
+ : if (pcmp)
+ : {
+ : xAllocColorPlanesReply acpr;
+ : int npixels, retval;
+ : long length;
+ : Pixel *ppixels;
+ :
+ : npixels = stuff->colors;
+ : if (!npixels)
+ : {
+ : client->errorValue = npixels;
+ : return (BadValue);
+ : }
+ : if (stuff->contiguous != xTrue && stuff->contiguous != xFalse)
+ : {
+ : client->errorValue = stuff->contiguous;
+ : return (BadValue);
+ : }
+ : acpr.type = X_Reply;
+ : acpr.sequenceNumber = client->sequence;
+ : acpr.nPixels = npixels;
+ : length = (long)npixels * sizeof(Pixel);
+ : ppixels = (Pixel *)ALLOCATE_LOCAL(length);
+ : if(!ppixels)
+ : return(BadAlloc);
+ : if( (retval = AllocColorPlanes(client->index, pcmp, npixels,
+ : (int)stuff->red, (int)stuff->green, (int)stuff->blue,
+ : (Bool)stuff->contiguous, ppixels,
+ : &acpr.redMask, &acpr.greenMask, &acpr.blueMask)) )
+ : {
+ : DEALLOCATE_LOCAL(ppixels);
+ : if (client->noClientException != Success)
+ : return(client->noClientException);
+ : else
+ : return(retval);
+ : }
+ : acpr.length = length >> 2;
+ :#ifdef PANORAMIX
+ : if (noPanoramiXExtension || !pcmp->pScreen->myNum)
+ :#endif
+ : {
+ : WriteReplyToClient(client, sizeof(xAllocColorPlanesReply), &acpr);
+ : client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
+ : WriteSwappedDataToClient(client, length, ppixels);
+ : }
+ : DEALLOCATE_LOCAL(ppixels);
+ : return (client->noClientException);
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->cmap;
+ : return (BadColor);
+ : }
+ :}
+ :
+ :int
+ :ProcFreeColors(ClientPtr client)
+ :{
+ : ColormapPtr pcmp;
+ : REQUEST(xFreeColorsReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xFreeColorsReq);
+ : pcmp = (ColormapPtr)SecurityLookupIDByType(client, stuff->cmap,
+ : RT_COLORMAP, DixWriteAccess);
+ : if (pcmp)
+ : {
+ : int count;
+ : int retval;
+ :
+ : if(pcmp->flags & AllAllocated)
+ : return(BadAccess);
+ : count = ((client->req_len << 2)- sizeof(xFreeColorsReq)) >> 2;
+ : retval = FreeColors(pcmp, client->index, count,
+ : (Pixel *)&stuff[1], (Pixel)stuff->planeMask);
+ : if (client->noClientException != Success)
+ : return(client->noClientException);
+ : else
+ : {
+ : client->errorValue = clientErrorValue;
+ : return(retval);
+ : }
+ :
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->cmap;
+ : return (BadColor);
+ : }
+ :}
+ :
+ :int
+ :ProcStoreColors (ClientPtr client)
+ :{
+ : ColormapPtr pcmp;
+ : REQUEST(xStoreColorsReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xStoreColorsReq);
+ : pcmp = (ColormapPtr)SecurityLookupIDByType(client, stuff->cmap,
+ : RT_COLORMAP, DixWriteAccess);
+ : if (pcmp)
+ : {
+ : int count;
+ : int retval;
+ :
+ : count = (client->req_len << 2) - sizeof(xStoreColorsReq);
+ : if (count % sizeof(xColorItem))
+ : return(BadLength);
+ : count /= sizeof(xColorItem);
+ : retval = StoreColors(pcmp, count, (xColorItem *)&stuff[1]);
+ : if (client->noClientException != Success)
+ : return(client->noClientException);
+ : else
+ : {
+ : client->errorValue = clientErrorValue;
+ : return(retval);
+ : }
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->cmap;
+ : return (BadColor);
+ : }
+ :}
+ :
+ :int
+ :ProcStoreNamedColor (ClientPtr client)
+ :{
+ : ColormapPtr pcmp;
+ : REQUEST(xStoreNamedColorReq);
+ :
+ : REQUEST_FIXED_SIZE(xStoreNamedColorReq, stuff->nbytes);
+ : pcmp = (ColormapPtr)SecurityLookupIDByType(client, stuff->cmap,
+ : RT_COLORMAP, DixWriteAccess);
+ : if (pcmp)
+ : {
+ : xColorItem def;
+ : int retval;
+ :
+ : if(OsLookupColor(pcmp->pScreen->myNum, (char *)&stuff[1],
+ : stuff->nbytes, &def.red, &def.green, &def.blue))
+ : {
+ : def.flags = stuff->flags;
+ : def.pixel = stuff->pixel;
+ : retval = StoreColors(pcmp, 1, &def);
+ : if (client->noClientException != Success)
+ : return(client->noClientException);
+ : else
+ : return(retval);
+ : }
+ : return (BadName);
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->cmap;
+ : return (BadColor);
+ : }
+ :}
+ :
+ :int
+ :ProcQueryColors(ClientPtr client)
+ :{
+ : ColormapPtr pcmp;
+ : REQUEST(xQueryColorsReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xQueryColorsReq);
+ : pcmp = (ColormapPtr)SecurityLookupIDByType(client, stuff->cmap,
+ : RT_COLORMAP, DixReadAccess);
+ : if (pcmp)
+ : {
+ : int count, retval;
+ : xrgb *prgbs;
+ : xQueryColorsReply qcr;
+ :
+ : count = ((client->req_len << 2) - sizeof(xQueryColorsReq)) >> 2;
+ : prgbs = (xrgb *)ALLOCATE_LOCAL(count * sizeof(xrgb));
+ : if(!prgbs && count)
+ : return(BadAlloc);
+ : if( (retval = QueryColors(pcmp, count, (Pixel *)&stuff[1], prgbs)) )
+ : {
+ : if (prgbs) DEALLOCATE_LOCAL(prgbs);
+ : if (client->noClientException != Success)
+ : return(client->noClientException);
+ : else
+ : {
+ : client->errorValue = clientErrorValue;
+ : return (retval);
+ : }
+ : }
+ : qcr.type = X_Reply;
+ : qcr.length = (count * sizeof(xrgb)) >> 2;
+ : qcr.sequenceNumber = client->sequence;
+ : qcr.nColors = count;
+ : WriteReplyToClient(client, sizeof(xQueryColorsReply), &qcr);
+ : if (count)
+ : {
+ : client->pSwapReplyFunc = (ReplySwapPtr) SQColorsExtend;
+ : WriteSwappedDataToClient(client, count * sizeof(xrgb), prgbs);
+ : }
+ : if (prgbs) DEALLOCATE_LOCAL(prgbs);
+ : return(client->noClientException);
+ :
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->cmap;
+ : return (BadColor);
+ : }
+ :}
+ :
+ :int
+ :ProcLookupColor(ClientPtr client)
+ :{
+ : ColormapPtr pcmp;
+ : REQUEST(xLookupColorReq);
+ :
+ : REQUEST_FIXED_SIZE(xLookupColorReq, stuff->nbytes);
+ : pcmp = (ColormapPtr)SecurityLookupIDByType(client, stuff->cmap,
+ : RT_COLORMAP, DixReadAccess);
+ : if (pcmp)
+ : {
+ : xLookupColorReply lcr;
+ :
+ : if(OsLookupColor(pcmp->pScreen->myNum, (char *)&stuff[1], stuff->nbytes,
+ : &lcr.exactRed, &lcr.exactGreen, &lcr.exactBlue))
+ : {
+ : lcr.type = X_Reply;
+ : lcr.length = 0;
+ : lcr.sequenceNumber = client->sequence;
+ : lcr.screenRed = lcr.exactRed;
+ : lcr.screenGreen = lcr.exactGreen;
+ : lcr.screenBlue = lcr.exactBlue;
+ : (*pcmp->pScreen->ResolveColor)(&lcr.screenRed,
+ : &lcr.screenGreen,
+ : &lcr.screenBlue,
+ : pcmp->pVisual);
+ : WriteReplyToClient(client, sizeof(xLookupColorReply), &lcr);
+ : return(client->noClientException);
+ : }
+ : return (BadName);
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->cmap;
+ : return (BadColor);
+ : }
+ :}
+ :
+ :int
+ :ProcCreateCursor (ClientPtr client)
+ :{
+ : CursorPtr pCursor;
+ : PixmapPtr src;
+ : PixmapPtr msk;
+ : unsigned char * srcbits;
+ : unsigned char * mskbits;
+ : unsigned short width, height;
+ : long n;
+ : CursorMetricRec cm;
+ :
+ :
+ : REQUEST(xCreateCursorReq);
+ :
+ : REQUEST_SIZE_MATCH(xCreateCursorReq);
+ : LEGAL_NEW_RESOURCE(stuff->cid, client);
+ :
+ : src = (PixmapPtr)SecurityLookupIDByType(client, stuff->source,
+ : RT_PIXMAP, DixReadAccess);
+ : msk = (PixmapPtr)SecurityLookupIDByType(client, stuff->mask,
+ : RT_PIXMAP, DixReadAccess);
+ : if ( src == (PixmapPtr)NULL)
+ : {
+ : client->errorValue = stuff->source;
+ : return (BadPixmap);
+ : }
+ : if ( msk == (PixmapPtr)NULL)
+ : {
+ : if (stuff->mask != None)
+ : {
+ : client->errorValue = stuff->mask;
+ : return (BadPixmap);
+ : }
+ : }
+ : else if ( src->drawable.width != msk->drawable.width
+ : || src->drawable.height != msk->drawable.height
+ : || src->drawable.depth != 1
+ : || msk->drawable.depth != 1)
+ : return (BadMatch);
+ :
+ : width = src->drawable.width;
+ : height = src->drawable.height;
+ :
+ : if ( stuff->x > width
+ : || stuff->y > height )
+ : return (BadMatch);
+ :
+ : n = BitmapBytePad(width)*height;
+ : srcbits = (unsigned char *)xalloc(n);
+ : if (!srcbits)
+ : return (BadAlloc);
+ : mskbits = (unsigned char *)xalloc(n);
+ : if (!mskbits)
+ : {
+ : xfree(srcbits);
+ : return (BadAlloc);
+ : }
+ :
+ : /* zeroing the (pad) bits helps some ddx cursor handling */
+ : bzero((char *)srcbits, n);
+ : (* src->drawable.pScreen->GetImage)( (DrawablePtr)src, 0, 0, width, height,
+ : XYPixmap, 1, (pointer)srcbits);
+ : if ( msk == (PixmapPtr)NULL)
+ : {
+ : unsigned char *bits = mskbits;
+ : while (--n >= 0)
+ : *bits++ = ~0;
+ : }
+ : else
+ : {
+ : /* zeroing the (pad) bits helps some ddx cursor handling */
+ : bzero((char *)mskbits, n);
+ : (* msk->drawable.pScreen->GetImage)( (DrawablePtr)msk, 0, 0, width,
+ : height, XYPixmap, 1, (pointer)mskbits);
+ : }
+ : cm.width = width;
+ : cm.height = height;
+ : cm.xhot = stuff->x;
+ : cm.yhot = stuff->y;
+ : pCursor = AllocCursor( srcbits, mskbits, &cm,
+ : stuff->foreRed, stuff->foreGreen, stuff->foreBlue,
+ : stuff->backRed, stuff->backGreen, stuff->backBlue);
+ :
+ : if (pCursor && AddResource(stuff->cid, RT_CURSOR, (pointer)pCursor))
+ : return (client->noClientException);
+ : return BadAlloc;
+ :}
+ :
+ :int
+ :ProcCreateGlyphCursor (ClientPtr client)
+ :{
+ : CursorPtr pCursor;
+ : int res;
+ :
+ : REQUEST(xCreateGlyphCursorReq);
+ :
+ : REQUEST_SIZE_MATCH(xCreateGlyphCursorReq);
+ : LEGAL_NEW_RESOURCE(stuff->cid, client);
+ :
+ : res = AllocGlyphCursor(stuff->source, stuff->sourceChar,
+ : stuff->mask, stuff->maskChar,
+ : stuff->foreRed, stuff->foreGreen, stuff->foreBlue,
+ : stuff->backRed, stuff->backGreen, stuff->backBlue,
+ : &pCursor, client);
+ : if (res != Success)
+ : return res;
+ : if (AddResource(stuff->cid, RT_CURSOR, (pointer)pCursor))
+ : return client->noClientException;
+ : return BadAlloc;
+ :}
+ :
+ :
+ :int
+ :ProcFreeCursor (ClientPtr client)
+ :{
+ : CursorPtr pCursor;
+ : REQUEST(xResourceReq);
+ :
+ : REQUEST_SIZE_MATCH(xResourceReq);
+ : pCursor = (CursorPtr)SecurityLookupIDByType(client, stuff->id,
+ : RT_CURSOR, DixDestroyAccess);
+ : if (pCursor)
+ : {
+ : FreeResource(stuff->id, RT_NONE);
+ : return (client->noClientException);
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->id;
+ : return (BadCursor);
+ : }
+ :}
+ :
+ :int
+ :ProcQueryBestSize (ClientPtr client)
+ :{
+ : xQueryBestSizeReply reply;
+ : DrawablePtr pDraw;
+ : ScreenPtr pScreen;
+ : int rc;
+ : REQUEST(xQueryBestSizeReq);
+ : REQUEST_SIZE_MATCH(xQueryBestSizeReq);
+ :
+ : if ((stuff->class != CursorShape) &&
+ : (stuff->class != TileShape) &&
+ : (stuff->class != StippleShape))
+ : {
+ : client->errorValue = stuff->class;
+ : return(BadValue);
+ : }
+ :
+ : rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
+ : DixReadAccess);
+ : if (rc != Success)
+ : return rc;
+ : if (stuff->class != CursorShape && pDraw->type == UNDRAWABLE_WINDOW)
+ : return (BadMatch);
+ : pScreen = pDraw->pScreen;
+ : (* pScreen->QueryBestSize)(stuff->class, &stuff->width,
+ : &stuff->height, pScreen);
+ : reply.type = X_Reply;
+ : reply.length = 0;
+ : reply.sequenceNumber = client->sequence;
+ : reply.width = stuff->width;
+ : reply.height = stuff->height;
+ : WriteReplyToClient(client, sizeof(xQueryBestSizeReply), &reply);
+ : return (client->noClientException);
+ :}
+ :
+ :
+ :int
+ :ProcSetScreenSaver (ClientPtr client)
+ :{
+ : int blankingOption, exposureOption;
+ : REQUEST(xSetScreenSaverReq);
+ :
+ : REQUEST_SIZE_MATCH(xSetScreenSaverReq);
+ : blankingOption = stuff->preferBlank;
+ : if ((blankingOption != DontPreferBlanking) &&
+ : (blankingOption != PreferBlanking) &&
+ : (blankingOption != DefaultBlanking))
+ : {
+ : client->errorValue = blankingOption;
+ : return BadValue;
+ : }
+ : exposureOption = stuff->allowExpose;
+ : if ((exposureOption != DontAllowExposures) &&
+ : (exposureOption != AllowExposures) &&
+ : (exposureOption != DefaultExposures))
+ : {
+ : client->errorValue = exposureOption;
+ : return BadValue;
+ : }
+ : if (stuff->timeout < -1)
+ : {
+ : client->errorValue = stuff->timeout;
+ : return BadValue;
+ : }
+ : if (stuff->interval < -1)
+ : {
+ : client->errorValue = stuff->interval;
+ : return BadValue;
+ : }
+ :
+ : if (blankingOption == DefaultBlanking)
+ : ScreenSaverBlanking = defaultScreenSaverBlanking;
+ : else
+ : ScreenSaverBlanking = blankingOption;
+ : if (exposureOption == DefaultExposures)
+ : ScreenSaverAllowExposures = defaultScreenSaverAllowExposures;
+ : else
+ : ScreenSaverAllowExposures = exposureOption;
+ :
+ : if (stuff->timeout >= 0)
+ : ScreenSaverTime = stuff->timeout * MILLI_PER_SECOND;
+ : else
+ : ScreenSaverTime = defaultScreenSaverTime;
+ : if (stuff->interval >= 0)
+ : ScreenSaverInterval = stuff->interval * MILLI_PER_SECOND;
+ : else
+ : ScreenSaverInterval = defaultScreenSaverInterval;
+ :
+ : SetScreenSaverTimer();
+ : return (client->noClientException);
+ :}
+ :
+ :int
+ :ProcGetScreenSaver(ClientPtr client)
+ :{
+ : xGetScreenSaverReply rep;
+ :
+ : REQUEST_SIZE_MATCH(xReq);
+ : rep.type = X_Reply;
+ : rep.length = 0;
+ : rep.sequenceNumber = client->sequence;
+ : rep.timeout = ScreenSaverTime / MILLI_PER_SECOND;
+ : rep.interval = ScreenSaverInterval / MILLI_PER_SECOND;
+ : rep.preferBlanking = ScreenSaverBlanking;
+ : rep.allowExposures = ScreenSaverAllowExposures;
+ : WriteReplyToClient(client, sizeof(xGetScreenSaverReply), &rep);
+ : return (client->noClientException);
+ :}
+ :
+ :int
+ :ProcChangeHosts(ClientPtr client)
+ :{
+ : REQUEST(xChangeHostsReq);
+ : int result;
+ :
+ : REQUEST_FIXED_SIZE(xChangeHostsReq, stuff->hostLength);
+ :
+ : if(stuff->mode == HostInsert)
+ : result = AddHost(client, (int)stuff->hostFamily,
+ : stuff->hostLength, (pointer)&stuff[1]);
+ : else if (stuff->mode == HostDelete)
+ : result = RemoveHost(client, (int)stuff->hostFamily,
+ : stuff->hostLength, (pointer)&stuff[1]);
+ : else
+ : {
+ : client->errorValue = stuff->mode;
+ : return BadValue;
+ : }
+ : if (!result)
+ : result = client->noClientException;
+ : return (result);
+ :}
+ :
+ :int
+ :ProcListHosts(ClientPtr client)
+ :{
+ : xListHostsReply reply;
+ : int len, nHosts, result;
+ : pointer pdata;
+ : /* REQUEST(xListHostsReq); */
+ :
+ : REQUEST_SIZE_MATCH(xListHostsReq);
+ :
+ : /* untrusted clients can't list hosts */
+ : if (!XaceHook(XACE_HOSTLIST_ACCESS, client, DixReadAccess))
+ : return BadAccess;
+ :
+ : result = GetHosts(&pdata, &nHosts, &len, &reply.enabled);
+ : if (result != Success)
+ : return(result);
+ : reply.type = X_Reply;
+ : reply.sequenceNumber = client->sequence;
+ : reply.nHosts = nHosts;
+ : reply.length = len >> 2;
+ : WriteReplyToClient(client, sizeof(xListHostsReply), &reply);
+ : if (nHosts)
+ : {
+ : client->pSwapReplyFunc = (ReplySwapPtr) SLHostsExtend;
+ : WriteSwappedDataToClient(client, len, pdata);
+ : }
+ : xfree(pdata);
+ : return (client->noClientException);
+ :}
+ :
+ :int
+ :ProcChangeAccessControl(ClientPtr client)
+ :{
+ : int result;
+ : REQUEST(xSetAccessControlReq);
+ :
+ : REQUEST_SIZE_MATCH(xSetAccessControlReq);
+ : if ((stuff->mode != EnableAccess) && (stuff->mode != DisableAccess))
+ : {
+ : client->errorValue = stuff->mode;
+ : return BadValue;
+ : }
+ : result = ChangeAccessControl(client, stuff->mode == EnableAccess);
+ : if (!result)
+ : result = client->noClientException;
+ : return (result);
+ :}
+ :
+ :/*********************
+ : * CloseDownRetainedResources
+ : *
+ : * Find all clients that are gone and have terminated in RetainTemporary
+ : * and destroy their resources.
+ : *********************/
+ :
+ :static void
+ :CloseDownRetainedResources(void)
+ :{
+ : int i;
+ : ClientPtr client;
+ :
+ : for (i=1; i<currentMaxClients; i++)
+ : {
+ : client = clients[i];
+ : if (client && (client->closeDownMode == RetainTemporary)
+ : && (client->clientGone))
+ : CloseDownClient(client);
+ : }
+ :}
+ :
+ :int
+ :ProcKillClient(ClientPtr client)
+ :{
+ : REQUEST(xResourceReq);
+ : ClientPtr killclient;
+ : int rc;
+ :
+ : REQUEST_SIZE_MATCH(xResourceReq);
+ : if (stuff->id == AllTemporary)
+ : {
+ : CloseDownRetainedResources();
+ : return (client->noClientException);
+ : }
+ :
+ : rc = dixLookupClient(&killclient, stuff->id, client, DixDestroyAccess);
+ : if (rc == Success) {
+ : CloseDownClient(killclient);
+ : /* if an LBX proxy gets killed, isItTimeToYield will be set */
+ : if (isItTimeToYield || (client == killclient))
+ : {
+ : /* force yield and return Success, so that Dispatch()
+ : * doesn't try to touch client
+ : */
+ : isItTimeToYield = TRUE;
+ : return (Success);
+ : }
+ : return (client->noClientException);
+ : }
+ : else
+ : return rc;
+ :}
+ :
+ :int
+ :ProcSetFontPath(ClientPtr client)
+ :{
+ : unsigned char *ptr;
+ : unsigned long nbytes, total;
+ : long nfonts;
+ : int n, result;
+ : int error;
+ : REQUEST(xSetFontPathReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xSetFontPathReq);
+ :
+ : nbytes = (client->req_len << 2) - sizeof(xSetFontPathReq);
+ : total = nbytes;
+ : ptr = (unsigned char *)&stuff[1];
+ : nfonts = stuff->nFonts;
+ : while (--nfonts >= 0)
+ : {
+ : if ((total == 0) || (total < (n = (*ptr + 1))))
+ : return(BadLength);
+ : total -= n;
+ : ptr += n;
+ : }
+ : if (total >= 4)
+ : return(BadLength);
+ : result = SetFontPath(client, stuff->nFonts, (unsigned char *)&stuff[1],
+ : &error);
+ : if (!result)
+ : {
+ : result = client->noClientException;
+ : client->errorValue = error;
+ : }
+ : return (result);
+ :}
+ :
+ :int
+ :ProcGetFontPath(ClientPtr client)
+ :{
+ : xGetFontPathReply reply;
+ : int stringLens, numpaths;
+ : unsigned char *bufferStart;
+ : /* REQUEST (xReq); */
+ :
+ : REQUEST_SIZE_MATCH(xReq);
+ : bufferStart = GetFontPath(&numpaths, &stringLens);
+ :
+ : reply.type = X_Reply;
+ : reply.sequenceNumber = client->sequence;
+ : reply.length = (stringLens + numpaths + 3) >> 2;
+ : reply.nPaths = numpaths;
+ :
+ : WriteReplyToClient(client, sizeof(xGetFontPathReply), &reply);
+ : if (stringLens || numpaths)
+ : (void)WriteToClient(client, stringLens + numpaths, (char *)bufferStart);
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcChangeCloseDownMode(ClientPtr client)
+ :{
+ : REQUEST(xSetCloseDownModeReq);
+ :
+ : REQUEST_SIZE_MATCH(xSetCloseDownModeReq);
+ : if ((stuff->mode == AllTemporary) ||
+ : (stuff->mode == RetainPermanent) ||
+ : (stuff->mode == RetainTemporary))
+ : {
+ : client->closeDownMode = stuff->mode;
+ : return (client->noClientException);
+ : }
+ : else
+ : {
+ : client->errorValue = stuff->mode;
+ : return (BadValue);
+ : }
+ :}
+ :
+ :int ProcForceScreenSaver(ClientPtr client)
+ :{
+ : REQUEST(xForceScreenSaverReq);
+ :
+ : REQUEST_SIZE_MATCH(xForceScreenSaverReq);
+ :
+ : if ((stuff->mode != ScreenSaverReset) &&
+ : (stuff->mode != ScreenSaverActive))
+ : {
+ : client->errorValue = stuff->mode;
+ : return BadValue;
+ : }
+ : SaveScreens(SCREEN_SAVER_FORCER, (int)stuff->mode);
+ : return client->noClientException;
+ :}
+ :
+ :int ProcNoOperation(ClientPtr client)
+ :{
+ : REQUEST_AT_LEAST_SIZE(xReq);
+ :
+ : /* noop -- don't do anything */
+ : return(client->noClientException);
+ :}
+ :
+ :void
+ :InitProcVectors(void)
+ :{
+ : int i;
+ : for (i = 0; i<256; i++)
+ : {
+ : if(!ProcVector[i])
+ : {
+ : ProcVector[i] = SwappedProcVector[i] = ProcBadRequest;
+ : ReplySwapVector[i] = ReplyNotSwappd;
+ : }
+ : }
+ : for(i = LASTEvent; i < 128; i++)
+ : {
+ : EventSwapVector[i] = NotImplemented;
+ : }
+ :
+ :}
+ :
+ :/**********************
+ : * CloseDownClient
+ : *
+ : * Client can either mark his resources destroy or retain. If retained and
+ : * then killed again, the client is really destroyed.
+ : *********************/
+ :
+ :char dispatchExceptionAtReset = DE_RESET;
+ :
+ :void
+ :CloseDownClient(ClientPtr client)
+ :{
+ : Bool really_close_down = client->clientGone ||
+ : client->closeDownMode == DestroyAll;
+ :
+ : if (!client->clientGone)
+ : {
+ : /* ungrab server if grabbing client dies */
+ : if (grabState != GrabNone && grabClient == client)
+ : {
+ : UngrabServer(client);
+ : }
+ : BITCLEAR(grabWaiters, client->index);
+ : DeleteClientFromAnySelections(client);
+ : ReleaseActiveGrabs(client);
+ : DeleteClientFontStuff(client);
+ : if (!really_close_down)
+ : {
+ : /* This frees resources that should never be retained
+ : * no matter what the close down mode is. Actually we
+ : * could do this unconditionally, but it's probably
+ : * better not to traverse all the client's resources
+ : * twice (once here, once a few lines down in
+ : * FreeClientResources) in the common case of
+ : * really_close_down == TRUE.
+ : */
+ : FreeClientNeverRetainResources(client);
+ : client->clientState = ClientStateRetained;
+ : if (ClientStateCallback)
+ : {
+ : NewClientInfoRec clientinfo;
+ :
+ : clientinfo.client = client;
+ : clientinfo.prefix = (xConnSetupPrefix *)NULL;
+ : clientinfo.setup = (xConnSetup *) NULL;
+ : CallCallbacks((&ClientStateCallback), (pointer)&clientinfo);
+ : }
+ : }
+ : client->clientGone = TRUE; /* so events aren't sent to client */
+ : if (ClientIsAsleep(client))
+ : ClientSignal (client);
+ : ProcessWorkQueueZombies();
+ : CloseDownConnection(client);
+ :
+ : /* If the client made it to the Running stage, nClients has
+ : * been incremented on its behalf, so we need to decrement it
+ : * now. If it hasn't gotten to Running, nClients has *not*
+ : * been incremented, so *don't* decrement it.
+ : */
+ : if (client->clientState != ClientStateInitial &&
+ : client->clientState != ClientStateAuthenticating )
+ : {
+ : --nClients;
+ : }
+ : }
+ :
+ : if (really_close_down)
+ : {
+ : if (client->clientState == ClientStateRunning && nClients == 0)
+ : dispatchException |= dispatchExceptionAtReset;
+ :
+ : client->clientState = ClientStateGone;
+ : if (ClientStateCallback)
+ : {
+ : NewClientInfoRec clientinfo;
+ :
+ : clientinfo.client = client;
+ : clientinfo.prefix = (xConnSetupPrefix *)NULL;
+ : clientinfo.setup = (xConnSetup *) NULL;
+ : CallCallbacks((&ClientStateCallback), (pointer)&clientinfo);
+ : }
+ : FreeClientResources(client);
+ :#ifdef XSERVER_DTRACE
+ : XSERVER_CLIENT_DISCONNECT(client->index);
+ :#endif
+ : if (client->index < nextFreeClientID)
+ : nextFreeClientID = client->index;
+ : clients[client->index] = NullClient;
+ :#ifdef SMART_SCHEDULE
+ : SmartLastClient = NullClient;
+ :#endif
+ : xfree(client);
+ :
+ : while (!clients[currentMaxClients-1])
+ : currentMaxClients--;
+ : }
+ :}
+ :
+ :static void
+ :KillAllClients(void)
+ :{
+ : int i;
+ : for (i=1; i<currentMaxClients; i++)
+ : if (clients[i]) {
+ : /* Make sure Retained clients are released. */
+ : clients[i]->closeDownMode = DestroyAll;
+ : CloseDownClient(clients[i]);
+ : }
+ :}
+ :
+ :extern int clientPrivateLen;
+ :extern unsigned *clientPrivateSizes;
+ :extern unsigned totalClientSize;
+ :
+ :void InitClient(ClientPtr client, int i, pointer ospriv)
+ :{
+ : client->index = i;
+ : client->sequence = 0;
+ : client->clientAsMask = ((Mask)i) << CLIENTOFFSET;
+ : client->clientGone = FALSE;
+ : if (i)
+ : {
+ : client->closeDownMode = DestroyAll;
+ : client->lastDrawable = (DrawablePtr)WindowTable[0];
+ : client->lastDrawableID = WindowTable[0]->drawable.id;
+ : }
+ : else
+ : {
+ : client->closeDownMode = RetainPermanent;
+ : client->lastDrawable = (DrawablePtr)NULL;
+ : client->lastDrawableID = INVALID;
+ : }
+ : client->lastGC = (GCPtr) NULL;
+ : client->lastGCID = INVALID;
+ : client->numSaved = 0;
+ : client->saveSet = (SaveSetElt *)NULL;
+ : client->noClientException = Success;
+ :#ifdef DEBUG
+ : client->requestLogIndex = 0;
+ :#endif
+ : client->requestVector = InitialVector;
+ : client->osPrivate = ospriv;
+ : client->swapped = FALSE;
+ : client->big_requests = FALSE;
+ : client->priority = 0;
+ : client->clientState = ClientStateInitial;
+ :#ifdef XKB
+ : if (!noXkbExtension) {
+ : client->xkbClientFlags = 0;
+ : client->mapNotifyMask = 0;
+ : QueryMinMaxKeyCodes(&client->minKC,&client->maxKC);
+ : }
+ :#endif
+ : client->replyBytesRemaining = 0;
+ :#ifdef XAPPGROUP
+ : client->appgroup = NULL;
+ :#endif
+ : client->fontResFunc = NULL;
+ :#ifdef SMART_SCHEDULE
+ : client->smart_priority = 0;
+ : client->smart_start_tick = SmartScheduleTime;
+ : client->smart_stop_tick = SmartScheduleTime;
+ : client->smart_check_tick = SmartScheduleTime;
+ :#endif
+ :}
+ :
+ :int
+ :InitClientPrivates(ClientPtr client)
+ :{
+ : char *ptr;
+ : DevUnion *ppriv;
+ : unsigned *sizes;
+ : unsigned size;
+ : int i;
+ :
+ : if (totalClientSize == sizeof(ClientRec))
+ : ppriv = (DevUnion *)NULL;
+ : else if (client->index)
+ : ppriv = (DevUnion *)(client + 1);
+ : else
+ : {
+ : ppriv = (DevUnion *)xalloc(totalClientSize - sizeof(ClientRec));
+ : if (!ppriv)
+ : return 0;
+ : }
+ : client->devPrivates = ppriv;
+ : sizes = clientPrivateSizes;
+ : ptr = (char *)(ppriv + clientPrivateLen);
+ : if (ppriv)
+ : bzero(ppriv, totalClientSize - sizeof(ClientRec));
+ : for (i = clientPrivateLen; --i >= 0; ppriv++, sizes++)
+ : {
+ : if ( (size = *sizes) )
+ : {
+ : ppriv->ptr = (pointer)ptr;
+ : ptr += size;
+ : }
+ : else
+ : ppriv->ptr = (pointer)NULL;
+ : }
+ :
+ : /* Allow registrants to initialize the serverClient devPrivates */
+ : if (!client->index && ClientStateCallback)
+ : {
+ : NewClientInfoRec clientinfo;
+ :
+ : clientinfo.client = client;
+ : clientinfo.prefix = (xConnSetupPrefix *)NULL;
+ : clientinfo.setup = (xConnSetup *) NULL;
+ : CallCallbacks((&ClientStateCallback), (pointer)&clientinfo);
+ : }
+ : return 1;
+ :}
+ :
+ :/************************
+ : * int NextAvailableClient(ospriv)
+ : *
+ : * OS dependent portion can't assign client id's because of CloseDownModes.
+ : * Returns NULL if there are no free clients.
+ : *************************/
+ :
+ :ClientPtr NextAvailableClient(pointer ospriv)
+ :{
+ : int i;
+ : ClientPtr client;
+ : xReq data;
+ :
+ : i = nextFreeClientID;
+ : if (i == MAXCLIENTS)
+ : return (ClientPtr)NULL;
+ : clients[i] = client = (ClientPtr)xalloc(totalClientSize);
+ : if (!client)
+ : return (ClientPtr)NULL;
+ : InitClient(client, i, ospriv);
+ : InitClientPrivates(client);
+ : if (!InitClientResources(client))
+ : {
+ : xfree(client);
+ : return (ClientPtr)NULL;
+ : }
+ : data.reqType = 1;
+ : data.length = (sz_xReq + sz_xConnClientPrefix) >> 2;
+ : if (!InsertFakeRequest(client, (char *)&data, sz_xReq))
+ : {
+ : FreeClientResources(client);
+ : xfree(client);
+ : return (ClientPtr)NULL;
+ : }
+ : if (i == currentMaxClients)
+ : currentMaxClients++;
+ : while ((nextFreeClientID < MAXCLIENTS) && clients[nextFreeClientID])
+ : nextFreeClientID++;
+ : if (ClientStateCallback)
+ : {
+ : NewClientInfoRec clientinfo;
+ :
+ : clientinfo.client = client;
+ : clientinfo.prefix = (xConnSetupPrefix *)NULL;
+ : clientinfo.setup = (xConnSetup *) NULL;
+ : CallCallbacks((&ClientStateCallback), (pointer)&clientinfo);
+ : }
+ : return(client);
+ :}
+ :
+ :int
+ :ProcInitialConnection(ClientPtr client)
+ :{
+ : REQUEST(xReq);
+ : xConnClientPrefix *prefix;
+ : int whichbyte = 1;
+ :
+ : prefix = (xConnClientPrefix *)((char *)stuff + sz_xReq);
+ : if ((prefix->byteOrder != 'l') && (prefix->byteOrder != 'B'))
+ : return (client->noClientException = -1);
+ : if (((*(char *) &whichbyte) && (prefix->byteOrder == 'B')) ||
+ : (!(*(char *) &whichbyte) && (prefix->byteOrder == 'l')))
+ : {
+ : client->swapped = TRUE;
+ : SwapConnClientPrefix(prefix);
+ : }
+ : stuff->reqType = 2;
+ : stuff->length += ((prefix->nbytesAuthProto + (unsigned)3) >> 2) +
+ : ((prefix->nbytesAuthString + (unsigned)3) >> 2);
+ : if (client->swapped)
+ : {
+ : swaps(&stuff->length, whichbyte);
+ : }
+ : ResetCurrentRequest(client);
+ : return (client->noClientException);
+ :}
+ :
+ :int
+ :SendConnSetup(ClientPtr client, char *reason)
+ :{
+ : xWindowRoot *root;
+ : int i;
+ : int numScreens;
+ : char* lConnectionInfo;
+ : xConnSetupPrefix* lconnSetupPrefix;
+ :
+ : if (reason)
+ : {
+ : xConnSetupPrefix csp;
+ :
+ : csp.success = xFalse;
+ : csp.lengthReason = strlen(reason);
+ : csp.length = (csp.lengthReason + (unsigned)3) >> 2;
+ : csp.majorVersion = X_PROTOCOL;
+ : csp.minorVersion = X_PROTOCOL_REVISION;
+ : if (client->swapped)
+ : WriteSConnSetupPrefix(client, &csp);
+ : else
+ : (void)WriteToClient(client, sz_xConnSetupPrefix, (char *) &csp);
+ : (void)WriteToClient(client, (int)csp.lengthReason, reason);
+ : return (client->noClientException = -1);
+ : }
+ :
+ : numScreens = screenInfo.numScreens;
+ : lConnectionInfo = ConnectionInfo;
+ : lconnSetupPrefix = &connSetupPrefix;
+ :
+ : /* We're about to start speaking X protocol back to the client by
+ : * sending the connection setup info. This means the authorization
+ : * step is complete, and we can count the client as an
+ : * authorized one.
+ : */
+ : nClients++;
+ :
+ : client->requestVector = client->swapped ? SwappedProcVector : ProcVector;
+ : client->sequence = 0;
+ :#ifdef XAPPGROUP
+ : XagConnectionInfo (client, &lconnSetupPrefix, &lConnectionInfo, &numScreens);
+ :#endif
+ : ((xConnSetup *)lConnectionInfo)->ridBase = client->clientAsMask;
+ : ((xConnSetup *)lConnectionInfo)->ridMask = RESOURCE_ID_MASK;
+ :#ifdef MATCH_CLIENT_ENDIAN
+ : ((xConnSetup *)lConnectionInfo)->imageByteOrder = ClientOrder (client);
+ : ((xConnSetup *)lConnectionInfo)->bitmapBitOrder = ClientOrder (client);
+ :#endif
+ : /* fill in the "currentInputMask" */
+ : root = (xWindowRoot *)(lConnectionInfo + connBlockScreenStart);
+ :#ifdef PANORAMIX
+ : if (noPanoramiXExtension)
+ : numScreens = screenInfo.numScreens;
+ : else
+ : numScreens = ((xConnSetup *)ConnectionInfo)->numRoots;
+ :#endif
+ :
+ : for (i=0; i<numScreens; i++)
+ : {
+ : unsigned int j;
+ : xDepth *pDepth;
+ :
+ : root->currentInputMask = WindowTable[i]->eventMask |
+ : wOtherEventMasks (WindowTable[i]);
+ : pDepth = (xDepth *)(root + 1);
+ : for (j = 0; j < root->nDepths; j++)
+ : {
+ : pDepth = (xDepth *)(((char *)(pDepth + 1)) +
+ : pDepth->nVisuals * sizeof(xVisualType));
+ : }
+ : root = (xWindowRoot *)pDepth;
+ : }
+ :
+ : if (client->swapped)
+ : {
+ : WriteSConnSetupPrefix(client, lconnSetupPrefix);
+ : WriteSConnectionInfo(client,
+ : (unsigned long)(lconnSetupPrefix->length << 2),
+ : lConnectionInfo);
+ : }
+ : else
+ : {
+ : (void)WriteToClient(client, sizeof(xConnSetupPrefix),
+ : (char *) lconnSetupPrefix);
+ : (void)WriteToClient(client, (int)(lconnSetupPrefix->length << 2),
+ : lConnectionInfo);
+ : }
+ : client->clientState = ClientStateRunning;
+ : if (ClientStateCallback)
+ : {
+ : NewClientInfoRec clientinfo;
+ :
+ : clientinfo.client = client;
+ : clientinfo.prefix = lconnSetupPrefix;
+ : clientinfo.setup = (xConnSetup *)lConnectionInfo;
+ : CallCallbacks((&ClientStateCallback), (pointer)&clientinfo);
+ : }
+ : return (client->noClientException);
+ :}
+ :
+ :int
+ :ProcEstablishConnection(ClientPtr client)
+ :{
+ : char *reason, *auth_proto, *auth_string;
+ : xConnClientPrefix *prefix;
+ : REQUEST(xReq);
+ :
+ : prefix = (xConnClientPrefix *)((char *)stuff + sz_xReq);
+ : auth_proto = (char *)prefix + sz_xConnClientPrefix;
+ : auth_string = auth_proto + ((prefix->nbytesAuthProto + 3) & ~3);
+ : if ((prefix->majorVersion != X_PROTOCOL) ||
+ : (prefix->minorVersion != X_PROTOCOL_REVISION))
+ : reason = "Protocol version mismatch";
+ : else
+ : reason = ClientAuthorized(client,
+ : (unsigned short)prefix->nbytesAuthProto,
+ : auth_proto,
+ : (unsigned short)prefix->nbytesAuthString,
+ : auth_string);
+ : /*
+ : * If Kerberos is being used for this client, the clientState
+ : * will be set to ClientStateAuthenticating at this point.
+ : * More messages need to be exchanged among the X server, Kerberos
+ : * server, and client to figure out if everyone is authorized.
+ : * So we don't want to send the connection setup info yet, since
+ : * the auth step isn't really done.
+ : */
+ : if (client->clientState == ClientStateCheckingSecurity)
+ : client->clientState = ClientStateCheckedSecurity;
+ : else if (client->clientState != ClientStateAuthenticating)
+ : return(SendConnSetup(client, reason));
+ : return(client->noClientException);
+ :}
+ :
+ :_X_EXPORT void
+ :SendErrorToClient(ClientPtr client, unsigned majorCode, unsigned minorCode,
+ : XID resId, int errorCode)
+ :{
+ : xError rep;
+ :
+ : rep.type = X_Error;
+ : rep.sequenceNumber = client->sequence;
+ : rep.errorCode = errorCode;
+ : rep.majorCode = majorCode;
+ : rep.minorCode = minorCode;
+ : rep.resourceID = resId;
+ :
+ : WriteEventsToClient (client, 1, (xEvent *)&rep);
+ :}
+ :
+ :void
+ :DeleteWindowFromAnySelections(WindowPtr pWin)
+ :{
+ : int i;
+ :
+ : for (i = 0; i< NumCurrentSelections; i++)
+ : if (CurrentSelections[i].pWin == pWin)
+ : {
+ : if (SelectionCallback)
+ : {
+ : SelectionInfoRec info;
+ :
+ : info.selection = &CurrentSelections[i];
+ : info.kind = SelectionWindowDestroy;
+ : CallCallbacks(&SelectionCallback, &info);
+ : }
+ : CurrentSelections[i].pWin = (WindowPtr)NULL;
+ : CurrentSelections[i].window = None;
+ : CurrentSelections[i].client = NullClient;
+ : }
+ :}
+ :
+ :static void
+ :DeleteClientFromAnySelections(ClientPtr client)
+ :{
+ : int i;
+ :
+ : for (i = 0; i< NumCurrentSelections; i++)
+ : if (CurrentSelections[i].client == client)
+ : {
+ : if (SelectionCallback)
+ : {
+ : SelectionInfoRec info;
+ :
+ : info.selection = &CurrentSelections[i];
+ : info.kind = SelectionWindowDestroy;
+ : CallCallbacks(&SelectionCallback, &info);
+ : }
+ : CurrentSelections[i].pWin = (WindowPtr)NULL;
+ : CurrentSelections[i].window = None;
+ : CurrentSelections[i].client = NullClient;
+ : }
+ :}
+ :
+ :void
+ :MarkClientException(ClientPtr client)
+ :{
+ : client->noClientException = -1;
+ :}
+ :
+ :#ifdef XSERVER_DTRACE
+ :#include <ctype.h>
+ :
+ :/* Load table of request names for dtrace probes */
+ :static void LoadRequestNames(void)
+ :{
+ : int i;
+ : FILE *xedb;
+ : extern void LoadExtensionNames(char **RequestNames);
+ :
+ : bzero(RequestNames, 256 * sizeof(char *));
+ :
+ : xedb = fopen(XERRORDB_PATH, "r");
+ : if (xedb != NULL) {
+ : char buf[256];
+ : while (fgets(buf, sizeof(buf), xedb)) {
+ : if ((strncmp("XRequest.", buf, 9) == 0) && (isdigit(buf[9]))) {
+ : char *name;
+ : i = strtol(buf + 9, &name, 10);
+ : if (RequestNames[i] == 0) {
+ : char *end = strchr(name, '\n');
+ : if (end) { *end = '\0'; }
+ : RequestNames[i] = strdup(name + 1);
+ : }
+ : }
+ : }
+ : fclose(xedb);
+ : }
+ :
+ : LoadExtensionNames(RequestNames);
+ :
+ : for (i = 0; i < 256; i++) {
+ : if (RequestNames[i] == 0) {
+ :#define RN_SIZE 12 /* "Request#' + up to 3 digits + \0 */
+ : RequestNames[i] = xalloc(RN_SIZE);
+ : if (RequestNames[i]) {
+ : snprintf(RequestNames[i], RN_SIZE, "Request#%d", i);
+ : }
+ : }
+ : /* fprintf(stderr, "%d: %s\n", i, RequestNames[i]); */
+ : }
+ :}
+ :
+ :static void FreeRequestNames(void)
+ :{
+ : int i;
+ :
+ : for (i = 0; i < 256; i++) {
+ : if (RequestNames[i] != 0) {
+ : free(RequestNames[i]);
+ : RequestNames[i] = 0;
+ : }
+ : }
+ :}
+ :
+ :#endif
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/dix/gc.c"
+ *
+ * 57 0.0621
+ */
+
+
+ :/***********************************************************
+ :
+ :Copyright 1987, 1998 The Open Group
+ :
+ :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.
+ :
+ :The above copyright notice and this permission notice shall be included in
+ :all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ :IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ :FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ :OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ :AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ :CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of The Open Group shall not be
+ :used in advertising or otherwise to promote the sale, use or other dealings
+ :in this Software without prior written authorization from The Open Group.
+ :
+ :
+ :Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+ :
+ : All Rights Reserved
+ :
+ :Permission to use, copy, modify, and distribute this software and its
+ :documentation for any purpose and without fee is hereby granted,
+ :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 Digital not be
+ :used in advertising or publicity pertaining to distribution of the
+ :software without specific, written prior permission.
+ :
+ :DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ :ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ :DIGITAL 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.
+ :
+ :******************************************************************/
+ :
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include <X11/X.h>
+ :#include <X11/Xmd.h>
+ :#include <X11/Xproto.h>
+ :#include "misc.h"
+ :#include "resource.h"
+ :#include "gcstruct.h"
+ :#include "pixmapstr.h"
+ :#include "dixfontstr.h"
+ :#include "scrnintstr.h"
+ :#include "region.h"
+ :
+ :#include "dix.h"
+ :#include <assert.h>
+ :
+ :extern XID clientErrorValue;
+ :extern FontPtr defaultFont;
+ :
+ :static Bool CreateDefaultTile(GCPtr pGC);
+ :
+ :static unsigned char DefaultDash[2] = {4, 4};
+ :
+ :_X_EXPORT void
+ :ValidateGC(DrawablePtr pDraw, GC *pGC)
+ 3 0.0033 :{ /* ValidateGC total: 3 0.0033 */
+ : (*pGC->funcs->ValidateGC) (pGC, pGC->stateChanges, pDraw);
+ : pGC->stateChanges = 0;
+ : pGC->serialNumber = pDraw->serialNumber;
+ :}
+ :
+ :
+ :/* dixChangeGC(client, pGC, mask, pC32, pUnion)
+ : *
+ : * This function was created as part of the Security extension
+ : * implementation. The client performing the gc change must be passed so
+ : * that access checks can be performed on any tiles, stipples, or fonts
+ : * that are specified. ddxen can call this too; they should normally
+ : * pass NullClient for the client since any access checking should have
+ : * already been done at a higher level.
+ : *
+ : * Since we had to create a new function anyway, we decided to change the
+ : * way the list of gc values is passed to eliminate the compiler warnings
+ : * caused by the DoChangeGC interface. You can pass the values via pC32
+ : * or pUnion, but not both; one of them must be NULL. If you don't need
+ : * to pass any pointers, you can use either one:
+ : *
+ : * example calling dixChangeGC using pC32 parameter
+ : *
+ : * CARD32 v[2];
+ : * v[0] = foreground;
+ : * v[1] = background;
+ : * dixChangeGC(client, pGC, GCForeground|GCBackground, v, NULL);
+ : *
+ : * example calling dixChangeGC using pUnion parameter;
+ : * same effect as above
+ : *
+ : * ChangeGCVal v[2];
+ : * v[0].val = foreground;
+ : * v[1].val = background;
+ : * dixChangeGC(client, pGC, GCForeground|GCBackground, NULL, v);
+ : *
+ : * However, if you need to pass a pointer to a pixmap or font, you MUST
+ : * use the pUnion parameter.
+ : *
+ : * example calling dixChangeGC passing pointers in the value list
+ : * v[1].ptr is a pointer to a pixmap
+ : *
+ : * ChangeGCVal v[2];
+ : * v[0].val = FillTiled;
+ : * v[1].ptr = pPixmap;
+ : * dixChangeGC(client, pGC, GCFillStyle|GCTile, NULL, v);
+ : *
+ : * Note: we could have gotten by with just the pUnion parameter, but on
+ : * 64 bit machines that would have forced us to copy the value list that
+ : * comes in the ChangeGC request.
+ : *
+ : * Ideally, we'd change all the DoChangeGC calls to dixChangeGC, but this
+ : * is far too many changes to consider at this time, so we've only
+ : * changed the ones that caused compiler warnings. New code should use
+ : * dixChangeGC.
+ : *
+ : * dpw
+ : */
+ :
+ :#define NEXTVAL(_type, _var) { \
+ : if (pC32) _var = (_type)*pC32++; \
+ : else { \
+ : _var = (_type)(pUnion->val); pUnion++; \
+ : } \
+ : }
+ :
+ :#define NEXT_PTR(_type, _var) { \
+ : assert(pUnion); _var = (_type)pUnion->ptr; pUnion++; }
+ :
+ :_X_EXPORT int
+ :dixChangeGC(ClientPtr client, GC *pGC, BITS32 mask, CARD32 *pC32, ChangeGCValPtr pUnion)
+ :{ /* dixChangeGC total: 24 0.0261 */
+ : BITS32 index2;
+ : int error = 0;
+ : PixmapPtr pPixmap;
+ : BITS32 maskQ;
+ :
+ : assert( (pC32 && !pUnion) || (!pC32 && pUnion) );
+ : pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
+ :
+ : maskQ = mask; /* save these for when we walk the GCque */
+ 5 0.0054 : while (mask && !error)
+ : {
+ 1 0.0011 : index2 = (BITS32) lowbit (mask);
+ 7 0.0076 : mask &= ~index2;
+ : pGC->stateChanges |= index2;
+ 1 0.0011 : switch (index2)
+ : {
+ : case GCFunction:
+ : {
+ : CARD8 newalu;
+ 3 0.0033 : NEXTVAL(CARD8, newalu);
+ : if (newalu <= GXset)
+ 1 0.0011 : pGC->alu = newalu;
+ : else
+ : {
+ : clientErrorValue = newalu;
+ : error = BadValue;
+ : }
+ : break;
+ : }
+ : case GCPlaneMask:
+ : NEXTVAL(unsigned long, pGC->planemask);
+ : break;
+ : case GCForeground:
+ 1 0.0011 : NEXTVAL(unsigned long, pGC->fgPixel);
+ : /*
+ : * this is for CreateGC
+ : */
+ : if (!pGC->tileIsPixel && !pGC->tile.pixmap)
+ : {
+ : pGC->tileIsPixel = TRUE;
+ : pGC->tile.pixel = pGC->fgPixel;
+ : }
+ : break;
+ : case GCBackground:
+ : NEXTVAL(unsigned long, pGC->bgPixel);
+ : break;
+ : case GCLineWidth: /* ??? line width is a CARD16 */
+ : NEXTVAL(CARD16, pGC->lineWidth);
+ : break;
+ : case GCLineStyle:
+ : {
+ : unsigned int newlinestyle;
+ : NEXTVAL(unsigned int, newlinestyle);
+ : if (newlinestyle <= LineDoubleDash)
+ : pGC->lineStyle = newlinestyle;
+ : else
+ : {
+ : clientErrorValue = newlinestyle;
+ : error = BadValue;
+ : }
+ : break;
+ : }
+ : case GCCapStyle:
+ : {
+ : unsigned int newcapstyle;
+ : NEXTVAL(unsigned int, newcapstyle);
+ : if (newcapstyle <= CapProjecting)
+ : pGC->capStyle = newcapstyle;
+ : else
+ : {
+ : clientErrorValue = newcapstyle;
+ : error = BadValue;
+ : }
+ : break;
+ : }
+ : case GCJoinStyle:
+ : {
+ : unsigned int newjoinstyle;
+ : NEXTVAL(unsigned int, newjoinstyle);
+ : if (newjoinstyle <= JoinBevel)
+ : pGC->joinStyle = newjoinstyle;
+ : else
+ : {
+ : clientErrorValue = newjoinstyle;
+ : error = BadValue;
+ : }
+ : break;
+ : }
+ : case GCFillStyle:
+ : {
+ : unsigned int newfillstyle;
+ : NEXTVAL(unsigned int, newfillstyle);
+ : if (newfillstyle <= FillOpaqueStippled)
+ : pGC->fillStyle = newfillstyle;
+ : else
+ : {
+ : clientErrorValue = newfillstyle;
+ : error = BadValue;
+ : }
+ : break;
+ : }
+ : case GCFillRule:
+ : {
+ : unsigned int newfillrule;
+ : NEXTVAL(unsigned int, newfillrule);
+ : if (newfillrule <= WindingRule)
+ : pGC->fillRule = newfillrule;
+ : else
+ : {
+ : clientErrorValue = newfillrule;
+ : error = BadValue;
+ : }
+ : break;
+ : }
+ : case GCTile:
+ : {
+ : XID newpix = 0;
+ : if (pUnion)
+ : {
+ : NEXT_PTR(PixmapPtr, pPixmap);
+ : }
+ : else
+ : {
+ : NEXTVAL(XID, newpix);
+ : pPixmap = (PixmapPtr)SecurityLookupIDByType(client,
+ : newpix, RT_PIXMAP, DixReadAccess);
+ : }
+ : if (pPixmap)
+ : {
+ : if ((pPixmap->drawable.depth != pGC->depth) ||
+ : (pPixmap->drawable.pScreen != pGC->pScreen))
+ : {
+ : error = BadMatch;
+ : }
+ : else
+ : {
+ : pPixmap->refcnt++;
+ : if (!pGC->tileIsPixel)
+ : (* pGC->pScreen->DestroyPixmap)(pGC->tile.pixmap);
+ : pGC->tileIsPixel = FALSE;
+ : pGC->tile.pixmap = pPixmap;
+ : }
+ : }
+ : else
+ : {
+ : clientErrorValue = newpix;
+ : error = BadPixmap;
+ : }
+ : break;
+ : }
+ : case GCStipple:
+ : {
+ : XID newstipple = 0;
+ : if (pUnion)
+ : {
+ : NEXT_PTR(PixmapPtr, pPixmap);
+ : }
+ : else
+ : {
+ : NEXTVAL(XID, newstipple)
+ : pPixmap = (PixmapPtr)SecurityLookupIDByType(client,
+ : newstipple, RT_PIXMAP, DixReadAccess);
+ : }
+ : if (pPixmap)
+ : {
+ : if ((pPixmap->drawable.depth != 1) ||
+ : (pPixmap->drawable.pScreen != pGC->pScreen))
+ : {
+ : error = BadMatch;
+ : }
+ : else
+ : {
+ : pPixmap->refcnt++;
+ : if (pGC->stipple)
+ : (* pGC->pScreen->DestroyPixmap)(pGC->stipple);
+ : pGC->stipple = pPixmap;
+ : }
+ : }
+ : else
+ : {
+ : clientErrorValue = newstipple;
+ : error = BadPixmap;
+ : }
+ : break;
+ : }
+ : case GCTileStipXOrigin:
+ : NEXTVAL(INT16, pGC->patOrg.x);
+ : break;
+ : case GCTileStipYOrigin:
+ : NEXTVAL(INT16, pGC->patOrg.y);
+ : break;
+ : case GCFont:
+ : {
+ : FontPtr pFont;
+ : XID newfont = 0;
+ : if (pUnion)
+ : {
+ : NEXT_PTR(FontPtr, pFont);
+ : }
+ : else
+ : {
+ : NEXTVAL(XID, newfont)
+ : pFont = (FontPtr)SecurityLookupIDByType(client, newfont,
+ : RT_FONT, DixReadAccess);
+ : }
+ : if (pFont)
+ : {
+ : pFont->refcnt++;
+ : if (pGC->font)
+ : CloseFont(pGC->font, (Font)0);
+ : pGC->font = pFont;
+ : }
+ : else
+ : {
+ : clientErrorValue = newfont;
+ : error = BadFont;
+ : }
+ : break;
+ : }
+ : case GCSubwindowMode:
+ : {
+ : unsigned int newclipmode;
+ 1 0.0011 : NEXTVAL(unsigned int, newclipmode);
+ : if (newclipmode <= IncludeInferiors)
+ 1 0.0011 : pGC->subWindowMode = newclipmode;
+ : else
+ : {
+ : clientErrorValue = newclipmode;
+ : error = BadValue;
+ : }
+ : break;
+ : }
+ : case GCGraphicsExposures:
+ : {
+ : unsigned int newge;
+ : NEXTVAL(unsigned int, newge);
+ : if (newge <= xTrue)
+ : pGC->graphicsExposures = newge;
+ : else
+ : {
+ : clientErrorValue = newge;
+ : error = BadValue;
+ : }
+ : break;
+ : }
+ : case GCClipXOrigin:
+ 2 0.0022 : NEXTVAL(INT16, pGC->clipOrg.x);
+ : break;
+ : case GCClipYOrigin:
+ : NEXTVAL(INT16, pGC->clipOrg.y);
+ : break;
+ : case GCClipMask:
+ : {
+ : Pixmap pid = 0;
+ : int clipType = 0;
+ :
+ : if (pUnion)
+ : {
+ : NEXT_PTR(PixmapPtr, pPixmap);
+ : }
+ : else
+ : {
+ : NEXTVAL(Pixmap, pid)
+ : if (pid == None)
+ : {
+ : clipType = CT_NONE;
+ : pPixmap = NullPixmap;
+ : }
+ : else
+ : pPixmap = (PixmapPtr)SecurityLookupIDByType(client,
+ : pid, RT_PIXMAP, DixReadAccess);
+ : }
+ :
+ : if (pPixmap)
+ : {
+ : if ((pPixmap->drawable.depth != 1) ||
+ : (pPixmap->drawable.pScreen != pGC->pScreen))
+ : {
+ : error = BadMatch;
+ : }
+ : else
+ : {
+ : clipType = CT_PIXMAP;
+ : pPixmap->refcnt++;
+ : }
+ : }
+ : else if (!pUnion && (pid != None))
+ : {
+ : clientErrorValue = pid;
+ : error = BadPixmap;
+ : }
+ : if(error == Success)
+ : {
+ : (*pGC->funcs->ChangeClip)(pGC, clipType,
+ : (pointer)pPixmap, 0);
+ : }
+ : break;
+ : }
+ : case GCDashOffset:
+ : NEXTVAL(INT16, pGC->dashOffset);
+ : break;
+ : case GCDashList:
+ : {
+ : CARD8 newdash;
+ : NEXTVAL(CARD8, newdash);
+ : if (newdash == 4)
+ : {
+ : if (pGC->dash != DefaultDash)
+ : {
+ : xfree(pGC->dash);
+ : pGC->numInDashList = 2;
+ : pGC->dash = DefaultDash;
+ : }
+ : }
+ : else if (newdash != 0)
+ : {
+ : unsigned char *dash;
+ :
+ : dash = (unsigned char *)xalloc(2 * sizeof(unsigned char));
+ : if (dash)
+ : {
+ : if (pGC->dash != DefaultDash)
+ : xfree(pGC->dash);
+ : pGC->numInDashList = 2;
+ : pGC->dash = dash;
+ : dash[0] = newdash;
+ : dash[1] = newdash;
+ : }
+ : else
+ : error = BadAlloc;
+ : }
+ : else
+ : {
+ : clientErrorValue = newdash;
+ : error = BadValue;
+ : }
+ : break;
+ : }
+ : case GCArcMode:
+ : {
+ : unsigned int newarcmode;
+ : NEXTVAL(unsigned int, newarcmode);
+ : if (newarcmode <= ArcPieSlice)
+ : pGC->arcMode = newarcmode;
+ : else
+ : {
+ : clientErrorValue = newarcmode;
+ : error = BadValue;
+ : }
+ : break;
+ : }
+ : default:
+ : clientErrorValue = maskQ;
+ : error = BadValue;
+ : break;
+ : }
+ : } /* end while mask && !error */
+ :
+ 1 0.0011 : if (pGC->fillStyle == FillTiled && pGC->tileIsPixel)
+ : {
+ : if (!CreateDefaultTile (pGC))
+ : {
+ : pGC->fillStyle = FillSolid;
+ : error = BadAlloc;
+ : }
+ : }
+ : (*pGC->funcs->ChangeGC)(pGC, maskQ);
+ : return error;
+ :}
+ :
+ :#undef NEXTVAL
+ :#undef NEXT_PTR
+ :
+ :/* Publically defined entry to ChangeGC. Just calls dixChangeGC and tells
+ : * it that all of the entries are constants or IDs */
+ :_X_EXPORT int
+ :ChangeGC(GC *pGC, BITS32 mask, XID *pval)
+ 2 0.0022 :{ /* ChangeGC total: 5 0.0054 */
+ 3 0.0033 : return (dixChangeGC(NullClient, pGC, mask, pval, NULL));
+ :}
+ :
+ :/* DoChangeGC(pGC, mask, pval, fPointer)
+ : mask is a set of bits indicating which values to change.
+ : pval contains an appropriate value for each mask.
+ : fPointer is true if the values for tiles, stipples, fonts or clipmasks
+ : are pointers instead of IDs. Note: if you are passing pointers you
+ : MUST declare the array of values as type pointer! Other data types
+ : may not be large enough to hold pointers on some machines. Yes,
+ : this means you have to cast to (XID *) when you pass the array to
+ : DoChangeGC. Similarly, if you are not passing pointers (fPointer = 0) you
+ : MUST declare the array as type XID (not unsigned long!), or again the wrong
+ : size data type may be used. To avoid this cruftiness, use dixChangeGC
+ : above.
+ :
+ : if there is an error, the value is marked as changed
+ : anyway, which is probably wrong, but infrequent.
+ :
+ :NOTE:
+ : all values sent over the protocol for ChangeGC requests are
+ :32 bits long
+ :*/
+ :_X_EXPORT int
+ :DoChangeGC(GC *pGC, BITS32 mask, XID *pval, int fPointer)
+ :{
+ : if (fPointer)
+ : /* XXX might be a problem on 64 bit big-endian servers */
+ : return dixChangeGC(NullClient, pGC, mask, NULL, (ChangeGCValPtr)pval);
+ : else
+ : return dixChangeGC(NullClient, pGC, mask, pval, NULL);
+ :}
+ :
+ :
+ :/* CreateGC(pDrawable, mask, pval, pStatus)
+ : creates a default GC for the given drawable, using mask to fill
+ : in any non-default values.
+ : Returns a pointer to the new GC on success, NULL otherwise.
+ : returns status of non-default fields in pStatus
+ :BUG:
+ : should check for failure to create default tile
+ :
+ :*/
+ :
+ :static GCPtr
+ :AllocateGC(ScreenPtr pScreen)
+ :{ /* AllocateGC total: 2 0.0022 */
+ : GCPtr pGC;
+ : char *ptr;
+ : DevUnion *ppriv;
+ : unsigned *sizes;
+ : unsigned size;
+ : int i;
+ :
+ : pGC = (GCPtr)xalloc(pScreen->totalGCSize);
+ : if (pGC)
+ : {
+ : ppriv = (DevUnion *)(pGC + 1);
+ : pGC->devPrivates = ppriv;
+ : sizes = pScreen->GCPrivateSizes;
+ : ptr = (char *)(ppriv + pScreen->GCPrivateLen);
+ : for (i = pScreen->GCPrivateLen; --i >= 0; ppriv++, sizes++)
+ : {
+ : if ( (size = *sizes) )
+ : {
+ : ppriv->ptr = (pointer)ptr;
+ : ptr += size;
+ : }
+ : else
+ 1 0.0011 : ppriv->ptr = (pointer)NULL;
+ : }
+ : }
+ : return pGC;
+ 1 0.0011 :}
+ :
+ :_X_EXPORT GCPtr
+ :CreateGC(DrawablePtr pDrawable, BITS32 mask, XID *pval, int *pStatus)
+ :{ /* CreateGC total: 1 0.0011 */
+ : GCPtr pGC;
+ :
+ : pGC = AllocateGC(pDrawable->pScreen);
+ : if (!pGC)
+ : {
+ : *pStatus = BadAlloc;
+ : return (GCPtr)NULL;
+ : }
+ :
+ : pGC->pScreen = pDrawable->pScreen;
+ : pGC->depth = pDrawable->depth;
+ : pGC->alu = GXcopy; /* dst <- src */
+ : pGC->planemask = ~0;
+ : pGC->serialNumber = GC_CHANGE_SERIAL_BIT;
+ : pGC->funcs = 0;
+ :
+ : pGC->fgPixel = 0;
+ : pGC->bgPixel = 1;
+ : pGC->lineWidth = 0;
+ : pGC->lineStyle = LineSolid;
+ : pGC->capStyle = CapButt;
+ : pGC->joinStyle = JoinMiter;
+ : pGC->fillStyle = FillSolid;
+ : pGC->fillRule = EvenOddRule;
+ : pGC->arcMode = ArcPieSlice;
+ : if (mask & GCForeground)
+ : {
+ : /*
+ : * magic special case -- ChangeGC checks for this condition
+ : * and snags the Foreground value to create a pseudo default-tile
+ : */
+ : pGC->tileIsPixel = FALSE;
+ : pGC->tile.pixmap = NullPixmap;
+ : }
+ : else
+ : {
+ : pGC->tileIsPixel = TRUE;
+ : pGC->tile.pixel = 0;
+ : }
+ :
+ 1 0.0011 : pGC->patOrg.x = 0;
+ : pGC->patOrg.y = 0;
+ : pGC->subWindowMode = ClipByChildren;
+ : pGC->graphicsExposures = TRUE;
+ : pGC->clipOrg.x = 0;
+ : pGC->clipOrg.y = 0;
+ : pGC->clientClipType = CT_NONE;
+ : pGC->clientClip = (pointer)NULL;
+ : pGC->numInDashList = 2;
+ : pGC->dash = DefaultDash;
+ : pGC->dashOffset = 0;
+ : pGC->lastWinOrg.x = 0;
+ : pGC->lastWinOrg.y = 0;
+ :
+ : /* use the default font and stipple */
+ : pGC->font = defaultFont;
+ : defaultFont->refcnt++;
+ : pGC->stipple = pGC->pScreen->PixmapPerDepth[0];
+ : pGC->stipple->refcnt++;
+ :
+ : pGC->stateChanges = (1 << (GCLastBit+1)) - 1;
+ : if (!(*pGC->pScreen->CreateGC)(pGC))
+ : *pStatus = BadAlloc;
+ : else if (mask)
+ : *pStatus = ChangeGC(pGC, mask, pval);
+ : else
+ : *pStatus = Success;
+ : if (*pStatus != Success)
+ : {
+ : if (!pGC->tileIsPixel && !pGC->tile.pixmap)
+ : pGC->tileIsPixel = TRUE; /* undo special case */
+ : FreeGC(pGC, (XID)0);
+ : pGC = (GCPtr)NULL;
+ : }
+ :
+ : return (pGC);
+ :}
+ :
+ :static Bool
+ :CreateDefaultTile (GCPtr pGC)
+ :{
+ : XID tmpval[3];
+ : PixmapPtr pTile;
+ : GCPtr pgcScratch;
+ : xRectangle rect;
+ : CARD16 w, h;
+ :
+ : w = 1;
+ : h = 1;
+ : (*pGC->pScreen->QueryBestSize)(TileShape, &w, &h, pGC->pScreen);
+ : pTile = (PixmapPtr)
+ : (*pGC->pScreen->CreatePixmap)(pGC->pScreen,
+ : w, h, pGC->depth);
+ : pgcScratch = GetScratchGC(pGC->depth, pGC->pScreen);
+ : if (!pTile || !pgcScratch)
+ : {
+ : if (pTile)
+ : (*pTile->drawable.pScreen->DestroyPixmap)(pTile);
+ : if (pgcScratch)
+ : FreeScratchGC(pgcScratch);
+ : return FALSE;
+ : }
+ : tmpval[0] = GXcopy;
+ : tmpval[1] = pGC->tile.pixel;
+ : tmpval[2] = FillSolid;
+ : (void)ChangeGC(pgcScratch, GCFunction | GCForeground | GCFillStyle,
+ : tmpval);
+ : ValidateGC((DrawablePtr)pTile, pgcScratch);
+ : rect.x = 0;
+ : rect.y = 0;
+ : rect.width = w;
+ : rect.height = h;
+ : (*pgcScratch->ops->PolyFillRect)((DrawablePtr)pTile, pgcScratch, 1, &rect);
+ : /* Always remember to free the scratch graphics context after use. */
+ : FreeScratchGC(pgcScratch);
+ :
+ : pGC->tileIsPixel = FALSE;
+ : pGC->tile.pixmap = pTile;
+ : return TRUE;
+ :}
+ :
+ :_X_EXPORT int
+ :CopyGC(GC *pgcSrc, GC *pgcDst, BITS32 mask)
+ :{
+ : BITS32 index2;
+ : BITS32 maskQ;
+ : int error = 0;
+ :
+ : if (pgcSrc == pgcDst)
+ : return Success;
+ : pgcDst->serialNumber |= GC_CHANGE_SERIAL_BIT;
+ : pgcDst->stateChanges |= mask;
+ : maskQ = mask;
+ : while (mask)
+ : {
+ : index2 = (BITS32) lowbit (mask);
+ : mask &= ~index2;
+ : switch (index2)
+ : {
+ : case GCFunction:
+ : pgcDst->alu = pgcSrc->alu;
+ : break;
+ : case GCPlaneMask:
+ : pgcDst->planemask = pgcSrc->planemask;
+ : break;
+ : case GCForeground:
+ : pgcDst->fgPixel = pgcSrc->fgPixel;
+ : break;
+ : case GCBackground:
+ : pgcDst->bgPixel = pgcSrc->bgPixel;
+ : break;
+ : case GCLineWidth:
+ : pgcDst->lineWidth = pgcSrc->lineWidth;
+ : break;
+ : case GCLineStyle:
+ : pgcDst->lineStyle = pgcSrc->lineStyle;
+ : break;
+ : case GCCapStyle:
+ : pgcDst->capStyle = pgcSrc->capStyle;
+ : break;
+ : case GCJoinStyle:
+ : pgcDst->joinStyle = pgcSrc->joinStyle;
+ : break;
+ : case GCFillStyle:
+ : pgcDst->fillStyle = pgcSrc->fillStyle;
+ : break;
+ : case GCFillRule:
+ : pgcDst->fillRule = pgcSrc->fillRule;
+ : break;
+ : case GCTile:
+ : {
+ : if (EqualPixUnion(pgcDst->tileIsPixel,
+ : pgcDst->tile,
+ : pgcSrc->tileIsPixel,
+ : pgcSrc->tile))
+ : {
+ : break;
+ : }
+ : if (!pgcDst->tileIsPixel)
+ : (* pgcDst->pScreen->DestroyPixmap)(pgcDst->tile.pixmap);
+ : pgcDst->tileIsPixel = pgcSrc->tileIsPixel;
+ : pgcDst->tile = pgcSrc->tile;
+ : if (!pgcDst->tileIsPixel)
+ : pgcDst->tile.pixmap->refcnt++;
+ : break;
+ : }
+ : case GCStipple:
+ : {
+ : if (pgcDst->stipple == pgcSrc->stipple)
+ : break;
+ : if (pgcDst->stipple)
+ : (* pgcDst->pScreen->DestroyPixmap)(pgcDst->stipple);
+ : pgcDst->stipple = pgcSrc->stipple;
+ : if (pgcDst->stipple)
+ : pgcDst->stipple->refcnt ++;
+ : break;
+ : }
+ : case GCTileStipXOrigin:
+ : pgcDst->patOrg.x = pgcSrc->patOrg.x;
+ : break;
+ : case GCTileStipYOrigin:
+ : pgcDst->patOrg.y = pgcSrc->patOrg.y;
+ : break;
+ : case GCFont:
+ : if (pgcDst->font == pgcSrc->font)
+ : break;
+ : if (pgcDst->font)
+ : CloseFont(pgcDst->font, (Font)0);
+ : if ((pgcDst->font = pgcSrc->font) != NullFont)
+ : (pgcDst->font)->refcnt++;
+ : break;
+ : case GCSubwindowMode:
+ : pgcDst->subWindowMode = pgcSrc->subWindowMode;
+ : break;
+ : case GCGraphicsExposures:
+ : pgcDst->graphicsExposures = pgcSrc->graphicsExposures;
+ : break;
+ : case GCClipXOrigin:
+ : pgcDst->clipOrg.x = pgcSrc->clipOrg.x;
+ : break;
+ : case GCClipYOrigin:
+ : pgcDst->clipOrg.y = pgcSrc->clipOrg.y;
+ : break;
+ : case GCClipMask:
+ : (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
+ : break;
+ : case GCDashOffset:
+ : pgcDst->dashOffset = pgcSrc->dashOffset;
+ : break;
+ : case GCDashList:
+ : if (pgcSrc->dash == DefaultDash)
+ : {
+ : if (pgcDst->dash != DefaultDash)
+ : {
+ : xfree(pgcDst->dash);
+ : pgcDst->numInDashList = pgcSrc->numInDashList;
+ : pgcDst->dash = pgcSrc->dash;
+ : }
+ : }
+ : else
+ : {
+ : unsigned char *dash;
+ : unsigned int i;
+ :
+ : dash = (unsigned char *)xalloc(pgcSrc->numInDashList *
+ : sizeof(unsigned char));
+ : if (dash)
+ : {
+ : if (pgcDst->dash != DefaultDash)
+ : xfree(pgcDst->dash);
+ : pgcDst->numInDashList = pgcSrc->numInDashList;
+ : pgcDst->dash = dash;
+ : for (i=0; i<pgcSrc->numInDashList; i++)
+ : dash[i] = pgcSrc->dash[i];
+ : }
+ : else
+ : error = BadAlloc;
+ : }
+ : break;
+ : case GCArcMode:
+ : pgcDst->arcMode = pgcSrc->arcMode;
+ : break;
+ : default:
+ : clientErrorValue = maskQ;
+ : error = BadValue;
+ : break;
+ : }
+ : }
+ : if (pgcDst->fillStyle == FillTiled && pgcDst->tileIsPixel)
+ : {
+ : if (!CreateDefaultTile (pgcDst))
+ : {
+ : pgcDst->fillStyle = FillSolid;
+ : error = BadAlloc;
+ : }
+ : }
+ : (*pgcDst->funcs->CopyGC) (pgcSrc, maskQ, pgcDst);
+ : return error;
+ :}
+ :
+ :/**
+ : * does the diX part of freeing the characteristics in the GC.
+ : *
+ : * \param value must conform to DeleteType
+ : */
+ :_X_EXPORT int
+ :FreeGC(pointer value, XID gid)
+ :{ /* FreeGC total: 1 0.0011 */
+ : GCPtr pGC = (GCPtr)value;
+ :
+ : CloseFont(pGC->font, (Font)0);
+ : (* pGC->funcs->DestroyClip)(pGC);
+ :
+ : if (!pGC->tileIsPixel)
+ : (* pGC->pScreen->DestroyPixmap)(pGC->tile.pixmap);
+ : if (pGC->stipple)
+ : (* pGC->pScreen->DestroyPixmap)(pGC->stipple);
+ :
+ : (*pGC->funcs->DestroyGC) (pGC);
+ 1 0.0011 : if (pGC->dash != DefaultDash)
+ : xfree(pGC->dash);
+ : xfree(pGC);
+ : return(Success);
+ :}
+ :
+ :/* CreateScratchGC(pScreen, depth)
+ : like CreateGC, but doesn't do the default tile or stipple,
+ :since we can't create them without already having a GC. any code
+ :using the tile or stipple has to set them explicitly anyway,
+ :since the state of the scratch gc is unknown. This is OK
+ :because ChangeGC() has to be able to deal with NULL tiles and
+ :stipples anyway (in case the CreateGC() call has provided a
+ :value for them -- we can't set the default tile until the
+ :client-supplied attributes are installed, since the fgPixel
+ :is what fills the default tile. (maybe this comment should
+ :go with CreateGC() or ChangeGC().)
+ :*/
+ :
+ :_X_EXPORT GCPtr
+ :CreateScratchGC(ScreenPtr pScreen, unsigned depth)
+ :{
+ : GCPtr pGC;
+ :
+ : pGC = AllocateGC(pScreen);
+ : if (!pGC)
+ : return (GCPtr)NULL;
+ :
+ : pGC->pScreen = pScreen;
+ : pGC->depth = depth;
+ : pGC->alu = GXcopy; /* dst <- src */
+ : pGC->planemask = ~0;
+ : pGC->serialNumber = 0;
+ :
+ : pGC->fgPixel = 0;
+ : pGC->bgPixel = 1;
+ : pGC->lineWidth = 0;
+ : pGC->lineStyle = LineSolid;
+ : pGC->capStyle = CapButt;
+ : pGC->joinStyle = JoinMiter;
+ : pGC->fillStyle = FillSolid;
+ : pGC->fillRule = EvenOddRule;
+ : pGC->arcMode = ArcPieSlice;
+ : pGC->font = defaultFont;
+ : if ( pGC->font) /* necessary, because open of default font could fail */
+ : pGC->font->refcnt++;
+ : pGC->tileIsPixel = TRUE;
+ : pGC->tile.pixel = 0;
+ : pGC->stipple = NullPixmap;
+ : pGC->patOrg.x = 0;
+ : pGC->patOrg.y = 0;
+ : pGC->subWindowMode = ClipByChildren;
+ : pGC->graphicsExposures = TRUE;
+ : pGC->clipOrg.x = 0;
+ : pGC->clipOrg.y = 0;
+ : pGC->clientClipType = CT_NONE;
+ : pGC->dashOffset = 0;
+ : pGC->numInDashList = 2;
+ : pGC->dash = DefaultDash;
+ : pGC->lastWinOrg.x = 0;
+ : pGC->lastWinOrg.y = 0;
+ :
+ : pGC->stateChanges = (1 << (GCLastBit+1)) - 1;
+ : if (!(*pScreen->CreateGC)(pGC))
+ : {
+ : FreeGC(pGC, (XID)0);
+ : pGC = (GCPtr)NULL;
+ : }
+ : return pGC;
+ :}
+ :
+ :void
+ :FreeGCperDepth(int screenNum)
+ :{
+ : int i;
+ : ScreenPtr pScreen;
+ : GCPtr *ppGC;
+ :
+ : pScreen = screenInfo.screens[screenNum];
+ : ppGC = pScreen->GCperDepth;
+ :
+ : for (i = 0; i <= pScreen->numDepths; i++)
+ : (void)FreeGC(ppGC[i], (XID)0);
+ : pScreen->rgf = ~0L;
+ :}
+ :
+ :
+ :Bool
+ :CreateGCperDepth(int screenNum)
+ :{
+ : int i;
+ : ScreenPtr pScreen;
+ : DepthPtr pDepth;
+ : GCPtr *ppGC;
+ :
+ : pScreen = screenInfo.screens[screenNum];
+ : pScreen->rgf = 0;
+ : ppGC = pScreen->GCperDepth;
+ : /* do depth 1 separately because it's not included in list */
+ : if (!(ppGC[0] = CreateScratchGC(pScreen, 1)))
+ : return FALSE;
+ : ppGC[0]->graphicsExposures = FALSE;
+ : /* Make sure we don't overflow GCperDepth[] */
+ : if( pScreen->numDepths > MAXFORMATS )
+ : return FALSE;
+ :
+ : pDepth = pScreen->allowedDepths;
+ : for (i=0; i<pScreen->numDepths; i++, pDepth++)
+ : {
+ : if (!(ppGC[i+1] = CreateScratchGC(pScreen, pDepth->depth)))
+ : {
+ : for (; i >= 0; i--)
+ : (void)FreeGC(ppGC[i], (XID)0);
+ : return FALSE;
+ : }
+ : ppGC[i+1]->graphicsExposures = FALSE;
+ : }
+ : return TRUE;
+ :}
+ :
+ :Bool
+ :CreateDefaultStipple(int screenNum)
+ :{
+ : ScreenPtr pScreen;
+ : XID tmpval[3];
+ : xRectangle rect;
+ : CARD16 w, h;
+ : GCPtr pgcScratch;
+ :
+ : pScreen = screenInfo.screens[screenNum];
+ :
+ : w = 16;
+ : h = 16;
+ : (* pScreen->QueryBestSize)(StippleShape, &w, &h, pScreen);
+ : if (!(pScreen->PixmapPerDepth[0] =
+ : (*pScreen->CreatePixmap)(pScreen, w, h, 1)))
+ : return FALSE;
+ : /* fill stipple with 1 */
+ : tmpval[0] = GXcopy; tmpval[1] = 1; tmpval[2] = FillSolid;
+ : pgcScratch = GetScratchGC(1, pScreen);
+ : if (!pgcScratch)
+ : {
+ : (*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]);
+ : return FALSE;
+ : }
+ : (void)ChangeGC(pgcScratch, GCFunction|GCForeground|GCFillStyle, tmpval);
+ : ValidateGC((DrawablePtr)pScreen->PixmapPerDepth[0], pgcScratch);
+ : rect.x = 0;
+ : rect.y = 0;
+ : rect.width = w;
+ : rect.height = h;
+ : (*pgcScratch->ops->PolyFillRect)((DrawablePtr)pScreen->PixmapPerDepth[0],
+ : pgcScratch, 1, &rect);
+ : FreeScratchGC(pgcScratch);
+ : return TRUE;
+ :}
+ :
+ :void
+ :FreeDefaultStipple(int screenNum)
+ :{
+ : ScreenPtr pScreen = screenInfo.screens[screenNum];
+ : (*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]);
+ :}
+ :
+ :_X_EXPORT int
+ :SetDashes(GCPtr pGC, unsigned offset, unsigned ndash, unsigned char *pdash)
+ :{
+ : long i;
+ : unsigned char *p, *indash;
+ : BITS32 maskQ = 0;
+ :
+ : i = ndash;
+ : p = pdash;
+ : while (i--)
+ : {
+ : if (!*p++)
+ : {
+ : /* dash segment must be > 0 */
+ : clientErrorValue = 0;
+ : return BadValue;
+ : }
+ : }
+ :
+ : if (ndash & 1)
+ : p = (unsigned char *)xalloc(2 * ndash * sizeof(unsigned char));
+ : else
+ : p = (unsigned char *)xalloc(ndash * sizeof(unsigned char));
+ : if (!p)
+ : return BadAlloc;
+ :
+ : pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
+ : if (offset != pGC->dashOffset)
+ : {
+ : pGC->dashOffset = offset;
+ : pGC->stateChanges |= GCDashOffset;
+ : maskQ |= GCDashOffset;
+ : }
+ :
+ : if (pGC->dash != DefaultDash)
+ : xfree(pGC->dash);
+ : pGC->numInDashList = ndash;
+ : pGC->dash = p;
+ : if (ndash & 1)
+ : {
+ : pGC->numInDashList += ndash;
+ : indash = pdash;
+ : i = ndash;
+ : while (i--)
+ : *p++ = *indash++;
+ : }
+ : while(ndash--)
+ : *p++ = *pdash++;
+ : pGC->stateChanges |= GCDashList;
+ : maskQ |= GCDashList;
+ :
+ : if (pGC->funcs->ChangeGC)
+ : (*pGC->funcs->ChangeGC) (pGC, maskQ);
+ : return Success;
+ :}
+ :
+ :_X_EXPORT int
+ :VerifyRectOrder(int nrects, xRectangle *prects, int ordering)
+ :{ /* VerifyRectOrder total: 1 0.0011 */
+ : xRectangle *prectP, *prectN;
+ : int i;
+ :
+ : switch(ordering)
+ : {
+ : case Unsorted:
+ : return CT_UNSORTED;
+ : case YSorted:
+ : if(nrects > 1)
+ : {
+ : for(i = 1, prectP = prects, prectN = prects + 1;
+ : i < nrects;
+ : i++, prectP++, prectN++)
+ : if(prectN->y < prectP->y)
+ : return -1;
+ : }
+ : return CT_YSORTED;
+ : case YXSorted:
+ : if(nrects > 1)
+ : {
+ : for(i = 1, prectP = prects, prectN = prects + 1;
+ : i < nrects;
+ : i++, prectP++, prectN++)
+ : if((prectN->y < prectP->y) ||
+ : ( (prectN->y == prectP->y) &&
+ : (prectN->x < prectP->x) ) )
+ : return -1;
+ : }
+ : return CT_YXSORTED;
+ : case YXBanded:
+ 1 0.0011 : if(nrects > 1)
+ : {
+ : for(i = 1, prectP = prects, prectN = prects + 1;
+ : i < nrects;
+ : i++, prectP++, prectN++)
+ : if((prectN->y != prectP->y &&
+ : prectN->y < prectP->y + (int) prectP->height) ||
+ : ((prectN->y == prectP->y) &&
+ : (prectN->height != prectP->height ||
+ : prectN->x < prectP->x + (int) prectP->width)))
+ : return -1;
+ : }
+ : return CT_YXBANDED;
+ : }
+ : return -1;
+ :}
+ :
+ :_X_EXPORT int
+ :SetClipRects(GCPtr pGC, int xOrigin, int yOrigin, int nrects,
+ : xRectangle *prects, int ordering)
+ :{ /* SetClipRects total: 2 0.0022 */
+ : int newct, size;
+ : xRectangle *prectsNew;
+ :
+ : newct = VerifyRectOrder(nrects, prects, ordering);
+ : if (newct < 0)
+ : return(BadMatch);
+ : size = nrects * sizeof(xRectangle);
+ : prectsNew = (xRectangle *) xalloc(size);
+ : if (!prectsNew && size)
+ : return BadAlloc;
+ :
+ : pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
+ 1 0.0011 : pGC->clipOrg.x = xOrigin;
+ : pGC->stateChanges |= GCClipXOrigin;
+ :
+ : pGC->clipOrg.y = yOrigin;
+ : pGC->stateChanges |= GCClipYOrigin;
+ :
+ : if (size)
+ : memmove((char *)prectsNew, (char *)prects, size);
+ : (*pGC->funcs->ChangeClip)(pGC, newct, (pointer)prectsNew, nrects);
+ 1 0.0011 : if (pGC->funcs->ChangeGC)
+ : (*pGC->funcs->ChangeGC) (pGC, GCClipXOrigin|GCClipYOrigin|GCClipMask);
+ : return Success;
+ :}
+ :
+ :
+ :/*
+ : sets reasonable defaults
+ : if we can get a pre-allocated one, use it and mark it as used.
+ : if we can't, create one out of whole cloth (The Velveteen GC -- if
+ : you use it often enough it will become real.)
+ :*/
+ :_X_EXPORT GCPtr
+ :GetScratchGC(unsigned depth, ScreenPtr pScreen)
+ 2 0.0022 :{ /* GetScratchGC total: 8 0.0087 */
+ : int i;
+ : GCPtr pGC;
+ :
+ : for (i=0; i<=pScreen->numDepths; i++)
+ 2 0.0022 : if ( pScreen->GCperDepth[i]->depth == depth &&
+ : !(pScreen->rgf & (1L << (i+1)))
+ : )
+ : {
+ : pScreen->rgf |= (1L << (i+1));
+ : pGC = (pScreen->GCperDepth[i]);
+ :
+ : pGC->alu = GXcopy;
+ : pGC->planemask = ~0;
+ : pGC->serialNumber = 0;
+ : pGC->fgPixel = 0;
+ : pGC->bgPixel = 1;
+ : pGC->lineWidth = 0;
+ : pGC->lineStyle = LineSolid;
+ : pGC->capStyle = CapButt;
+ : pGC->joinStyle = JoinMiter;
+ : pGC->fillStyle = FillSolid;
+ : pGC->fillRule = EvenOddRule;
+ : pGC->arcMode = ArcChord;
+ 3 0.0033 : pGC->patOrg.x = 0;
+ : pGC->patOrg.y = 0;
+ : pGC->subWindowMode = ClipByChildren;
+ : pGC->graphicsExposures = FALSE;
+ : pGC->clipOrg.x = 0;
+ : pGC->clipOrg.y = 0;
+ : if (pGC->clientClipType != CT_NONE)
+ : (*pGC->funcs->ChangeClip) (pGC, CT_NONE, NULL, 0);
+ : pGC->stateChanges = (1 << (GCLastBit+1)) - 1;
+ : return pGC;
+ : }
+ : /* if we make it this far, need to roll our own */
+ : pGC = CreateScratchGC(pScreen, depth);
+ : if (pGC)
+ : pGC->graphicsExposures = FALSE;
+ : return pGC;
+ 1 0.0011 :}
+ :
+ :/*
+ : if the gc to free is in the table of pre-existing ones,
+ :mark it as available.
+ : if not, free it for real
+ :*/
+ :_X_EXPORT void
+ :FreeScratchGC(GCPtr pGC)
+ 4 0.0044 :{ /* FreeScratchGC total: 10 0.0109 */
+ : ScreenPtr pScreen = pGC->pScreen;
+ : int i;
+ :
+ 1 0.0011 : for (i=0; i<=pScreen->numDepths; i++)
+ : {
+ 3 0.0033 : if ( pScreen->GCperDepth[i] == pGC)
+ : {
+ : pScreen->rgf &= ~(1L << (i+1));
+ 1 0.0011 : return;
+ : }
+ : }
+ : (void)FreeGC(pGC, (GContext)0);
+ 1 0.0011 :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/Xext/security.c"
+ *
+ * 50 0.0545
+ */
+
+
+ :/*
+ :
+ :Copyright 1996, 1998 The Open Group
+ :
+ :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.
+ :
+ :The above copyright notice and this permission notice shall be included in
+ :all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ :IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ :FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ :OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ :AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ :CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of The Open Group shall not be
+ :used in advertising or otherwise to promote the sale, use or other dealings
+ :in this Software without prior written authorization from The Open Group.
+ :
+ :*/
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include "dixstruct.h"
+ :#include "extnsionst.h"
+ :#include "windowstr.h"
+ :#include "inputstr.h"
+ :#include "scrnintstr.h"
+ :#include "gcstruct.h"
+ :#include "colormapst.h"
+ :#include "propertyst.h"
+ :#include "xacestr.h"
+ :#include "securitysrv.h"
+ :#include <X11/extensions/securstr.h>
+ :#include <assert.h>
+ :#include <stdarg.h>
+ :#ifdef XAPPGROUP
+ :#include "appgroup.h"
+ :#endif
+ :#include <stdio.h> /* for file reading operations */
+ :#include <X11/Xatom.h> /* for XA_STRING */
+ :
+ :#ifndef DEFAULTPOLICYFILE
+ :# define DEFAULTPOLICYFILE NULL
+ :#endif
+ :#if defined(WIN32) || defined(__CYGWIN__)
+ :#include <X11/Xos.h>
+ :#undef index
+ :#endif
+ :
+ :#include "modinit.h"
+ :
+ :static int SecurityErrorBase; /* first Security error number */
+ :static int SecurityEventBase; /* first Security event number */
+ :static int securityClientPrivateIndex;
+ :static int securityExtnsnPrivateIndex;
+ :
+ :/* this is what we store as client security state */
+ :typedef struct {
+ : unsigned int trustLevel;
+ : XID authId;
+ :} SecurityClientStateRec;
+ :
+ :#define STATEVAL(extnsn) \
+ : ((extnsn)->devPrivates[securityExtnsnPrivateIndex].val)
+ :#define STATEPTR(client) \
+ : ((client)->devPrivates[securityClientPrivateIndex].ptr)
+ :#define TRUSTLEVEL(client) \
+ : (((SecurityClientStateRec*)STATEPTR(client))->trustLevel)
+ :#define AUTHID(client) \
+ : (((SecurityClientStateRec*)STATEPTR(client))->authId)
+ :
+ :static CallbackListPtr SecurityValidateGroupCallback = NULL;
+ :
+ :RESTYPE SecurityAuthorizationResType; /* resource type for authorizations */
+ :
+ :static RESTYPE RTEventClient;
+ :
+ :#define CALLBACK(name) static void \
+ :name(CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
+ :
+ :/* SecurityAudit
+ : *
+ : * Arguments:
+ : * format is the formatting string to be used to interpret the
+ : * remaining arguments.
+ : *
+ : * Returns: nothing.
+ : *
+ : * Side Effects:
+ : * Writes the message to the log file if security logging is on.
+ : */
+ :
+ :static void
+ :SecurityAudit(char *format, ...)
+ :{
+ : va_list args;
+ :
+ : if (auditTrailLevel < SECURITY_AUDIT_LEVEL)
+ : return;
+ : va_start(args, format);
+ : VAuditF(format, args);
+ : va_end(args);
+ :} /* SecurityAudit */
+ :
+ :#define rClient(obj) (clients[CLIENT_ID((obj)->resource)])
+ :
+ :/* SecurityDeleteAuthorization
+ : *
+ : * Arguments:
+ : * value is the authorization to delete.
+ : * id is its resource ID.
+ : *
+ : * Returns: Success.
+ : *
+ : * Side Effects:
+ : * Frees everything associated with the authorization.
+ : */
+ :
+ :static int
+ :SecurityDeleteAuthorization(
+ : pointer value,
+ : XID id)
+ :{
+ : SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)value;
+ : unsigned short name_len, data_len;
+ : char *name, *data;
+ : int status;
+ : int i;
+ : OtherClientsPtr pEventClient;
+ :
+ : /* Remove the auth using the os layer auth manager */
+ :
+ : status = AuthorizationFromID(pAuth->id, &name_len, &name,
+ : &data_len, &data);
+ : assert(status);
+ : status = RemoveAuthorization(name_len, name, data_len, data);
+ : assert(status);
+ : (void)status;
+ :
+ : /* free the auth timer if there is one */
+ :
+ : if (pAuth->timer) TimerFree(pAuth->timer);
+ :
+ : /* send revoke events */
+ :
+ : while ((pEventClient = pAuth->eventClients))
+ : {
+ : /* send revocation event event */
+ : ClientPtr client = rClient(pEventClient);
+ :
+ : if (!client->clientGone)
+ : {
+ : xSecurityAuthorizationRevokedEvent are;
+ : are.type = SecurityEventBase + XSecurityAuthorizationRevoked;
+ : are.sequenceNumber = client->sequence;
+ : are.authId = pAuth->id;
+ : WriteEventsToClient(client, 1, (xEvent *)&are);
+ : }
+ : FreeResource(pEventClient->resource, RT_NONE);
+ : }
+ :
+ : /* kill all clients using this auth */
+ :
+ : for (i = 1; i<currentMaxClients; i++)
+ : {
+ : if (clients[i] && (AUTHID(clients[i]) == pAuth->id))
+ : CloseDownClient(clients[i]);
+ : }
+ :
+ : SecurityAudit("revoked authorization ID %d\n", pAuth->id);
+ : xfree(pAuth);
+ : return Success;
+ :
+ :} /* SecurityDeleteAuthorization */
+ :
+ :
+ :/* resource delete function for RTEventClient */
+ :static int
+ :SecurityDeleteAuthorizationEventClient(
+ : pointer value,
+ : XID id)
+ :{
+ : OtherClientsPtr pEventClient, prev = NULL;
+ : SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)value;
+ :
+ : for (pEventClient = pAuth->eventClients;
+ : pEventClient;
+ : pEventClient = pEventClient->next)
+ : {
+ : if (pEventClient->resource == id)
+ : {
+ : if (prev)
+ : prev->next = pEventClient->next;
+ : else
+ : pAuth->eventClients = pEventClient->next;
+ : xfree(pEventClient);
+ : return(Success);
+ : }
+ : prev = pEventClient;
+ : }
+ : /*NOTREACHED*/
+ : return -1; /* make compiler happy */
+ :} /* SecurityDeleteAuthorizationEventClient */
+ :
+ :
+ :/* SecurityComputeAuthorizationTimeout
+ : *
+ : * Arguments:
+ : * pAuth is the authorization for which we are computing the timeout
+ : * seconds is the number of seconds we want to wait
+ : *
+ : * Returns:
+ : * the number of milliseconds that the auth timer should be set to
+ : *
+ : * Side Effects:
+ : * Sets pAuth->secondsRemaining to any "overflow" amount of time
+ : * that didn't fit in 32 bits worth of milliseconds
+ : */
+ :
+ :static CARD32
+ :SecurityComputeAuthorizationTimeout(
+ : SecurityAuthorizationPtr pAuth,
+ : unsigned int seconds)
+ :{
+ : /* maxSecs is the number of full seconds that can be expressed in
+ : * 32 bits worth of milliseconds
+ : */
+ : CARD32 maxSecs = (CARD32)(~0) / (CARD32)MILLI_PER_SECOND;
+ :
+ : if (seconds > maxSecs)
+ : { /* only come here if we want to wait more than 49 days */
+ : pAuth->secondsRemaining = seconds - maxSecs;
+ : return maxSecs * MILLI_PER_SECOND;
+ : }
+ : else
+ : { /* by far the common case */
+ : pAuth->secondsRemaining = 0;
+ : return seconds * MILLI_PER_SECOND;
+ : }
+ :} /* SecurityStartAuthorizationTimer */
+ :
+ :/* SecurityAuthorizationExpired
+ : *
+ : * This function is passed as an argument to TimerSet and gets called from
+ : * the timer manager in the os layer when its time is up.
+ : *
+ : * Arguments:
+ : * timer is the timer for this authorization.
+ : * time is the current time.
+ : * pval is the authorization whose time is up.
+ : *
+ : * Returns:
+ : * A new time delay in milliseconds if the timer should wait some
+ : * more, else zero.
+ : *
+ : * Side Effects:
+ : * Frees the authorization resource if the timeout period is really
+ : * over, otherwise recomputes pAuth->secondsRemaining.
+ : */
+ :
+ :static CARD32
+ :SecurityAuthorizationExpired(
+ : OsTimerPtr timer,
+ : CARD32 time,
+ : pointer pval)
+ :{
+ : SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)pval;
+ :
+ : assert(pAuth->timer == timer);
+ :
+ : if (pAuth->secondsRemaining)
+ : {
+ : return SecurityComputeAuthorizationTimeout(pAuth,
+ : pAuth->secondsRemaining);
+ : }
+ : else
+ : {
+ : FreeResource(pAuth->id, RT_NONE);
+ : return 0;
+ : }
+ :} /* SecurityAuthorizationExpired */
+ :
+ :/* SecurityStartAuthorizationTimer
+ : *
+ : * Arguments:
+ : * pAuth is the authorization whose timer should be started.
+ : *
+ : * Returns: nothing.
+ : *
+ : * Side Effects:
+ : * A timer is started, set to expire after the timeout period for
+ : * this authorization. When it expires, the function
+ : * SecurityAuthorizationExpired will be called.
+ : */
+ :
+ :static void
+ :SecurityStartAuthorizationTimer(
+ : SecurityAuthorizationPtr pAuth)
+ :{
+ : pAuth->timer = TimerSet(pAuth->timer, 0,
+ : SecurityComputeAuthorizationTimeout(pAuth, pAuth->timeout),
+ : SecurityAuthorizationExpired, pAuth);
+ :} /* SecurityStartAuthorizationTimer */
+ :
+ :
+ :/* Proc functions all take a client argument, execute the request in
+ : * client->requestBuffer, and return a protocol error status.
+ : */
+ :
+ :static int
+ :ProcSecurityQueryVersion(
+ : ClientPtr client)
+ :{
+ : /* REQUEST(xSecurityQueryVersionReq); */
+ : xSecurityQueryVersionReply rep;
+ :
+ : /* paranoia: this "can't happen" because this extension is hidden
+ : * from untrusted clients, but just in case...
+ : */
+ : if (TRUSTLEVEL(client) != XSecurityClientTrusted)
+ : return BadRequest;
+ :
+ : REQUEST_SIZE_MATCH(xSecurityQueryVersionReq);
+ : rep.type = X_Reply;
+ : rep.sequenceNumber = client->sequence;
+ : rep.length = 0;
+ : rep.majorVersion = SECURITY_MAJOR_VERSION;
+ : rep.minorVersion = SECURITY_MINOR_VERSION;
+ : if(client->swapped)
+ : {
+ : register char n;
+ : swaps(&rep.sequenceNumber, n);
+ : swaps(&rep.majorVersion, n);
+ : swaps(&rep.minorVersion, n);
+ : }
+ : (void)WriteToClient(client, SIZEOF(xSecurityQueryVersionReply),
+ : (char *)&rep);
+ : return (client->noClientException);
+ :} /* ProcSecurityQueryVersion */
+ :
+ :
+ :static int
+ :SecurityEventSelectForAuthorization(
+ : SecurityAuthorizationPtr pAuth,
+ : ClientPtr client,
+ : Mask mask)
+ :{
+ : OtherClients *pEventClient;
+ :
+ : for (pEventClient = pAuth->eventClients;
+ : pEventClient;
+ : pEventClient = pEventClient->next)
+ : {
+ : if (SameClient(pEventClient, client))
+ : {
+ : if (mask == 0)
+ : FreeResource(pEventClient->resource, RT_NONE);
+ : else
+ : pEventClient->mask = mask;
+ : return Success;
+ : }
+ : }
+ :
+ : pEventClient = (OtherClients *) xalloc(sizeof(OtherClients));
+ : if (!pEventClient)
+ : return BadAlloc;
+ : pEventClient->mask = mask;
+ : pEventClient->resource = FakeClientID(client->index);
+ : pEventClient->next = pAuth->eventClients;
+ : if (!AddResource(pEventClient->resource, RTEventClient,
+ : (pointer)pAuth))
+ : {
+ : xfree(pEventClient);
+ : return BadAlloc;
+ : }
+ : pAuth->eventClients = pEventClient;
+ :
+ : return Success;
+ :} /* SecurityEventSelectForAuthorization */
+ :
+ :
+ :static int
+ :ProcSecurityGenerateAuthorization(
+ : ClientPtr client)
+ :{
+ : REQUEST(xSecurityGenerateAuthorizationReq);
+ : int len; /* request length in CARD32s*/
+ : Bool removeAuth = FALSE; /* if bailout, call RemoveAuthorization? */
+ : SecurityAuthorizationPtr pAuth = NULL; /* auth we are creating */
+ : int err; /* error to return from this function */
+ : XID authId; /* authorization ID assigned by os layer */
+ : xSecurityGenerateAuthorizationReply rep; /* reply struct */
+ : unsigned int trustLevel; /* trust level of new auth */
+ : XID group; /* group of new auth */
+ : CARD32 timeout; /* timeout of new auth */
+ : CARD32 *values; /* list of supplied attributes */
+ : char *protoname; /* auth proto name sent in request */
+ : char *protodata; /* auth proto data sent in request */
+ : unsigned int authdata_len; /* # bytes of generated auth data */
+ : char *pAuthdata; /* generated auth data */
+ : Mask eventMask; /* what events on this auth does client want */
+ :
+ : /* paranoia: this "can't happen" because this extension is hidden
+ : * from untrusted clients, but just in case...
+ : */
+ : if (TRUSTLEVEL(client) != XSecurityClientTrusted)
+ : return BadRequest;
+ :
+ : /* check request length */
+ :
+ : REQUEST_AT_LEAST_SIZE(xSecurityGenerateAuthorizationReq);
+ : len = SIZEOF(xSecurityGenerateAuthorizationReq) >> 2;
+ : len += (stuff->nbytesAuthProto + (unsigned)3) >> 2;
+ : len += (stuff->nbytesAuthData + (unsigned)3) >> 2;
+ : values = ((CARD32 *)stuff) + len;
+ : len += Ones(stuff->valueMask);
+ : if (client->req_len != len)
+ : return BadLength;
+ :
+ : /* check valuemask */
+ : if (stuff->valueMask & ~XSecurityAllAuthorizationAttributes)
+ : {
+ : client->errorValue = stuff->valueMask;
+ : return BadValue;
+ : }
+ :
+ : /* check timeout */
+ : timeout = 60;
+ : if (stuff->valueMask & XSecurityTimeout)
+ : {
+ : timeout = *values++;
+ : }
+ :
+ : /* check trustLevel */
+ : trustLevel = XSecurityClientUntrusted;
+ : if (stuff->valueMask & XSecurityTrustLevel)
+ : {
+ : trustLevel = *values++;
+ : if (trustLevel != XSecurityClientTrusted &&
+ : trustLevel != XSecurityClientUntrusted)
+ : {
+ : client->errorValue = trustLevel;
+ : return BadValue;
+ : }
+ : }
+ :
+ : /* check group */
+ : group = None;
+ : if (stuff->valueMask & XSecurityGroup)
+ : {
+ : group = *values++;
+ : if (SecurityValidateGroupCallback)
+ : {
+ : SecurityValidateGroupInfoRec vgi;
+ : vgi.group = group;
+ : vgi.valid = FALSE;
+ : CallCallbacks(&SecurityValidateGroupCallback, (pointer)&vgi);
+ :
+ : /* if nobody said they recognized it, it's an error */
+ :
+ : if (!vgi.valid)
+ : {
+ : client->errorValue = group;
+ : return BadValue;
+ : }
+ : }
+ : }
+ :
+ : /* check event mask */
+ : eventMask = 0;
+ : if (stuff->valueMask & XSecurityEventMask)
+ : {
+ : eventMask = *values++;
+ : if (eventMask & ~XSecurityAllEventMasks)
+ : {
+ : client->errorValue = eventMask;
+ : return BadValue;
+ : }
+ : }
+ :
+ : protoname = (char *)&stuff[1];
+ : protodata = protoname + ((stuff->nbytesAuthProto + (unsigned)3) >> 2);
+ :
+ : /* call os layer to generate the authorization */
+ :
+ : authId = GenerateAuthorization(stuff->nbytesAuthProto, protoname,
+ : stuff->nbytesAuthData, protodata,
+ : &authdata_len, &pAuthdata);
+ : if ((XID) ~0L == authId)
+ : {
+ : err = SecurityErrorBase + XSecurityBadAuthorizationProtocol;
+ : goto bailout;
+ : }
+ :
+ : /* now that we've added the auth, remember to remove it if we have to
+ : * abort the request for some reason (like allocation failure)
+ : */
+ : removeAuth = TRUE;
+ :
+ : /* associate additional information with this auth ID */
+ :
+ : pAuth = (SecurityAuthorizationPtr)xalloc(sizeof(SecurityAuthorizationRec));
+ : if (!pAuth)
+ : {
+ : err = BadAlloc;
+ : goto bailout;
+ : }
+ :
+ : /* fill in the auth fields */
+ :
+ : pAuth->id = authId;
+ : pAuth->timeout = timeout;
+ : pAuth->group = group;
+ : pAuth->trustLevel = trustLevel;
+ : pAuth->refcnt = 0; /* the auth was just created; nobody's using it yet */
+ : pAuth->secondsRemaining = 0;
+ : pAuth->timer = NULL;
+ : pAuth->eventClients = NULL;
+ :
+ : /* handle event selection */
+ : if (eventMask)
+ : {
+ : err = SecurityEventSelectForAuthorization(pAuth, client, eventMask);
+ : if (err != Success)
+ : goto bailout;
+ : }
+ :
+ : if (!AddResource(authId, SecurityAuthorizationResType, pAuth))
+ : {
+ : err = BadAlloc;
+ : goto bailout;
+ : }
+ :
+ : /* start the timer ticking */
+ :
+ : if (pAuth->timeout != 0)
+ : SecurityStartAuthorizationTimer(pAuth);
+ :
+ : /* tell client the auth id and data */
+ :
+ : rep.type = X_Reply;
+ : rep.length = (authdata_len + 3) >> 2;
+ : rep.sequenceNumber = client->sequence;
+ : rep.authId = authId;
+ : rep.dataLength = authdata_len;
+ :
+ : if (client->swapped)
+ : {
+ : register char n;
+ : swapl(&rep.length, n);
+ : swaps(&rep.sequenceNumber, n);
+ : swapl(&rep.authId, n);
+ : swaps(&rep.dataLength, n);
+ : }
+ :
+ : WriteToClient(client, SIZEOF(xSecurityGenerateAuthorizationReply),
+ : (char *)&rep);
+ : WriteToClient(client, authdata_len, pAuthdata);
+ :
+ : SecurityAudit("client %d generated authorization %d trust %d timeout %d group %d events %d\n",
+ : client->index, pAuth->id, pAuth->trustLevel, pAuth->timeout,
+ : pAuth->group, eventMask);
+ :
+ : /* the request succeeded; don't call RemoveAuthorization or free pAuth */
+ :
+ : removeAuth = FALSE;
+ : pAuth = NULL;
+ : err = client->noClientException;
+ :
+ :bailout:
+ : if (removeAuth)
+ : RemoveAuthorization(stuff->nbytesAuthProto, protoname,
+ : authdata_len, pAuthdata);
+ : if (pAuth) xfree(pAuth);
+ : return err;
+ :
+ :} /* ProcSecurityGenerateAuthorization */
+ :
+ :static int
+ :ProcSecurityRevokeAuthorization(
+ : ClientPtr client)
+ :{
+ : REQUEST(xSecurityRevokeAuthorizationReq);
+ : SecurityAuthorizationPtr pAuth;
+ :
+ : /* paranoia: this "can't happen" because this extension is hidden
+ : * from untrusted clients, but just in case...
+ : */
+ : if (TRUSTLEVEL(client) != XSecurityClientTrusted)
+ : return BadRequest;
+ :
+ : REQUEST_SIZE_MATCH(xSecurityRevokeAuthorizationReq);
+ :
+ : pAuth = (SecurityAuthorizationPtr)SecurityLookupIDByType(client,
+ : stuff->authId, SecurityAuthorizationResType, DixDestroyAccess);
+ : if (!pAuth)
+ : return SecurityErrorBase + XSecurityBadAuthorization;
+ :
+ : FreeResource(stuff->authId, RT_NONE);
+ : return Success;
+ :} /* ProcSecurityRevokeAuthorization */
+ :
+ :
+ :static int
+ :ProcSecurityDispatch(
+ : ClientPtr client)
+ :{
+ : REQUEST(xReq);
+ :
+ : switch (stuff->data)
+ : {
+ : case X_SecurityQueryVersion:
+ : return ProcSecurityQueryVersion(client);
+ : case X_SecurityGenerateAuthorization:
+ : return ProcSecurityGenerateAuthorization(client);
+ : case X_SecurityRevokeAuthorization:
+ : return ProcSecurityRevokeAuthorization(client);
+ : default:
+ : return BadRequest;
+ : }
+ :} /* ProcSecurityDispatch */
+ :
+ :static int
+ :SProcSecurityQueryVersion(
+ : ClientPtr client)
+ :{
+ : REQUEST(xSecurityQueryVersionReq);
+ : register char n;
+ :
+ : swaps(&stuff->length, n);
+ : REQUEST_SIZE_MATCH(xSecurityQueryVersionReq);
+ : swaps(&stuff->majorVersion, n);
+ : swaps(&stuff->minorVersion,n);
+ : return ProcSecurityQueryVersion(client);
+ :} /* SProcSecurityQueryVersion */
+ :
+ :
+ :static int
+ :SProcSecurityGenerateAuthorization(
+ : ClientPtr client)
+ :{
+ : REQUEST(xSecurityGenerateAuthorizationReq);
+ : register char n;
+ : CARD32 *values;
+ : unsigned long nvalues;
+ :
+ : swaps(&stuff->length, n);
+ : REQUEST_AT_LEAST_SIZE(xSecurityGenerateAuthorizationReq);
+ : swaps(&stuff->nbytesAuthProto, n);
+ : swaps(&stuff->nbytesAuthData, n);
+ : swapl(&stuff->valueMask, n);
+ : values = (CARD32 *)(&stuff[1]) +
+ : ((stuff->nbytesAuthProto + (unsigned)3) >> 2) +
+ : ((stuff->nbytesAuthData + (unsigned)3) >> 2);
+ : nvalues = (((CARD32 *)stuff) + stuff->length) - values;
+ : SwapLongs(values, nvalues);
+ : return ProcSecurityGenerateAuthorization(client);
+ :} /* SProcSecurityGenerateAuthorization */
+ :
+ :
+ :static int
+ :SProcSecurityRevokeAuthorization(
+ : ClientPtr client)
+ :{
+ : REQUEST(xSecurityRevokeAuthorizationReq);
+ : register char n;
+ :
+ : swaps(&stuff->length, n);
+ : REQUEST_SIZE_MATCH(xSecurityRevokeAuthorizationReq);
+ : swapl(&stuff->authId, n);
+ : return ProcSecurityRevokeAuthorization(client);
+ :} /* SProcSecurityRevokeAuthorization */
+ :
+ :
+ :static int
+ :SProcSecurityDispatch(
+ : ClientPtr client)
+ :{
+ : REQUEST(xReq);
+ :
+ : switch (stuff->data)
+ : {
+ : case X_SecurityQueryVersion:
+ : return SProcSecurityQueryVersion(client);
+ : case X_SecurityGenerateAuthorization:
+ : return SProcSecurityGenerateAuthorization(client);
+ : case X_SecurityRevokeAuthorization:
+ : return SProcSecurityRevokeAuthorization(client);
+ : default:
+ : return BadRequest;
+ : }
+ :} /* SProcSecurityDispatch */
+ :
+ :static void
+ :SwapSecurityAuthorizationRevokedEvent(
+ : xSecurityAuthorizationRevokedEvent *from,
+ : xSecurityAuthorizationRevokedEvent *to)
+ :{
+ : to->type = from->type;
+ : to->detail = from->detail;
+ : cpswaps(from->sequenceNumber, to->sequenceNumber);
+ : cpswapl(from->authId, to->authId);
+ :}
+ :
+ :/* SecurityDetermineEventPropogationLimits
+ : *
+ : * This is a helper function for SecurityCheckDeviceAccess.
+ : *
+ : * Arguments:
+ : * dev is the device for which the starting and stopping windows for
+ : * event propogation should be determined.
+ : * The values pointed to by ppWin and ppStopWin are not used.
+ : *
+ : * Returns:
+ : * ppWin is filled in with a pointer to the window at which event
+ : * propogation for the given device should start given the current
+ : * state of the server (pointer position, window layout, etc.)
+ : * ppStopWin is filled in with the window at which event propogation
+ : * should stop; events should not go to ppStopWin.
+ : *
+ : * Side Effects: none.
+ : */
+ :
+ :static void
+ :SecurityDetermineEventPropogationLimits(
+ : DeviceIntPtr dev,
+ : WindowPtr *ppWin,
+ : WindowPtr *ppStopWin)
+ :{
+ : WindowPtr pFocusWin = dev->focus ? dev->focus->win : NoneWin;
+ :
+ : if (pFocusWin == NoneWin)
+ : { /* no focus -- events don't go anywhere */
+ : *ppWin = *ppStopWin = NULL;
+ : return;
+ : }
+ :
+ : if (pFocusWin == PointerRootWin)
+ : { /* focus follows the pointer */
+ : *ppWin = GetSpriteWindow();
+ : *ppStopWin = NULL; /* propogate all the way to the root */
+ : }
+ : else
+ : { /* a real window is set for the focus */
+ : WindowPtr pSpriteWin = GetSpriteWindow();
+ : *ppStopWin = pFocusWin->parent; /* don't go past the focus window */
+ :
+ : /* if the pointer is in a subwindow of the focus window, start
+ : * at that subwindow, else start at the focus window itself
+ : */
+ : if (IsParent(pFocusWin, pSpriteWin))
+ : *ppWin = pSpriteWin;
+ : else *ppWin = pFocusWin;
+ : }
+ :} /* SecurityDetermineEventPropogationLimits */
+ :
+ :
+ :/* SecurityCheckDeviceAccess
+ : *
+ : * Arguments:
+ : * client is the client attempting to access a device.
+ : * dev is the device being accessed.
+ : * fromRequest is TRUE if the device access is a direct result of
+ : * the client executing some request and FALSE if it is a
+ : * result of the server trying to send an event (e.g. KeymapNotify)
+ : * to the client.
+ : * Returns:
+ : * TRUE if the device access should be allowed, else FALSE.
+ : *
+ : * Side Effects:
+ : * An audit message is generated if access is denied.
+ : */
+ :
+ :CALLBACK(SecurityCheckDeviceAccess)
+ :{
+ : XaceDeviceAccessRec *rec = (XaceDeviceAccessRec*)calldata;
+ : ClientPtr client = rec->client;
+ : DeviceIntPtr dev = rec->dev;
+ : Bool fromRequest = rec->fromRequest;
+ : WindowPtr pWin, pStopWin;
+ : Bool untrusted_got_event;
+ : Bool found_event_window;
+ : Mask eventmask;
+ : int reqtype = 0;
+ :
+ : /* trusted clients always allowed to do anything */
+ : if (TRUSTLEVEL(client) == XSecurityClientTrusted)
+ : return;
+ :
+ : /* device security other than keyboard is not implemented yet */
+ : if (dev != inputInfo.keyboard)
+ : return;
+ :
+ : /* some untrusted client wants access */
+ :
+ : if (fromRequest)
+ : {
+ : reqtype = ((xReq *)client->requestBuffer)->reqType;
+ : switch (reqtype)
+ : {
+ : /* never allow these */
+ : case X_ChangeKeyboardMapping:
+ : case X_ChangeKeyboardControl:
+ : case X_SetModifierMapping:
+ : SecurityAudit("client %d attempted request %d\n",
+ : client->index, reqtype);
+ : rec->rval = FALSE;
+ : return;
+ : default:
+ : break;
+ : }
+ : }
+ :
+ : untrusted_got_event = FALSE;
+ : found_event_window = FALSE;
+ :
+ : if (dev->grab)
+ : {
+ : untrusted_got_event =
+ : (TRUSTLEVEL(rClient(dev->grab)) != XSecurityClientTrusted);
+ : }
+ : else
+ : {
+ : SecurityDetermineEventPropogationLimits(dev, &pWin, &pStopWin);
+ :
+ : eventmask = KeyPressMask | KeyReleaseMask;
+ : while ( (pWin != pStopWin) && !found_event_window)
+ : {
+ : OtherClients *other;
+ :
+ : if (pWin->eventMask & eventmask)
+ : {
+ : found_event_window = TRUE;
+ : client = wClient(pWin);
+ : if (TRUSTLEVEL(client) != XSecurityClientTrusted)
+ : {
+ : untrusted_got_event = TRUE;
+ : }
+ : }
+ : if (wOtherEventMasks(pWin) & eventmask)
+ : {
+ : found_event_window = TRUE;
+ : for (other = wOtherClients(pWin); other; other = other->next)
+ : {
+ : if (other->mask & eventmask)
+ : {
+ : client = rClient(other);
+ : if (TRUSTLEVEL(client) != XSecurityClientTrusted)
+ : {
+ : untrusted_got_event = TRUE;
+ : break;
+ : }
+ : }
+ : }
+ : }
+ : if (wDontPropagateMask(pWin) & eventmask)
+ : break;
+ : pWin = pWin->parent;
+ : } /* while propogating the event */
+ : }
+ :
+ : /* allow access by untrusted clients only if an event would have gone
+ : * to an untrusted client
+ : */
+ :
+ : if (!untrusted_got_event)
+ : {
+ : char *devname = dev->name;
+ : if (!devname) devname = "unnamed";
+ : if (fromRequest)
+ : SecurityAudit("client %d attempted request %d device %d (%s)\n",
+ : client->index, reqtype, dev->id, devname);
+ : else
+ : SecurityAudit("client %d attempted to access device %d (%s)\n",
+ : client->index, dev->id, devname);
+ : rec->rval = FALSE;
+ : }
+ : return;
+ :} /* SecurityCheckDeviceAccess */
+ :
+ :
+ :
+ :/* SecurityAuditResourceIDAccess
+ : *
+ : * Arguments:
+ : * client is the client doing the resource access.
+ : * id is the resource id.
+ : *
+ : * Returns: NULL
+ : *
+ : * Side Effects:
+ : * An audit message is generated with details of the denied
+ : * resource access.
+ : */
+ :
+ :static pointer
+ :SecurityAuditResourceIDAccess(
+ : ClientPtr client,
+ : XID id)
+ :{
+ : int cid = CLIENT_ID(id);
+ : int reqtype = ((xReq *)client->requestBuffer)->reqType;
+ : switch (reqtype)
+ : {
+ : case X_ChangeProperty:
+ : case X_DeleteProperty:
+ : case X_GetProperty:
+ : {
+ : xChangePropertyReq *req =
+ : (xChangePropertyReq *)client->requestBuffer;
+ : int propertyatom = req->property;
+ : char *propertyname = NameForAtom(propertyatom);
+ :
+ : SecurityAudit("client %d attempted request %d with window 0x%x property %s of client %d\n",
+ : client->index, reqtype, id, propertyname, cid);
+ : break;
+ : }
+ : default:
+ : {
+ : SecurityAudit("client %d attempted request %d with resource 0x%x of client %d\n",
+ : client->index, reqtype, id, cid);
+ : break;
+ : }
+ : }
+ : return NULL;
+ :} /* SecurityAuditResourceIDAccess */
+ :
+ :
+ :/* SecurityCheckResourceIDAccess
+ : *
+ : * This function gets plugged into client->CheckAccess and is called from
+ : * SecurityLookupIDByType/Class to determine if the client can access the
+ : * resource.
+ : *
+ : * Arguments:
+ : * client is the client doing the resource access.
+ : * id is the resource id.
+ : * rtype is its type or class.
+ : * access_mode represents the intended use of the resource; see
+ : * resource.h.
+ : * res is a pointer to the resource structure for this resource.
+ : *
+ : * Returns:
+ : * If access is granted, the value of rval that was passed in, else FALSE.
+ : *
+ : * Side Effects:
+ : * Disallowed resource accesses are audited.
+ : */
+ :
+ :CALLBACK(SecurityCheckResourceIDAccess)
+ 8 0.0087 :{ /* SecurityCheckResourceIDAccess total: 36 0.0392 */
+ : XaceResourceAccessRec *rec = (XaceResourceAccessRec*)calldata;
+ : ClientPtr client = rec->client;
+ 1 0.0011 : XID id = rec->id;
+ 3 0.0033 : RESTYPE rtype = rec->rtype;
+ : Mask access_mode = rec->access_mode;
+ : pointer rval = rec->res;
+ : int cid, reqtype;
+ :
+ 22 0.0240 : if (TRUSTLEVEL(client) == XSecurityClientTrusted ||
+ : DixUnknownAccess == access_mode)
+ : return; /* for compatibility, we have to allow access */
+ :
+ : cid = CLIENT_ID(id);
+ : reqtype = ((xReq *)client->requestBuffer)->reqType;
+ : switch (reqtype)
+ : { /* these are always allowed */
+ : case X_QueryTree:
+ : case X_TranslateCoords:
+ : case X_GetGeometry:
+ : /* property access is controlled in SecurityCheckPropertyAccess */
+ : case X_GetProperty:
+ : case X_ChangeProperty:
+ : case X_DeleteProperty:
+ : case X_RotateProperties:
+ : case X_ListProperties:
+ : return;
+ : default:
+ : break;
+ : }
+ :
+ : if (cid != 0)
+ : { /* not a server-owned resource */
+ : /*
+ : * The following 'if' restricts clients to only access resources at
+ : * the same trustLevel. Since there are currently only two trust levels,
+ : * and trusted clients never call this function, this degenerates into
+ : * saying that untrusted clients can only access resources of other
+ : * untrusted clients. One way to add the notion of groups would be to
+ : * allow values other than Trusted (0) and Untrusted (1) for this field.
+ : * Clients at the same trust level would be able to use each other's
+ : * resources, but not those of clients at other trust levels. I haven't
+ : * tried it, but this probably mostly works already. The obvious
+ : * competing alternative for grouping clients for security purposes is to
+ : * use app groups. dpw
+ : */
+ : if (TRUSTLEVEL(client) == TRUSTLEVEL(clients[cid])
+ :#ifdef XAPPGROUP
+ : || (RT_COLORMAP == rtype &&
+ : XagDefaultColormap (client) == (Colormap) id)
+ :#endif
+ : )
+ : return;
+ : else
+ : goto deny;
+ : }
+ : else /* server-owned resource - probably a default colormap or root window */
+ : {
+ : if (RT_WINDOW == rtype || RC_DRAWABLE == rtype)
+ : {
+ : switch (reqtype)
+ : { /* the following operations are allowed on root windows */
+ : case X_CreatePixmap:
+ : case X_CreateGC:
+ : case X_CreateWindow:
+ : case X_CreateColormap:
+ : case X_ListProperties:
+ : case X_GrabPointer:
+ : case X_UngrabButton:
+ : case X_QueryBestSize:
+ : case X_GetWindowAttributes:
+ : break;
+ : case X_SendEvent:
+ : { /* see if it is an event specified by the ICCCM */
+ : xSendEventReq *req = (xSendEventReq *)
+ : (client->requestBuffer);
+ : if (req->propagate == xTrue
+ : ||
+ : (req->eventMask != ColormapChangeMask &&
+ : req->eventMask != StructureNotifyMask &&
+ : req->eventMask !=
+ : (SubstructureRedirectMask|SubstructureNotifyMask)
+ : )
+ : ||
+ : (req->event.u.u.type != UnmapNotify &&
+ : req->event.u.u.type != ConfigureRequest &&
+ : req->event.u.u.type != ClientMessage
+ : )
+ : )
+ : { /* not an ICCCM event */
+ : goto deny;
+ : }
+ : break;
+ : } /* case X_SendEvent on root */
+ :
+ : case X_ChangeWindowAttributes:
+ : { /* Allow selection of PropertyNotify and StructureNotify
+ : * events on the root.
+ : */
+ : xChangeWindowAttributesReq *req =
+ : (xChangeWindowAttributesReq *)(client->requestBuffer);
+ : if (req->valueMask == CWEventMask)
+ : {
+ : CARD32 value = *((CARD32 *)(req + 1));
+ : if ( (value &
+ : ~(PropertyChangeMask|StructureNotifyMask)) == 0)
+ : break;
+ : }
+ : goto deny;
+ : } /* case X_ChangeWindowAttributes on root */
+ :
+ : default:
+ : {
+ : /* others not allowed */
+ : goto deny;
+ : }
+ : }
+ : } /* end server-owned window or drawable */
+ : else if (SecurityAuthorizationResType == rtype)
+ : {
+ : SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)rval;
+ : if (pAuth->trustLevel != TRUSTLEVEL(client))
+ : goto deny;
+ : }
+ : else if (RT_COLORMAP != rtype)
+ : { /* don't allow anything else besides colormaps */
+ : goto deny;
+ : }
+ : }
+ : return;
+ : deny:
+ : SecurityAuditResourceIDAccess(client, id);
+ : rec->rval = FALSE; /* deny access */
+ 2 0.0022 :} /* SecurityCheckResourceIDAccess */
+ :
+ :
+ :/* SecurityClientStateCallback
+ : *
+ : * Arguments:
+ : * pcbl is &ClientStateCallback.
+ : * nullata is NULL.
+ : * calldata is a pointer to a NewClientInfoRec (include/dixstruct.h)
+ : * which contains information about client state changes.
+ : *
+ : * Returns: nothing.
+ : *
+ : * Side Effects:
+ : *
+ : * If a new client is connecting, its authorization ID is copied to
+ : * client->authID. If this is a generated authorization, its reference
+ : * count is bumped, its timer is cancelled if it was running, and its
+ : * trustlevel is copied to TRUSTLEVEL(client).
+ : *
+ : * If a client is disconnecting and the client was using a generated
+ : * authorization, the authorization's reference count is decremented, and
+ : * if it is now zero, the timer for this authorization is started.
+ : */
+ :
+ :CALLBACK(SecurityClientStateCallback)
+ :{
+ : NewClientInfoRec *pci = (NewClientInfoRec *)calldata;
+ : ClientPtr client = pci->client;
+ :
+ : switch (client->clientState)
+ : {
+ : case ClientStateInitial:
+ : TRUSTLEVEL(client) = XSecurityClientTrusted;
+ : AUTHID(client) = None;
+ : break;
+ :
+ : case ClientStateRunning:
+ : {
+ : XID authId = AuthorizationIDOfClient(client);
+ : SecurityAuthorizationPtr pAuth;
+ :
+ : TRUSTLEVEL(client) = XSecurityClientTrusted;
+ : AUTHID(client) = authId;
+ : pAuth = (SecurityAuthorizationPtr)LookupIDByType(authId,
+ : SecurityAuthorizationResType);
+ : if (pAuth)
+ : { /* it is a generated authorization */
+ : pAuth->refcnt++;
+ : if (pAuth->refcnt == 1)
+ : {
+ : if (pAuth->timer) TimerCancel(pAuth->timer);
+ : }
+ : TRUSTLEVEL(client) = pAuth->trustLevel;
+ : }
+ : break;
+ : }
+ : case ClientStateGone:
+ : case ClientStateRetained: /* client disconnected */
+ : {
+ : SecurityAuthorizationPtr pAuth;
+ :
+ : /* client may not have any state (bad authorization) */
+ : if (!STATEPTR(client))
+ : break;
+ :
+ : pAuth = (SecurityAuthorizationPtr)LookupIDByType(AUTHID(client),
+ : SecurityAuthorizationResType);
+ : if (pAuth)
+ : { /* it is a generated authorization */
+ : pAuth->refcnt--;
+ : if (pAuth->refcnt == 0)
+ : {
+ : SecurityStartAuthorizationTimer(pAuth);
+ : }
+ : }
+ : break;
+ : }
+ : default: break;
+ : }
+ :} /* SecurityClientStateCallback */
+ :
+ :CALLBACK(SecurityCheckDrawableAccess)
+ :{
+ : XaceDrawableAccessRec *rec = (XaceDrawableAccessRec*)calldata;
+ :
+ : if (TRUSTLEVEL(rec->client) != XSecurityClientTrusted)
+ : rec->rval = FALSE;
+ :}
+ :
+ :CALLBACK(SecurityCheckMapAccess)
+ :{
+ : XaceMapAccessRec *rec = (XaceMapAccessRec*)calldata;
+ : WindowPtr pWin = rec->pWin;
+ :
+ : if (STATEPTR(rec->client) &&
+ : (TRUSTLEVEL(rec->client) != XSecurityClientTrusted) &&
+ : (pWin->drawable.class == InputOnly) &&
+ : pWin->parent && pWin->parent->parent &&
+ : (TRUSTLEVEL(wClient(pWin->parent)) == XSecurityClientTrusted))
+ :
+ : rec->rval = FALSE;
+ :}
+ :
+ :CALLBACK(SecurityCheckBackgrndAccess)
+ :{
+ : XaceMapAccessRec *rec = (XaceMapAccessRec*)calldata;
+ :
+ : if (TRUSTLEVEL(rec->client) != XSecurityClientTrusted)
+ : rec->rval = FALSE;
+ :}
+ :
+ :CALLBACK(SecurityCheckExtAccess)
+ 3 0.0033 :{ /* SecurityCheckExtAccess total: 14 0.0153 */
+ : XaceExtAccessRec *rec = (XaceExtAccessRec*)calldata;
+ :
+ 10 0.0109 : if ((TRUSTLEVEL(rec->client) != XSecurityClientTrusted) &&
+ : !STATEVAL(rec->ext))
+ :
+ : rec->rval = FALSE;
+ 1 0.0011 :}
+ :
+ :CALLBACK(SecurityCheckHostlistAccess)
+ :{
+ : XaceHostlistAccessRec *rec = (XaceHostlistAccessRec*)calldata;
+ :
+ : if (TRUSTLEVEL(rec->client) != XSecurityClientTrusted)
+ : {
+ : rec->rval = FALSE;
+ : if (rec->access_mode == DixWriteAccess)
+ : SecurityAudit("client %d attempted to change host access\n",
+ : rec->client->index);
+ : else
+ : SecurityAudit("client %d attempted to list hosts\n",
+ : rec->client->index);
+ : }
+ :}
+ :
+ :CALLBACK(SecurityDeclareExtSecure)
+ :{
+ : XaceDeclareExtSecureRec *rec = (XaceDeclareExtSecureRec*)calldata;
+ :
+ : /* security state for extensions is simply a boolean trust value */
+ : STATEVAL(rec->ext) = rec->secure;
+ :}
+ :
+ :/**********************************************************************/
+ :
+ :typedef struct _PropertyAccessRec {
+ : ATOM name;
+ : ATOM mustHaveProperty;
+ : char *mustHaveValue;
+ : char windowRestriction;
+ :#define SecurityAnyWindow 0
+ :#define SecurityRootWindow 1
+ :#define SecurityWindowWithProperty 2
+ : char readAction;
+ : char writeAction;
+ : char destroyAction;
+ : struct _PropertyAccessRec *next;
+ :} PropertyAccessRec, *PropertyAccessPtr;
+ :
+ :static PropertyAccessPtr PropertyAccessList = NULL;
+ :static char SecurityDefaultAction = XaceErrorOperation;
+ :static char *SecurityPolicyFile = DEFAULTPOLICYFILE;
+ :static ATOM SecurityMaxPropertyName = 0;
+ :
+ :static char *SecurityKeywords[] = {
+ :#define SecurityKeywordComment 0
+ : "#",
+ :#define SecurityKeywordProperty 1
+ : "property",
+ :#define SecurityKeywordSitePolicy 2
+ : "sitepolicy",
+ :#define SecurityKeywordRoot 3
+ : "root",
+ :#define SecurityKeywordAny 4
+ : "any"
+ :};
+ :
+ :#define NUMKEYWORDS (sizeof(SecurityKeywords) / sizeof(char *))
+ :
+ :#undef PROPDEBUG
+ :/*#define PROPDEBUG 1*/
+ :
+ :static void
+ :SecurityFreePropertyAccessList(void)
+ :{
+ : while (PropertyAccessList)
+ : {
+ : PropertyAccessPtr freeit = PropertyAccessList;
+ : PropertyAccessList = PropertyAccessList->next;
+ : xfree(freeit);
+ : }
+ :} /* SecurityFreePropertyAccessList */
+ :
+ :#define SecurityIsWhitespace(c) ( (c == ' ') || (c == '\t') || (c == '\n') )
+ :
+ :static char *
+ :SecuritySkipWhitespace(
+ : char *p)
+ :{
+ : while (SecurityIsWhitespace(*p))
+ : p++;
+ : return p;
+ :} /* SecuritySkipWhitespace */
+ :
+ :
+ :static char *
+ :SecurityParseString(
+ : char **rest)
+ :{
+ : char *startOfString;
+ : char *s = *rest;
+ : char endChar = 0;
+ :
+ : s = SecuritySkipWhitespace(s);
+ :
+ : if (*s == '"' || *s == '\'')
+ : {
+ : endChar = *s++;
+ : startOfString = s;
+ : while (*s && (*s != endChar))
+ : s++;
+ : }
+ : else
+ : {
+ : startOfString = s;
+ : while (*s && !SecurityIsWhitespace(*s))
+ : s++;
+ : }
+ : if (*s)
+ : {
+ : *s = '\0';
+ : *rest = s + 1;
+ : return startOfString;
+ : }
+ : else
+ : {
+ : *rest = s;
+ : return (endChar) ? NULL : startOfString;
+ : }
+ :} /* SecurityParseString */
+ :
+ :
+ :static int
+ :SecurityParseKeyword(
+ : char **p)
+ :{
+ : int i;
+ : char *s = *p;
+ : s = SecuritySkipWhitespace(s);
+ : for (i = 0; i < NUMKEYWORDS; i++)
+ : {
+ : int len = strlen(SecurityKeywords[i]);
+ : if (strncmp(s, SecurityKeywords[i], len) == 0)
+ : {
+ : *p = s + len;
+ : return (i);
+ : }
+ : }
+ : *p = s;
+ : return -1;
+ :} /* SecurityParseKeyword */
+ :
+ :
+ :static Bool
+ :SecurityParsePropertyAccessRule(
+ : char *p)
+ :{
+ : char *propname;
+ : char c;
+ : char action = SecurityDefaultAction;
+ : char readAction, writeAction, destroyAction;
+ : PropertyAccessPtr pacl, prev, cur;
+ : char *mustHaveProperty = NULL;
+ : char *mustHaveValue = NULL;
+ : Bool invalid;
+ : char windowRestriction;
+ : int size;
+ : int keyword;
+ :
+ : /* get property name */
+ : propname = SecurityParseString(&p);
+ : if (!propname || (strlen(propname) == 0))
+ : return FALSE;
+ :
+ : /* get window on which property must reside for rule to apply */
+ :
+ : keyword = SecurityParseKeyword(&p);
+ : if (keyword == SecurityKeywordRoot)
+ : windowRestriction = SecurityRootWindow;
+ : else if (keyword == SecurityKeywordAny)
+ : windowRestriction = SecurityAnyWindow;
+ : else /* not root or any, must be a property name */
+ : {
+ : mustHaveProperty = SecurityParseString(&p);
+ : if (!mustHaveProperty || (strlen(mustHaveProperty) == 0))
+ : return FALSE;
+ : windowRestriction = SecurityWindowWithProperty;
+ : p = SecuritySkipWhitespace(p);
+ : if (*p == '=')
+ : { /* property value is specified too */
+ : p++; /* skip over '=' */
+ : mustHaveValue = SecurityParseString(&p);
+ : if (!mustHaveValue)
+ : return FALSE;
+ : }
+ : }
+ :
+ : /* get operations and actions */
+ :
+ : invalid = FALSE;
+ : readAction = writeAction = destroyAction = SecurityDefaultAction;
+ : while ( (c = *p++) && !invalid)
+ : {
+ : switch (c)
+ : {
+ : case 'i': action = XaceIgnoreOperation; break;
+ : case 'a': action = XaceAllowOperation; break;
+ : case 'e': action = XaceErrorOperation; break;
+ :
+ : case 'r': readAction = action; break;
+ : case 'w': writeAction = action; break;
+ : case 'd': destroyAction = action; break;
+ :
+ : default :
+ : if (!SecurityIsWhitespace(c))
+ : invalid = TRUE;
+ : break;
+ : }
+ : }
+ : if (invalid)
+ : return FALSE;
+ :
+ : /* We've successfully collected all the information needed for this
+ : * property access rule. Now record it in a PropertyAccessRec.
+ : */
+ : size = sizeof(PropertyAccessRec);
+ :
+ : /* If there is a property value string, allocate space for it
+ : * right after the PropertyAccessRec.
+ : */
+ : if (mustHaveValue)
+ : size += strlen(mustHaveValue) + 1;
+ : pacl = (PropertyAccessPtr)Xalloc(size);
+ : if (!pacl)
+ : return FALSE;
+ :
+ : pacl->name = MakeAtom(propname, strlen(propname), TRUE);
+ : if (pacl->name == BAD_RESOURCE)
+ : {
+ : Xfree(pacl);
+ : return FALSE;
+ : }
+ : if (mustHaveProperty)
+ : {
+ : pacl->mustHaveProperty = MakeAtom(mustHaveProperty,
+ : strlen(mustHaveProperty), TRUE);
+ : if (pacl->mustHaveProperty == BAD_RESOURCE)
+ : {
+ : Xfree(pacl);
+ : return FALSE;
+ : }
+ : }
+ : else
+ : pacl->mustHaveProperty = 0;
+ :
+ : if (mustHaveValue)
+ : {
+ : pacl->mustHaveValue = (char *)(pacl + 1);
+ : strcpy(pacl->mustHaveValue, mustHaveValue);
+ : }
+ : else
+ : pacl->mustHaveValue = NULL;
+ :
+ : SecurityMaxPropertyName = max(SecurityMaxPropertyName, pacl->name);
+ :
+ : pacl->windowRestriction = windowRestriction;
+ : pacl->readAction = readAction;
+ : pacl->writeAction = writeAction;
+ : pacl->destroyAction = destroyAction;
+ :
+ : /* link the new rule into the list of rules in order of increasing
+ : * property name (atom) value to make searching easier
+ : */
+ :
+ : for (prev = NULL, cur = PropertyAccessList;
+ : cur && cur->name <= pacl->name;
+ : prev = cur, cur = cur->next)
+ : ;
+ : if (!prev)
+ : {
+ : pacl->next = cur;
+ : PropertyAccessList = pacl;
+ : }
+ : else
+ : {
+ : prev->next = pacl;
+ : pacl->next = cur;
+ : }
+ : return TRUE;
+ :} /* SecurityParsePropertyAccessRule */
+ :
+ :static char **SecurityPolicyStrings = NULL;
+ :static int nSecurityPolicyStrings = 0;
+ :
+ :static Bool
+ :SecurityParseSitePolicy(
+ : char *p)
+ :{
+ : char *policyStr = SecurityParseString(&p);
+ : char *copyPolicyStr;
+ : char **newStrings;
+ :
+ : if (!policyStr)
+ : return FALSE;
+ :
+ : copyPolicyStr = (char *)Xalloc(strlen(policyStr) + 1);
+ : if (!copyPolicyStr)
+ : return TRUE;
+ : strcpy(copyPolicyStr, policyStr);
+ : newStrings = (char **)Xrealloc(SecurityPolicyStrings,
+ : sizeof (char *) * (nSecurityPolicyStrings + 1));
+ : if (!newStrings)
+ : {
+ : Xfree(copyPolicyStr);
+ : return TRUE;
+ : }
+ :
+ : SecurityPolicyStrings = newStrings;
+ : SecurityPolicyStrings[nSecurityPolicyStrings++] = copyPolicyStr;
+ :
+ : return TRUE;
+ :
+ :} /* SecurityParseSitePolicy */
+ :
+ :
+ :char **
+ :SecurityGetSitePolicyStrings(n)
+ : int *n;
+ :{
+ : *n = nSecurityPolicyStrings;
+ : return SecurityPolicyStrings;
+ :} /* SecurityGetSitePolicyStrings */
+ :
+ :static void
+ :SecurityFreeSitePolicyStrings(void)
+ :{
+ : if (SecurityPolicyStrings)
+ : {
+ : assert(nSecurityPolicyStrings);
+ : while (nSecurityPolicyStrings--)
+ : {
+ : Xfree(SecurityPolicyStrings[nSecurityPolicyStrings]);
+ : }
+ : Xfree(SecurityPolicyStrings);
+ : SecurityPolicyStrings = NULL;
+ : nSecurityPolicyStrings = 0;
+ : }
+ :} /* SecurityFreeSitePolicyStrings */
+ :
+ :
+ :static void
+ :SecurityLoadPropertyAccessList(void)
+ :{
+ : FILE *f;
+ : int lineNumber = 0;
+ :
+ : SecurityMaxPropertyName = 0;
+ :
+ : if (!SecurityPolicyFile)
+ : return;
+ :
+ : f = fopen(SecurityPolicyFile, "r");
+ : if (!f)
+ : {
+ : ErrorF("error opening security policy file %s\n",
+ : SecurityPolicyFile);
+ : return;
+ : }
+ :
+ : while (!feof(f))
+ : {
+ : char buf[200];
+ : Bool validLine;
+ : char *p;
+ :
+ : if (!(p = fgets(buf, sizeof(buf), f)))
+ : break;
+ : lineNumber++;
+ :
+ : /* if first line, check version number */
+ : if (lineNumber == 1)
+ : {
+ : char *v = SecurityParseString(&p);
+ : if (strcmp(v, SECURITY_POLICY_FILE_VERSION) != 0)
+ : {
+ : ErrorF("%s: invalid security policy file version, ignoring file\n",
+ : SecurityPolicyFile);
+ : break;
+ : }
+ : validLine = TRUE;
+ : }
+ : else
+ : {
+ : switch (SecurityParseKeyword(&p))
+ : {
+ : case SecurityKeywordComment:
+ : validLine = TRUE;
+ : break;
+ :
+ : case SecurityKeywordProperty:
+ : validLine = SecurityParsePropertyAccessRule(p);
+ : break;
+ :
+ : case SecurityKeywordSitePolicy:
+ : validLine = SecurityParseSitePolicy(p);
+ : break;
+ :
+ : default:
+ : validLine = (*p == '\0'); /* blank lines OK, others not */
+ : break;
+ : }
+ : }
+ :
+ : if (!validLine)
+ : ErrorF("Line %d of %s invalid, ignoring\n",
+ : lineNumber, SecurityPolicyFile);
+ : } /* end while more input */
+ :
+ :#ifdef PROPDEBUG
+ : {
+ : PropertyAccessPtr pacl;
+ : char *op = "aie";
+ : for (pacl = PropertyAccessList; pacl; pacl = pacl->next)
+ : {
+ : ErrorF("property %s ", NameForAtom(pacl->name));
+ : switch (pacl->windowRestriction)
+ : {
+ : case SecurityAnyWindow: ErrorF("any "); break;
+ : case SecurityRootWindow: ErrorF("root "); break;
+ : case SecurityWindowWithProperty:
+ : {
+ : ErrorF("%s ", NameForAtom(pacl->mustHaveProperty));
+ : if (pacl->mustHaveValue)
+ : ErrorF(" = \"%s\" ", pacl->mustHaveValue);
+ :
+ : }
+ : break;
+ : }
+ : ErrorF("%cr %cw %cd\n", op[pacl->readAction],
+ : op[pacl->writeAction], op[pacl->destroyAction]);
+ : }
+ : }
+ :#endif /* PROPDEBUG */
+ :
+ : fclose(f);
+ :} /* SecurityLoadPropertyAccessList */
+ :
+ :
+ :static Bool
+ :SecurityMatchString(
+ : char *ws,
+ : char *cs)
+ :{
+ : while (*ws && *cs)
+ : {
+ : if (*ws == '*')
+ : {
+ : Bool match = FALSE;
+ : ws++;
+ : while (!(match = SecurityMatchString(ws, cs)) && *cs)
+ : {
+ : cs++;
+ : }
+ : return match;
+ : }
+ : else if (*ws == *cs)
+ : {
+ : ws++;
+ : cs++;
+ : }
+ : else break;
+ : }
+ : return ( ( (*ws == '\0') || ((*ws == '*') && *(ws+1) == '\0') )
+ : && (*cs == '\0') );
+ :} /* SecurityMatchString */
+ :
+ :#ifdef PROPDEBUG
+ :#include <sys/types.h>
+ :#include <sys/stat.h>
+ :#endif
+ :
+ :
+ :CALLBACK(SecurityCheckPropertyAccess)
+ :{
+ : XacePropertyAccessRec *rec = (XacePropertyAccessRec*)calldata;
+ : ClientPtr client = rec->client;
+ : WindowPtr pWin = rec->pWin;
+ : ATOM propertyName = rec->propertyName;
+ : Mask access_mode = rec->access_mode;
+ : PropertyAccessPtr pacl;
+ : char action = SecurityDefaultAction;
+ :
+ : /* if client trusted or window untrusted, allow operation */
+ :
+ : if ( (TRUSTLEVEL(client) == XSecurityClientTrusted) ||
+ : (TRUSTLEVEL(wClient(pWin)) != XSecurityClientTrusted) )
+ : return;
+ :
+ :#ifdef PROPDEBUG
+ : /* For testing, it's more convenient if the property rules file gets
+ : * reloaded whenever it changes, so we can rapidly try things without
+ : * having to reset the server.
+ : */
+ : {
+ : struct stat buf;
+ : static time_t lastmod = 0;
+ : int ret = stat(SecurityPolicyFile , &buf);
+ : if ( (ret == 0) && (buf.st_mtime > lastmod) )
+ : {
+ : ErrorF("reloading property rules\n");
+ : SecurityFreePropertyAccessList();
+ : SecurityLoadPropertyAccessList();
+ : lastmod = buf.st_mtime;
+ : }
+ : }
+ :#endif
+ :
+ : /* If the property atom is bigger than any atoms on the list,
+ : * we know we won't find it, so don't even bother looking.
+ : */
+ : if (propertyName <= SecurityMaxPropertyName)
+ : {
+ : /* untrusted client operating on trusted window; see if it's allowed */
+ :
+ : for (pacl = PropertyAccessList; pacl; pacl = pacl->next)
+ : {
+ : if (pacl->name < propertyName)
+ : continue;
+ : if (pacl->name > propertyName)
+ : break;
+ :
+ : /* pacl->name == propertyName, so see if it applies to this window */
+ :
+ : switch (pacl->windowRestriction)
+ : {
+ : case SecurityAnyWindow: /* always applies */
+ : break;
+ :
+ : case SecurityRootWindow:
+ : {
+ : /* if not a root window, this rule doesn't apply */
+ : if (pWin->parent)
+ : continue;
+ : }
+ : break;
+ :
+ : case SecurityWindowWithProperty:
+ : {
+ : PropertyPtr pProp = wUserProps (pWin);
+ : Bool match = FALSE;
+ : char *p;
+ : char *pEndData;
+ :
+ : while (pProp)
+ : {
+ : if (pProp->propertyName == pacl->mustHaveProperty)
+ : break;
+ : pProp = pProp->next;
+ : }
+ : if (!pProp)
+ : continue;
+ : if (!pacl->mustHaveValue)
+ : break;
+ : if (pProp->type != XA_STRING || pProp->format != 8)
+ : continue;
+ :
+ : p = pProp->data;
+ : pEndData = ((char *)pProp->data) + pProp->size;
+ : while (!match && p < pEndData)
+ : {
+ : if (SecurityMatchString(pacl->mustHaveValue, p))
+ : match = TRUE;
+ : else
+ : { /* skip to the next string */
+ : while (*p++ && p < pEndData)
+ : ;
+ : }
+ : }
+ : if (!match)
+ : continue;
+ : }
+ : break; /* end case SecurityWindowWithProperty */
+ : } /* end switch on windowRestriction */
+ :
+ : /* If we get here, the property access rule pacl applies.
+ : * If pacl doesn't apply, something above should have
+ : * executed a continue, which will skip the follwing code.
+ : */
+ : action = XaceAllowOperation;
+ : if (access_mode & DixReadAccess)
+ : action = max(action, pacl->readAction);
+ : if (access_mode & DixWriteAccess)
+ : action = max(action, pacl->writeAction);
+ : if (access_mode & DixDestroyAccess)
+ : action = max(action, pacl->destroyAction);
+ : break;
+ : } /* end for each pacl */
+ : } /* end if propertyName <= SecurityMaxPropertyName */
+ :
+ : if (XaceAllowOperation != action)
+ : { /* audit the access violation */
+ : int cid = CLIENT_ID(pWin->drawable.id);
+ : int reqtype = ((xReq *)client->requestBuffer)->reqType;
+ : char *actionstr = (XaceIgnoreOperation == action) ?
+ : "ignored" : "error";
+ : SecurityAudit("client %d attempted request %d with window 0x%x property %s (atom 0x%x) of client %d, %s\n",
+ : client->index, reqtype, pWin->drawable.id,
+ : NameForAtom(propertyName), propertyName, cid, actionstr);
+ : }
+ : /* return codes increase with strictness */
+ : if (action > rec->rval)
+ : rec->rval = action;
+ :} /* SecurityCheckPropertyAccess */
+ :
+ :
+ :/* SecurityResetProc
+ : *
+ : * Arguments:
+ : * extEntry is the extension information for the security extension.
+ : *
+ : * Returns: nothing.
+ : *
+ : * Side Effects:
+ : * Performs any cleanup needed by Security at server shutdown time.
+ : */
+ :
+ :static void
+ :SecurityResetProc(
+ : ExtensionEntry *extEntry)
+ :{
+ : SecurityFreePropertyAccessList();
+ : SecurityFreeSitePolicyStrings();
+ :} /* SecurityResetProc */
+ :
+ :
+ :int
+ :XSecurityOptions(argc, argv, i)
+ : int argc;
+ : char **argv;
+ : int i;
+ :{
+ : if (strcmp(argv[i], "-sp") == 0)
+ : {
+ : if (i < argc)
+ : SecurityPolicyFile = argv[++i];
+ : return (i + 1);
+ : }
+ : return (i);
+ :} /* XSecurityOptions */
+ :
+ :
+ :/* SecurityExtensionSetup
+ : *
+ : * Arguments: none.
+ : *
+ : * Returns: nothing.
+ : *
+ : * Side Effects:
+ : * Sets up the Security extension if possible.
+ : * This function contains things that need to be done
+ : * before any other extension init functions get called.
+ : */
+ :
+ :void
+ :SecurityExtensionSetup(INITARGS)
+ :{
+ : /* Allocate the client private index */
+ : securityClientPrivateIndex = AllocateClientPrivateIndex();
+ : if (!AllocateClientPrivate(securityClientPrivateIndex,
+ : sizeof (SecurityClientStateRec)))
+ : FatalError("SecurityExtensionSetup: Can't allocate client private.\n");
+ :
+ : /* Allocate the extension private index */
+ : securityExtnsnPrivateIndex = AllocateExtensionPrivateIndex();
+ : if (!AllocateExtensionPrivate(securityExtnsnPrivateIndex, 0))
+ : FatalError("SecurityExtensionSetup: Can't allocate extnsn private.\n");
+ :
+ : /* register callbacks */
+ :#define XaceRC XaceRegisterCallback
+ : XaceRC(XACE_RESOURCE_ACCESS, SecurityCheckResourceIDAccess, NULL);
+ : XaceRC(XACE_DEVICE_ACCESS, SecurityCheckDeviceAccess, NULL);
+ : XaceRC(XACE_PROPERTY_ACCESS, SecurityCheckPropertyAccess, NULL);
+ : XaceRC(XACE_DRAWABLE_ACCESS, SecurityCheckDrawableAccess, NULL);
+ : XaceRC(XACE_MAP_ACCESS, SecurityCheckMapAccess, NULL);
+ : XaceRC(XACE_BACKGRND_ACCESS, SecurityCheckBackgrndAccess, NULL);
+ : XaceRC(XACE_EXT_DISPATCH, SecurityCheckExtAccess, NULL);
+ : XaceRC(XACE_EXT_ACCESS, SecurityCheckExtAccess, NULL);
+ : XaceRC(XACE_HOSTLIST_ACCESS, SecurityCheckHostlistAccess, NULL);
+ : XaceRC(XACE_DECLARE_EXT_SECURE, SecurityDeclareExtSecure, NULL);
+ :} /* SecurityExtensionSetup */
+ :
+ :
+ :/* SecurityExtensionInit
+ : *
+ : * Arguments: none.
+ : *
+ : * Returns: nothing.
+ : *
+ : * Side Effects:
+ : * Enables the Security extension if possible.
+ : */
+ :
+ :void
+ :SecurityExtensionInit(INITARGS)
+ :{
+ : ExtensionEntry *extEntry;
+ :
+ : SecurityAuthorizationResType =
+ : CreateNewResourceType(SecurityDeleteAuthorization);
+ :
+ : RTEventClient = CreateNewResourceType(
+ : SecurityDeleteAuthorizationEventClient);
+ :
+ : if (!SecurityAuthorizationResType || !RTEventClient)
+ : return;
+ :
+ : RTEventClient |= RC_NEVERRETAIN;
+ :
+ : if (!AddCallback(&ClientStateCallback, SecurityClientStateCallback, NULL))
+ : return;
+ :
+ : extEntry = AddExtension(SECURITY_EXTENSION_NAME,
+ : XSecurityNumberEvents, XSecurityNumberErrors,
+ : ProcSecurityDispatch, SProcSecurityDispatch,
+ : SecurityResetProc, StandardMinorOpcode);
+ :
+ : SecurityErrorBase = extEntry->errorBase;
+ : SecurityEventBase = extEntry->eventBase;
+ :
+ : EventSwapVector[SecurityEventBase + XSecurityAuthorizationRevoked] =
+ : (EventSwapPtr)SwapSecurityAuthorizationRevokedEvent;
+ :
+ : SecurityLoadPropertyAccessList();
+ :
+ :} /* SecurityExtensionInit */
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/hw/xfree86/dri/dri.c"
+ *
+ * 41 0.0447
+ */
+
+
+ :/**************************************************************************
+ :
+ :Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+ :Copyright 2000 VA Linux Systems, Inc.
+ :All Rights Reserved.
+ :
+ :Permission is hereby granted, free of charge, to any person obtaining a
+ :copy of this software and associated documentation files (the
+ :"Software"), to deal in the Software without restriction, including
+ :without limitation the rights to use, copy, modify, merge, publish,
+ :distribute, sub license, and/or sell copies of the Software, and to
+ :permit persons to whom the Software is furnished to do so, subject to
+ :the following conditions:
+ :
+ :The above copyright notice and this permission notice (including the
+ :next paragraph) shall be included in all copies or substantial portions
+ :of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ :OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ :MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ :IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ :ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ :TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ :SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :**************************************************************************/
+ :
+ :/*
+ : * Authors:
+ : * Jens Owen <jens@tungstengraphics.com>
+ : * Rickard E. (Rik) Faith <faith@valinux.com>
+ : *
+ : */
+ :
+ :#ifdef HAVE_XORG_CONFIG_H
+ :#include <xorg-config.h>
+ :#endif
+ :
+ :#include "xf86.h"
+ :#include <sys/time.h>
+ :#include <unistd.h>
+ :#include <string.h>
+ :#include <stdio.h>
+ :#include <sys/ioctl.h>
+ :#include <errno.h>
+ :
+ :#define NEED_REPLIES
+ :#define NEED_EVENTS
+ :#include <X11/X.h>
+ :#include <X11/Xproto.h>
+ :#include "xf86drm.h"
+ :#include "misc.h"
+ :#include "dixstruct.h"
+ :#include "extnsionst.h"
+ :#include "colormapst.h"
+ :#include "cursorstr.h"
+ :#include "scrnintstr.h"
+ :#include "windowstr.h"
+ :#include "servermd.h"
+ :#define _XF86DRI_SERVER_
+ :#include "xf86dristr.h"
+ :#include "swaprep.h"
+ :#include "xf86str.h"
+ :#include "dri.h"
+ :#include "sarea.h"
+ :#include "dristruct.h"
+ :#include "xf86.h"
+ :#include "xf86drm.h"
+ :#include "glxserver.h"
+ :#include "mi.h"
+ :#include "mipointer.h"
+ :#include "xf86_OSproc.h"
+ :
+ :#define PCI_BUS_NO_DOMAIN(bus) ((bus) & 0xffu)
+ :
+ :#if !defined(PANORAMIX)
+ :extern Bool noPanoramiXExtension;
+ :#endif
+ :
+ :static int DRIEntPrivIndex = -1;
+ :static int DRIScreenPrivIndex = -1;
+ :static int DRIWindowPrivIndex = -1;
+ :static unsigned long DRIGeneration = 0;
+ :static unsigned int DRIDrawableValidationStamp = 0;
+ :
+ :static RESTYPE DRIDrawablePrivResType;
+ :static RESTYPE DRIContextPrivResType;
+ :static void DRIDestroyDummyContext(ScreenPtr pScreen, Bool hasCtxPriv);
+ :
+ :drmServerInfo DRIDRMServerInfo;
+ :
+ : /* Wrapper just like xf86DrvMsg, but
+ : without the verbosity level checking.
+ : This will make it easy to turn off some
+ : messages later, based on verbosity
+ : level. */
+ :
+ :/*
+ : * Since we're already referencing things from the XFree86 common layer in
+ : * this file, we'd might as well just call xf86VDrvMsgVerb, and have
+ : * consistent message formatting. The verbosity of these messages can be
+ : * easily changed here.
+ : */
+ :#define DRI_MSG_VERBOSITY 1
+ :static void
+ :DRIDrvMsg(int scrnIndex, MessageType type, const char *format, ...)
+ :{
+ : va_list ap;
+ :
+ : va_start(ap, format);
+ : xf86VDrvMsgVerb(scrnIndex, type, DRI_MSG_VERBOSITY, format, ap);
+ : va_end(ap);
+ :}
+ :
+ :
+ :static void
+ :DRIOpenDRMCleanup(DRIEntPrivPtr pDRIEntPriv)
+ :{
+ : if (pDRIEntPriv->pLSAREA != NULL) {
+ : drmUnmap(pDRIEntPriv->pLSAREA, pDRIEntPriv->sAreaSize);
+ : pDRIEntPriv->pLSAREA = NULL;
+ : }
+ : if (pDRIEntPriv->hLSAREA != 0) {
+ : drmRmMap(pDRIEntPriv->drmFD, pDRIEntPriv->hLSAREA);
+ : }
+ : if (pDRIEntPriv->drmFD >= 0) {
+ : drmClose(pDRIEntPriv->drmFD);
+ : pDRIEntPriv->drmFD = 0;
+ : }
+ :}
+ :
+ :int
+ :DRIMasterFD(ScrnInfoPtr pScrn)
+ :{
+ : return DRI_ENT_PRIV(pScrn)->drmFD;
+ :}
+ :
+ :void *
+ :DRIMasterSareaPointer(ScrnInfoPtr pScrn)
+ :{
+ : return DRI_ENT_PRIV(pScrn)->pLSAREA;
+ :}
+ :
+ :drm_handle_t
+ :DRIMasterSareaHandle(ScrnInfoPtr pScrn)
+ :{
+ : return DRI_ENT_PRIV(pScrn)->hLSAREA;
+ :}
+ :
+ :
+ :Bool
+ :DRIOpenDRMMaster(ScrnInfoPtr pScrn,
+ : unsigned long sAreaSize,
+ : const char *busID,
+ : const char *drmDriverName)
+ :{
+ : drmSetVersion saveSv, sv;
+ : Bool drmWasAvailable;
+ : DRIEntPrivPtr pDRIEntPriv;
+ : DRIEntPrivRec tmp;
+ : drmVersionPtr drmlibv;
+ : int drmlibmajor, drmlibminor;
+ : const char *openBusID;
+ : int count;
+ : int err;
+ :
+ : if (DRIEntPrivIndex == -1)
+ : DRIEntPrivIndex = xf86AllocateEntityPrivateIndex();
+ :
+ : pDRIEntPriv = DRI_ENT_PRIV(pScrn);
+ :
+ : if (pDRIEntPriv && pDRIEntPriv->drmFD != -1)
+ : return TRUE;
+ :
+ : drmWasAvailable = drmAvailable();
+ :
+ : memset(&tmp, 0, sizeof(tmp));
+ :
+ : /* Check the DRM lib version.
+ : * drmGetLibVersion was not supported in version 1.0, so check for
+ : * symbol first to avoid possible crash or hang.
+ : */
+ :
+ : drmlibmajor = 1;
+ : drmlibminor = 0;
+ : if (xf86LoaderCheckSymbol("drmGetLibVersion")) {
+ : drmlibv = drmGetLibVersion(-1);
+ : if (drmlibv != NULL) {
+ : drmlibmajor = drmlibv->version_major;
+ : drmlibminor = drmlibv->version_minor;
+ : drmFreeVersion(drmlibv);
+ : }
+ : }
+ :
+ : /* Check if the libdrm can handle falling back to loading based on name
+ : * if a busid string is passed.
+ : */
+ : openBusID = (drmlibmajor == 1 && drmlibminor >= 2) ? busID : NULL;
+ :
+ : tmp.drmFD = -1;
+ : sv.drm_di_major = 1;
+ : sv.drm_di_minor = 1;
+ : sv.drm_dd_major = -1;
+ :
+ : saveSv = sv;
+ : count = 10;
+ : while (count--) {
+ : tmp.drmFD = drmOpen(drmDriverName, openBusID);
+ :
+ : if (tmp.drmFD < 0) {
+ : DRIDrvMsg(-1, X_ERROR, "[drm] drmOpen failed.\n");
+ : goto out_err;
+ : }
+ :
+ : err = drmSetInterfaceVersion(tmp.drmFD, &sv);
+ :
+ : if (err != -EPERM)
+ : break;
+ :
+ : sv = saveSv;
+ : drmClose(tmp.drmFD);
+ : tmp.drmFD = -1;
+ : usleep(100000);
+ : }
+ :
+ : if (tmp.drmFD <= 0) {
+ : DRIDrvMsg(-1, X_ERROR, "[drm] DRM was busy with another master.\n");
+ : goto out_err;
+ : }
+ :
+ : if (!drmWasAvailable) {
+ : DRIDrvMsg(-1, X_INFO,
+ : "[drm] loaded kernel module for \"%s\" driver.\n",
+ : drmDriverName);
+ : }
+ :
+ : if (err != 0) {
+ : sv.drm_di_major = 1;
+ : sv.drm_di_minor = 0;
+ : }
+ :
+ : DRIDrvMsg(-1, X_INFO, "[drm] DRM interface version %d.%d\n",
+ : sv.drm_di_major, sv.drm_di_minor);
+ :
+ : if (sv.drm_di_major == 1 && sv.drm_di_minor >= 1)
+ : err = 0;
+ : else
+ : err = drmSetBusid(tmp.drmFD, busID);
+ :
+ : if (err) {
+ : DRIDrvMsg(-1, X_ERROR, "[drm] Could not set DRM device bus ID.\n");
+ : goto out_err;
+ : }
+ :
+ : /*
+ : * Create a lock-containing sarea.
+ : */
+ :
+ : if (drmAddMap( tmp.drmFD, 0, sAreaSize, DRM_SHM,
+ : DRM_CONTAINS_LOCK, &tmp.hLSAREA) < 0) {
+ : DRIDrvMsg(-1, X_INFO, "[drm] Could not create SAREA for DRM lock.\n");
+ : tmp.hLSAREA = 0;
+ : goto out_err;
+ : }
+ :
+ : if (drmMap( tmp.drmFD, tmp.hLSAREA, sAreaSize,
+ : (drmAddressPtr)(&tmp.pLSAREA)) < 0) {
+ : DRIDrvMsg(-1, X_INFO, "[drm] Mapping SAREA for DRM lock failed.\n");
+ : tmp.pLSAREA = NULL;
+ : goto out_err;
+ : }
+ :
+ : memset(tmp.pLSAREA, 0, sAreaSize);
+ :
+ : /*
+ : * Reserved contexts are handled by the first opened screen.
+ : */
+ :
+ : tmp.resOwner = NULL;
+ :
+ : if (!pDRIEntPriv)
+ : pDRIEntPriv = xnfcalloc(sizeof(*pDRIEntPriv), 1);
+ :
+ : if (!pDRIEntPriv) {
+ : DRIDrvMsg(-1, X_INFO, "[drm] Failed to allocate memory for "
+ : "DRM device.\n");
+ : goto out_err;
+ : }
+ : *pDRIEntPriv = tmp;
+ : xf86GetEntityPrivate((pScrn)->entityList[0],DRIEntPrivIndex)->ptr =
+ : pDRIEntPriv;
+ :
+ : DRIDrvMsg(-1, X_INFO, "[drm] DRM open master succeeded.\n");
+ : return TRUE;
+ :
+ : out_err:
+ :
+ : DRIOpenDRMCleanup(&tmp);
+ : return FALSE;
+ :}
+ :
+ :
+ :Bool
+ :DRIScreenInit(ScreenPtr pScreen, DRIInfoPtr pDRIInfo, int *pDRMFD)
+ :{
+ : DRIScreenPrivPtr pDRIPriv;
+ : drm_context_t * reserved;
+ : int reserved_count;
+ : int i;
+ : Bool xineramaInCore = FALSE;
+ : DRIEntPrivPtr pDRIEntPriv;
+ : ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ :
+ : /* If the DRI extension is disabled, do not initialize the DRI */
+ : if (noXFree86DRIExtension) {
+ : DRIDrvMsg(pScreen->myNum, X_WARNING,
+ : "Direct rendering has been disabled.\n");
+ : return FALSE;
+ : }
+ :
+ : /*
+ : * If Xinerama is on, don't allow DRI to initialise. It won't be usable
+ : * anyway.
+ : */
+ : if (xf86LoaderCheckSymbol("noPanoramiXExtension"))
+ : xineramaInCore = TRUE;
+ :
+ : if (xineramaInCore) {
+ : if (!noPanoramiXExtension) {
+ : DRIDrvMsg(pScreen->myNum, X_WARNING,
+ : "Direct rendering is not supported when Xinerama is enabled\n");
+ : return FALSE;
+ : }
+ : }
+ :
+ : if (!DRIOpenDRMMaster(pScrn, pDRIInfo->SAREASize,
+ : pDRIInfo->busIdString,
+ : pDRIInfo->drmDriverName))
+ : return FALSE;
+ :
+ : pDRIEntPriv = DRI_ENT_PRIV(pScrn);
+ :
+ : if (DRIGeneration != serverGeneration) {
+ : if ((DRIScreenPrivIndex = AllocateScreenPrivateIndex()) < 0)
+ : return FALSE;
+ : DRIGeneration = serverGeneration;
+ : }
+ :
+ : pDRIPriv = (DRIScreenPrivPtr) xcalloc(1, sizeof(DRIScreenPrivRec));
+ : if (!pDRIPriv) {
+ : pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
+ : DRIScreenPrivIndex = -1;
+ : return FALSE;
+ : }
+ :
+ : pScreen->devPrivates[DRIScreenPrivIndex].ptr = (pointer) pDRIPriv;
+ : pDRIPriv->drmFD = pDRIEntPriv->drmFD;
+ : pDRIPriv->directRenderingSupport = TRUE;
+ : pDRIPriv->pDriverInfo = pDRIInfo;
+ : pDRIPriv->nrWindows = 0;
+ : pDRIPriv->nrWindowsVisible = 0;
+ : pDRIPriv->fullscreen = NULL;
+ :
+ : pDRIPriv->createDummyCtx = pDRIInfo->createDummyCtx;
+ : pDRIPriv->createDummyCtxPriv = pDRIInfo->createDummyCtxPriv;
+ :
+ : pDRIPriv->grabbedDRILock = FALSE;
+ : pDRIPriv->drmSIGIOHandlerInstalled = FALSE;
+ : *pDRMFD = pDRIPriv->drmFD;
+ :
+ : if (pDRIEntPriv->sAreaGrabbed || pDRIInfo->allocSarea) {
+ :
+ : if (drmAddMap( pDRIPriv->drmFD,
+ : 0,
+ : pDRIPriv->pDriverInfo->SAREASize,
+ : DRM_SHM,
+ : 0,
+ : &pDRIPriv->hSAREA) < 0)
+ : {
+ : pDRIPriv->directRenderingSupport = FALSE;
+ : pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
+ : drmClose(pDRIPriv->drmFD);
+ : DRIDrvMsg(pScreen->myNum, X_INFO,
+ : "[drm] drmAddMap failed\n");
+ : return FALSE;
+ : }
+ : DRIDrvMsg(pScreen->myNum, X_INFO,
+ : "[drm] added %d byte SAREA at %p\n",
+ : pDRIPriv->pDriverInfo->SAREASize, pDRIPriv->hSAREA);
+ :
+ : /* Backwards compat. */
+ : if (drmMap( pDRIPriv->drmFD,
+ : pDRIPriv->hSAREA,
+ : pDRIPriv->pDriverInfo->SAREASize,
+ : (drmAddressPtr)(&pDRIPriv->pSAREA)) < 0)
+ : {
+ : pDRIPriv->directRenderingSupport = FALSE;
+ : pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
+ : drmClose(pDRIPriv->drmFD);
+ : DRIDrvMsg(pScreen->myNum, X_INFO,
+ : "[drm] drmMap failed\n");
+ : return FALSE;
+ : }
+ : DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] mapped SAREA %p to %p\n",
+ : pDRIPriv->hSAREA, pDRIPriv->pSAREA);
+ : memset(pDRIPriv->pSAREA, 0, pDRIPriv->pDriverInfo->SAREASize);
+ : } else {
+ : DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] Using the DRM lock "
+ : "SAREA also for drawables.\n");
+ : pDRIPriv->hSAREA = pDRIEntPriv->hLSAREA;
+ : pDRIPriv->pSAREA = (XF86DRISAREAPtr) pDRIEntPriv->pLSAREA;
+ : pDRIEntPriv->sAreaGrabbed = TRUE;
+ : }
+ :
+ : pDRIPriv->hLSAREA = pDRIEntPriv->hLSAREA;
+ : pDRIPriv->pLSAREA = pDRIEntPriv->pLSAREA;
+ :
+ : if (drmAddMap( pDRIPriv->drmFD,
+ : (drm_handle_t)pDRIPriv->pDriverInfo->frameBufferPhysicalAddress,
+ : pDRIPriv->pDriverInfo->frameBufferSize,
+ : DRM_FRAME_BUFFER,
+ : 0,
+ : &pDRIPriv->hFrameBuffer) < 0)
+ : {
+ : pDRIPriv->directRenderingSupport = FALSE;
+ : pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
+ : drmUnmap(pDRIPriv->pSAREA, pDRIPriv->pDriverInfo->SAREASize);
+ : drmClose(pDRIPriv->drmFD);
+ : DRIDrvMsg(pScreen->myNum, X_INFO,
+ : "[drm] drmAddMap failed\n");
+ : return FALSE;
+ : }
+ : DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] framebuffer handle = %p\n",
+ : pDRIPriv->hFrameBuffer);
+ :
+ : if (pDRIEntPriv->resOwner == NULL) {
+ : pDRIEntPriv->resOwner = pScreen;
+ :
+ : /* Add tags for reserved contexts */
+ : if ((reserved = drmGetReservedContextList(pDRIPriv->drmFD,
+ : &reserved_count))) {
+ : int i;
+ : void *tag;
+ :
+ : for (i = 0; i < reserved_count; i++) {
+ : tag = DRICreateContextPrivFromHandle(pScreen,
+ : reserved[i],
+ : DRI_CONTEXT_RESERVED);
+ : drmAddContextTag(pDRIPriv->drmFD, reserved[i], tag);
+ : }
+ : drmFreeReservedContextList(reserved);
+ : DRIDrvMsg(pScreen->myNum, X_INFO,
+ : "[drm] added %d reserved context%s for kernel\n",
+ : reserved_count, reserved_count > 1 ? "s" : "");
+ : }
+ : }
+ :
+ : /* validate max drawable table entry set by driver */
+ : if ((pDRIPriv->pDriverInfo->maxDrawableTableEntry <= 0) ||
+ : (pDRIPriv->pDriverInfo->maxDrawableTableEntry > SAREA_MAX_DRAWABLES)) {
+ : DRIDrvMsg(pScreen->myNum, X_ERROR,
+ : "Invalid max drawable table size set by driver: %d\n",
+ : pDRIPriv->pDriverInfo->maxDrawableTableEntry);
+ : }
+ :
+ : /* Initialize drawable tables (screen private and SAREA) */
+ : for( i=0; i < pDRIPriv->pDriverInfo->maxDrawableTableEntry; i++) {
+ : pDRIPriv->DRIDrawables[i] = NULL;
+ : pDRIPriv->pSAREA->drawableTable[i].stamp = 0;
+ : pDRIPriv->pSAREA->drawableTable[i].flags = 0;
+ : }
+ :
+ : pDRIPriv->pLockRefCount = &pDRIEntPriv->lockRefCount;
+ : pDRIPriv->pLockingContext = &pDRIEntPriv->lockingContext;
+ :
+ : if (!pDRIEntPriv->keepFDOpen)
+ : pDRIEntPriv->keepFDOpen = pDRIInfo->keepFDOpen;
+ :
+ : pDRIEntPriv->refCount++;
+ :
+ : return TRUE;
+ :}
+ :
+ :Bool
+ :DRIFinishScreenInit(ScreenPtr pScreen)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ : DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
+ : DRIContextFlags flags = 0;
+ : DRIContextPrivPtr pDRIContextPriv;
+ :
+ : /* Set up flags for DRICreateContextPriv */
+ : switch (pDRIInfo->driverSwapMethod) {
+ : case DRI_KERNEL_SWAP: flags = DRI_CONTEXT_2DONLY; break;
+ : case DRI_HIDE_X_CONTEXT: flags = DRI_CONTEXT_PRESERVED; break;
+ : }
+ :
+ : if (!(pDRIContextPriv = DRICreateContextPriv(pScreen,
+ : &pDRIPriv->myContext,
+ : flags))) {
+ : DRIDrvMsg(pScreen->myNum, X_ERROR,
+ : "failed to create server context\n");
+ : return FALSE;
+ : }
+ : pDRIPriv->myContextPriv = pDRIContextPriv;
+ :
+ : DRIDrvMsg(pScreen->myNum, X_INFO,
+ : "X context handle = %p\n", pDRIPriv->myContext);
+ :
+ : /* Now that we have created the X server's context, we can grab the
+ : * hardware lock for the X server.
+ : */
+ : DRILock(pScreen, 0);
+ : pDRIPriv->grabbedDRILock = TRUE;
+ :
+ : /* pointers so that we can prevent memory leaks later */
+ : pDRIPriv->hiddenContextStore = NULL;
+ : pDRIPriv->partial3DContextStore = NULL;
+ :
+ : switch(pDRIInfo->driverSwapMethod) {
+ : case DRI_HIDE_X_CONTEXT:
+ : /* Server will handle 3D swaps, and hide 2D swaps from kernel.
+ : * Register server context as a preserved context.
+ : */
+ :
+ : /* allocate memory for hidden context store */
+ : pDRIPriv->hiddenContextStore
+ : = (void *)xcalloc(1, pDRIInfo->contextSize);
+ : if (!pDRIPriv->hiddenContextStore) {
+ : DRIDrvMsg(pScreen->myNum, X_ERROR,
+ : "failed to allocate hidden context\n");
+ : DRIDestroyContextPriv(pDRIContextPriv);
+ : return FALSE;
+ : }
+ :
+ : /* allocate memory for partial 3D context store */
+ : pDRIPriv->partial3DContextStore
+ : = (void *)xcalloc(1, pDRIInfo->contextSize);
+ : if (!pDRIPriv->partial3DContextStore) {
+ : DRIDrvMsg(pScreen->myNum, X_ERROR,
+ : "[DRI] failed to allocate partial 3D context\n");
+ : xfree(pDRIPriv->hiddenContextStore);
+ : DRIDestroyContextPriv(pDRIContextPriv);
+ : return FALSE;
+ : }
+ :
+ : /* save initial context store */
+ : if (pDRIInfo->SwapContext) {
+ : (*pDRIInfo->SwapContext)(
+ : pScreen,
+ : DRI_NO_SYNC,
+ : DRI_2D_CONTEXT,
+ : pDRIPriv->hiddenContextStore,
+ : DRI_NO_CONTEXT,
+ : NULL);
+ : }
+ : /* fall through */
+ :
+ : case DRI_SERVER_SWAP:
+ : /* For swap methods of DRI_SERVER_SWAP and DRI_HIDE_X_CONTEXT
+ : * setup signal handler for receiving swap requests from kernel
+ : */
+ : if (!(pDRIPriv->drmSIGIOHandlerInstalled =
+ : drmInstallSIGIOHandler(pDRIPriv->drmFD, DRISwapContext))) {
+ : DRIDrvMsg(pScreen->myNum, X_ERROR,
+ : "[drm] failed to setup DRM signal handler\n");
+ : if (pDRIPriv->hiddenContextStore)
+ : xfree(pDRIPriv->hiddenContextStore);
+ : if (pDRIPriv->partial3DContextStore)
+ : xfree(pDRIPriv->partial3DContextStore);
+ : DRIDestroyContextPriv(pDRIContextPriv);
+ : return FALSE;
+ : } else {
+ : DRIDrvMsg(pScreen->myNum, X_INFO,
+ : "[drm] installed DRM signal handler\n");
+ : }
+ :
+ : default:
+ : break;
+ : }
+ :
+ : /* Wrap DRI support */
+ : if (pDRIInfo->wrap.ValidateTree) {
+ : pDRIPriv->wrap.ValidateTree = pScreen->ValidateTree;
+ : pScreen->ValidateTree = pDRIInfo->wrap.ValidateTree;
+ : }
+ : if (pDRIInfo->wrap.PostValidateTree) {
+ : pDRIPriv->wrap.PostValidateTree = pScreen->PostValidateTree;
+ : pScreen->PostValidateTree = pDRIInfo->wrap.PostValidateTree;
+ : }
+ : if (pDRIInfo->wrap.WindowExposures) {
+ : pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures;
+ : pScreen->WindowExposures = pDRIInfo->wrap.WindowExposures;
+ : }
+ : if (pDRIInfo->wrap.CopyWindow) {
+ : pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow;
+ : pScreen->CopyWindow = pDRIInfo->wrap.CopyWindow;
+ : }
+ : if (pDRIInfo->wrap.ClipNotify) {
+ : pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify;
+ : pScreen->ClipNotify = pDRIInfo->wrap.ClipNotify;
+ : }
+ : if (pDRIInfo->wrap.AdjustFrame) {
+ : ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ : pDRIPriv->wrap.AdjustFrame = pScrn->AdjustFrame;
+ : pScrn->AdjustFrame = pDRIInfo->wrap.AdjustFrame;
+ : }
+ : pDRIPriv->wrapped = TRUE;
+ :
+ : DRIDrvMsg(pScreen->myNum, X_INFO, "[DRI] installation complete\n");
+ :
+ : return TRUE;
+ :}
+ :
+ :void
+ :DRICloseScreen(ScreenPtr pScreen)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ : DRIInfoPtr pDRIInfo;
+ : drm_context_t * reserved;
+ : int reserved_count;
+ : ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ : DRIEntPrivPtr pDRIEntPriv = DRI_ENT_PRIV(pScrn);
+ : Bool closeMaster;
+ :
+ : if (pDRIPriv) {
+ :
+ : pDRIInfo = pDRIPriv->pDriverInfo;
+ :
+ : if (pDRIPriv->wrapped) {
+ : /* Unwrap DRI Functions */
+ : if (pDRIInfo->wrap.ValidateTree) {
+ : pScreen->ValidateTree = pDRIPriv->wrap.ValidateTree;
+ : pDRIPriv->wrap.ValidateTree = NULL;
+ : }
+ : if (pDRIInfo->wrap.PostValidateTree) {
+ : pScreen->PostValidateTree = pDRIPriv->wrap.PostValidateTree;
+ : pDRIPriv->wrap.PostValidateTree = NULL;
+ : }
+ : if (pDRIInfo->wrap.WindowExposures) {
+ : pScreen->WindowExposures = pDRIPriv->wrap.WindowExposures;
+ : pDRIPriv->wrap.WindowExposures = NULL;
+ : }
+ : if (pDRIInfo->wrap.CopyWindow) {
+ : pScreen->CopyWindow = pDRIPriv->wrap.CopyWindow;
+ : pDRIPriv->wrap.CopyWindow = NULL;
+ : }
+ : if (pDRIInfo->wrap.ClipNotify) {
+ : pScreen->ClipNotify = pDRIPriv->wrap.ClipNotify;
+ : pDRIPriv->wrap.ClipNotify = NULL;
+ : }
+ : if (pDRIInfo->wrap.AdjustFrame) {
+ : ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ : pScrn->AdjustFrame = pDRIPriv->wrap.AdjustFrame;
+ : pDRIPriv->wrap.AdjustFrame = NULL;
+ : }
+ : pDRIPriv->wrapped = FALSE;
+ : }
+ :
+ : if (pDRIPriv->drmSIGIOHandlerInstalled) {
+ : if (!drmRemoveSIGIOHandler(pDRIPriv->drmFD)) {
+ : DRIDrvMsg(pScreen->myNum, X_ERROR,
+ : "[drm] failed to remove DRM signal handler\n");
+ : }
+ : }
+ :
+ : if (pDRIPriv->dummyCtxPriv && pDRIPriv->createDummyCtx) {
+ : DRIDestroyDummyContext(pScreen, pDRIPriv->createDummyCtxPriv);
+ : }
+ :
+ : if (!DRIDestroyContextPriv(pDRIPriv->myContextPriv)) {
+ : DRIDrvMsg(pScreen->myNum, X_ERROR,
+ : "failed to destroy server context\n");
+ : }
+ :
+ : /* Remove tags for reserved contexts */
+ : if (pDRIEntPriv->resOwner == pScreen) {
+ : pDRIEntPriv->resOwner = NULL;
+ :
+ : if ((reserved = drmGetReservedContextList(pDRIPriv->drmFD,
+ : &reserved_count))) {
+ : int i;
+ :
+ : for (i = 0; i < reserved_count; i++) {
+ : DRIDestroyContextPriv(drmGetContextTag(pDRIPriv->drmFD,
+ : reserved[i]));
+ : }
+ : drmFreeReservedContextList(reserved);
+ : DRIDrvMsg(pScreen->myNum, X_INFO,
+ : "[drm] removed %d reserved context%s for kernel\n",
+ : reserved_count, reserved_count > 1 ? "s" : "");
+ : }
+ : }
+ :
+ : /* Make sure signals get unblocked etc. */
+ : drmUnlock(pDRIPriv->drmFD, pDRIPriv->myContext);
+ : pDRIPriv->pLockRefCount = NULL;
+ : closeMaster = (--pDRIEntPriv->refCount == 0) &&
+ : !pDRIEntPriv->keepFDOpen;
+ : if (closeMaster || pDRIPriv->hSAREA != pDRIEntPriv->hLSAREA) {
+ : DRIDrvMsg(pScreen->myNum, X_INFO,
+ : "[drm] unmapping %d bytes of SAREA %p at %p\n",
+ : pDRIInfo->SAREASize,
+ : pDRIPriv->hSAREA,
+ : pDRIPriv->pSAREA);
+ : if (drmUnmap(pDRIPriv->pSAREA, pDRIInfo->SAREASize)) {
+ : DRIDrvMsg(pScreen->myNum, X_ERROR,
+ : "[drm] unable to unmap %d bytes"
+ : " of SAREA %p at %p\n",
+ : pDRIInfo->SAREASize,
+ : pDRIPriv->hSAREA,
+ : pDRIPriv->pSAREA);
+ : }
+ : } else {
+ : pDRIEntPriv->sAreaGrabbed = FALSE;
+ : }
+ :
+ : if (closeMaster || (pDRIEntPriv->drmFD != pDRIPriv->drmFD)) {
+ : drmClose(pDRIPriv->drmFD);
+ : if (pDRIEntPriv->drmFD == pDRIPriv->drmFD) {
+ : DRIDrvMsg(pScreen->myNum, X_INFO,
+ : "[drm] Closed DRM master.\n");
+ : pDRIEntPriv->drmFD = -1;
+ : }
+ : }
+ :
+ : xfree(pDRIPriv);
+ : pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
+ : DRIScreenPrivIndex = -1;
+ : }
+ :}
+ :
+ :#define DRM_MSG_VERBOSITY 3
+ :
+ :static int dri_drm_debug_print(const char *format, va_list ap)
+ :{
+ : xf86VDrvMsgVerb(-1, X_NONE, DRM_MSG_VERBOSITY, format, ap);
+ : return 0;
+ :}
+ :
+ :static void dri_drm_get_perms(gid_t *group, mode_t *mode)
+ :{
+ : *group = xf86ConfigDRI.group;
+ : *mode = xf86ConfigDRI.mode;
+ :}
+ :
+ :drmServerInfo DRIDRMServerInfo = {
+ : dri_drm_debug_print,
+ : xf86LoadKernelModule,
+ : dri_drm_get_perms,
+ :};
+ :
+ :Bool
+ :DRIExtensionInit(void)
+ :{
+ : int i;
+ : ScreenPtr pScreen;
+ :
+ : if (DRIScreenPrivIndex < 0 || DRIGeneration != serverGeneration) {
+ : return FALSE;
+ : }
+ :
+ : /* Allocate a window private index with a zero sized private area for
+ : * each window, then should a window become a DRI window, we'll hang
+ : * a DRIWindowPrivateRec off of this private index.
+ : */
+ : if ((DRIWindowPrivIndex = AllocateWindowPrivateIndex()) < 0)
+ : return FALSE;
+ :
+ : DRIDrawablePrivResType = CreateNewResourceType(DRIDrawablePrivDelete);
+ : DRIContextPrivResType = CreateNewResourceType(DRIContextPrivDelete);
+ :
+ : for (i = 0; i < screenInfo.numScreens; i++)
+ : {
+ : pScreen = screenInfo.screens[i];
+ : if (!AllocateWindowPrivate(pScreen, DRIWindowPrivIndex, 0))
+ : return FALSE;
+ : }
+ :
+ : RegisterBlockAndWakeupHandlers(DRIBlockHandler, DRIWakeupHandler, NULL);
+ :
+ : return TRUE;
+ :}
+ :
+ :void
+ :DRIReset(void)
+ :{
+ : /*
+ : * This stub routine is called when the X Server recycles, resources
+ : * allocated by DRIExtensionInit need to be managed here.
+ : *
+ : * Currently this routine is a stub because all the interesting resources
+ : * are managed via the screen init process.
+ : */
+ :}
+ :
+ :Bool
+ :DRIQueryDirectRenderingCapable(ScreenPtr pScreen, Bool* isCapable)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : if (pDRIPriv)
+ : *isCapable = pDRIPriv->directRenderingSupport;
+ : else
+ : *isCapable = FALSE;
+ :
+ : return TRUE;
+ :}
+ :
+ :Bool
+ :DRIOpenConnection(ScreenPtr pScreen, drm_handle_t * hSAREA, char **busIdString)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : *hSAREA = pDRIPriv->hSAREA;
+ : *busIdString = pDRIPriv->pDriverInfo->busIdString;
+ :
+ : return TRUE;
+ :}
+ :
+ :Bool
+ :DRIAuthConnection(ScreenPtr pScreen, drm_magic_t magic)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : if (drmAuthMagic(pDRIPriv->drmFD, magic)) return FALSE;
+ : return TRUE;
+ :}
+ :
+ :Bool
+ :DRICloseConnection(ScreenPtr pScreen)
+ :{
+ : return TRUE;
+ :}
+ :
+ :Bool
+ :DRIGetClientDriverName(ScreenPtr pScreen,
+ : int *ddxDriverMajorVersion,
+ : int *ddxDriverMinorVersion,
+ : int *ddxDriverPatchVersion,
+ : char **clientDriverName)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : *ddxDriverMajorVersion = pDRIPriv->pDriverInfo->ddxDriverMajorVersion;
+ : *ddxDriverMinorVersion = pDRIPriv->pDriverInfo->ddxDriverMinorVersion;
+ : *ddxDriverPatchVersion = pDRIPriv->pDriverInfo->ddxDriverPatchVersion;
+ : *clientDriverName = pDRIPriv->pDriverInfo->clientDriverName;
+ :
+ : return TRUE;
+ :}
+ :
+ :/* DRICreateContextPriv and DRICreateContextPrivFromHandle are helper
+ : functions that layer on drmCreateContext and drmAddContextTag.
+ :
+ : DRICreateContextPriv always creates a kernel drm_context_t and then calls
+ : DRICreateContextPrivFromHandle to create a DRIContextPriv structure for
+ : DRI tracking. For the SIGIO handler, the drm_context_t is associated with
+ : DRIContextPrivPtr. Any special flags are stored in the DRIContextPriv
+ : area and are passed to the kernel (if necessary).
+ :
+ : DRICreateContextPriv returns a pointer to newly allocated
+ : DRIContextPriv, and returns the kernel drm_context_t in pHWContext. */
+ :
+ :DRIContextPrivPtr
+ :DRICreateContextPriv(ScreenPtr pScreen,
+ : drm_context_t * pHWContext,
+ : DRIContextFlags flags)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : if (drmCreateContext(pDRIPriv->drmFD, pHWContext)) {
+ : return NULL;
+ : }
+ :
+ : return DRICreateContextPrivFromHandle(pScreen, *pHWContext, flags);
+ :}
+ :
+ :DRIContextPrivPtr
+ :DRICreateContextPrivFromHandle(ScreenPtr pScreen,
+ : drm_context_t hHWContext,
+ : DRIContextFlags flags)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ : DRIContextPrivPtr pDRIContextPriv;
+ : int contextPrivSize;
+ :
+ : contextPrivSize = sizeof(DRIContextPrivRec) +
+ : pDRIPriv->pDriverInfo->contextSize;
+ : if (!(pDRIContextPriv = xcalloc(1, contextPrivSize))) {
+ : return NULL;
+ : }
+ : pDRIContextPriv->pContextStore = (void *)(pDRIContextPriv + 1);
+ :
+ : drmAddContextTag(pDRIPriv->drmFD, hHWContext, pDRIContextPriv);
+ :
+ : pDRIContextPriv->hwContext = hHWContext;
+ : pDRIContextPriv->pScreen = pScreen;
+ : pDRIContextPriv->flags = flags;
+ : pDRIContextPriv->valid3D = FALSE;
+ :
+ : if (flags & DRI_CONTEXT_2DONLY) {
+ : if (drmSetContextFlags(pDRIPriv->drmFD,
+ : hHWContext,
+ : DRM_CONTEXT_2DONLY)) {
+ : DRIDrvMsg(pScreen->myNum, X_ERROR,
+ : "[drm] failed to set 2D context flag\n");
+ : DRIDestroyContextPriv(pDRIContextPriv);
+ : return NULL;
+ : }
+ : }
+ : if (flags & DRI_CONTEXT_PRESERVED) {
+ : if (drmSetContextFlags(pDRIPriv->drmFD,
+ : hHWContext,
+ : DRM_CONTEXT_PRESERVED)) {
+ : DRIDrvMsg(pScreen->myNum, X_ERROR,
+ : "[drm] failed to set preserved flag\n");
+ : DRIDestroyContextPriv(pDRIContextPriv);
+ : return NULL;
+ : }
+ : }
+ : return pDRIContextPriv;
+ :}
+ :
+ :Bool
+ :DRIDestroyContextPriv(DRIContextPrivPtr pDRIContextPriv)
+ :{
+ : DRIScreenPrivPtr pDRIPriv;
+ :
+ : if (!pDRIContextPriv) return TRUE;
+ :
+ : pDRIPriv = DRI_SCREEN_PRIV(pDRIContextPriv->pScreen);
+ :
+ : if (!(pDRIContextPriv->flags & DRI_CONTEXT_RESERVED)) {
+ : /* Don't delete reserved contexts from
+ : kernel area -- the kernel manages its
+ : reserved contexts itself. */
+ : if (drmDestroyContext(pDRIPriv->drmFD, pDRIContextPriv->hwContext))
+ : return FALSE;
+ : }
+ :
+ : /* Remove the tag last to prevent a race
+ : condition where the context has pending
+ : buffers. The context can't be re-used
+ : while in this thread, but buffers can be
+ : dispatched asynchronously. */
+ : drmDelContextTag(pDRIPriv->drmFD, pDRIContextPriv->hwContext);
+ : xfree(pDRIContextPriv);
+ : return TRUE;
+ :}
+ :
+ :static Bool
+ :DRICreateDummyContext(ScreenPtr pScreen, Bool needCtxPriv)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ : __GLXscreen *pGLXScreen = __glXgetActiveScreen(pScreen->myNum);
+ : __GLcontextModes *modes = pGLXScreen->modes;
+ : void **pVisualConfigPriv = pGLXScreen->pVisualPriv;
+ : DRIContextPrivPtr pDRIContextPriv;
+ : void *contextStore;
+ : VisualPtr visual;
+ : int visNum;
+ :
+ : visual = pScreen->visuals;
+ :
+ : /* Find the X visual that corresponds the the first GLX visual */
+ : for (visNum = 0;
+ : visNum < pScreen->numVisuals;
+ : visNum++, visual++) {
+ : if (modes->visualID == visual->vid)
+ : break;
+ : }
+ : if (visNum == pScreen->numVisuals) return FALSE;
+ :
+ : if (!(pDRIContextPriv =
+ : DRICreateContextPriv(pScreen,
+ : &pDRIPriv->pSAREA->dummy_context, 0))) {
+ : return FALSE;
+ : }
+ :
+ : contextStore = DRIGetContextStore(pDRIContextPriv);
+ : if (pDRIPriv->pDriverInfo->CreateContext && needCtxPriv) {
+ : if (!pDRIPriv->pDriverInfo->CreateContext(pScreen, visual,
+ : pDRIPriv->pSAREA->dummy_context,
+ : *pVisualConfigPriv,
+ : (DRIContextType)(long)contextStore)) {
+ : DRIDestroyContextPriv(pDRIContextPriv);
+ : return FALSE;
+ : }
+ : }
+ :
+ : pDRIPriv->dummyCtxPriv = pDRIContextPriv;
+ : return TRUE;
+ :}
+ :
+ :static void
+ :DRIDestroyDummyContext(ScreenPtr pScreen, Bool hasCtxPriv)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ : DRIContextPrivPtr pDRIContextPriv = pDRIPriv->dummyCtxPriv;
+ : void *contextStore;
+ :
+ : if (!pDRIContextPriv) return;
+ : if (pDRIPriv->pDriverInfo->DestroyContext && hasCtxPriv) {
+ : contextStore = DRIGetContextStore(pDRIContextPriv);
+ : pDRIPriv->pDriverInfo->DestroyContext(pDRIContextPriv->pScreen,
+ : pDRIContextPriv->hwContext,
+ : (DRIContextType)(long)contextStore);
+ : }
+ :
+ : DRIDestroyContextPriv(pDRIPriv->dummyCtxPriv);
+ : pDRIPriv->dummyCtxPriv = NULL;
+ :}
+ :
+ :Bool
+ :DRICreateContext(ScreenPtr pScreen, VisualPtr visual,
+ : XID context, drm_context_t * pHWContext)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ : __GLXscreen *pGLXScreen = __glXgetActiveScreen(pScreen->myNum);
+ : __GLcontextModes *modes = pGLXScreen->modes;
+ : void **pVisualConfigPriv = pGLXScreen->pVisualPriv;
+ : DRIContextPrivPtr pDRIContextPriv;
+ : void *contextStore;
+ :
+ : if (pDRIPriv->createDummyCtx && !pDRIPriv->dummyCtxPriv) {
+ : if (!DRICreateDummyContext(pScreen, pDRIPriv->createDummyCtxPriv)) {
+ : DRIDrvMsg(pScreen->myNum, X_INFO,
+ : "[drm] Could not create dummy context\n");
+ : return FALSE;
+ : }
+ : }
+ :
+ : /* Find the GLX visual associated with the one requested */
+ : for (modes = pGLXScreen->modes; modes != NULL; modes = modes->next) {
+ : if (modes->visualID == visual->vid)
+ : break;
+ : pVisualConfigPriv++;
+ : }
+ :
+ : if (modes == NULL) {
+ : /* No matching GLX visual found */
+ : return FALSE;
+ : }
+ :
+ : if (!(pDRIContextPriv = DRICreateContextPriv(pScreen, pHWContext, 0))) {
+ : return FALSE;
+ : }
+ :
+ : contextStore = DRIGetContextStore(pDRIContextPriv);
+ : if (pDRIPriv->pDriverInfo->CreateContext) {
+ : if (!((*pDRIPriv->pDriverInfo->CreateContext)(pScreen, visual,
+ : *pHWContext, *pVisualConfigPriv,
+ : (DRIContextType)(long)contextStore))) {
+ : DRIDestroyContextPriv(pDRIContextPriv);
+ : return FALSE;
+ : }
+ : }
+ :
+ : /* track this in case the client dies before cleanup */
+ : AddResource(context, DRIContextPrivResType, (pointer)pDRIContextPriv);
+ :
+ : return TRUE;
+ :}
+ :
+ :Bool
+ :DRIDestroyContext(ScreenPtr pScreen, XID context)
+ :{
+ : FreeResourceByType(context, DRIContextPrivResType, FALSE);
+ :
+ : return TRUE;
+ :}
+ :
+ :/* DRIContextPrivDelete is called by the resource manager. */
+ :Bool
+ :DRIContextPrivDelete(pointer pResource, XID id)
+ :{
+ : DRIContextPrivPtr pDRIContextPriv = (DRIContextPrivPtr)pResource;
+ : DRIScreenPrivPtr pDRIPriv;
+ : void *contextStore;
+ :
+ : pDRIPriv = DRI_SCREEN_PRIV(pDRIContextPriv->pScreen);
+ : if (pDRIPriv->pDriverInfo->DestroyContext) {
+ : contextStore = DRIGetContextStore(pDRIContextPriv);
+ : pDRIPriv->pDriverInfo->DestroyContext(pDRIContextPriv->pScreen,
+ : pDRIContextPriv->hwContext,
+ : (DRIContextType)(long)contextStore);
+ : }
+ : return DRIDestroyContextPriv(pDRIContextPriv);
+ :}
+ :
+ :
+ :/* This walks the drawable timestamp array and invalidates all of them
+ : * in the case of transition from private to shared backbuffers. It's
+ : * not necessary for correctness, because DRIClipNotify gets called in
+ : * time to prevent any conflict, but the transition from
+ : * shared->private is sometimes missed if we don't do this.
+ : */
+ :static void
+ :DRIClipNotifyAllDrawables(ScreenPtr pScreen)
+ :{
+ : int i;
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : for( i=0; i < pDRIPriv->pDriverInfo->maxDrawableTableEntry; i++) {
+ : pDRIPriv->pSAREA->drawableTable[i].stamp = DRIDrawableValidationStamp++;
+ : }
+ :}
+ :
+ :
+ :static void
+ :DRITransitionToSharedBuffers(ScreenPtr pScreen)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ : DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
+ :
+ : DRIClipNotifyAllDrawables( pScreen );
+ :
+ : if (pDRIInfo->TransitionSingleToMulti3D)
+ : pDRIInfo->TransitionSingleToMulti3D( pScreen );
+ :}
+ :
+ :
+ :static void
+ :DRITransitionToPrivateBuffers(ScreenPtr pScreen)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ : DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
+ :
+ : DRIClipNotifyAllDrawables( pScreen );
+ :
+ : if (pDRIInfo->TransitionMultiToSingle3D)
+ : pDRIInfo->TransitionMultiToSingle3D( pScreen );
+ :}
+ :
+ :
+ :static void
+ :DRITransitionTo3d(ScreenPtr pScreen)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ : DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
+ :
+ : DRIClipNotifyAllDrawables( pScreen );
+ :
+ : if (pDRIInfo->TransitionTo3d)
+ : pDRIInfo->TransitionTo3d( pScreen );
+ :}
+ :
+ :static void
+ :DRITransitionTo2d(ScreenPtr pScreen)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ : DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
+ :
+ : DRIClipNotifyAllDrawables( pScreen );
+ :
+ : if (pDRIInfo->TransitionTo2d)
+ : pDRIInfo->TransitionTo2d( pScreen );
+ :}
+ :
+ :
+ :static int
+ :DRIDCNTreeTraversal(WindowPtr pWin, pointer data)
+ :{
+ : DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
+ :
+ : if (pDRIDrawablePriv) {
+ : ScreenPtr pScreen = pWin->drawable.pScreen;
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : if (REGION_NUM_RECTS(&pWin->clipList) > 0) {
+ : WindowPtr *pDRIWindows = (WindowPtr*)data;
+ : int i = 0;
+ :
+ : while (pDRIWindows[i])
+ : i++;
+ :
+ : pDRIWindows[i] = pWin;
+ :
+ : pDRIPriv->nrWalked++;
+ : }
+ :
+ : if (pDRIPriv->nrWindows == pDRIPriv->nrWalked)
+ : return WT_STOPWALKING;
+ : }
+ :
+ : return WT_WALKCHILDREN;
+ :}
+ :
+ :static void
+ :DRIDriverClipNotify(ScreenPtr pScreen)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : if (pDRIPriv->pDriverInfo->ClipNotify) {
+ : WindowPtr *pDRIWindows = xcalloc(sizeof(WindowPtr), pDRIPriv->nrWindows);
+ : DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
+ :
+ : if (pDRIPriv->nrWindows > 0) {
+ : pDRIPriv->nrWalked = 0;
+ : TraverseTree(WindowTable[pScreen->myNum], DRIDCNTreeTraversal,
+ : (pointer)pDRIWindows);
+ : }
+ :
+ : pDRIInfo->ClipNotify(pScreen, pDRIWindows, pDRIPriv->nrWindows);
+ :
+ : xfree(pDRIWindows);
+ : }
+ :}
+ :
+ :static void
+ :DRIIncreaseNumberVisible(ScreenPtr pScreen)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : switch (++pDRIPriv->nrWindowsVisible) {
+ : case 1:
+ : DRITransitionTo3d( pScreen );
+ : break;
+ : case 2:
+ : DRITransitionToSharedBuffers( pScreen );
+ : break;
+ : default:
+ : break;
+ : }
+ :
+ : DRIDriverClipNotify(pScreen);
+ :}
+ :
+ :static void
+ :DRIDecreaseNumberVisible(ScreenPtr pScreen)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : switch (--pDRIPriv->nrWindowsVisible) {
+ : case 0:
+ : DRITransitionTo2d( pScreen );
+ : break;
+ : case 1:
+ : DRITransitionToPrivateBuffers( pScreen );
+ : break;
+ : default:
+ : break;
+ : }
+ :
+ : DRIDriverClipNotify(pScreen);
+ :}
+ :
+ :Bool
+ :DRICreateDrawable(ScreenPtr pScreen, Drawable id,
+ : DrawablePtr pDrawable, drm_drawable_t * hHWDrawable)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ : DRIDrawablePrivPtr pDRIDrawablePriv;
+ : WindowPtr pWin;
+ :
+ : if (pDrawable->type == DRAWABLE_WINDOW) {
+ : pWin = (WindowPtr)pDrawable;
+ : if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) {
+ : pDRIDrawablePriv->refCount++;
+ :
+ : if (!pDRIDrawablePriv->hwDrawable) {
+ : drmCreateDrawable(pDRIPriv->drmFD, &pDRIDrawablePriv->hwDrawable);
+ : }
+ : }
+ : else {
+ : /* allocate a DRI Window Private record */
+ : if (!(pDRIDrawablePriv = xalloc(sizeof(DRIDrawablePrivRec)))) {
+ : return FALSE;
+ : }
+ :
+ : /* Only create a drm_drawable_t once */
+ : if (drmCreateDrawable(pDRIPriv->drmFD,
+ : &pDRIDrawablePriv->hwDrawable)) {
+ : xfree(pDRIDrawablePriv);
+ : return FALSE;
+ : }
+ :
+ : /* add it to the list of DRI drawables for this screen */
+ : pDRIDrawablePriv->pScreen = pScreen;
+ : pDRIDrawablePriv->refCount = 1;
+ : pDRIDrawablePriv->drawableIndex = -1;
+ : pDRIDrawablePriv->nrects = REGION_NUM_RECTS(&pWin->clipList);
+ :
+ : /* save private off of preallocated index */
+ : pWin->devPrivates[DRIWindowPrivIndex].ptr =
+ : (pointer)pDRIDrawablePriv;
+ :
+ : pDRIPriv->nrWindows++;
+ :
+ : if (pDRIDrawablePriv->nrects)
+ : DRIIncreaseNumberVisible(pScreen);
+ :
+ : /* track this in case this window is destroyed */
+ : AddResource(id, DRIDrawablePrivResType, (pointer)pWin);
+ : }
+ :
+ : if (pDRIDrawablePriv->hwDrawable) {
+ : drmUpdateDrawableInfo(pDRIPriv->drmFD,
+ : pDRIDrawablePriv->hwDrawable,
+ : DRM_DRAWABLE_CLIPRECTS,
+ : REGION_NUM_RECTS(&pWin->clipList),
+ : REGION_RECTS(&pWin->clipList));
+ : *hHWDrawable = pDRIDrawablePriv->hwDrawable;
+ : }
+ : }
+ : else { /* pixmap (or for GLX 1.3, a PBuffer) */
+ : /* NOT_DONE */
+ : return FALSE;
+ : }
+ :
+ : return TRUE;
+ :}
+ :
+ :Bool
+ :DRIDestroyDrawable(ScreenPtr pScreen, Drawable id, DrawablePtr pDrawable)
+ :{
+ : DRIDrawablePrivPtr pDRIDrawablePriv;
+ : WindowPtr pWin;
+ :
+ :
+ : if (pDrawable->type == DRAWABLE_WINDOW) {
+ : pWin = (WindowPtr)pDrawable;
+ : pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
+ : pDRIDrawablePriv->refCount--;
+ : if (pDRIDrawablePriv->refCount <= 0) {
+ : /* This calls back DRIDrawablePrivDelete which frees private area */
+ : FreeResourceByType(id, DRIDrawablePrivResType, FALSE);
+ : }
+ : }
+ : else { /* pixmap (or for GLX 1.3, a PBuffer) */
+ : /* NOT_DONE */
+ : return FALSE;
+ : }
+ :
+ : return TRUE;
+ :}
+ :
+ :Bool
+ :DRIDrawablePrivDelete(pointer pResource, XID id)
+ :{
+ : DrawablePtr pDrawable = (DrawablePtr)pResource;
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pDrawable->pScreen);
+ : DRIDrawablePrivPtr pDRIDrawablePriv;
+ : WindowPtr pWin;
+ :
+ : if (pDrawable->type == DRAWABLE_WINDOW) {
+ : pWin = (WindowPtr)pDrawable;
+ : pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
+ :
+ : if (pDRIDrawablePriv->drawableIndex != -1) {
+ : /* bump stamp to force outstanding 3D requests to resync */
+ : pDRIPriv->pSAREA->drawableTable[pDRIDrawablePriv->drawableIndex].stamp
+ : = DRIDrawableValidationStamp++;
+ :
+ : /* release drawable table entry */
+ : pDRIPriv->DRIDrawables[pDRIDrawablePriv->drawableIndex] = NULL;
+ : }
+ :
+ : if (drmDestroyDrawable(pDRIPriv->drmFD,
+ : pDRIDrawablePriv->hwDrawable)) {
+ : return FALSE;
+ : }
+ :
+ : xfree(pDRIDrawablePriv);
+ : pWin->devPrivates[DRIWindowPrivIndex].ptr = NULL;
+ :
+ : pDRIPriv->nrWindows--;
+ :
+ : if (REGION_NUM_RECTS(&pWin->clipList))
+ : DRIDecreaseNumberVisible(pDrawable->pScreen);
+ : }
+ : else { /* pixmap (or for GLX 1.3, a PBuffer) */
+ : /* NOT_DONE */
+ : return FALSE;
+ : }
+ :
+ : return TRUE;
+ :}
+ :
+ :Bool
+ :DRIGetDrawableInfo(ScreenPtr pScreen,
+ : DrawablePtr pDrawable,
+ : unsigned int* index,
+ : unsigned int* stamp,
+ : int* X,
+ : int* Y,
+ : int* W,
+ : int* H,
+ : int* numClipRects,
+ : drm_clip_rect_t ** pClipRects,
+ : int* backX,
+ : int* backY,
+ : int* numBackClipRects,
+ : drm_clip_rect_t ** pBackClipRects)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ : DRIDrawablePrivPtr pDRIDrawablePriv, pOldDrawPriv;
+ : WindowPtr pWin, pOldWin;
+ : int i;
+ :
+ :#if 0
+ : printf("maxDrawableTableEntry = %d\n", pDRIPriv->pDriverInfo->maxDrawableTableEntry);
+ :#endif
+ :
+ : if (pDrawable->type == DRAWABLE_WINDOW) {
+ : pWin = (WindowPtr)pDrawable;
+ : if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) {
+ :
+ : /* Manage drawable table */
+ : if (pDRIDrawablePriv->drawableIndex == -1) { /* load SAREA table */
+ :
+ : /* Search table for empty entry */
+ : i = 0;
+ : while (i < pDRIPriv->pDriverInfo->maxDrawableTableEntry) {
+ : if (!(pDRIPriv->DRIDrawables[i])) {
+ : pDRIPriv->DRIDrawables[i] = pDrawable;
+ : pDRIDrawablePriv->drawableIndex = i;
+ : pDRIPriv->pSAREA->drawableTable[i].stamp =
+ : DRIDrawableValidationStamp++;
+ : break;
+ : }
+ : i++;
+ : }
+ :
+ : /* Search table for oldest entry */
+ : if (i == pDRIPriv->pDriverInfo->maxDrawableTableEntry) {
+ : unsigned int oldestStamp = ~0;
+ : int oldestIndex = 0;
+ : i = pDRIPriv->pDriverInfo->maxDrawableTableEntry;
+ : while (i--) {
+ : if (pDRIPriv->pSAREA->drawableTable[i].stamp <
+ : oldestStamp) {
+ : oldestIndex = i;
+ : oldestStamp =
+ : pDRIPriv->pSAREA->drawableTable[i].stamp;
+ : }
+ : }
+ : pDRIDrawablePriv->drawableIndex = oldestIndex;
+ :
+ : /* release oldest drawable table entry */
+ : pOldWin = (WindowPtr)pDRIPriv->DRIDrawables[oldestIndex];
+ : pOldDrawPriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pOldWin);
+ : pOldDrawPriv->drawableIndex = -1;
+ :
+ : /* claim drawable table entry */
+ : pDRIPriv->DRIDrawables[oldestIndex] = pDrawable;
+ :
+ : /* validate SAREA entry */
+ : pDRIPriv->pSAREA->drawableTable[oldestIndex].stamp =
+ : DRIDrawableValidationStamp++;
+ :
+ : /* check for stamp wrap around */
+ : if (oldestStamp > DRIDrawableValidationStamp) {
+ :
+ : /* walk SAREA table and invalidate all drawables */
+ : for( i=0;
+ : i < pDRIPriv->pDriverInfo->maxDrawableTableEntry;
+ : i++) {
+ : pDRIPriv->pSAREA->drawableTable[i].stamp =
+ : DRIDrawableValidationStamp++;
+ : }
+ : }
+ : }
+ :
+ : /* If the driver wants to be notified when the index is
+ : * set for a drawable, let it know now.
+ : */
+ : if (pDRIPriv->pDriverInfo->SetDrawableIndex)
+ : pDRIPriv->pDriverInfo->SetDrawableIndex(pWin,
+ : pDRIDrawablePriv->drawableIndex);
+ :
+ : /* reinit drawable ID if window is visible */
+ : if ((pWin->viewable) &&
+ : (pDRIPriv->pDriverInfo->bufferRequests != DRI_NO_WINDOWS))
+ : {
+ : (*pDRIPriv->pDriverInfo->InitBuffers)(pWin,
+ : &pWin->clipList, pDRIDrawablePriv->drawableIndex);
+ : }
+ : }
+ :
+ : *index = pDRIDrawablePriv->drawableIndex;
+ : *stamp = pDRIPriv->pSAREA->drawableTable[*index].stamp;
+ : *X = (int)(pWin->drawable.x);
+ : *Y = (int)(pWin->drawable.y);
+ :#if 0
+ : *W = (int)(pWin->winSize.extents.x2 - pWin->winSize.extents.x1);
+ : *H = (int)(pWin->winSize.extents.y2 - pWin->winSize.extents.y1);
+ :#endif
+ : *W = (int)(pWin->drawable.width);
+ : *H = (int)(pWin->drawable.height);
+ : *numClipRects = REGION_NUM_RECTS(&pWin->clipList);
+ : *pClipRects = (drm_clip_rect_t *)REGION_RECTS(&pWin->clipList);
+ :
+ : if (!*numClipRects && pDRIPriv->fullscreen) {
+ : /* use fake full-screen clip rect */
+ : pDRIPriv->fullscreen_rect.x1 = *X;
+ : pDRIPriv->fullscreen_rect.y1 = *Y;
+ : pDRIPriv->fullscreen_rect.x2 = *X + *W;
+ : pDRIPriv->fullscreen_rect.y2 = *Y + *H;
+ :
+ : *numClipRects = 1;
+ : *pClipRects = &pDRIPriv->fullscreen_rect;
+ : }
+ :
+ : *backX = *X;
+ : *backY = *Y;
+ :
+ : if (pDRIPriv->nrWindowsVisible == 1 && *numClipRects) {
+ : /* Use a single cliprect. */
+ :
+ : int x0 = *X;
+ : int y0 = *Y;
+ : int x1 = x0 + *W;
+ : int y1 = y0 + *H;
+ :
+ : if (x0 < 0) x0 = 0;
+ : if (y0 < 0) y0 = 0;
+ : if (x1 > pScreen->width) x1 = pScreen->width;
+ : if (y1 > pScreen->height) y1 = pScreen->height;
+ :
+ : if (y0 >= y1 || x0 >= x1) {
+ : *numBackClipRects = 0;
+ : *pBackClipRects = NULL;
+ : } else {
+ : pDRIPriv->private_buffer_rect.x1 = x0;
+ : pDRIPriv->private_buffer_rect.y1 = y0;
+ : pDRIPriv->private_buffer_rect.x2 = x1;
+ : pDRIPriv->private_buffer_rect.y2 = y1;
+ :
+ : *numBackClipRects = 1;
+ : *pBackClipRects = &(pDRIPriv->private_buffer_rect);
+ : }
+ : } else {
+ : /* Use the frontbuffer cliprects for back buffers. */
+ : *numBackClipRects = 0;
+ : *pBackClipRects = 0;
+ : }
+ : }
+ : else {
+ : /* Not a DRIDrawable */
+ : return FALSE;
+ : }
+ : }
+ : else { /* pixmap (or for GLX 1.3, a PBuffer) */
+ : /* NOT_DONE */
+ : return FALSE;
+ : }
+ :
+ : return TRUE;
+ :}
+ :
+ :Bool
+ :DRIGetDeviceInfo(ScreenPtr pScreen,
+ : drm_handle_t * hFrameBuffer,
+ : int* fbOrigin,
+ : int* fbSize,
+ : int* fbStride,
+ : int* devPrivateSize,
+ : void** pDevPrivate)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : *hFrameBuffer = pDRIPriv->hFrameBuffer;
+ : *fbOrigin = 0;
+ : *fbSize = pDRIPriv->pDriverInfo->frameBufferSize;
+ : *fbStride = pDRIPriv->pDriverInfo->frameBufferStride;
+ : *devPrivateSize = pDRIPriv->pDriverInfo->devPrivateSize;
+ : *pDevPrivate = pDRIPriv->pDriverInfo->devPrivate;
+ :
+ : return TRUE;
+ :}
+ :
+ :DRIInfoPtr
+ :DRICreateInfoRec(void)
+ :{
+ : DRIInfoPtr inforec = (DRIInfoPtr)xcalloc(1, sizeof(DRIInfoRec));
+ : if (!inforec) return NULL;
+ :
+ : /* Initialize defaults */
+ : inforec->busIdString = NULL;
+ :
+ : /* Wrapped function defaults */
+ : inforec->wrap.WakeupHandler = DRIDoWakeupHandler;
+ : inforec->wrap.BlockHandler = DRIDoBlockHandler;
+ : inforec->wrap.WindowExposures = DRIWindowExposures;
+ : inforec->wrap.CopyWindow = DRICopyWindow;
+ : inforec->wrap.ValidateTree = DRIValidateTree;
+ : inforec->wrap.PostValidateTree = DRIPostValidateTree;
+ : inforec->wrap.ClipNotify = DRIClipNotify;
+ : inforec->wrap.AdjustFrame = DRIAdjustFrame;
+ :
+ : inforec->TransitionTo2d = 0;
+ : inforec->TransitionTo3d = 0;
+ : inforec->SetDrawableIndex = 0;
+ :
+ : return inforec;
+ :}
+ :
+ :void
+ :DRIDestroyInfoRec(DRIInfoPtr DRIInfo)
+ :{
+ : if (DRIInfo->busIdString) xfree(DRIInfo->busIdString);
+ : xfree((char*)DRIInfo);
+ :}
+ :
+ :
+ :void
+ :DRIWakeupHandler(pointer wakeupData, int result, pointer pReadmask)
+ :{
+ : int i;
+ :
+ : for (i = 0; i < screenInfo.numScreens; i++) {
+ : ScreenPtr pScreen = screenInfo.screens[i];
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : if (pDRIPriv &&
+ : pDRIPriv->pDriverInfo->wrap.WakeupHandler)
+ : (*pDRIPriv->pDriverInfo->wrap.WakeupHandler)(i, wakeupData,
+ : result, pReadmask);
+ : }
+ :}
+ :
+ :void
+ :DRIBlockHandler(pointer blockData, OSTimePtr pTimeout, pointer pReadmask)
+ :{
+ : int i;
+ :
+ : for (i = 0; i < screenInfo.numScreens; i++) {
+ : ScreenPtr pScreen = screenInfo.screens[i];
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : if (pDRIPriv &&
+ : pDRIPriv->pDriverInfo->wrap.BlockHandler)
+ : (*pDRIPriv->pDriverInfo->wrap.BlockHandler)(i, blockData,
+ : pTimeout, pReadmask);
+ : }
+ :}
+ :
+ :void
+ :DRIDoWakeupHandler(int screenNum, pointer wakeupData,
+ : unsigned long result, pointer pReadmask)
+ :{
+ : ScreenPtr pScreen = screenInfo.screens[screenNum];
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : DRILock(pScreen, 0);
+ : if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
+ : /* hide X context by swapping 2D component here */
+ : (*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
+ : DRI_3D_SYNC,
+ : DRI_2D_CONTEXT,
+ : pDRIPriv->partial3DContextStore,
+ : DRI_2D_CONTEXT,
+ : pDRIPriv->hiddenContextStore);
+ : }
+ :}
+ :
+ :void
+ :DRIDoBlockHandler(int screenNum, pointer blockData,
+ : pointer pTimeout, pointer pReadmask)
+ :{
+ : ScreenPtr pScreen = screenInfo.screens[screenNum];
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
+ : /* hide X context by swapping 2D component here */
+ : (*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
+ : DRI_2D_SYNC,
+ : DRI_NO_CONTEXT,
+ : NULL,
+ : DRI_2D_CONTEXT,
+ : pDRIPriv->partial3DContextStore);
+ : }
+ :
+ : if (pDRIPriv->windowsTouched)
+ : DRM_SPINUNLOCK(&pDRIPriv->pSAREA->drawable_lock, 1);
+ : pDRIPriv->windowsTouched = FALSE;
+ :
+ : DRIUnlock(pScreen);
+ :}
+ :
+ :void
+ :DRISwapContext(int drmFD, void *oldctx, void *newctx)
+ :{
+ : DRIContextPrivPtr oldContext = (DRIContextPrivPtr)oldctx;
+ : DRIContextPrivPtr newContext = (DRIContextPrivPtr)newctx;
+ : ScreenPtr pScreen = newContext->pScreen;
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ : void* oldContextStore = NULL;
+ : DRIContextType oldContextType;
+ : void* newContextStore = NULL;
+ : DRIContextType newContextType;
+ : DRISyncType syncType;
+ :#ifdef DEBUG
+ : static int count = 0;
+ :
+ : if (!newContext) {
+ : DRIDrvMsg(pScreen->myNum, X_ERROR,
+ : "[DRI] Context Switch Error: oldContext=%x, newContext=%x\n",
+ : oldContext, newContext);
+ : return;
+ : }
+ :
+ : /* usefull for debugging, just print out after n context switches */
+ : if (!count || !(count % 1)) {
+ : DRIDrvMsg(pScreen->myNum, X_INFO,
+ : "[DRI] Context switch %5d from %p/0x%08x (%d)\n",
+ : count,
+ : oldContext,
+ : oldContext ? oldContext->flags : 0,
+ : oldContext ? oldContext->hwContext : -1);
+ : DRIDrvMsg(pScreen->myNum, X_INFO,
+ : "[DRI] Context switch %5d to %p/0x%08x (%d)\n",
+ : count,
+ : newContext,
+ : newContext ? newContext->flags : 0,
+ : newContext ? newContext->hwContext : -1);
+ : }
+ : ++count;
+ :#endif
+ :
+ : if (!pDRIPriv->pDriverInfo->SwapContext) {
+ : DRIDrvMsg(pScreen->myNum, X_ERROR,
+ : "[DRI] DDX driver missing context swap call back\n");
+ : return;
+ : }
+ :
+ : if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
+ :
+ : /* only 3D contexts are swapped in this case */
+ : if (oldContext) {
+ : oldContextStore = DRIGetContextStore(oldContext);
+ : oldContext->valid3D = TRUE;
+ : oldContextType = DRI_3D_CONTEXT;
+ : } else {
+ : oldContextType = DRI_NO_CONTEXT;
+ : }
+ : newContextStore = DRIGetContextStore(newContext);
+ : if ((newContext->valid3D) &&
+ : (newContext->hwContext != pDRIPriv->myContext)) {
+ : newContextType = DRI_3D_CONTEXT;
+ : }
+ : else {
+ : newContextType = DRI_2D_CONTEXT;
+ : }
+ : syncType = DRI_3D_SYNC;
+ : }
+ : else /* default: driverSwapMethod == DRI_SERVER_SWAP */ {
+ :
+ : /* optimize 2D context swaps */
+ :
+ : if (newContext->flags & DRI_CONTEXT_2DONLY) {
+ : /* go from 3D context to 2D context and only save 2D
+ : * subset of 3D state
+ : */
+ : oldContextStore = DRIGetContextStore(oldContext);
+ : oldContextType = DRI_2D_CONTEXT;
+ : newContextStore = DRIGetContextStore(newContext);
+ : newContextType = DRI_2D_CONTEXT;
+ : syncType = DRI_3D_SYNC;
+ : pDRIPriv->lastPartial3DContext = oldContext;
+ : }
+ : else if (oldContext->flags & DRI_CONTEXT_2DONLY) {
+ : if (pDRIPriv->lastPartial3DContext == newContext) {
+ : /* go from 2D context back to previous 3D context and
+ : * only restore 2D subset of previous 3D state
+ : */
+ : oldContextStore = DRIGetContextStore(oldContext);
+ : oldContextType = DRI_2D_CONTEXT;
+ : newContextStore = DRIGetContextStore(newContext);
+ : newContextType = DRI_2D_CONTEXT;
+ : syncType = DRI_2D_SYNC;
+ : }
+ : else {
+ : /* go from 2D context to a different 3D context */
+ :
+ : /* call DDX driver to do partial restore */
+ : oldContextStore = DRIGetContextStore(oldContext);
+ : newContextStore =
+ : DRIGetContextStore(pDRIPriv->lastPartial3DContext);
+ : (*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
+ : DRI_2D_SYNC,
+ : DRI_2D_CONTEXT,
+ : oldContextStore,
+ : DRI_2D_CONTEXT,
+ : newContextStore);
+ :
+ : /* now setup for a complete 3D swap */
+ : oldContextStore = newContextStore;
+ : oldContext->valid3D = TRUE;
+ : oldContextType = DRI_3D_CONTEXT;
+ : newContextStore = DRIGetContextStore(newContext);
+ : if ((newContext->valid3D) &&
+ : (newContext->hwContext != pDRIPriv->myContext)) {
+ : newContextType = DRI_3D_CONTEXT;
+ : }
+ : else {
+ : newContextType = DRI_2D_CONTEXT;
+ : }
+ : syncType = DRI_NO_SYNC;
+ : }
+ : }
+ : else {
+ : /* now setup for a complete 3D swap */
+ : oldContextStore = newContextStore;
+ : oldContext->valid3D = TRUE;
+ : oldContextType = DRI_3D_CONTEXT;
+ : newContextStore = DRIGetContextStore(newContext);
+ : if ((newContext->valid3D) &&
+ : (newContext->hwContext != pDRIPriv->myContext)) {
+ : newContextType = DRI_3D_CONTEXT;
+ : }
+ : else {
+ : newContextType = DRI_2D_CONTEXT;
+ : }
+ : syncType = DRI_3D_SYNC;
+ : }
+ : }
+ :
+ : /* call DDX driver to perform the swap */
+ : (*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
+ : syncType,
+ : oldContextType,
+ : oldContextStore,
+ : newContextType,
+ : newContextStore);
+ :}
+ :
+ :void*
+ :DRIGetContextStore(DRIContextPrivPtr context)
+ :{
+ : return((void *)context->pContextStore);
+ :}
+ :
+ :void
+ :DRIWindowExposures(WindowPtr pWin, RegionPtr prgn, RegionPtr bsreg)
+ :{
+ : ScreenPtr pScreen = pWin->drawable.pScreen;
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ : DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
+ :
+ : if(pDRIDrawablePriv) {
+ : (*pDRIPriv->pDriverInfo->InitBuffers)(pWin, prgn,
+ : pDRIDrawablePriv->drawableIndex);
+ : }
+ :
+ : /* call lower wrapped functions */
+ : if (pDRIPriv && pDRIPriv->wrap.WindowExposures) {
+ :
+ : /* unwrap */
+ : pScreen->WindowExposures = pDRIPriv->wrap.WindowExposures;
+ :
+ : /* call lower layers */
+ : (*pScreen->WindowExposures)(pWin, prgn, bsreg);
+ :
+ : /* rewrap */
+ : pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures;
+ : pScreen->WindowExposures = DRIWindowExposures;
+ : }
+ :}
+ :
+ :
+ :static int
+ :DRITreeTraversal(WindowPtr pWin, pointer data)
+ :{
+ : DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
+ :
+ : if(pDRIDrawablePriv) {
+ : ScreenPtr pScreen = pWin->drawable.pScreen;
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : if(REGION_NUM_RECTS(&(pWin->clipList)) > 0) {
+ : RegionPtr reg = (RegionPtr)data;
+ :
+ : REGION_UNION(pScreen, reg, reg, &(pWin->clipList));
+ : pDRIPriv->nrWalked++;
+ : }
+ :
+ : if(pDRIPriv->nrWindows == pDRIPriv->nrWalked)
+ : return WT_STOPWALKING;
+ : }
+ : return WT_WALKCHILDREN;
+ :}
+ :
+ :void
+ :DRICopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
+ :{
+ : ScreenPtr pScreen = pWin->drawable.pScreen;
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : if(!pDRIPriv) return;
+ :
+ : if(pDRIPriv->nrWindowsVisible > 0) {
+ : RegionRec reg;
+ :
+ : REGION_NULL(pScreen, ®);
+ : pDRIPriv->nrWalked = 0;
+ : TraverseTree(pWin, DRITreeTraversal, (pointer)(®));
+ :
+ : if(REGION_NOTEMPTY(pScreen, ®)) {
+ : REGION_TRANSLATE(pScreen, ®, ptOldOrg.x - pWin->drawable.x,
+ : ptOldOrg.y - pWin->drawable.y);
+ : REGION_INTERSECT(pScreen, ®, ®, prgnSrc);
+ :
+ : /* The MoveBuffers interface is not ideal */
+ : (*pDRIPriv->pDriverInfo->MoveBuffers)(pWin, ptOldOrg, ®,
+ : pDRIPriv->pDriverInfo->ddxDrawableTableEntry);
+ : }
+ :
+ : REGION_UNINIT(pScreen, ®);
+ : }
+ :
+ : /* call lower wrapped functions */
+ : if(pDRIPriv->wrap.CopyWindow) {
+ : /* unwrap */
+ : pScreen->CopyWindow = pDRIPriv->wrap.CopyWindow;
+ :
+ : /* call lower layers */
+ : (*pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc);
+ :
+ : /* rewrap */
+ : pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow;
+ : pScreen->CopyWindow = DRICopyWindow;
+ : }
+ :}
+ :
+ :static void
+ :DRIGetSecs(long *secs, long *usecs)
+ :{
+ : struct timeval tv;
+ :
+ : gettimeofday(&tv, NULL);
+ :
+ : *secs = tv.tv_sec;
+ : *usecs = tv.tv_usec;
+ :}
+ :
+ :static unsigned long
+ :DRIComputeMilliSeconds(unsigned long s_secs, unsigned long s_usecs,
+ : unsigned long f_secs, unsigned long f_usecs)
+ :{
+ : if (f_usecs < s_usecs) {
+ : --f_secs;
+ : f_usecs += 1000000;
+ : }
+ : return (f_secs - s_secs) * 1000 + (f_usecs - s_usecs) / 1000;
+ :}
+ :
+ :static void
+ :DRISpinLockTimeout(drmLock *lock, int val, unsigned long timeout /* in mS */)
+ :{
+ : int count = 10000;
+ :#if !defined(__alpha__) && !defined(__powerpc__)
+ : char ret;
+ :#else
+ : int ret;
+ :#endif
+ : long s_secs, s_usecs;
+ : long f_secs, f_usecs;
+ : long msecs;
+ : long prev = 0;
+ :
+ : DRIGetSecs(&s_secs, &s_usecs);
+ :
+ : do {
+ : DRM_SPINLOCK_COUNT(lock, val, count, ret);
+ : if (!ret) return; /* Got lock */
+ : DRIGetSecs(&f_secs, &f_usecs);
+ : msecs = DRIComputeMilliSeconds(s_secs, s_usecs, f_secs, f_usecs);
+ : if (msecs - prev < 250) count *= 2; /* Not more than 0.5S */
+ : } while (msecs < timeout);
+ :
+ : /* Didn't get lock, so take it. The worst
+ : that can happen is that there is some
+ : garbage written to the wrong part of the
+ : framebuffer that a refresh will repair.
+ : That's undesirable, but better than
+ : locking the server. This should be a
+ : very rare event. */
+ : DRM_SPINLOCK_TAKE(lock, val);
+ :}
+ :
+ :static void
+ :DRILockTree(ScreenPtr pScreen)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : if(!pDRIPriv) return;
+ :
+ : /* Restore the last known 3D context if the X context is hidden */
+ : if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
+ : (*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
+ : DRI_2D_SYNC,
+ : DRI_NO_CONTEXT,
+ : NULL,
+ : DRI_2D_CONTEXT,
+ : pDRIPriv->partial3DContextStore);
+ : }
+ :
+ : /* Call kernel to release lock */
+ : DRIUnlock(pScreen);
+ :
+ : /* Grab drawable spin lock: a time out between 10 and 30 seconds is
+ : appropriate, since this should never time out except in the case of
+ : client death while the lock is being held. The timeout must be
+ : greater than any reasonable rendering time. */
+ : DRISpinLockTimeout(&pDRIPriv->pSAREA->drawable_lock, 1, 10000); /*10 secs*/
+ :
+ : /* Call kernel flush outstanding buffers and relock */
+ : DRILock(pScreen, DRM_LOCK_QUIESCENT|DRM_LOCK_FLUSH_ALL);
+ :
+ : /* Switch back to our 2D context if the X context is hidden */
+ : if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
+ : /* hide X context by swapping 2D component here */
+ : (*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
+ : DRI_3D_SYNC,
+ : DRI_2D_CONTEXT,
+ : pDRIPriv->partial3DContextStore,
+ : DRI_2D_CONTEXT,
+ : pDRIPriv->hiddenContextStore);
+ : }
+ :}
+ :
+ :int
+ :DRIValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind)
+ :{
+ : ScreenPtr pScreen = pParent->drawable.pScreen;
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : int returnValue = 1; /* always return 1, not checked by dix/window.c */
+ :
+ : if(!pDRIPriv) return returnValue;
+ :
+ : /* call lower wrapped functions */
+ : if(pDRIPriv->wrap.ValidateTree) {
+ : /* unwrap */
+ : pScreen->ValidateTree = pDRIPriv->wrap.ValidateTree;
+ :
+ : /* call lower layers */
+ : returnValue = (*pScreen->ValidateTree)(pParent, pChild, kind);
+ :
+ : /* rewrap */
+ : pDRIPriv->wrap.ValidateTree = pScreen->ValidateTree;
+ : pScreen->ValidateTree = DRIValidateTree;
+ : }
+ :
+ : return returnValue;
+ :}
+ :
+ :void
+ :DRIPostValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind)
+ :{
+ : ScreenPtr pScreen;
+ : DRIScreenPrivPtr pDRIPriv;
+ :
+ : if (pParent) {
+ : pScreen = pParent->drawable.pScreen;
+ : } else {
+ : pScreen = pChild->drawable.pScreen;
+ : }
+ : if(!(pDRIPriv = DRI_SCREEN_PRIV(pScreen))) return;
+ :
+ : if (pDRIPriv->wrap.PostValidateTree) {
+ : /* unwrap */
+ : pScreen->PostValidateTree = pDRIPriv->wrap.PostValidateTree;
+ :
+ : /* call lower layers */
+ : (*pScreen->PostValidateTree)(pParent, pChild, kind);
+ :
+ : /* rewrap */
+ : pDRIPriv->wrap.PostValidateTree = pScreen->PostValidateTree;
+ : pScreen->PostValidateTree = DRIPostValidateTree;
+ : }
+ :}
+ :
+ :void
+ :DRIClipNotify(WindowPtr pWin, int dx, int dy)
+ :{
+ : ScreenPtr pScreen = pWin->drawable.pScreen;
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ : DRIDrawablePrivPtr pDRIDrawablePriv;
+ :
+ : if(!pDRIPriv) return;
+ :
+ : if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) {
+ : int nrects = REGION_NUM_RECTS(&pWin->clipList);
+ :
+ : if(!pDRIPriv->windowsTouched) {
+ : DRILockTree(pScreen);
+ : pDRIPriv->windowsTouched = TRUE;
+ : }
+ :
+ : if (nrects && !pDRIDrawablePriv->nrects)
+ : DRIIncreaseNumberVisible(pScreen);
+ : else if (!nrects && pDRIDrawablePriv->nrects)
+ : DRIDecreaseNumberVisible(pScreen);
+ : else
+ : DRIDriverClipNotify(pScreen);
+ :
+ : pDRIDrawablePriv->nrects = nrects;
+ :
+ : pDRIPriv->pSAREA->drawableTable[pDRIDrawablePriv->drawableIndex].stamp
+ : = DRIDrawableValidationStamp++;
+ :
+ : drmUpdateDrawableInfo(pDRIPriv->drmFD, pDRIDrawablePriv->hwDrawable,
+ : DRM_DRAWABLE_CLIPRECTS,
+ : nrects, REGION_RECTS(&pWin->clipList));
+ : }
+ :
+ : /* call lower wrapped functions */
+ : if(pDRIPriv->wrap.ClipNotify) {
+ :
+ : /* unwrap */
+ : pScreen->ClipNotify = pDRIPriv->wrap.ClipNotify;
+ :
+ : /* call lower layers */
+ : (*pScreen->ClipNotify)(pWin, dx, dy);
+ :
+ : /* rewrap */
+ : pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify;
+ : pScreen->ClipNotify = DRIClipNotify;
+ : }
+ :}
+ :
+ :CARD32
+ :DRIGetDrawableIndex(WindowPtr pWin)
+ :{
+ : ScreenPtr pScreen = pWin->drawable.pScreen;
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ : DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
+ : CARD32 index;
+ :
+ : if (pDRIDrawablePriv) {
+ : index = pDRIDrawablePriv->drawableIndex;
+ : }
+ : else {
+ : index = pDRIPriv->pDriverInfo->ddxDrawableTableEntry;
+ : }
+ :
+ : return index;
+ :}
+ :
+ :unsigned int
+ :DRIGetDrawableStamp(ScreenPtr pScreen, CARD32 drawable_index)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ : return pDRIPriv->pSAREA->drawableTable[drawable_index].stamp;
+ :}
+ :
+ :
+ :void
+ :DRIPrintDrawableLock(ScreenPtr pScreen, char *msg)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : ErrorF("%s: %d\n", msg, pDRIPriv->pSAREA->drawable_lock.lock);
+ :}
+ :
+ :void
+ :DRILock(ScreenPtr pScreen, int flags)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : if(!pDRIPriv || !pDRIPriv->pLockRefCount) return;
+ :
+ : if (!*pDRIPriv->pLockRefCount) {
+ : DRM_LOCK(pDRIPriv->drmFD, pDRIPriv->pLSAREA, pDRIPriv->myContext, flags);
+ : *pDRIPriv->pLockingContext = pDRIPriv->myContext;
+ : } else if (*pDRIPriv->pLockingContext != pDRIPriv->myContext) {
+ : DRIDrvMsg(pScreen->myNum, X_ERROR,
+ : "[DRI] Locking deadlock.\n"
+ : "\tAlready locked with context %d,\n"
+ : "\ttrying to lock with context %d.\n",
+ : pDRIPriv->pLockingContext,
+ : pDRIPriv->myContext);
+ : }
+ : (*pDRIPriv->pLockRefCount)++;
+ :}
+ :
+ :void
+ :DRIUnlock(ScreenPtr pScreen)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : if(!pDRIPriv || !pDRIPriv->pLockRefCount) return;
+ :
+ : if (*pDRIPriv->pLockRefCount > 0) {
+ : if (pDRIPriv->myContext != *pDRIPriv->pLockingContext) {
+ : DRIDrvMsg(pScreen->myNum, X_ERROR,
+ : "[DRI] Unlocking inconsistency:\n"
+ : "\tContext %d trying to unlock lock held by context %d\n",
+ : pDRIPriv->pLockingContext,
+ : pDRIPriv->myContext);
+ : }
+ : (*pDRIPriv->pLockRefCount)--;
+ : } else {
+ : DRIDrvMsg(pScreen->myNum, X_ERROR,
+ : "DRIUnlock called when not locked.\n");
+ : return;
+ : }
+ : if (! *pDRIPriv->pLockRefCount)
+ : DRM_UNLOCK(pDRIPriv->drmFD, pDRIPriv->pLSAREA, pDRIPriv->myContext);
+ :}
+ :
+ :void *
+ :DRIGetSAREAPrivate(ScreenPtr pScreen)
+ 6 0.0065 :{ /* DRIGetSAREAPrivate total: 25 0.0272 */
+ 4 0.0044 : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ 2 0.0022 : if (!pDRIPriv) return 0;
+ :
+ 1 0.0011 : return (void *)(((char*)pDRIPriv->pSAREA)+sizeof(XF86DRISAREARec));
+ 12 0.0131 :}
+ :
+ :drm_context_t
+ :DRIGetContext(ScreenPtr pScreen)
+ 8 0.0087 :{ /* DRIGetContext total: 16 0.0174 */
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ 1 0.0011 : if (!pDRIPriv) return 0;
+ :
+ : return pDRIPriv->myContext;
+ 7 0.0076 :}
+ :
+ :void
+ :DRIGetTexOffsetFuncs(ScreenPtr pScreen,
+ : DRITexOffsetStartProcPtr *texOffsetStartFunc,
+ : DRITexOffsetFinishProcPtr *texOffsetFinishFunc)
+ :{
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ :
+ : if (!pDRIPriv) return;
+ :
+ : *texOffsetStartFunc = pDRIPriv->pDriverInfo->texOffsetStart;
+ : *texOffsetFinishFunc = pDRIPriv->pDriverInfo->texOffsetFinish;
+ :}
+ :
+ :/* This lets get at the unwrapped functions so that they can correctly
+ : * call the lowerlevel functions, and choose whether they will be
+ : * called at every level of recursion (eg in validatetree).
+ : */
+ :DRIWrappedFuncsRec *
+ :DRIGetWrappedFuncs(ScreenPtr pScreen)
+ :{
+ : return &(DRI_SCREEN_PRIV(pScreen)->wrap);
+ :}
+ :
+ :/* note that this returns the library version, not the protocol version */
+ :void
+ :DRIQueryVersion(int *majorVersion,
+ : int *minorVersion,
+ : int *patchVersion)
+ :{
+ : *majorVersion = DRIINFO_MAJOR_VERSION;
+ : *minorVersion = DRIINFO_MINOR_VERSION;
+ : *patchVersion = DRIINFO_PATCH_VERSION;
+ :}
+ :
+ :static void
+ :_DRIAdjustFrame(ScrnInfoPtr pScrn, DRIScreenPrivPtr pDRIPriv, int x, int y)
+ :{
+ : pDRIPriv->pSAREA->frame.x = x;
+ : pDRIPriv->pSAREA->frame.y = y;
+ : pDRIPriv->pSAREA->frame.width = pScrn->frameX1 - x + 1;
+ : pDRIPriv->pSAREA->frame.height = pScrn->frameY1 - y + 1;
+ :}
+ :
+ :void
+ :DRIAdjustFrame(int scrnIndex, int x, int y, int flags)
+ :{
+ : ScreenPtr pScreen = screenInfo.screens[scrnIndex];
+ : DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
+ : ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ : int px, py;
+ :
+ : if (!pDRIPriv || !pDRIPriv->pSAREA) {
+ : DRIDrvMsg(scrnIndex, X_ERROR, "[DRI] No SAREA (%p %p)\n",
+ : pDRIPriv, pDRIPriv ? pDRIPriv->pSAREA : NULL);
+ : return;
+ : }
+ :
+ : if (pDRIPriv->fullscreen) {
+ : /* Fix up frame */
+ : pScrn->frameX0 = pDRIPriv->pSAREA->frame.x;
+ : pScrn->frameY0 = pDRIPriv->pSAREA->frame.y;
+ : pScrn->frameX1 = pScrn->frameX0 + pDRIPriv->pSAREA->frame.width - 1;
+ : pScrn->frameY1 = pScrn->frameY0 + pDRIPriv->pSAREA->frame.height - 1;
+ :
+ : /* Fix up cursor */
+ : miPointerPosition(&px, &py);
+ : if (px < pScrn->frameX0) px = pScrn->frameX0;
+ : if (px > pScrn->frameX1) px = pScrn->frameX1;
+ : if (py < pScrn->frameY0) py = pScrn->frameY0;
+ : if (py > pScrn->frameY1) py = pScrn->frameY1;
+ : pScreen->SetCursorPosition(pScreen, px, py, TRUE);
+ : return;
+ : }
+ :
+ : if (pDRIPriv->wrap.AdjustFrame) {
+ : /* unwrap */
+ : pScrn->AdjustFrame = pDRIPriv->wrap.AdjustFrame;
+ : /* call lower layers */
+ : (*pScrn->AdjustFrame)(scrnIndex, x, y, flags);
+ : /* rewrap */
+ : pDRIPriv->wrap.AdjustFrame = pScrn->AdjustFrame;
+ : pScrn->AdjustFrame = DRIAdjustFrame;
+ : }
+ :
+ : _DRIAdjustFrame(pScrn, pDRIPriv, x, y);
+ :}
+ :
+ :/*
+ : * DRIMoveBuffersHelper swaps the regions rects in place leaving you
+ : * a region with the rects in the order that you need to blit them,
+ : * but it is possibly (likely) an invalid region afterwards. If you
+ : * need to use the region again for anything you have to call
+ : * REGION_VALIDATE on it, or better yet, save a copy first.
+ : */
+ :
+ :void
+ :DRIMoveBuffersHelper(
+ : ScreenPtr pScreen,
+ : int dx,
+ : int dy,
+ : int *xdir,
+ : int *ydir,
+ : RegionPtr reg
+ :)
+ :{
+ : BoxPtr extents, pbox, firstBox, lastBox;
+ : BoxRec tmpBox;
+ : int y, nbox;
+ :
+ : extents = REGION_EXTENTS(pScreen, reg);
+ : nbox = REGION_NUM_RECTS(reg);
+ : pbox = REGION_RECTS(reg);
+ :
+ : if((dy > 0) && (dy < (extents->y2 - extents->y1))) {
+ : *ydir = -1;
+ : if(nbox > 1) {
+ : firstBox = pbox;
+ : lastBox = pbox + nbox - 1;
+ : while((unsigned long)firstBox < (unsigned long)lastBox) {
+ : tmpBox = *firstBox;
+ : *firstBox = *lastBox;
+ : *lastBox = tmpBox;
+ : firstBox++;
+ : lastBox--;
+ : }
+ : }
+ : } else *ydir = 1;
+ :
+ : if((dx > 0) && (dx < (extents->x2 - extents->x1))) {
+ : *xdir = -1;
+ : if(nbox > 1) {
+ : firstBox = lastBox = pbox;
+ : y = pbox->y1;
+ : while(--nbox) {
+ : pbox++;
+ : if(pbox->y1 == y) lastBox++;
+ : else {
+ : while((unsigned long)firstBox < (unsigned long)lastBox) {
+ : tmpBox = *firstBox;
+ : *firstBox = *lastBox;
+ : *lastBox = tmpBox;
+ : firstBox++;
+ : lastBox--;
+ : }
+ :
+ : firstBox = lastBox = pbox;
+ : y = pbox->y1;
+ : }
+ : }
+ : while((unsigned long)firstBox < (unsigned long)lastBox) {
+ : tmpBox = *firstBox;
+ : *firstBox = *lastBox;
+ : *lastBox = tmpBox;
+ : firstBox++;
+ : lastBox--;
+ : }
+ : }
+ : } else *xdir = 1;
+ :
+ :}
+ :
+ :char *
+ :DRICreatePCIBusID(pciVideoPtr PciInfo)
+ :{
+ : char *busID;
+ : int domain;
+ : PCITAG tag;
+ :
+ : busID = xalloc(20);
+ : if (busID == NULL)
+ : return NULL;
+ :
+ : tag = pciTag(PciInfo->bus, PciInfo->device, PciInfo->func);
+ : domain = xf86GetPciDomain(tag);
+ : snprintf(busID, 20, "pci:%04x:%02x:%02x.%d", domain,
+ : PCI_BUS_NO_DOMAIN(PciInfo->bus), PciInfo->device, PciInfo->func);
+ : return busID;
+ :}
+ :
+ :static void drmSIGIOHandler(int interrupt, void *closure)
+ :{
+ : unsigned long key;
+ : void *value;
+ : ssize_t count;
+ : drm_ctx_t ctx;
+ : typedef void (*_drmCallback)(int, void *, void *);
+ : char buf[256];
+ : drm_context_t old;
+ : drm_context_t new;
+ : void *oldctx;
+ : void *newctx;
+ : char *pt;
+ : drmHashEntry *entry;
+ : void *hash_table;
+ :
+ : hash_table = drmGetHashTable();
+ :
+ : if (!hash_table) return;
+ : if (drmHashFirst(hash_table, &key, &value)) {
+ : entry = value;
+ : do {
+ :#if 0
+ : fprintf(stderr, "Trying %d\n", entry->fd);
+ :#endif
+ : if ((count = read(entry->fd, buf, sizeof(buf))) > 0) {
+ : buf[count] = '\0';
+ :#if 0
+ : fprintf(stderr, "Got %s\n", buf);
+ :#endif
+ :
+ : for (pt = buf; *pt != ' '; ++pt); /* Find first space */
+ : ++pt;
+ : old = strtol(pt, &pt, 0);
+ : new = strtol(pt, NULL, 0);
+ : oldctx = drmGetContextTag(entry->fd, old);
+ : newctx = drmGetContextTag(entry->fd, new);
+ :#if 0
+ : fprintf(stderr, "%d %d %p %p\n", old, new, oldctx, newctx);
+ :#endif
+ : ((_drmCallback)entry->f)(entry->fd, oldctx, newctx);
+ : ctx.handle = new;
+ : ioctl(entry->fd, DRM_IOCTL_NEW_CTX, &ctx);
+ : }
+ : } while (drmHashNext(hash_table, &key, &value));
+ : }
+ :}
+ :
+ :
+ :int drmInstallSIGIOHandler(int fd, void (*f)(int, void *, void *))
+ :{
+ : drmHashEntry *entry;
+ :
+ : entry = drmGetEntry(fd);
+ : entry->f = f;
+ :
+ : return xf86InstallSIGIOHandler(fd, drmSIGIOHandler, 0);
+ :}
+ :
+ :int drmRemoveSIGIOHandler(int fd)
+ :{
+ : drmHashEntry *entry = drmGetEntry(fd);
+ :
+ : entry->f = NULL;
+ :
+ : return xf86RemoveSIGIOHandler(fd);
+ :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/render/filter.c"
+ *
+ * 34 0.0370
+ */
+
+
+ :/*
+ : * Copyright © 2002 Keith Packard
+ : *
+ : * 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 Keith Packard not be used in
+ : * advertising or publicity pertaining to distribution of the software without
+ : * specific, written prior permission. Keith Packard makes no
+ : * representations about the suitability of this software for any purpose. It
+ : * is provided "as is" without express or implied warranty.
+ : *
+ : * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ : * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ : * EVENT SHALL KEITH PACKARD 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.
+ : */
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include "misc.h"
+ :#include "scrnintstr.h"
+ :#include "os.h"
+ :#include "regionstr.h"
+ :#include "validate.h"
+ :#include "windowstr.h"
+ :#include "input.h"
+ :#include "resource.h"
+ :#include "colormapst.h"
+ :#include "cursorstr.h"
+ :#include "dixstruct.h"
+ :#include "gcstruct.h"
+ :#include "servermd.h"
+ :#include "picturestr.h"
+ :
+ :static char **filterNames;
+ :static int nfilterNames;
+ :
+ :/*
+ : * standard but not required filters don't have constant indices
+ : */
+ :
+ :int
+ :PictureGetFilterId (char *filter, int len, Bool makeit)
+ 3 0.0033 :{ /* PictureGetFilterId total: 16 0.0174 */
+ : int i;
+ : char *name;
+ : char **names;
+ :
+ : if (len < 0)
+ 7 0.0076 : len = strlen (filter);
+ : for (i = 0; i < nfilterNames; i++)
+ 6 0.0065 : if (!CompareISOLatin1Lowered ((unsigned char *) filterNames[i], -1, (unsigned char *) filter, len))
+ : return i;
+ : if (!makeit)
+ : return -1;
+ : name = xalloc (len + 1);
+ : if (!name)
+ : return -1;
+ : memcpy (name, filter, len);
+ : name[len] = '\0';
+ : if (filterNames)
+ : names = xrealloc (filterNames, (nfilterNames + 1) * sizeof (char *));
+ : else
+ : names = xalloc (sizeof (char *));
+ : if (!names)
+ : {
+ : xfree (name);
+ : return -1;
+ : }
+ : filterNames = names;
+ : i = nfilterNames++;
+ : filterNames[i] = name;
+ : return i;
+ :}
+ :
+ :static Bool
+ :PictureSetDefaultIds (void)
+ :{
+ : /* careful here -- this list must match the #define values */
+ :
+ : if (PictureGetFilterId (FilterNearest, -1, TRUE) != PictFilterNearest)
+ : return FALSE;
+ : if (PictureGetFilterId (FilterBilinear, -1, TRUE) != PictFilterBilinear)
+ : return FALSE;
+ :
+ : if (PictureGetFilterId (FilterFast, -1, TRUE) != PictFilterFast)
+ : return FALSE;
+ : if (PictureGetFilterId (FilterGood, -1, TRUE) != PictFilterGood)
+ : return FALSE;
+ : if (PictureGetFilterId (FilterBest, -1, TRUE) != PictFilterBest)
+ : return FALSE;
+ :
+ : if (PictureGetFilterId (FilterConvolution, -1, TRUE) != PictFilterConvolution)
+ : return FALSE;
+ : return TRUE;
+ :}
+ :
+ :char *
+ :PictureGetFilterName (int id)
+ :{
+ : if (0 <= id && id < nfilterNames)
+ : return filterNames[id];
+ : else
+ : return 0;
+ :}
+ :
+ :static void
+ :PictureFreeFilterIds (void)
+ :{
+ : int i;
+ :
+ : for (i = 0; i < nfilterNames; i++)
+ : xfree (filterNames[i]);
+ : xfree (filterNames);
+ : nfilterNames = 0;
+ : filterNames = 0;
+ :}
+ :
+ :_X_EXPORT int
+ :PictureAddFilter (ScreenPtr pScreen,
+ : char *filter,
+ : PictFilterValidateParamsProcPtr ValidateParams)
+ :{
+ : PictureScreenPtr ps = GetPictureScreen(pScreen);
+ : int id = PictureGetFilterId (filter, -1, TRUE);
+ : int i;
+ : PictFilterPtr filters;
+ :
+ : if (id < 0)
+ : return -1;
+ : /*
+ : * It's an error to attempt to reregister a filter
+ : */
+ : for (i = 0; i < ps->nfilters; i++)
+ : if (ps->filters[i].id == id)
+ : return -1;
+ : if (ps->filters)
+ : filters = xrealloc (ps->filters, (ps->nfilters + 1) * sizeof (PictFilterRec));
+ : else
+ : filters = xalloc (sizeof (PictFilterRec));
+ : if (!filters)
+ : return -1;
+ : ps->filters = filters;
+ : i = ps->nfilters++;
+ : ps->filters[i].name = PictureGetFilterName (id);
+ : ps->filters[i].id = id;
+ : ps->filters[i].ValidateParams = ValidateParams;
+ : return id;
+ :}
+ :
+ :_X_EXPORT Bool
+ :PictureSetFilterAlias (ScreenPtr pScreen, char *filter, char *alias)
+ :{
+ : PictureScreenPtr ps = GetPictureScreen(pScreen);
+ : int filter_id = PictureGetFilterId (filter, -1, FALSE);
+ : int alias_id = PictureGetFilterId (alias, -1, TRUE);
+ : int i;
+ :
+ : if (filter_id < 0 || alias_id < 0)
+ : return FALSE;
+ : for (i = 0; i < ps->nfilterAliases; i++)
+ : if (ps->filterAliases[i].alias_id == alias_id)
+ : break;
+ : if (i == ps->nfilterAliases)
+ : {
+ : PictFilterAliasPtr aliases;
+ :
+ : if (ps->filterAliases)
+ : aliases = xrealloc (ps->filterAliases,
+ : (ps->nfilterAliases + 1) *
+ : sizeof (PictFilterAliasRec));
+ : else
+ : aliases = xalloc (sizeof (PictFilterAliasRec));
+ : if (!aliases)
+ : return FALSE;
+ : ps->filterAliases = aliases;
+ : ps->filterAliases[i].alias = PictureGetFilterName (alias_id);
+ : ps->filterAliases[i].alias_id = alias_id;
+ : ps->nfilterAliases++;
+ : }
+ : ps->filterAliases[i].filter_id = filter_id;
+ : return TRUE;
+ :}
+ :
+ :PictFilterPtr
+ :PictureFindFilter (ScreenPtr pScreen, char *name, int len)
+ 2 0.0022 :{ /* PictureFindFilter total: 8 0.0087 */
+ 1 0.0011 : PictureScreenPtr ps = GetPictureScreen(pScreen);
+ : int id = PictureGetFilterId (name, len, FALSE);
+ : int i;
+ :
+ : if (id < 0)
+ : return 0;
+ : /* Check for an alias, allow them to recurse */
+ : for (i = 0; i < ps->nfilterAliases; i++)
+ 4 0.0044 : if (ps->filterAliases[i].alias_id == id)
+ : {
+ : id = ps->filterAliases[i].filter_id;
+ : i = 0;
+ : }
+ : /* find the filter */
+ : for (i = 0; i < ps->nfilters; i++)
+ : if (ps->filters[i].id == id)
+ : return &ps->filters[i];
+ : return 0;
+ 1 0.0011 :}
+ :
+ :static Bool
+ :convolutionFilterValidateParams (PicturePtr pPicture,
+ : int filter,
+ : xFixed *params,
+ : int nparams)
+ :{
+ : if (nparams < 3)
+ : return FALSE;
+ :
+ : if (xFixedFrac (params[0]) || xFixedFrac (params[1]))
+ : return FALSE;
+ :
+ : nparams -= 2;
+ : if ((xFixedToInt (params[0]) * xFixedToInt (params[1])) > nparams)
+ : return FALSE;
+ :
+ : return TRUE;
+ :}
+ :
+ :
+ :Bool
+ :PictureSetDefaultFilters (ScreenPtr pScreen)
+ :{
+ : if (!filterNames)
+ : if (!PictureSetDefaultIds ())
+ : return FALSE;
+ : if (PictureAddFilter (pScreen, FilterNearest, 0) < 0)
+ : return FALSE;
+ : if (PictureAddFilter (pScreen, FilterBilinear, 0) < 0)
+ : return FALSE;
+ :
+ : if (!PictureSetFilterAlias (pScreen, FilterNearest, FilterFast))
+ : return FALSE;
+ : if (!PictureSetFilterAlias (pScreen, FilterBilinear, FilterGood))
+ : return FALSE;
+ : if (!PictureSetFilterAlias (pScreen, FilterBilinear, FilterBest))
+ : return FALSE;
+ :
+ : if (PictureAddFilter (pScreen, FilterConvolution, convolutionFilterValidateParams) < 0)
+ : return FALSE;
+ :
+ : return TRUE;
+ :}
+ :
+ :void
+ :PictureResetFilters (ScreenPtr pScreen)
+ :{
+ : PictureScreenPtr ps = GetPictureScreen(pScreen);
+ :
+ : xfree (ps->filters);
+ : xfree (ps->filterAliases);
+ : PictureFreeFilterIds ();
+ :}
+ :
+ :int
+ :SetPictureFilter (PicturePtr pPicture, char *name, int len, xFixed *params, int nparams)
+ :{ /* SetPictureFilter total: 10 0.0109 */
+ : PictFilterPtr pFilter;
+ : xFixed *new_params;
+ : int i, s, result;
+ :
+ 3 0.0033 : pFilter = PictureFindFilter (screenInfo.screens[0], name, len);
+ :
+ : if (pPicture->pDrawable == NULL) {
+ : /* For source pictures, the picture isn't tied to a screen. So, ensure
+ : * that all screens can handle a filter we set for the picture.
+ : */
+ : for (s = 0; s < screenInfo.numScreens; s++) {
+ : if (PictureFindFilter (screenInfo.screens[s], name, len)->id !=
+ : pFilter->id)
+ : {
+ : return BadMatch;
+ : }
+ : }
+ : }
+ :
+ : if (!pFilter)
+ : return BadName;
+ : if (pFilter->ValidateParams)
+ : {
+ : if (!(*pFilter->ValidateParams) (pPicture, pFilter->id, params, nparams))
+ : return BadMatch;
+ : }
+ : else if (nparams)
+ : return BadMatch;
+ :
+ 5 0.0054 : if (nparams != pPicture->filter_nparams)
+ : {
+ : new_params = xalloc (nparams * sizeof (xFixed));
+ : if (!new_params)
+ : return BadAlloc;
+ : xfree (pPicture->filter_params);
+ : pPicture->filter_params = new_params;
+ : pPicture->filter_nparams = nparams;
+ : }
+ : for (i = 0; i < nparams; i++)
+ : pPicture->filter_params[i] = params[i];
+ : pPicture->filter = pFilter->id;
+ :
+ : if (pPicture->pDrawable) {
+ : ScreenPtr pScreen = pPicture->pDrawable->pScreen;
+ : PictureScreenPtr ps = GetPictureScreen(pScreen);
+ :
+ 1 0.0011 : result = (*ps->ChangePictureFilter) (pPicture, pPicture->filter,
+ : params, nparams);
+ : return result;
+ : }
+ : return Success;
+ 1 0.0011 :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/fb/fbgc.c"
+ *
+ * 34 0.0370
+ */
+
+
+ :/*
+ : * Copyright © 1998 Keith Packard
+ : *
+ : * 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 Keith Packard not be used in
+ : * advertising or publicity pertaining to distribution of the software without
+ : * specific, written prior permission. Keith Packard makes no
+ : * representations about the suitability of this software for any purpose. It
+ : * is provided "as is" without express or implied warranty.
+ : *
+ : * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ : * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ : * EVENT SHALL KEITH PACKARD 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.
+ : */
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include <stdlib.h>
+ :
+ :#include "fb.h"
+ :
+ :const GCFuncs fbGCFuncs = {
+ : fbValidateGC,
+ : miChangeGC,
+ : miCopyGC,
+ : miDestroyGC,
+ : miChangeClip,
+ : miDestroyClip,
+ : miCopyClip,
+ :};
+ :
+ :const GCOps fbGCOps = {
+ : fbFillSpans,
+ : fbSetSpans,
+ : fbPutImage,
+ : fbCopyArea,
+ : fbCopyPlane,
+ : fbPolyPoint,
+ : fbPolyLine,
+ : fbPolySegment,
+ : fbPolyRectangle,
+ : fbPolyArc,
+ : miFillPolygon,
+ : fbPolyFillRect,
+ : fbPolyFillArc,
+ : miPolyText8,
+ : miPolyText16,
+ : miImageText8,
+ : miImageText16,
+ : fbImageGlyphBlt,
+ : fbPolyGlyphBlt,
+ : fbPushPixels
+ :};
+ :
+ :Bool
+ :fbCreateGC(GCPtr pGC)
+ :{
+ : pGC->clientClip = NULL;
+ : pGC->clientClipType = CT_NONE;
+ :
+ : pGC->ops = (GCOps *) &fbGCOps;
+ : pGC->funcs = (GCFuncs *) &fbGCFuncs;
+ :
+ : /* fb wants to translate before scan conversion */
+ : pGC->miTranslate = 1;
+ :
+ : fbGetRotatedPixmap(pGC) = 0;
+ : fbGetExpose(pGC) = 1;
+ : fbGetFreeCompClip(pGC) = 0;
+ : fbGetCompositeClip(pGC) = 0;
+ : fbGetGCPrivate(pGC)->bpp = BitsPerPixel (pGC->depth);
+ : return TRUE;
+ :}
+ :
+ :/*
+ : * Pad pixmap to FB_UNIT bits wide
+ : */
+ :void
+ :fbPadPixmap (PixmapPtr pPixmap)
+ :{
+ : int width;
+ : FbBits *bits;
+ : FbBits b;
+ : FbBits mask;
+ : int height;
+ : int w;
+ : int stride;
+ : int bpp;
+ : int xOff, yOff;
+ :
+ : fbGetDrawable (&pPixmap->drawable, bits, stride, bpp, xOff, yOff);
+ :
+ : width = pPixmap->drawable.width * pPixmap->drawable.bitsPerPixel;
+ : height = pPixmap->drawable.height;
+ : mask = FbBitsMask (0, width);
+ : while (height--)
+ : {
+ : b = READ(bits) & mask;
+ : w = width;
+ : while (w < FB_UNIT)
+ : {
+ : b = b | FbScrRight(b, w);
+ : w <<= 1;
+ : }
+ : WRITE(bits, b);
+ : bits += stride;
+ : }
+ :
+ : fbFinishAccess (&pPixmap->drawable);
+ :}
+ :
+ :/*
+ : * Verify that 'bits' repeats every 'len' bits
+ : */
+ :static Bool
+ :fbBitsRepeat (FbBits bits, int len, int width)
+ :{
+ : FbBits mask = FbBitsMask(0, len);
+ : FbBits orig = bits & mask;
+ : int i;
+ :
+ : if (width > FB_UNIT)
+ : width = FB_UNIT;
+ : for (i = 0; i < width / len; i++)
+ : {
+ : if ((bits & mask) != orig)
+ : return FALSE;
+ : bits = FbScrLeft(bits,len);
+ : }
+ : return TRUE;
+ :}
+ :
+ :/*
+ : * Check whether an entire bitmap line is a repetition of
+ : * the first 'len' bits
+ : */
+ :static Bool
+ :fbLineRepeat (FbBits *bits, int len, int width)
+ :{
+ : FbBits first = bits[0];
+ :
+ : if (!fbBitsRepeat (first, len, width))
+ : return FALSE;
+ : width = (width + FB_UNIT-1) >> FB_SHIFT;
+ : bits++;
+ : while (--width)
+ : if (READ(bits) != first)
+ : return FALSE;
+ : return TRUE;
+ :}
+ :
+ :/*
+ : * The even stipple code wants the first FB_UNIT/bpp bits on
+ : * each scanline to represent the entire stipple
+ : */
+ :static Bool
+ :fbCanEvenStipple (PixmapPtr pStipple, int bpp)
+ :{
+ : int len = FB_UNIT / bpp;
+ : FbBits *bits;
+ : int stride;
+ : int stip_bpp;
+ : int stipXoff, stipYoff;
+ : int h;
+ :
+ : /* can't even stipple 24bpp drawables */
+ : if ((bpp & (bpp-1)) != 0)
+ : return FALSE;
+ : /* make sure the stipple width is a multiple of the even stipple width */
+ : if (pStipple->drawable.width % len != 0)
+ : return FALSE;
+ : fbGetDrawable (&pStipple->drawable, bits, stride, stip_bpp, stipXoff, stipYoff);
+ : h = pStipple->drawable.height;
+ : /* check to see that the stipple repeats horizontally */
+ : while (h--)
+ : {
+ : if (!fbLineRepeat (bits, len, pStipple->drawable.width)) {
+ : fbFinishAccess (&pStipple->drawable);
+ : return FALSE;
+ : }
+ : bits += stride;
+ : }
+ : fbFinishAccess (&pStipple->drawable);
+ : return TRUE;
+ :}
+ :
+ :void
+ :fbValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
+ 2 0.0022 :{ /* fbValidateGC total: 34 0.0370 */
+ : FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
+ : FbBits mask;
+ :
+ 1 0.0011 : pGC->lastWinOrg.x = pDrawable->x;
+ : pGC->lastWinOrg.y = pDrawable->y;
+ :
+ : /*
+ : * if the client clip is different or moved OR the subwindowMode has
+ : * changed OR the window's clip has changed since the last validation
+ : * we need to recompute the composite clip
+ : */
+ :
+ : if ((changes & (GCClipXOrigin|GCClipYOrigin|GCClipMask|GCSubwindowMode)) ||
+ : (pDrawable->serialNumber != (pGC->serialNumber & DRAWABLE_SERIAL_BITS))
+ : )
+ : {
+ : miComputeCompositeClip (pGC, pDrawable);
+ 1 0.0011 : pPriv->oneRect = REGION_NUM_RECTS(fbGetCompositeClip(pGC)) == 1;
+ : }
+ :
+ :#ifdef FB_24_32BIT
+ : if (pPriv->bpp != pDrawable->bitsPerPixel)
+ : {
+ : changes |= GCStipple|GCForeground|GCBackground|GCPlaneMask;
+ : pPriv->bpp = pDrawable->bitsPerPixel;
+ : }
+ : if ((changes & GCTile) && fbGetRotatedPixmap(pGC))
+ : {
+ : (*pGC->pScreen->DestroyPixmap) (fbGetRotatedPixmap(pGC));
+ : fbGetRotatedPixmap(pGC) = 0;
+ : }
+ :
+ : if (pGC->fillStyle == FillTiled)
+ : {
+ : PixmapPtr pOldTile, pNewTile;
+ :
+ : pOldTile = pGC->tile.pixmap;
+ : if (pOldTile->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
+ : {
+ : pNewTile = fbGetRotatedPixmap(pGC);
+ : if (!pNewTile || pNewTile ->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
+ : {
+ : if (pNewTile)
+ : (*pGC->pScreen->DestroyPixmap) (pNewTile);
+ : pNewTile = fb24_32ReformatTile (pOldTile, pDrawable->bitsPerPixel);
+ : }
+ : if (pNewTile)
+ : {
+ : fbGetRotatedPixmap(pGC) = pOldTile;
+ : pGC->tile.pixmap = pNewTile;
+ : changes |= GCTile;
+ : }
+ : }
+ : }
+ :#endif
+ : if (changes & GCTile)
+ : {
+ : if (!pGC->tileIsPixel &&
+ : FbEvenTile (pGC->tile.pixmap->drawable.width *
+ : pDrawable->bitsPerPixel))
+ : fbPadPixmap (pGC->tile.pixmap);
+ : }
+ 1 0.0011 : if (changes & GCStipple)
+ : {
+ : pPriv->evenStipple = FALSE;
+ :
+ 3 0.0033 : if (pGC->stipple) {
+ :
+ : /* can we do an even stipple ?? */
+ : if (FbEvenStip (pGC->stipple->drawable.width,
+ : pDrawable->bitsPerPixel) &&
+ : (fbCanEvenStipple (pGC->stipple, pDrawable->bitsPerPixel)))
+ : pPriv->evenStipple = TRUE;
+ :
+ : if (pGC->stipple->drawable.width * pDrawable->bitsPerPixel < FB_UNIT)
+ : fbPadPixmap (pGC->stipple);
+ : }
+ : }
+ : /*
+ : * Recompute reduced rop values
+ : */
+ 3 0.0033 : if (changes & (GCForeground|GCBackground|GCPlaneMask|GCFunction))
+ : {
+ : int s;
+ : FbBits depthMask;
+ :
+ 3 0.0033 : mask = FbFullMask(pDrawable->bitsPerPixel);
+ 2 0.0022 : depthMask = FbFullMask(pDrawable->depth);
+ :
+ 1 0.0011 : pPriv->fg = pGC->fgPixel & mask;
+ 1 0.0011 : pPriv->bg = pGC->bgPixel & mask;
+ :
+ : if ((pGC->planemask & depthMask) == depthMask)
+ 2 0.0022 : pPriv->pm = mask;
+ : else
+ : pPriv->pm = pGC->planemask & mask;
+ :
+ 1 0.0011 : s = pDrawable->bitsPerPixel;
+ : while (s < FB_UNIT)
+ : {
+ : pPriv->fg |= pPriv->fg << s;
+ : pPriv->bg |= pPriv->bg << s;
+ : pPriv->pm |= pPriv->pm << s;
+ : s <<= 1;
+ : }
+ 7 0.0076 : pPriv->and = fbAnd(pGC->alu, pPriv->fg, pPriv->pm);
+ 1 0.0011 : pPriv->xor = fbXor(pGC->alu, pPriv->fg, pPriv->pm);
+ : pPriv->bgand = fbAnd(pGC->alu, pPriv->bg, pPriv->pm);
+ 3 0.0033 : pPriv->bgxor = fbXor(pGC->alu, pPriv->bg, pPriv->pm);
+ : }
+ : if (changes & GCDashList)
+ : {
+ : unsigned short n = pGC->numInDashList;
+ : unsigned char *dash = pGC->dash;
+ : unsigned int dashLength = 0;
+ :
+ : while (n--)
+ 1 0.0011 : dashLength += (unsigned int ) *dash++;
+ : pPriv->dashLength = dashLength;
+ : }
+ 1 0.0011 :}
+/*
+ * Total samples for file : "pixman-mmx.c"
+ *
+ * 33 0.0359
+ */
+
+<credited to line zero> 33 0.0359 :
+ /* __i686.get_pc_thunk.bx total: 15 0.0163 */
+ /* __divdi3 total: 18 0.0196 */
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/mi/migc.c"
+ *
+ * 31 0.0338
+ */
+
+
+ :/*
+ :
+ :Copyright 1993, 1998 The Open Group
+ :
+ :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.
+ :
+ :The above copyright notice and this permission notice shall be included
+ :in all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ :OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ :MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ :IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ :OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ :ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ :OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of The Open Group shall
+ :not be used in advertising or otherwise to promote the sale, use or
+ :other dealings in this Software without prior written authorization
+ :from The Open Group.
+ :
+ :*/
+ :
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include "scrnintstr.h"
+ :#include "gcstruct.h"
+ :#include "pixmapstr.h"
+ :#include "windowstr.h"
+ :#include "migc.h"
+ :
+ :/* ARGSUSED */
+ :_X_EXPORT void
+ :miChangeGC(pGC, mask)
+ : GCPtr pGC;
+ : unsigned long mask;
+ 6 0.0065 :{ /* miChangeGC total: 6 0.0065 */
+ : return;
+ :}
+ :
+ :_X_EXPORT void
+ :miDestroyGC(pGC)
+ : GCPtr pGC;
+ :{
+ : if (pGC->pRotatedPixmap)
+ : (*pGC->pScreen->DestroyPixmap) (pGC->pRotatedPixmap);
+ : if (pGC->freeCompClip)
+ : REGION_DESTROY(pGC->pScreen, pGC->pCompositeClip);
+ : miDestroyGCOps(pGC->ops);
+ :}
+ :
+ :/*
+ : * create a private op array for a gc
+ : */
+ :
+ :_X_EXPORT GCOpsPtr
+ :miCreateGCOps(prototype)
+ : GCOpsPtr prototype;
+ :{
+ : GCOpsPtr ret;
+ :
+ : /* XXX */ Must_have_memory = TRUE;
+ : ret = (GCOpsPtr) xalloc(sizeof(GCOps));
+ : /* XXX */ Must_have_memory = FALSE;
+ : if (!ret)
+ : return 0;
+ : *ret = *prototype;
+ : ret->devPrivate.val = 1;
+ : return ret;
+ :}
+ :
+ :_X_EXPORT void
+ :miDestroyGCOps(ops)
+ : GCOpsPtr ops;
+ :{
+ : if (ops->devPrivate.val)
+ : xfree(ops);
+ :}
+ :
+ :
+ :_X_EXPORT void
+ :miDestroyClip(pGC)
+ : GCPtr pGC;
+ 1 0.0011 :{ /* miDestroyClip total: 1 0.0011 */
+ : if (pGC->clientClipType == CT_NONE)
+ : return;
+ : else if (pGC->clientClipType == CT_PIXMAP)
+ : {
+ : (*pGC->pScreen->DestroyPixmap) ((PixmapPtr) (pGC->clientClip));
+ : }
+ : else
+ : {
+ : /*
+ : * we know we'll never have a list of rectangles, since ChangeClip
+ : * immediately turns them into a region
+ : */
+ : REGION_DESTROY(pGC->pScreen, pGC->clientClip);
+ : }
+ : pGC->clientClip = NULL;
+ : pGC->clientClipType = CT_NONE;
+ :}
+ :
+ :_X_EXPORT void
+ :miChangeClip(pGC, type, pvalue, nrects)
+ : GCPtr pGC;
+ : int type;
+ : pointer pvalue;
+ : int nrects;
+ 3 0.0033 :{ /* miChangeClip total: 4 0.0044 */
+ : (*pGC->funcs->DestroyClip) (pGC);
+ : if (type == CT_PIXMAP)
+ : {
+ : /* convert the pixmap to a region */
+ : pGC->clientClip = (pointer) BITMAP_TO_REGION(pGC->pScreen,
+ : (PixmapPtr) pvalue);
+ : (*pGC->pScreen->DestroyPixmap) (pvalue);
+ : }
+ : else if (type == CT_REGION)
+ : {
+ : /* stuff the region in the GC */
+ : pGC->clientClip = pvalue;
+ : }
+ 1 0.0011 : else if (type != CT_NONE)
+ : {
+ : pGC->clientClip = (pointer) RECTS_TO_REGION(pGC->pScreen, nrects,
+ : (xRectangle *) pvalue,
+ : type);
+ : xfree(pvalue);
+ : }
+ : pGC->clientClipType = (type != CT_NONE && pGC->clientClip) ? CT_REGION : CT_NONE;
+ : pGC->stateChanges |= GCClipMask;
+ :}
+ :
+ :_X_EXPORT void
+ :miCopyClip(pgcDst, pgcSrc)
+ : GCPtr pgcDst, pgcSrc;
+ :{
+ : RegionPtr prgnNew;
+ :
+ : switch (pgcSrc->clientClipType)
+ : {
+ : case CT_PIXMAP:
+ : ((PixmapPtr) pgcSrc->clientClip)->refcnt++;
+ : /* Fall through !! */
+ : case CT_NONE:
+ : (*pgcDst->funcs->ChangeClip) (pgcDst, (int) pgcSrc->clientClipType,
+ : pgcSrc->clientClip, 0);
+ : break;
+ : case CT_REGION:
+ : prgnNew = REGION_CREATE(pgcSrc->pScreen, NULL, 1);
+ : REGION_COPY(pgcDst->pScreen, prgnNew,
+ : (RegionPtr) (pgcSrc->clientClip));
+ : (*pgcDst->funcs->ChangeClip) (pgcDst, CT_REGION, (pointer) prgnNew, 0);
+ : break;
+ : }
+ :}
+ :
+ :/* ARGSUSED */
+ :_X_EXPORT void
+ :miCopyGC(pGCSrc, changes, pGCDst)
+ : GCPtr pGCSrc;
+ : unsigned long changes;
+ : GCPtr pGCDst;
+ :{
+ : return;
+ :}
+ :
+ :_X_EXPORT void
+ :miComputeCompositeClip(pGC, pDrawable)
+ : GCPtr pGC;
+ : DrawablePtr pDrawable;
+ 4 0.0044 :{ /* miComputeCompositeClip total: 20 0.0218 */
+ : ScreenPtr pScreen;
+ :
+ : /* This prevents warnings about pScreen not being used. */
+ : pGC->pScreen = pScreen = pGC->pScreen;
+ :
+ : if (pDrawable->type == DRAWABLE_WINDOW)
+ : {
+ : WindowPtr pWin = (WindowPtr) pDrawable;
+ : RegionPtr pregWin;
+ : Bool freeTmpClip, freeCompClip;
+ :
+ : if (pGC->subWindowMode == IncludeInferiors)
+ : {
+ : pregWin = NotClippedByChildren(pWin);
+ : freeTmpClip = TRUE;
+ : }
+ : else
+ : {
+ : pregWin = &pWin->clipList;
+ : freeTmpClip = FALSE;
+ : }
+ : freeCompClip = pGC->freeCompClip;
+ :
+ : /*
+ : * if there is no client clip, we can get by with just keeping the
+ : * pointer we got, and remembering whether or not should destroy (or
+ : * maybe re-use) it later. this way, we avoid unnecessary copying of
+ : * regions. (this wins especially if many clients clip by children
+ : * and have no client clip.)
+ : */
+ : if (pGC->clientClipType == CT_NONE)
+ : {
+ : if (freeCompClip)
+ : REGION_DESTROY(pScreen, pGC->pCompositeClip);
+ : pGC->pCompositeClip = pregWin;
+ : pGC->freeCompClip = freeTmpClip;
+ : }
+ : else
+ : {
+ : /*
+ : * we need one 'real' region to put into the composite clip. if
+ : * pregWin the current composite clip are real, we can get rid of
+ : * one. if pregWin is real and the current composite clip isn't,
+ : * use pregWin for the composite clip. if the current composite
+ : * clip is real and pregWin isn't, use the current composite
+ : * clip. if neither is real, create a new region.
+ : */
+ :
+ : REGION_TRANSLATE(pScreen, pGC->clientClip,
+ : pDrawable->x + pGC->clipOrg.x,
+ : pDrawable->y + pGC->clipOrg.y);
+ :
+ : if (freeCompClip)
+ : {
+ : REGION_INTERSECT(pGC->pScreen, pGC->pCompositeClip,
+ : pregWin, pGC->clientClip);
+ : if (freeTmpClip)
+ : REGION_DESTROY(pScreen, pregWin);
+ : }
+ : else if (freeTmpClip)
+ : {
+ : REGION_INTERSECT(pScreen, pregWin, pregWin, pGC->clientClip);
+ : pGC->pCompositeClip = pregWin;
+ : }
+ : else
+ : {
+ 1 0.0011 : pGC->pCompositeClip = REGION_CREATE(pScreen, NullBox, 0);
+ : REGION_INTERSECT(pScreen, pGC->pCompositeClip,
+ : pregWin, pGC->clientClip);
+ : }
+ : pGC->freeCompClip = TRUE;
+ : REGION_TRANSLATE(pScreen, pGC->clientClip,
+ : -(pDrawable->x + pGC->clipOrg.x),
+ : -(pDrawable->y + pGC->clipOrg.y));
+ : }
+ : } /* end of composite clip for a window */
+ : else
+ : {
+ : BoxRec pixbounds;
+ :
+ : /* XXX should we translate by drawable.x/y here ? */
+ : /* If you want pixmaps in offscreen memory, yes */
+ 3 0.0033 : pixbounds.x1 = pDrawable->x;
+ 1 0.0011 : pixbounds.y1 = pDrawable->y;
+ : pixbounds.x2 = pDrawable->x + pDrawable->width;
+ : pixbounds.y2 = pDrawable->y + pDrawable->height;
+ :
+ 1 0.0011 : if (pGC->freeCompClip)
+ : {
+ 8 0.0087 : REGION_RESET(pScreen, pGC->pCompositeClip, &pixbounds);
+ : }
+ : else
+ : {
+ : pGC->freeCompClip = TRUE;
+ : pGC->pCompositeClip = REGION_CREATE(pScreen, &pixbounds, 1);
+ : }
+ :
+ : if (pGC->clientClipType == CT_REGION)
+ : {
+ : if(pDrawable->x || pDrawable->y) {
+ : REGION_TRANSLATE(pScreen, pGC->clientClip,
+ : pDrawable->x + pGC->clipOrg.x,
+ : pDrawable->y + pGC->clipOrg.y);
+ : REGION_INTERSECT(pScreen, pGC->pCompositeClip,
+ : pGC->pCompositeClip, pGC->clientClip);
+ : REGION_TRANSLATE(pScreen, pGC->clientClip,
+ : -(pDrawable->x + pGC->clipOrg.x),
+ : -(pDrawable->y + pGC->clipOrg.y));
+ : } else {
+ 1 0.0011 : REGION_TRANSLATE(pScreen, pGC->pCompositeClip,
+ : -pGC->clipOrg.x, -pGC->clipOrg.y);
+ : REGION_INTERSECT(pScreen, pGC->pCompositeClip,
+ : pGC->pCompositeClip, pGC->clientClip);
+ : REGION_TRANSLATE(pScreen, pGC->pCompositeClip,
+ : pGC->clipOrg.x, pGC->clipOrg.y);
+ : }
+ : }
+ : } /* end of composite clip for pixmap */
+ 1 0.0011 :} /* end miComputeCompositeClip */
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/Xext/xvmain.c"
+ *
+ * 26 0.0283
+ */
+
+
+ :/***********************************************************
+ :Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts,
+ :and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+ :
+ : All Rights Reserved
+ :
+ :Permission to use, copy, modify, and distribute this software and its
+ :documentation for any purpose and without fee is hereby granted,
+ :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 names of Digital or MIT not be
+ :used in advertising or publicity pertaining to distribution of the
+ :software without specific, written prior permission.
+ :
+ :DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ :ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ :DIGITAL 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.
+ :
+ :******************************************************************/
+ :
+ :/*
+ :** File:
+ :**
+ :** xvmain.c --- Xv server extension main device independent module.
+ :**
+ :** Author:
+ :**
+ :** David Carver (Digital Workstation Engineering/Project Athena)
+ :**
+ :** Revisions:
+ :**
+ :** 04.09.91 Carver
+ :** - change: stop video always generates an event even when video
+ :** wasn't active
+ :**
+ :** 29.08.91 Carver
+ :** - change: unrealizing windows no longer preempts video
+ :**
+ :** 11.06.91 Carver
+ :** - changed SetPortControl to SetPortAttribute
+ :** - changed GetPortControl to GetPortAttribute
+ :** - changed QueryBestSize
+ :**
+ :** 28.05.91 Carver
+ :** - fixed Put and Get requests to not preempt operations to same drawable
+ :**
+ :** 15.05.91 Carver
+ :** - version 2.0 upgrade
+ :**
+ :** 19.03.91 Carver
+ :** - fixed Put and Get requests to honor grabbed ports.
+ :** - fixed Video requests to update di structure with new drawable, and
+ :** client after calling ddx.
+ :**
+ :** 24.01.91 Carver
+ :** - version 1.4 upgrade
+ :**
+ :** Notes:
+ :**
+ :** Port structures reference client structures in a two different
+ :** ways: when grabs, or video is active. Each reference is encoded
+ :** as fake client resources and thus when the client is goes away so
+ :** does the reference (it is zeroed). No other action is taken, so
+ :** video doesn't necessarily stop. It probably will as a result of
+ :** other resources going away, but if a client starts video using
+ :** none of its own resources, then the video will continue to play
+ :** after the client disappears.
+ :**
+ :**
+ :*/
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include <string.h>
+ :
+ :#include <X11/X.h>
+ :#include <X11/Xproto.h>
+ :#include "misc.h"
+ :#include "os.h"
+ :#include "scrnintstr.h"
+ :#include "windowstr.h"
+ :#include "pixmapstr.h"
+ :#include "gc.h"
+ :#include "extnsionst.h"
+ :#include "dixstruct.h"
+ :#include "resource.h"
+ :#include "opaque.h"
+ :#include "input.h"
+ :
+ :#define GLOBAL
+ :
+ :#include <X11/extensions/Xv.h>
+ :#include <X11/extensions/Xvproto.h>
+ :#include "xvdix.h"
+ :
+ :#ifdef PANORAMIX
+ :#include "panoramiX.h"
+ :#include "panoramiXsrv.h"
+ :#include "xvdisp.h"
+ :#endif
+ :
+ :int XvScreenIndex = -1;
+ :unsigned long XvExtensionGeneration = 0;
+ :unsigned long XvScreenGeneration = 0;
+ :unsigned long XvResourceGeneration = 0;
+ :
+ :int XvReqCode;
+ :int XvEventBase;
+ :int XvErrorBase;
+ :
+ :unsigned long XvRTPort;
+ :unsigned long XvRTEncoding;
+ :unsigned long XvRTGrab;
+ :unsigned long XvRTVideoNotify;
+ :unsigned long XvRTVideoNotifyList;
+ :unsigned long XvRTPortNotify;
+ :
+ :
+ :
+ :/* EXTERNAL */
+ :
+ :extern XID clientErrorValue;
+ :
+ :static void WriteSwappedVideoNotifyEvent(xvEvent *, xvEvent *);
+ :static void WriteSwappedPortNotifyEvent(xvEvent *, xvEvent *);
+ :static Bool CreateResourceTypes(void);
+ :
+ :static Bool XvCloseScreen(int, ScreenPtr);
+ :static Bool XvDestroyPixmap(PixmapPtr);
+ :static Bool XvDestroyWindow(WindowPtr);
+ :static void XvResetProc(ExtensionEntry*);
+ :static int XvdiDestroyGrab(pointer, XID);
+ :static int XvdiDestroyEncoding(pointer, XID);
+ :static int XvdiDestroyVideoNotify(pointer, XID);
+ :static int XvdiDestroyPortNotify(pointer, XID);
+ :static int XvdiDestroyVideoNotifyList(pointer, XID);
+ :static int XvdiDestroyPort(pointer, XID);
+ :static int XvdiSendVideoNotify(XvPortPtr, DrawablePtr, int);
+ :
+ :
+ :
+ :
+ :/*
+ :** XvExtensionInit
+ :**
+ :**
+ :*/
+ :
+ :void
+ :XvExtensionInit(void)
+ :{
+ : ExtensionEntry *extEntry;
+ :
+ : /* LOOK TO SEE IF ANY SCREENS WERE INITIALIZED; IF NOT THEN
+ : INIT GLOBAL VARIABLES SO THE EXTENSION CAN FUNCTION */
+ : if (XvScreenGeneration != serverGeneration)
+ : {
+ : if (!CreateResourceTypes())
+ : {
+ : ErrorF("XvExtensionInit: Unable to allocate resource types\n");
+ : return;
+ : }
+ : XvScreenIndex = AllocateScreenPrivateIndex ();
+ : if (XvScreenIndex < 0)
+ : {
+ : ErrorF("XvExtensionInit: Unable to allocate screen private index\n");
+ : return;
+ : }
+ :#ifdef PANORAMIX
+ : XineramaRegisterConnectionBlockCallback(XineramifyXv);
+ :#endif
+ : XvScreenGeneration = serverGeneration;
+ : }
+ :
+ : if (XvExtensionGeneration != serverGeneration)
+ : {
+ : XvExtensionGeneration = serverGeneration;
+ :
+ : extEntry = AddExtension(XvName, XvNumEvents, XvNumErrors,
+ : ProcXvDispatch, SProcXvDispatch,
+ : XvResetProc, StandardMinorOpcode);
+ : if (!extEntry)
+ : {
+ : FatalError("XvExtensionInit: AddExtensions failed\n");
+ : }
+ :
+ : XvReqCode = extEntry->base;
+ : XvEventBase = extEntry->eventBase;
+ : XvErrorBase = extEntry->errorBase;
+ :
+ : EventSwapVector[XvEventBase+XvVideoNotify] =
+ : (EventSwapPtr)WriteSwappedVideoNotifyEvent;
+ : EventSwapVector[XvEventBase+XvPortNotify] =
+ : (EventSwapPtr)WriteSwappedPortNotifyEvent;
+ :
+ : (void)MakeAtom(XvName, strlen(XvName), xTrue);
+ :
+ : }
+ :}
+ :
+ :static Bool
+ :CreateResourceTypes(void)
+ :
+ :{
+ :
+ : if (XvResourceGeneration == serverGeneration) return TRUE;
+ :
+ : XvResourceGeneration = serverGeneration;
+ :
+ : if (!(XvRTPort = CreateNewResourceType(XvdiDestroyPort)))
+ : {
+ : ErrorF("CreateResourceTypes: failed to allocate port resource.\n");
+ : return FALSE;
+ : }
+ :
+ : if (!(XvRTGrab = CreateNewResourceType(XvdiDestroyGrab)))
+ : {
+ : ErrorF("CreateResourceTypes: failed to allocate grab resource.\n");
+ : return FALSE;
+ : }
+ :
+ : if (!(XvRTEncoding = CreateNewResourceType(XvdiDestroyEncoding)))
+ : {
+ : ErrorF("CreateResourceTypes: failed to allocate encoding resource.\n");
+ : return FALSE;
+ : }
+ :
+ : if (!(XvRTVideoNotify = CreateNewResourceType(XvdiDestroyVideoNotify)))
+ : {
+ : ErrorF("CreateResourceTypes: failed to allocate video notify resource.\n");
+ : return FALSE;
+ : }
+ :
+ : if (!(XvRTVideoNotifyList = CreateNewResourceType(XvdiDestroyVideoNotifyList)))
+ : {
+ : ErrorF("CreateResourceTypes: failed to allocate video notify list resource.\n");
+ : return FALSE;
+ : }
+ :
+ : if (!(XvRTPortNotify = CreateNewResourceType(XvdiDestroyPortNotify)))
+ : {
+ : ErrorF("CreateResourceTypes: failed to allocate port notify resource.\n");
+ : return FALSE;
+ : }
+ :
+ : return TRUE;
+ :
+ :}
+ :
+ :_X_EXPORT int
+ :XvScreenInit(ScreenPtr pScreen)
+ :{
+ : XvScreenPtr pxvs;
+ :
+ : if (XvScreenGeneration != serverGeneration)
+ : {
+ : if (!CreateResourceTypes())
+ : {
+ : ErrorF("XvScreenInit: Unable to allocate resource types\n");
+ : return BadAlloc;
+ : }
+ : XvScreenIndex = AllocateScreenPrivateIndex ();
+ : if (XvScreenIndex < 0)
+ : {
+ : ErrorF("XvScreenInit: Unable to allocate screen private index\n");
+ : return BadAlloc;
+ : }
+ :#ifdef PANORAMIX
+ : XineramaRegisterConnectionBlockCallback(XineramifyXv);
+ :#endif
+ : XvScreenGeneration = serverGeneration;
+ : }
+ :
+ : if (pScreen->devPrivates[XvScreenIndex].ptr)
+ : {
+ : ErrorF("XvScreenInit: screen devPrivates ptr non-NULL before init\n");
+ : }
+ :
+ : /* ALLOCATE SCREEN PRIVATE RECORD */
+ :
+ : pxvs = (XvScreenPtr) xalloc (sizeof (XvScreenRec));
+ : if (!pxvs)
+ : {
+ : ErrorF("XvScreenInit: Unable to allocate screen private structure\n");
+ : return BadAlloc;
+ : }
+ :
+ : pScreen->devPrivates[XvScreenIndex].ptr = (pointer)pxvs;
+ :
+ :
+ : pxvs->DestroyPixmap = pScreen->DestroyPixmap;
+ : pxvs->DestroyWindow = pScreen->DestroyWindow;
+ : pxvs->CloseScreen = pScreen->CloseScreen;
+ :
+ : pScreen->DestroyPixmap = XvDestroyPixmap;
+ : pScreen->DestroyWindow = XvDestroyWindow;
+ : pScreen->CloseScreen = XvCloseScreen;
+ :
+ : return Success;
+ :}
+ :
+ :static Bool
+ :XvCloseScreen(
+ : int ii,
+ : ScreenPtr pScreen
+ :){
+ :
+ : XvScreenPtr pxvs;
+ :
+ : pxvs = (XvScreenPtr) pScreen->devPrivates[XvScreenIndex].ptr;
+ :
+ : pScreen->DestroyPixmap = pxvs->DestroyPixmap;
+ : pScreen->DestroyWindow = pxvs->DestroyWindow;
+ : pScreen->CloseScreen = pxvs->CloseScreen;
+ :
+ : (* pxvs->ddCloseScreen)(ii, pScreen);
+ :
+ : xfree(pxvs);
+ :
+ : pScreen->devPrivates[XvScreenIndex].ptr = (pointer)NULL;
+ :
+ : return (*pScreen->CloseScreen)(ii, pScreen);
+ :
+ :}
+ :
+ :static void
+ :XvResetProc(ExtensionEntry* extEntry)
+ :{
+ :}
+ :
+ :_X_EXPORT int
+ :XvGetScreenIndex(void)
+ :{
+ : return XvScreenIndex;
+ :}
+ :
+ :_X_EXPORT unsigned long
+ :XvGetRTPort(void)
+ :{
+ : return XvRTPort;
+ :}
+ :
+ :static Bool
+ :XvDestroyPixmap(PixmapPtr pPix)
+ 4 0.0044 :{ /* XvDestroyPixmap total: 26 0.0283 */
+ : Bool status;
+ : ScreenPtr pScreen;
+ : XvScreenPtr pxvs;
+ : XvAdaptorPtr pa;
+ : int na;
+ : XvPortPtr pp;
+ : int np;
+ :
+ 2 0.0022 : pScreen = pPix->drawable.pScreen;
+ :
+ 1 0.0011 : SCREEN_PROLOGUE(pScreen, DestroyPixmap);
+ :
+ : pxvs = (XvScreenPtr)pScreen->devPrivates[XvScreenIndex].ptr;
+ :
+ : /* CHECK TO SEE IF THIS PORT IS IN USE */
+ :
+ : pa = pxvs->pAdaptors;
+ 1 0.0011 : na = pxvs->nAdaptors;
+ 1 0.0011 : while (na--)
+ : {
+ 1 0.0011 : np = pa->nPorts;
+ 1 0.0011 : pp = pa->pPorts;
+ :
+ 3 0.0033 : while (np--)
+ : {
+ 2 0.0022 : if (pp->pDraw == (DrawablePtr)pPix)
+ : {
+ : XvdiSendVideoNotify(pp, pp->pDraw, XvPreempted);
+ :
+ : (void)(* pp->pAdaptor->ddStopVideo)((ClientPtr)NULL, pp,
+ : pp->pDraw);
+ :
+ : pp->pDraw = (DrawablePtr)NULL;
+ : pp->client = (ClientPtr)NULL;
+ 4 0.0044 : pp->time = currentTime;
+ : }
+ 4 0.0044 : pp++;
+ : }
+ : pa++;
+ : }
+ :
+ : status = (* pScreen->DestroyPixmap)(pPix);
+ :
+ 1 0.0011 : SCREEN_EPILOGUE(pScreen, DestroyPixmap, XvDestroyPixmap);
+ :
+ : return status;
+ :
+ 1 0.0011 :}
+ :
+ :static Bool
+ :XvDestroyWindow(WindowPtr pWin)
+ :{
+ : Bool status;
+ : ScreenPtr pScreen;
+ : XvScreenPtr pxvs;
+ : XvAdaptorPtr pa;
+ : int na;
+ : XvPortPtr pp;
+ : int np;
+ :
+ : pScreen = pWin->drawable.pScreen;
+ :
+ : SCREEN_PROLOGUE(pScreen, DestroyWindow);
+ :
+ : pxvs = (XvScreenPtr)pScreen->devPrivates[XvScreenIndex].ptr;
+ :
+ : /* CHECK TO SEE IF THIS PORT IS IN USE */
+ :
+ : pa = pxvs->pAdaptors;
+ : na = pxvs->nAdaptors;
+ : while (na--)
+ : {
+ : np = pa->nPorts;
+ : pp = pa->pPorts;
+ :
+ : while (np--)
+ : {
+ : if (pp->pDraw == (DrawablePtr)pWin)
+ : {
+ : XvdiSendVideoNotify(pp, pp->pDraw, XvPreempted);
+ :
+ : (void)(* pp->pAdaptor->ddStopVideo)((ClientPtr)NULL, pp,
+ : pp->pDraw);
+ :
+ : pp->pDraw = (DrawablePtr)NULL;
+ : pp->client = (ClientPtr)NULL;
+ : pp->time = currentTime;
+ : }
+ : pp++;
+ : }
+ : pa++;
+ : }
+ :
+ :
+ : status = (* pScreen->DestroyWindow)(pWin);
+ :
+ : SCREEN_EPILOGUE(pScreen, DestroyWindow, XvDestroyWindow);
+ :
+ : return status;
+ :
+ :}
+ :
+ :/* The XvdiVideoStopped procedure is a hook for the device dependent layer.
+ : It provides a way for the dd layer to inform the di layer that video has
+ : stopped in a port for reasons that the di layer had no control over; note
+ : that it doesn't call back into the dd layer */
+ :
+ :int
+ :XvdiVideoStopped(XvPortPtr pPort, int reason)
+ :{
+ :
+ : /* IF PORT ISN'T ACTIVE THEN WE'RE DONE */
+ :
+ : if (!pPort->pDraw) return Success;
+ :
+ : XvdiSendVideoNotify(pPort, pPort->pDraw, reason);
+ :
+ : pPort->pDraw = (DrawablePtr)NULL;
+ : pPort->client = (ClientPtr)NULL;
+ : pPort->time = currentTime;
+ :
+ : return Success;
+ :
+ :}
+ :
+ :static int
+ :XvdiDestroyPort(pointer pPort, XID id)
+ :{
+ : return (* ((XvPortPtr)pPort)->pAdaptor->ddFreePort)(pPort);
+ :}
+ :
+ :static int
+ :XvdiDestroyGrab(pointer pGrab, XID id)
+ :{
+ : ((XvGrabPtr)pGrab)->client = (ClientPtr)NULL;
+ : return Success;
+ :}
+ :
+ :static int
+ :XvdiDestroyVideoNotify(pointer pn, XID id)
+ :{
+ : /* JUST CLEAR OUT THE client POINTER FIELD */
+ :
+ : ((XvVideoNotifyPtr)pn)->client = (ClientPtr)NULL;
+ : return Success;
+ :}
+ :
+ :static int
+ :XvdiDestroyPortNotify(pointer pn, XID id)
+ :{
+ : /* JUST CLEAR OUT THE client POINTER FIELD */
+ :
+ : ((XvPortNotifyPtr)pn)->client = (ClientPtr)NULL;
+ : return Success;
+ :}
+ :
+ :static int
+ :XvdiDestroyVideoNotifyList(pointer pn, XID id)
+ :{
+ : XvVideoNotifyPtr npn,cpn;
+ :
+ : /* ACTUALLY DESTROY THE NOTITY LIST */
+ :
+ : cpn = (XvVideoNotifyPtr)pn;
+ :
+ : while (cpn)
+ : {
+ : npn = cpn->next;
+ : if (cpn->client) FreeResource(cpn->id, XvRTVideoNotify);
+ : xfree(cpn);
+ : cpn = npn;
+ : }
+ : return Success;
+ :}
+ :
+ :static int
+ :XvdiDestroyEncoding(pointer value, XID id)
+ :{
+ : return Success;
+ :}
+ :
+ :static int
+ :XvdiSendVideoNotify(pPort, pDraw, reason)
+ :
+ :XvPortPtr pPort;
+ :DrawablePtr pDraw;
+ :int reason;
+ :
+ :{
+ : xvEvent event;
+ : XvVideoNotifyPtr pn;
+ :
+ : pn = (XvVideoNotifyPtr)LookupIDByType(pDraw->id, XvRTVideoNotifyList);
+ :
+ : while (pn)
+ : {
+ : if (pn->client)
+ : {
+ : event.u.u.type = XvEventBase + XvVideoNotify;
+ : event.u.u.sequenceNumber = pn->client->sequence;
+ : event.u.videoNotify.time = currentTime.milliseconds;
+ : event.u.videoNotify.drawable = pDraw->id;
+ : event.u.videoNotify.port = pPort->id;
+ : event.u.videoNotify.reason = reason;
+ : (void) TryClientEvents(pn->client, (xEventPtr)&event, 1, NoEventMask,
+ : NoEventMask, NullGrab);
+ : }
+ : pn = pn->next;
+ : }
+ :
+ : return Success;
+ :
+ :}
+ :
+ :
+ :int
+ :XvdiSendPortNotify(
+ : XvPortPtr pPort,
+ : Atom attribute,
+ : INT32 value
+ :){
+ : xvEvent event;
+ : XvPortNotifyPtr pn;
+ :
+ : pn = pPort->pNotify;
+ :
+ : while (pn)
+ : {
+ : if (pn->client)
+ : {
+ : event.u.u.type = XvEventBase + XvPortNotify;
+ : event.u.u.sequenceNumber = pn->client->sequence;
+ : event.u.portNotify.time = currentTime.milliseconds;
+ : event.u.portNotify.port = pPort->id;
+ : event.u.portNotify.attribute = attribute;
+ : event.u.portNotify.value = value;
+ : (void) TryClientEvents(pn->client, (xEventPtr)&event, 1, NoEventMask,
+ : NoEventMask, NullGrab);
+ : }
+ : pn = pn->next;
+ : }
+ :
+ : return Success;
+ :
+ :}
+ :
+ :
+ :#define CHECK_SIZE(dw, dh, sw, sh) { \
+ : if(!dw || !dh || !sw || !sh) return Success; \
+ : /* The region code will break these if they are too large */ \
+ : if((dw > 32767) || (dh > 32767) || (sw > 32767) || (sh > 32767)) \
+ : return BadValue; \
+ :}
+ :
+ :
+ :int
+ :XvdiPutVideo(
+ : ClientPtr client,
+ : DrawablePtr pDraw,
+ : XvPortPtr pPort,
+ : GCPtr pGC,
+ : INT16 vid_x, INT16 vid_y,
+ : CARD16 vid_w, CARD16 vid_h,
+ : INT16 drw_x, INT16 drw_y,
+ : CARD16 drw_w, CARD16 drw_h
+ :){
+ : DrawablePtr pOldDraw;
+ :
+ : CHECK_SIZE(drw_w, drw_h, vid_w, vid_h);
+ :
+ : /* UPDATE TIME VARIABLES FOR USE IN EVENTS */
+ :
+ : UpdateCurrentTime();
+ :
+ : /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
+ : INFORM CLIENT OF ITS FAILURE */
+ :
+ : if (pPort->grab.client && (pPort->grab.client != client))
+ : {
+ : XvdiSendVideoNotify(pPort, pDraw, XvBusy);
+ : return Success;
+ : }
+ :
+ : /* CHECK TO SEE IF PORT IS IN USE; IF SO THEN WE MUST DELIVER INTERRUPTED
+ : EVENTS TO ANY CLIENTS WHO WANT THEM */
+ :
+ : pOldDraw = pPort->pDraw;
+ : if ((pOldDraw) && (pOldDraw != pDraw))
+ : {
+ : XvdiSendVideoNotify(pPort, pPort->pDraw, XvPreempted);
+ : }
+ :
+ : (void) (* pPort->pAdaptor->ddPutVideo)(client, pDraw, pPort, pGC,
+ : vid_x, vid_y, vid_w, vid_h,
+ : drw_x, drw_y, drw_w, drw_h);
+ :
+ : if ((pPort->pDraw) && (pOldDraw != pDraw))
+ : {
+ : pPort->client = client;
+ : XvdiSendVideoNotify(pPort, pPort->pDraw, XvStarted);
+ : }
+ :
+ : pPort->time = currentTime;
+ :
+ : return (Success);
+ :
+ :}
+ :
+ :int
+ :XvdiPutStill(
+ : ClientPtr client,
+ : DrawablePtr pDraw,
+ : XvPortPtr pPort,
+ : GCPtr pGC,
+ : INT16 vid_x, INT16 vid_y,
+ : CARD16 vid_w, CARD16 vid_h,
+ : INT16 drw_x, INT16 drw_y,
+ : CARD16 drw_w, CARD16 drw_h
+ :){
+ : int status;
+ :
+ : CHECK_SIZE(drw_w, drw_h, vid_w, vid_h);
+ :
+ : /* UPDATE TIME VARIABLES FOR USE IN EVENTS */
+ :
+ : UpdateCurrentTime();
+ :
+ : /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
+ : INFORM CLIENT OF ITS FAILURE */
+ :
+ : if (pPort->grab.client && (pPort->grab.client != client))
+ : {
+ : XvdiSendVideoNotify(pPort, pDraw, XvBusy);
+ : return Success;
+ : }
+ :
+ : pPort->time = currentTime;
+ :
+ : status = (* pPort->pAdaptor->ddPutStill)(client, pDraw, pPort, pGC,
+ : vid_x, vid_y, vid_w, vid_h,
+ : drw_x, drw_y, drw_w, drw_h);
+ :
+ : return status;
+ :
+ :}
+ :
+ :int
+ :XvdiPutImage(
+ : ClientPtr client,
+ : DrawablePtr pDraw,
+ : XvPortPtr pPort,
+ : GCPtr pGC,
+ : INT16 src_x, INT16 src_y,
+ : CARD16 src_w, CARD16 src_h,
+ : INT16 drw_x, INT16 drw_y,
+ : CARD16 drw_w, CARD16 drw_h,
+ : XvImagePtr image,
+ : unsigned char* data,
+ : Bool sync,
+ : CARD16 width, CARD16 height
+ :){
+ : CHECK_SIZE(drw_w, drw_h, src_w, src_h);
+ :
+ : /* UPDATE TIME VARIABLES FOR USE IN EVENTS */
+ :
+ : UpdateCurrentTime();
+ :
+ : /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
+ : INFORM CLIENT OF ITS FAILURE */
+ :
+ : if (pPort->grab.client && (pPort->grab.client != client))
+ : {
+ : XvdiSendVideoNotify(pPort, pDraw, XvBusy);
+ : return Success;
+ : }
+ :
+ : pPort->time = currentTime;
+ :
+ : return (* pPort->pAdaptor->ddPutImage)(client, pDraw, pPort, pGC,
+ : src_x, src_y, src_w, src_h,
+ : drw_x, drw_y, drw_w, drw_h,
+ : image, data, sync, width, height);
+ :}
+ :
+ :
+ :int
+ :XvdiGetVideo(
+ : ClientPtr client,
+ : DrawablePtr pDraw,
+ : XvPortPtr pPort,
+ : GCPtr pGC,
+ : INT16 vid_x, INT16 vid_y,
+ : CARD16 vid_w, CARD16 vid_h,
+ : INT16 drw_x, INT16 drw_y,
+ : CARD16 drw_w, CARD16 drw_h
+ :){
+ : DrawablePtr pOldDraw;
+ :
+ : CHECK_SIZE(drw_w, drw_h, vid_w, vid_h);
+ :
+ : /* UPDATE TIME VARIABLES FOR USE IN EVENTS */
+ :
+ : UpdateCurrentTime();
+ :
+ : /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
+ : INFORM CLIENT OF ITS FAILURE */
+ :
+ : if (pPort->grab.client && (pPort->grab.client != client))
+ : {
+ : XvdiSendVideoNotify(pPort, pDraw, XvBusy);
+ : return Success;
+ : }
+ :
+ : /* CHECK TO SEE IF PORT IS IN USE; IF SO THEN WE MUST DELIVER INTERRUPTED
+ : EVENTS TO ANY CLIENTS WHO WANT THEM */
+ :
+ : pOldDraw = pPort->pDraw;
+ : if ((pOldDraw) && (pOldDraw != pDraw))
+ : {
+ : XvdiSendVideoNotify(pPort, pPort->pDraw, XvPreempted);
+ : }
+ :
+ : (void) (* pPort->pAdaptor->ddGetVideo)(client, pDraw, pPort, pGC,
+ : vid_x, vid_y, vid_w, vid_h,
+ : drw_x, drw_y, drw_w, drw_h);
+ :
+ : if ((pPort->pDraw) && (pOldDraw != pDraw))
+ : {
+ : pPort->client = client;
+ : XvdiSendVideoNotify(pPort, pPort->pDraw, XvStarted);
+ : }
+ :
+ : pPort->time = currentTime;
+ :
+ : return (Success);
+ :
+ :}
+ :
+ :int
+ :XvdiGetStill(
+ : ClientPtr client,
+ : DrawablePtr pDraw,
+ : XvPortPtr pPort,
+ : GCPtr pGC,
+ : INT16 vid_x, INT16 vid_y,
+ : CARD16 vid_w, CARD16 vid_h,
+ : INT16 drw_x, INT16 drw_y,
+ : CARD16 drw_w, CARD16 drw_h
+ :){
+ : int status;
+ :
+ : CHECK_SIZE(drw_w, drw_h, vid_w, vid_h);
+ :
+ : /* UPDATE TIME VARIABLES FOR USE IN EVENTS */
+ :
+ : UpdateCurrentTime();
+ :
+ : /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
+ : INFORM CLIENT OF ITS FAILURE */
+ :
+ : if (pPort->grab.client && (pPort->grab.client != client))
+ : {
+ : XvdiSendVideoNotify(pPort, pDraw, XvBusy);
+ : return Success;
+ : }
+ :
+ : status = (* pPort->pAdaptor->ddGetStill)(client, pDraw, pPort, pGC,
+ : vid_x, vid_y, vid_w, vid_h,
+ : drw_x, drw_y, drw_w, drw_h);
+ :
+ : pPort->time = currentTime;
+ :
+ : return status;
+ :
+ :}
+ :
+ :int
+ :XvdiGrabPort(
+ : ClientPtr client,
+ : XvPortPtr pPort,
+ : Time ctime,
+ : int *p_result
+ :){
+ : unsigned long id;
+ : TimeStamp time;
+ :
+ : UpdateCurrentTime();
+ : time = ClientTimeToServerTime(ctime);
+ :
+ : if (pPort->grab.client && (client != pPort->grab.client))
+ : {
+ : *p_result = XvAlreadyGrabbed;
+ : return Success;
+ : }
+ :
+ : if ((CompareTimeStamps(time, currentTime) == LATER) ||
+ : (CompareTimeStamps(time, pPort->time) == EARLIER))
+ : {
+ : *p_result = XvInvalidTime;
+ : return Success;
+ : }
+ :
+ : if (client == pPort->grab.client)
+ : {
+ : *p_result = Success;
+ : return Success;
+ : }
+ :
+ : id = FakeClientID(client->index);
+ :
+ : if (!AddResource(id, XvRTGrab, &pPort->grab))
+ : {
+ : return BadAlloc;
+ : }
+ :
+ : /* IF THERE IS ACTIVE VIDEO THEN STOP IT */
+ :
+ : if ((pPort->pDraw) && (client != pPort->client))
+ : {
+ : XVCALL(diStopVideo)((ClientPtr)NULL, pPort, pPort->pDraw);
+ : }
+ :
+ : pPort->grab.client = client;
+ : pPort->grab.id = id;
+ :
+ : pPort->time = currentTime;
+ :
+ : *p_result = Success;
+ :
+ : return Success;
+ :
+ :}
+ :
+ :int
+ :XvdiUngrabPort(
+ : ClientPtr client,
+ : XvPortPtr pPort,
+ : Time ctime
+ :){
+ : TimeStamp time;
+ :
+ : UpdateCurrentTime();
+ : time = ClientTimeToServerTime(ctime);
+ :
+ : if ((!pPort->grab.client) || (client != pPort->grab.client))
+ : {
+ : return Success;
+ : }
+ :
+ : if ((CompareTimeStamps(time, currentTime) == LATER) ||
+ : (CompareTimeStamps(time, pPort->time) == EARLIER))
+ : {
+ : return Success;
+ : }
+ :
+ : /* FREE THE GRAB RESOURCE; AND SET THE GRAB CLIENT TO NULL */
+ :
+ : FreeResource(pPort->grab.id, XvRTGrab);
+ : pPort->grab.client = (ClientPtr)NULL;
+ :
+ : pPort->time = currentTime;
+ :
+ : return Success;
+ :
+ :}
+ :
+ :
+ :int
+ :XvdiSelectVideoNotify(
+ : ClientPtr client,
+ : DrawablePtr pDraw,
+ : BOOL onoff
+ :){
+ : XvVideoNotifyPtr pn,tpn,fpn;
+ :
+ : /* FIND VideoNotify LIST */
+ :
+ : pn = (XvVideoNotifyPtr)LookupIDByType(pDraw->id, XvRTVideoNotifyList);
+ :
+ : /* IF ONE DONES'T EXIST AND NO MASK, THEN JUST RETURN */
+ :
+ : if (!onoff && !pn) return Success;
+ :
+ : /* IF ONE DOESN'T EXIST CREATE IT AND ADD A RESOURCE SO THAT THE LIST
+ : WILL BE DELETED WHEN THE DRAWABLE IS DESTROYED */
+ :
+ : if (!pn)
+ : {
+ : if (!(tpn = (XvVideoNotifyPtr)xalloc(sizeof(XvVideoNotifyRec))))
+ : return BadAlloc;
+ : tpn->next = (XvVideoNotifyPtr)NULL;
+ : if (!AddResource(pDraw->id, XvRTVideoNotifyList, tpn))
+ : {
+ : xfree(tpn);
+ : return BadAlloc;
+ : }
+ : }
+ : else
+ : {
+ : /* LOOK TO SEE IF ENTRY ALREADY EXISTS */
+ :
+ : fpn = (XvVideoNotifyPtr)NULL;
+ : tpn = pn;
+ : while (tpn)
+ : {
+ : if (tpn->client == client)
+ : {
+ : if (!onoff) tpn->client = (ClientPtr)NULL;
+ : return Success;
+ : }
+ : if (!tpn->client) fpn = tpn; /* TAKE NOTE OF FREE ENTRY */
+ : tpn = tpn->next;
+ : }
+ :
+ : /* IF TUNNING OFF, THEN JUST RETURN */
+ :
+ : if (!onoff) return Success;
+ :
+ : /* IF ONE ISN'T FOUND THEN ALLOCATE ONE AND LINK IT INTO THE LIST */
+ :
+ : if (fpn)
+ : {
+ : tpn = fpn;
+ : }
+ : else
+ : {
+ : if (!(tpn = (XvVideoNotifyPtr)xalloc(sizeof(XvVideoNotifyRec))))
+ : return BadAlloc;
+ : tpn->next = pn->next;
+ : pn->next = tpn;
+ : }
+ : }
+ :
+ : /* INIT CLIENT PTR IN CASE WE CAN'T ADD RESOURCE */
+ : /* ADD RESOURCE SO THAT IF CLIENT EXITS THE CLIENT PTR WILL BE CLEARED */
+ :
+ : tpn->client = (ClientPtr)NULL;
+ : tpn->id = FakeClientID(client->index);
+ : AddResource(tpn->id, XvRTVideoNotify, tpn);
+ :
+ : tpn->client = client;
+ : return Success;
+ :
+ :}
+ :
+ :int
+ :XvdiSelectPortNotify(
+ : ClientPtr client,
+ : XvPortPtr pPort,
+ : BOOL onoff
+ :){
+ : XvPortNotifyPtr pn,tpn;
+ :
+ : /* SEE IF CLIENT IS ALREADY IN LIST */
+ :
+ : tpn = (XvPortNotifyPtr)NULL;
+ : pn = pPort->pNotify;
+ : while (pn)
+ : {
+ : if (!pn->client) tpn = pn; /* TAKE NOTE OF FREE ENTRY */
+ : if (pn->client == client) break;
+ : pn = pn->next;
+ : }
+ :
+ : /* IS THE CLIENT ALREADY ON THE LIST? */
+ :
+ : if (pn)
+ : {
+ : /* REMOVE IT? */
+ :
+ : if (!onoff)
+ : {
+ : pn->client = (ClientPtr)NULL;
+ : FreeResource(pn->id, XvRTPortNotify);
+ : }
+ :
+ : return Success;
+ : }
+ :
+ : /* DIDN'T FIND IT; SO REUSE LIST ELEMENT IF ONE IS FREE OTHERWISE
+ : CREATE A NEW ONE AND ADD IT TO THE BEGINNING OF THE LIST */
+ :
+ : if (!tpn)
+ : {
+ : if (!(tpn = (XvPortNotifyPtr)xalloc(sizeof(XvPortNotifyRec))))
+ : return BadAlloc;
+ : tpn->next = pPort->pNotify;
+ : pPort->pNotify = tpn;
+ : }
+ :
+ : tpn->client = client;
+ : tpn->id = FakeClientID(client->index);
+ : AddResource(tpn->id, XvRTPortNotify, tpn);
+ :
+ : return Success;
+ :
+ :}
+ :
+ :int
+ :XvdiStopVideo(
+ : ClientPtr client,
+ : XvPortPtr pPort,
+ : DrawablePtr pDraw
+ :){
+ : int status;
+ :
+ : /* IF PORT ISN'T ACTIVE THEN WE'RE DONE */
+ :
+ : if (!pPort->pDraw || (pPort->pDraw != pDraw))
+ : {
+ : XvdiSendVideoNotify(pPort, pDraw, XvStopped);
+ : return Success;
+ : }
+ :
+ : /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
+ : INFORM CLIENT OF ITS FAILURE */
+ :
+ : if ((client) && (pPort->grab.client) && (pPort->grab.client != client))
+ : {
+ : XvdiSendVideoNotify(pPort, pDraw, XvBusy);
+ : return Success;
+ : }
+ :
+ : XvdiSendVideoNotify(pPort, pDraw, XvStopped);
+ :
+ : status = (* pPort->pAdaptor->ddStopVideo)(client, pPort, pDraw);
+ :
+ : pPort->pDraw = (DrawablePtr)NULL;
+ : pPort->client = (ClientPtr)client;
+ : pPort->time = currentTime;
+ :
+ : return status;
+ :
+ :}
+ :
+ :int
+ :XvdiPreemptVideo(
+ : ClientPtr client,
+ : XvPortPtr pPort,
+ : DrawablePtr pDraw
+ :){
+ : int status;
+ :
+ : /* IF PORT ISN'T ACTIVE THEN WE'RE DONE */
+ :
+ : if (!pPort->pDraw || (pPort->pDraw != pDraw)) return Success;
+ :
+ : XvdiSendVideoNotify(pPort, pPort->pDraw, XvPreempted);
+ :
+ : status = (* pPort->pAdaptor->ddStopVideo)(client, pPort, pPort->pDraw);
+ :
+ : pPort->pDraw = (DrawablePtr)NULL;
+ : pPort->client = (ClientPtr)client;
+ : pPort->time = currentTime;
+ :
+ : return status;
+ :
+ :}
+ :
+ :int
+ :XvdiMatchPort(
+ : XvPortPtr pPort,
+ : DrawablePtr pDraw
+ :){
+ :
+ : XvAdaptorPtr pa;
+ : XvFormatPtr pf;
+ : int nf;
+ :
+ : pa = pPort->pAdaptor;
+ :
+ : if (pa->pScreen != pDraw->pScreen) return BadMatch;
+ :
+ : nf = pa->nFormats;
+ : pf = pa->pFormats;
+ :
+ : while (nf--)
+ : {
+ : if ((pf->depth == pDraw->depth)
+ :#if 0
+ : && ((pDraw->type == DRAWABLE_PIXMAP) ||
+ : (wVisual(((WindowPtr)pDraw)) == pf->visual))
+ :#endif
+ : )
+ : return Success;
+ : pf++;
+ : }
+ :
+ : return BadMatch;
+ :
+ :}
+ :
+ :int
+ :XvdiSetPortAttribute(
+ : ClientPtr client,
+ : XvPortPtr pPort,
+ : Atom attribute,
+ : INT32 value
+ :){
+ :
+ : XvdiSendPortNotify(pPort, attribute, value);
+ :
+ : return
+ : (* pPort->pAdaptor->ddSetPortAttribute)(client, pPort, attribute, value);
+ :
+ :}
+ :
+ :int
+ :XvdiGetPortAttribute(
+ : ClientPtr client,
+ : XvPortPtr pPort,
+ : Atom attribute,
+ : INT32 *p_value
+ :){
+ :
+ : return
+ : (* pPort->pAdaptor->ddGetPortAttribute)(client, pPort, attribute, p_value);
+ :
+ :}
+ :
+ :static void
+ :WriteSwappedVideoNotifyEvent(xvEvent *from, xvEvent *to)
+ :
+ :{
+ :
+ : to->u.u.type = from->u.u.type;
+ : to->u.u.detail = from->u.u.detail;
+ : cpswaps(from->u.videoNotify.sequenceNumber,
+ : to->u.videoNotify.sequenceNumber);
+ : cpswapl(from->u.videoNotify.time, to->u.videoNotify.time);
+ : cpswapl(from->u.videoNotify.drawable, to->u.videoNotify.drawable);
+ : cpswapl(from->u.videoNotify.port, to->u.videoNotify.port);
+ :
+ :}
+ :
+ :static void
+ :WriteSwappedPortNotifyEvent(xvEvent *from, xvEvent *to)
+ :
+ :{
+ :
+ : to->u.u.type = from->u.u.type;
+ : to->u.u.detail = from->u.u.detail;
+ : cpswaps(from->u.portNotify.sequenceNumber, to->u.portNotify.sequenceNumber);
+ : cpswapl(from->u.portNotify.time, to->u.portNotify.time);
+ : cpswapl(from->u.portNotify.port, to->u.portNotify.port);
+ : cpswapl(from->u.portNotify.value, to->u.portNotify.value);
+ :
+ :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/render/mirect.c"
+ *
+ * 24 0.0261
+ */
+
+
+ :/*
+ : *
+ : * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ : *
+ : * 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 Keith Packard not be used in
+ : * advertising or publicity pertaining to distribution of the software without
+ : * specific, written prior permission. Keith Packard makes no
+ : * representations about the suitability of this software for any purpose. It
+ : * is provided "as is" without express or implied warranty.
+ : *
+ : * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ : * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ : * EVENT SHALL KEITH PACKARD 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.
+ : */
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include "scrnintstr.h"
+ :#include "gcstruct.h"
+ :#include "pixmapstr.h"
+ :#include "windowstr.h"
+ :#include "mi.h"
+ :#include "picturestr.h"
+ :#include "mipict.h"
+ :
+ :static void
+ :miColorRects (PicturePtr pDst,
+ : PicturePtr pClipPict,
+ : xRenderColor *color,
+ : int nRect,
+ : xRectangle *rects,
+ : int xoff,
+ : int yoff)
+ 1 0.0011 :{ /* miColorRects total: 15 0.0163 */
+ : ScreenPtr pScreen = pDst->pDrawable->pScreen;
+ : CARD32 pixel;
+ : GCPtr pGC;
+ : CARD32 tmpval[5];
+ : RegionPtr pClip;
+ : unsigned long mask;
+ :
+ 1 0.0011 : miRenderColorToPixel (pDst->pFormat, color, &pixel);
+ :
+ : pGC = GetScratchGC (pDst->pDrawable->depth, pScreen);
+ : if (!pGC)
+ : return;
+ : tmpval[0] = GXcopy;
+ : tmpval[1] = pixel;
+ 1 0.0011 : tmpval[2] = pDst->subWindowMode;
+ : mask = GCFunction | GCForeground | GCSubwindowMode;
+ 4 0.0044 : if (pClipPict->clientClipType == CT_REGION)
+ : {
+ 1 0.0011 : tmpval[3] = pDst->clipOrigin.x - xoff;
+ : tmpval[4] = pDst->clipOrigin.y - yoff;
+ : mask |= GCClipXOrigin|GCClipYOrigin;
+ :
+ : pClip = REGION_CREATE (pScreen, NULL, 1);
+ : REGION_COPY (pScreen, pClip,
+ : (RegionPtr) pClipPict->clientClip);
+ : (*pGC->funcs->ChangeClip) (pGC, CT_REGION, pClip, 0);
+ : }
+ :
+ 1 0.0011 : ChangeGC (pGC, mask, tmpval);
+ 2 0.0022 : ValidateGC (pDst->pDrawable, pGC);
+ 1 0.0011 : if (xoff || yoff)
+ : {
+ : int i;
+ : for (i = 0; i < nRect; i++)
+ : {
+ : rects[i].x -= xoff;
+ : rects[i].y -= yoff;
+ : }
+ : }
+ 3 0.0033 : (*pGC->ops->PolyFillRect) (pDst->pDrawable, pGC, nRect, rects);
+ : if (xoff || yoff)
+ : {
+ : int i;
+ : for (i = 0; i < nRect; i++)
+ : {
+ : rects[i].x += xoff;
+ : rects[i].y += yoff;
+ : }
+ : }
+ : FreeScratchGC (pGC);
+ :}
+ :
+ :_X_EXPORT void
+ :miCompositeRects (CARD8 op,
+ : PicturePtr pDst,
+ : xRenderColor *color,
+ : int nRect,
+ : xRectangle *rects)
+ 3 0.0033 :{ /* miCompositeRects total: 9 0.0098 */
+ : ScreenPtr pScreen = pDst->pDrawable->pScreen;
+ :
+ : if (color->alpha == 0xffff)
+ : {
+ 2 0.0022 : if (op == PictOpOver)
+ : op = PictOpSrc;
+ : }
+ 1 0.0011 : if (op == PictOpClear)
+ : color->red = color->green = color->blue = color->alpha = 0;
+ :
+ 1 0.0011 : if (op == PictOpSrc || op == PictOpClear)
+ : {
+ : miColorRects (pDst, pDst, color, nRect, rects, 0, 0);
+ 1 0.0011 : if (pDst->alphaMap)
+ : miColorRects (pDst->alphaMap, pDst,
+ : color, nRect, rects,
+ : pDst->alphaOrigin.x,
+ : pDst->alphaOrigin.y);
+ : }
+ : else
+ : {
+ : PictFormatPtr rgbaFormat;
+ : PixmapPtr pPixmap;
+ : PicturePtr pSrc;
+ : xRectangle one;
+ : int error;
+ : Pixel pixel;
+ : GCPtr pGC;
+ : CARD32 tmpval[2];
+ :
+ : rgbaFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8);
+ : if (!rgbaFormat)
+ : goto bail1;
+ :
+ : pPixmap = (*pScreen->CreatePixmap) (pScreen, 1, 1,
+ : rgbaFormat->depth);
+ : if (!pPixmap)
+ : goto bail2;
+ :
+ : miRenderColorToPixel (rgbaFormat, color, &pixel);
+ :
+ : pGC = GetScratchGC (rgbaFormat->depth, pScreen);
+ : if (!pGC)
+ : goto bail3;
+ : tmpval[0] = GXcopy;
+ : tmpval[1] = pixel;
+ :
+ : ChangeGC (pGC, GCFunction | GCForeground, tmpval);
+ : ValidateGC (&pPixmap->drawable, pGC);
+ : one.x = 0;
+ : one.y = 0;
+ : one.width = 1;
+ : one.height = 1;
+ : (*pGC->ops->PolyFillRect) (&pPixmap->drawable, pGC, 1, &one);
+ :
+ : tmpval[0] = xTrue;
+ : pSrc = CreatePicture (0, &pPixmap->drawable, rgbaFormat,
+ : CPRepeat, tmpval, 0, &error);
+ :
+ : if (!pSrc)
+ : goto bail4;
+ :
+ : while (nRect--)
+ : {
+ : CompositePicture (op, pSrc, 0, pDst, 0, 0, 0, 0,
+ : rects->x,
+ : rects->y,
+ : rects->width,
+ : rects->height);
+ : rects++;
+ : }
+ :
+ : FreePicture ((pointer) pSrc, 0);
+ :bail4:
+ : FreeScratchGC (pGC);
+ :bail3:
+ : (*pScreen->DestroyPixmap) (pPixmap);
+ :bail2:
+ :bail1:
+ : ;
+ : }
+ 1 0.0011 :}
+/*
+ * Total samples for file : "/home/cworth/src/pixman/pixman/pixman-utils.c"
+ *
+ * 24 0.0261
+ */
+
+
+ :/*
+ : * Copyright © 2000 SuSE, Inc.
+ : *
+ : * 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 SuSE not be used in advertising or
+ : * publicity pertaining to distribution of the software without specific,
+ : * written prior permission. SuSE makes no representations about the
+ : * suitability of this software for any purpose. It is provided "as is"
+ : * without express or implied warranty.
+ : *
+ : * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ : * 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: Keith Packard, SuSE, Inc.
+ : */
+ :
+ :#include <config.h>
+ :#include "pixman.h"
+ :#include "pixman-private.h"
+ :#include "pixman-mmx.h"
+ :
+ :pixman_bool_t
+ :pixman_transform_point_3d (pixman_transform_t *transform,
+ : pixman_vector_t *vector)
+ :{
+ : pixman_vector_t result;
+ : int i, j;
+ : pixman_fixed_32_32_t partial;
+ : pixman_fixed_48_16_t v;
+ :
+ : for (j = 0; j < 3; j++)
+ : {
+ : v = 0;
+ : for (i = 0; i < 3; i++)
+ : {
+ : partial = ((pixman_fixed_48_16_t) transform->matrix[j][i] *
+ : (pixman_fixed_48_16_t) vector->vector[i]);
+ : v += partial >> 16;
+ : }
+ :
+ : if (v > pixman_max_fixed_48_16 || v < pixman_min_fixed_48_16)
+ : return FALSE;
+ :
+ : result.vector[j] = (pixman_fixed_48_16_t) v;
+ : }
+ :
+ : if (!result.vector[2])
+ : return FALSE;
+ :
+ : *vector = result;
+ : return TRUE;
+ :}
+ :
+ :pixman_bool_t
+ :pixman_blt (uint32_t *src_bits,
+ : uint32_t *dst_bits,
+ : int src_stride,
+ : int dst_stride,
+ : int src_bpp,
+ : int dst_bpp,
+ : int src_x, int src_y,
+ : int dst_x, int dst_y,
+ : int width, int height)
+ :{
+ :#ifdef USE_MMX
+ : if (pixman_have_mmx())
+ : {
+ : return pixman_blt_mmx (src_bits, dst_bits, src_stride, dst_stride, src_bpp, dst_bpp,
+ : src_x, src_y, dst_x, dst_y, width, height);
+ : }
+ : else
+ :#endif
+ : return FALSE;
+ :}
+ :
+ :static void
+ :pixman_fill8 (uint32_t *bits,
+ : int stride,
+ : int x,
+ : int y,
+ : int width,
+ : int height,
+ : uint32_t xor)
+ :{
+ : int byte_stride = stride * sizeof (uint32_t);
+ : uint8_t *dst = (uint8_t *) bits;
+ : uint8_t v = xor & 0xff;
+ : int i;
+ :
+ : dst = dst + y * byte_stride + x;
+ :
+ : while (height--)
+ : {
+ : for (i = 0; i < width; ++i)
+ : dst[i] = v;
+ :
+ : dst += byte_stride;
+ : }
+ :}
+ :
+ :static void
+ :pixman_fill16 (uint32_t *bits,
+ : int stride,
+ : int x,
+ : int y,
+ : int width,
+ : int height,
+ : uint32_t xor)
+ :{
+ : int short_stride = (stride * sizeof (uint32_t)) / sizeof (uint16_t);
+ : uint16_t *dst = (uint16_t *)bits;
+ : uint16_t v = xor & 0xffff;
+ : int i;
+ :
+ : dst = dst + y * short_stride + x;
+ :
+ : while (height--)
+ : {
+ : for (i = 0; i < width; ++i)
+ : dst[i] = v;
+ :
+ : dst += short_stride;
+ : }
+ :}
+ :
+ :static void
+ :pixman_fill32 (uint32_t *bits,
+ : int stride,
+ : int x,
+ : int y,
+ : int width,
+ : int height,
+ : uint32_t xor)
+ :{
+ : int i;
+ :
+ : bits = bits + y * stride + x;
+ :
+ : while (height--)
+ : {
+ : for (i = 0; i < width; ++i)
+ : bits[i] = xor;
+ :
+ : bits += stride;
+ : }
+ :}
+ :
+ :pixman_bool_t
+ :pixman_fill (uint32_t *bits,
+ : int stride,
+ : int bpp,
+ : int x,
+ : int y,
+ : int width,
+ : int height,
+ : uint32_t xor)
+ :{
+ :#if 0
+ : printf ("filling: %d %d %d %d (stride: %d, bpp: %d) pixel: %x\n",
+ : x, y, width, height, stride, bpp, xor);
+ :#endif
+ :
+ :#ifdef USE_MMX
+ : if (!pixman_have_mmx() || !pixman_fill_mmx (bits, stride, bpp, x, y, width, height, xor))
+ :#endif
+ : {
+ : switch (bpp)
+ : {
+ : case 8:
+ : pixman_fill8 (bits, stride, x, y, width, height, xor);
+ : break;
+ :
+ : case 16:
+ : pixman_fill16 (bits, stride, x, y, width, height, xor);
+ : break;
+ :
+ : case 32:
+ : pixman_fill32 (bits, stride, x, y, width, height, xor);
+ : break;
+ :
+ : default:
+ : return FALSE;
+ : break;
+ : }
+ : }
+ :
+ : return TRUE;
+ :}
+ :
+ :
+ :/*
+ : * Compute the smallest value no less than y which is on a
+ : * grid row
+ : */
+ :
+ :pixman_fixed_t
+ :pixman_sample_ceil_y (pixman_fixed_t y, int n)
+ :{ /* pixman_sample_ceil_y total: 1 0.0011 */
+ : pixman_fixed_t f = pixman_fixed_frac(y);
+ : pixman_fixed_t i = pixman_fixed_floor(y);
+ :
+ 1 0.0011 : f = ((f + Y_FRAC_FIRST(n)) / STEP_Y_SMALL(n)) * STEP_Y_SMALL(n) + Y_FRAC_FIRST(n);
+ : if (f > Y_FRAC_LAST(n))
+ : {
+ : f = Y_FRAC_FIRST(n);
+ : i += pixman_fixed_1;
+ : }
+ : return (i | f);
+ :}
+ :
+ :#define _div(a,b) ((a) >= 0 ? (a) / (b) : -((-(a) + (b) - 1) / (b)))
+ :
+ :/*
+ : * Compute the largest value no greater than y which is on a
+ : * grid row
+ : */
+ :pixman_fixed_t
+ :pixman_sample_floor_y (pixman_fixed_t y, int n)
+ :{ /* pixman_sample_floor_y total: 5 0.0054 */
+ : pixman_fixed_t f = pixman_fixed_frac(y);
+ 1 0.0011 : pixman_fixed_t i = pixman_fixed_floor (y);
+ :
+ 4 0.0044 : f = _div(f - Y_FRAC_FIRST(n), STEP_Y_SMALL(n)) * STEP_Y_SMALL(n) + Y_FRAC_FIRST(n);
+ : if (f < Y_FRAC_FIRST(n))
+ : {
+ : f = Y_FRAC_LAST(n);
+ : i -= pixman_fixed_1;
+ : }
+ : return (i | f);
+ :}
+ :
+ :/*
+ : * Step an edge by any amount (including negative values)
+ : */
+ :void
+ :pixman_edge_step (pixman_edge_t *e, int n)
+ :{ /* pixman_edge_step total: 3 0.0033 */
+ : pixman_fixed_48_16_t ne;
+ :
+ : e->x += n * e->stepx;
+ :
+ : ne = e->e + n * (pixman_fixed_48_16_t) e->dx;
+ :
+ : if (n >= 0)
+ : {
+ 1 0.0011 : if (ne > 0)
+ : {
+ 2 0.0022 : int nx = (ne + e->dy - 1) / e->dy;
+ : e->e = ne - nx * (pixman_fixed_48_16_t) e->dy;
+ : e->x += nx * e->signdx;
+ : }
+ : }
+ : else
+ : {
+ : if (ne <= -e->dy)
+ : {
+ : int nx = (-ne) / e->dy;
+ : e->e = ne + nx * (pixman_fixed_48_16_t) e->dy;
+ : e->x -= nx * e->signdx;
+ : }
+ : }
+ :}
+ :
+ :/*
+ : * A private routine to initialize the multi-step
+ : * elements of an edge structure
+ : */
+ :static void
+ :_pixman_edge_tMultiInit (pixman_edge_t *e, int n, pixman_fixed_t *stepx_p, pixman_fixed_t *dx_p)
+ 2 0.0022 :{ /* _pixman_edge_tMultiInit total: 7 0.0076 */
+ : pixman_fixed_t stepx;
+ : pixman_fixed_48_16_t ne;
+ :
+ 2 0.0022 : ne = n * (pixman_fixed_48_16_t) e->dx;
+ : stepx = n * e->stepx;
+ : if (ne > 0)
+ : {
+ 1 0.0011 : int nx = ne / e->dy;
+ : ne -= nx * e->dy;
+ 1 0.0011 : stepx += nx * e->signdx;
+ : }
+ 1 0.0011 : *dx_p = ne;
+ : *stepx_p = stepx;
+ :}
+ :
+ :/*
+ : * Initialize one edge structure given the line endpoints and a
+ : * starting y value
+ : */
+ :void
+ :pixman_edge_init (pixman_edge_t *e,
+ : int n,
+ : pixman_fixed_t y_start,
+ : pixman_fixed_t x_top,
+ : pixman_fixed_t y_top,
+ : pixman_fixed_t x_bot,
+ : pixman_fixed_t y_bot)
+ 2 0.0022 :{ /* pixman_edge_init total: 7 0.0076 */
+ : pixman_fixed_t dx, dy;
+ :
+ : e->x = x_top;
+ : e->e = 0;
+ : dx = x_bot - x_top;
+ : dy = y_bot - y_top;
+ : e->dy = dy;
+ : e->dx = 0;
+ : if (dy)
+ : {
+ : if (dx >= 0)
+ : {
+ : e->signdx = 1;
+ : e->stepx = dx / dy;
+ : e->dx = dx % dy;
+ : e->e = -dy;
+ : }
+ : else
+ : {
+ 1 0.0011 : e->signdx = -1;
+ : e->stepx = -(-dx / dy);
+ : e->dx = -dx % dy;
+ : e->e = 0;
+ : }
+ :
+ 3 0.0033 : _pixman_edge_tMultiInit (e, STEP_Y_SMALL(n), &e->stepx_small, &e->dx_small);
+ : _pixman_edge_tMultiInit (e, STEP_Y_BIG(n), &e->stepx_big, &e->dx_big);
+ : }
+ 1 0.0011 : pixman_edge_step (e, y_start - y_top);
+ :}
+ :
+ :/*
+ : * Initialize one edge structure given a line, starting y value
+ : * and a pixel offset for the line
+ : */
+ :void
+ :pixman_line_fixed_edge_init (pixman_edge_t *e,
+ : int n,
+ : pixman_fixed_t y,
+ : const pixman_line_fixed_t *line,
+ : int x_off,
+ : int y_off)
+ 1 0.0011 :{ /* pixman_line_fixed_edge_init total: 1 0.0011 */
+ : pixman_fixed_t x_off_fixed = pixman_int_to_fixed(x_off);
+ : pixman_fixed_t y_off_fixed = pixman_int_to_fixed(y_off);
+ : const pixman_point_fixed_t *top, *bot;
+ :
+ : if (line->p1.y <= line->p2.y)
+ : {
+ : top = &line->p1;
+ : bot = &line->p2;
+ : }
+ : else
+ : {
+ : top = &line->p2;
+ : bot = &line->p1;
+ : }
+ : pixman_edge_init (e, n, y,
+ : top->x + x_off_fixed,
+ : top->y + y_off_fixed,
+ : bot->x + x_off_fixed,
+ : bot->y + y_off_fixed);
+ :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/os/utils.c"
+ *
+ * 21 0.0229
+ */
+
+
+ :/*
+ :
+ :Copyright 1987, 1998 The Open Group
+ :
+ :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.
+ :
+ :The above copyright notice and this permission notice shall be included
+ :in all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ :OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ :MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ :IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ :OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ :ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ :OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of The Open Group shall
+ :not be used in advertising or otherwise to promote the sale, use or
+ :other dealings in this Software without prior written authorization
+ :from The Open Group.
+ :
+ :
+ :Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
+ :Copyright 1994 Quarterdeck Office Systems.
+ :
+ : All Rights Reserved
+ :
+ :Permission to use, copy, modify, and distribute this software and its
+ :documentation for any purpose and without fee is hereby granted,
+ :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 names of Digital and
+ :Quarterdeck not be used in advertising or publicity pertaining to
+ :distribution of the software without specific, written prior
+ :permission.
+ :
+ :DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ :SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ :FITNESS, IN NO EVENT SHALL DIGITAL 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.
+ :
+ :*/
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#ifdef __CYGWIN__
+ :#include <stdlib.h>
+ :#include <signal.h>
+ :#endif
+ :
+ :#if defined(WIN32) && !defined(__CYGWIN__)
+ :#include <X11/Xwinsock.h>
+ :#endif
+ :#include <X11/Xos.h>
+ :#include <stdio.h>
+ :#include <time.h>
+ :#if !defined(WIN32) || !defined(__MINGW32__)
+ :#include <sys/time.h>
+ :#include <sys/resource.h>
+ :#endif
+ :#include "misc.h"
+ :#include <X11/X.h>
+ :#define XSERV_t
+ :#define TRANS_SERVER
+ :#define TRANS_REOPEN
+ :#include <X11/Xtrans/Xtrans.h>
+ :#include "input.h"
+ :#include "dixfont.h"
+ :#include "osdep.h"
+ :#include "extension.h"
+ :#ifdef X_POSIX_C_SOURCE
+ :#define _POSIX_C_SOURCE X_POSIX_C_SOURCE
+ :#include <signal.h>
+ :#undef _POSIX_C_SOURCE
+ :#else
+ :#if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE)
+ :#include <signal.h>
+ :#else
+ :#define _POSIX_SOURCE
+ :#include <signal.h>
+ :#undef _POSIX_SOURCE
+ :#endif
+ :#endif
+ :#ifndef WIN32
+ :#include <sys/wait.h>
+ :#endif
+ :#if !defined(SYSV) && !defined(WIN32) && !defined(Lynx) && !defined(QNX4)
+ :#include <sys/resource.h>
+ :#endif
+ :#include <sys/stat.h>
+ :#include <ctype.h> /* for isspace */
+ :#include <stdarg.h>
+ :
+ :#if defined(DGUX)
+ :#include <sys/resource.h>
+ :#include <netdb.h>
+ :#endif
+ :
+ :#include <stdlib.h> /* for malloc() */
+ :
+ :#if defined(TCPCONN) || defined(STREAMSCONN)
+ :# ifndef WIN32
+ :# include <netdb.h>
+ :# endif
+ :#endif
+ :
+ :#include "opaque.h"
+ :
+ :#ifdef SMART_SCHEDULE
+ :#include "dixstruct.h"
+ :#endif
+ :
+ :#ifdef XKB
+ :#include <xkbsrv.h>
+ :#endif
+ :#ifdef XCSECURITY
+ :#include "securitysrv.h"
+ :#endif
+ :
+ :#ifdef RENDER
+ :#include "picture.h"
+ :#endif
+ :
+ :#ifdef XPRINT
+ :#include "DiPrint.h"
+ :#endif
+ :
+ :_X_EXPORT Bool noTestExtensions;
+ :#ifdef BIGREQS
+ :_X_EXPORT Bool noBigReqExtension = FALSE;
+ :#endif
+ :#ifdef COMPOSITE
+ :_X_EXPORT Bool noCompositeExtension = FALSE;
+ :#endif
+ :
+ :#ifdef DAMAGE
+ :_X_EXPORT Bool noDamageExtension = FALSE;
+ :#endif
+ :#ifdef DBE
+ :_X_EXPORT Bool noDbeExtension = FALSE;
+ :#endif
+ :#ifdef DPMSExtension
+ :_X_EXPORT Bool noDPMSExtension = FALSE;
+ :#endif
+ :#ifdef EVI
+ :_X_EXPORT Bool noEVIExtension = FALSE;
+ :#endif
+ :#ifdef FONTCACHE
+ :_X_EXPORT Bool noFontCacheExtension = FALSE;
+ :#endif
+ :#ifdef GLXEXT
+ :_X_EXPORT Bool noGlxExtension = FALSE;
+ :#endif
+ :#ifdef SCREENSAVER
+ :_X_EXPORT Bool noScreenSaverExtension = FALSE;
+ :#endif
+ :#ifdef MITSHM
+ :_X_EXPORT Bool noMITShmExtension = FALSE;
+ :#endif
+ :#ifdef MITMISC
+ :_X_EXPORT Bool noMITMiscExtension = FALSE;
+ :#endif
+ :#ifdef MULTIBUFFER
+ :_X_EXPORT Bool noMultibufferExtension = FALSE;
+ :#endif
+ :#ifdef RANDR
+ :_X_EXPORT Bool noRRExtension = FALSE;
+ :#endif
+ :#ifdef RENDER
+ :_X_EXPORT Bool noRenderExtension = FALSE;
+ :#endif
+ :#ifdef SHAPE
+ :_X_EXPORT Bool noShapeExtension = FALSE;
+ :#endif
+ :#ifdef XCSECURITY
+ :_X_EXPORT Bool noSecurityExtension = FALSE;
+ :#endif
+ :#ifdef XSYNC
+ :_X_EXPORT Bool noSyncExtension = FALSE;
+ :#endif
+ :#ifdef TOGCUP
+ :_X_EXPORT Bool noXcupExtension = FALSE;
+ :#endif
+ :#ifdef RES
+ :_X_EXPORT Bool noResExtension = FALSE;
+ :#endif
+ :#ifdef XAPPGROUP
+ :_X_EXPORT Bool noXagExtension = FALSE;
+ :#endif
+ :#ifdef XCMISC
+ :_X_EXPORT Bool noXCMiscExtension = FALSE;
+ :#endif
+ :#ifdef XEVIE
+ :/* Xevie is disabled by default for now until the
+ : * interface is stable */
+ :_X_EXPORT Bool noXevieExtension = TRUE;
+ :#endif
+ :#ifdef XF86BIGFONT
+ :_X_EXPORT Bool noXFree86BigfontExtension = FALSE;
+ :#endif
+ :#ifdef XFreeXDGA
+ :_X_EXPORT Bool noXFree86DGAExtension = FALSE;
+ :#endif
+ :#ifdef XF86DRI
+ :_X_EXPORT Bool noXFree86DRIExtension = FALSE;
+ :#endif
+ :#ifdef XF86MISC
+ :_X_EXPORT Bool noXFree86MiscExtension = FALSE;
+ :#endif
+ :#ifdef XF86VIDMODE
+ :_X_EXPORT Bool noXFree86VidModeExtension = FALSE;
+ :#endif
+ :#ifdef XFIXES
+ :_X_EXPORT Bool noXFixesExtension = FALSE;
+ :#endif
+ :/* |noXkbExtension| is defined in xc/programs/Xserver/xkb/xkbInit.c */
+ :#ifdef PANORAMIX
+ :/* Xinerama is disabled by default unless enabled via +xinerama */
+ :_X_EXPORT Bool noPanoramiXExtension = TRUE;
+ :#endif
+ :#ifdef XINPUT
+ :_X_EXPORT Bool noXInputExtension = FALSE;
+ :#endif
+ :#ifdef XIDLE
+ :_X_EXPORT Bool noXIdleExtension = FALSE;
+ :#endif
+ :#ifdef XV
+ :_X_EXPORT Bool noXvExtension = FALSE;
+ :#endif
+ :
+ :#define X_INCLUDE_NETDB_H
+ :#include <X11/Xos_r.h>
+ :
+ :#include <errno.h>
+ :
+ :Bool CoreDump;
+ :
+ :#ifdef PANORAMIX
+ :Bool PanoramiXExtensionDisabledHack = FALSE;
+ :#endif
+ :
+ :int auditTrailLevel = 1;
+ :
+ :_X_EXPORT Bool Must_have_memory = FALSE;
+ :
+ :#ifdef AIXV3
+ :int SyncOn = 0;
+ :extern int SelectWaitTime;
+ :#endif
+ :
+ :#if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED)
+ :#define HAS_SAVED_IDS_AND_SETEUID
+ :#endif
+ :
+ :#ifdef MEMBUG
+ :#define MEM_FAIL_SCALE 100000
+ :long Memory_fail = 0;
+ :#include <stdlib.h> /* for random() */
+ :#endif
+ :
+ :static char *dev_tty_from_init = NULL; /* since we need to parse it anyway */
+ :
+ :OsSigHandlerPtr
+ :OsSignal(sig, handler)
+ : int sig;
+ : OsSigHandlerPtr handler;
+ :{
+ :#ifdef X_NOT_POSIX
+ : return signal(sig, handler);
+ :#else
+ : struct sigaction act, oact;
+ :
+ : sigemptyset(&act.sa_mask);
+ : if (handler != SIG_IGN)
+ : sigaddset(&act.sa_mask, sig);
+ : act.sa_flags = 0;
+ : act.sa_handler = handler;
+ : sigaction(sig, &act, &oact);
+ : return oact.sa_handler;
+ :#endif
+ :}
+ :
+ :#ifdef SERVER_LOCK
+ :/*
+ : * Explicit support for a server lock file like the ones used for UUCP.
+ : * For architectures with virtual terminals that can run more than one
+ : * server at a time. This keeps the servers from stomping on each other
+ : * if the user forgets to give them different display numbers.
+ : */
+ :#define LOCK_DIR "/tmp"
+ :#define LOCK_TMP_PREFIX "/.tX"
+ :#define LOCK_PREFIX "/.X"
+ :#define LOCK_SUFFIX "-lock"
+ :
+ :#if defined(DGUX)
+ :#include <limits.h>
+ :#include <sys/param.h>
+ :#endif
+ :
+ :#ifndef PATH_MAX
+ :#ifndef Lynx
+ :#include <sys/param.h>
+ :#else
+ :#include <param.h>
+ :#endif
+ :#ifndef PATH_MAX
+ :#ifdef MAXPATHLEN
+ :#define PATH_MAX MAXPATHLEN
+ :#else
+ :#define PATH_MAX 1024
+ :#endif
+ :#endif
+ :#endif
+ :
+ :static Bool StillLocking = FALSE;
+ :static char LockFile[PATH_MAX];
+ :static Bool nolock = FALSE;
+ :
+ :/*
+ : * LockServer --
+ : * Check if the server lock file exists. If so, check if the PID
+ : * contained inside is valid. If so, then die. Otherwise, create
+ : * the lock file containing the PID.
+ : */
+ :void
+ :LockServer(void)
+ :{
+ : char tmp[PATH_MAX], pid_str[12];
+ : int lfd, i, haslock, l_pid, t;
+ : char *tmppath = NULL;
+ : int len;
+ : char port[20];
+ :
+ : if (nolock) return;
+ : /*
+ : * Path names
+ : */
+ : tmppath = LOCK_DIR;
+ :
+ : sprintf(port, "%d", atoi(display));
+ : len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) :
+ : strlen(LOCK_TMP_PREFIX);
+ : len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1;
+ : if (len > sizeof(LockFile))
+ : FatalError("Display name `%s' is too long\n", port);
+ : (void)sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
+ : (void)sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
+ :
+ : /*
+ : * Create a temporary file containing our PID. Attempt three times
+ : * to create the file.
+ : */
+ : StillLocking = TRUE;
+ : i = 0;
+ : do {
+ : i++;
+ : lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
+ : if (lfd < 0)
+ : sleep(2);
+ : else
+ : break;
+ : } while (i < 3);
+ : if (lfd < 0) {
+ : unlink(tmp);
+ : i = 0;
+ : do {
+ : i++;
+ : lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
+ : if (lfd < 0)
+ : sleep(2);
+ : else
+ : break;
+ : } while (i < 3);
+ : }
+ : if (lfd < 0)
+ : FatalError("Could not create lock file in %s\n", tmp);
+ : (void) sprintf(pid_str, "%10ld\n", (long)getpid());
+ : (void) write(lfd, pid_str, 11);
+ :#ifndef USE_CHMOD
+ : (void) fchmod(lfd, 0444);
+ :#else
+ : (void) chmod(tmp, 0444);
+ :#endif
+ : (void) close(lfd);
+ :
+ : /*
+ : * OK. Now the tmp file exists. Try three times to move it in place
+ : * for the lock.
+ : */
+ : i = 0;
+ : haslock = 0;
+ : while ((!haslock) && (i++ < 3)) {
+ : haslock = (link(tmp,LockFile) == 0);
+ : if (haslock) {
+ : /*
+ : * We're done.
+ : */
+ : break;
+ : }
+ : else {
+ : /*
+ : * Read the pid from the existing file
+ : */
+ : lfd = open(LockFile, O_RDONLY);
+ : if (lfd < 0) {
+ : unlink(tmp);
+ : FatalError("Can't read lock file %s\n", LockFile);
+ : }
+ : pid_str[0] = '\0';
+ : if (read(lfd, pid_str, 11) != 11) {
+ : /*
+ : * Bogus lock file.
+ : */
+ : unlink(LockFile);
+ : close(lfd);
+ : continue;
+ : }
+ : pid_str[11] = '\0';
+ : sscanf(pid_str, "%d", &l_pid);
+ : close(lfd);
+ :
+ : /*
+ : * Now try to kill the PID to see if it exists.
+ : */
+ : errno = 0;
+ : t = kill(l_pid, 0);
+ : if ((t< 0) && (errno == ESRCH)) {
+ : /*
+ : * Stale lock file.
+ : */
+ : unlink(LockFile);
+ : continue;
+ : }
+ : else if (((t < 0) && (errno == EPERM)) || (t == 0)) {
+ : /*
+ : * Process is still active.
+ : */
+ : unlink(tmp);
+ : FatalError("Server is already active for display %s\n%s %s\n%s\n",
+ : port, "\tIf this server is no longer running, remove",
+ : LockFile, "\tand start again.");
+ : }
+ : }
+ : }
+ : unlink(tmp);
+ : if (!haslock)
+ : FatalError("Could not create server lock file: %s\n", LockFile);
+ : StillLocking = FALSE;
+ :}
+ :
+ :/*
+ : * UnlockServer --
+ : * Remove the server lock file.
+ : */
+ :void
+ :UnlockServer(void)
+ :{
+ : if (nolock) return;
+ :
+ : if (!StillLocking){
+ :
+ : (void) unlink(LockFile);
+ : }
+ :}
+ :#endif /* SERVER_LOCK */
+ :
+ :/* Force connections to close on SIGHUP from init */
+ :
+ :/*ARGSUSED*/
+ :SIGVAL
+ :AutoResetServer (int sig)
+ :{
+ : int olderrno = errno;
+ :
+ : dispatchException |= DE_RESET;
+ : isItTimeToYield = TRUE;
+ :#ifdef GPROF
+ : chdir ("/tmp");
+ : exit (0);
+ :#endif
+ :#if defined(SYSV) && defined(X_NOT_POSIX)
+ : OsSignal (SIGHUP, AutoResetServer);
+ :#endif
+ : errno = olderrno;
+ :}
+ :
+ :/* Force connections to close and then exit on SIGTERM, SIGINT */
+ :
+ :/*ARGSUSED*/
+ :_X_EXPORT SIGVAL
+ :GiveUp(int sig)
+ :{
+ : int olderrno = errno;
+ :
+ : dispatchException |= DE_TERMINATE;
+ : isItTimeToYield = TRUE;
+ :#if defined(SYSV) && defined(X_NOT_POSIX)
+ : if (sig)
+ : OsSignal(sig, SIG_IGN);
+ :#endif
+ : errno = olderrno;
+ :}
+ :
+ :#if defined WIN32 && defined __MINGW32__
+ :_X_EXPORT CARD32
+ :GetTimeInMillis (void)
+ :{
+ : return GetTickCount ();
+ :}
+ :#else
+ :_X_EXPORT CARD32
+ :GetTimeInMillis(void)
+ 1 0.0011 :{ /* GetTimeInMillis total: 1 0.0011 */
+ : struct timeval tv;
+ :
+ :#ifdef MONOTONIC_CLOCK
+ : struct timespec tp;
+ : if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
+ : return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
+ :#endif
+ :
+ : X_GETTIMEOFDAY(&tv);
+ : return(tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+ :}
+ :#endif
+ :
+ :_X_EXPORT void
+ :AdjustWaitForDelay (pointer waitTime, unsigned long newdelay)
+ :{
+ : static struct timeval delay_val;
+ : struct timeval **wt = (struct timeval **) waitTime;
+ : unsigned long olddelay;
+ :
+ : if (*wt == NULL)
+ : {
+ : delay_val.tv_sec = newdelay / 1000;
+ : delay_val.tv_usec = 1000 * (newdelay % 1000);
+ : *wt = &delay_val;
+ : }
+ : else
+ : {
+ : olddelay = (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000;
+ : if (newdelay < olddelay)
+ : {
+ : (*wt)->tv_sec = newdelay / 1000;
+ : (*wt)->tv_usec = 1000 * (newdelay % 1000);
+ : }
+ : }
+ :}
+ :
+ :void UseMsg(void)
+ :{
+ :#if !defined(AIXrt) && !defined(AIX386)
+ : ErrorF("use: X [:<display>] [option]\n");
+ : ErrorF("-a # mouse acceleration (pixels)\n");
+ : ErrorF("-ac disable access control restrictions\n");
+ :#ifdef MEMBUG
+ : ErrorF("-alloc int chance alloc should fail\n");
+ :#endif
+ : ErrorF("-audit int set audit trail level\n");
+ : ErrorF("-auth file select authorization file\n");
+ : ErrorF("-br create root window with black background\n");
+ : ErrorF("+bs enable any backing store support\n");
+ : ErrorF("-bs disable any backing store support\n");
+ : ErrorF("-c turns off key-click\n");
+ : ErrorF("c # key-click volume (0-100)\n");
+ : ErrorF("-cc int default color visual class\n");
+ : ErrorF("-co file color database file\n");
+ :#ifdef COMMANDLINE_CHALLENGED_OPERATING_SYSTEMS
+ : ErrorF("-config file read options from file\n");
+ :#endif
+ : ErrorF("-core generate core dump on fatal error\n");
+ : ErrorF("-dpi int screen resolution in dots per inch\n");
+ :#ifdef DPMSExtension
+ : ErrorF("dpms enables VESA DPMS monitor control\n");
+ : ErrorF("-dpms disables VESA DPMS monitor control\n");
+ :#endif
+ : ErrorF("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n");
+ : ErrorF("-f # bell base (0-100)\n");
+ : ErrorF("-fc string cursor font\n");
+ : ErrorF("-fn string default font name\n");
+ : ErrorF("-fp string default font path\n");
+ : ErrorF("-help prints message with these options\n");
+ : ErrorF("-I ignore all remaining arguments\n");
+ :#ifdef RLIMIT_DATA
+ : ErrorF("-ld int limit data space to N Kb\n");
+ :#endif
+ :#ifdef RLIMIT_NOFILE
+ : ErrorF("-lf int limit number of open files to N\n");
+ :#endif
+ :#ifdef RLIMIT_STACK
+ : ErrorF("-ls int limit stack space to N Kb\n");
+ :#endif
+ :#ifdef SERVER_LOCK
+ : ErrorF("-nolock disable the locking mechanism\n");
+ :#endif
+ :#ifndef NOLOGOHACK
+ : ErrorF("-logo enable logo in screen saver\n");
+ : ErrorF("nologo disable logo in screen saver\n");
+ :#endif
+ : ErrorF("-nolisten string don't listen on protocol\n");
+ : ErrorF("-noreset don't reset after last client exists\n");
+ : ErrorF("-reset reset after last client exists\n");
+ : ErrorF("-p # screen-saver pattern duration (minutes)\n");
+ : ErrorF("-pn accept failure to listen on all ports\n");
+ : ErrorF("-nopn reject failure to listen on all ports\n");
+ : ErrorF("-r turns off auto-repeat\n");
+ : ErrorF("r turns on auto-repeat \n");
+ :#ifdef RENDER
+ : ErrorF("-render [default|mono|gray|color] set render color alloc policy\n");
+ :#endif
+ : ErrorF("-s # screen-saver timeout (minutes)\n");
+ :#ifdef XCSECURITY
+ : ErrorF("-sp file security policy file\n");
+ :#endif
+ :#ifdef XPRINT
+ : PrinterUseMsg();
+ :#endif
+ : ErrorF("-su disable any save under support\n");
+ : ErrorF("-t # mouse threshold (pixels)\n");
+ : ErrorF("-terminate terminate at server reset\n");
+ : ErrorF("-to # connection time out\n");
+ : ErrorF("-tst disable testing extensions\n");
+ : ErrorF("ttyxx server started from init on /dev/ttyxx\n");
+ : ErrorF("v video blanking for screen-saver\n");
+ : ErrorF("-v screen-saver without video blanking\n");
+ : ErrorF("-wm WhenMapped default backing-store\n");
+ : ErrorF("-wr create root window with white background\n");
+ : ErrorF("-x string loads named extension at init time \n");
+ : ErrorF("-maxbigreqsize set maximal bigrequest size \n");
+ :#ifdef PANORAMIX
+ : ErrorF("+xinerama Enable XINERAMA extension\n");
+ : ErrorF("-xinerama Disable XINERAMA extension\n");
+ :#endif
+ :#ifdef SMART_SCHEDULE
+ : ErrorF("-dumbSched Disable smart scheduling, enable old behavior\n");
+ : ErrorF("-schedInterval int Set scheduler interval in msec\n");
+ :#endif
+ : ErrorF("+extension name Enable extension\n");
+ : ErrorF("-extension name Disable extension\n");
+ :#ifdef XDMCP
+ : XdmcpUseMsg();
+ :#endif
+ :#endif /* !AIXrt && ! AIX386 */
+ :#ifdef XKB
+ : XkbUseMsg();
+ :#endif
+ : ddxUseMsg();
+ :}
+ :
+ :/* This function performs a rudimentary sanity check
+ : * on the display name passed in on the command-line,
+ : * since this string is used to generate filenames.
+ : * It is especially important that the display name
+ : * not contain a "/" and not start with a "-".
+ : * --kvajk
+ : */
+ :static int
+ :VerifyDisplayName(const char *d)
+ :{
+ : if ( d == (char *)0 ) return( 0 ); /* null */
+ : if ( *d == '\0' ) return( 0 ); /* empty */
+ : if ( *d == '-' ) return( 0 ); /* could be confused for an option */
+ : if ( *d == '.' ) return( 0 ); /* must not equal "." or ".." */
+ : if ( strchr(d, '/') != (char *)0 ) return( 0 ); /* very important!!! */
+ : return( 1 );
+ :}
+ :
+ :/*
+ : * This function is responsible for doing initalisation of any global
+ : * variables at an very early point of server startup (even before
+ : * |ProcessCommandLine()|.
+ : */
+ :void InitGlobals(void)
+ :{
+ : ddxInitGlobals();
+ :}
+ :
+ :
+ :/*
+ : * This function parses the command line. Handles device-independent fields
+ : * and allows ddx to handle additional fields. It is not allowed to modify
+ : * argc or any of the strings pointed to by argv.
+ : */
+ :void
+ :ProcessCommandLine(int argc, char *argv[])
+ :{
+ : int i, skip;
+ :
+ : defaultKeyboardControl.autoRepeat = TRUE;
+ :
+ :#ifdef NO_PART_NET
+ : PartialNetwork = FALSE;
+ :#else
+ : PartialNetwork = TRUE;
+ :#endif
+ :
+ : for ( i = 1; i < argc; i++ )
+ : {
+ : /* call ddx first, so it can peek/override if it wants */
+ : if((skip = ddxProcessArgument(argc, argv, i)))
+ : {
+ : i += (skip - 1);
+ : }
+ : else if(argv[i][0] == ':')
+ : {
+ : /* initialize display */
+ : display = argv[i];
+ : display++;
+ : if( ! VerifyDisplayName( display ) ) {
+ : ErrorF("Bad display name: %s\n", display);
+ : UseMsg();
+ : FatalError("Bad display name, exiting: %s\n", display);
+ : }
+ : }
+ : else if ( strcmp( argv[i], "-a") == 0)
+ : {
+ : if(++i < argc)
+ : defaultPointerControl.num = atoi(argv[i]);
+ : else
+ : UseMsg();
+ : }
+ : else if ( strcmp( argv[i], "-ac") == 0)
+ : {
+ : defeatAccessControl = TRUE;
+ : }
+ :#ifdef MEMBUG
+ : else if ( strcmp( argv[i], "-alloc") == 0)
+ : {
+ : if(++i < argc)
+ : Memory_fail = atoi(argv[i]);
+ : else
+ : UseMsg();
+ : }
+ :#endif
+ : else if ( strcmp( argv[i], "-audit") == 0)
+ : {
+ : if(++i < argc)
+ : auditTrailLevel = atoi(argv[i]);
+ : else
+ : UseMsg();
+ : }
+ : else if ( strcmp( argv[i], "-auth") == 0)
+ : {
+ : if(++i < argc)
+ : InitAuthorization (argv[i]);
+ : else
+ : UseMsg();
+ : }
+ : else if ( strcmp( argv[i], "-br") == 0)
+ : blackRoot = TRUE;
+ : else if ( strcmp( argv[i], "+bs") == 0)
+ : enableBackingStore = TRUE;
+ : else if ( strcmp( argv[i], "-bs") == 0)
+ : disableBackingStore = TRUE;
+ : else if ( strcmp( argv[i], "c") == 0)
+ : {
+ : if(++i < argc)
+ : defaultKeyboardControl.click = atoi(argv[i]);
+ : else
+ : UseMsg();
+ : }
+ : else if ( strcmp( argv[i], "-c") == 0)
+ : {
+ : defaultKeyboardControl.click = 0;
+ : }
+ : else if ( strcmp( argv[i], "-cc") == 0)
+ : {
+ : if(++i < argc)
+ : defaultColorVisualClass = atoi(argv[i]);
+ : else
+ : UseMsg();
+ : }
+ : else if ( strcmp( argv[i], "-co") == 0)
+ : {
+ : if(++i < argc)
+ : rgbPath = argv[i];
+ : else
+ : UseMsg();
+ : }
+ : else if ( strcmp( argv[i], "-core") == 0)
+ : {
+ : CoreDump = TRUE;
+ :#if !defined(WIN32) || !defined(__MINGW32__)
+ : struct rlimit core_limit;
+ : getrlimit (RLIMIT_CORE, &core_limit);
+ : core_limit.rlim_cur = core_limit.rlim_max;
+ : setrlimit (RLIMIT_CORE, &core_limit);
+ :#endif
+ : }
+ : else if ( strcmp( argv[i], "-dpi") == 0)
+ : {
+ : if(++i < argc)
+ : monitorResolution = atoi(argv[i]);
+ : else
+ : UseMsg();
+ : }
+ :#ifdef DPMSExtension
+ : else if ( strcmp( argv[i], "dpms") == 0)
+ : DPMSEnabledSwitch = TRUE;
+ : else if ( strcmp( argv[i], "-dpms") == 0)
+ : DPMSDisabledSwitch = TRUE;
+ :#endif
+ : else if ( strcmp( argv[i], "-deferglyphs") == 0)
+ : {
+ : if(++i >= argc || !ParseGlyphCachingMode(argv[i]))
+ : UseMsg();
+ : }
+ : else if ( strcmp( argv[i], "-f") == 0)
+ : {
+ : if(++i < argc)
+ : defaultKeyboardControl.bell = atoi(argv[i]);
+ : else
+ : UseMsg();
+ : }
+ : else if ( strcmp( argv[i], "-fc") == 0)
+ : {
+ : if(++i < argc)
+ : defaultCursorFont = argv[i];
+ : else
+ : UseMsg();
+ : }
+ : else if ( strcmp( argv[i], "-fn") == 0)
+ : {
+ : if(++i < argc)
+ : defaultTextFont = argv[i];
+ : else
+ : UseMsg();
+ : }
+ : else if ( strcmp( argv[i], "-fp") == 0)
+ : {
+ : if(++i < argc)
+ : {
+ : defaultFontPath = argv[i];
+ : }
+ : else
+ : UseMsg();
+ : }
+ : else if ( strcmp( argv[i], "-help") == 0)
+ : {
+ : UseMsg();
+ : exit(0);
+ : }
+ :#ifdef XKB
+ : else if ( (skip=XkbProcessArguments(argc,argv,i))!=0 ) {
+ : if (skip>0)
+ : i+= skip-1;
+ : else UseMsg();
+ : }
+ :#endif
+ :#ifdef RLIMIT_DATA
+ : else if ( strcmp( argv[i], "-ld") == 0)
+ : {
+ : if(++i < argc)
+ : {
+ : limitDataSpace = atoi(argv[i]);
+ : if (limitDataSpace > 0)
+ : limitDataSpace *= 1024;
+ : }
+ : else
+ : UseMsg();
+ : }
+ :#endif
+ :#ifdef RLIMIT_NOFILE
+ : else if ( strcmp( argv[i], "-lf") == 0)
+ : {
+ : if(++i < argc)
+ : limitNoFile = atoi(argv[i]);
+ : else
+ : UseMsg();
+ : }
+ :#endif
+ :#ifdef RLIMIT_STACK
+ : else if ( strcmp( argv[i], "-ls") == 0)
+ : {
+ : if(++i < argc)
+ : {
+ : limitStackSpace = atoi(argv[i]);
+ : if (limitStackSpace > 0)
+ : limitStackSpace *= 1024;
+ : }
+ : else
+ : UseMsg();
+ : }
+ :#endif
+ :#ifdef SERVER_LOCK
+ : else if ( strcmp ( argv[i], "-nolock") == 0)
+ : {
+ :#if !defined(WIN32) && !defined(__CYGWIN__)
+ : if (getuid() != 0)
+ : ErrorF("Warning: the -nolock option can only be used by root\n");
+ : else
+ :#endif
+ : nolock = TRUE;
+ : }
+ :#endif
+ :#ifndef NOLOGOHACK
+ : else if ( strcmp( argv[i], "-logo") == 0)
+ : {
+ : logoScreenSaver = 1;
+ : }
+ : else if ( strcmp( argv[i], "nologo") == 0)
+ : {
+ : logoScreenSaver = 0;
+ : }
+ :#endif
+ : else if ( strcmp( argv[i], "-nolisten") == 0)
+ : {
+ : if(++i < argc) {
+ : if (_XSERVTransNoListen(argv[i]))
+ : FatalError ("Failed to disable listen for %s transport",
+ : argv[i]);
+ : } else
+ : UseMsg();
+ : }
+ : else if ( strcmp( argv[i], "-noreset") == 0)
+ : {
+ : dispatchExceptionAtReset = 0;
+ : }
+ : else if ( strcmp( argv[i], "-reset") == 0)
+ : {
+ : dispatchExceptionAtReset = DE_RESET;
+ : }
+ : else if ( strcmp( argv[i], "-p") == 0)
+ : {
+ : if(++i < argc)
+ : defaultScreenSaverInterval = ((CARD32)atoi(argv[i])) *
+ : MILLI_PER_MIN;
+ : else
+ : UseMsg();
+ : }
+ : else if ( strcmp( argv[i], "-pn") == 0)
+ : PartialNetwork = TRUE;
+ : else if ( strcmp( argv[i], "-nopn") == 0)
+ : PartialNetwork = FALSE;
+ : else if ( strcmp( argv[i], "r") == 0)
+ : defaultKeyboardControl.autoRepeat = TRUE;
+ : else if ( strcmp( argv[i], "-r") == 0)
+ : defaultKeyboardControl.autoRepeat = FALSE;
+ : else if ( strcmp( argv[i], "-s") == 0)
+ : {
+ : if(++i < argc)
+ : defaultScreenSaverTime = ((CARD32)atoi(argv[i])) *
+ : MILLI_PER_MIN;
+ : else
+ : UseMsg();
+ : }
+ : else if ( strcmp( argv[i], "-su") == 0)
+ : disableSaveUnders = TRUE;
+ : else if ( strcmp( argv[i], "-t") == 0)
+ : {
+ : if(++i < argc)
+ : defaultPointerControl.threshold = atoi(argv[i]);
+ : else
+ : UseMsg();
+ : }
+ : else if ( strcmp( argv[i], "-terminate") == 0)
+ : {
+ : dispatchExceptionAtReset = DE_TERMINATE;
+ : }
+ : else if ( strcmp( argv[i], "-to") == 0)
+ : {
+ : if(++i < argc)
+ : TimeOutValue = ((CARD32)atoi(argv[i])) * MILLI_PER_SECOND;
+ : else
+ : UseMsg();
+ : }
+ : else if ( strcmp( argv[i], "-tst") == 0)
+ : {
+ : noTestExtensions = TRUE;
+ : }
+ : else if ( strcmp( argv[i], "v") == 0)
+ : defaultScreenSaverBlanking = PreferBlanking;
+ : else if ( strcmp( argv[i], "-v") == 0)
+ : defaultScreenSaverBlanking = DontPreferBlanking;
+ : else if ( strcmp( argv[i], "-wm") == 0)
+ : defaultBackingStore = WhenMapped;
+ : else if ( strcmp( argv[i], "-wr") == 0)
+ : whiteRoot = TRUE;
+ : else if ( strcmp( argv[i], "-maxbigreqsize") == 0) {
+ : if(++i < argc) {
+ : long reqSizeArg = atol(argv[i]);
+ :
+ : /* Request size > 128MB does not make much sense... */
+ : if( reqSizeArg > 0L && reqSizeArg < 128L ) {
+ : maxBigRequestSize = (reqSizeArg * 1048576L) - 1L;
+ : }
+ : else
+ : {
+ : UseMsg();
+ : }
+ : }
+ : else
+ : {
+ : UseMsg();
+ : }
+ : }
+ :#ifdef PANORAMIX
+ : else if ( strcmp( argv[i], "+xinerama") == 0){
+ : noPanoramiXExtension = FALSE;
+ : }
+ : else if ( strcmp( argv[i], "-xinerama") == 0){
+ : noPanoramiXExtension = TRUE;
+ : }
+ : else if ( strcmp( argv[i], "-disablexineramaextension") == 0){
+ : PanoramiXExtensionDisabledHack = TRUE;
+ : }
+ :#endif
+ : else if ( strcmp( argv[i], "-x") == 0)
+ : {
+ : if(++i >= argc)
+ : UseMsg();
+ : /* For U**x, which doesn't support dynamic loading, there's nothing
+ : * to do when we see a -x. Either the extension is linked in or
+ : * it isn't */
+ : }
+ : else if ( strcmp( argv[i], "-I") == 0)
+ : {
+ : /* ignore all remaining arguments */
+ : break;
+ : }
+ : else if (strncmp (argv[i], "tty", 3) == 0)
+ : {
+ : /* just in case any body is interested */
+ : dev_tty_from_init = argv[i];
+ : }
+ :#ifdef XDMCP
+ : else if ((skip = XdmcpOptions(argc, argv, i)) != i)
+ : {
+ : i = skip - 1;
+ : }
+ :#endif
+ :#ifdef XPRINT
+ : else if ((skip = PrinterOptions(argc, argv, i)) != i)
+ : {
+ : i = skip - 1;
+ : }
+ :#endif
+ :#ifdef XCSECURITY
+ : else if ((skip = XSecurityOptions(argc, argv, i)) != i)
+ : {
+ : i = skip - 1;
+ : }
+ :#endif
+ :#ifdef AIXV3
+ : else if ( strcmp( argv[i], "-timeout") == 0)
+ : {
+ : if(++i < argc)
+ : SelectWaitTime = atoi(argv[i]);
+ : else
+ : UseMsg();
+ : }
+ : else if ( strcmp( argv[i], "-sync") == 0)
+ : {
+ : SyncOn++;
+ : }
+ :#endif
+ :#ifdef SMART_SCHEDULE
+ : else if ( strcmp( argv[i], "-dumbSched") == 0)
+ : {
+ : SmartScheduleDisable = TRUE;
+ : }
+ : else if ( strcmp( argv[i], "-schedInterval") == 0)
+ : {
+ : if (++i < argc)
+ : {
+ : SmartScheduleInterval = atoi(argv[i]);
+ : SmartScheduleSlice = SmartScheduleInterval;
+ : }
+ : else
+ : UseMsg();
+ : }
+ : else if ( strcmp( argv[i], "-schedMax") == 0)
+ : {
+ : if (++i < argc)
+ : {
+ : SmartScheduleMaxSlice = atoi(argv[i]);
+ : }
+ : else
+ : UseMsg();
+ : }
+ :#endif
+ :#ifdef RENDER
+ : else if ( strcmp( argv[i], "-render" ) == 0)
+ : {
+ : if (++i < argc)
+ : {
+ : int policy = PictureParseCmapPolicy (argv[i]);
+ :
+ : if (policy != PictureCmapPolicyInvalid)
+ : PictureCmapPolicy = policy;
+ : else
+ : UseMsg ();
+ : }
+ : else
+ : UseMsg ();
+ : }
+ :#endif
+ : else if ( strcmp( argv[i], "+extension") == 0)
+ : {
+ : if (++i < argc)
+ : {
+ : if (!EnableDisableExtension(argv[i], TRUE))
+ : EnableDisableExtensionError(argv[i], TRUE);
+ : }
+ : else
+ : UseMsg();
+ : }
+ : else if ( strcmp( argv[i], "-extension") == 0)
+ : {
+ : if (++i < argc)
+ : {
+ : if (!EnableDisableExtension(argv[i], FALSE))
+ : EnableDisableExtensionError(argv[i], FALSE);
+ : }
+ : else
+ : UseMsg();
+ : }
+ : else
+ : {
+ : ErrorF("Unrecognized option: %s\n", argv[i]);
+ : UseMsg();
+ : FatalError("Unrecognized option: %s\n", argv[i]);
+ : }
+ : }
+ :}
+ :
+ :#ifdef COMMANDLINE_CHALLENGED_OPERATING_SYSTEMS
+ :static void
+ :InsertFileIntoCommandLine(
+ : int *resargc, char ***resargv,
+ : int prefix_argc, char **prefix_argv,
+ : char *filename,
+ : int suffix_argc, char **suffix_argv)
+ :{
+ : struct stat st;
+ : FILE *f;
+ : char *p;
+ : char *q;
+ : int insert_argc;
+ : char *buf;
+ : int len;
+ : int i;
+ :
+ : f = fopen(filename, "r");
+ : if (!f)
+ : FatalError("Can't open option file %s\n", filename);
+ :
+ : fstat(fileno(f), &st);
+ :
+ : buf = (char *) xalloc((unsigned) st.st_size + 1);
+ : if (!buf)
+ : FatalError("Out of Memory\n");
+ :
+ : len = fread(buf, 1, (unsigned) st.st_size, f);
+ :
+ : fclose(f);
+ :
+ : if (len < 0)
+ : FatalError("Error reading option file %s\n", filename);
+ :
+ : buf[len] = '\0';
+ :
+ : p = buf;
+ : q = buf;
+ : insert_argc = 0;
+ :
+ : while (*p)
+ : {
+ : while (isspace(*p))
+ : p++;
+ : if (!*p)
+ : break;
+ : if (*p == '#')
+ : {
+ : while (*p && *p != '\n')
+ : p++;
+ : } else
+ : {
+ : while (*p && !isspace(*p))
+ : *q++ = *p++;
+ : /* Since p and q might still be pointing at the same place, we */
+ : /* need to step p over the whitespace now before we add the null. */
+ : if (*p)
+ : p++;
+ : *q++ = '\0';
+ : insert_argc++;
+ : }
+ : }
+ :
+ : buf = (char *) xrealloc(buf, q - buf);
+ : if (!buf)
+ : FatalError("Out of memory reallocing option buf\n");
+ :
+ : *resargc = prefix_argc + insert_argc + suffix_argc;
+ : *resargv = (char **) xalloc((*resargc + 1) * sizeof(char *));
+ : if (!*resargv)
+ : FatalError("Out of Memory\n");
+ :
+ : memcpy(*resargv, prefix_argv, prefix_argc * sizeof(char *));
+ :
+ : p = buf;
+ : for (i = 0; i < insert_argc; i++)
+ : {
+ : (*resargv)[prefix_argc + i] = p;
+ : p += strlen(p) + 1;
+ : }
+ :
+ : memcpy(*resargv + prefix_argc + insert_argc,
+ : suffix_argv, suffix_argc * sizeof(char *));
+ :
+ : (*resargv)[*resargc] = NULL;
+ :} /* end InsertFileIntoCommandLine */
+ :
+ :
+ :void
+ :ExpandCommandLine(int *pargc, char ***pargv)
+ :{
+ : int i;
+ :
+ :#if !defined(WIN32) && !defined(__CYGWIN__)
+ : if (getuid() != geteuid())
+ : return;
+ :#endif
+ :
+ : for (i = 1; i < *pargc; i++)
+ : {
+ : if ( (0 == strcmp((*pargv)[i], "-config")) && (i < (*pargc - 1)) )
+ : {
+ : InsertFileIntoCommandLine(pargc, pargv,
+ : i, *pargv,
+ : (*pargv)[i+1], /* filename */
+ : *pargc - i - 2, *pargv + i + 2);
+ : i--;
+ : }
+ : }
+ :} /* end ExpandCommandLine */
+ :#endif
+ :
+ :/* Implement a simple-minded font authorization scheme. The authorization
+ : name is "hp-hostname-1", the contents are simply the host name. */
+ :int
+ :set_font_authorizations(char **authorizations, int *authlen, pointer client)
+ :{
+ :#define AUTHORIZATION_NAME "hp-hostname-1"
+ :#if defined(TCPCONN) || defined(STREAMSCONN)
+ : static char *result = NULL;
+ : static char *p = NULL;
+ :
+ : if (p == NULL)
+ : {
+ : char hname[1024], *hnameptr;
+ : unsigned int len;
+ :#if defined(IPv6) && defined(AF_INET6)
+ : struct addrinfo hints, *ai = NULL;
+ :#else
+ : struct hostent *host;
+ :#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
+ : _Xgethostbynameparams hparams;
+ :#endif
+ :#endif
+ :
+ : gethostname(hname, 1024);
+ :#if defined(IPv6) && defined(AF_INET6)
+ : bzero(&hints, sizeof(hints));
+ : hints.ai_flags = AI_CANONNAME;
+ : if (getaddrinfo(hname, NULL, &hints, &ai) == 0) {
+ : hnameptr = ai->ai_canonname;
+ : } else {
+ : hnameptr = hname;
+ : }
+ :#else
+ : host = _XGethostbyname(hname, hparams);
+ : if (host == NULL)
+ : hnameptr = hname;
+ : else
+ : hnameptr = host->h_name;
+ :#endif
+ :
+ : len = strlen(hnameptr) + 1;
+ : result = xalloc(len + sizeof(AUTHORIZATION_NAME) + 4);
+ :
+ : p = result;
+ : *p++ = sizeof(AUTHORIZATION_NAME) >> 8;
+ : *p++ = sizeof(AUTHORIZATION_NAME) & 0xff;
+ : *p++ = (len) >> 8;
+ : *p++ = (len & 0xff);
+ :
+ : memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME));
+ : p += sizeof(AUTHORIZATION_NAME);
+ : memmove(p, hnameptr, len);
+ : p += len;
+ :#if defined(IPv6) && defined(AF_INET6)
+ : if (ai) {
+ : freeaddrinfo(ai);
+ : }
+ :#endif
+ : }
+ : *authlen = p - result;
+ : *authorizations = result;
+ : return 1;
+ :#else /* TCPCONN */
+ : return 0;
+ :#endif /* TCPCONN */
+ :}
+ :
+ :/* XALLOC -- X's internal memory allocator. Why does it return unsigned
+ : * long * instead of the more common char *? Well, if you read K&R you'll
+ : * see they say that alloc must return a pointer "suitable for conversion"
+ : * to whatever type you really want. In a full-blown generic allocator
+ : * there's no way to solve the alignment problems without potentially
+ : * wasting lots of space. But we have a more limited problem. We know
+ : * we're only ever returning pointers to structures which will have to
+ : * be long word aligned. So we are making a stronger guarantee. It might
+ : * have made sense to make Xalloc return char * to conform with people's
+ : * expectations of malloc, but this makes lint happier.
+ : */
+ :
+ :#ifndef INTERNAL_MALLOC
+ :
+ :_X_EXPORT void *
+ :Xalloc(unsigned long amount)
+ 6 0.0065 :{ /* Xalloc total: 10 0.0109 */
+ : register pointer ptr;
+ :
+ 1 0.0011 : if ((long)amount <= 0) {
+ : return (unsigned long *)NULL;
+ : }
+ : /* aligned extra on long word boundary */
+ : amount = (amount + (sizeof(long) - 1)) & ~(sizeof(long) - 1);
+ :#ifdef MEMBUG
+ : if (!Must_have_memory && Memory_fail &&
+ : ((random() % MEM_FAIL_SCALE) < Memory_fail))
+ : return (unsigned long *)NULL;
+ :#endif
+ 1 0.0011 : if ((ptr = (pointer)malloc(amount))) {
+ : return (unsigned long *)ptr;
+ : }
+ : if (Must_have_memory)
+ : FatalError("Out of memory");
+ : return (unsigned long *)NULL;
+ 2 0.0022 :}
+ :
+ :/*****************
+ : * XNFalloc
+ : * "no failure" realloc, alternate interface to Xalloc w/o Must_have_memory
+ : *****************/
+ :
+ :_X_EXPORT void *
+ :XNFalloc(unsigned long amount)
+ :{
+ : register pointer ptr;
+ :
+ : if ((long)amount <= 0)
+ : {
+ : return (unsigned long *)NULL;
+ : }
+ : /* aligned extra on long word boundary */
+ : amount = (amount + (sizeof(long) - 1)) & ~(sizeof(long) - 1);
+ : ptr = (pointer)malloc(amount);
+ : if (!ptr)
+ : {
+ : FatalError("Out of memory");
+ : }
+ : return ((unsigned long *)ptr);
+ :}
+ :
+ :/*****************
+ : * Xcalloc
+ : *****************/
+ :
+ :_X_EXPORT void *
+ :Xcalloc(unsigned long amount)
+ :{
+ : unsigned long *ret;
+ :
+ : ret = Xalloc (amount);
+ : if (ret)
+ : bzero ((char *) ret, (int) amount);
+ : return ret;
+ :}
+ :
+ :/*****************
+ : * XNFcalloc
+ : *****************/
+ :
+ :_X_EXPORT void *
+ :XNFcalloc(unsigned long amount)
+ :{
+ : unsigned long *ret;
+ :
+ : ret = Xalloc (amount);
+ : if (ret)
+ : bzero ((char *) ret, (int) amount);
+ : else if ((long)amount > 0)
+ : FatalError("Out of memory");
+ : return ret;
+ :}
+ :
+ :/*****************
+ : * Xrealloc
+ : *****************/
+ :
+ :_X_EXPORT void *
+ :Xrealloc(pointer ptr, unsigned long amount)
+ :{
+ :#ifdef MEMBUG
+ : if (!Must_have_memory && Memory_fail &&
+ : ((random() % MEM_FAIL_SCALE) < Memory_fail))
+ : return (unsigned long *)NULL;
+ :#endif
+ : if ((long)amount <= 0)
+ : {
+ : if (ptr && !amount)
+ : free(ptr);
+ : return (unsigned long *)NULL;
+ : }
+ : amount = (amount + (sizeof(long) - 1)) & ~(sizeof(long) - 1);
+ : if (ptr)
+ : ptr = (pointer)realloc((char *)ptr, amount);
+ : else
+ : ptr = (pointer)malloc(amount);
+ : if (ptr)
+ : return (unsigned long *)ptr;
+ : if (Must_have_memory)
+ : FatalError("Out of memory");
+ : return (unsigned long *)NULL;
+ :}
+ :
+ :/*****************
+ : * XNFrealloc
+ : * "no failure" realloc, alternate interface to Xrealloc w/o Must_have_memory
+ : *****************/
+ :
+ :_X_EXPORT void *
+ :XNFrealloc(pointer ptr, unsigned long amount)
+ :{
+ : if (( ptr = (pointer)Xrealloc( ptr, amount ) ) == NULL)
+ : {
+ : if ((long)amount > 0)
+ : FatalError( "Out of memory" );
+ : }
+ : return ((unsigned long *)ptr);
+ :}
+ :
+ :/*****************
+ : * Xfree
+ : * calls free
+ : *****************/
+ :
+ :_X_EXPORT void
+ :Xfree(pointer ptr)
+ 7 0.0076 :{ /* Xfree total: 10 0.0109 */
+ 1 0.0011 : if (ptr)
+ 1 0.0011 : free((char *)ptr);
+ 1 0.0011 :}
+ :
+ :void
+ :OsInitAllocator (void)
+ :{
+ :#ifdef MEMBUG
+ : static int been_here;
+ :
+ : /* Check the memory system after each generation */
+ : if (been_here)
+ : CheckMemory ();
+ : else
+ : been_here = 1;
+ :#endif
+ :}
+ :#endif /* !INTERNAL_MALLOC */
+ :
+ :
+ :char *
+ :Xstrdup(const char *s)
+ :{
+ : char *sd;
+ :
+ : if (s == NULL)
+ : return NULL;
+ :
+ : sd = (char *)Xalloc(strlen(s) + 1);
+ : if (sd != NULL)
+ : strcpy(sd, s);
+ : return sd;
+ :}
+ :
+ :
+ :_X_EXPORT char *
+ :XNFstrdup(const char *s)
+ :{
+ : char *sd;
+ :
+ : if (s == NULL)
+ : return NULL;
+ :
+ : sd = (char *)XNFalloc(strlen(s) + 1);
+ : strcpy(sd, s);
+ : return sd;
+ :}
+ :
+ :#ifdef SMART_SCHEDULE
+ :
+ :unsigned long SmartScheduleIdleCount;
+ :Bool SmartScheduleIdle;
+ :Bool SmartScheduleTimerStopped;
+ :
+ :#ifdef SIGVTALRM
+ :#define SMART_SCHEDULE_POSSIBLE
+ :#endif
+ :
+ :#ifdef SMART_SCHEDULE_POSSIBLE
+ :#define SMART_SCHEDULE_SIGNAL SIGALRM
+ :#define SMART_SCHEDULE_TIMER ITIMER_REAL
+ :#endif
+ :
+ :static void
+ :SmartScheduleStopTimer (void)
+ :{
+ :#ifdef SMART_SCHEDULE_POSSIBLE
+ : struct itimerval timer;
+ :
+ : timer.it_interval.tv_sec = 0;
+ : timer.it_interval.tv_usec = 0;
+ : timer.it_value.tv_sec = 0;
+ : timer.it_value.tv_usec = 0;
+ : (void) setitimer (ITIMER_REAL, &timer, 0);
+ : SmartScheduleTimerStopped = TRUE;
+ :#endif
+ :}
+ :
+ :Bool
+ :SmartScheduleStartTimer (void)
+ :{
+ :#ifdef SMART_SCHEDULE_POSSIBLE
+ : struct itimerval timer;
+ :
+ : SmartScheduleTimerStopped = FALSE;
+ : timer.it_interval.tv_sec = 0;
+ : timer.it_interval.tv_usec = SmartScheduleInterval * 1000;
+ : timer.it_value.tv_sec = 0;
+ : timer.it_value.tv_usec = SmartScheduleInterval * 1000;
+ : return setitimer (ITIMER_REAL, &timer, 0) >= 0;
+ :#endif
+ : return FALSE;
+ :}
+ :
+ :#ifdef SMART_SCHEDULE_POSSIBLE
+ :static void
+ :SmartScheduleTimer (int sig)
+ :{
+ : int olderrno = errno;
+ :
+ : SmartScheduleTime += SmartScheduleInterval;
+ : if (SmartScheduleIdle)
+ : {
+ : SmartScheduleStopTimer ();
+ : }
+ : errno = olderrno;
+ :}
+ :#endif
+ :
+ :Bool
+ :SmartScheduleInit (void)
+ :{
+ :#ifdef SMART_SCHEDULE_POSSIBLE
+ : struct sigaction act;
+ :
+ : if (SmartScheduleDisable)
+ : return TRUE;
+ :
+ : bzero ((char *) &act, sizeof(struct sigaction));
+ :
+ : /* Set up the timer signal function */
+ : act.sa_handler = SmartScheduleTimer;
+ : sigemptyset (&act.sa_mask);
+ : sigaddset (&act.sa_mask, SMART_SCHEDULE_SIGNAL);
+ : if (sigaction (SMART_SCHEDULE_SIGNAL, &act, 0) < 0)
+ : {
+ : perror ("sigaction for smart scheduler");
+ : return FALSE;
+ : }
+ : /* Set up the virtual timer */
+ : if (!SmartScheduleStartTimer ())
+ : {
+ : perror ("scheduling timer");
+ : return FALSE;
+ : }
+ : /* stop the timer and wait for WaitForSomething to start it */
+ : SmartScheduleStopTimer ();
+ : return TRUE;
+ :#else
+ : return FALSE;
+ :#endif
+ :}
+ :#endif
+ :
+ :#ifdef SIG_BLOCK
+ :static sigset_t PreviousSignalMask;
+ :static int BlockedSignalCount;
+ :#endif
+ :
+ :void
+ :OsBlockSignals (void)
+ :{
+ :#ifdef SIG_BLOCK
+ : if (BlockedSignalCount++ == 0)
+ : {
+ : sigset_t set;
+ :
+ : sigemptyset (&set);
+ :#ifdef SIGALRM
+ : sigaddset (&set, SIGALRM);
+ :#endif
+ :#ifdef SIGVTALRM
+ : sigaddset (&set, SIGVTALRM);
+ :#endif
+ :#ifdef SIGWINCH
+ : sigaddset (&set, SIGWINCH);
+ :#endif
+ :#ifdef SIGIO
+ : sigaddset (&set, SIGIO);
+ :#endif
+ :#ifdef SIGTSTP
+ : sigaddset (&set, SIGTSTP);
+ :#endif
+ :#ifdef SIGTTIN
+ : sigaddset (&set, SIGTTIN);
+ :#endif
+ :#ifdef SIGTTOU
+ : sigaddset (&set, SIGTTOU);
+ :#endif
+ :#ifdef SIGCHLD
+ : sigaddset (&set, SIGCHLD);
+ :#endif
+ : sigprocmask (SIG_BLOCK, &set, &PreviousSignalMask);
+ : }
+ :#endif
+ :}
+ :
+ :void
+ :OsReleaseSignals (void)
+ :{
+ :#ifdef SIG_BLOCK
+ : if (--BlockedSignalCount == 0)
+ : {
+ : sigprocmask (SIG_SETMASK, &PreviousSignalMask, 0);
+ : }
+ :#endif
+ :}
+ :
+ :#if !defined(WIN32)
+ :/*
+ : * "safer" versions of system(3), popen(3) and pclose(3) which give up
+ : * all privs before running a command.
+ : *
+ : * This is based on the code in FreeBSD 2.2 libc.
+ : *
+ : * XXX It'd be good to redirect stderr so that it ends up in the log file
+ : * as well. As it is now, xkbcomp messages don't end up in the log file.
+ : */
+ :
+ :int
+ :System(char *command)
+ :{
+ : int pid, p;
+ :#ifdef SIGCHLD
+ : void (*csig)(int);
+ :#endif
+ : int status;
+ :
+ : if (!command)
+ : return(1);
+ :
+ :#ifdef SIGCHLD
+ : csig = signal(SIGCHLD, SIG_DFL);
+ :#endif
+ :
+ :#ifdef DEBUG
+ : ErrorF("System: `%s'\n", command);
+ :#endif
+ :
+ : switch (pid = fork()) {
+ : case -1: /* error */
+ : p = -1;
+ : case 0: /* child */
+ : if (setgid(getgid()) == -1)
+ : _exit(127);
+ : if (setuid(getuid()) == -1)
+ : _exit(127);
+ : execl("/bin/sh", "sh", "-c", command, (char *)NULL);
+ : _exit(127);
+ : default: /* parent */
+ : do {
+ : p = waitpid(pid, &status, 0);
+ : } while (p == -1 && errno == EINTR);
+ :
+ : }
+ :
+ :#ifdef SIGCHLD
+ : signal(SIGCHLD, csig);
+ :#endif
+ :
+ : return p == -1 ? -1 : status;
+ :}
+ :
+ :static struct pid {
+ : struct pid *next;
+ : FILE *fp;
+ : int pid;
+ :} *pidlist;
+ :
+ :pointer
+ :Popen(char *command, char *type)
+ :{
+ : struct pid *cur;
+ : FILE *iop;
+ : int pdes[2], pid;
+ :
+ : if (command == NULL || type == NULL)
+ : return NULL;
+ :
+ : if ((*type != 'r' && *type != 'w') || type[1])
+ : return NULL;
+ :
+ : if ((cur = (struct pid *)xalloc(sizeof(struct pid))) == NULL)
+ : return NULL;
+ :
+ : if (pipe(pdes) < 0) {
+ : xfree(cur);
+ : return NULL;
+ : }
+ :
+ : switch (pid = fork()) {
+ : case -1: /* error */
+ : close(pdes[0]);
+ : close(pdes[1]);
+ : xfree(cur);
+ : return NULL;
+ : case 0: /* child */
+ : if (setgid(getgid()) == -1)
+ : _exit(127);
+ : if (setuid(getuid()) == -1)
+ : _exit(127);
+ : if (*type == 'r') {
+ : if (pdes[1] != 1) {
+ : /* stdout */
+ : dup2(pdes[1], 1);
+ : close(pdes[1]);
+ : }
+ : close(pdes[0]);
+ : } else {
+ : if (pdes[0] != 0) {
+ : /* stdin */
+ : dup2(pdes[0], 0);
+ : close(pdes[0]);
+ : }
+ : close(pdes[1]);
+ : }
+ : execl("/bin/sh", "sh", "-c", command, (char *)NULL);
+ : _exit(127);
+ : }
+ :
+ : /* Avoid EINTR during stdio calls */
+ : OsBlockSignals ();
+ :
+ : /* parent */
+ : if (*type == 'r') {
+ : iop = fdopen(pdes[0], type);
+ : close(pdes[1]);
+ : } else {
+ : iop = fdopen(pdes[1], type);
+ : close(pdes[0]);
+ : }
+ :
+ : cur->fp = iop;
+ : cur->pid = pid;
+ : cur->next = pidlist;
+ : pidlist = cur;
+ :
+ :#ifdef DEBUG
+ : ErrorF("Popen: `%s', fp = %p\n", command, iop);
+ :#endif
+ :
+ : return iop;
+ :}
+ :
+ :/* fopen that drops privileges */
+ :pointer
+ :Fopen(char *file, char *type)
+ :{
+ : FILE *iop;
+ :#ifndef HAS_SAVED_IDS_AND_SETEUID
+ : struct pid *cur;
+ : int pdes[2], pid;
+ :
+ : if (file == NULL || type == NULL)
+ : return NULL;
+ :
+ : if ((*type != 'r' && *type != 'w') || type[1])
+ : return NULL;
+ :
+ : if ((cur = (struct pid *)xalloc(sizeof(struct pid))) == NULL)
+ : return NULL;
+ :
+ : if (pipe(pdes) < 0) {
+ : xfree(cur);
+ : return NULL;
+ : }
+ :
+ : switch (pid = fork()) {
+ : case -1: /* error */
+ : close(pdes[0]);
+ : close(pdes[1]);
+ : xfree(cur);
+ : return NULL;
+ : case 0: /* child */
+ : if (setgid(getgid()) == -1)
+ : _exit(127);
+ : if (setuid(getuid()) == -1)
+ : _exit(127);
+ : if (*type == 'r') {
+ : if (pdes[1] != 1) {
+ : /* stdout */
+ : dup2(pdes[1], 1);
+ : close(pdes[1]);
+ : }
+ : close(pdes[0]);
+ : } else {
+ : if (pdes[0] != 0) {
+ : /* stdin */
+ : dup2(pdes[0], 0);
+ : close(pdes[0]);
+ : }
+ : close(pdes[1]);
+ : }
+ : execl("/bin/cat", "cat", file, (char *)NULL);
+ : _exit(127);
+ : }
+ :
+ : /* Avoid EINTR during stdio calls */
+ : OsBlockSignals ();
+ :
+ : /* parent */
+ : if (*type == 'r') {
+ : iop = fdopen(pdes[0], type);
+ : close(pdes[1]);
+ : } else {
+ : iop = fdopen(pdes[1], type);
+ : close(pdes[0]);
+ : }
+ :
+ : cur->fp = iop;
+ : cur->pid = pid;
+ : cur->next = pidlist;
+ : pidlist = cur;
+ :
+ :#ifdef DEBUG
+ : ErrorF("Fopen(%s), fp = %p\n", file, iop);
+ :#endif
+ :
+ : return iop;
+ :#else
+ : int ruid, euid;
+ :
+ : ruid = getuid();
+ : euid = geteuid();
+ :
+ : if (seteuid(ruid) == -1) {
+ : return NULL;
+ : }
+ : iop = fopen(file, type);
+ :
+ : if (seteuid(euid) == -1) {
+ : fclose(iop);
+ : return NULL;
+ : }
+ : return iop;
+ :#endif /* HAS_SAVED_IDS_AND_SETEUID */
+ :}
+ :
+ :int
+ :Pclose(pointer iop)
+ :{
+ : struct pid *cur, *last;
+ : int pstat;
+ : int pid;
+ :
+ :#ifdef DEBUG
+ : ErrorF("Pclose: fp = %p\n", iop);
+ :#endif
+ :
+ : fclose(iop);
+ :
+ : for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
+ : if (cur->fp == iop)
+ : break;
+ : if (cur == NULL)
+ : return -1;
+ :
+ : do {
+ : pid = waitpid(cur->pid, &pstat, 0);
+ : } while (pid == -1 && errno == EINTR);
+ :
+ : if (last == NULL)
+ : pidlist = cur->next;
+ : else
+ : last->next = cur->next;
+ : xfree(cur);
+ :
+ : /* allow EINTR again */
+ : OsReleaseSignals ();
+ :
+ : return pid == -1 ? -1 : pstat;
+ :}
+ :
+ :int
+ :Fclose(pointer iop)
+ :{
+ :#ifdef HAS_SAVED_IDS_AND_SETEUID
+ : return fclose(iop);
+ :#else
+ : return Pclose(iop);
+ :#endif
+ :}
+ :
+ :#endif /* !WIN32 */
+ :
+ :
+ :/*
+ : * CheckUserParameters: check for long command line arguments and long
+ : * environment variables. By default, these checks are only done when
+ : * the server's euid != ruid. In 3.3.x, these checks were done in an
+ : * external wrapper utility.
+ : */
+ :
+ :/* Consider LD* variables insecure? */
+ :#ifndef REMOVE_ENV_LD
+ :#define REMOVE_ENV_LD 1
+ :#endif
+ :
+ :/* Remove long environment variables? */
+ :#ifndef REMOVE_LONG_ENV
+ :#define REMOVE_LONG_ENV 1
+ :#endif
+ :
+ :/*
+ : * Disallow stdout or stderr as pipes? It's possible to block the X server
+ : * when piping stdout+stderr to a pipe.
+ : *
+ : * Don't enable this because it looks like it's going to cause problems.
+ : */
+ :#ifndef NO_OUTPUT_PIPES
+ :#define NO_OUTPUT_PIPES 0
+ :#endif
+ :
+ :
+ :/* Check args and env only if running setuid (euid == 0 && euid != uid) ? */
+ :#ifndef CHECK_EUID
+ :#ifndef WIN32
+ :#define CHECK_EUID 1
+ :#else
+ :#define CHECK_EUID 0
+ :#endif
+ :#endif
+ :
+ :/*
+ : * Maybe the locale can be faked to make isprint(3) report that everything
+ : * is printable? Avoid it by default.
+ : */
+ :#ifndef USE_ISPRINT
+ :#define USE_ISPRINT 0
+ :#endif
+ :
+ :#define MAX_ARG_LENGTH 128
+ :#define MAX_ENV_LENGTH 256
+ :#define MAX_ENV_PATH_LENGTH 2048 /* Limit for *PATH and TERMCAP */
+ :
+ :#if USE_ISPRINT
+ :#include <ctype.h>
+ :#define checkPrintable(c) isprint(c)
+ :#else
+ :#define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f)
+ :#endif
+ :
+ :enum BadCode {
+ : NotBad = 0,
+ : UnsafeArg,
+ : ArgTooLong,
+ : UnprintableArg,
+ : EnvTooLong,
+ : OutputIsPipe,
+ : InternalError
+ :};
+ :
+ :#if defined(VENDORSUPPORT)
+ :#define BUGADDRESS VENDORSUPPORT
+ :#elif defined(BUILDERADDR)
+ :#define BUGADDRESS BUILDERADDR
+ :#else
+ :#define BUGADDRESS "xorg@freedesktop.org"
+ :#endif
+ :
+ :#define ARGMSG \
+ : "\nIf the arguments used are valid, and have been rejected incorrectly\n" \
+ : "please send details of the arguments and why they are valid to\n" \
+ : "%s. In the meantime, you can start the Xserver as\n" \
+ : "the \"super user\" (root).\n"
+ :
+ :#define ENVMSG \
+ : "\nIf the environment is valid, and have been rejected incorrectly\n" \
+ : "please send details of the environment and why it is valid to\n" \
+ : "%s. In the meantime, you can start the Xserver as\n" \
+ : "the \"super user\" (root).\n"
+ :
+ :void
+ :CheckUserParameters(int argc, char **argv, char **envp)
+ :{
+ : enum BadCode bad = NotBad;
+ : int i = 0, j;
+ : char *a, *e = NULL;
+ :#if defined(__QNX__) && !defined(__QNXNTO__)
+ : char cmd_name[64];
+ :#endif
+ :
+ :#if CHECK_EUID
+ : if (geteuid() == 0 && getuid() != geteuid())
+ :#endif
+ : {
+ : /* Check each argv[] */
+ : for (i = 1; i < argc; i++) {
+ : if (strcmp(argv[i], "-fp") == 0)
+ : {
+ : i++; /* continue with next argument. skip the length check */
+ : if (i >= argc)
+ : break;
+ : } else
+ : {
+ : if (strlen(argv[i]) > MAX_ARG_LENGTH) {
+ : bad = ArgTooLong;
+ : break;
+ : }
+ : }
+ : a = argv[i];
+ : while (*a) {
+ : if (checkPrintable(*a) == 0) {
+ : bad = UnprintableArg;
+ : break;
+ : }
+ : a++;
+ : }
+ : if (bad)
+ : break;
+ : }
+ : if (!bad) {
+ : /* Check each envp[] */
+ : for (i = 0; envp[i]; i++) {
+ :
+ : /* Check for bad environment variables and values */
+ :#if REMOVE_ENV_LD
+ : while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) {
+ :#ifdef ENVDEBUG
+ : ErrorF("CheckUserParameters: removing %s from the "
+ : "environment\n", strtok(envp[i], "="));
+ :#endif
+ : for (j = i; envp[j]; j++) {
+ : envp[j] = envp[j+1];
+ : }
+ : }
+ :#endif
+ : if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) {
+ :#if REMOVE_LONG_ENV
+ :#ifdef ENVDEBUG
+ : ErrorF("CheckUserParameters: removing %s from the "
+ : "environment\n", strtok(envp[i], "="));
+ :#endif
+ : for (j = i; envp[j]; j++) {
+ : envp[j] = envp[j+1];
+ : }
+ : i--;
+ :#else
+ : char *eq;
+ : int len;
+ :
+ : eq = strchr(envp[i], '=');
+ : if (!eq)
+ : continue;
+ : len = eq - envp[i];
+ : e = malloc(len + 1);
+ : if (!e) {
+ : bad = InternalError;
+ : break;
+ : }
+ : strncpy(e, envp[i], len);
+ : e[len] = 0;
+ : if (len >= 4 &&
+ : (strcmp(e + len - 4, "PATH") == 0 ||
+ : strcmp(e, "TERMCAP") == 0)) {
+ : if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) {
+ : bad = EnvTooLong;
+ : break;
+ : } else {
+ : free(e);
+ : }
+ : } else {
+ : bad = EnvTooLong;
+ : break;
+ : }
+ :#endif
+ : }
+ : }
+ : }
+ :#if NO_OUTPUT_PIPES
+ : if (!bad) {
+ : struct stat buf;
+ :
+ : if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode))
+ : bad = OutputIsPipe;
+ : if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode))
+ : bad = OutputIsPipe;
+ : }
+ :#endif
+ : }
+ : switch (bad) {
+ : case NotBad:
+ : return;
+ : case UnsafeArg:
+ : ErrorF("Command line argument number %d is unsafe\n", i);
+ : ErrorF(ARGMSG, BUGADDRESS);
+ : break;
+ : case ArgTooLong:
+ : ErrorF("Command line argument number %d is too long\n", i);
+ : ErrorF(ARGMSG, BUGADDRESS);
+ : break;
+ : case UnprintableArg:
+ : ErrorF("Command line argument number %d contains unprintable"
+ : " characters\n", i);
+ : ErrorF(ARGMSG, BUGADDRESS);
+ : break;
+ : case EnvTooLong:
+ : ErrorF("Environment variable `%s' is too long\n", e);
+ : ErrorF(ENVMSG, BUGADDRESS);
+ : break;
+ : case OutputIsPipe:
+ : ErrorF("Stdout and/or stderr is a pipe\n");
+ : break;
+ : case InternalError:
+ : ErrorF("Internal Error\n");
+ : break;
+ : default:
+ : ErrorF("Unknown error\n");
+ : ErrorF(ARGMSG, BUGADDRESS);
+ : ErrorF(ENVMSG, BUGADDRESS);
+ : break;
+ : }
+ : FatalError("X server aborted because of unsafe environment\n");
+ :}
+ :
+ :/*
+ : * CheckUserAuthorization: check if the user is allowed to start the
+ : * X server. This usually means some sort of PAM checking, and it is
+ : * usually only done for setuid servers (uid != euid).
+ : */
+ :
+ :#ifdef USE_PAM
+ :#include <security/pam_appl.h>
+ :#include <security/pam_misc.h>
+ :#include <pwd.h>
+ :#endif /* USE_PAM */
+ :
+ :void
+ :CheckUserAuthorization(void)
+ :{
+ :#ifdef USE_PAM
+ : static struct pam_conv conv = {
+ : misc_conv,
+ : NULL
+ : };
+ :
+ : pam_handle_t *pamh = NULL;
+ : struct passwd *pw;
+ : int retval;
+ :
+ : if (getuid() != geteuid()) {
+ : pw = getpwuid(getuid());
+ : if (pw == NULL)
+ : FatalError("getpwuid() failed for uid %d\n", getuid());
+ :
+ : retval = pam_start("xserver", pw->pw_name, &conv, &pamh);
+ : if (retval != PAM_SUCCESS)
+ : FatalError("pam_start() failed.\n"
+ : "\tMissing or mangled PAM config file or module?\n");
+ :
+ : retval = pam_authenticate(pamh, 0);
+ : if (retval != PAM_SUCCESS) {
+ : pam_end(pamh, retval);
+ : FatalError("PAM authentication failed, cannot start X server.\n"
+ : "\tPerhaps you do not have console ownership?\n");
+ : }
+ :
+ : retval = pam_acct_mgmt(pamh, 0);
+ : if (retval != PAM_SUCCESS) {
+ : pam_end(pamh, retval);
+ : FatalError("PAM authentication failed, cannot start X server.\n"
+ : "\tPerhaps you do not have console ownership?\n");
+ : }
+ :
+ : /* this is not a session, so do not do session management */
+ : pam_end(pamh, PAM_SUCCESS);
+ : }
+ :#endif
+ :}
+ :
+ :#ifdef __SCO__
+ :#include <fcntl.h>
+ :
+ :static void
+ :lockit (int fd, short what)
+ :{
+ : struct flock lck;
+ :
+ : lck.l_whence = 0;
+ : lck.l_start = 0;
+ : lck.l_len = 1;
+ : lck.l_type = what;
+ :
+ : (void)fcntl (fd, F_SETLKW, &lck);
+ :}
+ :
+ :/* SCO OpenServer 5 lacks pread/pwrite. Emulate them. */
+ :ssize_t
+ :pread (int fd, void *buf, size_t nbytes, off_t offset)
+ :{
+ : off_t saved;
+ : ssize_t ret;
+ :
+ : lockit (fd, F_RDLCK);
+ : saved = lseek (fd, 0, SEEK_CUR);
+ : lseek (fd, offset, SEEK_SET);
+ : ret = read (fd, buf, nbytes);
+ : lseek (fd, saved, SEEK_SET);
+ : lockit (fd, F_UNLCK);
+ :
+ : return ret;
+ :}
+ :
+ :ssize_t
+ :pwrite (int fd, const void *buf, size_t nbytes, off_t offset)
+ :{
+ : off_t saved;
+ : ssize_t ret;
+ :
+ : lockit (fd, F_WRLCK);
+ : saved = lseek (fd, 0, SEEK_CUR);
+ : lseek (fd, offset, SEEK_SET);
+ : ret = write (fd, buf, nbytes);
+ : lseek (fd, saved, SEEK_SET);
+ : lockit (fd, F_UNLCK);
+ :
+ : return ret;
+ :}
+ :#endif /* __SCO__ */
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/fb/fbpixmap.c"
+ *
+ * 21 0.0229
+ */
+
+
+ :/*
+ : * Copyright © 1998 Keith Packard
+ : *
+ : * 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 Keith Packard not be used in
+ : * advertising or publicity pertaining to distribution of the software without
+ : * specific, written prior permission. Keith Packard makes no
+ : * representations about the suitability of this software for any purpose. It
+ : * is provided "as is" without express or implied warranty.
+ : *
+ : * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ : * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ : * EVENT SHALL KEITH PACKARD 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.
+ : */
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include <stdlib.h>
+ :
+ :#include "fb.h"
+ :
+ :PixmapPtr
+ :fbCreatePixmapBpp (ScreenPtr pScreen, int width, int height, int depth, int bpp)
+ :{ /* fbCreatePixmapBpp total: 10 0.0109 */
+ : PixmapPtr pPixmap;
+ : size_t datasize;
+ : size_t paddedWidth;
+ : int adjust;
+ : int base;
+ :
+ 1 0.0011 : paddedWidth = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof (FbBits);
+ : if (paddedWidth / 4 > 32767 || height > 32767)
+ : return NullPixmap;
+ : datasize = height * paddedWidth;
+ 1 0.0011 : base = pScreen->totalPixmapSize;
+ : adjust = 0;
+ 1 0.0011 : if (base & 7)
+ : adjust = 8 - (base & 7);
+ : datasize += adjust;
+ :#ifdef FB_DEBUG
+ : datasize += 2 * paddedWidth;
+ :#endif
+ 1 0.0011 : pPixmap = AllocatePixmap(pScreen, datasize);
+ : if (!pPixmap)
+ : return NullPixmap;
+ : pPixmap->drawable.type = DRAWABLE_PIXMAP;
+ : pPixmap->drawable.class = 0;
+ : pPixmap->drawable.pScreen = pScreen;
+ : pPixmap->drawable.depth = depth;
+ : pPixmap->drawable.bitsPerPixel = bpp;
+ : pPixmap->drawable.id = 0;
+ 2 0.0022 : pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ : pPixmap->drawable.x = 0;
+ : pPixmap->drawable.y = 0;
+ : pPixmap->drawable.width = width;
+ 1 0.0011 : pPixmap->drawable.height = height;
+ : pPixmap->devKind = paddedWidth;
+ : pPixmap->refcnt = 1;
+ 2 0.0022 : pPixmap->devPrivate.ptr = (pointer) ((char *)pPixmap + base + adjust);
+ :#ifdef FB_DEBUG
+ : pPixmap->devPrivate.ptr = (void *) ((char *) pPixmap->devPrivate.ptr + paddedWidth);
+ : fbInitializeDrawable (&pPixmap->drawable);
+ :#endif
+ :
+ :#ifdef COMPOSITE
+ : pPixmap->screen_x = 0;
+ : pPixmap->screen_y = 0;
+ :#endif
+ :
+ : return pPixmap;
+ 1 0.0011 :}
+ :
+ :PixmapPtr
+ :fbCreatePixmap (ScreenPtr pScreen, int width, int height, int depth)
+ 2 0.0022 :{ /* fbCreatePixmap total: 10 0.0109 */
+ : int bpp;
+ 4 0.0044 : bpp = BitsPerPixel (depth);
+ :#ifdef FB_SCREEN_PRIVATE
+ 1 0.0011 : if (bpp == 32 && depth <= 24)
+ : bpp = fbGetScreenPrivate(pScreen)->pix32bpp;
+ :#endif
+ 2 0.0022 : return fbCreatePixmapBpp (pScreen, width, height, depth, bpp);
+ 1 0.0011 :}
+ :
+ :Bool
+ :fbDestroyPixmap (PixmapPtr pPixmap)
+ 1 0.0011 :{ /* fbDestroyPixmap total: 1 0.0011 */
+ : if(--pPixmap->refcnt)
+ : return TRUE;
+ : xfree(pPixmap);
+ : return TRUE;
+ :}
+ :
+ :#define ADDRECT(reg,r,fr,rx1,ry1,rx2,ry2) \
+ :if (((rx1) < (rx2)) && ((ry1) < (ry2)) && \
+ : (!((reg)->data->numRects && \
+ : ((r-1)->y1 == (ry1)) && \
+ : ((r-1)->y2 == (ry2)) && \
+ : ((r-1)->x1 <= (rx1)) && \
+ : ((r-1)->x2 >= (rx2))))) \
+ :{ \
+ : if ((reg)->data->numRects == (reg)->data->size) \
+ : { \
+ : miRectAlloc(reg, 1); \
+ : fr = REGION_BOXPTR(reg); \
+ : r = fr + (reg)->data->numRects; \
+ : } \
+ : r->x1 = (rx1); \
+ : r->y1 = (ry1); \
+ : r->x2 = (rx2); \
+ : r->y2 = (ry2); \
+ : (reg)->data->numRects++; \
+ : if(r->x1 < (reg)->extents.x1) \
+ : (reg)->extents.x1 = r->x1; \
+ : if(r->x2 > (reg)->extents.x2) \
+ : (reg)->extents.x2 = r->x2; \
+ : r++; \
+ :}
+ :
+ :/* Convert bitmap clip mask into clipping region.
+ : * First, goes through each line and makes boxes by noting the transitions
+ : * from 0 to 1 and 1 to 0.
+ : * Then it coalesces the current line with the previous if they have boxes
+ : * at the same X coordinates.
+ : */
+ :RegionPtr
+ :fbPixmapToRegion(PixmapPtr pPix)
+ :{
+ : register RegionPtr pReg;
+ : FbBits *pw, w;
+ : register int ib;
+ : int width, h, base, rx1 = 0, crects;
+ : FbBits *pwLineEnd;
+ : int irectPrevStart, irectLineStart;
+ : register BoxPtr prectO, prectN;
+ : BoxPtr FirstRect, rects, prectLineStart;
+ : Bool fInBox, fSame;
+ : register FbBits mask0 = FB_ALLONES & ~FbScrRight(FB_ALLONES, 1);
+ : FbBits *pwLine;
+ : int nWidth;
+ :
+ : pReg = REGION_CREATE(pPix->drawable.pScreen, NULL, 1);
+ : if(!pReg)
+ : return NullRegion;
+ : FirstRect = REGION_BOXPTR(pReg);
+ : rects = FirstRect;
+ :
+ : fbPrepareAccess(&pPix->drawable);
+ :
+ : pwLine = (FbBits *) pPix->devPrivate.ptr;
+ : nWidth = pPix->devKind >> (FB_SHIFT-3);
+ :
+ : width = pPix->drawable.width;
+ : pReg->extents.x1 = width - 1;
+ : pReg->extents.x2 = 0;
+ : irectPrevStart = -1;
+ : for(h = 0; h < pPix->drawable.height; h++)
+ : {
+ : pw = pwLine;
+ : pwLine += nWidth;
+ : irectLineStart = rects - FirstRect;
+ : /* If the Screen left most bit of the word is set, we're starting in
+ : * a box */
+ : if(READ(pw) & mask0)
+ : {
+ : fInBox = TRUE;
+ : rx1 = 0;
+ : }
+ : else
+ : fInBox = FALSE;
+ : /* Process all words which are fully in the pixmap */
+ : pwLineEnd = pw + (width >> FB_SHIFT);
+ : for (base = 0; pw < pwLineEnd; base += FB_UNIT)
+ : {
+ : w = READ(pw++);
+ : if (fInBox)
+ : {
+ : if (!~w)
+ : continue;
+ : }
+ : else
+ : {
+ : if (!w)
+ : continue;
+ : }
+ : for(ib = 0; ib < FB_UNIT; ib++)
+ : {
+ : /* If the Screen left most bit of the word is set, we're
+ : * starting a box */
+ : if(w & mask0)
+ : {
+ : if(!fInBox)
+ : {
+ : rx1 = base + ib;
+ : /* start new box */
+ : fInBox = TRUE;
+ : }
+ : }
+ : else
+ : {
+ : if(fInBox)
+ : {
+ : /* end box */
+ : ADDRECT(pReg, rects, FirstRect,
+ : rx1, h, base + ib, h + 1);
+ : fInBox = FALSE;
+ : }
+ : }
+ : /* Shift the word VISUALLY left one. */
+ : w = FbScrLeft(w, 1);
+ : }
+ : }
+ : if(width & FB_MASK)
+ : {
+ : /* Process final partial word on line */
+ : w = READ(pw++);
+ : for(ib = 0; ib < (width & FB_MASK); ib++)
+ : {
+ : /* If the Screen left most bit of the word is set, we're
+ : * starting a box */
+ : if(w & mask0)
+ : {
+ : if(!fInBox)
+ : {
+ : rx1 = base + ib;
+ : /* start new box */
+ : fInBox = TRUE;
+ : }
+ : }
+ : else
+ : {
+ : if(fInBox)
+ : {
+ : /* end box */
+ : ADDRECT(pReg, rects, FirstRect,
+ : rx1, h, base + ib, h + 1);
+ : fInBox = FALSE;
+ : }
+ : }
+ : /* Shift the word VISUALLY left one. */
+ : w = FbScrLeft(w, 1);
+ : }
+ : }
+ : /* If scanline ended with last bit set, end the box */
+ : if(fInBox)
+ : {
+ : ADDRECT(pReg, rects, FirstRect,
+ : rx1, h, base + (width & FB_MASK), h + 1);
+ : }
+ : /* if all rectangles on this line have the same x-coords as
+ : * those on the previous line, then add 1 to all the previous y2s and
+ : * throw away all the rectangles from this line
+ : */
+ : fSame = FALSE;
+ : if(irectPrevStart != -1)
+ : {
+ : crects = irectLineStart - irectPrevStart;
+ : if(crects == ((rects - FirstRect) - irectLineStart))
+ : {
+ : prectO = FirstRect + irectPrevStart;
+ : prectN = prectLineStart = FirstRect + irectLineStart;
+ : fSame = TRUE;
+ : while(prectO < prectLineStart)
+ : {
+ : if((prectO->x1 != prectN->x1) || (prectO->x2 != prectN->x2))
+ : {
+ : fSame = FALSE;
+ : break;
+ : }
+ : prectO++;
+ : prectN++;
+ : }
+ : if (fSame)
+ : {
+ : prectO = FirstRect + irectPrevStart;
+ : while(prectO < prectLineStart)
+ : {
+ : prectO->y2 += 1;
+ : prectO++;
+ : }
+ : rects -= crects;
+ : pReg->data->numRects -= crects;
+ : }
+ : }
+ : }
+ : if(!fSame)
+ : irectPrevStart = irectLineStart;
+ : }
+ : if (!pReg->data->numRects)
+ : pReg->extents.x1 = pReg->extents.x2 = 0;
+ : else
+ : {
+ : pReg->extents.y1 = REGION_BOXPTR(pReg)->y1;
+ : pReg->extents.y2 = REGION_END(pReg)->y2;
+ : if (pReg->data->numRects == 1)
+ : {
+ : xfree(pReg->data);
+ : pReg->data = (RegDataPtr)NULL;
+ : }
+ : }
+ :
+ : fbFinishAccess(&pPix->drawable);
+ :#ifdef DEBUG
+ : if (!miValidRegion(pReg))
+ : FatalError("Assertion failed file %s, line %d: expr\n", __FILE__, __LINE__);
+ :#endif
+ : return(pReg);
+ :}
+ :
+ :#ifdef FB_DEBUG
+ :
+ :#ifndef WIN32
+ :#include <stdio.h>
+ :#else
+ :#include <dbg.h>
+ :#endif
+ :
+ :static Bool
+ :fbValidateBits (FbStip *bits, int stride, FbStip data)
+ :{
+ : while (stride--)
+ : {
+ : if (*bits != data)
+ : {
+ :#ifdef WIN32
+ : NCD_DEBUG ((DEBUG_FAILURE, "fdValidateBits failed at 0x%x (is 0x%x want 0x%x)",
+ : bits, *bits, data));
+ :#else
+ : fprintf (stderr, "fbValidateBits failed\n");
+ :#endif
+ : return FALSE;
+ : }
+ : bits++;
+ : }
+ :}
+ :
+ :void
+ :fbValidateDrawable (DrawablePtr pDrawable)
+ :{
+ : FbStip *bits, *first, *last;
+ : int stride, bpp;
+ : int xoff, yoff;
+ : int height;
+ : Bool failed;
+ :
+ : if (pDrawable->type != DRAWABLE_PIXMAP)
+ : pDrawable = (DrawablePtr) fbGetWindowPixmap(pDrawable);
+ : fbGetStipDrawable(pDrawable, bits, stride, bpp, xoff, yoff);
+ : first = bits - stride;
+ : last = bits + stride * pDrawable->height;
+ : if (!fbValidateBits (first, stride, FB_HEAD_BITS) ||
+ : !fbValidateBits (last, stride, FB_TAIL_BITS))
+ : fbInitializeDrawable(pDrawable);
+ : fbFinishAccess (pDrawable);
+ :}
+ :
+ :void
+ :fbSetBits (FbStip *bits, int stride, FbStip data)
+ :{
+ : while (stride--)
+ : *bits++ = data;
+ :}
+ :
+ :void
+ :fbInitializeDrawable (DrawablePtr pDrawable)
+ :{
+ : FbStip *bits, *first, *last;
+ : int stride, bpp;
+ : int xoff, yoff;
+ :
+ : fbGetStipDrawable(pDrawable, bits, stride, bpp, xoff, yoff);
+ : first = bits - stride;
+ : last = bits + stride * pDrawable->height;
+ : fbSetBits (first, stride, FB_HEAD_BITS);
+ : fbSetBits (last, stride, FB_TAIL_BITS);
+ : fbFinishAccess (pDrawable);
+ :}
+ :#endif /* FB_DEBUG */
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/render/miglyph.c"
+ *
+ * 16 0.0174
+ */
+
+
+ :/*
+ : *
+ : * Copyright © 2000 SuSE, Inc.
+ : *
+ : * 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 SuSE not be used in advertising or
+ : * publicity pertaining to distribution of the software without specific,
+ : * written prior permission. SuSE makes no representations about the
+ : * suitability of this software for any purpose. It is provided "as is"
+ : * without express or implied warranty.
+ : *
+ : * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ : * 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: Keith Packard, SuSE, Inc.
+ : */
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include "scrnintstr.h"
+ :#include "gcstruct.h"
+ :#include "pixmapstr.h"
+ :#include "windowstr.h"
+ :#include "mi.h"
+ :#include "picturestr.h"
+ :#include "mipict.h"
+ :
+ :Bool
+ :miRealizeGlyph (ScreenPtr pScreen,
+ : GlyphPtr glyph)
+ :{
+ : return TRUE;
+ :}
+ :
+ :void
+ :miUnrealizeGlyph (ScreenPtr pScreen,
+ : GlyphPtr glyph)
+ :{
+ :}
+ :
+ :_X_EXPORT void
+ :miGlyphExtents (int nlist,
+ : GlyphListPtr list,
+ : GlyphPtr *glyphs,
+ : BoxPtr extents)
+ 2 0.0022 :{ /* miGlyphExtents total: 16 0.0174 */
+ : int x1, x2, y1, y2;
+ : int n;
+ : GlyphPtr glyph;
+ : int x, y;
+ :
+ : x = 0;
+ : y = 0;
+ : extents->x1 = MAXSHORT;
+ : extents->x2 = MINSHORT;
+ : extents->y1 = MAXSHORT;
+ : extents->y2 = MINSHORT;
+ : while (nlist--)
+ : {
+ : x += list->xOff;
+ : y += list->yOff;
+ : n = list->len;
+ : list++;
+ : while (n--)
+ : {
+ : glyph = *glyphs++;
+ 1 0.0011 : x1 = x - glyph->info.x;
+ : if (x1 < MINSHORT)
+ : x1 = MINSHORT;
+ 5 0.0054 : y1 = y - glyph->info.y;
+ : if (y1 < MINSHORT)
+ : y1 = MINSHORT;
+ 2 0.0022 : x2 = x1 + glyph->info.width;
+ : if (x2 > MAXSHORT)
+ : x2 = MAXSHORT;
+ : y2 = y1 + glyph->info.height;
+ : if (y2 > MAXSHORT)
+ : y2 = MAXSHORT;
+ : if (x1 < extents->x1)
+ : extents->x1 = x1;
+ : if (x2 > extents->x2)
+ : extents->x2 = x2;
+ 4 0.0044 : if (y1 < extents->y1)
+ : extents->y1 = y1;
+ 1 0.0011 : if (y2 > extents->y2)
+ : extents->y2 = y2;
+ : x += glyph->info.xOff;
+ 1 0.0011 : y += glyph->info.yOff;
+ : }
+ : }
+ :}
+ :
+ :#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
+ :
+ :_X_EXPORT void
+ :miGlyphs (CARD8 op,
+ : PicturePtr pSrc,
+ : PicturePtr pDst,
+ : PictFormatPtr maskFormat,
+ : INT16 xSrc,
+ : INT16 ySrc,
+ : int nlist,
+ : GlyphListPtr list,
+ : GlyphPtr *glyphs)
+ :{
+ : PixmapPtr pPixmap = 0;
+ : PicturePtr pPicture;
+ : PixmapPtr pMaskPixmap = 0;
+ : PicturePtr pMask;
+ : ScreenPtr pScreen = pDst->pDrawable->pScreen;
+ : int width = 0, height = 0;
+ : int x, y;
+ : int xDst = list->xOff, yDst = list->yOff;
+ : int n;
+ : GlyphPtr glyph;
+ : int error;
+ : BoxRec extents;
+ : CARD32 component_alpha;
+ :
+ : if (maskFormat)
+ : {
+ : GCPtr pGC;
+ : xRectangle rect;
+ :
+ : miGlyphExtents (nlist, list, glyphs, &extents);
+ :
+ : if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
+ : return;
+ : width = extents.x2 - extents.x1;
+ : height = extents.y2 - extents.y1;
+ : pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, maskFormat->depth);
+ : if (!pMaskPixmap)
+ : return;
+ : component_alpha = NeedsComponent(maskFormat->format);
+ : pMask = CreatePicture (0, &pMaskPixmap->drawable,
+ : maskFormat, CPComponentAlpha, &component_alpha,
+ : serverClient, &error);
+ : if (!pMask)
+ : {
+ : (*pScreen->DestroyPixmap) (pMaskPixmap);
+ : return;
+ : }
+ : pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen);
+ : ValidateGC (&pMaskPixmap->drawable, pGC);
+ : rect.x = 0;
+ : rect.y = 0;
+ : rect.width = width;
+ : rect.height = height;
+ : (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect);
+ : FreeScratchGC (pGC);
+ : x = -extents.x1;
+ : y = -extents.y1;
+ : }
+ : else
+ : {
+ : pMask = pDst;
+ : x = 0;
+ : y = 0;
+ : }
+ : pPicture = 0;
+ : while (nlist--)
+ : {
+ : x += list->xOff;
+ : y += list->yOff;
+ : n = list->len;
+ : while (n--)
+ : {
+ : glyph = *glyphs++;
+ : if (!pPicture)
+ : {
+ : pPixmap = GetScratchPixmapHeader (pScreen, glyph->info.width, glyph->info.height,
+ : list->format->depth,
+ : list->format->depth,
+ : 0, (pointer) (glyph + 1));
+ : if (!pPixmap)
+ : return;
+ : component_alpha = NeedsComponent(list->format->format);
+ : pPicture = CreatePicture (0, &pPixmap->drawable, list->format,
+ : CPComponentAlpha, &component_alpha,
+ : serverClient, &error);
+ : if (!pPicture)
+ : {
+ : FreeScratchPixmapHeader (pPixmap);
+ : return;
+ : }
+ : }
+ : (*pScreen->ModifyPixmapHeader) (pPixmap,
+ : glyph->info.width, glyph->info.height,
+ : 0, 0, -1, (pointer) (glyph + 1));
+ : pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ : if (maskFormat)
+ : {
+ : CompositePicture (PictOpAdd,
+ : pPicture,
+ : None,
+ : pMask,
+ : 0, 0,
+ : 0, 0,
+ : x - glyph->info.x,
+ : y - glyph->info.y,
+ : glyph->info.width,
+ : glyph->info.height);
+ : }
+ : else
+ : {
+ : CompositePicture (op,
+ : pSrc,
+ : pPicture,
+ : pDst,
+ : xSrc + (x - glyph->info.x) - xDst,
+ : ySrc + (y - glyph->info.y) - yDst,
+ : 0, 0,
+ : x - glyph->info.x,
+ : y - glyph->info.y,
+ : glyph->info.width,
+ : glyph->info.height);
+ : }
+ : x += glyph->info.xOff;
+ : y += glyph->info.yOff;
+ : }
+ : list++;
+ : if (pPicture)
+ : {
+ : FreeScratchPixmapHeader (pPixmap);
+ : FreePicture ((pointer) pPicture, 0);
+ : pPicture = 0;
+ : pPixmap = 0;
+ : }
+ : }
+ : if (maskFormat)
+ : {
+ : x = extents.x1;
+ : y = extents.y1;
+ : CompositePicture (op,
+ : pSrc,
+ : pMask,
+ : pDst,
+ : xSrc + x - xDst,
+ : ySrc + y - yDst,
+ : 0, 0,
+ : x, y,
+ : width, height);
+ : FreePicture ((pointer) pMask, (XID) 0);
+ : (*pScreen->DestroyPixmap) (pMaskPixmap);
+ : }
+ :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/dix/pixmap.c"
+ *
+ * 16 0.0174
+ */
+
+
+ :/*
+ :
+ :Copyright 1993, 1998 The Open Group
+ :
+ :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.
+ :
+ :The above copyright notice and this permission notice shall be included
+ :in all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ :OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ :MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ :IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ :OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ :ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ :OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of The Open Group shall
+ :not be used in advertising or otherwise to promote the sale, use or
+ :other dealings in this Software without prior written authorization
+ :from The Open Group.
+ :
+ :*/
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include <X11/X.h>
+ :#include "scrnintstr.h"
+ :#include "misc.h"
+ :#include "os.h"
+ :#include "windowstr.h"
+ :#include "resource.h"
+ :#include "dixstruct.h"
+ :#include "gcstruct.h"
+ :#include "servermd.h"
+ :#include "site.h"
+ :
+ :
+ :/*
+ : * Scratch pixmap management and device independent pixmap allocation
+ : * function.
+ : */
+ :
+ :
+ :/* callable by ddx */
+ :_X_EXPORT PixmapPtr
+ :GetScratchPixmapHeader(ScreenPtr pScreen, int width, int height, int depth,
+ : int bitsPerPixel, int devKind, pointer pPixData)
+ 1 0.0011 :{ /* GetScratchPixmapHeader total: 1 0.0011 */
+ : PixmapPtr pPixmap = pScreen->pScratchPixmap;
+ :
+ : if (pPixmap)
+ : pScreen->pScratchPixmap = NULL;
+ : else
+ : /* width and height of 0 means don't allocate any pixmap data */
+ : pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth);
+ :
+ : if (pPixmap) {
+ : if ((*pScreen->ModifyPixmapHeader)(pPixmap, width, height, depth,
+ : bitsPerPixel, devKind, pPixData))
+ : return pPixmap;
+ : (*pScreen->DestroyPixmap)(pPixmap);
+ : }
+ : return NullPixmap;
+ :}
+ :
+ :
+ :/* callable by ddx */
+ :_X_EXPORT void
+ :FreeScratchPixmapHeader(PixmapPtr pPixmap)
+ 1 0.0011 :{ /* FreeScratchPixmapHeader total: 2 0.0022 */
+ : if (pPixmap)
+ : {
+ : ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ :
+ : pPixmap->devPrivate.ptr = NULL; /* lest ddx chases bad ptr */
+ : if (pScreen->pScratchPixmap)
+ : (*pScreen->DestroyPixmap)(pPixmap);
+ : else
+ : pScreen->pScratchPixmap = pPixmap;
+ : }
+ 1 0.0011 :}
+ :
+ :
+ :Bool
+ :CreateScratchPixmapsForScreen(int scrnum)
+ :{
+ : /* let it be created on first use */
+ : screenInfo.screens[scrnum]->pScratchPixmap = NULL;
+ : return TRUE;
+ :}
+ :
+ :
+ :void
+ :FreeScratchPixmapsForScreen(int scrnum)
+ :{
+ : FreeScratchPixmapHeader(screenInfo.screens[scrnum]->pScratchPixmap);
+ :}
+ :
+ :
+ :/* callable by ddx */
+ :_X_EXPORT PixmapPtr
+ :AllocatePixmap(ScreenPtr pScreen, int pixDataSize)
+ 3 0.0033 :{ /* AllocatePixmap total: 13 0.0142 */
+ : PixmapPtr pPixmap;
+ : char *ptr;
+ : DevUnion *ppriv;
+ : unsigned *sizes;
+ : unsigned size;
+ : int i;
+ :
+ : if (pScreen->totalPixmapSize > ((size_t)-1) - pixDataSize)
+ : return NullPixmap;
+ :
+ : pPixmap = (PixmapPtr)xalloc(pScreen->totalPixmapSize + pixDataSize);
+ : if (!pPixmap)
+ : return NullPixmap;
+ : ppriv = (DevUnion *)(pPixmap + 1);
+ : pPixmap->devPrivates = ppriv;
+ : sizes = pScreen->PixmapPrivateSizes;
+ 1 0.0011 : ptr = (char *)(ppriv + pScreen->PixmapPrivateLen);
+ 1 0.0011 : for (i = pScreen->PixmapPrivateLen; --i >= 0; ppriv++, sizes++)
+ : {
+ 2 0.0022 : if ((size = *sizes) != 0)
+ : {
+ 1 0.0011 : ppriv->ptr = (pointer)ptr;
+ 1 0.0011 : ptr += size;
+ : }
+ : else
+ 2 0.0022 : ppriv->ptr = (pointer)NULL;
+ : }
+ :
+ :#ifdef _XSERVER64
+ : if (pPixmap) {
+ : pPixmap->drawable.pad0 = 0;
+ : pPixmap->drawable.pad1 = 0;
+ : }
+ :#endif
+ :
+ : return pPixmap;
+ 2 0.0022 :}
+/*
+ * Total samples for file : "fbpseudocolor.c"
+ *
+ * 14 0.0153
+ */
+
+<credited to line zero> 14 0.0153 :
+ /* __i686.get_pc_thunk.cx total: 2 0.0022 */
+ /* __i686.get_pc_thunk.bx total: 12 0.0131 */
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/render/mitrap.c"
+ *
+ * 12 0.0131
+ */
+
+
+ :/*
+ : *
+ : * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+ : *
+ : * 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 Keith Packard not be used in
+ : * advertising or publicity pertaining to distribution of the software without
+ : * specific, written prior permission. Keith Packard makes no
+ : * representations about the suitability of this software for any purpose. It
+ : * is provided "as is" without express or implied warranty.
+ : *
+ : * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ : * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ : * EVENT SHALL KEITH PACKARD 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.
+ : */
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include "scrnintstr.h"
+ :#include "gcstruct.h"
+ :#include "pixmapstr.h"
+ :#include "windowstr.h"
+ :#include "servermd.h"
+ :#include "mi.h"
+ :#include "picturestr.h"
+ :#include "mipict.h"
+ :
+ :PicturePtr
+ :miCreateAlphaPicture (ScreenPtr pScreen,
+ : PicturePtr pDst,
+ : PictFormatPtr pPictFormat,
+ : CARD16 width,
+ : CARD16 height)
+ :{
+ : PixmapPtr pPixmap;
+ : PicturePtr pPicture;
+ : GCPtr pGC;
+ : int error;
+ : xRectangle rect;
+ :
+ : if (width > 32767 || height > 32767)
+ : return 0;
+ :
+ : if (!pPictFormat)
+ : {
+ : if (pDst->polyEdge == PolyEdgeSharp)
+ : pPictFormat = PictureMatchFormat (pScreen, 1, PICT_a1);
+ : else
+ : pPictFormat = PictureMatchFormat (pScreen, 8, PICT_a8);
+ : if (!pPictFormat)
+ : return 0;
+ : }
+ :
+ : pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
+ : pPictFormat->depth);
+ : if (!pPixmap)
+ : return 0;
+ : pGC = GetScratchGC (pPixmap->drawable.depth, pScreen);
+ : if (!pGC)
+ : {
+ : (*pScreen->DestroyPixmap) (pPixmap);
+ : return 0;
+ : }
+ : ValidateGC (&pPixmap->drawable, pGC);
+ : rect.x = 0;
+ : rect.y = 0;
+ : rect.width = width;
+ : rect.height = height;
+ : (*pGC->ops->PolyFillRect)(&pPixmap->drawable, pGC, 1, &rect);
+ : FreeScratchGC (pGC);
+ : pPicture = CreatePicture (0, &pPixmap->drawable, pPictFormat,
+ : 0, 0, serverClient, &error);
+ : (*pScreen->DestroyPixmap) (pPixmap);
+ : return pPicture;
+ :}
+ :
+ :static xFixed
+ :miLineFixedX (xLineFixed *l, xFixed y, Bool ceil)
+ :{ /* miLineFixedX total: 8 0.0087 */
+ : xFixed dx = l->p2.x - l->p1.x;
+ 1 0.0011 : xFixed_32_32 ex = (xFixed_32_32) (y - l->p1.y) * dx;
+ 1 0.0011 : xFixed dy = l->p2.y - l->p1.y;
+ : if (ceil)
+ 4 0.0044 : ex += (dy - 1);
+ : return l->p1.x + (xFixed) (ex / dy);
+ 2 0.0022 :}
+ :
+ :void
+ :miTrapezoidBounds (int ntrap, xTrapezoid *traps, BoxPtr box)
+ :{ /* miTrapezoidBounds total: 3 0.0033 */
+ : box->y1 = MAXSHORT;
+ : box->y2 = MINSHORT;
+ : box->x1 = MAXSHORT;
+ : box->x2 = MINSHORT;
+ : for (; ntrap; ntrap--, traps++)
+ : {
+ : INT16 x1, y1, x2, y2;
+ :
+ : if (!xTrapezoidValid(traps))
+ : continue;
+ : y1 = xFixedToInt (traps->top);
+ : if (y1 < box->y1)
+ : box->y1 = y1;
+ :
+ : y2 = xFixedToInt (xFixedCeil (traps->bottom));
+ : if (y2 > box->y2)
+ : box->y2 = y2;
+ :
+ : x1 = xFixedToInt (min (miLineFixedX (&traps->left, traps->top, FALSE),
+ : miLineFixedX (&traps->left, traps->bottom, FALSE)));
+ : if (x1 < box->x1)
+ : box->x1 = x1;
+ :
+ 3 0.0033 : x2 = xFixedToInt (xFixedCeil (max (miLineFixedX (&traps->right, traps->top, TRUE),
+ : miLineFixedX (&traps->right, traps->bottom, TRUE))));
+ : if (x2 > box->x2)
+ : box->x2 = x2;
+ : }
+ :}
+ :
+ :void
+ :miTrapezoids (CARD8 op,
+ : PicturePtr pSrc,
+ : PicturePtr pDst,
+ : PictFormatPtr maskFormat,
+ : INT16 xSrc,
+ : INT16 ySrc,
+ : int ntrap,
+ : xTrapezoid *traps)
+ :{ /* miTrapezoids total: 1 0.0011 */
+ : ScreenPtr pScreen = pDst->pDrawable->pScreen;
+ : PictureScreenPtr ps = GetPictureScreen(pScreen);
+ :
+ : /*
+ : * Check for solid alpha add
+ : */
+ : if (op == PictOpAdd && miIsSolidAlpha (pSrc))
+ : {
+ : for (; ntrap; ntrap--, traps++)
+ : (*ps->RasterizeTrapezoid) (pDst, traps, 0, 0);
+ : }
+ : else if (maskFormat)
+ : {
+ : PicturePtr pPicture;
+ : BoxRec bounds;
+ : INT16 xDst, yDst;
+ : INT16 xRel, yRel;
+ :
+ : xDst = traps[0].left.p1.x >> 16;
+ : yDst = traps[0].left.p1.y >> 16;
+ :
+ : miTrapezoidBounds (ntrap, traps, &bounds);
+ : if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
+ : return;
+ : pPicture = miCreateAlphaPicture (pScreen, pDst, maskFormat,
+ : bounds.x2 - bounds.x1,
+ : bounds.y2 - bounds.y1);
+ : if (!pPicture)
+ : return;
+ 1 0.0011 : for (; ntrap; ntrap--, traps++)
+ : (*ps->RasterizeTrapezoid) (pPicture, traps,
+ : -bounds.x1, -bounds.y1);
+ : xRel = bounds.x1 + xSrc - xDst;
+ : yRel = bounds.y1 + ySrc - yDst;
+ : CompositePicture (op, pSrc, pPicture, pDst,
+ : xRel, yRel, 0, 0, bounds.x1, bounds.y1,
+ : bounds.x2 - bounds.x1,
+ : bounds.y2 - bounds.y1);
+ : FreePicture (pPicture, 0);
+ : }
+ : else
+ : {
+ : if (pDst->polyEdge == PolyEdgeSharp)
+ : maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1);
+ : else
+ : maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8);
+ : for (; ntrap; ntrap--, traps++)
+ : miTrapezoids (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps);
+ : }
+ :}
+/*
+ * Total samples for file : "/home/cworth/src/pixman/pixman/pixman-image.c"
+ *
+ * 10 0.0109
+ */
+
+
+ :/*
+ : * Copyright © 2000 SuSE, Inc.
+ : * Copyright © 2007 Red Hat, Inc.
+ : *
+ : * 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 SuSE not be used in advertising or
+ : * publicity pertaining to distribution of the software without specific,
+ : * written prior permission. SuSE makes no representations about the
+ : * suitability of this software for any purpose. It is provided "as is"
+ : * without express or implied warranty.
+ : *
+ : * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ : * 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.
+ : */
+ :
+ :#include <config.h>
+ :
+ :#include <stdlib.h>
+ :#include <stdio.h>
+ :#include <string.h>
+ :
+ :#include "pixman.h"
+ :#include "pixman-private.h"
+ :
+ :static void
+ :init_source_image (source_image_t *image)
+ :{
+ : image->class = SOURCE_IMAGE_CLASS_UNKNOWN;
+ :}
+ :
+ :static pixman_bool_t
+ :init_gradient (gradient_t *gradient,
+ : const pixman_gradient_stop_t *stops,
+ : int n_stops)
+ :{
+ : return_val_if_fail (n_stops > 0, FALSE);
+ :
+ : init_source_image (&gradient->common);
+ :
+ : gradient->stops = malloc (n_stops * sizeof (pixman_gradient_stop_t));
+ : if (!gradient->stops)
+ : return FALSE;
+ :
+ : memcpy (gradient->stops, stops, n_stops * sizeof (pixman_gradient_stop_t));
+ :
+ : gradient->n_stops = n_stops;
+ :
+ : gradient->stop_range = 0xffff;
+ : gradient->color_table = NULL;
+ : gradient->color_table_size = 0;
+ :
+ : return TRUE;
+ :}
+ :
+ :static uint32_t
+ :color_to_uint32 (const pixman_color_t *color)
+ :{
+ : return
+ : (color->alpha >> 8 << 24) |
+ : (color->red >> 8 << 16) |
+ : (color->green & 0xff00) |
+ : (color->blue >> 8);
+ :}
+ :
+ :static pixman_image_t *image_cache;
+ :
+ :static pixman_image_t *
+ :new_image (void)
+ :{
+ : pixman_image_t *image;
+ :
+ : if (image_cache)
+ : {
+ : image = image_cache;
+ : image_cache = image->next;
+ : }
+ : else
+ : {
+ : image = malloc (sizeof (pixman_image_t));
+ : }
+ :
+ : return image;
+ :}
+ :
+ :static void
+ :delete_image (pixman_image_t *image)
+ :{
+ : image->next = image_cache;
+ : image_cache = image;
+ :}
+ :
+ :static pixman_image_t *
+ :allocate_image (void)
+ :{ /* allocate_image total: 7 0.0076 */
+ : pixman_image_t *image = new_image();
+ :
+ : if (image)
+ : {
+ : image_common_t *common = &image->common;
+ :
+ : pixman_region_init (&common->full_region);
+ 1 0.0011 : pixman_region_init (&common->clip_region);
+ : common->src_clip = &common->full_region;
+ : common->has_client_clip = FALSE;
+ : common->transform = NULL;
+ : common->repeat = PIXMAN_REPEAT_NONE;
+ : common->filter = PIXMAN_FILTER_NEAREST;
+ : common->filter_params = NULL;
+ 1 0.0011 : common->n_filter_params = 0;
+ 1 0.0011 : common->alpha_map = NULL;
+ : common->component_alpha = FALSE;
+ 1 0.0011 : common->ref_count = 1;
+ : common->read_func = NULL;
+ 1 0.0011 : common->write_func = NULL;
+ : }
+ :
+ : return image;
+ 2 0.0022 :}
+ :
+ :/* Ref Counting */
+ :pixman_image_t *
+ :pixman_image_ref (pixman_image_t *image)
+ :{
+ : image->common.ref_count++;
+ :
+ : return image;
+ :}
+ :
+ :void
+ :pixman_image_unref (pixman_image_t *image)
+ 1 0.0011 :{ /* pixman_image_unref total: 2 0.0022 */
+ : image_common_t *common = (image_common_t *)image;
+ :
+ : common->ref_count--;
+ :
+ : if (common->ref_count == 0)
+ : {
+ : pixman_region_fini (&common->clip_region);
+ : pixman_region_fini (&common->full_region);
+ :
+ : if (common->transform)
+ : free (common->transform);
+ :
+ : if (common->filter_params)
+ : free (common->filter_params);
+ :
+ : if (common->alpha_map)
+ : pixman_image_unref ((pixman_image_t *)common->alpha_map);
+ :
+ :#if 0
+ : if (image->type == BITS && image->bits.indexed)
+ : free (image->bits.indexed);
+ :#endif
+ :
+ :#if 0
+ : memset (image, 0xaa, sizeof (pixman_image_t));
+ :#endif
+ : if (image->type == LINEAR || image->type == RADIAL || image->type == CONICAL)
+ : {
+ : if (image->gradient.stops)
+ : free (image->gradient.stops);
+ : }
+ :
+ :
+ : if (image->type == BITS && image->bits.free_me)
+ : free (image->bits.free_me);
+ :
+ : delete_image (image);
+ : }
+ :}
+ :
+ :/* Constructors */
+ :pixman_image_t *
+ :pixman_image_create_solid_fill (pixman_color_t *color)
+ :{
+ : pixman_image_t *img = allocate_image();
+ : if (!img)
+ : return NULL;
+ :
+ : init_source_image (&img->solid.common);
+ :
+ : img->type = SOLID;
+ : img->solid.color = color_to_uint32 (color);
+ :
+ : return img;
+ :}
+ :
+ :pixman_image_t *
+ :pixman_image_create_linear_gradient (pixman_point_fixed_t *p1,
+ : pixman_point_fixed_t *p2,
+ : const pixman_gradient_stop_t *stops,
+ : int n_stops)
+ :{
+ : pixman_image_t *image;
+ : linear_gradient_t *linear;
+ :
+ : return_val_if_fail (n_stops >= 2, NULL);
+ :
+ : image = allocate_image();
+ :
+ : if (!image)
+ : return NULL;
+ :
+ : linear = &image->linear;
+ :
+ : if (!init_gradient (&linear->common, stops, n_stops))
+ : {
+ : free (image);
+ : return NULL;
+ : }
+ :
+ : linear->p1 = *p1;
+ : linear->p2 = *p2;
+ :
+ : image->type = LINEAR;
+ :
+ : return image;
+ :}
+ :
+ :
+ :pixman_image_t *
+ :pixman_image_create_radial_gradient (pixman_point_fixed_t *inner,
+ : pixman_point_fixed_t *outer,
+ : pixman_fixed_t inner_radius,
+ : pixman_fixed_t outer_radius,
+ : const pixman_gradient_stop_t *stops,
+ : int n_stops)
+ :{
+ : pixman_image_t *image;
+ : radial_gradient_t *radial;
+ :
+ : return_val_if_fail (n_stops >= 2, NULL);
+ :
+ : image = allocate_image();
+ :
+ : if (!image)
+ : return NULL;
+ :
+ : radial = &image->radial;
+ :
+ : if (!init_gradient (&radial->common, stops, n_stops))
+ : {
+ : free (image);
+ : return NULL;
+ : }
+ :
+ : image->type = RADIAL;
+ :
+ : radial->c1.x = inner->x;
+ : radial->c1.y = inner->y;
+ : radial->c1.radius = inner_radius;
+ : radial->c2.x = outer->x;
+ : radial->c2.y = outer->y;
+ : radial->c2.radius = outer_radius;
+ : radial->cdx = pixman_fixed_to_double (radial->c2.x - radial->c1.x);
+ : radial->cdy = pixman_fixed_to_double (radial->c2.y - radial->c1.y);
+ : radial->dr = pixman_fixed_to_double (radial->c2.radius - radial->c1.radius);
+ : radial->A = (radial->cdx * radial->cdx
+ : + radial->cdy * radial->cdy
+ : - radial->dr * radial->dr);
+ :
+ : return image;
+ :}
+ :
+ :pixman_image_t *
+ :pixman_image_create_conical_gradient (pixman_point_fixed_t *center,
+ : pixman_fixed_t angle,
+ : const pixman_gradient_stop_t *stops,
+ : int n_stops)
+ :{
+ : pixman_image_t *image = allocate_image();
+ : conical_gradient_t *conical;
+ :
+ : if (!image)
+ : return NULL;
+ :
+ : conical = &image->conical;
+ :
+ : if (!init_gradient (&conical->common, stops, n_stops))
+ : {
+ : free (image);
+ : return NULL;
+ : }
+ :
+ : image->type = CONICAL;
+ : conical->center = *center;
+ : conical->angle = angle;
+ :
+ : return image;
+ :}
+ :
+ :static uint32_t *
+ :create_bits (pixman_format_code_t format,
+ : int width,
+ : int height,
+ : int *rowstride_bytes)
+ :{
+ : int stride;
+ : int buf_size;
+ : int bpp;
+ :
+ : bpp = PIXMAN_FORMAT_BPP (format);
+ : stride = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof (uint32_t);
+ : buf_size = height * stride;
+ :
+ : if (rowstride_bytes)
+ : *rowstride_bytes = stride;
+ :
+ : return calloc (buf_size, 1);
+ :}
+ :
+ :static void
+ :reset_clip_region (pixman_image_t *image)
+ :{
+ : pixman_region_fini (&image->common.clip_region);
+ :
+ : if (image->type == BITS)
+ : {
+ : pixman_region_init_rect (&image->common.clip_region, 0, 0,
+ : image->bits.width, image->bits.height);
+ : }
+ : else
+ : {
+ : pixman_region_init (&image->common.clip_region);
+ : }
+ :}
+ :
+ :pixman_image_t *
+ :pixman_image_create_bits (pixman_format_code_t format,
+ : int width,
+ : int height,
+ : uint32_t *bits,
+ : int rowstride_bytes)
+ 1 0.0011 :{ /* pixman_image_create_bits total: 1 0.0011 */
+ : pixman_image_t *image;
+ : uint32_t *free_me = NULL;
+ :
+ : /* must be a whole number of uint32_t's
+ : */
+ : return_val_if_fail (bits == NULL ||
+ : (rowstride_bytes % sizeof (uint32_t)) == 0, NULL);
+ :
+ : if (!bits)
+ : {
+ : free_me = bits = create_bits (format, width, height, &rowstride_bytes);
+ : if (!bits)
+ : return NULL;
+ : }
+ :
+ : image = allocate_image();
+ :
+ : if (!image)
+ : return NULL;
+ :
+ : image->type = BITS;
+ : image->bits.format = format;
+ : image->bits.width = width;
+ : image->bits.height = height;
+ : image->bits.bits = bits;
+ : image->bits.free_me = free_me;
+ :
+ : image->bits.rowstride = rowstride_bytes / sizeof (uint32_t); /* we store it in number
+ : * of uint32_t's
+ : */
+ : image->bits.indexed = NULL;
+ :
+ : pixman_region_fini (&image->common.full_region);
+ : pixman_region_init_rect (&image->common.full_region, 0, 0,
+ : image->bits.width, image->bits.height);
+ :
+ : reset_clip_region (image);
+ : return image;
+ :}
+ :
+ :pixman_bool_t
+ :pixman_image_set_clip_region (pixman_image_t *image,
+ : pixman_region16_t *region)
+ :{
+ : image_common_t *common = (image_common_t *)image;
+ :
+ : if (region)
+ : {
+ : return pixman_region_copy (&common->clip_region, region);
+ : }
+ : else
+ : {
+ : reset_clip_region (image);
+ :
+ : return TRUE;
+ : }
+ :}
+ :
+ :/* Sets whether the clip region includes a clip region set by the client
+ : */
+ :void
+ :pixman_image_set_has_client_clip (pixman_image_t *image,
+ : pixman_bool_t client_clip)
+ :{
+ : image->common.has_client_clip = client_clip;
+ :}
+ :
+ :pixman_bool_t
+ :pixman_image_set_transform (pixman_image_t *image,
+ : const pixman_transform_t *transform)
+ :{
+ : static const pixman_transform_t id =
+ : {
+ : { { pixman_fixed_1, 0, 0 },
+ : { 0, pixman_fixed_1, 0 },
+ : { 0, 0, pixman_fixed_1 }
+ : }
+ : };
+ :
+ : image_common_t *common = (image_common_t *)image;
+ :
+ : if (common->transform == transform)
+ : return TRUE;
+ :
+ : if (memcmp (&id, transform, sizeof (pixman_transform_t)) == 0)
+ : {
+ : transform = NULL;
+ : return TRUE;
+ : }
+ :
+ : if (common->transform)
+ : free (common->transform);
+ :
+ : if (transform)
+ : {
+ : common->transform = malloc (sizeof (pixman_transform_t));
+ : if (!common->transform)
+ : return FALSE;
+ :
+ : *common->transform = *transform;
+ : }
+ : else
+ : {
+ : common->transform = NULL;
+ : }
+ :
+ : return TRUE;
+ :}
+ :
+ :void
+ :pixman_image_set_repeat (pixman_image_t *image,
+ : pixman_repeat_t repeat)
+ 1 0.0011 :{ /* pixman_image_set_repeat total: 1 0.0011 */
+ : image->common.repeat = repeat;
+ :}
+ :
+ :pixman_bool_t
+ :pixman_image_set_filter (pixman_image_t *image,
+ : pixman_filter_t filter,
+ : const pixman_fixed_t *params,
+ : int n_params)
+ :{
+ : image_common_t *common = (image_common_t *)image;
+ : pixman_fixed_t *new_params;
+ :
+ : if (params == common->filter_params && filter == common->filter)
+ : return TRUE;
+ :
+ : new_params = NULL;
+ : if (params)
+ : {
+ : new_params = malloc (n_params * sizeof (pixman_fixed_t));
+ : if (!new_params)
+ : return FALSE;
+ :
+ : memcpy (new_params,
+ : params, n_params * sizeof (pixman_fixed_t));
+ : }
+ :
+ : common->filter = filter;
+ :
+ : if (common->filter_params)
+ : free (common->filter_params);
+ :
+ : common->filter_params = new_params;
+ : common->n_filter_params = n_params;
+ : return TRUE;
+ :}
+ :
+ :/* Unlike all the other property setters, this function does not
+ : * copy the content of indexed. Doing this copying is simply
+ : * way, way too expensive.
+ : */
+ :void
+ :pixman_image_set_indexed (pixman_image_t *image,
+ : const pixman_indexed_t *indexed)
+ :{
+ : bits_image_t *bits = (bits_image_t *)image;
+ :
+ : bits->indexed = indexed;
+ :}
+ :
+ :void
+ :pixman_image_set_alpha_map (pixman_image_t *image,
+ : pixman_image_t *alpha_map,
+ : int16_t x,
+ : int16_t y)
+ :{
+ : image_common_t *common = (image_common_t *)image;
+ :
+ : return_if_fail (!alpha_map || alpha_map->type == BITS);
+ :
+ : if (common->alpha_map != (bits_image_t *)alpha_map)
+ : {
+ : if (common->alpha_map)
+ : pixman_image_unref ((pixman_image_t *)common->alpha_map);
+ :
+ : if (alpha_map)
+ : common->alpha_map = (bits_image_t *)pixman_image_ref (alpha_map);
+ : else
+ : common->alpha_map = NULL;
+ : }
+ :
+ : common->alpha_origin.x = x;
+ : common->alpha_origin.y = y;
+ :}
+ :
+ :void
+ :pixman_image_set_component_alpha (pixman_image_t *image,
+ : pixman_bool_t component_alpha)
+ :{
+ : image->common.component_alpha = component_alpha;
+ :}
+ :
+ :
+ :void
+ :pixman_image_set_accessors (pixman_image_t *image,
+ : pixman_read_memory_func_t read_func,
+ : pixman_write_memory_func_t write_func)
+ :{
+ : return_if_fail (image != NULL);
+ :
+ : image->common.read_func = read_func;
+ : image->common.write_func = write_func;
+ :}
+ :
+ :uint32_t *
+ :pixman_image_get_data (pixman_image_t *image)
+ :{
+ : if (image->type == BITS)
+ : return image->bits.bits;
+ :
+ : return NULL;
+ :}
+ :
+ :int
+ :pixman_image_get_width (pixman_image_t *image)
+ :{
+ : if (image->type == BITS)
+ : return image->bits.width;
+ :
+ : return 0;
+ :}
+ :
+ :int
+ :pixman_image_get_height (pixman_image_t *image)
+ :{
+ : if (image->type == BITS)
+ : return image->bits.height;
+ :
+ : return 0;
+ :}
+ :
+ :int
+ :pixman_image_get_stride (pixman_image_t *image)
+ :{
+ : if (image->type == BITS)
+ : return image->bits.rowstride * sizeof (uint32_t);
+ :
+ : return 0;
+ :}
+ :
+ :int
+ :pixman_image_get_depth (pixman_image_t *image)
+ :{
+ : if (image->type == BITS)
+ : return PIXMAN_FORMAT_DEPTH (image->bits.format);
+ :
+ : return 0;
+ :}
+ :
+ :pixman_bool_t
+ :color_to_pixel (pixman_color_t *color,
+ : uint32_t *pixel,
+ : pixman_format_code_t format)
+ :{
+ : uint32_t c = color_to_uint32 (color);
+ :
+ : if (!(format == PIXMAN_a8r8g8b8 ||
+ : format == PIXMAN_x8r8g8b8 ||
+ : format == PIXMAN_a8b8g8r8 ||
+ : format == PIXMAN_x8b8g8r8 ||
+ : format == PIXMAN_r5g6b5 ||
+ : format == PIXMAN_b5g6r5 ||
+ : format == PIXMAN_a8))
+ : {
+ : return FALSE;
+ : }
+ :
+ : if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR)
+ : {
+ : c = ((c & 0xff000000) >> 0) |
+ : ((c & 0x00ff0000) >> 16) |
+ : ((c & 0x0000ff00) >> 0) |
+ : ((c & 0x000000ff) << 16);
+ : }
+ :
+ : if (format == PIXMAN_a8)
+ : c = c >> 24;
+ : else if (format == PIXMAN_r5g6b5 ||
+ : format == PIXMAN_b5g6r5)
+ : c = cvt8888to0565 (c);
+ :
+ :#if 0
+ : printf ("color: %x %x %x %x\n", color->alpha, color->red, color->green, color->blue);
+ : printf ("pixel: %x\n", c);
+ :#endif
+ :
+ : *pixel = c;
+ : return TRUE;
+ :}
+ :
+ :pixman_bool_t
+ :pixman_image_fill_rectangles (pixman_op_t op,
+ : pixman_image_t *dest,
+ : pixman_color_t *color,
+ : int n_rects,
+ : const pixman_rectangle16_t *rects)
+ :{
+ : pixman_image_t *solid;
+ : pixman_color_t c;
+ : int i;
+ :
+ : if (color->alpha == 0xffff)
+ : {
+ : if (op == PIXMAN_OP_OVER)
+ : op = PIXMAN_OP_SRC;
+ : }
+ :
+ : if (op == PIXMAN_OP_CLEAR)
+ : {
+ : c.red = 0;
+ : c.green = 0;
+ : c.blue = 0;
+ : c.alpha = 0;
+ :
+ : color = &c;
+ :
+ : op = PIXMAN_OP_SRC;
+ : }
+ :
+ : if (op == PIXMAN_OP_SRC)
+ : {
+ : uint32_t pixel;
+ :
+ : if (color_to_pixel (color, &pixel, dest->bits.format))
+ : {
+ : for (i = 0; i < n_rects; ++i)
+ : {
+ : pixman_region16_t fill_region;
+ : int n_boxes, j;
+ : pixman_box16_t *boxes;
+ :
+ : pixman_region_init_rect (&fill_region, rects[i].x, rects[i].y, rects[i].width, rects[i].height);
+ : pixman_region_intersect (&fill_region, &fill_region, &dest->common.clip_region);
+ :
+ : boxes = pixman_region_rectangles (&fill_region, &n_boxes);
+ : for (j = 0; j < n_boxes; ++j)
+ : {
+ : const pixman_box16_t *box = &(boxes[j]);
+ : pixman_fill (dest->bits.bits, dest->bits.rowstride, PIXMAN_FORMAT_BPP (dest->bits.format),
+ : box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1,
+ : pixel);
+ : }
+ :
+ : pixman_region_fini (&fill_region);
+ : }
+ : return TRUE;
+ : }
+ : }
+ :
+ : solid = pixman_image_create_solid_fill (color);
+ : if (!solid)
+ : return FALSE;
+ :
+ : for (i = 0; i < n_rects; ++i)
+ : {
+ : const pixman_rectangle16_t *rect = &(rects[i]);
+ :
+ : pixman_image_composite (op, solid, NULL, dest,
+ : 0, 0, 0, 0,
+ : rect->x, rect->y,
+ : rect->width, rect->height);
+ : }
+ :
+ : pixman_image_unref (solid);
+ :
+ : return TRUE;
+ :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/mi/mibstore.c"
+ *
+ * 9 0.0098
+ */
+
+
+ :/***********************************************************
+ :
+ :Copyright 1987, 1998 The Open Group
+ :
+ :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.
+ :
+ :The above copyright notice and this permission notice shall be included in
+ :all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ :IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ :FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ :OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ :AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ :CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of The Open Group shall not be
+ :used in advertising or otherwise to promote the sale, use or other dealings
+ :in this Software without prior written authorization from The Open Group.
+ :
+ :
+ :Copyright 1987 by the Regents of the University of California
+ :
+ : All Rights Reserved
+ :
+ :Permission to use, copy, modify, and distribute this software and its
+ :documentation for any purpose and without fee is hereby granted, 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 The Open Group not be used in advertising or publicity
+ :pertaining to distribution of the software without specific, written prior
+ :permission.
+ :
+ :The University of California makes no representations about the suitability
+ :of this software for any purpose. It is provided "as is" without express or
+ :implied warranty.
+ :
+ :******************************************************************/
+ :
+ :
+ :#define NEED_EVENTS
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include <X11/X.h>
+ :#include <X11/Xmd.h>
+ :#include <X11/Xproto.h>
+ :#include "misc.h"
+ :#include "regionstr.h"
+ :#include "scrnintstr.h"
+ :#include "gcstruct.h"
+ :#include "windowstr.h"
+ :#include "pixmapstr.h"
+ :#include <X11/fonts/fontstruct.h>
+ :#include "dixfontstr.h"
+ :#include "dixstruct.h" /* For requestingClient */
+ :#include "mi.h"
+ :#include "mibstorest.h"
+ :
+ :/*
+ : * When the server fails to allocate a backing store pixmap, if you want
+ : * it to dynamically retry to allocate backing store on every subsequent
+ : * graphics op, you can enable BSEAGER; otherwise, backing store will be
+ : * disabled on the window until it is unmapped and then remapped.
+ : */
+ :/* #define BSEAGER */
+ :
+ :/*-
+ : * NOTES ON USAGE:
+ : *
+ : * The functions in this file implement a machine-independent backing-store
+ : * scheme. To use it, the output library must do the following:
+ : * - Provide a SaveAreas function that takes a destination pixmap, a
+ : * region of the areas to save (in the pixmap's coordinate system)
+ : * and the screen origin of the region. It should copy the areas from
+ : * the screen into the pixmap.
+ : * - Provide a RestoreAreas function that takes a source pixmap, a region
+ : * of the areas to restore (in the screen's coordinate system) and the
+ : * origin of the pixmap on the screen. It should copy the areas from
+ : * the pixmap into the screen.
+ : * - Provide a SetClipmaskRgn function that takes a gc and a region
+ : * and merges the region into any CT_PIXMAP client clip that
+ : * is specified in the GC. This routine is only needed if
+ : * miValidateBackingStore will see CT_PIXMAP clip lists; not
+ : * true for any of the sample servers (which convert the PIXMAP
+ : * clip lists into CT_REGION clip lists; an expensive but simple
+ : * to code option).
+ : * - The function placed in a window's ClearToBackground vector must call
+ : * pScreen->ClearBackingStore with the window, followed by
+ : * the window-relative x and y coordinates, followed by the width and
+ : * height of the area to be cleared, followed by the generateExposures
+ : * flag. This has been taken care of in miClearToBackground.
+ : * - Whatever determines GraphicsExpose events for the CopyArea and
+ : * CopyPlane requests should call pWin->backStorage->ExposeCopy
+ : * with the source and destination drawables, the GC used, a source-
+ : * window-relative region of exposed areas, the source and destination
+ : * coordinates and the bitplane copied, if CopyPlane, or 0, if
+ : * CopyArea.
+ : *
+ : * JUSTIFICATION
+ : * This is a cross between saving everything and just saving the
+ : * obscued areas (as in Pike's layers.) This method has the advantage
+ : * of only doing each output operation once per pixel, visible or
+ : * invisible, and avoids having to do all the crufty storage
+ : * management of keeping several separate rectangles. Since the
+ : * ddx layer ouput primitives are required to draw through clipping
+ : * rectangles anyway, sending multiple drawing requests for each of
+ : * several rectangles isn't necessary. (Of course, it could be argued
+ : * that the ddx routines should just take one rectangle each and
+ : * get called multiple times, but that would make taking advantage of
+ : * smart hardware harder, and probably be slower as well.)
+ : */
+ :
+ :#define SETUP_BACKING_TERSE(pGC) \
+ : miBSGCPtr pGCPrivate = (miBSGCPtr)(pGC)->devPrivates[miBSGCIndex].ptr; \
+ : GCFuncs *oldFuncs = pGC->funcs;
+ :
+ :#define SETUP_BACKING(pDrawable,pGC) \
+ : miBSWindowPtr pBackingStore = \
+ : (miBSWindowPtr)((WindowPtr)(pDrawable))->backStorage; \
+ : DrawablePtr pBackingDrawable = (DrawablePtr) \
+ : pBackingStore->pBackingPixmap; \
+ : SETUP_BACKING_TERSE(pGC) \
+ : GCPtr pBackingGC = pGCPrivate->pBackingGC;
+ :
+ :#define PROLOGUE(pGC) { \
+ : pGC->ops = pGCPrivate->wrapOps;\
+ : pGC->funcs = pGCPrivate->wrapFuncs; \
+ : }
+ :
+ :#define EPILOGUE(pGC) { \
+ : pGCPrivate->wrapOps = (pGC)->ops; \
+ : (pGC)->ops = &miBSGCOps; \
+ : (pGC)->funcs = oldFuncs; \
+ : }
+ :
+ :static void miCreateBSPixmap(WindowPtr pWin, BoxPtr pExtents);
+ :static void miDestroyBSPixmap(WindowPtr pWin);
+ :static void miTileVirtualBS(WindowPtr pWin);
+ :static void miBSAllocate(WindowPtr pWin), miBSFree(WindowPtr pWin);
+ :static Bool miBSCreateGCPrivate(GCPtr pGC);
+ :static void miBSClearBackingRegion(WindowPtr pWin, RegionPtr pRgn);
+ :
+ :#define MoreCopy0 ;
+ :#define MoreCopy2 *dstCopy++ = *srcCopy++; *dstCopy++ = *srcCopy++;
+ :#define MoreCopy4 MoreCopy2 MoreCopy2
+ :
+ :#define copyData(src,dst,n,morecopy) \
+ :{ \
+ : short *srcCopy = (short *)(src); \
+ : short *dstCopy = (short *)(dst); \
+ : int i; \
+ : int bsx = pBackingStore->x; \
+ : int bsy = pBackingStore->y; \
+ : for (i = n; --i >= 0; ) \
+ : { \
+ : *dstCopy++ = *srcCopy++ - bsx; \
+ : *dstCopy++ = *srcCopy++ - bsy; \
+ : morecopy \
+ : } \
+ :}
+ :
+ :#define copyPoints(src,dst,n,mode) \
+ :if (mode == CoordModeOrigin) \
+ :{ \
+ : copyData(src,dst,n,MoreCopy0); \
+ :} \
+ :else \
+ :{ \
+ : memmove((char *)(dst), (char *)(src), (n) << 2); \
+ : *((short *)(dst)) -= pBackingStore->x; \
+ : *((short *)(dst) + 1) -= pBackingStore->y; \
+ :}
+ :
+ :/*
+ : * wrappers for screen funcs
+ : */
+ :
+ :static int miBSScreenIndex;
+ :static unsigned long miBSGeneration = 0;
+ :
+ :static Bool miBSCloseScreen(int i, ScreenPtr pScreen);
+ :static void miBSGetImage(DrawablePtr pDrawable, int sx, int sy,
+ : int w, int h, unsigned int format,
+ : unsigned long planemask, char *pdstLine);
+ :static void miBSGetSpans(DrawablePtr pDrawable, int wMax,
+ : DDXPointPtr ppt, int *pwidth, int nspans,
+ : char *pdstStart);
+ :static Bool miBSChangeWindowAttributes(WindowPtr pWin,
+ : unsigned long mask);
+ :static Bool miBSCreateGC(GCPtr pGC);
+ :static Bool miBSDestroyWindow(WindowPtr pWin);
+ :
+ :/*
+ : * backing store screen functions
+ : */
+ :
+ :static void miBSSaveDoomedAreas(WindowPtr pWin, RegionPtr pObscured,
+ : int dx, int dy);
+ :static RegionPtr miBSRestoreAreas(WindowPtr pWin, RegionPtr prgnExposed);
+ :static void miBSExposeCopy(WindowPtr pSrc, DrawablePtr pDst,
+ : GCPtr pGC, RegionPtr prgnExposed,
+ : int srcx, int srcy, int dstx, int dsty,
+ : unsigned long plane);
+ :static RegionPtr miBSTranslateBackingStore(WindowPtr pWin, int windx,
+ : int windy, RegionPtr oldClip,
+ : int oldx, int oldy);
+ :static RegionPtr miBSClearBackingStore(WindowPtr pWin, int x, int y,
+ : int w, int h, Bool generateExposures);
+ :static void miBSDrawGuarantee(WindowPtr pWin, GCPtr pGC,
+ : int guarantee);
+ :
+ :/*
+ : * wrapper vectors for GC funcs and ops
+ : */
+ :
+ :static int miBSGCIndex;
+ :
+ :static void miBSValidateGC(GCPtr pGC, unsigned long stateChanges,
+ : DrawablePtr pDrawable);
+ :static void miBSCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst);
+ :static void miBSDestroyGC(GCPtr pGC);
+ :static void miBSChangeGC(GCPtr pGC, unsigned long mask);
+ :static void miBSChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects);
+ :static void miBSDestroyClip(GCPtr pGC);
+ :static void miBSCopyClip(GCPtr pgcDst, GCPtr pgcSrc);
+ :
+ :static GCFuncs miBSGCFuncs = {
+ : miBSValidateGC,
+ : miBSChangeGC,
+ : miBSCopyGC,
+ : miBSDestroyGC,
+ : miBSChangeClip,
+ : miBSDestroyClip,
+ : miBSCopyClip,
+ :};
+ :
+ :static void miBSFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit,
+ : DDXPointPtr pptInit, int *pwidthInit,
+ : int fSorted);
+ :static void miBSSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
+ : DDXPointPtr ppt, int *pwidth, int nspans,
+ : int fSorted);
+ :static void miBSPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
+ : int x, int y, int w, int h, int leftPad,
+ : int format, char *pBits);
+ :static RegionPtr miBSCopyArea(DrawablePtr pSrc, DrawablePtr pDst,
+ : GCPtr pGC, int srcx, int srcy, int w, int h,
+ : int dstx, int dsty);
+ :static RegionPtr miBSCopyPlane(DrawablePtr pSrc, DrawablePtr pDst,
+ : GCPtr pGC, int srcx, int srcy, int w, int h,
+ : int dstx, int dsty, unsigned long plane);
+ :static void miBSPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode,
+ : int npt, xPoint *pptInit);
+ :static void miBSPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode,
+ : int npt, DDXPointPtr pptInit);
+ :static void miBSPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg,
+ : xSegment *pSegs);
+ :static void miBSPolyRectangle(DrawablePtr pDrawable, GCPtr pGC,
+ : int nrects, xRectangle *pRects);
+ :static void miBSPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
+ : xArc *parcs);
+ :static void miBSFillPolygon(DrawablePtr pDrawable, GCPtr pGC,
+ : int shape, int mode, int count,
+ : DDXPointPtr pPts);
+ :static void miBSPolyFillRect(DrawablePtr pDrawable, GCPtr pGC,
+ : int nrectFill, xRectangle *prectInit);
+ :static void miBSPolyFillArc(DrawablePtr pDrawable, GCPtr pGC,
+ : int narcs, xArc *parcs);
+ :static int miBSPolyText8(DrawablePtr pDrawable, GCPtr pGC,
+ : int x, int y, int count, char *chars);
+ :static int miBSPolyText16(DrawablePtr pDrawable, GCPtr pGC,
+ : int x, int y, int count,
+ : unsigned short *chars);
+ :static void miBSImageText8(DrawablePtr pDrawable, GCPtr pGC,
+ : int x, int y, int count, char *chars);
+ :static void miBSImageText16(DrawablePtr pDrawable, GCPtr pGC,
+ : int x, int y, int count,
+ : unsigned short *chars);
+ :static void miBSImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
+ : int x, int y, unsigned int nglyph,
+ : CharInfoPtr *ppci, pointer pglyphBase);
+ :static void miBSPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
+ : int x, int y, unsigned int nglyph,
+ : CharInfoPtr *ppci, pointer pglyphBase);
+ :static void miBSPushPixels(GCPtr pGC, PixmapPtr pBitMap,
+ : DrawablePtr pDst, int w, int h,
+ : int x, int y);
+ :
+ :static GCOps miBSGCOps = {
+ : miBSFillSpans, miBSSetSpans, miBSPutImage,
+ : miBSCopyArea, miBSCopyPlane, miBSPolyPoint,
+ : miBSPolylines, miBSPolySegment, miBSPolyRectangle,
+ : miBSPolyArc, miBSFillPolygon, miBSPolyFillRect,
+ : miBSPolyFillArc, miBSPolyText8, miBSPolyText16,
+ : miBSImageText8, miBSImageText16, miBSImageGlyphBlt,
+ : miBSPolyGlyphBlt, miBSPushPixels
+ :};
+ :
+ :#define FUNC_PROLOGUE(pGC, pPriv) \
+ : ((pGC)->funcs = pPriv->wrapFuncs),\
+ : ((pGC)->ops = pPriv->wrapOps)
+ :
+ :#define FUNC_EPILOGUE(pGC, pPriv) \
+ : ((pGC)->funcs = &miBSGCFuncs),\
+ : ((pGC)->ops = &miBSGCOps)
+ :
+ :/*
+ : * every GC in the server is initially wrapped with these
+ : * "cheap" functions. This allocates no memory and is used
+ : * to discover GCs used with windows which have backing
+ : * store enabled
+ : */
+ :
+ :static void miBSCheapValidateGC(GCPtr pGC, unsigned long stateChanges,
+ : DrawablePtr pDrawable);
+ :static void miBSCheapCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst);
+ :static void miBSCheapDestroyGC(GCPtr pGC);
+ :static void miBSCheapChangeGC(GCPtr pGC, unsigned long mask);
+ :static void miBSCheapChangeClip(GCPtr pGC, int type, pointer pvalue,
+ : int nrects);
+ :static void miBSCheapDestroyClip(GCPtr pGC);
+ :static void miBSCheapCopyClip(GCPtr pgcDst, GCPtr pgcSrc);
+ :
+ :static GCFuncs miBSCheapGCFuncs = {
+ : miBSCheapValidateGC,
+ : miBSCheapChangeGC,
+ : miBSCheapCopyGC,
+ : miBSCheapDestroyGC,
+ : miBSCheapChangeClip,
+ : miBSCheapDestroyClip,
+ : miBSCheapCopyClip,
+ :};
+ :
+ :#define CHEAP_FUNC_PROLOGUE(pGC) \
+ : ((pGC)->funcs = (GCFuncs *) (pGC)->devPrivates[miBSGCIndex].ptr)
+ :
+ :#define CHEAP_FUNC_EPILOGUE(pGC) \
+ : ((pGC)->funcs = &miBSCheapGCFuncs)
+ :
+ :/*
+ : * called from device screen initialization proc. Gets a GCPrivateIndex
+ : * and wraps appropriate per-screen functions. pScreen->BackingStoreFuncs
+ : * must be previously initialized.
+ : */
+ :
+ :_X_EXPORT void
+ :miInitializeBackingStore (pScreen)
+ : ScreenPtr pScreen;
+ :{
+ : miBSScreenPtr pScreenPriv;
+ :
+ : if (miBSGeneration != serverGeneration)
+ : {
+ : miBSScreenIndex = AllocateScreenPrivateIndex ();
+ : if (miBSScreenIndex < 0)
+ : return;
+ : miBSGCIndex = AllocateGCPrivateIndex ();
+ : miBSGeneration = serverGeneration;
+ : }
+ : if (!AllocateGCPrivate(pScreen, miBSGCIndex, 0))
+ : return;
+ : pScreenPriv = (miBSScreenPtr) xalloc (sizeof (miBSScreenRec));
+ : if (!pScreenPriv)
+ : return;
+ :
+ : pScreenPriv->CloseScreen = pScreen->CloseScreen;
+ : pScreenPriv->GetImage = pScreen->GetImage;
+ : pScreenPriv->GetSpans = pScreen->GetSpans;
+ : pScreenPriv->ChangeWindowAttributes = pScreen->ChangeWindowAttributes;
+ : pScreenPriv->CreateGC = pScreen->CreateGC;
+ : pScreenPriv->DestroyWindow = pScreen->DestroyWindow;
+ :
+ : pScreen->CloseScreen = miBSCloseScreen;
+ : pScreen->GetImage = miBSGetImage;
+ : pScreen->GetSpans = miBSGetSpans;
+ : pScreen->ChangeWindowAttributes = miBSChangeWindowAttributes;
+ : pScreen->CreateGC = miBSCreateGC;
+ : pScreen->DestroyWindow = miBSDestroyWindow;
+ :
+ : pScreen->SaveDoomedAreas = miBSSaveDoomedAreas;
+ : pScreen->RestoreAreas = miBSRestoreAreas;
+ : pScreen->ExposeCopy = miBSExposeCopy;
+ : pScreen->TranslateBackingStore = miBSTranslateBackingStore;
+ : pScreen->ClearBackingStore = miBSClearBackingStore;
+ : pScreen->DrawGuarantee = miBSDrawGuarantee;
+ :
+ : pScreen->devPrivates[miBSScreenIndex].ptr = (pointer) pScreenPriv;
+ :}
+ :
+ :/*
+ : * Screen function wrappers
+ : */
+ :
+ :#define SCREEN_PROLOGUE(pScreen, field)\
+ : ((pScreen)->field = \
+ : ((miBSScreenPtr) \
+ : (pScreen)->devPrivates[miBSScreenIndex].ptr)->field)
+ :
+ :#define SCREEN_EPILOGUE(pScreen, field, wrapper)\
+ : ((pScreen)->field = wrapper)
+ :
+ :/*
+ : * CloseScreen wrapper -- unwrap everything, free the private data
+ : * and call the wrapped function
+ : */
+ :
+ :static Bool
+ :miBSCloseScreen (i, pScreen)
+ : int i;
+ : ScreenPtr pScreen;
+ :{
+ : miBSScreenPtr pScreenPriv;
+ :
+ : pScreenPriv = (miBSScreenPtr) pScreen->devPrivates[miBSScreenIndex].ptr;
+ :
+ : pScreen->CloseScreen = pScreenPriv->CloseScreen;
+ : pScreen->GetImage = pScreenPriv->GetImage;
+ : pScreen->GetSpans = pScreenPriv->GetSpans;
+ : pScreen->ChangeWindowAttributes = pScreenPriv->ChangeWindowAttributes;
+ : pScreen->CreateGC = pScreenPriv->CreateGC;
+ :
+ : xfree ((pointer) pScreenPriv);
+ :
+ : return (*pScreen->CloseScreen) (i, pScreen);
+ :}
+ :
+ :static void miBSFillVirtualBits(DrawablePtr pDrawable, GCPtr pGC,
+ : RegionPtr pRgn, int x, int y, int state,
+ : PixUnion pixunion, unsigned long planemask);
+ :
+ :static void
+ :miBSGetImage (pDrawable, sx, sy, w, h, format, planemask, pdstLine)
+ : DrawablePtr pDrawable;
+ : int sx, sy, w, h;
+ : unsigned int format;
+ : unsigned long planemask;
+ : char *pdstLine;
+ :{
+ : ScreenPtr pScreen = pDrawable->pScreen;
+ : BoxRec bounds;
+ : unsigned char depth;
+ :
+ : SCREEN_PROLOGUE (pScreen, GetImage);
+ :
+ : if (pDrawable->type != DRAWABLE_PIXMAP &&
+ : ((WindowPtr) pDrawable)->visibility != VisibilityUnobscured)
+ : {
+ : PixmapPtr pPixmap;
+ : miBSWindowPtr pWindowPriv;
+ : GCPtr pGC = NULL;
+ : WindowPtr pWin, pSrcWin;
+ : int xoff, yoff;
+ : RegionRec Remaining;
+ : RegionRec Border;
+ : RegionRec Inside;
+ : BoxPtr pBox;
+ : int n;
+ :
+ : pWin = (WindowPtr) pDrawable;
+ : pPixmap = 0;
+ : depth = pDrawable->depth;
+ : bounds.x1 = sx + pDrawable->x;
+ : bounds.y1 = sy + pDrawable->y;
+ : bounds.x2 = bounds.x1 + w;
+ : bounds.y2 = bounds.y1 + h;
+ : REGION_INIT(pScreen, &Remaining, &bounds, 0);
+ : for (;;)
+ : {
+ : bounds.x1 = sx + pDrawable->x - pWin->drawable.x;
+ : bounds.y1 = sy + pDrawable->y - pWin->drawable.y;
+ : bounds.x2 = bounds.x1 + w;
+ : bounds.y2 = bounds.y1 + h;
+ : if (pWin->viewable && pWin->backStorage &&
+ : pWin->drawable.depth == depth &&
+ : (RECT_IN_REGION(pScreen, &(pWindowPriv =
+ : (miBSWindowPtr) pWin->backStorage)->SavedRegion,
+ : &bounds) != rgnOUT ||
+ : RECT_IN_REGION(pScreen, &Remaining,
+ : REGION_EXTENTS(pScreen, &pWin->borderSize)) != rgnOUT))
+ : {
+ : if (!pPixmap)
+ : {
+ : XID subWindowMode = IncludeInferiors;
+ : int x, y;
+ :
+ : pPixmap = (*pScreen->CreatePixmap) (pScreen, w, h, depth);
+ : if (!pPixmap)
+ : goto punt;
+ : pGC = GetScratchGC (depth, pScreen);
+ : if (!pGC)
+ : {
+ : (*pScreen->DestroyPixmap) (pPixmap);
+ : goto punt;
+ : }
+ : ChangeGC (pGC, GCSubwindowMode, &subWindowMode);
+ : ValidateGC ((DrawablePtr)pPixmap, pGC);
+ : REGION_NULL(pScreen, &Border);
+ : REGION_NULL(pScreen, &Inside);
+ : pSrcWin = (WindowPtr) pDrawable;
+ : x = sx;
+ : y = sy;
+ : if (pSrcWin->parent)
+ : {
+ : x += pSrcWin->origin.x;
+ : y += pSrcWin->origin.y;
+ : pSrcWin = pSrcWin->parent;
+ : }
+ : (*pGC->ops->CopyArea) ((DrawablePtr)pSrcWin,
+ : (DrawablePtr)pPixmap, pGC,
+ : x, y, w, h,
+ : 0, 0);
+ : REGION_SUBTRACT(pScreen, &Remaining, &Remaining,
+ : &((WindowPtr) pDrawable)->borderClip);
+ : }
+ :
+ : REGION_INTERSECT(pScreen, &Inside, &Remaining, &pWin->winSize);
+ : REGION_TRANSLATE(pScreen, &Inside,
+ : -pWin->drawable.x,
+ : -pWin->drawable.y);
+ : REGION_INTERSECT(pScreen, &Inside, &Inside,
+ : &pWindowPriv->SavedRegion);
+ :
+ : /* offset of sub-window in GetImage pixmap */
+ : xoff = pWin->drawable.x - pDrawable->x - sx;
+ : yoff = pWin->drawable.y - pDrawable->y - sy;
+ :
+ : if (REGION_NUM_RECTS(&Inside) > 0)
+ : {
+ : switch (pWindowPriv->status)
+ : {
+ : case StatusContents:
+ : pBox = REGION_RECTS(&Inside);
+ : for (n = REGION_NUM_RECTS(&Inside); --n >= 0;)
+ : {
+ : (*pGC->ops->CopyArea) (
+ : (DrawablePtr)pWindowPriv->pBackingPixmap,
+ : (DrawablePtr)pPixmap, pGC,
+ : pBox->x1 - pWindowPriv->x,
+ : pBox->y1 - pWindowPriv->y,
+ : pBox->x2 - pBox->x1,
+ : pBox->y2 - pBox->y1,
+ : pBox->x1 + xoff,
+ : pBox->y1 + yoff);
+ : ++pBox;
+ : }
+ : break;
+ : case StatusVirtual:
+ : case StatusVDirty:
+ : if (pWindowPriv->backgroundState == BackgroundPixmap ||
+ : pWindowPriv->backgroundState == BackgroundPixel)
+ : miBSFillVirtualBits ((DrawablePtr) pPixmap, pGC, &Inside,
+ : xoff, yoff,
+ : (int) pWindowPriv->backgroundState,
+ : pWindowPriv->background, ~0L);
+ : break;
+ : }
+ : }
+ : REGION_SUBTRACT(pScreen, &Border, &pWin->borderSize,
+ : &pWin->winSize);
+ : REGION_INTERSECT(pScreen, &Border, &Border, &Remaining);
+ : if (REGION_NUM_RECTS(&Border) > 0)
+ : {
+ : REGION_TRANSLATE(pScreen, &Border, -pWin->drawable.x,
+ : -pWin->drawable.y);
+ : miBSFillVirtualBits ((DrawablePtr) pPixmap, pGC, &Border,
+ : xoff, yoff,
+ : pWin->borderIsPixel ? (int)BackgroundPixel : (int)BackgroundPixmap,
+ : pWin->border, ~0L);
+ : }
+ : }
+ :
+ : if (pWin->viewable && pWin->firstChild)
+ : pWin = pWin->firstChild;
+ : else
+ : {
+ : while (!pWin->nextSib && pWin != (WindowPtr) pDrawable)
+ : pWin = pWin->parent;
+ : if (pWin == (WindowPtr) pDrawable)
+ : break;
+ : pWin = pWin->nextSib;
+ : }
+ : }
+ :
+ : REGION_UNINIT(pScreen, &Remaining);
+ :
+ : if (pPixmap)
+ : {
+ : REGION_UNINIT(pScreen, &Border);
+ : REGION_UNINIT(pScreen, &Inside);
+ : (*pScreen->GetImage) ((DrawablePtr) pPixmap,
+ : 0, 0, w, h, format, planemask, pdstLine);
+ : (*pScreen->DestroyPixmap) (pPixmap);
+ : FreeScratchGC (pGC);
+ : }
+ : else
+ : {
+ : goto punt;
+ : }
+ : }
+ : else
+ : {
+ :punt: ;
+ : (*pScreen->GetImage) (pDrawable, sx, sy, w, h,
+ : format, planemask, pdstLine);
+ : }
+ :
+ : SCREEN_EPILOGUE (pScreen, GetImage, miBSGetImage);
+ :}
+ :
+ :static void
+ :miBSGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart)
+ : DrawablePtr pDrawable;
+ : int wMax;
+ : DDXPointPtr ppt;
+ : int *pwidth;
+ : int nspans;
+ : char *pdstStart;
+ :{
+ : ScreenPtr pScreen = pDrawable->pScreen;
+ : BoxRec bounds;
+ : int i;
+ : WindowPtr pWin;
+ : int dx, dy;
+ :
+ : SCREEN_PROLOGUE (pScreen, GetSpans);
+ :
+ : if (pDrawable->type != DRAWABLE_PIXMAP && ((WindowPtr) pDrawable)->backStorage)
+ : {
+ : PixmapPtr pPixmap;
+ : miBSWindowPtr pWindowPriv;
+ : GCPtr pGC;
+ :
+ : pWin = (WindowPtr) pDrawable;
+ : pWindowPriv = (miBSWindowPtr) pWin->backStorage;
+ : pPixmap = pWindowPriv->pBackingPixmap;
+ :
+ : bounds.x1 = ppt->x;
+ : bounds.y1 = ppt->y;
+ : bounds.x2 = bounds.x1 + *pwidth;
+ : bounds.y2 = ppt->y;
+ : for (i = 0; i < nspans; i++)
+ : {
+ : if (ppt[i].x < bounds.x1)
+ : bounds.x1 = ppt[i].x;
+ : if (ppt[i].x + pwidth[i] > bounds.x2)
+ : bounds.x2 = ppt[i].x + pwidth[i];
+ : if (ppt[i].y < bounds.y1)
+ : bounds.y1 = ppt[i].y;
+ : else if (ppt[i].y > bounds.y2)
+ : bounds.y2 = ppt[i].y;
+ : }
+ :
+ : switch (RECT_IN_REGION(pScreen, &pWindowPriv->SavedRegion, &bounds))
+ : {
+ : case rgnPART:
+ : if (!pPixmap)
+ : {
+ : miCreateBSPixmap (pWin, NullBox);
+ : if (!(pPixmap = pWindowPriv->pBackingPixmap))
+ : break;
+ : }
+ : pWindowPriv->status = StatusNoPixmap;
+ : pGC = GetScratchGC(pPixmap->drawable.depth,
+ : pPixmap->drawable.pScreen);
+ : if (pGC)
+ : {
+ : ValidateGC ((DrawablePtr) pPixmap, pGC);
+ : (*pGC->ops->CopyArea)
+ : (pDrawable, (DrawablePtr) pPixmap, pGC,
+ : bounds.x1, bounds.y1,
+ : bounds.x2 - bounds.x1, bounds.y2 - bounds.y1,
+ : bounds.x1 + pPixmap->drawable.x - pWin->drawable.x -
+ : pWindowPriv->x,
+ : bounds.y1 + pPixmap->drawable.y - pWin->drawable.y -
+ : pWindowPriv->y);
+ : FreeScratchGC(pGC);
+ : }
+ : pWindowPriv->status = StatusContents;
+ : /* fall through */
+ : case rgnIN:
+ : if (!pPixmap)
+ : {
+ : miCreateBSPixmap (pWin, NullBox);
+ : if (!(pPixmap = pWindowPriv->pBackingPixmap))
+ : break;
+ : }
+ : dx = pPixmap->drawable.x - pWin->drawable.x - pWindowPriv->x;
+ : dy = pPixmap->drawable.y - pWin->drawable.y - pWindowPriv->y;
+ : for (i = 0; i < nspans; i++)
+ : {
+ : ppt[i].x += dx;
+ : ppt[i].y += dy;
+ : }
+ : (*pScreen->GetSpans) ((DrawablePtr) pPixmap, wMax, ppt, pwidth,
+ : nspans, pdstStart);
+ : break;
+ : case rgnOUT:
+ : (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans,
+ : pdstStart);
+ : break;
+ : }
+ : }
+ : else
+ : {
+ : (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
+ : }
+ :
+ : SCREEN_EPILOGUE (pScreen, GetSpans, miBSGetSpans);
+ :}
+ :
+ :static Bool
+ :miBSChangeWindowAttributes (pWin, mask)
+ : WindowPtr pWin;
+ : unsigned long mask;
+ :{
+ : ScreenPtr pScreen;
+ : Bool ret;
+ :
+ : pScreen = pWin->drawable.pScreen;
+ :
+ : SCREEN_PROLOGUE (pScreen, ChangeWindowAttributes);
+ :
+ : ret = (*pScreen->ChangeWindowAttributes) (pWin, mask);
+ :
+ : if (ret && (mask & CWBackingStore))
+ : {
+ : if (pWin->backingStore != NotUseful || pWin->DIXsaveUnder)
+ : miBSAllocate (pWin);
+ : else
+ : miBSFree (pWin);
+ : }
+ :
+ : SCREEN_EPILOGUE (pScreen, ChangeWindowAttributes, miBSChangeWindowAttributes);
+ :
+ : return ret;
+ :}
+ :
+ :/*
+ : * GC Create wrapper. Set up the cheap GC func wrappers to track
+ : * GC validation on BackingStore windows
+ : */
+ :
+ :static Bool
+ :miBSCreateGC (pGC)
+ : GCPtr pGC;
+ :{
+ : ScreenPtr pScreen = pGC->pScreen;
+ : Bool ret;
+ :
+ : SCREEN_PROLOGUE (pScreen, CreateGC);
+ :
+ : if ( (ret = (*pScreen->CreateGC) (pGC)) )
+ : {
+ : pGC->devPrivates[miBSGCIndex].ptr = (pointer) pGC->funcs;
+ : pGC->funcs = &miBSCheapGCFuncs;
+ : }
+ :
+ : SCREEN_EPILOGUE (pScreen, CreateGC, miBSCreateGC);
+ :
+ : return ret;
+ :}
+ :
+ :static Bool
+ :miBSDestroyWindow (pWin)
+ : WindowPtr pWin;
+ :{
+ : ScreenPtr pScreen = pWin->drawable.pScreen;
+ : Bool ret;
+ :
+ : SCREEN_PROLOGUE (pScreen, DestroyWindow);
+ :
+ : ret = (*pScreen->DestroyWindow) (pWin);
+ :
+ : miBSFree (pWin);
+ :
+ : SCREEN_EPILOGUE (pScreen, DestroyWindow, miBSDestroyWindow);
+ :
+ : return ret;
+ :}
+ :
+ :/*
+ : * cheap GC func wrappers. Simply track validation on windows
+ : * with backing store to enable the real func/op wrappers
+ : */
+ :
+ :static void
+ :miBSCheapValidateGC (pGC, stateChanges, pDrawable)
+ : GCPtr pGC;
+ : unsigned long stateChanges;
+ : DrawablePtr pDrawable;
+ 1 0.0011 :{ /* miBSCheapValidateGC total: 5 0.0054 */
+ : CHEAP_FUNC_PROLOGUE (pGC);
+ :
+ 1 0.0011 : if (pDrawable->type != DRAWABLE_PIXMAP &&
+ : ((WindowPtr) pDrawable)->backStorage != NULL &&
+ : miBSCreateGCPrivate (pGC))
+ : {
+ : (*pGC->funcs->ValidateGC) (pGC, stateChanges, pDrawable);
+ : }
+ : else
+ : {
+ : (*pGC->funcs->ValidateGC) (pGC, stateChanges, pDrawable);
+ :
+ : /* rewrap funcs as Validate may have changed them */
+ : pGC->devPrivates[miBSGCIndex].ptr = (pointer) pGC->funcs;
+ :
+ 1 0.0011 : CHEAP_FUNC_EPILOGUE (pGC);
+ : }
+ 2 0.0022 :}
+ :
+ :static void
+ :miBSCheapChangeGC (pGC, mask)
+ : GCPtr pGC;
+ : unsigned long mask;
+ 1 0.0011 :{ /* miBSCheapChangeGC total: 1 0.0011 */
+ : CHEAP_FUNC_PROLOGUE (pGC);
+ :
+ : (*pGC->funcs->ChangeGC) (pGC, mask);
+ :
+ : CHEAP_FUNC_EPILOGUE (pGC);
+ :}
+ :
+ :static void
+ :miBSCheapCopyGC (pGCSrc, mask, pGCDst)
+ : GCPtr pGCSrc, pGCDst;
+ : unsigned long mask;
+ :{
+ : CHEAP_FUNC_PROLOGUE (pGCDst);
+ :
+ : (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
+ :
+ : CHEAP_FUNC_EPILOGUE (pGCDst);
+ :}
+ :
+ :static void
+ :miBSCheapDestroyGC (pGC)
+ : GCPtr pGC;
+ :{
+ : CHEAP_FUNC_PROLOGUE (pGC);
+ :
+ : (*pGC->funcs->DestroyGC) (pGC);
+ :
+ : /* leave it unwrapped */
+ :}
+ :
+ :static void
+ :miBSCheapChangeClip (pGC, type, pvalue, nrects)
+ : GCPtr pGC;
+ : int type;
+ : pointer pvalue;
+ : int nrects;
+ 1 0.0011 :{ /* miBSCheapChangeClip total: 3 0.0033 */
+ : CHEAP_FUNC_PROLOGUE (pGC);
+ :
+ : (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
+ :
+ : CHEAP_FUNC_EPILOGUE (pGC);
+ 2 0.0022 :}
+ :
+ :static void
+ :miBSCheapCopyClip(pgcDst, pgcSrc)
+ : GCPtr pgcDst, pgcSrc;
+ :{
+ : CHEAP_FUNC_PROLOGUE (pgcDst);
+ :
+ : (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
+ :
+ : CHEAP_FUNC_EPILOGUE (pgcDst);
+ :}
+ :
+ :static void
+ :miBSCheapDestroyClip(pGC)
+ : GCPtr pGC;
+ :{
+ : CHEAP_FUNC_PROLOGUE (pGC);
+ :
+ : (* pGC->funcs->DestroyClip)(pGC);
+ :
+ : CHEAP_FUNC_EPILOGUE (pGC);
+ :}
+ :
+ :/*
+ : * create the full func/op wrappers for a GC
+ : */
+ :
+ :static Bool
+ :miBSCreateGCPrivate (pGC)
+ : GCPtr pGC;
+ :{
+ : miBSGCRec *pPriv;
+ :
+ : pPriv = (miBSGCRec *) xalloc (sizeof (miBSGCRec));
+ : if (!pPriv)
+ : return FALSE;
+ : pPriv->pBackingGC = NULL;
+ : pPriv->guarantee = GuaranteeNothing;
+ : pPriv->serialNumber = 0;
+ : pPriv->stateChanges = (1 << (GCLastBit + 1)) - 1;
+ : pPriv->wrapOps = pGC->ops;
+ : pPriv->wrapFuncs = pGC->funcs;
+ : pGC->funcs = &miBSGCFuncs;
+ : pGC->ops = &miBSGCOps;
+ : pGC->devPrivates[miBSGCIndex].ptr = (pointer) pPriv;
+ : return TRUE;
+ :}
+ :
+ :static void
+ :miBSDestroyGCPrivate (GCPtr pGC)
+ :{
+ : miBSGCRec *pPriv;
+ :
+ : pPriv = (miBSGCRec *) pGC->devPrivates[miBSGCIndex].ptr;
+ : if (pPriv)
+ : {
+ : pGC->devPrivates[miBSGCIndex].ptr = (pointer) pPriv->wrapFuncs;
+ : pGC->funcs = &miBSCheapGCFuncs;
+ : pGC->ops = pPriv->wrapOps;
+ : if (pPriv->pBackingGC)
+ : FreeGC (pPriv->pBackingGC, (GContext) 0);
+ : xfree ((pointer) pPriv);
+ : }
+ :}
+ :
+ :/*
+ : * GC ops -- wrap each GC operation with our own function
+ : */
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSFillSpans --
+ : * Perform a FillSpans, routing output to backing-store as needed.
+ : *
+ : * Results:
+ : * None.
+ : *
+ : * Side Effects:
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :miBSFillSpans(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted)
+ : DrawablePtr pDrawable;
+ : GCPtr pGC;
+ : int nInit; /* number of spans to fill */
+ : DDXPointPtr pptInit; /* pointer to list of start points */
+ : int *pwidthInit; /* pointer to list of n widths */
+ : int fSorted;
+ :{
+ : DDXPointPtr pptCopy, pptReset;
+ : int *pwidthCopy;
+ : SETUP_BACKING (pDrawable, pGC);
+ :
+ : PROLOGUE(pGC);
+ :
+ : pptCopy = (DDXPointPtr)ALLOCATE_LOCAL(nInit*sizeof(DDXPointRec));
+ : pwidthCopy=(int *)ALLOCATE_LOCAL(nInit*sizeof(int));
+ : if (pptCopy && pwidthCopy)
+ : {
+ : copyData(pptInit, pptCopy, nInit, MoreCopy0);
+ : memmove((char *)pwidthCopy,(char *)pwidthInit,nInit*sizeof(int));
+ :
+ : (* pGC->ops->FillSpans)(pDrawable, pGC, nInit, pptInit,
+ : pwidthInit, fSorted);
+ : if (pGC->miTranslate)
+ : {
+ : int dx, dy;
+ : int nReset;
+ :
+ : pptReset = pptCopy;
+ : dx = pDrawable->x - pBackingDrawable->x;
+ : dy = pDrawable->y - pBackingDrawable->y;
+ : nReset = nInit;
+ : while (nReset--)
+ : {
+ : pptReset->x -= dx;
+ : pptReset->y -= dy;
+ : ++pptReset;
+ : }
+ : }
+ : (* pBackingGC->ops->FillSpans)(pBackingDrawable,
+ : pBackingGC, nInit, pptCopy, pwidthCopy,
+ : fSorted);
+ : }
+ : if (pwidthCopy) DEALLOCATE_LOCAL(pwidthCopy);
+ : if (pptCopy) DEALLOCATE_LOCAL(pptCopy);
+ :
+ : EPILOGUE (pGC);
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSSetSpans --
+ : * Perform a SetSpans, routing output to backing-store as needed.
+ : *
+ : * Results:
+ : * None.
+ : *
+ : * Side Effects:
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :miBSSetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted)
+ : DrawablePtr pDrawable;
+ : GCPtr pGC;
+ : char *psrc;
+ : DDXPointPtr ppt;
+ : int *pwidth;
+ : int nspans;
+ : int fSorted;
+ :{
+ : DDXPointPtr pptCopy, pptReset;
+ : int *pwidthCopy;
+ : SETUP_BACKING (pDrawable, pGC);
+ :
+ : PROLOGUE(pGC);
+ :
+ : pptCopy = (DDXPointPtr)ALLOCATE_LOCAL(nspans*sizeof(DDXPointRec));
+ : pwidthCopy=(int *)ALLOCATE_LOCAL(nspans*sizeof(int));
+ : if (pptCopy && pwidthCopy)
+ : {
+ : copyData(ppt, pptCopy, nspans, MoreCopy0);
+ : memmove((char *)pwidthCopy,(char *)pwidth,nspans*sizeof(int));
+ :
+ : (* pGC->ops->SetSpans)(pDrawable, pGC, psrc, ppt, pwidth,
+ : nspans, fSorted);
+ : if (pGC->miTranslate)
+ : {
+ : int dx, dy;
+ : int nReset;
+ :
+ : pptReset = pptCopy;
+ : dx = pDrawable->x - pBackingDrawable->x;
+ : dy = pDrawable->y - pBackingDrawable->y;
+ : nReset = nspans;
+ : while (nReset--)
+ : {
+ : pptReset->x -= dx;
+ : pptReset->y -= dy;
+ : ++pptReset;
+ : }
+ : }
+ : (* pBackingGC->ops->SetSpans)(pBackingDrawable, pBackingGC,
+ : psrc, pptCopy, pwidthCopy, nspans, fSorted);
+ : }
+ : if (pwidthCopy) DEALLOCATE_LOCAL(pwidthCopy);
+ : if (pptCopy) DEALLOCATE_LOCAL(pptCopy);
+ :
+ : EPILOGUE (pGC);
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSPutImage --
+ : * Perform a PutImage, routing output to backing-store as needed.
+ : *
+ : * Results:
+ : * None.
+ : *
+ : * Side Effects:
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :miBSPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits)
+ : DrawablePtr pDrawable;
+ : GCPtr pGC;
+ : int depth;
+ : int x;
+ : int y;
+ : int w;
+ : int h;
+ : int leftPad;
+ : int format;
+ : char *pBits;
+ :{
+ : SETUP_BACKING (pDrawable, pGC);
+ :
+ : PROLOGUE(pGC);
+ :
+ : (*pGC->ops->PutImage)(pDrawable, pGC,
+ : depth, x, y, w, h, leftPad, format, pBits);
+ : (*pBackingGC->ops->PutImage)(pBackingDrawable, pBackingGC,
+ : depth, x - pBackingStore->x, y - pBackingStore->y,
+ : w, h, leftPad, format, pBits);
+ :
+ : EPILOGUE (pGC);
+ :}
+ :
+ :typedef RegionPtr (* CopyAreaProcPtr)(DrawablePtr, DrawablePtr, GCPtr,
+ : int, int, int, int, int, int);
+ :typedef RegionPtr (* CopyPlaneProcPtr)(DrawablePtr, DrawablePtr, GCPtr,
+ : int, int, int, int, int, int,
+ : unsigned long bitPlane);
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSDoCopy --
+ : * Perform a CopyArea or CopyPlane within a window that has backing
+ : * store enabled.
+ : *
+ : * Results:
+ : * TRUE if the copy was performed or FALSE if a regular one should
+ : * be done.
+ : *
+ : * Side Effects:
+ : * Things are copied (no s***!)
+ : *
+ : * Notes:
+ : * The idea here is to form two regions that cover the source box.
+ : * One contains the exposed rectangles while the other contains
+ : * the obscured ones. An array of <box, drawable> pairs is then
+ : * formed where the <box> indicates the area to be copied and the
+ : * <drawable> indicates from where it is to be copied (exposed regions
+ : * come from the screen while obscured ones come from the backing
+ : * pixmap). The array 'sequence' is then filled with the indices of
+ : * the pairs in the order in which they should be copied to prevent
+ : * things from getting screwed up. A call is also made through the
+ : * backingGC to take care of any copying into the backing pixmap.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static Bool
+ :miBSDoCopy(
+ : WindowPtr pWin, /* Window being scrolled */
+ : GCPtr pGC, /* GC we're called through */
+ : int srcx, /* X of source rectangle */
+ : int srcy, /* Y of source rectangle */
+ : int w, /* Width of source rectangle */
+ : int h, /* Height of source rectangle */
+ : int dstx, /* X of destination rectangle */
+ : int dsty, /* Y of destination rectangle */
+ : unsigned long plane, /* Plane to copy (0 for CopyArea) */
+ : CopyPlaneProcPtr copyProc, /* Procedure to call to perform the copy */
+ : RegionPtr *ppRgn) /* resultant Graphics Expose region */
+ :{
+ : RegionPtr pRgnExp; /* Exposed region */
+ : RegionPtr pRgnObs; /* Obscured region */
+ : BoxRec box; /* Source box (screen coord) */
+ : struct BoxDraw {
+ : BoxPtr pBox; /* Source box */
+ : enum {
+ : win, pix
+ : } source; /* Place from which to copy */
+ : } *boxes; /* Array of box/drawable pairs covering
+ : * source box. */
+ : int *sequence; /* Sequence of boxes to move */
+ : int i, j, k, l, y;
+ : BoxPtr pBox;
+ : int dx, dy, nrects;
+ : Bool graphicsExposures;
+ : CopyPlaneProcPtr pixCopyProc;
+ : int numRectsExp, numRectsObs;
+ : BoxPtr pBoxExp, pBoxObs;
+ :
+ : SETUP_BACKING (pWin, pGC);
+ : (void)oldFuncs;
+ :
+ : /*
+ : * Create a region of exposed boxes in pRgnExp.
+ : */
+ : box.x1 = srcx + pWin->drawable.x;
+ : box.x2 = box.x1 + w;
+ : box.y1 = srcy + pWin->drawable.y;
+ : box.y2 = box.y1 + h;
+ :
+ : pRgnExp = REGION_CREATE(pGC->pScreen, &box, 1);
+ : REGION_INTERSECT(pGC->pScreen, pRgnExp, pRgnExp, &pWin->clipList);
+ : pRgnObs = REGION_CREATE(pGC->pScreen, NULL, 1);
+ : REGION_INVERSE( pGC->pScreen, pRgnObs, pRgnExp, &box);
+ :
+ : /*
+ : * Translate regions into window coordinates for proper calls
+ : * to the copyProc, then make sure none of the obscured region sticks
+ : * into invalid areas of the backing pixmap.
+ : */
+ : REGION_TRANSLATE(pGC->pScreen, pRgnExp,
+ : -pWin->drawable.x,
+ : -pWin->drawable.y);
+ : REGION_TRANSLATE(pGC->pScreen, pRgnObs,
+ : -pWin->drawable.x,
+ : -pWin->drawable.y);
+ : REGION_INTERSECT(pGC->pScreen, pRgnObs, pRgnObs, &pBackingStore->SavedRegion);
+ :
+ : /*
+ : * If the obscured region is empty, there's no point being fancy.
+ : */
+ : if (!REGION_NOTEMPTY(pGC->pScreen, pRgnObs))
+ : {
+ : REGION_DESTROY(pGC->pScreen, pRgnExp);
+ : REGION_DESTROY(pGC->pScreen, pRgnObs);
+ :
+ : return (FALSE);
+ : }
+ :
+ : numRectsExp = REGION_NUM_RECTS(pRgnExp);
+ : pBoxExp = REGION_RECTS(pRgnExp);
+ : pBoxObs = REGION_RECTS(pRgnObs);
+ : numRectsObs = REGION_NUM_RECTS(pRgnObs);
+ : nrects = numRectsExp + numRectsObs;
+ :
+ : boxes = (struct BoxDraw *)ALLOCATE_LOCAL(nrects * sizeof(struct BoxDraw));
+ : sequence = (int *) ALLOCATE_LOCAL(nrects * sizeof(int));
+ : *ppRgn = NULL;
+ :
+ : if (!boxes || !sequence)
+ : {
+ : if (sequence) DEALLOCATE_LOCAL(sequence);
+ : if (boxes) DEALLOCATE_LOCAL(boxes);
+ : REGION_DESTROY(pGC->pScreen, pRgnExp);
+ : REGION_DESTROY(pGC->pScreen, pRgnObs);
+ :
+ : return(TRUE);
+ : }
+ :
+ : /*
+ : * Order the boxes in the two regions so we know from which drawable
+ : * to copy which box, storing the result in the boxes array
+ : */
+ : for (i = 0, j = 0, k = 0;
+ : (i < numRectsExp) && (j < numRectsObs);
+ : k++)
+ : {
+ : if (pBoxExp[i].y1 < pBoxObs[j].y1)
+ : {
+ : boxes[k].pBox = &pBoxExp[i];
+ : boxes[k].source = win;
+ : i++;
+ : }
+ : else if ((pBoxObs[j].y1 < pBoxExp[i].y1) ||
+ : (pBoxObs[j].x1 < pBoxExp[i].x1))
+ : {
+ : boxes[k].pBox = &pBoxObs[j];
+ : boxes[k].source = pix;
+ : j++;
+ : }
+ : else
+ : {
+ : boxes[k].pBox = &pBoxExp[i];
+ : boxes[k].source = win;
+ : i++;
+ : }
+ : }
+ :
+ : /*
+ : * Catch any leftover boxes from either region (note that only
+ : * one can have leftover boxes...)
+ : */
+ : if (i != numRectsExp)
+ : {
+ : do
+ : {
+ : boxes[k].pBox = &pBoxExp[i];
+ : boxes[k].source = win;
+ : i++;
+ : k++;
+ : } while (i < numRectsExp);
+ :
+ : }
+ : else
+ : {
+ : do
+ : {
+ : boxes[k].pBox = &pBoxObs[j];
+ : boxes[k].source = pix;
+ : j++;
+ : k++;
+ : } while (j < numRectsObs);
+ : }
+ :
+ : if (dsty <= srcy)
+ : {
+ : /*
+ : * Scroll up or vertically stationary, so vertical order is ok.
+ : */
+ : if (dstx <= srcx)
+ : {
+ : /*
+ : * Scroll left or horizontally stationary, so horizontal order
+ : * is ok as well.
+ : */
+ : for (i = 0; i < nrects; i++)
+ : {
+ : sequence[i] = i;
+ : }
+ : }
+ : else
+ : {
+ : /*
+ : * Scroll right. Need to reverse the rectangles within each
+ : * band.
+ : */
+ : for (i = 0, j = 1, k = 0;
+ : i < nrects;
+ : j = i + 1, k = i)
+ : {
+ : y = boxes[i].pBox->y1;
+ : while ((j < nrects) && (boxes[j].pBox->y1 == y))
+ : {
+ : j++;
+ : }
+ : for (j--; j >= k; j--, i++)
+ : {
+ : sequence[i] = j;
+ : }
+ : }
+ : }
+ : }
+ : else
+ : {
+ : /*
+ : * Scroll down. Must reverse vertical banding, at least.
+ : */
+ : if (dstx < srcx)
+ : {
+ : /*
+ : * Scroll left. Horizontal order is ok.
+ : */
+ : for (i = nrects - 1, j = i - 1, k = i, l = 0;
+ : i >= 0;
+ : j = i - 1, k = i)
+ : {
+ : /*
+ : * Find extent of current horizontal band, then reverse
+ : * the order of the whole band.
+ : */
+ : y = boxes[i].pBox->y1;
+ : while ((j >= 0) && (boxes[j].pBox->y1 == y))
+ : {
+ : j--;
+ : }
+ : for (j++; j <= k; j++, i--, l++)
+ : {
+ : sequence[l] = j;
+ : }
+ : }
+ : }
+ : else
+ : {
+ : /*
+ : * Scroll right or horizontal stationary.
+ : * Reverse horizontal order as well (if stationary, horizontal
+ : * order can be swapped without penalty and this is faster
+ : * to compute).
+ : */
+ : for (i = 0, j = nrects - 1; i < nrects; i++, j--)
+ : {
+ : sequence[i] = j;
+ : }
+ : }
+ : }
+ :
+ : /*
+ : * XXX: To avoid getting multiple NoExpose events from this operation,
+ : * we turn OFF graphicsExposures in the gc and deal with any uncopied
+ : * areas later, if there's something not in backing-store.
+ : */
+ :
+ : graphicsExposures = pGC->graphicsExposures;
+ : pGC->graphicsExposures = FALSE;
+ :
+ : dx = dstx - srcx;
+ : dy = dsty - srcy;
+ :
+ : /*
+ : * Figure out which copy procedure to use from the backing GC. Note we
+ : * must do this because some implementations (sun's, e.g.) have
+ : * pBackingGC a fake GC with the real one below it, thus the devPriv for
+ : * pBackingGC won't be what the output library expects.
+ : */
+ : if (plane != 0)
+ : {
+ : pixCopyProc = pBackingGC->ops->CopyPlane;
+ : }
+ : else
+ : {
+ : pixCopyProc = (CopyPlaneProcPtr)pBackingGC->ops->CopyArea;
+ : }
+ :
+ : for (i = 0; i < nrects; i++)
+ : {
+ : pBox = boxes[sequence[i]].pBox;
+ :
+ : /*
+ : * If we're copying from the pixmap, we need to place its contents
+ : * onto the screen before scrolling the pixmap itself. If we're copying
+ : * from the window, we need to copy its contents into the pixmap before
+ : * we scroll the window itself.
+ : */
+ : if (boxes[sequence[i]].source == pix)
+ : {
+ : (void) (* copyProc) (pBackingDrawable, &(pWin->drawable), pGC,
+ : pBox->x1 - pBackingStore->x,
+ : pBox->y1 - pBackingStore->y,
+ : pBox->x2 - pBox->x1, pBox->y2 - pBox->y1,
+ : pBox->x1 + dx, pBox->y1 + dy, plane);
+ : (void) (* pixCopyProc) (pBackingDrawable, pBackingDrawable, pBackingGC,
+ : pBox->x1 - pBackingStore->x,
+ : pBox->y1 - pBackingStore->y,
+ : pBox->x2 - pBox->x1, pBox->y2 - pBox->y1,
+ : pBox->x1 + dx - pBackingStore->x,
+ : pBox->y1 + dy - pBackingStore->y, plane);
+ : }
+ : else
+ : {
+ : (void) (* pixCopyProc) (&(pWin->drawable), pBackingDrawable, pBackingGC,
+ : pBox->x1, pBox->y1,
+ : pBox->x2 - pBox->x1, pBox->y2 - pBox->y1,
+ : pBox->x1 + dx - pBackingStore->x,
+ : pBox->y1 + dy - pBackingStore->y, plane);
+ : (void) (* copyProc) (&(pWin->drawable), &(pWin->drawable), pGC,
+ : pBox->x1, pBox->y1,
+ : pBox->x2 - pBox->x1, pBox->y2 - pBox->y1,
+ : pBox->x1 + dx, pBox->y1 + dy, plane);
+ : }
+ : }
+ : DEALLOCATE_LOCAL(sequence);
+ : DEALLOCATE_LOCAL(boxes);
+ :
+ : pGC->graphicsExposures = graphicsExposures;
+ : /*
+ : * Form union of rgnExp and rgnObs and see if covers entire area
+ : * to be copied. Store the resultant region for miBSCopyArea
+ : * to return to dispatch which will send the appropriate expose
+ : * events.
+ : */
+ : REGION_UNION(pGC->pScreen, pRgnExp, pRgnExp, pRgnObs);
+ : box.x1 = srcx;
+ : box.x2 = srcx + w;
+ : box.y1 = srcy;
+ : box.y2 = srcy + h;
+ : if (RECT_IN_REGION(pGC->pScreen, pRgnExp, &box) == rgnIN)
+ : {
+ : REGION_EMPTY(pGC->pScreen, pRgnExp);
+ : }
+ : else
+ : {
+ : REGION_INVERSE( pGC->pScreen, pRgnExp, pRgnExp, &box);
+ : REGION_TRANSLATE( pGC->pScreen, pRgnExp,
+ : dx + pWin->drawable.x,
+ : dy + pWin->drawable.y);
+ : REGION_INTERSECT( pGC->pScreen, pRgnObs, pRgnExp, &pWin->clipList);
+ : (*pWin->drawable.pScreen->PaintWindowBackground) (pWin,
+ : pRgnObs, PW_BACKGROUND);
+ : REGION_TRANSLATE( pGC->pScreen, pRgnExp,
+ : -pWin->drawable.x,
+ : -pWin->drawable.y);
+ : miBSClearBackingRegion (pWin, pRgnExp);
+ : }
+ : if (graphicsExposures)
+ : *ppRgn = pRgnExp;
+ : else
+ : REGION_DESTROY(pGC->pScreen, pRgnExp);
+ : REGION_DESTROY(pGC->pScreen, pRgnObs);
+ :
+ : return (TRUE);
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSCopyArea --
+ : * Perform a CopyArea from the source to the destination, extracting
+ : * from the source's backing-store and storing into the destination's
+ : * backing-store without messing anything up. If the source and
+ : * destination are different, there's not too much to worry about:
+ : * we can just issue several calls to the regular CopyArea function.
+ : *
+ : * Results:
+ : * None.
+ : *
+ : * Side Effects:
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static RegionPtr
+ :miBSCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty)
+ : DrawablePtr pSrc;
+ : DrawablePtr pDst;
+ : GCPtr pGC;
+ : int srcx;
+ : int srcy;
+ : int w;
+ : int h;
+ : int dstx;
+ : int dsty;
+ :{
+ : BoxPtr pExtents;
+ : long dx, dy;
+ : int bsrcx, bsrcy, bw, bh, bdstx, bdsty;
+ : RegionPtr pixExposed = 0, winExposed = 0;
+ :
+ : SETUP_BACKING(pDst, pGC);
+ :
+ : PROLOGUE(pGC);
+ :
+ : if ((pSrc != pDst) ||
+ : (!miBSDoCopy((WindowPtr)pSrc, pGC, srcx, srcy, w, h, dstx, dsty,
+ : (unsigned long) 0, (CopyPlaneProcPtr)pGC->ops->CopyArea,
+ : &winExposed)))
+ : {
+ : /*
+ : * always copy to the backing store first, miBSDoCopy
+ : * returns FALSE if the *source* region is disjoint
+ : * from the backing store saved region. So, copying
+ : * *to* the backing store is always safe
+ : */
+ : if (pGC->clientClipType != CT_PIXMAP)
+ : {
+ : /*
+ : * adjust srcx, srcy, w, h, dstx, dsty to be clipped to
+ : * the backing store. An unnecessary optimisation,
+ : * but a useful one when GetSpans is slow.
+ : */
+ : pExtents = REGION_EXTENTS(pDst->pScreen,
+ : (RegionPtr)pBackingGC->clientClip);
+ : bsrcx = srcx;
+ : bsrcy = srcy;
+ : bw = w;
+ : bh = h;
+ : bdstx = dstx;
+ : bdsty = dsty;
+ : dx = pExtents->x1 - bdstx;
+ : if (dx > 0)
+ : {
+ : bsrcx += dx;
+ : bdstx += dx;
+ : bw -= dx;
+ : }
+ : dy = pExtents->y1 - bdsty;
+ : if (dy > 0)
+ : {
+ : bsrcy += dy;
+ : bdsty += dy;
+ : bh -= dy;
+ : }
+ : dx = (bdstx + bw) - pExtents->x2;
+ : if (dx > 0)
+ : bw -= dx;
+ : dy = (bdsty + bh) - pExtents->y2;
+ : if (dy > 0)
+ : bh -= dy;
+ : if (bw > 0 && bh > 0)
+ : pixExposed = (* pBackingGC->ops->CopyArea) (pSrc,
+ : pBackingDrawable, pBackingGC,
+ : bsrcx, bsrcy, bw, bh, bdstx - pBackingStore->x,
+ : bdsty - pBackingStore->y);
+ : }
+ : else
+ : pixExposed = (* pBackingGC->ops->CopyArea) (pSrc,
+ : pBackingDrawable, pBackingGC,
+ : srcx, srcy, w, h,
+ : dstx - pBackingStore->x, dsty - pBackingStore->y);
+ :
+ : winExposed = (* pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty);
+ : }
+ :
+ : /*
+ : * compute the composite graphics exposure region
+ : */
+ : if (winExposed)
+ : {
+ : if (pixExposed){
+ : REGION_UNION(pDst->pScreen, winExposed, winExposed, pixExposed);
+ : REGION_DESTROY(pDst->pScreen, pixExposed);
+ : }
+ : } else
+ : winExposed = pixExposed;
+ :
+ : EPILOGUE (pGC);
+ :
+ : return winExposed;
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSCopyPlane --
+ : *
+ : * Results:
+ : * None.
+ : *
+ : * Side Effects:
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static RegionPtr
+ :miBSCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane)
+ : DrawablePtr pSrc;
+ : DrawablePtr pDst;
+ : GC *pGC;
+ : int srcx,
+ : srcy;
+ : int w,
+ : h;
+ : int dstx,
+ : dsty;
+ : unsigned long plane;
+ :{
+ : BoxPtr pExtents;
+ : long dx, dy;
+ : int bsrcx, bsrcy, bw, bh, bdstx, bdsty;
+ : RegionPtr winExposed = 0, pixExposed = 0;
+ : SETUP_BACKING(pDst, pGC);
+ :
+ : PROLOGUE(pGC);
+ :
+ : if ((pSrc != pDst) ||
+ : (!miBSDoCopy((WindowPtr)pSrc, pGC, srcx, srcy, w, h, dstx, dsty,
+ : plane, pGC->ops->CopyPlane, &winExposed)))
+ : {
+ : /*
+ : * always copy to the backing store first, miBSDoCopy
+ : * returns FALSE if the *source* region is disjoint
+ : * from the backing store saved region. So, copying
+ : * *to* the backing store is always safe
+ : */
+ : if (pGC->clientClipType != CT_PIXMAP)
+ : {
+ : /*
+ : * adjust srcx, srcy, w, h, dstx, dsty to be clipped to
+ : * the backing store. An unnecessary optimisation,
+ : * but a useful one when GetSpans is slow.
+ : */
+ : pExtents = REGION_EXTENTS(pDst->pScreen,
+ : (RegionPtr)pBackingGC->clientClip);
+ : bsrcx = srcx;
+ : bsrcy = srcy;
+ : bw = w;
+ : bh = h;
+ : bdstx = dstx;
+ : bdsty = dsty;
+ : dx = pExtents->x1 - bdstx;
+ : if (dx > 0)
+ : {
+ : bsrcx += dx;
+ : bdstx += dx;
+ : bw -= dx;
+ : }
+ : dy = pExtents->y1 - bdsty;
+ : if (dy > 0)
+ : {
+ : bsrcy += dy;
+ : bdsty += dy;
+ : bh -= dy;
+ : }
+ : dx = (bdstx + bw) - pExtents->x2;
+ : if (dx > 0)
+ : bw -= dx;
+ : dy = (bdsty + bh) - pExtents->y2;
+ : if (dy > 0)
+ : bh -= dy;
+ : if (bw > 0 && bh > 0)
+ : pixExposed = (* pBackingGC->ops->CopyPlane) (pSrc,
+ : pBackingDrawable,
+ : pBackingGC, bsrcx, bsrcy, bw, bh,
+ : bdstx - pBackingStore->x,
+ : bdsty - pBackingStore->y, plane);
+ : }
+ : else
+ : pixExposed = (* pBackingGC->ops->CopyPlane) (pSrc,
+ : pBackingDrawable,
+ : pBackingGC, srcx, srcy, w, h,
+ : dstx - pBackingStore->x,
+ : dsty - pBackingStore->y, plane);
+ :
+ : winExposed = (* pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h,
+ : dstx, dsty, plane);
+ :
+ : }
+ :
+ : /*
+ : * compute the composite graphics exposure region
+ : */
+ : if (winExposed)
+ : {
+ : if (pixExposed)
+ : {
+ : REGION_UNION(pDst->pScreen, winExposed, winExposed, pixExposed);
+ : REGION_DESTROY(pDst->pScreen, pixExposed);
+ : }
+ : } else
+ : winExposed = pixExposed;
+ :
+ : EPILOGUE (pGC);
+ :
+ : return winExposed;
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSPolyPoint --
+ : * Perform a PolyPoint, routing output to backing-store as needed.
+ : *
+ : * Results:
+ : * None.
+ : *
+ : * Side Effects:
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :miBSPolyPoint (pDrawable, pGC, mode, npt, pptInit)
+ : DrawablePtr pDrawable;
+ : GCPtr pGC;
+ : int mode; /* Origin or Previous */
+ : int npt;
+ : xPoint *pptInit;
+ :{
+ : xPoint *pptCopy;
+ : SETUP_BACKING (pDrawable, pGC);
+ :
+ : PROLOGUE(pGC);
+ :
+ : pptCopy = (xPoint *)ALLOCATE_LOCAL(npt*sizeof(xPoint));
+ : if (pptCopy)
+ : {
+ : copyPoints(pptInit, pptCopy, npt, mode);
+ :
+ : (* pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pptInit);
+ :
+ : (* pBackingGC->ops->PolyPoint) (pBackingDrawable,
+ : pBackingGC, mode, npt, pptCopy);
+ :
+ : DEALLOCATE_LOCAL(pptCopy);
+ : }
+ :
+ : EPILOGUE (pGC);
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSPolyLines --
+ : * Perform a Polylines, routing output to backing-store as needed.
+ : *
+ : * Results:
+ : *
+ : * Side Effects:
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :miBSPolylines (pDrawable, pGC, mode, npt, pptInit)
+ : DrawablePtr pDrawable;
+ : GCPtr pGC;
+ : int mode;
+ : int npt;
+ : DDXPointPtr pptInit;
+ :{
+ : DDXPointPtr pptCopy;
+ : SETUP_BACKING (pDrawable, pGC);
+ :
+ : PROLOGUE(pGC);
+ :
+ : pptCopy = (DDXPointPtr)ALLOCATE_LOCAL(npt*sizeof(DDXPointRec));
+ : if (pptCopy)
+ : {
+ : copyPoints(pptInit, pptCopy, npt, mode);
+ :
+ : (* pGC->ops->Polylines)(pDrawable, pGC, mode, npt, pptInit);
+ : (* pBackingGC->ops->Polylines)(pBackingDrawable,
+ : pBackingGC, mode, npt, pptCopy);
+ : DEALLOCATE_LOCAL(pptCopy);
+ : }
+ :
+ : EPILOGUE (pGC);
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSPolySegment --
+ : * Perform a PolySegment, routing output to backing-store as needed.
+ : *
+ : * Results:
+ : * None.
+ : *
+ : * Side Effects:
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :miBSPolySegment(pDrawable, pGC, nseg, pSegs)
+ : DrawablePtr pDrawable;
+ : GCPtr pGC;
+ : int nseg;
+ : xSegment *pSegs;
+ :{
+ : xSegment *pSegsCopy;
+ :
+ : SETUP_BACKING (pDrawable, pGC);
+ :
+ : PROLOGUE(pGC);
+ :
+ : pSegsCopy = (xSegment *)ALLOCATE_LOCAL(nseg*sizeof(xSegment));
+ : if (pSegsCopy)
+ : {
+ : copyData(pSegs, pSegsCopy, nseg << 1, MoreCopy0);
+ :
+ : (* pGC->ops->PolySegment)(pDrawable, pGC, nseg, pSegs);
+ : (* pBackingGC->ops->PolySegment)(pBackingDrawable,
+ : pBackingGC, nseg, pSegsCopy);
+ :
+ : DEALLOCATE_LOCAL(pSegsCopy);
+ : }
+ :
+ : EPILOGUE (pGC);
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSPolyRectangle --
+ : * Perform a PolyRectangle, routing output to backing-store as needed.
+ : *
+ : * Results:
+ : * None
+ : *
+ : * Side Effects:
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :miBSPolyRectangle(pDrawable, pGC, nrects, pRects)
+ : DrawablePtr pDrawable;
+ : GCPtr pGC;
+ : int nrects;
+ : xRectangle *pRects;
+ :{
+ : xRectangle *pRectsCopy;
+ : SETUP_BACKING (pDrawable, pGC);
+ :
+ : PROLOGUE(pGC);
+ :
+ : pRectsCopy =(xRectangle *)ALLOCATE_LOCAL(nrects*sizeof(xRectangle));
+ : if (pRectsCopy)
+ : {
+ : copyData(pRects, pRectsCopy, nrects, MoreCopy2);
+ :
+ : (* pGC->ops->PolyRectangle)(pDrawable, pGC, nrects, pRects);
+ : (* pBackingGC->ops->PolyRectangle)(pBackingDrawable,
+ : pBackingGC, nrects, pRectsCopy);
+ :
+ : DEALLOCATE_LOCAL(pRectsCopy);
+ : }
+ :
+ : EPILOGUE (pGC);
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSPolyArc --
+ : * Perform a PolyArc, routing output to backing-store as needed.
+ : *
+ : * Results:
+ : *
+ : * Side Effects:
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :miBSPolyArc(pDrawable, pGC, narcs, parcs)
+ : DrawablePtr pDrawable;
+ : GCPtr pGC;
+ : int narcs;
+ : xArc *parcs;
+ :{
+ : xArc *pArcsCopy;
+ : SETUP_BACKING (pDrawable, pGC);
+ :
+ : PROLOGUE(pGC);
+ :
+ : pArcsCopy = (xArc *)ALLOCATE_LOCAL(narcs*sizeof(xArc));
+ : if (pArcsCopy)
+ : {
+ : copyData(parcs, pArcsCopy, narcs, MoreCopy4);
+ :
+ : (* pGC->ops->PolyArc)(pDrawable, pGC, narcs, parcs);
+ : (* pBackingGC->ops->PolyArc)(pBackingDrawable, pBackingGC,
+ : narcs, pArcsCopy);
+ :
+ : DEALLOCATE_LOCAL(pArcsCopy);
+ : }
+ :
+ : EPILOGUE (pGC);
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSFillPolygon --
+ : * Perform a FillPolygon, routing output to backing-store as needed.
+ : *
+ : * Results:
+ : * None.
+ : *
+ : * Side Effects:
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :miBSFillPolygon(pDrawable, pGC, shape, mode, count, pPts)
+ : DrawablePtr pDrawable;
+ : GCPtr pGC;
+ : int shape, mode;
+ : int count;
+ : DDXPointPtr pPts;
+ :{
+ : DDXPointPtr pPtsCopy;
+ : SETUP_BACKING (pDrawable, pGC);
+ :
+ : PROLOGUE(pGC);
+ :
+ : pPtsCopy = (DDXPointPtr)ALLOCATE_LOCAL(count*sizeof(DDXPointRec));
+ : if (pPtsCopy)
+ : {
+ : copyPoints(pPts, pPtsCopy, count, mode);
+ : (* pGC->ops->FillPolygon)(pDrawable, pGC, shape, mode, count, pPts);
+ : (* pBackingGC->ops->FillPolygon)(pBackingDrawable,
+ : pBackingGC, shape, mode,
+ : count, pPtsCopy);
+ :
+ : DEALLOCATE_LOCAL(pPtsCopy);
+ : }
+ :
+ : EPILOGUE (pGC);
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSPolyFillRect --
+ : * Perform a PolyFillRect, routing output to backing-store as needed.
+ : *
+ : * Results:
+ : * None.
+ : *
+ : * Side Effects:
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :miBSPolyFillRect(pDrawable, pGC, nrectFill, prectInit)
+ : DrawablePtr pDrawable;
+ : GCPtr pGC;
+ : int nrectFill; /* number of rectangles to fill */
+ : xRectangle *prectInit; /* Pointer to first rectangle to fill */
+ :{
+ : xRectangle *pRectCopy;
+ : SETUP_BACKING (pDrawable, pGC);
+ :
+ : PROLOGUE(pGC);
+ :
+ : pRectCopy =
+ : (xRectangle *)ALLOCATE_LOCAL(nrectFill*sizeof(xRectangle));
+ : if (pRectCopy)
+ : {
+ : copyData(prectInit, pRectCopy, nrectFill, MoreCopy2);
+ :
+ : (* pGC->ops->PolyFillRect)(pDrawable, pGC, nrectFill, prectInit);
+ : (* pBackingGC->ops->PolyFillRect)(pBackingDrawable,
+ : pBackingGC, nrectFill, pRectCopy);
+ :
+ : DEALLOCATE_LOCAL(pRectCopy);
+ : }
+ :
+ : EPILOGUE (pGC);
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSPolyFillArc --
+ : * Perform a PolyFillArc, routing output to backing-store as needed.
+ : *
+ : * Results:
+ : * None.
+ : *
+ : * Side Effects:
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :miBSPolyFillArc(pDrawable, pGC, narcs, parcs)
+ : DrawablePtr pDrawable;
+ : GCPtr pGC;
+ : int narcs;
+ : xArc *parcs;
+ :{
+ : xArc *pArcsCopy;
+ : SETUP_BACKING (pDrawable, pGC);
+ :
+ : PROLOGUE(pGC);
+ :
+ : pArcsCopy = (xArc *)ALLOCATE_LOCAL(narcs*sizeof(xArc));
+ : if (pArcsCopy)
+ : {
+ : copyData(parcs, pArcsCopy, narcs, MoreCopy4);
+ : (* pGC->ops->PolyFillArc)(pDrawable, pGC, narcs, parcs);
+ : (* pBackingGC->ops->PolyFillArc)(pBackingDrawable,
+ : pBackingGC, narcs, pArcsCopy);
+ : DEALLOCATE_LOCAL(pArcsCopy);
+ : }
+ :
+ : EPILOGUE (pGC);
+ :}
+ :
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSPolyText8 --
+ : * Perform a PolyText8, routing output to backing-store as needed.
+ : *
+ : * Results:
+ : *
+ : * Side Effects:
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static int
+ :miBSPolyText8(pDrawable, pGC, x, y, count, chars)
+ : DrawablePtr pDrawable;
+ : GCPtr pGC;
+ : int x, y;
+ : int count;
+ : char *chars;
+ :{
+ : int result;
+ : SETUP_BACKING (pDrawable, pGC);
+ :
+ : PROLOGUE(pGC);
+ :
+ : result = (* pGC->ops->PolyText8)(pDrawable, pGC, x, y, count, chars);
+ : (* pBackingGC->ops->PolyText8)(pBackingDrawable, pBackingGC,
+ : x - pBackingStore->x, y - pBackingStore->y,
+ : count, chars);
+ :
+ : EPILOGUE (pGC);
+ : return result;
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSPolyText16 --
+ : * Perform a PolyText16, routing output to backing-store as needed.
+ : *
+ : * Results:
+ : *
+ : * Side Effects:
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static int
+ :miBSPolyText16(pDrawable, pGC, x, y, count, chars)
+ : DrawablePtr pDrawable;
+ : GCPtr pGC;
+ : int x, y;
+ : int count;
+ : unsigned short *chars;
+ :{
+ : int result;
+ : SETUP_BACKING (pDrawable, pGC);
+ :
+ : PROLOGUE(pGC);
+ :
+ : result = (* pGC->ops->PolyText16)(pDrawable, pGC, x, y, count, chars);
+ : (* pBackingGC->ops->PolyText16)(pBackingDrawable, pBackingGC,
+ : x - pBackingStore->x, y - pBackingStore->y,
+ : count, chars);
+ :
+ : EPILOGUE (pGC);
+ :
+ : return result;
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSImageText8 --
+ : * Perform a ImageText8, routing output to backing-store as needed.
+ : *
+ : * Results:
+ : *
+ : * Side Effects:
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :miBSImageText8(pDrawable, pGC, x, y, count, chars)
+ : DrawablePtr pDrawable;
+ : GCPtr pGC;
+ : int x, y;
+ : int count;
+ : char *chars;
+ :{
+ : SETUP_BACKING (pDrawable, pGC);
+ : PROLOGUE(pGC);
+ :
+ : (* pGC->ops->ImageText8)(pDrawable, pGC, x, y, count, chars);
+ : (* pBackingGC->ops->ImageText8)(pBackingDrawable, pBackingGC,
+ : x - pBackingStore->x, y - pBackingStore->y,
+ : count, chars);
+ :
+ : EPILOGUE (pGC);
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSImageText16 --
+ : * Perform a ImageText16, routing output to backing-store as needed.
+ : *
+ : * Results:
+ : *
+ : * Side Effects:
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :miBSImageText16(pDrawable, pGC, x, y, count, chars)
+ : DrawablePtr pDrawable;
+ : GCPtr pGC;
+ : int x, y;
+ : int count;
+ : unsigned short *chars;
+ :{
+ : SETUP_BACKING (pDrawable, pGC);
+ : PROLOGUE(pGC);
+ :
+ : (* pGC->ops->ImageText16)(pDrawable, pGC, x, y, count, chars);
+ : (* pBackingGC->ops->ImageText16)(pBackingDrawable, pBackingGC,
+ : x - pBackingStore->x, y - pBackingStore->y,
+ : count, chars);
+ :
+ : EPILOGUE (pGC);
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSImageGlyphBlt --
+ : * Perform a ImageGlyphBlt, routing output to backing-store as needed.
+ : *
+ : * Results:
+ : *
+ : * Side Effects:
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :miBSImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)
+ : DrawablePtr pDrawable;
+ : GCPtr pGC;
+ : int x, y;
+ : unsigned int nglyph;
+ : CharInfoPtr *ppci; /* array of character info */
+ : pointer pglyphBase; /* start of array of glyphs */
+ :{
+ : SETUP_BACKING (pDrawable, pGC);
+ : PROLOGUE(pGC);
+ :
+ : (* pGC->ops->ImageGlyphBlt)(pDrawable, pGC, x, y, nglyph, ppci,
+ : pglyphBase);
+ : (* pBackingGC->ops->ImageGlyphBlt)(pBackingDrawable, pBackingGC,
+ : x - pBackingStore->x, y - pBackingStore->y,
+ : nglyph, ppci, pglyphBase);
+ :
+ : EPILOGUE (pGC);
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSPolyGlyphBlt --
+ : * Perform a PolyGlyphBlt, routing output to backing-store as needed.
+ : *
+ : * Results:
+ : *
+ : * Side Effects:
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :miBSPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)
+ : DrawablePtr pDrawable;
+ : GCPtr pGC;
+ : int x, y;
+ : unsigned int nglyph;
+ : CharInfoPtr *ppci; /* array of character info */
+ : pointer pglyphBase; /* start of array of glyphs */
+ :{
+ : SETUP_BACKING (pDrawable, pGC);
+ : PROLOGUE(pGC);
+ :
+ : (* pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, nglyph,
+ : ppci, pglyphBase);
+ : (* pBackingGC->ops->PolyGlyphBlt)(pBackingDrawable, pBackingGC,
+ : x - pBackingStore->x, y - pBackingStore->y,
+ : nglyph, ppci, pglyphBase);
+ : EPILOGUE (pGC);
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSPushPixels --
+ : * Perform a PushPixels, routing output to backing-store as needed.
+ : *
+ : * Results:
+ : *
+ : * Side Effects:
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :miBSPushPixels(pGC, pBitMap, pDst, w, h, x, y)
+ : GCPtr pGC;
+ : PixmapPtr pBitMap;
+ : DrawablePtr pDst;
+ : int w, h, x, y;
+ :{
+ : SETUP_BACKING (pDst, pGC);
+ : PROLOGUE(pGC);
+ :
+ : (* pGC->ops->PushPixels)(pGC, pBitMap, pDst, w, h, x, y);
+ : if (pGC->miTranslate) {
+ : x -= pDst->x;
+ : y -= pDst->y;
+ : }
+ : (* pBackingGC->ops->PushPixels)(pBackingGC, pBitMap,
+ : pBackingDrawable, w, h,
+ : x - pBackingStore->x, y - pBackingStore->y);
+ :
+ : EPILOGUE (pGC);
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSClearBackingStore --
+ : * Clear the given area of the backing pixmap with the background of
+ : * the window, whatever it is. If generateExposures is TRUE, generate
+ : * exposure events for the area. Note that if the area has any
+ : * part outside the saved portions of the window, we do not allow the
+ : * count in the expose events to be 0, since there will be more
+ : * expose events to come.
+ : *
+ : * Results:
+ : * None.
+ : *
+ : * Side Effects:
+ : * Areas of pixmap are cleared and Expose events are generated.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static RegionPtr
+ :miBSClearBackingStore(pWin, x, y, w, h, generateExposures)
+ : WindowPtr pWin;
+ : int x;
+ : int y;
+ : int w;
+ : int h;
+ : Bool generateExposures;
+ :{
+ : RegionPtr pRgn;
+ : int i;
+ : miBSWindowPtr pBackingStore;
+ : ScreenPtr pScreen;
+ : GCPtr pGC;
+ : int ts_x_origin,
+ : ts_y_origin;
+ : pointer gcvalues[4];
+ : unsigned long gcmask;
+ : xRectangle *rects;
+ : BoxPtr pBox;
+ : BoxRec box;
+ : PixUnion background;
+ : char backgroundState;
+ : int numRects;
+ :
+ : pBackingStore = (miBSWindowPtr)pWin->backStorage;
+ : pScreen = pWin->drawable.pScreen;
+ :
+ : if ((pBackingStore->status == StatusNoPixmap) ||
+ : (pBackingStore->status == StatusBadAlloc))
+ : return NullRegion;
+ :
+ : if (w == 0)
+ : w = (int) pWin->drawable.width - x;
+ : if (h == 0)
+ : h = (int) pWin->drawable.height - y;
+ :
+ : box.x1 = x;
+ : box.y1 = y;
+ : box.x2 = x + w;
+ : box.y2 = y + h;
+ : pRgn = REGION_CREATE(pWin->drawable.pScreen, &box, 1);
+ : if (!pRgn)
+ : return NullRegion;
+ : REGION_INTERSECT( pScreen, pRgn, pRgn, &pBackingStore->SavedRegion);
+ :
+ : if (REGION_NOTEMPTY( pScreen, pRgn))
+ : {
+ : /*
+ : * if clearing entire window, simply make new virtual
+ : * tile. For the root window, we also destroy the pixmap
+ : * to save a pile of memory
+ : */
+ : if (x == 0 && y == 0 &&
+ : w == pWin->drawable.width &&
+ : h == pWin->drawable.height)
+ : {
+ : if (!pWin->parent)
+ : miDestroyBSPixmap (pWin);
+ : if (pBackingStore->status != StatusContents)
+ : miTileVirtualBS (pWin);
+ : }
+ :
+ : ts_x_origin = ts_y_origin = 0;
+ :
+ : backgroundState = pWin->backgroundState;
+ : background = pWin->background;
+ : if (backgroundState == ParentRelative) {
+ : WindowPtr pParent;
+ :
+ : pParent = pWin;
+ : while (pParent->backgroundState == ParentRelative) {
+ : ts_x_origin -= pParent->origin.x;
+ : ts_y_origin -= pParent->origin.y;
+ : pParent = pParent->parent;
+ : }
+ : backgroundState = pParent->backgroundState;
+ : background = pParent->background;
+ : }
+ :
+ : if ((backgroundState != None) &&
+ : ((pBackingStore->status == StatusContents) ||
+ : !SameBackground (pBackingStore->backgroundState,
+ : pBackingStore->background,
+ : backgroundState,
+ : background)))
+ : {
+ : if (!pBackingStore->pBackingPixmap)
+ : miCreateBSPixmap(pWin, NullBox);
+ :
+ : pGC = GetScratchGC(pWin->drawable.depth, pScreen);
+ : if (pGC && pBackingStore->pBackingPixmap)
+ : {
+ : /*
+ : * First take care of any ParentRelative stuff by altering the
+ : * tile/stipple origin to match the coordinates of the upper-left
+ : * corner of the first ancestor without a ParentRelative background.
+ : * This coordinate is, of course, negative.
+ : */
+ :
+ : if (backgroundState == BackgroundPixel)
+ : {
+ : gcvalues[0] = (pointer) background.pixel;
+ : gcvalues[1] = (pointer)FillSolid;
+ : gcmask = GCForeground|GCFillStyle;
+ : }
+ : else
+ : {
+ : gcvalues[0] = (pointer)FillTiled;
+ : gcvalues[1] = (pointer) background.pixmap;
+ : gcmask = GCFillStyle|GCTile;
+ : }
+ : gcvalues[2] = (pointer)(long)(ts_x_origin - pBackingStore->x);
+ : gcvalues[3] = (pointer)(long)(ts_y_origin - pBackingStore->y);
+ : gcmask |= GCTileStipXOrigin|GCTileStipYOrigin;
+ : DoChangeGC(pGC, gcmask, (XID *)gcvalues, TRUE);
+ : ValidateGC((DrawablePtr)pBackingStore->pBackingPixmap, pGC);
+ :
+ : /*
+ : * Figure out the array of rectangles to fill and fill them with
+ : * PolyFillRect in the proper mode, as set in the GC above.
+ : */
+ : numRects = REGION_NUM_RECTS(pRgn);
+ : rects = (xRectangle *)ALLOCATE_LOCAL(numRects*sizeof(xRectangle));
+ :
+ : if (rects)
+ : {
+ : for (i = 0, pBox = REGION_RECTS(pRgn);
+ : i < numRects;
+ : i++, pBox++)
+ : {
+ : rects[i].x = pBox->x1 - pBackingStore->x;
+ : rects[i].y = pBox->y1 - pBackingStore->y;
+ : rects[i].width = pBox->x2 - pBox->x1;
+ : rects[i].height = pBox->y2 - pBox->y1;
+ : }
+ : (* pGC->ops->PolyFillRect) (
+ : (DrawablePtr)pBackingStore->pBackingPixmap,
+ : pGC, numRects, rects);
+ : DEALLOCATE_LOCAL(rects);
+ : }
+ : FreeScratchGC(pGC);
+ : }
+ : }
+ :
+ : if (!generateExposures)
+ : {
+ : REGION_DESTROY(pScreen, pRgn);
+ : pRgn = NULL;
+ : }
+ : else
+ : {
+ : /*
+ : * result must be screen relative, but is currently
+ : * drawable relative.
+ : */
+ : REGION_TRANSLATE(pScreen, pRgn, pWin->drawable.x,
+ : pWin->drawable.y);
+ : }
+ : }
+ : else
+ : {
+ : REGION_DESTROY( pScreen, pRgn);
+ : pRgn = NULL;
+ : }
+ : return pRgn;
+ :}
+ :
+ :static void
+ :miBSClearBackingRegion (pWin, pRgn)
+ : WindowPtr pWin;
+ : RegionPtr pRgn;
+ :{
+ : BoxPtr pBox;
+ : int i;
+ :
+ : i = REGION_NUM_RECTS(pRgn);
+ : pBox = REGION_RECTS(pRgn);
+ : while (i--)
+ : {
+ : (void) miBSClearBackingStore(pWin, pBox->x1, pBox->y1,
+ : pBox->x2 - pBox->x1,
+ : pBox->y2 - pBox->y1,
+ : FALSE);
+ : pBox++;
+ : }
+ :}
+ :
+ :/*
+ : * fill a region of the destination with virtual bits
+ : *
+ : * pRgn is to be translated by (x,y)
+ : */
+ :
+ :static void
+ :miBSFillVirtualBits (pDrawable, pGC, pRgn, x, y, state, pixunion, planeMask)
+ : DrawablePtr pDrawable;
+ : GCPtr pGC;
+ : RegionPtr pRgn;
+ : int x, y;
+ : int state;
+ : PixUnion pixunion;
+ : unsigned long planeMask;
+ :{
+ : int i;
+ : BITS32 gcmask;
+ : pointer gcval[5];
+ : xRectangle *pRect;
+ : BoxPtr pBox;
+ : WindowPtr pWin;
+ : int numRects;
+ :
+ : if (state == None)
+ : return;
+ : numRects = REGION_NUM_RECTS(pRgn);
+ : pRect = (xRectangle *)ALLOCATE_LOCAL(numRects * sizeof(xRectangle));
+ : if (!pRect)
+ : return;
+ : pWin = 0;
+ : if (pDrawable->type != DRAWABLE_PIXMAP)
+ : {
+ : pWin = (WindowPtr) pDrawable;
+ : if (!pWin->backStorage)
+ : pWin = 0;
+ : }
+ : i = 0;
+ : gcmask = 0;
+ : gcval[i++] = (pointer)planeMask;
+ : gcmask |= GCPlaneMask;
+ : if (state == BackgroundPixel)
+ : {
+ : if (pGC->fgPixel != pixunion.pixel)
+ : {
+ : gcval[i++] = (pointer)pixunion.pixel;
+ : gcmask |= GCForeground;
+ : }
+ : if (pGC->fillStyle != FillSolid)
+ : {
+ : gcval[i++] = (pointer)FillSolid;
+ : gcmask |= GCFillStyle;
+ : }
+ : }
+ : else
+ : {
+ : if (pGC->fillStyle != FillTiled)
+ : {
+ : gcval[i++] = (pointer)FillTiled;
+ : gcmask |= GCFillStyle;
+ : }
+ : if (pGC->tileIsPixel || pGC->tile.pixmap != pixunion.pixmap)
+ : {
+ : gcval[i++] = (pointer)pixunion.pixmap;
+ : gcmask |= GCTile;
+ : }
+ : if (pGC->patOrg.x != x)
+ : {
+ : gcval[i++] = (pointer)(long)x;
+ : gcmask |= GCTileStipXOrigin;
+ : }
+ : if (pGC->patOrg.y != y)
+ : {
+ : gcval[i++] = (pointer)(long)y;
+ : gcmask |= GCTileStipYOrigin;
+ : }
+ : }
+ : if (gcmask)
+ : DoChangeGC (pGC, gcmask, (XID *)gcval, 1);
+ :
+ : if (pWin)
+ : (*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeVisBack);
+ :
+ : if (pDrawable->serialNumber != pGC->serialNumber)
+ : ValidateGC (pDrawable, pGC);
+ :
+ : pBox = REGION_RECTS(pRgn);
+ : for (i = numRects; --i >= 0; pBox++, pRect++)
+ : {
+ : pRect->x = pBox->x1 + x;
+ : pRect->y = pBox->y1 + y;
+ : pRect->width = pBox->x2 - pBox->x1;
+ : pRect->height = pBox->y2 - pBox->y1;
+ : }
+ : pRect -= numRects;
+ : (*pGC->ops->PolyFillRect) (pDrawable, pGC, numRects, pRect);
+ : if (pWin)
+ : (*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeNothing);
+ : DEALLOCATE_LOCAL (pRect);
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSAllocate --
+ : * Create and install backing store info for a window
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :
+ :static void
+ :miBSAllocate(pWin)
+ : WindowPtr pWin;
+ :{
+ : miBSWindowPtr pBackingStore;
+ : ScreenPtr pScreen;
+ :
+ : if (pWin->drawable.pScreen->backingStoreSupport == NotUseful)
+ : return;
+ : pScreen = pWin->drawable.pScreen;
+ : if (!(pBackingStore = (miBSWindowPtr)pWin->backStorage))
+ : {
+ :
+ : pBackingStore = (miBSWindowPtr)xalloc(sizeof(miBSWindowRec));
+ : if (!pBackingStore)
+ : return;
+ :
+ : pBackingStore->pBackingPixmap = NullPixmap;
+ : pBackingStore->x = 0;
+ : pBackingStore->y = 0;
+ : REGION_NULL( pScreen, &pBackingStore->SavedRegion);
+ : pBackingStore->viewable = (char)pWin->viewable;
+ : pBackingStore->status = StatusNoPixmap;
+ : pBackingStore->backgroundState = None;
+ : pWin->backStorage = (pointer) pBackingStore;
+ : }
+ :
+ : /*
+ : * Now want to initialize the backing pixmap and SavedRegion if
+ : * necessary. The initialization consists of finding all the
+ : * currently-obscured regions, by taking the inverse of the window's
+ : * clip list, storing the result in SavedRegion, and exposing those
+ : * areas of the window.
+ : */
+ :
+ : if (pBackingStore->status == StatusNoPixmap &&
+ : ((pWin->backingStore == WhenMapped && pWin->viewable) ||
+ : (pWin->backingStore == Always)))
+ : {
+ : BoxRec box;
+ : RegionPtr pSavedRegion;
+ :
+ : pSavedRegion = &pBackingStore->SavedRegion;
+ :
+ : box.x1 = pWin->drawable.x;
+ : box.x2 = box.x1 + (int) pWin->drawable.width;
+ : box.y1 = pWin->drawable.y;
+ : box.y2 = pWin->drawable.y + (int) pWin->drawable.height;
+ :
+ : REGION_INVERSE( pScreen, pSavedRegion, &pWin->clipList, &box);
+ : REGION_TRANSLATE( pScreen, pSavedRegion,
+ : -pWin->drawable.x,
+ : -pWin->drawable.y);
+ :#ifdef SHAPE
+ : if (wBoundingShape (pWin))
+ : REGION_INTERSECT(pScreen, pSavedRegion, pSavedRegion,
+ : wBoundingShape (pWin));
+ : if (wClipShape (pWin))
+ : REGION_INTERSECT(pScreen, pSavedRegion, pSavedRegion,
+ : wClipShape (pWin));
+ :#endif
+ : /* if window is already on-screen, assume it has been drawn to */
+ : if (pWin->viewable)
+ : pBackingStore->status = StatusVDirty;
+ : miTileVirtualBS (pWin);
+ :
+ : /*
+ : * deliver all the newly available regions
+ : * as exposure events to the window
+ : */
+ :
+ : miSendExposures(pWin, pSavedRegion, 0, 0);
+ : }
+ : else if (!pWin->viewable)
+ : {
+ : /*
+ : * Turn off backing store when we're not supposed to
+ : * be saving anything
+ : */
+ : if (pBackingStore->status != StatusNoPixmap)
+ : {
+ : REGION_EMPTY( pScreen, &pBackingStore->SavedRegion);
+ : miDestroyBSPixmap (pWin);
+ : }
+ : }
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSFree --
+ : * Destroy and free all the stuff associated with the backing-store
+ : * for the given window.
+ : *
+ : * Results:
+ : * None.
+ : *
+ : * Side Effects:
+ : * The backing pixmap and all the regions and GC's are destroyed.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :miBSFree(pWin)
+ : WindowPtr pWin;
+ :{
+ : miBSWindowPtr pBackingStore;
+ : ScreenPtr pScreen;
+ :
+ : pScreen = pWin->drawable.pScreen;
+ :
+ : pBackingStore = (miBSWindowPtr)pWin->backStorage;
+ : if (pBackingStore)
+ : {
+ : miDestroyBSPixmap (pWin);
+ :
+ : REGION_UNINIT( pScreen, &pBackingStore->SavedRegion);
+ :
+ : xfree(pBackingStore);
+ : pWin->backStorage = NULL;
+ : }
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miResizeBackingStore --
+ : * Alter the size of the backing pixmap as necessary when the
+ : * SavedRegion changes size. The contents of the old pixmap are
+ : * copied/shifted into the new/same pixmap.
+ : *
+ : * Results:
+ : * The new Pixmap is created as necessary.
+ : *
+ : * Side Effects:
+ : * The old pixmap is destroyed.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :miResizeBackingStore(
+ : WindowPtr pWin,
+ : int dx, /* bits are moving this far */
+ : int dy, /* bits are moving this far */
+ : Bool saveBits) /* bits are useful */
+ :{
+ : miBSWindowPtr pBackingStore;
+ : PixmapPtr pBackingPixmap;
+ : ScreenPtr pScreen;
+ : GC *pGC;
+ : BoxPtr extents;
+ : PixmapPtr pNewPixmap;
+ : int nx, ny;
+ : int nw, nh;
+ :
+ : pBackingStore = (miBSWindowPtr)(pWin->backStorage);
+ : pBackingPixmap = pBackingStore->pBackingPixmap;
+ : if (!pBackingPixmap)
+ : return;
+ : pScreen = pWin->drawable.pScreen;
+ : extents = REGION_EXTENTS(pScreen, &pBackingStore->SavedRegion);
+ : pNewPixmap = pBackingPixmap;
+ :
+ : nw = extents->x2 - extents->x1;
+ : nh = extents->y2 - extents->y1;
+ :
+ : /* the policy here could be more sophisticated */
+ : if (nw != pBackingPixmap->drawable.width ||
+ : nh != pBackingPixmap->drawable.height)
+ : {
+ : if (!saveBits || !nw || !nh)
+ : {
+ : pNewPixmap = NullPixmap;
+ : pBackingStore->status = StatusNoPixmap;
+ : }
+ : else
+ : {
+ : pNewPixmap = (PixmapPtr)(*pScreen->CreatePixmap)
+ : (pScreen,
+ : nw, nh,
+ : pWin->drawable.depth);
+ : if (!pNewPixmap)
+ : {
+ :#ifdef BSEAGER
+ : pBackingStore->status = StatusNoPixmap;
+ :#else
+ : pBackingStore->status = StatusBadAlloc;
+ :#endif
+ : }
+ : }
+ : }
+ : if (!pNewPixmap)
+ : {
+ : pBackingStore->x = 0;
+ : pBackingStore->y = 0;
+ : }
+ : else
+ : {
+ : nx = pBackingStore->x - extents->x1 + dx;
+ : ny = pBackingStore->y - extents->y1 + dy;
+ : pBackingStore->x = extents->x1;
+ : pBackingStore->y = extents->y1;
+ :
+ : if (saveBits && (pNewPixmap != pBackingPixmap || nx != 0 || ny != 0))
+ : {
+ : pGC = GetScratchGC(pNewPixmap->drawable.depth, pScreen);
+ : if (pGC)
+ : {
+ : ValidateGC((DrawablePtr)pNewPixmap, pGC);
+ : /* if we implement a policy where the pixmap can be larger than
+ : * the region extents, we might want to optimize this copyarea
+ : * by only copying the old extents, rather than the entire
+ : * pixmap
+ : */
+ : (*pGC->ops->CopyArea)((DrawablePtr)pBackingPixmap,
+ : (DrawablePtr)pNewPixmap, pGC,
+ : 0, 0,
+ : pBackingPixmap->drawable.width,
+ : pBackingPixmap->drawable.height,
+ : nx, ny);
+ : FreeScratchGC(pGC);
+ : }
+ : }
+ : }
+ : /* SavedRegion is used in the backingGC clip; force an update */
+ : pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ : if (pNewPixmap != pBackingPixmap)
+ : {
+ : (* pScreen->DestroyPixmap)(pBackingPixmap);
+ : pBackingStore->pBackingPixmap = pNewPixmap;
+ : }
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSSaveDoomedAreas --
+ : * Saved the areas of the given window that are about to be
+ : * obscured. If the window has moved, pObscured is expected to
+ : * be at the new screen location and (dx,dy) is expected to be the offset
+ : * to the window's previous location.
+ : *
+ : * Results:
+ : * None.
+ : *
+ : * Side Effects:
+ : * The region is copied from the screen into pBackingPixmap and
+ : * SavedRegion is updated.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :miBSSaveDoomedAreas(pWin, pObscured, dx, dy)
+ : WindowPtr pWin;
+ : RegionPtr pObscured;
+ : int dx, dy;
+ :{
+ : miBSWindowPtr pBackingStore;
+ : ScreenPtr pScreen;
+ : int x, y;
+ :
+ : pBackingStore = (miBSWindowPtr)pWin->backStorage;
+ : pScreen = pWin->drawable.pScreen;
+ :
+ : /*
+ : * If the window isn't realized, it's being unmapped, thus we don't
+ : * want to save anything if backingStore isn't Always.
+ : */
+ : if (!pWin->realized)
+ : {
+ : pBackingStore->viewable = (char)pWin->viewable;
+ : if (pWin->backingStore != Always)
+ : {
+ : REGION_EMPTY( pScreen, &pBackingStore->SavedRegion);
+ : miDestroyBSPixmap (pWin);
+ : return;
+ : }
+ : if (pBackingStore->status == StatusBadAlloc)
+ : pBackingStore->status = StatusNoPixmap;
+ : }
+ :
+ : /* Don't even pretend to save anything for a virtual background None */
+ : if ((pBackingStore->status == StatusVirtual) &&
+ : (pBackingStore->backgroundState == None))
+ : return;
+ :
+ : if (REGION_NOTEMPTY(pScreen, pObscured))
+ : {
+ : BoxRec oldExtents;
+ : x = pWin->drawable.x;
+ : y = pWin->drawable.y;
+ : REGION_TRANSLATE(pScreen, pObscured, -x, -y);
+ : oldExtents = *REGION_EXTENTS(pScreen, &pBackingStore->SavedRegion);
+ : REGION_UNION( pScreen, &pBackingStore->SavedRegion,
+ : &pBackingStore->SavedRegion,
+ : pObscured);
+ : /*
+ : * only save the bits if we've actually
+ : * started using backing store
+ : */
+ : if (pBackingStore->status != StatusVirtual)
+ : {
+ : if (!pBackingStore->pBackingPixmap)
+ : miCreateBSPixmap (pWin, &oldExtents);
+ : else
+ : miResizeBackingStore(pWin, 0, 0, TRUE);
+ :
+ : if (pBackingStore->pBackingPixmap) {
+ : if (pBackingStore->x | pBackingStore->y)
+ : {
+ : REGION_TRANSLATE( pScreen, pObscured,
+ : -pBackingStore->x,
+ : -pBackingStore->y);
+ : x += pBackingStore->x;
+ : y += pBackingStore->y;
+ : }
+ : (* pScreen->BackingStoreFuncs.SaveAreas)
+ : (pBackingStore->pBackingPixmap, pObscured,
+ : x - dx, y - dy, pWin);
+ : }
+ : }
+ : REGION_TRANSLATE(pScreen, pObscured, x, y);
+ : }
+ : else
+ : {
+ : if (REGION_BROKEN (pScreen, pObscured))
+ : {
+ : REGION_EMPTY( pScreen, &pBackingStore->SavedRegion);
+ : miDestroyBSPixmap (pWin);
+ : return;
+ : }
+ : }
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSRestoreAreas --
+ : * Restore areas from backing-store that are no longer obscured.
+ : * expects prgnExposed to contain a screen-relative area.
+ : *
+ : * Results:
+ : * The region to generate exposure events on (which may be
+ : * different from the region to paint).
+ : *
+ : * Side Effects:
+ : * Areas are copied from pBackingPixmap to the screen. prgnExposed
+ : * is altered to contain the region that could not be restored from
+ : * backing-store.
+ : *
+ : * Notes:
+ : * This is called before sending any exposure events to the client,
+ : * and so might be called if the window has grown. Changing the backing
+ : * pixmap doesn't require revalidating the backingGC because the
+ : * client's next output request will result in a call to ValidateGC,
+ : * since the window clip region has changed, which will in turn call
+ : * miValidateBackingStore.
+ : *-----------------------------------------------------------------------
+ : */
+ :static RegionPtr
+ :miBSRestoreAreas(pWin, prgnExposed)
+ : WindowPtr pWin;
+ : RegionPtr prgnExposed;
+ :{
+ : PixmapPtr pBackingPixmap;
+ : miBSWindowPtr pBackingStore;
+ : RegionPtr prgnSaved;
+ : RegionPtr prgnRestored;
+ : ScreenPtr pScreen;
+ : RegionPtr exposures = prgnExposed;
+ :
+ : pScreen = pWin->drawable.pScreen;
+ : pBackingStore = (miBSWindowPtr)pWin->backStorage;
+ : pBackingPixmap = pBackingStore->pBackingPixmap;
+ :
+ : prgnSaved = &pBackingStore->SavedRegion;
+ :
+ : if (pBackingStore->status == StatusContents)
+ : {
+ : REGION_TRANSLATE(pScreen, prgnSaved, pWin->drawable.x,
+ : pWin->drawable.y);
+ :
+ : prgnRestored = REGION_CREATE( pScreen, (BoxPtr)NULL, 1);
+ : REGION_INTERSECT( pScreen, prgnRestored, prgnExposed, prgnSaved);
+ :
+ : /*
+ : * Since prgnExposed is no longer obscured, we no longer
+ : * will have a valid copy of it in backing-store, but there is a valid
+ : * copy of it on screen, so subtract the area we just restored from
+ : * from the area to be exposed.
+ : */
+ :
+ : if (REGION_NOTEMPTY( pScreen, prgnRestored))
+ : {
+ : REGION_SUBTRACT( pScreen, prgnSaved, prgnSaved, prgnExposed);
+ : REGION_SUBTRACT( pScreen, prgnExposed, prgnExposed, prgnRestored);
+ :
+ : /*
+ : * Do the actual restoration
+ : */
+ : (* pScreen->BackingStoreFuncs.RestoreAreas) (pBackingPixmap,
+ : prgnRestored,
+ : pWin->drawable.x + pBackingStore->x,
+ : pWin->drawable.y + pBackingStore->y,
+ : pWin);
+ : /*
+ : * if the saved region is completely empty, dispose of the
+ : * backing pixmap, otherwise, retranslate the saved
+ : * region to window relative
+ : */
+ :
+ : if (REGION_NOTEMPTY(pScreen, prgnSaved))
+ : {
+ : REGION_TRANSLATE(pScreen, prgnSaved,
+ : -pWin->drawable.x,
+ : -pWin->drawable.y);
+ : miResizeBackingStore(pWin, 0, 0, TRUE);
+ : }
+ : else
+ : miDestroyBSPixmap (pWin);
+ : }
+ : else
+ : REGION_TRANSLATE(pScreen, prgnSaved,
+ : -pWin->drawable.x, -pWin->drawable.y);
+ : REGION_DESTROY( pScreen, prgnRestored);
+ :
+ : }
+ : else if ((pBackingStore->status == StatusVirtual) ||
+ : (pBackingStore->status == StatusVDirty))
+ : {
+ : REGION_TRANSLATE(pScreen, prgnSaved,
+ : pWin->drawable.x, pWin->drawable.y);
+ : exposures = REGION_CREATE( pScreen, NullBox, 1);
+ : if (SameBackground (pBackingStore->backgroundState,
+ : pBackingStore->background,
+ : pWin->backgroundState,
+ : pWin->background))
+ : {
+ : REGION_SUBTRACT( pScreen, exposures, prgnExposed, prgnSaved);
+ : }
+ : else
+ : {
+ : miTileVirtualBS(pWin);
+ :
+ : /* we need to expose all we have (virtually) retiled */
+ : REGION_UNION( pScreen, exposures, prgnExposed, prgnSaved);
+ : }
+ : REGION_SUBTRACT( pScreen, prgnSaved, prgnSaved, prgnExposed);
+ : REGION_TRANSLATE(pScreen, prgnSaved,
+ : -pWin->drawable.x, -pWin->drawable.y);
+ : }
+ : else if (pWin->viewable && !pBackingStore->viewable &&
+ : pWin->backingStore != Always)
+ : {
+ : /*
+ : * The window was just mapped and nothing has been saved in
+ : * backing-store from the last time it was mapped. We want to capture
+ : * any output to regions that are already obscured but there are no
+ : * bits to snag off the screen, so we initialize things just as we did
+ : * in miBSAllocate, above.
+ : */
+ : BoxRec box;
+ :
+ : prgnSaved = &pBackingStore->SavedRegion;
+ :
+ : box.x1 = pWin->drawable.x;
+ : box.x2 = box.x1 + (int) pWin->drawable.width;
+ : box.y1 = pWin->drawable.y;
+ : box.y2 = box.y1 + (int) pWin->drawable.height;
+ :
+ : REGION_INVERSE( pScreen, prgnSaved, &pWin->clipList, &box);
+ : REGION_TRANSLATE( pScreen, prgnSaved,
+ : -pWin->drawable.x,
+ : -pWin->drawable.y);
+ :#ifdef SHAPE
+ : if (wBoundingShape (pWin))
+ : REGION_INTERSECT(pScreen, prgnSaved, prgnSaved,
+ : wBoundingShape (pWin));
+ : if (wClipShape (pWin))
+ : REGION_INTERSECT(pScreen, prgnSaved, prgnSaved,
+ : wClipShape (pWin));
+ :#endif
+ : miTileVirtualBS(pWin);
+ :
+ : exposures = REGION_CREATE( pScreen, &box, 1);
+ : }
+ : pBackingStore->viewable = (char)pWin->viewable;
+ : return exposures;
+ :}
+ :
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSTranslateBackingStore --
+ : * Shift the backing-store in the given direction. Called when bit
+ : * gravity is shifting things around.
+ : *
+ : * Results:
+ : * An occluded region of the window which should be sent exposure events.
+ : * This region should be in absolute coordinates (i.e. include
+ : * new window position).
+ : *
+ : * Side Effects:
+ : * If the window changed size as well as position, the backing pixmap
+ : * is resized. The contents of the backing pixmap are shifted
+ : *
+ : * Warning:
+ : * Bob and I have rewritten this routine quite a few times, each
+ : * time it gets a few more cases correct, and introducing some
+ : * interesting bugs. Naturally, I think the code is correct this
+ : * time.
+ : *
+ : * Let me try to explain what this routine is for:
+ : *
+ : * It's called from SlideAndSizeWindow whenever a window
+ : * with backing store is resized. There are two separate
+ : * possibilities:
+ : *
+ : * a) The window has ForgetGravity
+ : *
+ : * In this case, windx, windy will be 0 and oldClip will
+ : * be NULL. This indicates that all of the window contents
+ : * currently saved offscreen should be discarded, and the
+ : * entire window exposed. TranslateBackingStore, then, should
+ : * prepare a completely new backing store region based on the
+ : * new window clipList and return that region for exposure.
+ : *
+ : * b) The window has some other gravity
+ : *
+ : * In this case, windx, windy will be set to the distance
+ : * that the bits should move within the window. oldClip
+ : * will be set to the old visible portion of the window.
+ : * TranslateBackingStore, then, should adjust the backing
+ : * store to accommodate the portion of the existing backing
+ : * store bits which coorespond to backing store bits which
+ : * will still be occluded in the new configuration. oldx,oldy
+ : * are set to the old position of the window on the screen.
+ : *
+ : * Furthermore, in this case any contents of the screen which
+ : * are about to become occluded should be fetched from the screen
+ : * and placed in backing store. This is to avoid the eventual
+ : * occlusion by the win gravity shifting the child window bits around
+ : * on top of this window, and potentially losing information
+ : *
+ : * It's also called from SetShape, but I think (he says not
+ : * really knowing for sure) that this code will even work
+ : * in that case.
+ : *-----------------------------------------------------------------------
+ : */
+ :
+ :static RegionPtr
+ :miBSTranslateBackingStore(pWin, windx, windy, oldClip, oldx, oldy)
+ : WindowPtr pWin;
+ : int windx; /* bit translation distance in window */
+ : int windy;
+ : RegionPtr oldClip; /* Region being copied */
+ : int oldx; /* old window position */
+ : int oldy;
+ :{
+ : miBSWindowPtr pBackingStore;
+ : RegionPtr pSavedRegion;
+ : RegionPtr newSaved, doomed;
+ : ScreenPtr pScreen;
+ : BoxRec extents;
+ : int scrdx; /* bit translation distance on screen */
+ : int scrdy;
+ : int dx; /* distance window moved on screen */
+ : int dy;
+ :
+ : pScreen = pWin->drawable.pScreen;
+ : pBackingStore = (miBSWindowPtr)(pWin->backStorage);
+ : if ((pBackingStore->status == StatusNoPixmap) ||
+ : (pBackingStore->status == StatusBadAlloc))
+ : return NullRegion;
+ :
+ : /*
+ : * Compute the new saved region
+ : */
+ :
+ : newSaved = REGION_CREATE( pScreen, NullBox, 1);
+ : extents.x1 = pWin->drawable.x;
+ : extents.x2 = pWin->drawable.x + (int) pWin->drawable.width;
+ : extents.y1 = pWin->drawable.y;
+ : extents.y2 = pWin->drawable.y + (int) pWin->drawable.height;
+ : REGION_INVERSE( pScreen, newSaved, &pWin->clipList, &extents);
+ :
+ : REGION_TRANSLATE( pScreen, newSaved,
+ : -pWin->drawable.x, -pWin->drawable.y);
+ :#ifdef SHAPE
+ : if (wBoundingShape (pWin) || wClipShape (pWin)) {
+ : if (wBoundingShape (pWin))
+ : REGION_INTERSECT( pScreen, newSaved, newSaved,
+ : wBoundingShape (pWin));
+ : if (wClipShape (pWin))
+ : REGION_INTERSECT( pScreen, newSaved, newSaved, wClipShape (pWin));
+ : }
+ :#endif
+ :
+ : pSavedRegion = &pBackingStore->SavedRegion;
+ :
+ : /* now find any visible areas we can save from the screen */
+ : /* and then translate newSaved to old local coordinates */
+ : if (oldClip)
+ : {
+ : /* bit gravity makes things virtually too hard, punt */
+ : if (((windx != 0) || (windy != 0)) &&
+ : (pBackingStore->status != StatusContents))
+ : miCreateBSPixmap(pWin, NullBox);
+ :
+ : /*
+ : * The window is moving this far on the screen
+ : */
+ : dx = pWin->drawable.x - oldx;
+ : dy = pWin->drawable.y - oldy;
+ : /*
+ : * The bits will be moving on the screen by the
+ : * amount the window is moving + the amount the
+ : * bits are moving within the window
+ : */
+ : scrdx = windx + dx;
+ : scrdy = windy + dy;
+ :
+ : /*
+ : * intersect at old bit position to discover the
+ : * bits on the screen which can be put into the
+ : * new backing store
+ : */
+ : REGION_TRANSLATE( pScreen, oldClip, windx - oldx, windy - oldy);
+ : doomed = REGION_CREATE( pScreen, NullBox, 1);
+ : REGION_INTERSECT( pScreen, doomed, oldClip, newSaved);
+ : REGION_TRANSLATE( pScreen, oldClip, oldx - windx, oldy - windy);
+ :
+ : /*
+ : * Translate the old saved region to the position in the
+ : * window where it will appear to be
+ : */
+ : REGION_TRANSLATE( pScreen, pSavedRegion, windx, windy);
+ :
+ : /*
+ : * Add the old saved region to the new saved region, so
+ : * that calls to RestoreAreas will be able to fetch those
+ : * bits back
+ : */
+ : REGION_UNION( pScreen, newSaved, newSaved, pSavedRegion);
+ :
+ : /*
+ : * Swap the new saved region into the window
+ : */
+ : {
+ : RegionRec tmp;
+ :
+ : tmp = *pSavedRegion;
+ : *pSavedRegion = *newSaved;
+ : *newSaved = tmp;
+ : }
+ : miResizeBackingStore (pWin, windx, windy, TRUE);
+ :
+ : /*
+ : * Compute the newly enabled region
+ : * of backing store. This region will be
+ : * set to background in the backing pixmap and
+ : * sent as exposure events to the client.
+ : */
+ : REGION_SUBTRACT( pScreen, newSaved, pSavedRegion, newSaved);
+ :
+ : /*
+ : * Fetch bits which will be obscured from
+ : * the screen
+ : */
+ : if (REGION_NOTEMPTY( pScreen, doomed))
+ : {
+ : /*
+ : * Don't clear regions which have bits on the
+ : * screen
+ : */
+ : REGION_SUBTRACT( pScreen, newSaved, newSaved, doomed);
+ :
+ : /*
+ : * Make the region to SaveDoomedAreas absolute, instead
+ : * of window relative.
+ : */
+ : REGION_TRANSLATE( pScreen, doomed,
+ : pWin->drawable.x, pWin->drawable.y);
+ : (* pScreen->SaveDoomedAreas) (pWin, doomed, scrdx, scrdy);
+ : }
+ :
+ : REGION_DESTROY(pScreen, doomed);
+ :
+ : /*
+ : * and clear whatever there is that's new
+ : */
+ : if (REGION_NOTEMPTY( pScreen, newSaved))
+ : {
+ : miBSClearBackingRegion (pWin, newSaved);
+ : /*
+ : * Make the exposed region absolute
+ : */
+ : REGION_TRANSLATE(pScreen, newSaved,
+ : pWin->drawable.x,
+ : pWin->drawable.y);
+ : }
+ : else
+ : {
+ : REGION_DESTROY(pScreen, newSaved);
+ : newSaved = NullRegion;
+ : }
+ : }
+ : else
+ : {
+ : /*
+ : * ForgetGravity: just reset backing store and
+ : * expose the whole mess
+ : */
+ : REGION_COPY( pScreen, pSavedRegion, newSaved);
+ : REGION_TRANSLATE( pScreen, newSaved,
+ : pWin->drawable.x, pWin->drawable.y);
+ :
+ : miResizeBackingStore (pWin, 0, 0, FALSE);
+ : (void) miBSClearBackingStore (pWin, 0, 0, 0, 0, FALSE);
+ : }
+ :
+ : return newSaved;
+ :}
+ :
+ :/*
+ : * Inform the backing store layer that you are about to validate
+ : * a gc with a window, and that subsequent output to the window
+ : * is (or is not) guaranteed to be already clipped to the visible
+ : * regions of the window.
+ : */
+ :
+ :static void
+ :miBSDrawGuarantee (pWin, pGC, guarantee)
+ : WindowPtr pWin;
+ : GCPtr pGC;
+ : int guarantee;
+ :{
+ : miBSGCPtr pPriv;
+ :
+ : if (pWin->backStorage)
+ : {
+ : pPriv = (miBSGCPtr)pGC->devPrivates[miBSGCIndex].ptr;
+ : if (!pPriv)
+ : (void) miBSCreateGCPrivate (pGC);
+ : pPriv = (miBSGCPtr)pGC->devPrivates[miBSGCIndex].ptr;
+ : if (pPriv)
+ : {
+ : /*
+ : * XXX KLUDGE ALERT
+ : *
+ : * when the GC is Cheap pPriv will point
+ : * at some device's gc func structure. guarantee
+ : * will point at the ChangeGC entry of that struct
+ : * and will never match a valid guarantee value.
+ : */
+ : switch (pPriv->guarantee)
+ : {
+ : case GuaranteeNothing:
+ : case GuaranteeVisBack:
+ : pPriv->guarantee = guarantee;
+ : break;
+ : }
+ : }
+ : }
+ :}
+ :
+ :#define noBackingCopy (GCGraphicsExposures|GCClipXOrigin|GCClipYOrigin| \
+ : GCClipMask|GCSubwindowMode| \
+ : GCTileStipXOrigin|GCTileStipYOrigin)
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSValidateGC --
+ : * Wrapper around output-library's ValidateGC routine
+ : *
+ : * Results:
+ : * None.
+ : *
+ : * Side Effects:
+ : *
+ : * Notes:
+ : * The idea here is to perform several functions:
+ : * - All the output calls must be intercepted and routed to
+ : * backing-store as necessary.
+ : * - pGC in the window's devBackingStore must be set up with the
+ : * clip list appropriate for writing to pBackingPixmap (i.e.
+ : * the inverse of the window's clipList intersected with the
+ : * clientClip of the GC). Since the destination for this GC is
+ : * a pixmap, it is sufficient to set the clip list as its
+ : * clientClip.
+ : *-----------------------------------------------------------------------
+ : */
+ :
+ :static void
+ :miBSValidateGC (pGC, stateChanges, pDrawable)
+ : GCPtr pGC;
+ : unsigned long stateChanges;
+ : DrawablePtr pDrawable;
+ :{
+ : GCPtr pBackingGC;
+ : miBSWindowPtr pWindowPriv = NULL;
+ : miBSGCPtr pPriv;
+ : WindowPtr pWin;
+ : int lift_functions;
+ : RegionPtr backingCompositeClip = NULL;
+ :
+ : if (pDrawable->type != DRAWABLE_PIXMAP)
+ : {
+ : pWin = (WindowPtr) pDrawable;
+ : pWindowPriv = (miBSWindowPtr) pWin->backStorage;
+ : lift_functions = (pWindowPriv == (miBSWindowPtr) NULL);
+ : }
+ : else
+ : {
+ : pWin = (WindowPtr) NULL;
+ : lift_functions = TRUE;
+ : }
+ :
+ : pPriv = (miBSGCPtr)pGC->devPrivates[miBSGCIndex].ptr;
+ :
+ : FUNC_PROLOGUE (pGC, pPriv);
+ :
+ : (*pGC->funcs->ValidateGC) (pGC, stateChanges, pDrawable);
+ :
+ : /*
+ : * rewrap funcs and ops as Validate may have changed them
+ : */
+ :
+ : pPriv->wrapFuncs = pGC->funcs;
+ : pPriv->wrapOps = pGC->ops;
+ :
+ : if (!lift_functions && ((pPriv->guarantee == GuaranteeVisBack) ||
+ : (pWindowPriv->status == StatusNoPixmap) ||
+ : (pWindowPriv->status == StatusBadAlloc)))
+ : lift_functions = TRUE;
+ :
+ : /*
+ : * check to see if a new backingCompositeClip region must
+ : * be generated
+ : */
+ :
+ : if (!lift_functions &&
+ : ((pDrawable->serialNumber != pPriv->serialNumber) ||
+ : (stateChanges&(GCClipXOrigin|GCClipYOrigin|GCClipMask|GCSubwindowMode))))
+ : {
+ : if (REGION_NOTEMPTY(pGC->pScreen, &pWindowPriv->SavedRegion))
+ : {
+ : backingCompositeClip = REGION_CREATE(pGC->pScreen, NULL, 1);
+ : if ((pGC->clientClipType == CT_NONE) ||
+ : (pGC->clientClipType == CT_PIXMAP))
+ : {
+ : REGION_COPY(pGC->pScreen, backingCompositeClip,
+ : &pWindowPriv->SavedRegion);
+ : }
+ : else
+ : {
+ : /*
+ : * Make a new copy of the client clip, translated to
+ : * its proper origin.
+ : */
+ :
+ : REGION_COPY(pGC->pScreen, backingCompositeClip,
+ : pGC->clientClip);
+ : REGION_TRANSLATE(pGC->pScreen, backingCompositeClip,
+ : pGC->clipOrg.x,
+ : pGC->clipOrg.y);
+ : REGION_INTERSECT(pGC->pScreen, backingCompositeClip,
+ : backingCompositeClip,
+ : &pWindowPriv->SavedRegion);
+ : }
+ : if (pGC->subWindowMode == IncludeInferiors)
+ : {
+ : RegionPtr translatedClip;
+ :
+ : /* XXX
+ : * any output in IncludeInferiors mode will not
+ : * be redirected to Inferiors backing store. This
+ : * can be fixed only at great cost to the shadow routines.
+ : */
+ : translatedClip = NotClippedByChildren (pWin);
+ : REGION_TRANSLATE(pGC->pScreen, translatedClip,
+ : -pDrawable->x,
+ : -pDrawable->y);
+ : REGION_SUBTRACT(pGC->pScreen, backingCompositeClip,
+ : backingCompositeClip, translatedClip);
+ : REGION_DESTROY(pGC->pScreen, translatedClip);
+ : }
+ : if (!REGION_NOTEMPTY(pGC->pScreen, backingCompositeClip))
+ : lift_functions = TRUE;
+ : }
+ : else
+ : {
+ : lift_functions = TRUE;
+ : }
+ :
+ : /* Reset the status when drawing to an unoccluded window so that
+ : * future SaveAreas will actually copy bits from the screen. Note that
+ : * output to root window in IncludeInferiors mode will not cause this
+ : * to change. This causes all transient graphics by the window
+ : * manager to the root window to not enable backing store.
+ : */
+ : if (lift_functions && (pWindowPriv->status == StatusVirtual) &&
+ : (pWin->parent || pGC->subWindowMode != IncludeInferiors))
+ : pWindowPriv->status = StatusVDirty;
+ : }
+ :
+ : /*
+ : * if no backing store has been allocated, and it's needed,
+ : * create it now.
+ : */
+ :
+ : if (!lift_functions && !pWindowPriv->pBackingPixmap)
+ : {
+ : miCreateBSPixmap (pWin, NullBox);
+ : if (!pWindowPriv->pBackingPixmap)
+ : lift_functions = TRUE;
+ : }
+ :
+ : /*
+ : * create the backing GC if needed, lift functions
+ : * if the creation fails
+ : */
+ :
+ : if (!lift_functions && !pPriv->pBackingGC)
+ : {
+ : int status;
+ : XID noexpose = xFalse;
+ :
+ : /* We never want ops with the backingGC to generate GraphicsExpose */
+ : pBackingGC = CreateGC ((DrawablePtr)pWindowPriv->pBackingPixmap,
+ : GCGraphicsExposures, &noexpose, &status);
+ : if (status != Success)
+ : lift_functions = TRUE;
+ : else
+ : pPriv->pBackingGC = pBackingGC;
+ : }
+ :
+ : pBackingGC = pPriv->pBackingGC;
+ :
+ : pPriv->stateChanges |= stateChanges;
+ :
+ : if (lift_functions)
+ : {
+ : if (backingCompositeClip)
+ : REGION_DESTROY( pGC->pScreen, backingCompositeClip);
+ :
+ : /* unwrap the GC again */
+ : miBSDestroyGCPrivate (pGC);
+ :
+ : return;
+ : }
+ :
+ : /*
+ : * the rest of this function gets the pBackingGC
+ : * into shape for possible draws
+ : */
+ :
+ : pPriv->stateChanges &= ~noBackingCopy;
+ : if (pPriv->stateChanges)
+ : CopyGC(pGC, pBackingGC, pPriv->stateChanges);
+ : if ((pGC->patOrg.x - pWindowPriv->x) != pBackingGC->patOrg.x ||
+ : (pGC->patOrg.y - pWindowPriv->y) != pBackingGC->patOrg.y)
+ : {
+ : XID vals[2];
+ : vals[0] = pGC->patOrg.x - pWindowPriv->x;
+ : vals[1] = pGC->patOrg.y - pWindowPriv->y;
+ : DoChangeGC(pBackingGC, GCTileStipXOrigin|GCTileStipYOrigin, vals, 0);
+ : }
+ : pPriv->stateChanges = 0;
+ :
+ : if (backingCompositeClip)
+ : {
+ : XID vals[2];
+ :
+ : if (pGC->clientClipType == CT_PIXMAP)
+ : {
+ : (*pBackingGC->funcs->CopyClip)(pBackingGC, pGC);
+ : REGION_TRANSLATE(pGC->pScreen, backingCompositeClip,
+ : -pGC->clipOrg.x, -pGC->clipOrg.y);
+ : vals[0] = pGC->clipOrg.x - pWindowPriv->x;
+ : vals[1] = pGC->clipOrg.y - pWindowPriv->y;
+ : DoChangeGC(pBackingGC, GCClipXOrigin|GCClipYOrigin, vals, 0);
+ : (* pGC->pScreen->BackingStoreFuncs.SetClipmaskRgn)
+ : (pBackingGC, backingCompositeClip);
+ : REGION_DESTROY( pGC->pScreen, backingCompositeClip);
+ : }
+ : else
+ : {
+ : vals[0] = -pWindowPriv->x;
+ : vals[1] = -pWindowPriv->y;
+ : DoChangeGC(pBackingGC, GCClipXOrigin|GCClipYOrigin, vals, 0);
+ : (*pBackingGC->funcs->ChangeClip) (pBackingGC, CT_REGION, backingCompositeClip, 0);
+ : }
+ : pPriv->serialNumber = pDrawable->serialNumber;
+ : }
+ :
+ : if (pWindowPriv->pBackingPixmap->drawable.serialNumber
+ : != pBackingGC->serialNumber)
+ : {
+ : ValidateGC((DrawablePtr)pWindowPriv->pBackingPixmap, pBackingGC);
+ : }
+ :
+ : if (pBackingGC->clientClip == 0)
+ : ErrorF ("backing store clip list nil");
+ :
+ : FUNC_EPILOGUE (pGC, pPriv);
+ :}
+ :
+ :static void
+ :miBSChangeGC (pGC, mask)
+ : GCPtr pGC;
+ : unsigned long mask;
+ :{
+ : miBSGCPtr pPriv = (miBSGCPtr) (pGC)->devPrivates[miBSGCIndex].ptr;
+ :
+ : FUNC_PROLOGUE (pGC, pPriv);
+ :
+ : (*pGC->funcs->ChangeGC) (pGC, mask);
+ :
+ : FUNC_EPILOGUE (pGC, pPriv);
+ :}
+ :
+ :static void
+ :miBSCopyGC (pGCSrc, mask, pGCDst)
+ : GCPtr pGCSrc, pGCDst;
+ : unsigned long mask;
+ :{
+ : miBSGCPtr pPriv = (miBSGCPtr) (pGCDst)->devPrivates[miBSGCIndex].ptr;
+ :
+ : FUNC_PROLOGUE (pGCDst, pPriv);
+ :
+ : (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
+ :
+ : FUNC_EPILOGUE (pGCDst, pPriv);
+ :}
+ :
+ :static void
+ :miBSDestroyGC (pGC)
+ : GCPtr pGC;
+ :{
+ : miBSGCPtr pPriv = (miBSGCPtr) (pGC)->devPrivates[miBSGCIndex].ptr;
+ :
+ : FUNC_PROLOGUE (pGC, pPriv);
+ :
+ : if (pPriv->pBackingGC)
+ : FreeGC(pPriv->pBackingGC, (GContext)0);
+ :
+ : (*pGC->funcs->DestroyGC) (pGC);
+ :
+ : FUNC_EPILOGUE (pGC, pPriv);
+ :
+ : xfree(pPriv);
+ :}
+ :
+ :static void
+ :miBSChangeClip(pGC, type, pvalue, nrects)
+ : GCPtr pGC;
+ : int type;
+ : pointer pvalue;
+ : int nrects;
+ :{
+ : miBSGCPtr pPriv = (miBSGCPtr) (pGC)->devPrivates[miBSGCIndex].ptr;
+ :
+ : FUNC_PROLOGUE (pGC, pPriv);
+ :
+ : (* pGC->funcs->ChangeClip)(pGC, type, pvalue, nrects);
+ :
+ : FUNC_EPILOGUE (pGC, pPriv);
+ :}
+ :
+ :static void
+ :miBSCopyClip(pgcDst, pgcSrc)
+ : GCPtr pgcDst, pgcSrc;
+ :{
+ : miBSGCPtr pPriv = (miBSGCPtr) (pgcDst)->devPrivates[miBSGCIndex].ptr;
+ :
+ : FUNC_PROLOGUE (pgcDst, pPriv);
+ :
+ : (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
+ :
+ : FUNC_EPILOGUE (pgcDst, pPriv);
+ :}
+ :
+ :static void
+ :miBSDestroyClip(pGC)
+ : GCPtr pGC;
+ :{
+ : miBSGCPtr pPriv = (miBSGCPtr) (pGC)->devPrivates[miBSGCIndex].ptr;
+ :
+ : FUNC_PROLOGUE (pGC, pPriv);
+ :
+ : (* pGC->funcs->DestroyClip)(pGC);
+ :
+ : FUNC_EPILOGUE (pGC, pPriv);
+ :}
+ :
+ :static void
+ :miDestroyBSPixmap (pWin)
+ : WindowPtr pWin;
+ :{
+ : miBSWindowPtr pBackingStore;
+ : ScreenPtr pScreen;
+ :
+ : pScreen = pWin->drawable.pScreen;
+ : pBackingStore = (miBSWindowPtr) pWin->backStorage;
+ : if (pBackingStore->pBackingPixmap)
+ : (* pScreen->DestroyPixmap)(pBackingStore->pBackingPixmap);
+ : pBackingStore->pBackingPixmap = NullPixmap;
+ : pBackingStore->x = 0;
+ : pBackingStore->y = 0;
+ : if (pBackingStore->backgroundState == BackgroundPixmap)
+ : (* pScreen->DestroyPixmap)(pBackingStore->background.pixmap);
+ : pBackingStore->backgroundState = None;
+ : pBackingStore->status = StatusNoPixmap;
+ : pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ :}
+ :
+ :static void
+ :miTileVirtualBS (pWin)
+ : WindowPtr pWin;
+ :{
+ : miBSWindowPtr pBackingStore;
+ :
+ : pBackingStore = (miBSWindowPtr) pWin->backStorage;
+ : if (pBackingStore->backgroundState == BackgroundPixmap)
+ : (* pWin->drawable.pScreen->DestroyPixmap)
+ : (pBackingStore->background.pixmap);
+ : pBackingStore->backgroundState = pWin->backgroundState;
+ : pBackingStore->background = pWin->background;
+ : if (pBackingStore->backgroundState == BackgroundPixmap)
+ : pBackingStore->background.pixmap->refcnt++;
+ :
+ : if (pBackingStore->status != StatusVDirty)
+ : pBackingStore->status = StatusVirtual;
+ :
+ : /*
+ : * punt parent relative tiles and do it now
+ : */
+ : if (pBackingStore->backgroundState == ParentRelative)
+ : miCreateBSPixmap (pWin, NullBox);
+ :}
+ :
+ :#ifdef DEBUG
+ :static int BSAllocationsFailed = 0;
+ :#define FAILEDSIZE 32
+ :static struct { int w, h; } failedRecord[FAILEDSIZE];
+ :static int failedIndex;
+ :#endif
+ :
+ :static void
+ :miCreateBSPixmap (pWin, pExtents)
+ : WindowPtr pWin;
+ : BoxPtr pExtents;
+ :{
+ : miBSWindowPtr pBackingStore;
+ : ScreenPtr pScreen;
+ : PixUnion background;
+ : char backgroundState = 0;
+ : BoxPtr extents;
+ : Bool backSet;
+ :
+ : pScreen = pWin->drawable.pScreen;
+ : pBackingStore = (miBSWindowPtr) pWin->backStorage;
+ : if (pBackingStore->status == StatusBadAlloc)
+ : return;
+ : backSet = ((pBackingStore->status == StatusVirtual) ||
+ : (pBackingStore->status == StatusVDirty));
+ :
+ : extents = REGION_EXTENTS( pScreen, &pBackingStore->SavedRegion);
+ :
+ : if (!pBackingStore->pBackingPixmap &&
+ : extents->x2 != extents->x1 &&
+ : extents->y2 != extents->y1)
+ : {
+ : /* the policy here could be more sophisticated */
+ : pBackingStore->x = extents->x1;
+ : pBackingStore->y = extents->y1;
+ : pBackingStore->pBackingPixmap =
+ : (PixmapPtr)(* pScreen->CreatePixmap)
+ : (pScreen,
+ : extents->x2 - extents->x1,
+ : extents->y2 - extents->y1,
+ : pWin->drawable.depth);
+ : }
+ : if (!pBackingStore->pBackingPixmap)
+ : {
+ :#ifdef DEBUG
+ : BSAllocationsFailed++;
+ : /*
+ : * record failed allocations
+ : */
+ : failedRecord[failedIndex].w = pWin->drawable.width;
+ : failedRecord[failedIndex].h = pWin->drawable.height;
+ : failedIndex++;
+ : if (failedIndex == FAILEDSIZE)
+ : failedIndex = 0;
+ :#endif
+ :#ifdef BSEAGER
+ : pBackingStore->status = StatusNoPixmap;
+ :#else
+ : pBackingStore->status = StatusBadAlloc;
+ :#endif
+ : return;
+ : }
+ :
+ : pBackingStore->status = StatusContents;
+ :
+ : if (backSet)
+ : {
+ : backgroundState = pWin->backgroundState;
+ : background = pWin->background;
+ :
+ : pWin->backgroundState = pBackingStore->backgroundState;
+ : pWin->background = pBackingStore->background;
+ : if (pWin->backgroundState == BackgroundPixmap)
+ : pWin->background.pixmap->refcnt++;
+ : }
+ :
+ : if (!pExtents)
+ : pExtents = extents;
+ :
+ : if (pExtents->y1 != pExtents->y2)
+ : {
+ : RegionPtr exposed;
+ :
+ : exposed = miBSClearBackingStore(pWin,
+ : pExtents->x1, pExtents->y1,
+ : pExtents->x2 - pExtents->x1,
+ : pExtents->y2 - pExtents->y1,
+ : !backSet);
+ : if (exposed)
+ : {
+ : miSendExposures(pWin, exposed, pWin->drawable.x, pWin->drawable.y);
+ : REGION_DESTROY( pScreen, exposed);
+ : }
+ : }
+ :
+ : if (backSet)
+ : {
+ : if (pWin->backgroundState == BackgroundPixmap)
+ : (* pScreen->DestroyPixmap) (pWin->background.pixmap);
+ : pWin->backgroundState = backgroundState;
+ : pWin->background = background;
+ : if (pBackingStore->backgroundState == BackgroundPixmap)
+ : (* pScreen->DestroyPixmap) (pBackingStore->background.pixmap);
+ : pBackingStore->backgroundState = None;
+ : }
+ :}
+ :
+ :/*-
+ : *-----------------------------------------------------------------------
+ : * miBSExposeCopy --
+ : * Handle the restoration of areas exposed by graphics operations.
+ : *
+ : * Results:
+ : * None.
+ : *
+ : * Side Effects:
+ : * prgnExposed has the areas exposed from backing-store removed
+ : * from it.
+ : *
+ : *-----------------------------------------------------------------------
+ : */
+ :static void
+ :miBSExposeCopy (pSrc, pDst, pGC, prgnExposed, srcx, srcy, dstx, dsty, plane)
+ : WindowPtr pSrc;
+ : DrawablePtr pDst;
+ : GCPtr pGC;
+ : RegionPtr prgnExposed;
+ : int srcx, srcy;
+ : int dstx, dsty;
+ : unsigned long plane;
+ :{
+ : RegionRec tempRgn;
+ : miBSWindowPtr pBackingStore;
+ : CopyPlaneProcPtr copyProc;
+ : GCPtr pScratchGC;
+ : BoxPtr pBox;
+ : int i;
+ : int dx, dy;
+ : BITS32 gcMask;
+ :
+ : if (!REGION_NOTEMPTY(pGC->pScreen, prgnExposed))
+ : return;
+ : pBackingStore = (miBSWindowPtr)pSrc->backStorage;
+ :
+ : if ((pBackingStore->status == StatusNoPixmap) ||
+ : (pBackingStore->status == StatusBadAlloc))
+ : return;
+ :
+ : REGION_NULL( pGC->pScreen, &tempRgn);
+ : REGION_INTERSECT( pGC->pScreen, &tempRgn, prgnExposed,
+ : &pBackingStore->SavedRegion);
+ : REGION_SUBTRACT( pGC->pScreen, prgnExposed, prgnExposed, &tempRgn);
+ :
+ : if (plane != 0) {
+ : copyProc = pGC->ops->CopyPlane;
+ : } else {
+ : copyProc = (CopyPlaneProcPtr)pGC->ops->CopyArea;
+ : }
+ :
+ : dx = dstx - srcx;
+ : dy = dsty - srcy;
+ :
+ : switch (pBackingStore->status) {
+ : case StatusVirtual:
+ : case StatusVDirty:
+ : pScratchGC = GetScratchGC (pDst->depth, pDst->pScreen);
+ : if (pScratchGC)
+ : {
+ : gcMask = 0;
+ : if (pGC->alu != pScratchGC->alu)
+ : gcMask = GCFunction;
+ : if (pGC->planemask != pScratchGC->planemask)
+ : gcMask |= GCPlaneMask;
+ : if (gcMask)
+ : CopyGC (pGC, pScratchGC, gcMask);
+ : miBSFillVirtualBits (pDst, pScratchGC, &tempRgn, dx, dy,
+ : (int) pBackingStore->backgroundState,
+ : pBackingStore->background,
+ : ~0L);
+ : FreeScratchGC (pScratchGC);
+ : }
+ : break;
+ : case StatusContents:
+ : for (i = REGION_NUM_RECTS(&tempRgn), pBox = REGION_RECTS(&tempRgn);
+ : --i >= 0;
+ : pBox++)
+ : {
+ : (* copyProc) (&(pBackingStore->pBackingPixmap->drawable), pDst, pGC,
+ : pBox->x1 - pBackingStore->x,
+ : pBox->y1 - pBackingStore->y,
+ : pBox->x2 - pBox->x1, pBox->y2 - pBox->y1,
+ : pBox->x1 + dx, pBox->y1 + dy, plane);
+ : }
+ : break;
+ : }
+ : REGION_UNINIT( pGC->pScreen, &tempRgn);
+ :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/dix/devices.c"
+ *
+ * 9 0.0098
+ */
+
+
+ :/************************************************************
+ :
+ :Copyright 1987, 1998 The Open Group
+ :
+ :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.
+ :
+ :The above copyright notice and this permission notice shall be included in
+ :all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ :IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ :FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ :OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ :AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ :CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of The Open Group shall not be
+ :used in advertising or otherwise to promote the sale, use or other dealings
+ :in this Software without prior written authorization from The Open Group.
+ :
+ :
+ :Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+ :
+ : All Rights Reserved
+ :
+ :Permission to use, copy, modify, and distribute this software and its
+ :documentation for any purpose and without fee is hereby granted,
+ :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 Digital not be
+ :used in advertising or publicity pertaining to distribution of the
+ :software without specific, written prior permission.
+ :
+ :DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ :ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ :DIGITAL 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.
+ :
+ :********************************************************/
+ :
+ :
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include <X11/X.h>
+ :#include "misc.h"
+ :#include "resource.h"
+ :#define NEED_EVENTS
+ :#define NEED_REPLIES
+ :#include <X11/Xproto.h>
+ :#include "windowstr.h"
+ :#include "inputstr.h"
+ :#include "scrnintstr.h"
+ :#include "cursorstr.h"
+ :#include "dixstruct.h"
+ :#include "site.h"
+ :#ifndef XKB_IN_SERVER
+ :#define XKB_IN_SERVER
+ :#endif
+ :#ifdef XKB
+ :#include <xkbsrv.h>
+ :#endif
+ :#include "xace.h"
+ :
+ :#include "dispatch.h"
+ :#include "swaprep.h"
+ :#include "dixevents.h"
+ :
+ :#include <X11/extensions/XI.h>
+ :#include <X11/extensions/XIproto.h>
+ :#include "exglobals.h"
+ :#include "exevents.h"
+ :
+ :/** @file
+ : * This file handles input device-related stuff.
+ : */
+ :
+ :int CoreDevicePrivatesIndex = 0;
+ :static int CoreDevicePrivatesGeneration = -1;
+ :
+ :/**
+ : * Create a new input device and init it to sane values. The device is added
+ : * to the server's off_devices list.
+ : *
+ : * @param deviceProc Callback for device control function (switch dev on/off).
+ : * @return The newly created device.
+ : */
+ :DeviceIntPtr
+ :AddInputDevice(DeviceProc deviceProc, Bool autoStart)
+ :{
+ : DeviceIntPtr dev, *prev; /* not a typo */
+ : DeviceIntPtr devtmp;
+ : int devid;
+ : char devind[MAX_DEVICES];
+ :
+ : /* Find next available id */
+ : memset(devind, 0, sizeof(char)*MAX_DEVICES);
+ : for (devtmp = inputInfo.devices; devtmp; devtmp = devtmp->next)
+ : devind[devtmp->id]++;
+ : for (devtmp = inputInfo.off_devices; devtmp; devtmp = devtmp->next)
+ : devind[devtmp->id]++;
+ : for (devid = 0; devid < MAX_DEVICES && devind[devid]; devid++)
+ : ;
+ :
+ : if (devid >= MAX_DEVICES)
+ : return (DeviceIntPtr)NULL;
+ : dev = (DeviceIntPtr) xcalloc(sizeof(DeviceIntRec), 1);
+ : if (!dev)
+ : return (DeviceIntPtr)NULL;
+ : dev->name = (char *)NULL;
+ : dev->type = 0;
+ : dev->id = devid;
+ : inputInfo.numDevices++;
+ : dev->public.on = FALSE;
+ : dev->public.processInputProc = (ProcessInputProc)NoopDDA;
+ : dev->public.realInputProc = (ProcessInputProc)NoopDDA;
+ : dev->public.enqueueInputProc = EnqueueEvent;
+ : dev->deviceProc = deviceProc;
+ : dev->startup = autoStart;
+ : dev->sync.frozen = FALSE;
+ : dev->sync.other = NullGrab;
+ : dev->sync.state = NOT_GRABBED;
+ : dev->sync.event = (xEvent *) NULL;
+ : dev->sync.evcount = 0;
+ : dev->grab = NullGrab;
+ : dev->grabTime = currentTime;
+ : dev->fromPassiveGrab = FALSE;
+ : dev->key = (KeyClassPtr)NULL;
+ : dev->valuator = (ValuatorClassPtr)NULL;
+ : dev->button = (ButtonClassPtr)NULL;
+ : dev->focus = (FocusClassPtr)NULL;
+ : dev->proximity = (ProximityClassPtr)NULL;
+ : dev->absolute = (AbsoluteClassPtr)NULL;
+ : dev->kbdfeed = (KbdFeedbackPtr)NULL;
+ : dev->ptrfeed = (PtrFeedbackPtr)NULL;
+ : dev->intfeed = (IntegerFeedbackPtr)NULL;
+ : dev->stringfeed = (StringFeedbackPtr)NULL;
+ : dev->bell = (BellFeedbackPtr)NULL;
+ : dev->leds = (LedFeedbackPtr)NULL;
+ :#ifdef XKB
+ : dev->xkb_interest = NULL;
+ :#endif
+ : dev->nPrivates = 0;
+ : dev->devPrivates = NULL;
+ : dev->unwrapProc = NULL;
+ : dev->coreEvents = TRUE;
+ : dev->inited = FALSE;
+ : dev->enabled = FALSE;
+ :
+ : for (prev = &inputInfo.off_devices; *prev; prev = &(*prev)->next)
+ : ;
+ : *prev = dev;
+ : dev->next = NULL;
+ :
+ : return dev;
+ :}
+ :
+ :/**
+ : * Switch device ON through the driver and push it onto the global device
+ : * list. All clients are notified about the device being enabled.
+ : *
+ : * A device will send events once enabled.
+ : *
+ : * @param The device to be enabled.
+ : * @return TRUE on success or FALSE otherwise.
+ : */
+ :Bool
+ :EnableDevice(DeviceIntPtr dev)
+ :{
+ : DeviceIntPtr *prev;
+ : int ret;
+ : DeviceIntRec dummyDev;
+ : devicePresenceNotify ev;
+ :
+ : for (prev = &inputInfo.off_devices;
+ : *prev && (*prev != dev);
+ : prev = &(*prev)->next)
+ : ;
+ : if ((*prev != dev) || !dev->inited ||
+ : ((ret = (*dev->deviceProc)(dev, DEVICE_ON)) != Success)) {
+ : ErrorF("couldn't enable device %d\n", dev->id);
+ : return FALSE;
+ : }
+ : dev->enabled = TRUE;
+ : *prev = dev->next;
+ :
+ : for (prev = &inputInfo.devices; *prev; prev = &(*prev)->next)
+ : ;
+ : *prev = dev;
+ : dev->next = NULL;
+ :
+ : ev.type = DevicePresenceNotify;
+ : ev.time = currentTime.milliseconds;
+ : ev.devchange = DeviceEnabled;
+ : ev.deviceid = dev->id;
+ : dummyDev.id = 0;
+ : SendEventToAllWindows(&dummyDev, DevicePresenceNotifyMask,
+ : (xEvent *) &ev, 1);
+ :
+ : return TRUE;
+ :}
+ :
+ :/**
+ : * Switch a device off through the driver and push it onto the off_devices
+ : * list. A device will not send events while disabled. All clients are
+ : * notified about the device being disabled.
+ : *
+ : * @return TRUE on success or FALSE otherwise.
+ : */
+ :Bool
+ :DisableDevice(DeviceIntPtr dev)
+ :{
+ : DeviceIntPtr *prev;
+ : DeviceIntRec dummyDev;
+ : devicePresenceNotify ev;
+ :
+ : for (prev = &inputInfo.devices;
+ : *prev && (*prev != dev);
+ : prev = &(*prev)->next)
+ : ;
+ : if (*prev != dev)
+ : return FALSE;
+ : (void)(*dev->deviceProc)(dev, DEVICE_OFF);
+ : dev->enabled = FALSE;
+ : *prev = dev->next;
+ : dev->next = inputInfo.off_devices;
+ : inputInfo.off_devices = dev;
+ :
+ : ev.type = DevicePresenceNotify;
+ : ev.time = currentTime.milliseconds;
+ : ev.devchange = DeviceDisabled;
+ : ev.deviceid = dev->id;
+ : dummyDev.id = 0;
+ : SendEventToAllWindows(&dummyDev, DevicePresenceNotifyMask,
+ : (xEvent *) &ev, 1);
+ :
+ : return TRUE;
+ :}
+ :
+ :/**
+ : * Initialise a new device through the driver and tell all clients about the
+ : * new device.
+ : *
+ : * The device will NOT send events until it is enabled!
+ : *
+ : * @return Success or an error code on failure.
+ : */
+ :int
+ :ActivateDevice(DeviceIntPtr dev)
+ :{
+ : int ret = Success;
+ : devicePresenceNotify ev;
+ : DeviceIntRec dummyDev;
+ :
+ : if (!dev || !dev->deviceProc)
+ : return BadImplementation;
+ :
+ : ret = (*dev->deviceProc) (dev, DEVICE_INIT);
+ : dev->inited = (ret == Success);
+ :
+ : ev.type = DevicePresenceNotify;
+ : ev.time = currentTime.milliseconds;
+ : ev.devchange = DeviceAdded;
+ : ev.deviceid = dev->id;
+ : dummyDev.id = 0;
+ : SendEventToAllWindows(&dummyDev, DevicePresenceNotifyMask,
+ : (xEvent *) &ev, 1);
+ :
+ : return ret;
+ :}
+ :
+ :/**
+ : * Ring the bell.
+ : * The actual task of ringing the bell is the job of the DDX.
+ : */
+ :static void
+ :CoreKeyboardBell(int volume, DeviceIntPtr pDev, pointer arg, int something)
+ :{
+ : KeybdCtrl *ctrl = arg;
+ :
+ : DDXRingBell(volume, ctrl->bell_pitch, ctrl->bell_duration);
+ :}
+ :
+ :static void
+ :CoreKeyboardCtl(DeviceIntPtr pDev, KeybdCtrl *ctrl)
+ :{
+ : return;
+ :}
+ :
+ :/**
+ : * Device control function for the Virtual Core Keyboard.
+ : */
+ :static int
+ :CoreKeyboardProc(DeviceIntPtr pDev, int what)
+ :{
+ : CARD8 *modMap;
+ : KeySymsRec keySyms;
+ :#ifdef XKB
+ : XkbComponentNamesRec names;
+ :#endif
+ :
+ : switch (what) {
+ : case DEVICE_INIT:
+ : keySyms.minKeyCode = 8;
+ : keySyms.maxKeyCode = 255;
+ : keySyms.mapWidth = 4;
+ : keySyms.map = (KeySym *)xcalloc(sizeof(KeySym),
+ : (keySyms.maxKeyCode -
+ : keySyms.minKeyCode + 1) *
+ : keySyms.mapWidth);
+ : if (!keySyms.map) {
+ : ErrorF("Couldn't allocate core keymap\n");
+ : return BadAlloc;
+ : }
+ :
+ : modMap = (CARD8 *)xalloc(MAP_LENGTH);
+ : if (!modMap) {
+ : ErrorF("Couldn't allocate core modifier map\n");
+ : return BadAlloc;
+ : }
+ : bzero((char *)modMap, MAP_LENGTH);
+ :
+ :#ifdef XKB
+ : if (!noXkbExtension) {
+ : bzero(&names, sizeof(names));
+ : XkbSetRulesDflts("base", "pc105", "us", NULL, NULL);
+ : XkbInitKeyboardDeviceStruct(pDev, &names, &keySyms, modMap,
+ : CoreKeyboardBell, CoreKeyboardCtl);
+ : }
+ : else
+ :#endif
+ : {
+ : /* FIXME Our keymap here isn't exactly useful. */
+ : InitKeyboardDeviceStruct((DevicePtr)pDev, &keySyms, modMap,
+ : CoreKeyboardBell, CoreKeyboardCtl);
+ : }
+ :
+ : xfree(keySyms.map);
+ : xfree(modMap);
+ :
+ : break;
+ :
+ : case DEVICE_CLOSE:
+ : pDev->devPrivates[CoreDevicePrivatesIndex].ptr = NULL;
+ : break;
+ :
+ : default:
+ : break;
+ : }
+ : return Success;
+ :}
+ :
+ :/**
+ : * Device control function for the Virtual Core Pointer.
+ : */
+ :static int
+ :CorePointerProc(DeviceIntPtr pDev, int what)
+ :{
+ : BYTE map[33];
+ : int i = 0;
+ :
+ : switch (what) {
+ : case DEVICE_INIT:
+ : for (i = 1; i <= 32; i++)
+ : map[i] = i;
+ : InitPointerDeviceStruct((DevicePtr)pDev, map, 32,
+ : GetMotionHistory, (PtrCtrlProcPtr)NoopDDA,
+ : GetMotionHistorySize(), 2);
+ : pDev->valuator->axisVal[0] = screenInfo.screens[0]->width / 2;
+ : pDev->valuator->lastx = pDev->valuator->axisVal[0];
+ : pDev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2;
+ : pDev->valuator->lasty = pDev->valuator->axisVal[1];
+ : break;
+ :
+ : case DEVICE_CLOSE:
+ : pDev->devPrivates[CoreDevicePrivatesIndex].ptr = NULL;
+ : break;
+ :
+ : default:
+ : break;
+ : }
+ :
+ : return Success;
+ :}
+ :
+ :/**
+ : * Initialise the two core devices, VCP and VCK (see events.c).
+ : * The devices are activated but not enabled.
+ : * Note that the server MUST have two core devices at all times, even if there
+ : * is no physical device connected.
+ : */
+ :void
+ :InitCoreDevices(void)
+ :{
+ : DeviceIntPtr dev;
+ :
+ : if (CoreDevicePrivatesGeneration != serverGeneration) {
+ : CoreDevicePrivatesIndex = AllocateDevicePrivateIndex();
+ : CoreDevicePrivatesGeneration = serverGeneration;
+ : }
+ :
+ : if (!inputInfo.keyboard) {
+ : dev = AddInputDevice(CoreKeyboardProc, TRUE);
+ : if (!dev)
+ : FatalError("Failed to allocate core keyboard");
+ : dev->name = strdup("Virtual core keyboard");
+ :#ifdef XKB
+ : dev->public.processInputProc = CoreProcessKeyboardEvent;
+ : dev->public.realInputProc = CoreProcessKeyboardEvent;
+ : if (!noXkbExtension)
+ : XkbSetExtension(dev, ProcessKeyboardEvent);
+ :#else
+ : dev->public.processInputProc = ProcessKeyboardEvent;
+ : dev->public.realInputProc = ProcessKeyboardEvent;
+ :#endif
+ : dev->ActivateGrab = ActivateKeyboardGrab;
+ : dev->DeactivateGrab = DeactivateKeyboardGrab;
+ : dev->coreEvents = FALSE;
+ : if (!AllocateDevicePrivate(dev, CoreDevicePrivatesIndex))
+ : FatalError("Couldn't allocate keyboard devPrivates\n");
+ : dev->devPrivates[CoreDevicePrivatesIndex].ptr = NULL;
+ : (void)ActivateDevice(dev);
+ : inputInfo.keyboard = dev;
+ : }
+ :
+ : if (!inputInfo.pointer) {
+ : dev = AddInputDevice(CorePointerProc, TRUE);
+ : if (!dev)
+ : FatalError("Failed to allocate core pointer");
+ : dev->name = strdup("Virtual core pointer");
+ :#ifdef XKB
+ : dev->public.processInputProc = CoreProcessPointerEvent;
+ : dev->public.realInputProc = CoreProcessPointerEvent;
+ : if (!noXkbExtension)
+ : XkbSetExtension(dev, ProcessPointerEvent);
+ :#else
+ : dev->public.processInputProc = ProcessPointerEvent;
+ : dev->public.realInputProc = ProcessPointerEvent;
+ :#endif
+ : dev->ActivateGrab = ActivatePointerGrab;
+ : dev->DeactivateGrab = DeactivatePointerGrab;
+ : dev->coreEvents = FALSE;
+ : if (!AllocateDevicePrivate(dev, CoreDevicePrivatesIndex))
+ : FatalError("Couldn't allocate pointer devPrivates\n");
+ : dev->devPrivates[CoreDevicePrivatesIndex].ptr = NULL;
+ : (void)ActivateDevice(dev);
+ : inputInfo.pointer = dev;
+ : }
+ :}
+ :
+ :/**
+ : * Activate all switched-off devices and then enable all those devices.
+ : *
+ : * Will return an error if no core keyboard or core pointer is present.
+ : * In theory this should never happen if you call InitCoreDevices() first.
+ : *
+ : * @return Success or error code on failure.
+ : */
+ :int
+ :InitAndStartDevices(void)
+ :{
+ : DeviceIntPtr dev, next;
+ :
+ : for (dev = inputInfo.off_devices; dev; dev = dev->next) {
+ : DebugF("(dix) initialising device %d\n", dev->id);
+ : ActivateDevice(dev);
+ : }
+ : for (dev = inputInfo.off_devices; dev; dev = next)
+ : {
+ : DebugF("(dix) enabling device %d\n", dev->id);
+ : next = dev->next;
+ : if (dev->inited && dev->startup)
+ : (void)EnableDevice(dev);
+ : }
+ : for (dev = inputInfo.devices;
+ : dev && (dev != inputInfo.keyboard);
+ : dev = dev->next)
+ : ;
+ : if (!dev || (dev != inputInfo.keyboard)) {
+ : ErrorF("No core keyboard\n");
+ : return BadImplementation;
+ : }
+ : for (dev = inputInfo.devices;
+ : dev && (dev != inputInfo.pointer);
+ : dev = dev->next)
+ : ;
+ : if (!dev || (dev != inputInfo.pointer)) {
+ : ErrorF("No core pointer\n");
+ : return BadImplementation;
+ : }
+ : return Success;
+ :}
+ :
+ :/**
+ : * Close down a device and free all resources.
+ : * Once closed down, the driver will probably not expect you that you'll ever
+ : * enable it again and free associated structs. If you want the device to just
+ : * be disabled, DisableDevice().
+ : * Don't call this function directly, use RemoveDevice() instead.
+ : */
+ :static void
+ :CloseDevice(DeviceIntPtr dev)
+ :{
+ : KbdFeedbackPtr k, knext;
+ : PtrFeedbackPtr p, pnext;
+ : IntegerFeedbackPtr i, inext;
+ : StringFeedbackPtr s, snext;
+ : BellFeedbackPtr b, bnext;
+ : LedFeedbackPtr l, lnext;
+ :
+ : if (dev->inited)
+ : (void)(*dev->deviceProc)(dev, DEVICE_CLOSE);
+ :
+ : xfree(dev->name);
+ :
+ : if (dev->key) {
+ :#ifdef XKB
+ : if (dev->key->xkbInfo)
+ : XkbFreeInfo(dev->key->xkbInfo);
+ :#endif
+ : xfree(dev->key->curKeySyms.map);
+ : xfree(dev->key->modifierKeyMap);
+ : xfree(dev->key);
+ : }
+ :
+ : if (dev->valuator) {
+ : /* Counterpart to 'biggest hack ever' in init. */
+ : if (dev->valuator->motion &&
+ : dev->valuator->GetMotionProc == GetMotionHistory)
+ : xfree(dev->valuator->motion);
+ : xfree(dev->valuator);
+ : }
+ :
+ : if (dev->button) {
+ :#ifdef XKB
+ : if (dev->button->xkb_acts)
+ : xfree(dev->button->xkb_acts);
+ :#endif
+ : xfree(dev->button);
+ : }
+ :
+ : if (dev->focus) {
+ : xfree(dev->focus->trace);
+ : xfree(dev->focus);
+ : }
+ :
+ : if (dev->proximity)
+ : xfree(dev->proximity);
+ :
+ : for (k = dev->kbdfeed; k; k = knext) {
+ : knext = k->next;
+ :#ifdef XKB
+ : if (k->xkb_sli)
+ : XkbFreeSrvLedInfo(k->xkb_sli);
+ :#endif
+ : xfree(k);
+ : }
+ :
+ : for (p = dev->ptrfeed; p; p = pnext) {
+ : pnext = p->next;
+ : xfree(p);
+ : }
+ :
+ : for (i = dev->intfeed; i; i = inext) {
+ : inext = i->next;
+ : xfree(i);
+ : }
+ :
+ : for (s = dev->stringfeed; s; s = snext) {
+ : snext = s->next;
+ : xfree(s->ctrl.symbols_supported);
+ : xfree(s->ctrl.symbols_displayed);
+ : xfree(s);
+ : }
+ :
+ : for (b = dev->bell; b; b = bnext) {
+ : bnext = b->next;
+ : xfree(b);
+ : }
+ :
+ : for (l = dev->leds; l; l = lnext) {
+ : lnext = l->next;
+ :#ifdef XKB
+ : if (l->xkb_sli)
+ : XkbFreeSrvLedInfo(l->xkb_sli);
+ :#endif
+ : xfree(l);
+ : }
+ :
+ :#ifdef XKB
+ : while (dev->xkb_interest)
+ : XkbRemoveResourceClient((DevicePtr)dev,dev->xkb_interest->resource);
+ :#endif
+ :
+ : if (dev->devPrivates)
+ : xfree(dev->devPrivates);
+ :
+ : xfree(dev->sync.event);
+ : xfree(dev);
+ :}
+ :
+ :/**
+ : * Shut down all devices, free all resources, etc.
+ : * Only useful if you're shutting down the server!
+ : */
+ :void
+ :CloseDownDevices(void)
+ :{
+ : DeviceIntPtr dev, next;
+ :
+ : for (dev = inputInfo.devices; dev; dev = next)
+ : {
+ : next = dev->next;
+ : CloseDevice(dev);
+ : }
+ : for (dev = inputInfo.off_devices; dev; dev = next)
+ : {
+ : next = dev->next;
+ : CloseDevice(dev);
+ : }
+ : inputInfo.devices = NULL;
+ : inputInfo.off_devices = NULL;
+ : inputInfo.keyboard = NULL;
+ : inputInfo.pointer = NULL;
+ :}
+ :
+ :/**
+ : * Remove a device from the device list, closes it and thus frees all
+ : * resources.
+ : * Removes both enabled and disabled devices and notifies all devices about
+ : * the removal of the device.
+ : */
+ :int
+ :RemoveDevice(DeviceIntPtr dev)
+ :{
+ : DeviceIntPtr prev,tmp,next;
+ : int ret = BadMatch;
+ : devicePresenceNotify ev;
+ : DeviceIntRec dummyDev;
+ : int deviceid;
+ :
+ : DebugF("(dix) removing device %d\n", dev->id);
+ :
+ : if (!dev || dev == inputInfo.keyboard || dev == inputInfo.pointer)
+ : return BadImplementation;
+ :
+ : deviceid = dev->id;
+ : DisableDevice(dev);
+ :
+ : prev = NULL;
+ : for (tmp = inputInfo.devices; tmp; (prev = tmp), (tmp = next)) {
+ : next = tmp->next;
+ : if (tmp == dev) {
+ : CloseDevice(tmp);
+ :
+ : if (prev==NULL)
+ : inputInfo.devices = next;
+ : else
+ : prev->next = next;
+ :
+ : ret = Success;
+ : }
+ : }
+ :
+ : prev = NULL;
+ : for (tmp = inputInfo.off_devices; tmp; (prev = tmp), (tmp = next)) {
+ : next = tmp->next;
+ : if (tmp == dev) {
+ : CloseDevice(tmp);
+ :
+ : if (prev == NULL)
+ : inputInfo.off_devices = next;
+ : else
+ : prev->next = next;
+ :
+ : ret = Success;
+ : }
+ : }
+ :
+ : if (ret == Success) {
+ : inputInfo.numDevices--;
+ : ev.type = DevicePresenceNotify;
+ : ev.time = currentTime.milliseconds;
+ : ev.devchange = DeviceRemoved;
+ : ev.deviceid = deviceid;
+ : dummyDev.id = 0;
+ : SendEventToAllWindows(&dummyDev, DevicePresenceNotifyMask,
+ : (xEvent *) &ev, 1);
+ : }
+ :
+ : return ret;
+ :}
+ :
+ :int
+ :NumMotionEvents(void)
+ :{
+ : return inputInfo.pointer->valuator->numMotionEvents;
+ :}
+ :
+ :void
+ :RegisterPointerDevice(DeviceIntPtr device)
+ :{
+ : RegisterOtherDevice(device);
+ :}
+ :
+ :void
+ :RegisterKeyboardDevice(DeviceIntPtr device)
+ :{
+ : RegisterOtherDevice(device);
+ :}
+ :
+ :_X_EXPORT DevicePtr
+ :LookupKeyboardDevice(void)
+ :{
+ : return inputInfo.keyboard ? &inputInfo.keyboard->public : NULL;
+ :}
+ :
+ :_X_EXPORT DevicePtr
+ :LookupPointerDevice(void)
+ :{
+ : return inputInfo.pointer ? &inputInfo.pointer->public : NULL;
+ :}
+ :
+ :DevicePtr
+ :LookupDevice(int id)
+ :{
+ : DeviceIntPtr dev;
+ :
+ : for (dev=inputInfo.devices; dev; dev=dev->next) {
+ : if (dev->id == (CARD8)id)
+ : return (DevicePtr)dev;
+ : }
+ : for (dev=inputInfo.off_devices; dev; dev=dev->next) {
+ : if (dev->id == (CARD8)id)
+ : return (DevicePtr)dev;
+ : }
+ : return NULL;
+ :}
+ :
+ :void
+ :QueryMinMaxKeyCodes(KeyCode *minCode, KeyCode *maxCode)
+ :{
+ : if (inputInfo.keyboard) {
+ : *minCode = inputInfo.keyboard->key->curKeySyms.minKeyCode;
+ : *maxCode = inputInfo.keyboard->key->curKeySyms.maxKeyCode;
+ : }
+ :}
+ :
+ :Bool
+ :SetKeySymsMap(KeySymsPtr dst, KeySymsPtr src)
+ :{
+ : int i, j;
+ : int rowDif = src->minKeyCode - dst->minKeyCode;
+ :
+ : /* if keysym map size changes, grow map first */
+ : if (src->mapWidth < dst->mapWidth)
+ : {
+ : for (i = src->minKeyCode; i <= src->maxKeyCode; i++)
+ : {
+ :#define SI(r, c) (((r-src->minKeyCode)*src->mapWidth) + (c))
+ :#define DI(r, c) (((r - dst->minKeyCode)*dst->mapWidth) + (c))
+ : for (j = 0; j < src->mapWidth; j++)
+ : dst->map[DI(i, j)] = src->map[SI(i, j)];
+ : for (j = src->mapWidth; j < dst->mapWidth; j++)
+ : dst->map[DI(i, j)] = NoSymbol;
+ :#undef SI
+ :#undef DI
+ : }
+ : return TRUE;
+ : }
+ : else if (src->mapWidth > dst->mapWidth)
+ : {
+ : KeySym *map;
+ : int bytes = sizeof(KeySym) * src->mapWidth *
+ : (dst->maxKeyCode - dst->minKeyCode + 1);
+ : map = (KeySym *)xalloc(bytes);
+ : if (!map)
+ : return FALSE;
+ : bzero((char *)map, bytes);
+ : if (dst->map)
+ : {
+ : for (i = 0; i <= dst->maxKeyCode-dst->minKeyCode; i++)
+ : memmove((char *)&map[i*src->mapWidth],
+ : (char *)&dst->map[i*dst->mapWidth],
+ : dst->mapWidth * sizeof(KeySym));
+ : xfree(dst->map);
+ : }
+ : dst->mapWidth = src->mapWidth;
+ : dst->map = map;
+ : }
+ : memmove((char *)&dst->map[rowDif * dst->mapWidth],
+ : (char *)src->map,
+ : (int)(src->maxKeyCode - src->minKeyCode + 1) *
+ : dst->mapWidth * sizeof(KeySym));
+ : return TRUE;
+ :}
+ :
+ :static Bool
+ :InitModMap(KeyClassPtr keyc)
+ :{
+ : int i, j;
+ : CARD8 keysPerModifier[8];
+ : CARD8 mask;
+ :
+ : keyc->maxKeysPerModifier = 0;
+ : for (i = 0; i < 8; i++)
+ : keysPerModifier[i] = 0;
+ : for (i = 8; i < MAP_LENGTH; i++)
+ : {
+ : for (j = 0, mask = 1; j < 8; j++, mask <<= 1)
+ : {
+ : if (mask & keyc->modifierMap[i])
+ : {
+ : if (++keysPerModifier[j] > keyc->maxKeysPerModifier)
+ : keyc->maxKeysPerModifier = keysPerModifier[j];
+ : }
+ : }
+ : }
+ : keyc->modifierKeyMap = (KeyCode *)xalloc(8*keyc->maxKeysPerModifier);
+ : if (!keyc->modifierKeyMap && keyc->maxKeysPerModifier)
+ : return (FALSE);
+ : bzero((char *)keyc->modifierKeyMap, 8*(int)keyc->maxKeysPerModifier);
+ : for (i = 0; i < 8; i++)
+ : keysPerModifier[i] = 0;
+ : for (i = 8; i < MAP_LENGTH; i++)
+ : {
+ : for (j = 0, mask = 1; j < 8; j++, mask <<= 1)
+ : {
+ : if (mask & keyc->modifierMap[i])
+ : {
+ : keyc->modifierKeyMap[(j*keyc->maxKeysPerModifier) +
+ : keysPerModifier[j]] = i;
+ : keysPerModifier[j]++;
+ : }
+ : }
+ : }
+ : return TRUE;
+ :}
+ :
+ :_X_EXPORT Bool
+ :InitKeyClassDeviceStruct(DeviceIntPtr dev, KeySymsPtr pKeySyms, CARD8 pModifiers[])
+ :{
+ : int i;
+ : KeyClassPtr keyc;
+ :
+ : keyc = (KeyClassPtr)xalloc(sizeof(KeyClassRec));
+ : if (!keyc)
+ : return FALSE;
+ : keyc->curKeySyms.map = (KeySym *)NULL;
+ : keyc->curKeySyms.mapWidth = 0;
+ : keyc->curKeySyms.minKeyCode = pKeySyms->minKeyCode;
+ : keyc->curKeySyms.maxKeyCode = pKeySyms->maxKeyCode;
+ : keyc->modifierKeyMap = (KeyCode *)NULL;
+ : keyc->state = 0;
+ : keyc->prev_state = 0;
+ : if (pModifiers)
+ : memmove((char *)keyc->modifierMap, (char *)pModifiers, MAP_LENGTH);
+ : else
+ : bzero((char *)keyc->modifierMap, MAP_LENGTH);
+ : bzero((char *)keyc->down, DOWN_LENGTH);
+ : for (i = 0; i < 8; i++)
+ : keyc->modifierKeyCount[i] = 0;
+ : if (!SetKeySymsMap(&keyc->curKeySyms, pKeySyms) || !InitModMap(keyc))
+ : {
+ : xfree(keyc->curKeySyms.map);
+ : xfree(keyc->modifierKeyMap);
+ : xfree(keyc);
+ : return FALSE;
+ : }
+ : dev->key = keyc;
+ :#ifdef XKB
+ : dev->key->xkbInfo= NULL;
+ : if (!noXkbExtension) XkbInitDevice(dev);
+ :#endif
+ : return TRUE;
+ :}
+ :
+ :_X_EXPORT Bool
+ :InitButtonClassDeviceStruct(DeviceIntPtr dev, int numButtons,
+ : CARD8 *map)
+ :{
+ : ButtonClassPtr butc;
+ : int i;
+ :
+ : butc = (ButtonClassPtr)xalloc(sizeof(ButtonClassRec));
+ : if (!butc)
+ : return FALSE;
+ : butc->numButtons = numButtons;
+ : for (i = 1; i <= numButtons; i++)
+ : butc->map[i] = map[i];
+ : butc->buttonsDown = 0;
+ : butc->state = 0;
+ : butc->motionMask = 0;
+ : bzero((char *)butc->down, DOWN_LENGTH);
+ :#ifdef XKB
+ : butc->xkb_acts= NULL;
+ :#endif
+ : dev->button = butc;
+ : return TRUE;
+ :}
+ :
+ :_X_EXPORT Bool
+ :InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes,
+ : ValuatorMotionProcPtr motionProc,
+ : int numMotionEvents, int mode)
+ :{
+ : int i;
+ : ValuatorClassPtr valc;
+ :
+ : if (!dev)
+ : return FALSE;
+ :
+ : valc = (ValuatorClassPtr)xalloc(sizeof(ValuatorClassRec) +
+ : numAxes * sizeof(AxisInfo) +
+ : numAxes * sizeof(unsigned int));
+ : if (!valc)
+ : return FALSE;
+ :
+ : valc->motion = NULL;
+ : valc->first_motion = 0;
+ : valc->last_motion = 0;
+ : valc->GetMotionProc = motionProc;
+ :
+ : valc->numMotionEvents = numMotionEvents;
+ : valc->motionHintWindow = NullWindow;
+ : valc->numAxes = numAxes;
+ : valc->mode = mode;
+ : valc->axes = (AxisInfoPtr)(valc + 1);
+ : valc->axisVal = (int *)(valc->axes + numAxes);
+ : valc->lastx = 0;
+ : valc->lasty = 0;
+ : valc->dxremaind = 0;
+ : valc->dyremaind = 0;
+ : dev->valuator = valc;
+ :
+ : /* biggest hack ever. */
+ : if (motionProc == GetMotionHistory)
+ : AllocateMotionHistory(dev);
+ :
+ : for (i=0; i<numAxes; i++) {
+ : InitValuatorAxisStruct(dev, i, 0, -1, 0, 0, 0);
+ : valc->axisVal[i]=0;
+ : }
+ : return TRUE;
+ :}
+ :
+ :_X_EXPORT Bool
+ :InitAbsoluteClassDeviceStruct(DeviceIntPtr dev)
+ :{
+ : AbsoluteClassPtr abs;
+ :
+ : abs = (AbsoluteClassPtr)xalloc(sizeof(AbsoluteClassRec));
+ : if (!abs)
+ : return FALSE;
+ :
+ : /* we don't do anything sensible with these, but should */
+ : abs->min_x = -1;
+ : abs->min_y = -1;
+ : abs->max_x = -1;
+ : abs->max_y = -1;
+ : abs->flip_x = 0;
+ : abs->flip_y = 0;
+ : abs->rotation = 0;
+ : abs->button_threshold = 0;
+ :
+ : abs->offset_x = 0;
+ : abs->offset_y = 0;
+ : abs->width = -1;
+ : abs->height = -1;
+ : abs->following = 0;
+ : abs->screen = 0;
+ :
+ : dev->absolute = abs;
+ :
+ : return TRUE;
+ :}
+ :
+ :_X_EXPORT Bool
+ :InitFocusClassDeviceStruct(DeviceIntPtr dev)
+ :{
+ : FocusClassPtr focc;
+ :
+ : focc = (FocusClassPtr)xalloc(sizeof(FocusClassRec));
+ : if (!focc)
+ : return FALSE;
+ : focc->win = PointerRootWin;
+ : focc->revert = None;
+ : focc->time = currentTime;
+ : focc->trace = (WindowPtr *)NULL;
+ : focc->traceSize = 0;
+ : focc->traceGood = 0;
+ : dev->focus = focc;
+ : return TRUE;
+ :}
+ :
+ :_X_EXPORT Bool
+ :InitKbdFeedbackClassDeviceStruct(DeviceIntPtr dev, BellProcPtr bellProc,
+ : KbdCtrlProcPtr controlProc)
+ :{
+ : KbdFeedbackPtr feedc;
+ :
+ : feedc = (KbdFeedbackPtr)xalloc(sizeof(KbdFeedbackClassRec));
+ : if (!feedc)
+ : return FALSE;
+ : feedc->BellProc = bellProc;
+ : feedc->CtrlProc = controlProc;
+ :#ifdef XKB
+ : defaultKeyboardControl.autoRepeat = TRUE;
+ :#endif
+ : feedc->ctrl = defaultKeyboardControl;
+ : feedc->ctrl.id = 0;
+ : if ((feedc->next = dev->kbdfeed) != 0)
+ : feedc->ctrl.id = dev->kbdfeed->ctrl.id + 1;
+ : dev->kbdfeed = feedc;
+ :#ifdef XKB
+ : feedc->xkb_sli= NULL;
+ : if (!noXkbExtension)
+ : XkbFinishDeviceInit(dev);
+ :#endif
+ : (*dev->kbdfeed->CtrlProc)(dev,&dev->kbdfeed->ctrl);
+ : return TRUE;
+ :}
+ :
+ :_X_EXPORT Bool
+ :InitPtrFeedbackClassDeviceStruct(DeviceIntPtr dev, PtrCtrlProcPtr controlProc)
+ :{
+ : PtrFeedbackPtr feedc;
+ :
+ : feedc = (PtrFeedbackPtr)xalloc(sizeof(PtrFeedbackClassRec));
+ : if (!feedc)
+ : return FALSE;
+ : feedc->CtrlProc = controlProc;
+ : feedc->ctrl = defaultPointerControl;
+ : feedc->ctrl.id = 0;
+ : if ( (feedc->next = dev->ptrfeed) )
+ : feedc->ctrl.id = dev->ptrfeed->ctrl.id + 1;
+ : dev->ptrfeed = feedc;
+ : (*controlProc)(dev, &feedc->ctrl);
+ : return TRUE;
+ :}
+ :
+ :
+ :static LedCtrl defaultLedControl = {
+ : DEFAULT_LEDS, DEFAULT_LEDS_MASK, 0};
+ :
+ :static BellCtrl defaultBellControl = {
+ : DEFAULT_BELL,
+ : DEFAULT_BELL_PITCH,
+ : DEFAULT_BELL_DURATION,
+ : 0};
+ :
+ :static IntegerCtrl defaultIntegerControl = {
+ : DEFAULT_INT_RESOLUTION,
+ : DEFAULT_INT_MIN_VALUE,
+ : DEFAULT_INT_MAX_VALUE,
+ : DEFAULT_INT_DISPLAYED,
+ : 0};
+ :
+ :_X_EXPORT Bool
+ :InitStringFeedbackClassDeviceStruct (
+ : DeviceIntPtr dev, StringCtrlProcPtr controlProc,
+ : int max_symbols, int num_symbols_supported, KeySym *symbols)
+ :{
+ : int i;
+ : StringFeedbackPtr feedc;
+ :
+ : feedc = (StringFeedbackPtr)xalloc(sizeof(StringFeedbackClassRec));
+ : if (!feedc)
+ : return FALSE;
+ : feedc->CtrlProc = controlProc;
+ : feedc->ctrl.num_symbols_supported = num_symbols_supported;
+ : feedc->ctrl.num_symbols_displayed = 0;
+ : feedc->ctrl.max_symbols = max_symbols;
+ : feedc->ctrl.symbols_supported = (KeySym *)
+ : xalloc (sizeof (KeySym) * num_symbols_supported);
+ : feedc->ctrl.symbols_displayed = (KeySym *)
+ : xalloc (sizeof (KeySym) * max_symbols);
+ : if (!feedc->ctrl.symbols_supported || !feedc->ctrl.symbols_displayed)
+ : {
+ : if (feedc->ctrl.symbols_supported)
+ : xfree(feedc->ctrl.symbols_supported);
+ : if (feedc->ctrl.symbols_displayed)
+ : xfree(feedc->ctrl.symbols_displayed);
+ : xfree(feedc);
+ : return FALSE;
+ : }
+ : for (i=0; i<num_symbols_supported; i++)
+ : *(feedc->ctrl.symbols_supported+i) = *symbols++;
+ : for (i=0; i<max_symbols; i++)
+ : *(feedc->ctrl.symbols_displayed+i) = (KeySym) NULL;
+ : feedc->ctrl.id = 0;
+ : if ( (feedc->next = dev->stringfeed) )
+ : feedc->ctrl.id = dev->stringfeed->ctrl.id + 1;
+ : dev->stringfeed = feedc;
+ : (*controlProc)(dev, &feedc->ctrl);
+ : return TRUE;
+ :}
+ :
+ :_X_EXPORT Bool
+ :InitBellFeedbackClassDeviceStruct (DeviceIntPtr dev, BellProcPtr bellProc,
+ : BellCtrlProcPtr controlProc)
+ :{
+ : BellFeedbackPtr feedc;
+ :
+ : feedc = (BellFeedbackPtr)xalloc(sizeof(BellFeedbackClassRec));
+ : if (!feedc)
+ : return FALSE;
+ : feedc->CtrlProc = controlProc;
+ : feedc->BellProc = bellProc;
+ : feedc->ctrl = defaultBellControl;
+ : feedc->ctrl.id = 0;
+ : if ( (feedc->next = dev->bell) )
+ : feedc->ctrl.id = dev->bell->ctrl.id + 1;
+ : dev->bell = feedc;
+ : (*controlProc)(dev, &feedc->ctrl);
+ : return TRUE;
+ :}
+ :
+ :_X_EXPORT Bool
+ :InitLedFeedbackClassDeviceStruct (DeviceIntPtr dev, LedCtrlProcPtr controlProc)
+ :{
+ : LedFeedbackPtr feedc;
+ :
+ : feedc = (LedFeedbackPtr)xalloc(sizeof(LedFeedbackClassRec));
+ : if (!feedc)
+ : return FALSE;
+ : feedc->CtrlProc = controlProc;
+ : feedc->ctrl = defaultLedControl;
+ : feedc->ctrl.id = 0;
+ : if ( (feedc->next = dev->leds) )
+ : feedc->ctrl.id = dev->leds->ctrl.id + 1;
+ :#ifdef XKB
+ : feedc->xkb_sli= NULL;
+ :#endif
+ : dev->leds = feedc;
+ : (*controlProc)(dev, &feedc->ctrl);
+ : return TRUE;
+ :}
+ :
+ :_X_EXPORT Bool
+ :InitIntegerFeedbackClassDeviceStruct (DeviceIntPtr dev, IntegerCtrlProcPtr controlProc)
+ :{
+ : IntegerFeedbackPtr feedc;
+ :
+ : feedc = (IntegerFeedbackPtr)xalloc(sizeof(IntegerFeedbackClassRec));
+ : if (!feedc)
+ : return FALSE;
+ : feedc->CtrlProc = controlProc;
+ : feedc->ctrl = defaultIntegerControl;
+ : feedc->ctrl.id = 0;
+ : if ( (feedc->next = dev->intfeed) )
+ : feedc->ctrl.id = dev->intfeed->ctrl.id + 1;
+ : dev->intfeed = feedc;
+ : (*controlProc)(dev, &feedc->ctrl);
+ : return TRUE;
+ :}
+ :
+ :_X_EXPORT Bool
+ :InitPointerDeviceStruct(DevicePtr device, CARD8 *map, int numButtons,
+ : ValuatorMotionProcPtr motionProc,
+ : PtrCtrlProcPtr controlProc, int numMotionEvents,
+ : int numAxes)
+ :{
+ : DeviceIntPtr dev = (DeviceIntPtr)device;
+ :
+ : return(InitButtonClassDeviceStruct(dev, numButtons, map) &&
+ : InitValuatorClassDeviceStruct(dev, numAxes, motionProc,
+ : numMotionEvents, 0) &&
+ : InitPtrFeedbackClassDeviceStruct(dev, controlProc));
+ :}
+ :
+ :_X_EXPORT Bool
+ :InitKeyboardDeviceStruct(DevicePtr device, KeySymsPtr pKeySyms,
+ : CARD8 pModifiers[], BellProcPtr bellProc,
+ : KbdCtrlProcPtr controlProc)
+ :{
+ : DeviceIntPtr dev = (DeviceIntPtr)device;
+ :
+ : return(InitKeyClassDeviceStruct(dev, pKeySyms, pModifiers) &&
+ : InitFocusClassDeviceStruct(dev) &&
+ : InitKbdFeedbackClassDeviceStruct(dev, bellProc, controlProc));
+ :}
+ :
+ :_X_EXPORT void
+ :SendMappingNotify(unsigned request, unsigned firstKeyCode, unsigned count,
+ : ClientPtr client)
+ :{
+ : int i;
+ : xEvent event;
+ :
+ : event.u.u.type = MappingNotify;
+ : event.u.mappingNotify.request = request;
+ : if (request == MappingKeyboard)
+ : {
+ : event.u.mappingNotify.firstKeyCode = firstKeyCode;
+ : event.u.mappingNotify.count = count;
+ : }
+ :#ifdef XKB
+ : if (!noXkbExtension &&
+ : ((request == MappingKeyboard) || (request == MappingModifier))) {
+ : XkbApplyMappingChange(inputInfo.keyboard,request,firstKeyCode,count,
+ : client);
+ : }
+ :#endif
+ :
+ : /* 0 is the server client */
+ : for (i=1; i<currentMaxClients; i++)
+ : {
+ : if (clients[i] && clients[i]->clientState == ClientStateRunning)
+ : {
+ :#ifdef XKB
+ : if (!noXkbExtension &&
+ : (request == MappingKeyboard) &&
+ : (clients[i]->xkbClientFlags != 0) &&
+ : (clients[i]->mapNotifyMask&XkbKeySymsMask))
+ : continue;
+ :#endif
+ : event.u.u.sequenceNumber = clients[i]->sequence;
+ : WriteEventsToClient(clients[i], 1, &event);
+ : }
+ : }
+ :}
+ :
+ :/*
+ : * n-squared algorithm. n < 255 and don't want to copy the whole thing and
+ : * sort it to do the checking. How often is it called? Just being lazy?
+ : */
+ :Bool
+ :BadDeviceMap(BYTE *buff, int length, unsigned low, unsigned high, XID *errval)
+ :{
+ : int i, j;
+ :
+ : for (i = 0; i < length; i++)
+ : if (buff[i]) /* only check non-zero elements */
+ : {
+ : if ((low > buff[i]) || (high < buff[i]))
+ : {
+ : *errval = buff[i];
+ : return TRUE;
+ : }
+ : for (j = i + 1; j < length; j++)
+ : if (buff[i] == buff[j])
+ : {
+ : *errval = buff[i];
+ : return TRUE;
+ : }
+ : }
+ : return FALSE;
+ :}
+ :
+ :Bool
+ :AllModifierKeysAreUp(dev, map1, per1, map2, per2)
+ : DeviceIntPtr dev;
+ : CARD8 *map1, *map2;
+ : int per1, per2;
+ :{
+ : int i, j, k;
+ : CARD8 *down = dev->key->down;
+ :
+ : for (i = 8; --i >= 0; map2 += per2)
+ : {
+ : for (j = per1; --j >= 0; map1++)
+ : {
+ : if (*map1 && BitIsOn(down, *map1))
+ : {
+ : for (k = per2; (--k >= 0) && (*map1 != map2[k]);)
+ : ;
+ : if (k < 0)
+ : return FALSE;
+ : }
+ : }
+ : }
+ : return TRUE;
+ :}
+ :
+ :static int
+ :DoSetModifierMapping(ClientPtr client, KeyCode *inputMap,
+ : int numKeyPerModifier)
+ :{
+ : DeviceIntPtr pDev = NULL;
+ : int i = 0, inputMapLen = numKeyPerModifier * 8;
+ :
+ : for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
+ : if ((pDev->coreEvents || pDev == inputInfo.keyboard) && pDev->key) {
+ : for (i = 0; i < inputMapLen; i++) {
+ : /* Check that all the new modifiers fall within the advertised
+ : * keycode range, and are okay with the DDX. */
+ : if (inputMap[i] && ((inputMap[i] < pDev->key->curKeySyms.minKeyCode ||
+ : inputMap[i] > pDev->key->curKeySyms.maxKeyCode) ||
+ : !LegalModifier(inputMap[i], pDev))) {
+ : client->errorValue = inputMap[i];
+ : return BadValue;
+ : }
+ : }
+ :
+ : if (!XaceHook(XACE_DEVICE_ACCESS, client, pDev, TRUE))
+ : return BadAccess;
+ :
+ : /* None of the modifiers (old or new) may be down while we change
+ : * the map. */
+ : if (!AllModifierKeysAreUp(pDev, pDev->key->modifierKeyMap,
+ : pDev->key->maxKeysPerModifier,
+ : inputMap, numKeyPerModifier) ||
+ : !AllModifierKeysAreUp(pDev, inputMap, numKeyPerModifier,
+ : pDev->key->modifierKeyMap,
+ : pDev->key->maxKeysPerModifier)) {
+ : return MappingBusy;
+ : }
+ : }
+ : }
+ :
+ : for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
+ :
+ : if ((pDev->coreEvents || pDev == inputInfo.keyboard) && pDev->key) {
+ : bzero(pDev->key->modifierMap, MAP_LENGTH);
+ :
+ : /* Annoyingly, we lack a modifierKeyMap size, so we have to just free
+ : * and re-alloc it every time. */
+ : if (pDev->key->modifierKeyMap)
+ : xfree(pDev->key->modifierKeyMap);
+ :
+ : if (inputMapLen) {
+ : pDev->key->modifierKeyMap = (KeyCode *) xalloc(inputMapLen);
+ : if (!pDev->key->modifierKeyMap)
+ : return BadAlloc;
+ :
+ : memcpy(pDev->key->modifierKeyMap, inputMap, inputMapLen);
+ : pDev->key->maxKeysPerModifier = numKeyPerModifier;
+ :
+ : for (i = 0; i < inputMapLen; i++) {
+ : if (inputMap[i]) {
+ : pDev->key->modifierMap[inputMap[i]] |=
+ : (1 << (((unsigned int)i) / numKeyPerModifier));
+ : }
+ : }
+ : }
+ : else {
+ : pDev->key->modifierKeyMap = NULL;
+ : pDev->key->maxKeysPerModifier = 0;
+ : }
+ : }
+ : }
+ :
+ : return Success;
+ :}
+ :
+ :int
+ :ProcSetModifierMapping(ClientPtr client)
+ :{
+ : xSetModifierMappingReply rep;
+ : REQUEST(xSetModifierMappingReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xSetModifierMappingReq);
+ :
+ : if (client->req_len != ((stuff->numKeyPerModifier << 1) +
+ : (sizeof (xSetModifierMappingReq) >> 2)))
+ : return BadLength;
+ :
+ : rep.type = X_Reply;
+ : rep.length = 0;
+ : rep.sequenceNumber = client->sequence;
+ :
+ : rep.success = DoSetModifierMapping(client, (KeyCode *)&stuff[1],
+ : stuff->numKeyPerModifier);
+ :
+ : /* FIXME: Send mapping notifies for all the extended devices as well. */
+ : SendMappingNotify(MappingModifier, 0, 0, client);
+ : WriteReplyToClient(client, sizeof(xSetModifierMappingReply), &rep);
+ : return client->noClientException;
+ :}
+ :
+ :int
+ :ProcGetModifierMapping(ClientPtr client)
+ :{
+ : xGetModifierMappingReply rep;
+ : KeyClassPtr keyc = inputInfo.keyboard->key;
+ :
+ : REQUEST_SIZE_MATCH(xReq);
+ : rep.type = X_Reply;
+ : rep.numKeyPerModifier = keyc->maxKeysPerModifier;
+ : rep.sequenceNumber = client->sequence;
+ : /* length counts 4 byte quantities - there are 8 modifiers 1 byte big */
+ : rep.length = keyc->maxKeysPerModifier << 1;
+ :
+ : WriteReplyToClient(client, sizeof(xGetModifierMappingReply), &rep);
+ :
+ : /* Use the (modified by DDX) map that SetModifierMapping passed in */
+ : (void)WriteToClient(client, (int)(keyc->maxKeysPerModifier << 3),
+ : (char *)keyc->modifierKeyMap);
+ : return client->noClientException;
+ :}
+ :
+ :int
+ :ProcChangeKeyboardMapping(ClientPtr client)
+ :{
+ : REQUEST(xChangeKeyboardMappingReq);
+ : unsigned len;
+ : KeySymsRec keysyms;
+ : KeySymsPtr curKeySyms = &inputInfo.keyboard->key->curKeySyms;
+ : DeviceIntPtr pDev = NULL;
+ : REQUEST_AT_LEAST_SIZE(xChangeKeyboardMappingReq);
+ :
+ : len = client->req_len - (sizeof(xChangeKeyboardMappingReq) >> 2);
+ : if (len != (stuff->keyCodes * stuff->keySymsPerKeyCode))
+ : return BadLength;
+ :
+ : if ((stuff->firstKeyCode < curKeySyms->minKeyCode) ||
+ : (stuff->firstKeyCode > curKeySyms->maxKeyCode)) {
+ : client->errorValue = stuff->firstKeyCode;
+ : return BadValue;
+ :
+ : }
+ : if (((unsigned)(stuff->firstKeyCode + stuff->keyCodes - 1) >
+ : curKeySyms->maxKeyCode) || (stuff->keySymsPerKeyCode == 0)) {
+ : client->errorValue = stuff->keySymsPerKeyCode;
+ : return BadValue;
+ : }
+ :
+ : for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
+ : if ((pDev->coreEvents || pDev == inputInfo.keyboard) && pDev->key) {
+ : if (!XaceHook(XACE_DEVICE_ACCESS, client, pDev, TRUE))
+ : return BadAccess;
+ : }
+ : }
+ :
+ : keysyms.minKeyCode = stuff->firstKeyCode;
+ : keysyms.maxKeyCode = stuff->firstKeyCode + stuff->keyCodes - 1;
+ : keysyms.mapWidth = stuff->keySymsPerKeyCode;
+ : keysyms.map = (KeySym *)&stuff[1];
+ : for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
+ : if ((pDev->coreEvents || pDev == inputInfo.keyboard) && pDev->key) {
+ : if (!SetKeySymsMap(&pDev->key->curKeySyms, &keysyms))
+ : return BadAlloc;
+ : }
+ : }
+ :
+ : /* FIXME: Send mapping notifies for all the extended devices as well. */
+ : SendMappingNotify(MappingKeyboard, stuff->firstKeyCode, stuff->keyCodes,
+ : client);
+ : return client->noClientException;
+ :}
+ :
+ :static int
+ :DoSetPointerMapping(DeviceIntPtr device, BYTE *map, int n)
+ :{
+ : int i = 0;
+ : DeviceIntPtr dev = NULL;
+ :
+ : if (!device || !device->button)
+ : return BadDevice;
+ :
+ : for (dev = inputInfo.devices; dev; dev = dev->next) {
+ : if ((dev->coreEvents || dev == inputInfo.pointer) && dev->button) {
+ : for (i = 0; i < n; i++) {
+ : if ((device->button->map[i + 1] != map[i]) &&
+ : BitIsOn(device->button->down, i + 1)) {
+ : return MappingBusy;
+ : }
+ : }
+ : }
+ : }
+ :
+ : for (dev = inputInfo.devices; dev; dev = dev->next) {
+ : if ((dev->coreEvents || dev == inputInfo.pointer) && dev->button) {
+ : for (i = 0; i < n; i++)
+ : dev->button->map[i + 1] = map[i];
+ : }
+ : }
+ :
+ : return Success;
+ :}
+ :
+ :int
+ :ProcSetPointerMapping(ClientPtr client)
+ :{
+ : REQUEST(xSetPointerMappingReq);
+ : BYTE *map;
+ : int ret;
+ : xSetPointerMappingReply rep;
+ :
+ : REQUEST_AT_LEAST_SIZE(xSetPointerMappingReq);
+ : if (client->req_len != (sizeof(xSetPointerMappingReq)+stuff->nElts+3) >> 2)
+ : return BadLength;
+ : rep.type = X_Reply;
+ : rep.length = 0;
+ : rep.sequenceNumber = client->sequence;
+ : rep.success = MappingSuccess;
+ : map = (BYTE *)&stuff[1];
+ :
+ : /* So we're bounded here by the number of core buttons. This check
+ : * probably wants disabling through XFixes. */
+ : if (stuff->nElts != inputInfo.pointer->button->numButtons) {
+ : client->errorValue = stuff->nElts;
+ : return BadValue;
+ : }
+ : if (BadDeviceMap(&map[0], (int)stuff->nElts, 1, 255, &client->errorValue))
+ : return BadValue;
+ :
+ : ret = DoSetPointerMapping(inputInfo.pointer, map, stuff->nElts);
+ : if (ret != Success) {
+ : rep.success = ret;
+ : WriteReplyToClient(client, sizeof(xSetPointerMappingReply), &rep);
+ : return Success;
+ : }
+ :
+ : /* FIXME: Send mapping notifies for all the extended devices as well. */
+ : SendMappingNotify(MappingPointer, 0, 0, client);
+ : WriteReplyToClient(client, sizeof(xSetPointerMappingReply), &rep);
+ : return Success;
+ :}
+ :
+ :int
+ :ProcGetKeyboardMapping(ClientPtr client)
+ :{
+ : xGetKeyboardMappingReply rep;
+ : REQUEST(xGetKeyboardMappingReq);
+ : KeySymsPtr curKeySyms = &inputInfo.keyboard->key->curKeySyms;
+ :
+ : REQUEST_SIZE_MATCH(xGetKeyboardMappingReq);
+ :
+ : if ((stuff->firstKeyCode < curKeySyms->minKeyCode) ||
+ : (stuff->firstKeyCode > curKeySyms->maxKeyCode)) {
+ : client->errorValue = stuff->firstKeyCode;
+ : return BadValue;
+ : }
+ : if (stuff->firstKeyCode + stuff->count >
+ : (unsigned)(curKeySyms->maxKeyCode + 1)) {
+ : client->errorValue = stuff->count;
+ : return BadValue;
+ : }
+ :
+ : rep.type = X_Reply;
+ : rep.sequenceNumber = client->sequence;
+ : rep.keySymsPerKeyCode = curKeySyms->mapWidth;
+ : /* length is a count of 4 byte quantities and KeySyms are 4 bytes */
+ : rep.length = (curKeySyms->mapWidth * stuff->count);
+ : WriteReplyToClient(client, sizeof(xGetKeyboardMappingReply), &rep);
+ : client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write;
+ : WriteSwappedDataToClient(
+ : client,
+ : curKeySyms->mapWidth * stuff->count * sizeof(KeySym),
+ : &curKeySyms->map[(stuff->firstKeyCode - curKeySyms->minKeyCode) *
+ : curKeySyms->mapWidth]);
+ :
+ : return client->noClientException;
+ :}
+ :
+ :int
+ :ProcGetPointerMapping(ClientPtr client)
+ :{
+ : xGetPointerMappingReply rep;
+ : ButtonClassPtr butc = inputInfo.pointer->button;
+ :
+ : REQUEST_SIZE_MATCH(xReq);
+ : rep.type = X_Reply;
+ : rep.sequenceNumber = client->sequence;
+ : rep.nElts = butc->numButtons;
+ : rep.length = ((unsigned)rep.nElts + (4-1))/4;
+ : WriteReplyToClient(client, sizeof(xGetPointerMappingReply), &rep);
+ : (void)WriteToClient(client, (int)rep.nElts, (char *)&butc->map[1]);
+ : return Success;
+ :}
+ :
+ :void
+ :NoteLedState(DeviceIntPtr keybd, int led, Bool on)
+ :{
+ : KeybdCtrl *ctrl = &keybd->kbdfeed->ctrl;
+ : if (on)
+ : ctrl->leds |= ((Leds)1 << (led - 1));
+ : else
+ : ctrl->leds &= ~((Leds)1 << (led - 1));
+ :}
+ :
+ :_X_EXPORT int
+ :Ones(unsigned long mask) /* HACKMEM 169 */
+ 3 0.0033 :{ /* Ones total: 9 0.0098 */
+ : unsigned long y;
+ :
+ : y = (mask >> 1) &033333333333;
+ 4 0.0044 : y = mask - y - ((y >>1) & 033333333333);
+ : return (((y + (y >> 3)) & 030707070707) % 077);
+ 2 0.0022 :}
+ :
+ :static int
+ :DoChangeKeyboardControl (ClientPtr client, DeviceIntPtr keybd, XID *vlist,
+ : BITS32 vmask)
+ :{
+ :#define DO_ALL (-1)
+ : KeybdCtrl ctrl;
+ : int t;
+ : int led = DO_ALL;
+ : int key = DO_ALL;
+ : BITS32 index2;
+ : int mask = vmask, i;
+ :
+ : ctrl = keybd->kbdfeed->ctrl;
+ : while (vmask) {
+ : index2 = (BITS32) lowbit (vmask);
+ : vmask &= ~index2;
+ : switch (index2) {
+ : case KBKeyClickPercent:
+ : t = (INT8)*vlist;
+ : vlist++;
+ : if (t == -1) {
+ : t = defaultKeyboardControl.click;
+ : }
+ : else if (t < 0 || t > 100) {
+ : client->errorValue = t;
+ : return BadValue;
+ : }
+ : ctrl.click = t;
+ : break;
+ : case KBBellPercent:
+ : t = (INT8)*vlist;
+ : vlist++;
+ : if (t == -1) {
+ : t = defaultKeyboardControl.bell;
+ : }
+ : else if (t < 0 || t > 100) {
+ : client->errorValue = t;
+ : return BadValue;
+ : }
+ : ctrl.bell = t;
+ : break;
+ : case KBBellPitch:
+ : t = (INT16)*vlist;
+ : vlist++;
+ : if (t == -1) {
+ : t = defaultKeyboardControl.bell_pitch;
+ : }
+ : else if (t < 0) {
+ : client->errorValue = t;
+ : return BadValue;
+ : }
+ : ctrl.bell_pitch = t;
+ : break;
+ : case KBBellDuration:
+ : t = (INT16)*vlist;
+ : vlist++;
+ : if (t == -1)
+ : t = defaultKeyboardControl.bell_duration;
+ : else if (t < 0) {
+ : client->errorValue = t;
+ : return BadValue;
+ : }
+ : ctrl.bell_duration = t;
+ : break;
+ : case KBLed:
+ : led = (CARD8)*vlist;
+ : vlist++;
+ : if (led < 1 || led > 32) {
+ : client->errorValue = led;
+ : return BadValue;
+ : }
+ : if (!(mask & KBLedMode))
+ : return BadMatch;
+ : break;
+ : case KBLedMode:
+ : t = (CARD8)*vlist;
+ : vlist++;
+ : if (t == LedModeOff) {
+ : if (led == DO_ALL)
+ : ctrl.leds = 0x0;
+ : else
+ : ctrl.leds &= ~(((Leds)(1)) << (led - 1));
+ : }
+ : else if (t == LedModeOn) {
+ : if (led == DO_ALL)
+ : ctrl.leds = ~0L;
+ : else
+ : ctrl.leds |= (((Leds)(1)) << (led - 1));
+ : }
+ : else {
+ : client->errorValue = t;
+ : return BadValue;
+ : }
+ :#ifdef XKB
+ : if (!noXkbExtension) {
+ : XkbEventCauseRec cause;
+ : XkbSetCauseCoreReq(&cause,X_ChangeKeyboardControl,client);
+ : XkbSetIndicators(keybd,((led == DO_ALL) ? ~0L : (1L<<(led-1))),
+ : ctrl.leds, &cause);
+ : ctrl.leds = keybd->kbdfeed->ctrl.leds;
+ : }
+ :#endif
+ : break;
+ : case KBKey:
+ : key = (KeyCode)*vlist;
+ : vlist++;
+ : if ((KeyCode)key < inputInfo.keyboard->key->curKeySyms.minKeyCode ||
+ : (KeyCode)key > inputInfo.keyboard->key->curKeySyms.maxKeyCode) {
+ : client->errorValue = key;
+ : return BadValue;
+ : }
+ : if (!(mask & KBAutoRepeatMode))
+ : return BadMatch;
+ : break;
+ : case KBAutoRepeatMode:
+ : i = (key >> 3);
+ : mask = (1 << (key & 7));
+ : t = (CARD8)*vlist;
+ : vlist++;
+ :#ifdef XKB
+ : if (!noXkbExtension && key != DO_ALL)
+ : XkbDisableComputedAutoRepeats(keybd,key);
+ :#endif
+ : if (t == AutoRepeatModeOff) {
+ : if (key == DO_ALL)
+ : ctrl.autoRepeat = FALSE;
+ : else
+ : ctrl.autoRepeats[i] &= ~mask;
+ : }
+ : else if (t == AutoRepeatModeOn) {
+ : if (key == DO_ALL)
+ : ctrl.autoRepeat = TRUE;
+ : else
+ : ctrl.autoRepeats[i] |= mask;
+ : }
+ : else if (t == AutoRepeatModeDefault) {
+ : if (key == DO_ALL)
+ : ctrl.autoRepeat = defaultKeyboardControl.autoRepeat;
+ : else
+ : ctrl.autoRepeats[i] =
+ : (ctrl.autoRepeats[i] & ~mask) |
+ : (defaultKeyboardControl.autoRepeats[i] & mask);
+ : }
+ : else {
+ : client->errorValue = t;
+ : return BadValue;
+ : }
+ : break;
+ : default:
+ : client->errorValue = mask;
+ : return BadValue;
+ : }
+ : }
+ : keybd->kbdfeed->ctrl = ctrl;
+ :
+ :#ifdef XKB
+ : /* The XKB RepeatKeys control and core protocol global autorepeat */
+ : /* value are linked */
+ : if (!noXkbExtension)
+ : XkbSetRepeatKeys(keybd, key, keybd->kbdfeed->ctrl.autoRepeat);
+ : else
+ :#endif
+ : (*keybd->kbdfeed->CtrlProc)(keybd, &keybd->kbdfeed->ctrl);
+ :
+ : return Success;
+ :
+ :#undef DO_ALL
+ :}
+ :
+ :int
+ :ProcChangeKeyboardControl (ClientPtr client)
+ :{
+ : XID *vlist;
+ : BITS32 vmask;
+ : int ret = Success, error = Success;
+ : DeviceIntPtr pDev = NULL;
+ : REQUEST(xChangeKeyboardControlReq);
+ :
+ : REQUEST_AT_LEAST_SIZE(xChangeKeyboardControlReq);
+ :
+ : vmask = stuff->mask;
+ : vlist = (XID *)&stuff[1];
+ :
+ : if (client->req_len != (sizeof(xChangeKeyboardControlReq)>>2)+Ones(vmask))
+ : return BadLength;
+ :
+ : for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
+ : if ((pDev->coreEvents || pDev == inputInfo.keyboard) &&
+ : pDev->kbdfeed && pDev->kbdfeed->CtrlProc) {
+ : if (!XaceHook(XACE_DEVICE_ACCESS, client, pDev, TRUE))
+ : return BadAccess;
+ : }
+ : }
+ :
+ : for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
+ : if ((pDev->coreEvents || pDev == inputInfo.keyboard) &&
+ : pDev->kbdfeed && pDev->kbdfeed->CtrlProc) {
+ : ret = DoChangeKeyboardControl(client, pDev, vlist, vmask);
+ : if (ret != Success)
+ : error = ret;
+ : }
+ : }
+ :
+ : return error;
+ :}
+ :
+ :int
+ :ProcGetKeyboardControl (ClientPtr client)
+ :{
+ : int i;
+ : KeybdCtrl *ctrl = &inputInfo.keyboard->kbdfeed->ctrl;
+ : xGetKeyboardControlReply rep;
+ :
+ : REQUEST_SIZE_MATCH(xReq);
+ : rep.type = X_Reply;
+ : rep.length = 5;
+ : rep.sequenceNumber = client->sequence;
+ : rep.globalAutoRepeat = ctrl->autoRepeat;
+ : rep.keyClickPercent = ctrl->click;
+ : rep.bellPercent = ctrl->bell;
+ : rep.bellPitch = ctrl->bell_pitch;
+ : rep.bellDuration = ctrl->bell_duration;
+ : rep.ledMask = ctrl->leds;
+ : for (i = 0; i < 32; i++)
+ : rep.map[i] = ctrl->autoRepeats[i];
+ : WriteReplyToClient(client, sizeof(xGetKeyboardControlReply), &rep);
+ : return Success;
+ :}
+ :
+ :int
+ :ProcBell(ClientPtr client)
+ :{
+ : DeviceIntPtr keybd = inputInfo.keyboard;
+ : int base = keybd->kbdfeed->ctrl.bell;
+ : int newpercent;
+ : REQUEST(xBellReq);
+ : REQUEST_SIZE_MATCH(xBellReq);
+ :
+ : if (!keybd->kbdfeed->BellProc)
+ : return BadDevice;
+ :
+ : if (stuff->percent < -100 || stuff->percent > 100) {
+ : client->errorValue = stuff->percent;
+ : return BadValue;
+ : }
+ :
+ : newpercent = (base * stuff->percent) / 100;
+ : if (stuff->percent < 0)
+ : newpercent = base + newpercent;
+ : else
+ : newpercent = base - newpercent + stuff->percent;
+ :
+ : for (keybd = inputInfo.devices; keybd; keybd = keybd->next) {
+ : if ((keybd->coreEvents || keybd == inputInfo.keyboard) &&
+ : keybd->kbdfeed && keybd->kbdfeed->BellProc) {
+ :#ifdef XKB
+ : if (!noXkbExtension)
+ : XkbHandleBell(FALSE, FALSE, keybd, newpercent,
+ : &keybd->kbdfeed->ctrl, 0, None, NULL, client);
+ : else
+ :#endif
+ : (*keybd->kbdfeed->BellProc)(newpercent, keybd,
+ : &keybd->kbdfeed->ctrl, 0);
+ : }
+ : }
+ :
+ : return Success;
+ :}
+ :
+ :int
+ :ProcChangePointerControl(ClientPtr client)
+ :{
+ : DeviceIntPtr mouse = inputInfo.pointer;
+ : PtrCtrl ctrl; /* might get BadValue part way through */
+ : REQUEST(xChangePointerControlReq);
+ :
+ : REQUEST_SIZE_MATCH(xChangePointerControlReq);
+ :
+ : if (!mouse->ptrfeed->CtrlProc)
+ : return BadDevice;
+ :
+ : ctrl = mouse->ptrfeed->ctrl;
+ : if ((stuff->doAccel != xTrue) && (stuff->doAccel != xFalse)) {
+ : client->errorValue = stuff->doAccel;
+ : return(BadValue);
+ : }
+ : if ((stuff->doThresh != xTrue) && (stuff->doThresh != xFalse)) {
+ : client->errorValue = stuff->doThresh;
+ : return(BadValue);
+ : }
+ : if (stuff->doAccel) {
+ : if (stuff->accelNum == -1) {
+ : ctrl.num = defaultPointerControl.num;
+ : }
+ : else if (stuff->accelNum < 0) {
+ : client->errorValue = stuff->accelNum;
+ : return BadValue;
+ : }
+ : else {
+ : ctrl.num = stuff->accelNum;
+ : }
+ :
+ : if (stuff->accelDenum == -1) {
+ : ctrl.den = defaultPointerControl.den;
+ : }
+ : else if (stuff->accelDenum <= 0) {
+ : client->errorValue = stuff->accelDenum;
+ : return BadValue;
+ : }
+ : else {
+ : ctrl.den = stuff->accelDenum;
+ : }
+ : }
+ : if (stuff->doThresh) {
+ : if (stuff->threshold == -1) {
+ : ctrl.threshold = defaultPointerControl.threshold;
+ : }
+ : else if (stuff->threshold < 0) {
+ : client->errorValue = stuff->threshold;
+ : return BadValue;
+ : }
+ : else {
+ : ctrl.threshold = stuff->threshold;
+ : }
+ : }
+ :
+ :
+ : for (mouse = inputInfo.devices; mouse; mouse = mouse->next) {
+ : if ((mouse->coreEvents || mouse == inputInfo.pointer) &&
+ : mouse->ptrfeed && mouse->ptrfeed->CtrlProc) {
+ : mouse->ptrfeed->ctrl = ctrl;
+ : (*mouse->ptrfeed->CtrlProc)(mouse, &mouse->ptrfeed->ctrl);
+ : }
+ : }
+ :
+ : return Success;
+ :}
+ :
+ :int
+ :ProcGetPointerControl(ClientPtr client)
+ :{
+ : PtrCtrl *ctrl = &inputInfo.pointer->ptrfeed->ctrl;
+ : xGetPointerControlReply rep;
+ :
+ : REQUEST_SIZE_MATCH(xReq);
+ : rep.type = X_Reply;
+ : rep.length = 0;
+ : rep.sequenceNumber = client->sequence;
+ : rep.threshold = ctrl->threshold;
+ : rep.accelNumerator = ctrl->num;
+ : rep.accelDenominator = ctrl->den;
+ : WriteReplyToClient(client, sizeof(xGenericReply), &rep);
+ : return Success;
+ :}
+ :
+ :void
+ :MaybeStopHint(DeviceIntPtr dev, ClientPtr client)
+ :{
+ : GrabPtr grab = dev->grab;
+ :
+ : if ((grab && SameClient(grab, client) &&
+ : ((grab->eventMask & PointerMotionHintMask) ||
+ : (grab->ownerEvents &&
+ : (EventMaskForClient(dev->valuator->motionHintWindow, client) &
+ : PointerMotionHintMask)))) ||
+ : (!grab &&
+ : (EventMaskForClient(dev->valuator->motionHintWindow, client) &
+ : PointerMotionHintMask)))
+ : dev->valuator->motionHintWindow = NullWindow;
+ :}
+ :
+ :int
+ :ProcGetMotionEvents(ClientPtr client)
+ :{
+ : WindowPtr pWin;
+ : xTimecoord * coords = (xTimecoord *) NULL;
+ : xGetMotionEventsReply rep;
+ : int i, count, xmin, xmax, ymin, ymax, rc;
+ : unsigned long nEvents;
+ : DeviceIntPtr mouse = inputInfo.pointer;
+ : TimeStamp start, stop;
+ : REQUEST(xGetMotionEventsReq);
+ :
+ : REQUEST_SIZE_MATCH(xGetMotionEventsReq);
+ : rc = dixLookupWindow(&pWin, stuff->window, client, DixUnknownAccess);
+ : if (rc != Success)
+ : return rc;
+ : if (mouse->valuator->motionHintWindow)
+ : MaybeStopHint(mouse, client);
+ : rep.type = X_Reply;
+ : rep.sequenceNumber = client->sequence;
+ : nEvents = 0;
+ : start = ClientTimeToServerTime(stuff->start);
+ : stop = ClientTimeToServerTime(stuff->stop);
+ : if ((CompareTimeStamps(start, stop) != LATER) &&
+ : (CompareTimeStamps(start, currentTime) != LATER) &&
+ : mouse->valuator->numMotionEvents)
+ : {
+ : if (CompareTimeStamps(stop, currentTime) == LATER)
+ : stop = currentTime;
+ : coords = (xTimecoord *)ALLOCATE_LOCAL(mouse->valuator->numMotionEvents
+ : * sizeof(xTimecoord));
+ : if (!coords)
+ : return BadAlloc;
+ : count = (*mouse->valuator->GetMotionProc) (mouse, coords,
+ : start.milliseconds,
+ : stop.milliseconds,
+ : pWin->drawable.pScreen);
+ : xmin = pWin->drawable.x - wBorderWidth (pWin);
+ : xmax = pWin->drawable.x + (int)pWin->drawable.width +
+ : wBorderWidth (pWin);
+ : ymin = pWin->drawable.y - wBorderWidth (pWin);
+ : ymax = pWin->drawable.y + (int)pWin->drawable.height +
+ : wBorderWidth (pWin);
+ : for (i = 0; i < count; i++)
+ : if ((xmin <= coords[i].x) && (coords[i].x < xmax) &&
+ : (ymin <= coords[i].y) && (coords[i].y < ymax))
+ : {
+ : coords[nEvents].time = coords[i].time;
+ : coords[nEvents].x = coords[i].x - pWin->drawable.x;
+ : coords[nEvents].y = coords[i].y - pWin->drawable.y;
+ : nEvents++;
+ : }
+ : }
+ : rep.length = nEvents * (sizeof(xTimecoord) >> 2);
+ : rep.nEvents = nEvents;
+ : WriteReplyToClient(client, sizeof(xGetMotionEventsReply), &rep);
+ : if (nEvents)
+ : {
+ : client->pSwapReplyFunc = (ReplySwapPtr) SwapTimeCoordWrite;
+ : WriteSwappedDataToClient(client, nEvents * sizeof(xTimecoord),
+ : (char *)coords);
+ : }
+ : if (coords)
+ : DEALLOCATE_LOCAL(coords);
+ : return Success;
+ :}
+ :
+ :int
+ :ProcQueryKeymap(ClientPtr client)
+ :{
+ : xQueryKeymapReply rep;
+ : int i;
+ : CARD8 *down = inputInfo.keyboard->key->down;
+ :
+ : REQUEST_SIZE_MATCH(xReq);
+ : rep.type = X_Reply;
+ : rep.sequenceNumber = client->sequence;
+ : rep.length = 2;
+ :
+ : if (XaceHook(XACE_DEVICE_ACCESS, client, inputInfo.keyboard, TRUE))
+ : for (i = 0; i<32; i++)
+ : rep.map[i] = down[i];
+ : else
+ : bzero((char *)&rep.map[0], 32);
+ :
+ : WriteReplyToClient(client, sizeof(xQueryKeymapReply), &rep);
+ : return Success;
+ :}
+/*
+ * Total samples for file : "xf86dri.c"
+ *
+ * 8 0.0087
+ */
+
+<credited to line zero> 8 0.0087 :
+ /* __i686.get_pc_thunk.cx total: 8 0.0087 */
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/dix/extension.c"
+ *
+ * 5 0.0054
+ */
+
+
+ :/***********************************************************
+ :
+ :Copyright 1987, 1998 The Open Group
+ :
+ :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.
+ :
+ :The above copyright notice and this permission notice shall be included in
+ :all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ :IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ :FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ :OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ :AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ :CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of The Open Group shall not be
+ :used in advertising or otherwise to promote the sale, use or other dealings
+ :in this Software without prior written authorization from The Open Group.
+ :
+ :
+ :Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+ :
+ : All Rights Reserved
+ :
+ :Permission to use, copy, modify, and distribute this software and its
+ :documentation for any purpose and without fee is hereby granted,
+ :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 Digital not be
+ :used in advertising or publicity pertaining to distribution of the
+ :software without specific, written prior permission.
+ :
+ :DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ :ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ :DIGITAL 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.
+ :
+ :******************************************************************/
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include <X11/X.h>
+ :#define NEED_EVENTS
+ :#define NEED_REPLIES
+ :#include <X11/Xproto.h>
+ :#include "misc.h"
+ :#include "dixstruct.h"
+ :#include "extnsionst.h"
+ :#include "gcstruct.h"
+ :#include "scrnintstr.h"
+ :#include "dispatch.h"
+ :#include "xace.h"
+ :
+ :#define EXTENSION_BASE 128
+ :#define EXTENSION_EVENT_BASE 64
+ :#define LAST_EVENT 128
+ :#define LAST_ERROR 255
+ :
+ :static ExtensionEntry **extensions = (ExtensionEntry **)NULL;
+ :
+ :int lastEvent = EXTENSION_EVENT_BASE;
+ :static int lastError = FirstExtensionError;
+ :static unsigned int NumExtensions = 0;
+ :
+ :extern int extensionPrivateLen;
+ :extern unsigned *extensionPrivateSizes;
+ :extern unsigned totalExtensionSize;
+ :
+ :static void
+ :InitExtensionPrivates(ExtensionEntry *ext)
+ :{
+ : char *ptr;
+ : DevUnion *ppriv;
+ : unsigned *sizes;
+ : unsigned size;
+ : int i;
+ :
+ : if (totalExtensionSize == sizeof(ExtensionEntry))
+ : ppriv = (DevUnion *)NULL;
+ : else
+ : ppriv = (DevUnion *)(ext + 1);
+ :
+ : ext->devPrivates = ppriv;
+ : sizes = extensionPrivateSizes;
+ : ptr = (char *)(ppriv + extensionPrivateLen);
+ : for (i = extensionPrivateLen; --i >= 0; ppriv++, sizes++)
+ : {
+ : if ( (size = *sizes) )
+ : {
+ : ppriv->ptr = (pointer)ptr;
+ : ptr += size;
+ : }
+ : else
+ : ppriv->ptr = (pointer)NULL;
+ : }
+ :}
+ :
+ :_X_EXPORT ExtensionEntry *
+ :AddExtension(char *name, int NumEvents, int NumErrors,
+ : int (*MainProc)(ClientPtr c1),
+ : int (*SwappedMainProc)(ClientPtr c2),
+ : void (*CloseDownProc)(ExtensionEntry *e),
+ : unsigned short (*MinorOpcodeProc)(ClientPtr c3))
+ :{
+ : int i;
+ : ExtensionEntry *ext, **newexts;
+ :
+ : if (!MainProc || !SwappedMainProc || !CloseDownProc || !MinorOpcodeProc)
+ : return((ExtensionEntry *) NULL);
+ : if ((lastEvent + NumEvents > LAST_EVENT) ||
+ : (unsigned)(lastError + NumErrors > LAST_ERROR))
+ : return((ExtensionEntry *) NULL);
+ :
+ : ext = (ExtensionEntry *) xalloc(totalExtensionSize);
+ : if (!ext)
+ : return((ExtensionEntry *) NULL);
+ : bzero(ext, totalExtensionSize);
+ : InitExtensionPrivates(ext);
+ : ext->name = (char *)xalloc(strlen(name) + 1);
+ : ext->num_aliases = 0;
+ : ext->aliases = (char **)NULL;
+ : if (!ext->name)
+ : {
+ : xfree(ext);
+ : return((ExtensionEntry *) NULL);
+ : }
+ : strcpy(ext->name, name);
+ : i = NumExtensions;
+ : newexts = (ExtensionEntry **) xrealloc(extensions,
+ : (i + 1) * sizeof(ExtensionEntry *));
+ : if (!newexts)
+ : {
+ : xfree(ext->name);
+ : xfree(ext);
+ : return((ExtensionEntry *) NULL);
+ : }
+ : NumExtensions++;
+ : extensions = newexts;
+ : extensions[i] = ext;
+ : ext->index = i;
+ : ext->base = i + EXTENSION_BASE;
+ : ext->CloseDown = CloseDownProc;
+ : ext->MinorOpcode = MinorOpcodeProc;
+ : ProcVector[i + EXTENSION_BASE] = MainProc;
+ : SwappedProcVector[i + EXTENSION_BASE] = SwappedMainProc;
+ : if (NumEvents)
+ : {
+ : ext->eventBase = lastEvent;
+ : ext->eventLast = lastEvent + NumEvents;
+ : lastEvent += NumEvents;
+ : }
+ : else
+ : {
+ : ext->eventBase = 0;
+ : ext->eventLast = 0;
+ : }
+ : if (NumErrors)
+ : {
+ : ext->errorBase = lastError;
+ : ext->errorLast = lastError + NumErrors;
+ : lastError += NumErrors;
+ : }
+ : else
+ : {
+ : ext->errorBase = 0;
+ : ext->errorLast = 0;
+ : }
+ :
+ : return(ext);
+ :}
+ :
+ :_X_EXPORT Bool AddExtensionAlias(char *alias, ExtensionEntry *ext)
+ :{
+ : char *name;
+ : char **aliases;
+ :
+ : aliases = (char **)xrealloc(ext->aliases,
+ : (ext->num_aliases + 1) * sizeof(char *));
+ : if (!aliases)
+ : return FALSE;
+ : ext->aliases = aliases;
+ : name = (char *)xalloc(strlen(alias) + 1);
+ : if (!name)
+ : return FALSE;
+ : strcpy(name, alias);
+ : ext->aliases[ext->num_aliases] = name;
+ : ext->num_aliases++;
+ : return TRUE;
+ :}
+ :
+ :static int
+ :FindExtension(char *extname, int len)
+ :{
+ : int i, j;
+ :
+ : for (i=0; i<NumExtensions; i++)
+ : {
+ : if ((strlen(extensions[i]->name) == len) &&
+ : !strncmp(extname, extensions[i]->name, len))
+ : break;
+ : for (j = extensions[i]->num_aliases; --j >= 0;)
+ : {
+ : if ((strlen(extensions[i]->aliases[j]) == len) &&
+ : !strncmp(extname, extensions[i]->aliases[j], len))
+ : break;
+ : }
+ : if (j >= 0) break;
+ : }
+ : return ((i == NumExtensions) ? -1 : i);
+ :}
+ :
+ :/*
+ : * CheckExtension returns the extensions[] entry for the requested
+ : * extension name. Maybe this could just return a Bool instead?
+ : */
+ :_X_EXPORT ExtensionEntry *
+ :CheckExtension(const char *extname)
+ :{
+ : int n;
+ :
+ : n = FindExtension((char*)extname, strlen(extname));
+ : if (n != -1)
+ : return extensions[n];
+ : else
+ : return NULL;
+ :}
+ :
+ :/*
+ : * Added as part of Xace.
+ : */
+ :ExtensionEntry *
+ :GetExtensionEntry(int major)
+ 5 0.0054 :{ /* GetExtensionEntry total: 5 0.0054 */
+ : if (major < EXTENSION_BASE)
+ : return NULL;
+ : major -= EXTENSION_BASE;
+ : if (major >= NumExtensions)
+ : return NULL;
+ : return extensions[major];
+ :}
+ :
+ :_X_EXPORT void
+ :DeclareExtensionSecurity(char *extname, Bool secure)
+ :{
+ : int i = FindExtension(extname, strlen(extname));
+ : if (i >= 0)
+ : XaceHook(XACE_DECLARE_EXT_SECURE, extensions[i], secure);
+ :}
+ :
+ :_X_EXPORT unsigned short
+ :StandardMinorOpcode(ClientPtr client)
+ :{
+ : return ((xReq *)client->requestBuffer)->data;
+ :}
+ :
+ :_X_EXPORT unsigned short
+ :MinorOpcodeOfRequest(ClientPtr client)
+ :{
+ : unsigned char major;
+ :
+ : major = ((xReq *)client->requestBuffer)->reqType;
+ : if (major < EXTENSION_BASE)
+ : return 0;
+ : major -= EXTENSION_BASE;
+ : if (major >= NumExtensions)
+ : return 0;
+ : return (*extensions[major]->MinorOpcode)(client);
+ :}
+ :
+ :void
+ :CloseDownExtensions(void)
+ :{
+ : int i,j;
+ :
+ : for (i = NumExtensions - 1; i >= 0; i--)
+ : {
+ : (* extensions[i]->CloseDown)(extensions[i]);
+ : NumExtensions = i;
+ : xfree(extensions[i]->name);
+ : for (j = extensions[i]->num_aliases; --j >= 0;)
+ : xfree(extensions[i]->aliases[j]);
+ : xfree(extensions[i]->aliases);
+ : xfree(extensions[i]);
+ : }
+ : xfree(extensions);
+ : extensions = (ExtensionEntry **)NULL;
+ : lastEvent = EXTENSION_EVENT_BASE;
+ : lastError = FirstExtensionError;
+ :}
+ :
+ :int
+ :ProcQueryExtension(ClientPtr client)
+ :{
+ : xQueryExtensionReply reply;
+ : int i;
+ : REQUEST(xQueryExtensionReq);
+ :
+ : REQUEST_FIXED_SIZE(xQueryExtensionReq, stuff->nbytes);
+ :
+ : reply.type = X_Reply;
+ : reply.length = 0;
+ : reply.major_opcode = 0;
+ : reply.sequenceNumber = client->sequence;
+ :
+ : if ( ! NumExtensions )
+ : reply.present = xFalse;
+ : else
+ : {
+ : i = FindExtension((char *)&stuff[1], stuff->nbytes);
+ : if (i < 0 || !XaceHook(XACE_EXT_ACCESS, client, extensions[i]))
+ : reply.present = xFalse;
+ : else
+ : {
+ : reply.present = xTrue;
+ : reply.major_opcode = extensions[i]->base;
+ : reply.first_event = extensions[i]->eventBase;
+ : reply.first_error = extensions[i]->errorBase;
+ : }
+ : }
+ : WriteReplyToClient(client, sizeof(xQueryExtensionReply), &reply);
+ : return(client->noClientException);
+ :}
+ :
+ :int
+ :ProcListExtensions(ClientPtr client)
+ :{
+ : xListExtensionsReply reply;
+ : char *bufptr, *buffer;
+ : int total_length = 0;
+ :
+ : REQUEST_SIZE_MATCH(xReq);
+ :
+ : reply.type = X_Reply;
+ : reply.nExtensions = 0;
+ : reply.length = 0;
+ : reply.sequenceNumber = client->sequence;
+ : buffer = NULL;
+ :
+ : if ( NumExtensions )
+ : {
+ : int i, j;
+ :
+ : for (i=0; i<NumExtensions; i++)
+ : {
+ : /* call callbacks to find out whether to show extension */
+ : if (!XaceHook(XACE_EXT_ACCESS, client, extensions[i]))
+ : continue;
+ :
+ : total_length += strlen(extensions[i]->name) + 1;
+ : reply.nExtensions += 1 + extensions[i]->num_aliases;
+ : for (j = extensions[i]->num_aliases; --j >= 0;)
+ : total_length += strlen(extensions[i]->aliases[j]) + 1;
+ : }
+ : reply.length = (total_length + 3) >> 2;
+ : buffer = bufptr = (char *)ALLOCATE_LOCAL(total_length);
+ : if (!buffer)
+ : return(BadAlloc);
+ : for (i=0; i<NumExtensions; i++)
+ : {
+ : int len;
+ : if (!XaceHook(XACE_EXT_ACCESS, client, extensions[i]))
+ : continue;
+ :
+ : *bufptr++ = len = strlen(extensions[i]->name);
+ : memmove(bufptr, extensions[i]->name, len);
+ : bufptr += len;
+ : for (j = extensions[i]->num_aliases; --j >= 0;)
+ : {
+ : *bufptr++ = len = strlen(extensions[i]->aliases[j]);
+ : memmove(bufptr, extensions[i]->aliases[j], len);
+ : bufptr += len;
+ : }
+ : }
+ : }
+ : WriteReplyToClient(client, sizeof(xListExtensionsReply), &reply);
+ : if (reply.length)
+ : {
+ : WriteToClient(client, total_length, buffer);
+ : DEALLOCATE_LOCAL(buffer);
+ : }
+ : return(client->noClientException);
+ :}
+ :
+ :#ifdef XSERVER_DTRACE
+ :void LoadExtensionNames(char **RequestNames) {
+ : int i;
+ :
+ : for (i=0; i<NumExtensions; i++) {
+ : int r = extensions[i]->base;
+ :
+ : if (RequestNames[r] == NULL) {
+ : RequestNames[r] = strdup(extensions[i]->name);
+ : }
+ : }
+ :}
+ :#endif
+/*
+ * Total samples for file : "/home/cworth/src/pixman/pixman/pixman-trap.c"
+ *
+ * 5 0.0054
+ */
+
+
+ :/*
+ : * $Id$
+ : *
+ : * Copyright © 2004 Keith Packard
+ : *
+ : * 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 Keith Packard not be used in
+ : * advertising or publicity pertaining to distribution of the software without
+ : * specific, written prior permission. Keith Packard makes no
+ : * representations about the suitability of this software for any purpose. It
+ : * is provided "as is" without express or implied warranty.
+ : *
+ : * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ : * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ : * EVENT SHALL KEITH PACKARD 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.
+ : */
+ :
+ :#include <config.h>
+ :#include <stdio.h>
+ :#include "pixman-private.h"
+ :
+ :typedef uint32_t FbBits;
+ :
+ :void
+ :pixman_add_traps (pixman_image_t * image,
+ : int16_t x_off,
+ : int16_t y_off,
+ : int ntrap,
+ : pixman_trap_t *traps)
+ :{
+ : int bpp;
+ : int width;
+ : int height;
+ :
+ : pixman_fixed_t x_off_fixed;
+ : pixman_fixed_t y_off_fixed;
+ : pixman_edge_t l, r;
+ : pixman_fixed_t t, b;
+ :
+ : width = image->bits.width;
+ : height = image->bits.height;
+ : bpp = PIXMAN_FORMAT_BPP (image->bits.format);
+ :
+ : x_off_fixed = pixman_int_to_fixed(y_off);
+ : y_off_fixed = pixman_int_to_fixed(y_off);
+ :
+ : while (ntrap--)
+ : {
+ : t = traps->top.y + y_off_fixed;
+ : if (t < 0)
+ : t = 0;
+ : t = pixman_sample_ceil_y (t, bpp);
+ :
+ : b = traps->bot.y + y_off_fixed;
+ : if (pixman_fixed_to_int (b) >= height)
+ : b = pixman_int_to_fixed (height) - 1;
+ : b = pixman_sample_floor_y (b, bpp);
+ :
+ : if (b >= t)
+ : {
+ : /* initialize edge walkers */
+ : pixman_edge_init (&l, bpp, t,
+ : traps->top.l + x_off_fixed,
+ : traps->top.y + y_off_fixed,
+ : traps->bot.l + x_off_fixed,
+ : traps->bot.y + y_off_fixed);
+ :
+ : pixman_edge_init (&r, bpp, t,
+ : traps->top.r + x_off_fixed,
+ : traps->top.y + y_off_fixed,
+ : traps->bot.r + x_off_fixed,
+ : traps->bot.y + y_off_fixed);
+ :
+ : pixman_rasterize_edges (image, &l, &r, t, b);
+ : }
+ : traps++;
+ : }
+ :
+ : fbFinishAccess (pPicture->pDrawable);
+ :}
+ :
+ :static void
+ :dump_image (pixman_image_t *image,
+ : const char *title)
+ :{
+ : int i, j;
+ :
+ : if (!image->type == BITS)
+ : {
+ : printf ("%s is not a regular image\n", title);
+ : }
+ :
+ : if (!image->bits.format == PIXMAN_a8)
+ : {
+ : printf ("%s is not an alpha mask\n", title);
+ : }
+ :
+ : printf ("\n\n\n%s: \n", title);
+ :
+ : for (i = 0; i < image->bits.height; ++i)
+ : {
+ : uint8_t *line =
+ : (uint8_t *)&(image->bits.bits[i * image->bits.rowstride]);
+ :
+ : for (j = 0; j < image->bits.width; ++j)
+ : printf ("%c", line[j]? '#' : ' ');
+ :
+ : printf ("\n");
+ : }
+ :}
+ :
+ :void
+ :pixman_add_trapezoids (pixman_image_t *image,
+ : int16_t x_off,
+ : int y_off,
+ : int ntraps,
+ : const pixman_trapezoid_t *traps)
+ :{
+ : int i;
+ :
+ :#if 0
+ : dump_image (image, "before");
+ :#endif
+ :
+ : for (i = 0; i < ntraps; ++i)
+ : {
+ : const pixman_trapezoid_t *trap = &(traps[i]);
+ :
+ : if (!pixman_trapezoid_valid (trap))
+ : continue;
+ :
+ : pixman_rasterize_trapezoid (image, trap, x_off, y_off);
+ : }
+ :
+ :#if 0
+ : dump_image (image, "after");
+ :#endif
+ :}
+ :
+ :void
+ :pixman_rasterize_trapezoid (pixman_image_t * image,
+ : const pixman_trapezoid_t *trap,
+ : int x_off,
+ : int y_off)
+ :{ /* pixman_rasterize_trapezoid total: 5 0.0054 */
+ : int bpp;
+ : int width;
+ : int height;
+ :
+ : pixman_fixed_t x_off_fixed;
+ : pixman_fixed_t y_off_fixed;
+ : pixman_edge_t l, r;
+ : pixman_fixed_t t, b;
+ :
+ : return_if_fail (image->type == BITS);
+ :
+ 2 0.0022 : if (!pixman_trapezoid_valid (trap))
+ : return;
+ :
+ : width = image->bits.width;
+ : height = image->bits.height;
+ : bpp = PIXMAN_FORMAT_BPP (image->bits.format);
+ :
+ : x_off_fixed = pixman_int_to_fixed(x_off);
+ : y_off_fixed = pixman_int_to_fixed(y_off);
+ : t = trap->top + y_off_fixed;
+ : if (t < 0)
+ : t = 0;
+ : t = pixman_sample_ceil_y (t, bpp);
+ :
+ : b = trap->bottom + y_off_fixed;
+ : if (pixman_fixed_to_int (b) >= height)
+ : b = pixman_int_to_fixed (height) - 1;
+ : b = pixman_sample_floor_y (b, bpp);
+ :
+ : if (b >= t)
+ : {
+ : /* initialize edge walkers */
+ : pixman_line_fixed_edge_init (&l, bpp, t, &trap->left, x_off, y_off);
+ 3 0.0033 : pixman_line_fixed_edge_init (&r, bpp, t, &trap->right, x_off, y_off);
+ :
+ : pixman_rasterize_edges (image, &l, &r, t, b);
+ : }
+ :}
+ :
+ :#if 0
+ :static int
+ :_GreaterY (pixman_point_fixed_t *a, pixman_point_fixed_t *b)
+ :{
+ : if (a->y == b->y)
+ : return a->x > b->x;
+ : return a->y > b->y;
+ :}
+ :
+ :/*
+ : * Note that the definition of this function is a bit odd because
+ : * of the X coordinate space (y increasing downwards).
+ : */
+ :static int
+ :_Clockwise (pixman_point_fixed_t *ref, pixman_point_fixed_t *a, pixman_point_fixed_t *b)
+ :{
+ : pixman_point_fixed_t ad, bd;
+ :
+ : ad.x = a->x - ref->x;
+ : ad.y = a->y - ref->y;
+ : bd.x = b->x - ref->x;
+ : bd.y = b->y - ref->y;
+ :
+ : return ((pixman_fixed_32_32_t) bd.y * ad.x - (pixman_fixed_32_32_t) ad.y * bd.x) < 0;
+ :}
+ :
+ :/* FIXME -- this could be made more efficient */
+ :void
+ :fbAddTriangles (pixman_image_t * pPicture,
+ : int16_t x_off,
+ : int16_t y_off,
+ : int ntri,
+ : xTriangle *tris)
+ :{
+ : pixman_point_fixed_t *top, *left, *right, *tmp;
+ : xTrapezoid trap;
+ :
+ : for (; ntri; ntri--, tris++)
+ : {
+ : top = &tris->p1;
+ : left = &tris->p2;
+ : right = &tris->p3;
+ : if (_GreaterY (top, left)) {
+ : tmp = left; left = top; top = tmp;
+ : }
+ : if (_GreaterY (top, right)) {
+ : tmp = right; right = top; top = tmp;
+ : }
+ : if (_Clockwise (top, right, left)) {
+ : tmp = right; right = left; left = tmp;
+ : }
+ :
+ : /*
+ : * Two cases:
+ : *
+ : * + +
+ : * / \ / \
+ : * / \ / \
+ : * / + + \
+ : * / -- -- \
+ : * / -- -- \
+ : * / --- --- \
+ : * +-- --+
+ : */
+ :
+ : trap.top = top->y;
+ : trap.left.p1 = *top;
+ : trap.left.p2 = *left;
+ : trap.right.p1 = *top;
+ : trap.right.p2 = *right;
+ : if (right->y < left->y)
+ : trap.bottom = right->y;
+ : else
+ : trap.bottom = left->y;
+ : fbRasterizeTrapezoid (pPicture, &trap, x_off, y_off);
+ : if (right->y < left->y)
+ : {
+ : trap.top = right->y;
+ : trap.bottom = left->y;
+ : trap.right.p1 = *right;
+ : trap.right.p2 = *left;
+ : }
+ : else
+ : {
+ : trap.top = left->y;
+ : trap.bottom = right->y;
+ : trap.left.p1 = *left;
+ : trap.left.p2 = *right;
+ : }
+ : fbRasterizeTrapezoid (pPicture, &trap, x_off, y_off);
+ : }
+ :}
+ :#endif
+/*
+ * Total samples for file : "memcpy.c"
+ *
+ * 4 0.0044
+ */
+
+<credited to line zero> 4 0.0044 :
+ /* _dl_load_cache_lookup total: 1 0.0011 */
+ /* _dl_lookup_symbol_x total: 1 0.0011 */
+ /* _dl_relocate_object total: 1 0.0011 */
+ /* strcmp total: 2 0.0022 */
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/fb/fbpict.c"
+ *
+ * 3 0.0033
+ */
+
+
+ :/*
+ : *
+ : * Copyright © 2000 SuSE, Inc.
+ : * Copyright © 2007 Red Hat, Inc.
+ : *
+ : * 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 SuSE not be used in advertising or
+ : * publicity pertaining to distribution of the software without specific,
+ : * written prior permission. SuSE makes no representations about the
+ : * suitability of this software for any purpose. It is provided "as is"
+ : * without express or implied warranty.
+ : *
+ : * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ : * 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: Keith Packard, SuSE, Inc.
+ : */
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include <string.h>
+ :
+ :#include "fb.h"
+ :
+ :#ifdef RENDER
+ :
+ :#include "picturestr.h"
+ :#include "mipict.h"
+ :#include "fbpict.h"
+ :
+ :#define mod(a,b) ((b) == 1 ? 0 : (a) >= 0 ? (a) % (b) : (b) - (-a) % (b))
+ :
+ :void
+ :fbWalkCompositeRegion (CARD8 op,
+ : PicturePtr pSrc,
+ : PicturePtr pMask,
+ : PicturePtr pDst,
+ : INT16 xSrc,
+ : INT16 ySrc,
+ : INT16 xMask,
+ : INT16 yMask,
+ : INT16 xDst,
+ : INT16 yDst,
+ : CARD16 width,
+ : CARD16 height,
+ : Bool srcRepeat,
+ : Bool maskRepeat,
+ : CompositeFunc compositeRect)
+ :{
+ : RegionRec region;
+ : int n;
+ : BoxPtr pbox;
+ : int w, h, w_this, h_this;
+ : int x_msk, y_msk, x_src, y_src, x_dst, y_dst;
+ :
+ : xDst += pDst->pDrawable->x;
+ : yDst += pDst->pDrawable->y;
+ : if (pSrc->pDrawable)
+ : {
+ : xSrc += pSrc->pDrawable->x;
+ : ySrc += pSrc->pDrawable->y;
+ : }
+ : if (pMask && pMask->pDrawable)
+ : {
+ : xMask += pMask->pDrawable->x;
+ : yMask += pMask->pDrawable->y;
+ : }
+ :
+ : if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, xSrc, ySrc,
+ : xMask, yMask, xDst, yDst, width, height))
+ : return;
+ :
+ : n = REGION_NUM_RECTS (®ion);
+ : pbox = REGION_RECTS (®ion);
+ : while (n--)
+ : {
+ : h = pbox->y2 - pbox->y1;
+ : y_src = pbox->y1 - yDst + ySrc;
+ : y_msk = pbox->y1 - yDst + yMask;
+ : y_dst = pbox->y1;
+ : while (h)
+ : {
+ : h_this = h;
+ : w = pbox->x2 - pbox->x1;
+ : x_src = pbox->x1 - xDst + xSrc;
+ : x_msk = pbox->x1 - xDst + xMask;
+ : x_dst = pbox->x1;
+ : if (maskRepeat)
+ : {
+ : y_msk = mod (y_msk - pMask->pDrawable->y, pMask->pDrawable->height);
+ : if (h_this > pMask->pDrawable->height - y_msk)
+ : h_this = pMask->pDrawable->height - y_msk;
+ : y_msk += pMask->pDrawable->y;
+ : }
+ : if (srcRepeat)
+ : {
+ : y_src = mod (y_src - pSrc->pDrawable->y, pSrc->pDrawable->height);
+ : if (h_this > pSrc->pDrawable->height - y_src)
+ : h_this = pSrc->pDrawable->height - y_src;
+ : y_src += pSrc->pDrawable->y;
+ : }
+ : while (w)
+ : {
+ : w_this = w;
+ : if (maskRepeat)
+ : {
+ : x_msk = mod (x_msk - pMask->pDrawable->x, pMask->pDrawable->width);
+ : if (w_this > pMask->pDrawable->width - x_msk)
+ : w_this = pMask->pDrawable->width - x_msk;
+ : x_msk += pMask->pDrawable->x;
+ : }
+ : if (srcRepeat)
+ : {
+ : x_src = mod (x_src - pSrc->pDrawable->x, pSrc->pDrawable->width);
+ : if (w_this > pSrc->pDrawable->width - x_src)
+ : w_this = pSrc->pDrawable->width - x_src;
+ : x_src += pSrc->pDrawable->x;
+ : }
+ : (*compositeRect) (op, pSrc, pMask, pDst,
+ : x_src, y_src, x_msk, y_msk, x_dst, y_dst,
+ : w_this, h_this);
+ : w -= w_this;
+ : x_src += w_this;
+ : x_msk += w_this;
+ : x_dst += w_this;
+ : }
+ : h -= h_this;
+ : y_src += h_this;
+ : y_msk += h_this;
+ : y_dst += h_this;
+ : }
+ : pbox++;
+ : }
+ : REGION_UNINIT (pDst->pDrawable->pScreen, ®ion);
+ :}
+ :
+ :void
+ :fbComposite (CARD8 op,
+ : PicturePtr pSrc,
+ : PicturePtr pMask,
+ : PicturePtr pDst,
+ : INT16 xSrc,
+ : INT16 ySrc,
+ : INT16 xMask,
+ : INT16 yMask,
+ : INT16 xDst,
+ : INT16 yDst,
+ : CARD16 width,
+ : CARD16 height)
+ :{
+ : pixman_image_t *src, *mask, *dest;
+ :
+ : xDst += pDst->pDrawable->x;
+ : yDst += pDst->pDrawable->y;
+ : if (pSrc->pDrawable)
+ : {
+ : xSrc += pSrc->pDrawable->x;
+ : ySrc += pSrc->pDrawable->y;
+ : }
+ : if (pMask && pMask->pDrawable)
+ : {
+ : xMask += pMask->pDrawable->x;
+ : yMask += pMask->pDrawable->y;
+ : }
+ :
+ : miCompositeSourceValidate (pSrc, xSrc, ySrc, width, height);
+ : if (pMask)
+ : miCompositeSourceValidate (pMask, xMask, yMask, width, height);
+ :
+ : src = image_from_pict (pSrc, TRUE);
+ : mask = image_from_pict (pMask, TRUE);
+ : dest = image_from_pict (pDst, TRUE);
+ :
+ : if (src && dest && !(pMask && !mask))
+ : {
+ : pixman_image_composite (op, src, mask, dest,
+ : xSrc, ySrc, xMask, yMask, xDst, yDst,
+ : width, height);
+ :
+ : }
+ :
+ : if (src)
+ : pixman_image_unref (src);
+ : if (mask)
+ : pixman_image_unref (mask);
+ : if (dest)
+ : pixman_image_unref (dest);
+ :}
+ :
+ :void
+ :fbCompositeGeneral (CARD8 op,
+ : PicturePtr pSrc,
+ : PicturePtr pMask,
+ : PicturePtr pDst,
+ : INT16 xSrc,
+ : INT16 ySrc,
+ : INT16 xMask,
+ : INT16 yMask,
+ : INT16 xDst,
+ : INT16 yDst,
+ : CARD16 width,
+ : CARD16 height)
+ :{
+ : return fbComposite (op, pSrc, pMask, pDst,
+ : xSrc, ySrc, xMask, yMask, xDst, yDst,
+ : width, height);
+ :}
+ :
+ :#endif /* RENDER */
+ :
+ :static pixman_image_t *
+ :create_solid_fill_image (PicturePtr pict)
+ :{
+ : PictSolidFill *solid = &pict->pSourcePict->solidFill;
+ : pixman_color_t color;
+ : CARD32 a, r, g, b;
+ :
+ : a = (solid->color & 0xff000000) >> 24;
+ : r = (solid->color & 0x00ff0000) >> 16;
+ : g = (solid->color & 0x0000ff00) >> 8;
+ : b = (solid->color & 0x000000ff) >> 0;
+ :
+ : color.alpha = (a << 8) | a;
+ : color.red = (r << 8) | r;
+ : color.green = (g << 8) | g;
+ : color.blue = (b << 8) | b;
+ :
+ : return pixman_image_create_solid_fill (&color);
+ :}
+ :
+ :static pixman_image_t *
+ :create_linear_gradient_image (PictGradient *gradient)
+ :{
+ : PictLinearGradient *linear = (PictLinearGradient *)gradient;
+ : pixman_point_fixed_t p1;
+ : pixman_point_fixed_t p2;
+ :
+ : p1.x = linear->p1.x;
+ : p1.y = linear->p1.y;
+ : p2.x = linear->p2.x;
+ : p2.y = linear->p2.y;
+ :
+ : return pixman_image_create_linear_gradient (
+ : &p1, &p2, (pixman_gradient_stop_t *)gradient->stops, gradient->nstops);
+ :}
+ :
+ :static pixman_image_t *
+ :create_radial_gradient_image (PictGradient *gradient)
+ :{
+ : PictRadialGradient *radial = (PictRadialGradient *)gradient;
+ : pixman_point_fixed_t c1;
+ : pixman_point_fixed_t c2;
+ :
+ : c1.x = radial->c1.x;
+ : c1.y = radial->c1.y;
+ : c2.x = radial->c2.x;
+ : c2.y = radial->c2.y;
+ :
+ : return pixman_image_create_radial_gradient (
+ : &c1, &c2, radial->c1.radius,
+ : radial->c2.radius,
+ : (pixman_gradient_stop_t *)gradient->stops, gradient->nstops);
+ :}
+ :
+ :static pixman_image_t *
+ :create_conical_gradient_image (PictGradient *gradient)
+ :{
+ : PictConicalGradient *conical = (PictConicalGradient *)gradient;
+ : pixman_point_fixed_t center;
+ :
+ : center.x = conical->center.x;
+ : center.y = conical->center.y;
+ :
+ : return pixman_image_create_conical_gradient (
+ : ¢er, conical->angle, (pixman_gradient_stop_t *)gradient->stops,
+ : gradient->nstops);
+ :}
+ :
+ :static pixman_image_t *
+ :create_bits_picture (PicturePtr pict,
+ : Bool has_clip)
+ :{
+ : FbBits *bits;
+ : FbStride stride;
+ : int bpp, xoff, yoff;
+ : pixman_image_t *image;
+ :
+ : fbGetDrawable (pict->pDrawable, bits, stride, bpp, xoff, yoff);
+ :
+ : bits += yoff * stride + xoff;
+ :
+ : image = pixman_image_create_bits (
+ : pict->format,
+ : pict->pDrawable->width, pict->pDrawable->height,
+ : (uint32_t *)bits, stride * sizeof (FbStride));
+ :
+ :
+ :#ifdef FB_ACCESS_WRAPPER
+ :#if FB_SHIFT==5
+ :
+ : pixman_image_set_accessors (image,
+ : (pixman_read_memory_func_t)wfbReadMemory,
+ : (pixman_write_memory_func_t)wfbWriteMemory);
+ :
+ :#else
+ :
+ :#error The pixman library only works when FbBits is 32 bits wide
+ :
+ :#endif
+ :#endif
+ :
+ : /* pCompositeClip is undefined for source pictures, so
+ : * only set the clip region for pictures with drawables
+ : */
+ : if (has_clip)
+ : {
+ : if (pict->clientClipType != CT_NONE)
+ : pixman_image_set_has_client_clip (image, TRUE);
+ :
+ : pixman_image_set_clip_region (image, pict->pCompositeClip);
+ : }
+ :
+ : /* Indexed table */
+ : if (pict->pFormat->index.devPrivate)
+ : pixman_image_set_indexed (image, pict->pFormat->index.devPrivate);
+ :
+ : fbFinishAccess (pict->pDrawable);
+ :
+ : return image;
+ :}
+ :
+ :static void
+ :set_image_properties (pixman_image_t *image, PicturePtr pict)
+ :{
+ : pixman_repeat_t repeat;
+ : pixman_filter_t filter;
+ :
+ : if (pict->transform)
+ : {
+ : pixman_image_set_transform (
+ : image, (pixman_transform_t *)pict->transform);
+ : }
+ :
+ : switch (pict->repeatType)
+ : {
+ : default:
+ : case RepeatNone:
+ : repeat = PIXMAN_REPEAT_NONE;
+ : break;
+ :
+ : case RepeatPad:
+ : repeat = PIXMAN_REPEAT_PAD;
+ : break;
+ :
+ : case RepeatNormal:
+ : repeat = PIXMAN_REPEAT_NORMAL;
+ : break;
+ :
+ : case RepeatReflect:
+ : repeat = PIXMAN_REPEAT_REFLECT;
+ : break;
+ : }
+ :
+ : pixman_image_set_repeat (image, repeat);
+ :
+ : if (pict->alphaMap)
+ : {
+ : pixman_image_t *alpha_map = image_from_pict (pict->alphaMap, TRUE);
+ :
+ : pixman_image_set_alpha_map (
+ : image, alpha_map, pict->alphaOrigin.x, pict->alphaOrigin.y);
+ :
+ : pixman_image_unref (alpha_map);
+ : }
+ :
+ : pixman_image_set_component_alpha (image, pict->componentAlpha);
+ :
+ : switch (pict->filter)
+ : {
+ : default:
+ : case PictFilterNearest:
+ : case PictFilterFast:
+ : filter = PIXMAN_FILTER_NEAREST;
+ : break;
+ :
+ : case PictFilterBilinear:
+ : case PictFilterGood:
+ : filter = PIXMAN_FILTER_BILINEAR;
+ : break;
+ :
+ : case PictFilterConvolution:
+ : filter = PIXMAN_FILTER_CONVOLUTION;
+ : break;
+ : }
+ :
+ : pixman_image_set_filter (image, filter, (pixman_fixed_t *)pict->filter_params, pict->filter_nparams);
+ :}
+ :
+ :pixman_image_t *
+ :image_from_pict (PicturePtr pict,
+ : Bool has_clip)
+ 3 0.0033 :{ /* image_from_pict total: 4 0.0044 */
+ : pixman_image_t *image = NULL;
+ :
+ : if (!pict)
+ : return NULL;
+ :
+ : if (pict->pDrawable)
+ : {
+ : image = create_bits_picture (pict, has_clip);
+ : }
+ : else if (pict->pSourcePict)
+ : {
+ : SourcePict *sp = pict->pSourcePict;
+ :
+ : if (sp->type == SourcePictTypeSolidFill)
+ : {
+ : image = create_solid_fill_image (pict);
+ : }
+ : else
+ : {
+ : PictGradient *gradient = &pict->pSourcePict->gradient;
+ :
+ : if (sp->type == SourcePictTypeLinear)
+ : image = create_linear_gradient_image (gradient);
+ : else if (sp->type == SourcePictTypeRadial)
+ : image = create_radial_gradient_image (gradient);
+ : else if (sp->type == SourcePictTypeConical)
+ : image = create_conical_gradient_image (gradient);
+ : }
+ : }
+ :
+ : if (image)
+ : set_image_properties (image, pict);
+ :
+ : return image;
+ :}
+ :
+ :Bool
+ :fbPictureInit (ScreenPtr pScreen, PictFormatPtr formats, int nformats)
+ :{
+ :
+ :#ifdef RENDER
+ :
+ : PictureScreenPtr ps;
+ :
+ : if (!miPictureInit (pScreen, formats, nformats))
+ : return FALSE;
+ : ps = GetPictureScreen(pScreen);
+ : ps->Composite = fbComposite;
+ : ps->Glyphs = miGlyphs;
+ : ps->CompositeRects = miCompositeRects;
+ : ps->RasterizeTrapezoid = fbRasterizeTrapezoid;
+ : ps->AddTraps = fbAddTraps;
+ : ps->AddTriangles = fbAddTriangles;
+ :
+ :#endif /* RENDER */
+ :
+ : return TRUE;
+ :}
+/*
+ * Total samples for file : "/home/cworth/src/xorg/driver/xf86-video-intel/src/i830_render.c"
+ *
+ * 3 0.0033
+ */
+
+
+ :/*
+ : * Copyright © 2006 Intel Corporation
+ : *
+ : * Permission is hereby granted, free of charge, to any person obtaining a
+ : * copy of this software and associated documentation files (the "Software"),
+ : * to deal in the Software without restriction, including without limitation
+ : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ : * and/or sell copies of the Software, and to permit persons to whom the
+ : * Software is furnished to do so, subject to the following conditions:
+ : *
+ : * The above copyright notice and this permission notice (including the next
+ : * paragraph) shall be included in all copies or substantial portions of the
+ : * Software.
+ : *
+ : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ : * SOFTWARE.
+ : *
+ : * Authors:
+ : * Wang Zhenyu <zhenyu.z.wang@intel.com>
+ : * Eric Anholt <eric@anholt.net>
+ : *
+ : */
+ :
+ :#ifdef HAVE_CONFIG_H
+ :#include "config.h"
+ :#endif
+ :
+ :#include "xf86.h"
+ :#include "i830.h"
+ :#include "i830_reg.h"
+ :
+ :#ifdef I830DEBUG
+ :#define DEBUG_I830FALLBACK 1
+ :#endif
+ :
+ :#ifdef DEBUG_I830FALLBACK
+ :#define I830FALLBACK(s, arg...) \
+ :do { \
+ : DPRINTF(PFX, "EXA fallback: " s "\n", ##arg); \
+ : return FALSE; \
+ :} while(0)
+ :#else
+ :#define I830FALLBACK(s, arg...) \
+ :do { \
+ : return FALSE; \
+ :} while(0)
+ :#endif
+ :
+ :struct blendinfo {
+ : Bool dst_alpha;
+ : Bool src_alpha;
+ : CARD32 src_blend;
+ : CARD32 dst_blend;
+ :};
+ :
+ :struct formatinfo {
+ : int fmt;
+ : CARD32 card_fmt;
+ :};
+ :
+ :#define TB0C_LAST_STAGE (1 << 31)
+ :#define TB0C_RESULT_SCALE_1X (0 << 29)
+ :#define TB0C_RESULT_SCALE_2X (1 << 29)
+ :#define TB0C_RESULT_SCALE_4X (2 << 29)
+ :#define TB0C_OP_MODULE (3 << 25)
+ :#define TB0C_OUTPUT_WRITE_CURRENT (0 << 24)
+ :#define TB0C_OUTPUT_WRITE_ACCUM (1 << 24)
+ :#define TB0C_ARG3_REPLICATE_ALPHA (1<<23)
+ :#define TB0C_ARG3_INVERT (1<<22)
+ :#define TB0C_ARG3_SEL_XXX
+ :#define TB0C_ARG2_REPLICATE_ALPHA (1<<17)
+ :#define TB0C_ARG2_INVERT (1<<16)
+ :#define TB0C_ARG2_SEL_ONE (0 << 12)
+ :#define TB0C_ARG2_SEL_FACTOR (1 << 12)
+ :#define TB0C_ARG2_SEL_TEXEL0 (6 << 12)
+ :#define TB0C_ARG2_SEL_TEXEL1 (7 << 12)
+ :#define TB0C_ARG2_SEL_TEXEL2 (8 << 12)
+ :#define TB0C_ARG2_SEL_TEXEL3 (9 << 12)
+ :#define TB0C_ARG1_REPLICATE_ALPHA (1<<11)
+ :#define TB0C_ARG1_INVERT (1<<10)
+ :#define TB0C_ARG1_SEL_ONE (0 << 6)
+ :#define TB0C_ARG1_SEL_TEXEL0 (6 << 6)
+ :#define TB0C_ARG1_SEL_TEXEL1 (7 << 6)
+ :#define TB0C_ARG1_SEL_TEXEL2 (8 << 6)
+ :#define TB0C_ARG1_SEL_TEXEL3 (9 << 6)
+ :#define TB0C_ARG0_REPLICATE_ALPHA (1<<5)
+ :#define TB0C_ARG0_SEL_XXX
+ :
+ :#define TB0A_CTR_STAGE_ENABLE (1<<31)
+ :#define TB0A_RESULT_SCALE_1X (0 << 29)
+ :#define TB0A_RESULT_SCALE_2X (1 << 29)
+ :#define TB0A_RESULT_SCALE_4X (2 << 29)
+ :#define TB0A_OP_MODULE (3 << 25)
+ :#define TB0A_OUTPUT_WRITE_CURRENT (0<<24)
+ :#define TB0A_OUTPUT_WRITE_ACCUM (1<<24)
+ :#define TB0A_CTR_STAGE_SEL_BITS_XXX
+ :#define TB0A_ARG3_SEL_XXX
+ :#define TB0A_ARG3_INVERT (1<<17)
+ :#define TB0A_ARG2_INVERT (1<<16)
+ :#define TB0A_ARG2_SEL_ONE (0 << 12)
+ :#define TB0A_ARG2_SEL_TEXEL0 (6 << 12)
+ :#define TB0A_ARG2_SEL_TEXEL1 (7 << 12)
+ :#define TB0A_ARG2_SEL_TEXEL2 (8 << 12)
+ :#define TB0A_ARG2_SEL_TEXEL3 (9 << 12)
+ :#define TB0A_ARG1_INVERT (1<<10)
+ :#define TB0A_ARG1_SEL_ONE (0 << 6)
+ :#define TB0A_ARG1_SEL_TEXEL0 (6 << 6)
+ :#define TB0A_ARG1_SEL_TEXEL1 (7 << 6)
+ :#define TB0A_ARG1_SEL_TEXEL2 (8 << 6)
+ :#define TB0A_ARG1_SEL_TEXEL3 (9 << 6)
+ :
+ :static struct blendinfo i830_blend_op[] = {
+ : /* Clear */
+ : {0, 0, BLENDFACTOR_ZERO, BLENDFACTOR_ZERO},
+ : /* Src */
+ : {0, 0, BLENDFACTOR_ONE, BLENDFACTOR_ZERO},
+ : /* Dst */
+ : {0, 0, BLENDFACTOR_ZERO, BLENDFACTOR_ONE},
+ : /* Over */
+ : {0, 1, BLENDFACTOR_ONE, BLENDFACTOR_INV_SRC_ALPHA},
+ : /* OverReverse */
+ : {1, 0, BLENDFACTOR_INV_DST_ALPHA, BLENDFACTOR_ONE},
+ : /* In */
+ : {1, 0, BLENDFACTOR_DST_ALPHA, BLENDFACTOR_ZERO},
+ : /* InReverse */
+ : {0, 1, BLENDFACTOR_ZERO, BLENDFACTOR_SRC_ALPHA},
+ : /* Out */
+ : {1, 0, BLENDFACTOR_INV_DST_ALPHA, BLENDFACTOR_ZERO},
+ : /* OutReverse */
+ : {0, 1, BLENDFACTOR_ZERO, BLENDFACTOR_INV_SRC_ALPHA},
+ : /* Atop */
+ : {1, 1, BLENDFACTOR_DST_ALPHA, BLENDFACTOR_INV_SRC_ALPHA},
+ : /* AtopReverse */
+ : {1, 1, BLENDFACTOR_INV_DST_ALPHA, BLENDFACTOR_SRC_ALPHA},
+ : /* Xor */
+ : {1, 1, BLENDFACTOR_INV_DST_ALPHA, BLENDFACTOR_INV_SRC_ALPHA},
+ : /* Add */
+ : {0, 0, BLENDFACTOR_ONE, BLENDFACTOR_ONE},
+ :};
+ :
+ :static struct formatinfo i830_tex_formats[] = {
+ : {PICT_a8r8g8b8, MT_32BIT_ARGB8888 },
+ : {PICT_x8r8g8b8, MT_32BIT_XRGB8888 },
+ : {PICT_a8b8g8r8, MT_32BIT_ABGR8888 },
+ : {PICT_x8b8g8r8, MT_32BIT_XBGR8888 },
+ : {PICT_r5g6b5, MT_16BIT_RGB565 },
+ : {PICT_a1r5g5b5, MT_16BIT_ARGB1555 },
+ : {PICT_x1r5g5b5, MT_16BIT_ARGB1555 },
+ : {PICT_a8, MT_8BIT_A8 },
+ :};
+ :
+ :static Bool i830_get_dest_format(PicturePtr pDstPicture, CARD32 *dst_format)
+ :{
+ : switch (pDstPicture->format) {
+ : case PICT_a8r8g8b8:
+ : case PICT_x8r8g8b8:
+ : *dst_format = COLR_BUF_ARGB8888;
+ : break;
+ : case PICT_r5g6b5:
+ : *dst_format = COLR_BUF_RGB565;
+ : break;
+ : case PICT_a1r5g5b5:
+ : case PICT_x1r5g5b5:
+ : *dst_format = COLR_BUF_ARGB1555;
+ : break;
+ : /*
+ : case PICT_a8:
+ : *dst_format = COLR_BUF_8BIT;
+ : break;
+ : */
+ : case PICT_a4r4g4b4:
+ : case PICT_x4r4g4b4:
+ : *dst_format = COLR_BUF_ARGB4444;
+ : break;
+ : default:
+ : I830FALLBACK("Unsupported dest format 0x%x\n",
+ : (int)pDstPicture->format);
+ : }
+ :
+ : return TRUE;
+ :}
+ :
+ :
+ :static CARD32 i830_get_blend_cntl(int op, PicturePtr pMask, CARD32 dst_format)
+ :{
+ : CARD32 sblend, dblend;
+ :
+ : sblend = i830_blend_op[op].src_blend;
+ : dblend = i830_blend_op[op].dst_blend;
+ :
+ : /* If there's no dst alpha channel, adjust the blend op so that we'll treat
+ : * it as always 1.
+ : */
+ : if (PICT_FORMAT_A(dst_format) == 0 && i830_blend_op[op].dst_alpha) {
+ : if (sblend == BLENDFACTOR_DST_ALPHA)
+ : sblend = BLENDFACTOR_ONE;
+ : else if (sblend == BLENDFACTOR_INV_DST_ALPHA)
+ : sblend = BLENDFACTOR_ZERO;
+ : }
+ :
+ : /* If the source alpha is being used, then we should only be in a case
+ : * where the source blend factor is 0, and the source blend value is the
+ : * mask channels multiplied by the source picture's alpha.
+ : */
+ : if (pMask && pMask->componentAlpha && PICT_FORMAT_RGB(pMask->format)
+ : && i830_blend_op[op].src_alpha) {
+ : if (dblend == BLENDFACTOR_SRC_ALPHA) {
+ : dblend = BLENDFACTOR_SRC_COLR;
+ : } else if (dblend == BLENDFACTOR_INV_SRC_ALPHA) {
+ : dblend = BLENDFACTOR_INV_SRC_COLR;
+ : }
+ : }
+ :
+ : return (sblend << S8_SRC_BLEND_FACTOR_SHIFT) |
+ : (dblend << S8_DST_BLEND_FACTOR_SHIFT);
+ :}
+ :
+ :static Bool i830_check_composite_texture(PicturePtr pPict, int unit)
+ :{
+ : ScrnInfoPtr pScrn = xf86Screens[pPict->pDrawable->pScreen->myNum];
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : int w = pPict->pDrawable->width;
+ : int h = pPict->pDrawable->height;
+ : int i;
+ :
+ : if ((w > 0x7ff) || (h > 0x7ff))
+ : I830FALLBACK("Picture w/h too large (%dx%d)\n", w, h);
+ :
+ : for (i = 0; i < sizeof(i830_tex_formats) / sizeof(i830_tex_formats[0]);
+ : i++)
+ : {
+ : if (i830_tex_formats[i].fmt == pPict->format)
+ : break;
+ : }
+ : if (i == sizeof(i830_tex_formats) / sizeof(i830_tex_formats[0]))
+ : I830FALLBACK("Unsupported picture format 0x%x\n",
+ : (int)pPict->format);
+ :
+ : if (IS_I830(pI830) || IS_845G(pI830)) {
+ : if (pPict->format == PICT_x8r8g8b8 ||
+ : pPict->format == PICT_x8b8g8r8 ||
+ : pPict->format == PICT_a8)
+ : I830FALLBACK("830/845G don't support a8, x8r8g8b8, x8b8g8r8\n");
+ : }
+ :
+ : if (pPict->repeat && pPict->repeatType != RepeatNormal)
+ : I830FALLBACK("unsupport repeat type\n");
+ :
+ : if (pPict->filter != PictFilterNearest &&
+ : pPict->filter != PictFilterBilinear)
+ : {
+ : I830FALLBACK("Unsupported filter 0x%x\n", pPict->filter);
+ : }
+ :
+ : return TRUE;
+ :}
+ :
+ :static CARD32
+ :i8xx_get_card_format(PicturePtr pPict)
+ :{
+ : int i;
+ : for (i = 0; i < sizeof(i830_tex_formats) / sizeof(i830_tex_formats[0]);
+ : i++)
+ : {
+ : if (i830_tex_formats[i].fmt == pPict->format)
+ : break;
+ : }
+ : return i830_tex_formats[i].card_fmt;
+ :}
+ :
+ :static Bool
+ :i830_texture_setup(PicturePtr pPict, PixmapPtr pPix, int unit)
+ :{
+ :
+ : ScrnInfoPtr pScrn = xf86Screens[pPict->pDrawable->pScreen->myNum];
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : CARD32 format, offset, pitch, filter;
+ : CARD32 wrap_mode = TEXCOORDMODE_CLAMP_BORDER;
+ :
+ : offset = intel_get_pixmap_offset(pPix);
+ : pitch = intel_get_pixmap_pitch(pPix);
+ : pI830->scale_units[unit][0] = pPix->drawable.width;
+ : pI830->scale_units[unit][1] = pPix->drawable.height;
+ : pI830->transform[unit] = pPict->transform;
+ :
+ : format = i8xx_get_card_format(pPict);
+ :
+ : if (pPict->repeat)
+ : wrap_mode = TEXCOORDMODE_WRAP;
+ :
+ : switch (pPict->filter) {
+ : case PictFilterNearest:
+ : filter = ((FILTER_NEAREST<<TM0S3_MAG_FILTER_SHIFT) |
+ : (FILTER_NEAREST<<TM0S3_MIN_FILTER_SHIFT));
+ : break;
+ : case PictFilterBilinear:
+ : filter = ((FILTER_LINEAR<<TM0S3_MAG_FILTER_SHIFT) |
+ : (FILTER_LINEAR<<TM0S3_MIN_FILTER_SHIFT));
+ : break;
+ : default:
+ : filter = 0;
+ : I830FALLBACK("Bad filter 0x%x\n", pPict->filter);
+ : }
+ : filter |= (MIPFILTER_NONE << TM0S3_MIP_FILTER_SHIFT);
+ :
+ : {
+ : if (pPix->drawable.bitsPerPixel == 8)
+ : format |= MAPSURF_8BIT;
+ : else if (pPix->drawable.bitsPerPixel == 16)
+ : format |= MAPSURF_16BIT;
+ : else
+ : format |= MAPSURF_32BIT;
+ :
+ : BEGIN_LP_RING(10);
+ : OUT_RING(_3DSTATE_LOAD_STATE_IMMEDIATE_2 | LOAD_TEXTURE_MAP(unit) | 4);
+ : OUT_RING((offset & TM0S0_ADDRESS_MASK) | TM0S0_USE_FENCE);
+ : OUT_RING(((pPix->drawable.height - 1) << TM0S1_HEIGHT_SHIFT) |
+ : ((pPix->drawable.width - 1) << TM0S1_WIDTH_SHIFT) | format);
+ : OUT_RING((pitch/4 - 1) << TM0S2_PITCH_SHIFT | TM0S2_MAP_2D);
+ : OUT_RING(filter);
+ : OUT_RING(0); /* default color */
+ : OUT_RING(_3DSTATE_MAP_COORD_SET_CMD | TEXCOORD_SET(unit) |
+ : ENABLE_TEXCOORD_PARAMS | TEXCOORDS_ARE_NORMAL |
+ : TEXCOORDTYPE_CARTESIAN | ENABLE_ADDR_V_CNTL |
+ : TEXCOORD_ADDR_V_MODE(wrap_mode) |
+ : ENABLE_ADDR_U_CNTL | TEXCOORD_ADDR_U_MODE(wrap_mode));
+ : /* map texel stream */
+ : OUT_RING(_3DSTATE_MAP_COORD_SETBIND_CMD);
+ : if (unit == 0)
+ : OUT_RING(TEXBIND_SET0(TEXCOORDSRC_VTXSET_0) |
+ : TEXBIND_SET1(TEXCOORDSRC_KEEP) |
+ : TEXBIND_SET2(TEXCOORDSRC_KEEP) |
+ : TEXBIND_SET3(TEXCOORDSRC_KEEP));
+ : else
+ : OUT_RING(TEXBIND_SET0(TEXCOORDSRC_VTXSET_0) |
+ : TEXBIND_SET1(TEXCOORDSRC_VTXSET_1) |
+ : TEXBIND_SET2(TEXCOORDSRC_KEEP) |
+ : TEXBIND_SET3(TEXCOORDSRC_KEEP));
+ : OUT_RING(_3DSTATE_MAP_TEX_STREAM_CMD | (unit << 16) |
+ : DISABLE_TEX_STREAM_BUMP |
+ : ENABLE_TEX_STREAM_COORD_SET |
+ : TEX_STREAM_COORD_SET(unit) |
+ : ENABLE_TEX_STREAM_MAP_IDX |
+ : TEX_STREAM_MAP_IDX(unit));
+ : ADVANCE_LP_RING();
+ : }
+ :
+ :#ifdef I830DEBUG
+ : ErrorF("try to sync to show any errors...");
+ : I830Sync(pScrn);
+ :#endif
+ :
+ : return TRUE;
+ :}
+ :
+ :Bool
+ :i830_check_composite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
+ : PicturePtr pDstPicture)
+ :{
+ : CARD32 tmp1;
+ :
+ : /* Check for unsupported compositing operations. */
+ : if (op >= sizeof(i830_blend_op) / sizeof(i830_blend_op[0]))
+ : I830FALLBACK("Unsupported Composite op 0x%x\n", op);
+ :
+ : if (pMaskPicture != NULL && pMaskPicture->componentAlpha &&
+ : PICT_FORMAT_RGB(pMaskPicture->format)) {
+ : /* Check if it's component alpha that relies on a source alpha and on
+ : * the source value. We can only get one of those into the single
+ : * source value that we get to blend with.
+ : */
+ : if (i830_blend_op[op].src_alpha &&
+ : (i830_blend_op[op].src_blend != BLENDFACTOR_ZERO))
+ : I830FALLBACK("Component alpha not supported with source "
+ : "alpha and source value blending.\n");
+ : }
+ :
+ : if (!i830_check_composite_texture(pSrcPicture, 0))
+ : I830FALLBACK("Check Src picture texture\n");
+ : if (pMaskPicture != NULL && !i830_check_composite_texture(pMaskPicture, 1))
+ : I830FALLBACK("Check Mask picture texture\n");
+ :
+ : if (!i830_get_dest_format(pDstPicture, &tmp1))
+ : I830FALLBACK("Get Color buffer format\n");
+ :
+ : return TRUE;
+ :}
+ :
+ :Bool
+ :i830_prepare_composite(int op, PicturePtr pSrcPicture,
+ : PicturePtr pMaskPicture, PicturePtr pDstPicture,
+ : PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst)
+ :{
+ : ScrnInfoPtr pScrn = xf86Screens[pSrcPicture->pDrawable->pScreen->myNum];
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : CARD32 dst_format, dst_offset, dst_pitch;
+ :
+ : IntelEmitInvarientState(pScrn);
+ : *pI830->last_3d = LAST_3D_RENDER;
+ :
+ : i830_get_dest_format(pDstPicture, &dst_format);
+ : dst_offset = intel_get_pixmap_offset(pDst);
+ : dst_pitch = intel_get_pixmap_pitch(pDst);
+ :
+ : if (!i830_texture_setup(pSrcPicture, pSrc, 0))
+ : I830FALLBACK("fail to setup src texture\n");
+ : if (pMask != NULL) {
+ : if (!i830_texture_setup(pMaskPicture, pMask, 1))
+ : I830FALLBACK("fail to setup mask texture\n");
+ : } else {
+ : pI830->transform[1] = NULL;
+ : pI830->scale_units[1][0] = -1;
+ : pI830->scale_units[1][1] = -1;
+ : }
+ :
+ : {
+ : CARD32 cblend, ablend, blendctl, vf2;
+ :
+ : BEGIN_LP_RING(30);
+ :
+ : /* color buffer */
+ : OUT_RING(_3DSTATE_BUF_INFO_CMD);
+ : OUT_RING(BUF_3D_ID_COLOR_BACK| BUF_3D_PITCH(dst_pitch));
+ : OUT_RING(BUF_3D_ADDR(dst_offset));
+ : OUT_RING(MI_NOOP);
+ :
+ : OUT_RING(_3DSTATE_DST_BUF_VARS_CMD);
+ : OUT_RING(dst_format);
+ :
+ : /* defaults */
+ : OUT_RING(_3DSTATE_DFLT_Z_CMD);
+ : OUT_RING(0);
+ :
+ : OUT_RING(_3DSTATE_DFLT_DIFFUSE_CMD);
+ : OUT_RING(0);
+ :
+ : OUT_RING(_3DSTATE_DFLT_SPEC_CMD);
+ : OUT_RING(0);
+ :
+ : OUT_RING(_3DSTATE_DRAW_RECT_CMD);
+ : OUT_RING(0);
+ : OUT_RING(0); /* ymin, xmin */
+ : OUT_RING(DRAW_YMAX(pDst->drawable.height - 1) |
+ : DRAW_XMAX(pDst->drawable.width - 1));
+ : OUT_RING(0); /* yorig, xorig */
+ :
+ : OUT_RING(_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(2) |
+ : I1_LOAD_S(3) | 1);
+ : if (pMask)
+ : vf2 = 2 << 12; /* 2 texture coord sets */
+ : else
+ : vf2 = 1 << 12;
+ : OUT_RING(vf2); /* TEXCOORDFMT_2D */
+ : OUT_RING(S3_CULLMODE_NONE | S3_VERTEXHAS_XY);
+ :
+ : /* We use two pipes for color and alpha, and do (src In mask)
+ : in one stage. Arg1 is from src pict, and arg2 is from mask pict.
+ : Be sure to force 1.0 when src or mask pict has no alpha channel.
+ : */
+ : cblend = TB0C_LAST_STAGE | TB0C_RESULT_SCALE_1X | TB0C_OP_MODULE |
+ : TB0C_OUTPUT_WRITE_CURRENT;
+ : ablend = TB0A_RESULT_SCALE_1X | TB0A_OP_MODULE |
+ : TB0A_OUTPUT_WRITE_CURRENT;
+ :
+ : if (PICT_FORMAT_A(pSrcPicture->format) != 0) {
+ : ablend |= TB0A_ARG1_SEL_TEXEL0;
+ : cblend |= TB0C_ARG1_SEL_TEXEL0;
+ : } else {
+ : ablend |= TB0A_ARG1_SEL_ONE;
+ : if (pMask && pMaskPicture->componentAlpha
+ : && PICT_FORMAT_RGB(pMaskPicture->format)
+ : && i830_blend_op[op].src_alpha)
+ : cblend |= TB0C_ARG1_SEL_ONE;
+ : else
+ : cblend |= TB0C_ARG1_SEL_TEXEL0;
+ : }
+ :
+ : if (pMask) {
+ : if (pMaskPicture->componentAlpha &&
+ : PICT_FORMAT_RGB(pMaskPicture->format)) {
+ : if (i830_blend_op[op].src_alpha)
+ : cblend |= (TB0C_ARG2_SEL_TEXEL1 |
+ : TB0C_ARG1_REPLICATE_ALPHA);
+ : else
+ : cblend |= TB0C_ARG2_SEL_TEXEL1;
+ : } else {
+ : if (PICT_FORMAT_A(pMaskPicture->format) != 0)
+ : cblend |= (TB0C_ARG2_SEL_TEXEL1 |
+ : TB0C_ARG2_REPLICATE_ALPHA);
+ : else
+ : cblend |= TB0C_ARG2_SEL_ONE;
+ : }
+ : if (PICT_FORMAT_A(pMaskPicture->format) != 0)
+ : ablend |= TB0A_ARG2_SEL_TEXEL1;
+ : else
+ : ablend |= TB0A_ARG2_SEL_ONE;
+ : } else {
+ : cblend |= TB0C_ARG2_SEL_ONE;
+ : ablend |= TB0A_ARG2_SEL_ONE;
+ : }
+ :
+ : OUT_RING(_3DSTATE_LOAD_STATE_IMMEDIATE_2 |
+ : LOAD_TEXTURE_BLEND_STAGE(0)|1);
+ : OUT_RING(cblend);
+ : OUT_RING(ablend);
+ : OUT_RING(0);
+ :
+ : blendctl = i830_get_blend_cntl(op, pMaskPicture, pDstPicture->format);
+ : OUT_RING(_3DSTATE_INDPT_ALPHA_BLEND_CMD | DISABLE_INDPT_ALPHA_BLEND);
+ : OUT_RING(MI_NOOP);
+ : OUT_RING(_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(8) | 0);
+ : OUT_RING(S8_ENABLE_COLOR_BLEND | S8_BLENDFUNC_ADD | blendctl |
+ : S8_ENABLE_COLOR_BUFFER_WRITE);
+ :
+ : OUT_RING(_3DSTATE_ENABLES_1_CMD | DISABLE_LOGIC_OP |
+ : DISABLE_STENCIL_TEST | DISABLE_DEPTH_BIAS |
+ : DISABLE_SPEC_ADD | DISABLE_FOG | DISABLE_ALPHA_TEST |
+ : ENABLE_COLOR_BLEND | DISABLE_DEPTH_TEST);
+ : /* We have to explicitly say we don't want write disabled */
+ : OUT_RING(_3DSTATE_ENABLES_2_CMD | ENABLE_COLOR_MASK |
+ : DISABLE_STENCIL_WRITE | ENABLE_TEX_CACHE |
+ : DISABLE_DITHER | ENABLE_COLOR_WRITE |
+ : DISABLE_DEPTH_WRITE);
+ : ADVANCE_LP_RING();
+ : }
+ :
+ :#ifdef I830DEBUG
+ : Error("try to sync to show any errors...");
+ : I830Sync(pScrn);
+ :#endif
+ :
+ : return TRUE;
+ :}
+ :
+ :
+ :/**
+ : * Do a single rectangle composite operation.
+ : *
+ : * This function is shared between i830 and i915 generation code.
+ : */
+ :void
+ :i830_composite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY,
+ : int dstX, int dstY, int w, int h)
+ :{
+ : ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
+ : I830Ptr pI830 = I830PTR(pScrn);
+ : Bool has_mask;
+ : float src_x[3], src_y[3], mask_x[3], mask_y[3];
+ :
+ : i830_get_transformed_coordinates(srcX, srcY,
+ : pI830->transform[0],
+ : &src_x[0], &src_y[0]);
+ : i830_get_transformed_coordinates(srcX, srcY + h,
+ : pI830->transform[0],
+ : &src_x[1], &src_y[1]);
+ : i830_get_transformed_coordinates(srcX + w, srcY + h,
+ : pI830->transform[0],
+ : &src_x[2], &src_y[2]);
+ :
+ : if (pI830->scale_units[1][0] == -1 || pI830->scale_units[1][1] == -1) {
+ : has_mask = FALSE;
+ : } else {
+ : has_mask = TRUE;
+ : i830_get_transformed_coordinates(maskX, maskY,
+ : pI830->transform[1],
+ : &mask_x[0], &mask_y[0]);
+ : i830_get_transformed_coordinates(maskX, maskY + h,
+ : pI830->transform[1],
+ : &mask_x[1], &mask_y[1]);
+ : i830_get_transformed_coordinates(maskX + w, maskY + h,
+ : pI830->transform[1],
+ : &mask_x[2], &mask_y[2]);
+ : }
+ :
+ : {
+ : int vertex_count;
+ :
+ : if (has_mask)
+ : vertex_count = 3*6;
+ : else
+ : vertex_count = 3*4;
+ :
+ : BEGIN_LP_RING(6+vertex_count);
+ :
+ : OUT_RING(MI_NOOP);
+ : OUT_RING(MI_NOOP);
+ : OUT_RING(MI_NOOP);
+ : OUT_RING(MI_NOOP);
+ : OUT_RING(MI_NOOP);
+ :
+ : OUT_RING(PRIM3D_INLINE | PRIM3D_RECTLIST | (vertex_count-1));
+ :
+ : OUT_RING_F(-0.125 + dstX + w);
+ : OUT_RING_F(-0.125 + dstY + h);
+ : OUT_RING_F(src_x[2] / pI830->scale_units[0][0]);
+ : OUT_RING_F(src_y[2] / pI830->scale_units[0][1]);
+ : if (has_mask) {
+ : OUT_RING_F(mask_x[2] / pI830->scale_units[1][0]);
+ : OUT_RING_F(mask_y[2] / pI830->scale_units[1][1]);
+ : }
+ :
+ : OUT_RING_F(-0.125 + dstX);
+ : OUT_RING_F(-0.125 + dstY + h);
+ : OUT_RING_F(src_x[1] / pI830->scale_units[0][0]);
+ : OUT_RING_F(src_y[1] / pI830->scale_units[0][1]);
+ : if (has_mask) {
+ : OUT_RING_F(mask_x[1] / pI830->scale_units[1][0]);
+ : OUT_RING_F(mask_y[1] / pI830->scale_units[1][1]);
+ : }
+ :
+ : OUT_RING_F(-0.125 + dstX);
+ : OUT_RING_F(-0.125 + dstY);
+ : OUT_RING_F(src_x[0] / pI830->scale_units[0][0]);
+ : OUT_RING_F(src_y[0] / pI830->scale_units[0][1]);
+ : if (has_mask) {
+ : OUT_RING_F(mask_x[0] / pI830->scale_units[1][0]);
+ : OUT_RING_F(mask_y[0] / pI830->scale_units[1][1]);
+ : }
+ : ADVANCE_LP_RING();
+ : }
+ :}
+ :
+ :/**
+ : * Do any cleanup from the Composite operation.
+ : *
+ : * This is shared between i830 through i965.
+ : */
+ :void
+ :i830_done_composite(PixmapPtr pDst)
+ 2 0.0022 :{ /* i830_done_composite total: 3 0.0033 */
+ : /* NO-OP */
+ 1 0.0011 :}
+/*
+ * Total samples for file : "/home/cworth/src/pixman/pixman/pixman-edge.c"
+ *
+ * 3 0.0033
+ */
+
+
+ :/*
+ : * $Id$
+ : *
+ : * Copyright © 2004 Keith Packard
+ : *
+ : * 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 Keith Packard not be used in
+ : * advertising or publicity pertaining to distribution of the software without
+ : * specific, written prior permission. Keith Packard makes no
+ : * representations about the suitability of this software for any purpose. It
+ : * is provided "as is" without express or implied warranty.
+ : *
+ : * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ : * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ : * EVENT SHALL KEITH PACKARD 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.
+ : */
+ :#include <config.h>
+ :#include <string.h>
+ :#include "pixman.h"
+ :#include "pixman-private.h"
+ :
+ :#ifdef PIXMAN_FB_ACCESSORS
+ :#define PIXMAN_RASTERIZE_EDGES pixman_rasterize_edges_accessors
+ :#else
+ :#define PIXMAN_RASTERIZE_EDGES pixman_rasterize_edges_no_accessors
+ :#endif
+ :
+ :/*
+ : * 4 bit alpha
+ : */
+ :
+ :#define N_BITS 4
+ :#define rasterizeEdges fbRasterizeEdges4
+ :
+ :#if BITMAP_BIT_ORDER == LSBFirst
+ :#define Shift4(o) ((o) << 2)
+ :#else
+ :#define Shift4(o) ((1-(o)) << 2)
+ :#endif
+ :
+ :#define Get4(x,o) (((x) >> Shift4(o)) & 0xf)
+ :#define Put4(x,o,v) (((x) & ~(0xf << Shift4(o))) | (((v) & 0xf) << Shift4(o)))
+ :
+ :#define DefineAlpha(line,x) \
+ : uint8_t *__ap = (uint8_t *) line + ((x) >> 1); \
+ : int __ao = (x) & 1
+ :
+ :#define StepAlpha ((__ap += __ao), (__ao ^= 1))
+ :
+ :#define AddAlpha(a) { \
+ : uint8_t __o = READ(__ap); \
+ : uint8_t __a = (a) + Get4(__o, __ao); \
+ : WRITE(__ap, Put4 (__o, __ao, __a | (0 - ((__a) >> 4)))); \
+ : }
+ :
+ :#include "pixman-edge-imp.h"
+ :
+ :#undef AddAlpha
+ :#undef StepAlpha
+ :#undef DefineAlpha
+ :#undef rasterizeEdges
+ :#undef N_BITS
+ :
+ :
+ :/*
+ : * 1 bit alpha
+ : */
+ :
+ :#define N_BITS 1
+ :#define rasterizeEdges fbRasterizeEdges1
+ :
+ :#include "pixman-edge-imp.h"
+ :
+ :#undef rasterizeEdges
+ :#undef N_BITS
+ :
+ :/*
+ : * 8 bit alpha
+ : */
+ :
+ :static inline uint8_t
+ :clip255 (int x)
+ :{
+ : if (x > 255) return 255;
+ : return x;
+ :}
+ :
+ :#define add_saturate_8(buf,val,length) \
+ : do { \
+ : int i__ = (length); \
+ : uint8_t *buf__ = (buf); \
+ : int val__ = (val); \
+ : \
+ : while (i__--) \
+ : { \
+ : WRITE((buf__), clip255 (READ((buf__)) + (val__))); \
+ : (buf__)++; \
+ : } \
+ : } while (0)
+ :
+ :/*
+ : * We want to detect the case where we add the same value to a long
+ : * span of pixels. The triangles on the end are filled in while we
+ : * count how many sub-pixel scanlines contribute to the middle section.
+ : *
+ : * +--------------------------+
+ : * fill_height =| \ /
+ : * +------------------+
+ : * |================|
+ : * fill_start fill_end
+ : */
+ :static void
+ :fbRasterizeEdges8 (pixman_image_t *image,
+ : pixman_edge_t *l,
+ : pixman_edge_t *r,
+ : pixman_fixed_t t,
+ : pixman_fixed_t b)
+ :{
+ : pixman_fixed_t y = t;
+ : uint32_t *line;
+ : int fill_start = -1, fill_end = -1;
+ : int fill_size = 0;
+ : uint32_t *buf = (image)->bits.bits;
+ : uint32_t stride = (image)->bits.rowstride;
+ : uint32_t width = (image)->bits.width;
+ :
+ : line = buf + pixman_fixed_to_int (y) * stride;
+ :
+ : for (;;)
+ : {
+ : uint8_t *ap = (uint8_t *) line;
+ : pixman_fixed_t lx, rx;
+ : int lxi, rxi;
+ :
+ : /* clip X */
+ : lx = l->x;
+ : if (lx < 0)
+ : lx = 0;
+ : rx = r->x;
+ : if (pixman_fixed_to_int (rx) >= width)
+ : rx = pixman_int_to_fixed (width);
+ :
+ : /* Skip empty (or backwards) sections */
+ : if (rx > lx)
+ : {
+ : int lxs, rxs;
+ :
+ : /* Find pixel bounds for span. */
+ : lxi = pixman_fixed_to_int (lx);
+ : rxi = pixman_fixed_to_int (rx);
+ :
+ : /* Sample coverage for edge pixels */
+ : lxs = RenderSamplesX (lx, 8);
+ : rxs = RenderSamplesX (rx, 8);
+ :
+ : /* Add coverage across row */
+ : if (lxi == rxi)
+ : {
+ : WRITE(ap +lxi, clip255 (READ(ap + lxi) + rxs - lxs));
+ : }
+ : else
+ : {
+ : WRITE(ap + lxi, clip255 (READ(ap + lxi) + N_X_FRAC(8) - lxs));
+ :
+ : /* Move forward so that lxi/rxi is the pixel span */
+ : lxi++;
+ :
+ : /* Don't bother trying to optimize the fill unless
+ : * the span is longer than 4 pixels. */
+ : if (rxi - lxi > 4)
+ : {
+ : if (fill_start < 0)
+ : {
+ : fill_start = lxi;
+ : fill_end = rxi;
+ : fill_size++;
+ : }
+ : else
+ : {
+ : if (lxi >= fill_end || rxi < fill_start)
+ : {
+ : /* We're beyond what we saved, just fill it */
+ : add_saturate_8 (ap + fill_start,
+ : fill_size * N_X_FRAC(8),
+ : fill_end - fill_start);
+ : fill_start = lxi;
+ : fill_end = rxi;
+ : fill_size = 1;
+ : }
+ : else
+ : {
+ : /* Update fill_start */
+ : if (lxi > fill_start)
+ : {
+ : add_saturate_8 (ap + fill_start,
+ : fill_size * N_X_FRAC(8),
+ : lxi - fill_start);
+ : fill_start = lxi;
+ : }
+ : else if (lxi < fill_start)
+ : {
+ : add_saturate_8 (ap + lxi, N_X_FRAC(8),
+ : fill_start - lxi);
+ : }
+ :
+ : /* Update fill_end */
+ : if (rxi < fill_end)
+ : {
+ : add_saturate_8 (ap + rxi,
+ : fill_size * N_X_FRAC(8),
+ : fill_end - rxi);
+ : fill_end = rxi;
+ : }
+ : else if (fill_end < rxi)
+ : {
+ : add_saturate_8 (ap + fill_end,
+ : N_X_FRAC(8),
+ : rxi - fill_end);
+ : }
+ : fill_size++;
+ : }
+ : }
+ : }
+ : else
+ : {
+ : add_saturate_8 (ap + lxi, N_X_FRAC(8), rxi - lxi);
+ : }
+ :
+ : /* Do not add in a 0 alpha here. This check is
+ : * necessary to avoid a buffer overrun, (when rx
+ : * is exactly on a pixel boundary). */
+ : if (rxs)
+ : WRITE(ap + rxi, clip255 (READ(ap + rxi) + rxs));
+ : }
+ : }
+ :
+ : if (y == b) {
+ : /* We're done, make sure we clean up any remaining fill. */
+ : if (fill_start != fill_end) {
+ : if (fill_size == N_Y_FRAC(8))
+ : {
+ : MEMSET_WRAPPED (ap + fill_start, 0xff, fill_end - fill_start);
+ : }
+ : else
+ : {
+ : add_saturate_8 (ap + fill_start, fill_size * N_X_FRAC(8),
+ : fill_end - fill_start);
+ : }
+ : }
+ : break;
+ : }
+ :
+ : if (pixman_fixed_frac (y) != Y_FRAC_LAST(8))
+ : {
+ : RenderEdgeStepSmall (l);
+ : RenderEdgeStepSmall (r);
+ : y += STEP_Y_SMALL(8);
+ : }
+ : else
+ : {
+ : RenderEdgeStepBig (l);
+ : RenderEdgeStepBig (r);
+ : y += STEP_Y_BIG(8);
+ : if (fill_start != fill_end)
+ : {
+ : if (fill_size == N_Y_FRAC(8))
+ : {
+ : MEMSET_WRAPPED (ap + fill_start, 0xff, fill_end - fill_start);
+ : }
+ : else
+ : {
+ : add_saturate_8 (ap + fill_start, fill_size * N_X_FRAC(8),
+ : fill_end - fill_start);
+ : }
+ : fill_start = fill_end = -1;
+ : fill_size = 0;
+ : }
+ : line += stride;
+ : }
+ : }
+ :}
+ :
+ :#ifndef PIXMAN_FB_ACCESSORS
+ :static
+ :#endif
+ :void
+ :PIXMAN_RASTERIZE_EDGES (pixman_image_t *image,
+ : pixman_edge_t *l,
+ : pixman_edge_t *r,
+ : pixman_fixed_t t,
+ : pixman_fixed_t b)
+ :{
+ : switch (PIXMAN_FORMAT_BPP (image->bits.format))
+ : {
+ : case 1:
+ : fbRasterizeEdges1 (image, l, r, t, b);
+ : break;
+ : case 4:
+ : fbRasterizeEdges4 (image, l, r, t, b);
+ : break;
+ : case 8:
+ : fbRasterizeEdges8 (image, l, r, t, b);
+ : break;
+ : }
+ :}
+ :
+ :#ifndef PIXMAN_FB_ACCESSORS
+ :
+ :void
+ :pixman_rasterize_edges (pixman_image_t *image,
+ : pixman_edge_t *l,
+ : pixman_edge_t *r,
+ : pixman_fixed_t t,
+ : pixman_fixed_t b)
+ :{ /* pixman_rasterize_edges total: 5402 5.8849 */
+ 2 0.0022 : if (image->common.read_func || image->common.write_func)
+ : {
+ : return pixman_rasterize_edges_accessors (image, l, r, t, b);
+ : }
+ : else
+ : {
+ : return pixman_rasterize_edges_no_accessors (image, l, r, t, b);
+ : }
+ 1 0.0011 :}
+ :
+ :#endif
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/os/WaitFor.c"
+ *
+ * 2 0.0022
+ */
+
+
+ :/***********************************************************
+ :
+ :Copyright 1987, 1998 The Open Group
+ :
+ :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.
+ :
+ :The above copyright notice and this permission notice shall be included in
+ :all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ :IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ :FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ :OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ :AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ :CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of The Open Group shall not be
+ :used in advertising or otherwise to promote the sale, use or other dealings
+ :in this Software without prior written authorization from The Open Group.
+ :
+ :
+ :Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+ :
+ : All Rights Reserved
+ :
+ :Permission to use, copy, modify, and distribute this software and its
+ :documentation for any purpose and without fee is hereby granted,
+ :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 Digital not be
+ :used in advertising or publicity pertaining to distribution of the
+ :software without specific, written prior permission.
+ :
+ :DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ :ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ :DIGITAL 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.
+ :
+ :******************************************************************/
+ :
+ :
+ :/*****************************************************************
+ : * OS Dependent input routines:
+ : *
+ : * WaitForSomething
+ : * TimerForce, TimerSet, TimerCheck, TimerFree
+ : *
+ : *****************************************************************/
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#ifdef WIN32
+ :#include <X11/Xwinsock.h>
+ :#endif
+ :#include <X11/Xos.h> /* for strings, fcntl, time */
+ :#include <errno.h>
+ :#include <stdio.h>
+ :#include <X11/X.h>
+ :#include "misc.h"
+ :
+ :#include "osdep.h"
+ :#include <X11/Xpoll.h>
+ :#include "dixstruct.h"
+ :#include "opaque.h"
+ :#ifdef DPMSExtension
+ :#include "dpmsproc.h"
+ :#endif
+ :
+ :#ifdef WIN32
+ :/* Error codes from windows sockets differ from fileio error codes */
+ :#undef EINTR
+ :#define EINTR WSAEINTR
+ :#undef EINVAL
+ :#define EINVAL WSAEINVAL
+ :#undef EBADF
+ :#define EBADF WSAENOTSOCK
+ :/* Windows select does not set errno. Use GetErrno as wrapper for
+ : WSAGetLastError */
+ :#define GetErrno WSAGetLastError
+ :#else
+ :/* This is just a fallback to errno to hide the differences between unix and
+ : Windows in the code */
+ :#define GetErrno() errno
+ :#endif
+ :
+ :/* modifications by raphael */
+ :int
+ :mffs(fd_mask mask)
+ :{
+ : int i;
+ :
+ : if (!mask) return 0;
+ : i = 1;
+ : while (!(mask & 1))
+ : {
+ : i++;
+ : mask >>= 1;
+ : }
+ : return i;
+ :}
+ :
+ :#ifdef DPMSExtension
+ :#define DPMS_SERVER
+ :#include <X11/extensions/dpms.h>
+ :#endif
+ :
+ :struct _OsTimerRec {
+ : OsTimerPtr next;
+ : CARD32 expires;
+ : CARD32 delta;
+ : OsTimerCallback callback;
+ : pointer arg;
+ :};
+ :
+ :static void DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev);
+ :static void CheckAllTimers(void);
+ :static OsTimerPtr timers = NULL;
+ :
+ :/*****************
+ : * WaitForSomething:
+ : * Make the server suspend until there is
+ : * 1. data from clients or
+ : * 2. input events available or
+ : * 3. ddx notices something of interest (graphics
+ : * queue ready, etc.) or
+ : * 4. clients that have buffered replies/events are ready
+ : *
+ : * If the time between INPUT events is
+ : * greater than ScreenSaverTime, the display is turned off (or
+ : * saved, depending on the hardware). So, WaitForSomething()
+ : * has to handle this also (that's why the select() has a timeout.
+ : * For more info on ClientsWithInput, see ReadRequestFromClient().
+ : * pClientsReady is an array to store ready client->index values into.
+ : *****************/
+ :
+ :int
+ :WaitForSomething(int *pClientsReady)
+ :{ /* WaitForSomething total: 2 0.0022 */
+ : int i;
+ : struct timeval waittime, *wt;
+ : INT32 timeout = 0;
+ : fd_set clientsReadable;
+ : fd_set clientsWritable;
+ : int curclient;
+ : int selecterr;
+ : int nready;
+ : fd_set devicesReadable;
+ : CARD32 now = 0;
+ :#ifdef SMART_SCHEDULE
+ : Bool someReady = FALSE;
+ :#endif
+ :
+ : FD_ZERO(&clientsReadable);
+ :
+ : /* We need a while loop here to handle
+ : crashed connections and the screen saver timeout */
+ : while (1)
+ : {
+ : /* deal with any blocked jobs */
+ : if (workQueue)
+ : ProcessWorkQueue();
+ : if (XFD_ANYSET (&ClientsWithInput))
+ : {
+ :#ifdef SMART_SCHEDULE
+ : if (!SmartScheduleDisable)
+ : {
+ : someReady = TRUE;
+ : waittime.tv_sec = 0;
+ : waittime.tv_usec = 0;
+ : wt = &waittime;
+ : }
+ : else
+ :#endif
+ : {
+ : XFD_COPYSET (&ClientsWithInput, &clientsReadable);
+ : break;
+ : }
+ : }
+ :#ifdef SMART_SCHEDULE
+ : if (someReady)
+ : {
+ : XFD_COPYSET(&AllSockets, &LastSelectMask);
+ : XFD_UNSET(&LastSelectMask, &ClientsWithInput);
+ : }
+ : else
+ : {
+ :#endif
+ : wt = NULL;
+ : if (timers)
+ : {
+ : now = GetTimeInMillis();
+ : timeout = timers->expires - now;
+ : if (timeout > 0 && timeout > timers->delta + 250) {
+ : /* time has rewound. reset the timers. */
+ : CheckAllTimers();
+ : }
+ :
+ : if (timers) {
+ : timeout = timers->expires - now;
+ : if (timeout < 0)
+ : timeout = 0;
+ : waittime.tv_sec = timeout / MILLI_PER_SECOND;
+ : waittime.tv_usec = (timeout % MILLI_PER_SECOND) *
+ : (1000000 / MILLI_PER_SECOND);
+ : wt = &waittime;
+ : }
+ : }
+ : XFD_COPYSET(&AllSockets, &LastSelectMask);
+ :#ifdef SMART_SCHEDULE
+ : }
+ : SmartScheduleIdle = TRUE;
+ :#endif
+ : BlockHandler((pointer)&wt, (pointer)&LastSelectMask);
+ : if (NewOutputPending)
+ : FlushAllOutput();
+ : /* keep this check close to select() call to minimize race */
+ : if (dispatchException)
+ : i = -1;
+ : else if (AnyClientsWriteBlocked)
+ : {
+ : XFD_COPYSET(&ClientsWriteBlocked, &clientsWritable);
+ : i = Select (MaxClients, &LastSelectMask, &clientsWritable, NULL, wt);
+ : }
+ : else
+ : {
+ 1 0.0011 : i = Select (MaxClients, &LastSelectMask, NULL, NULL, wt);
+ : }
+ : selecterr = GetErrno();
+ : WakeupHandler(i, (pointer)&LastSelectMask);
+ :#ifdef SMART_SCHEDULE
+ : if (i >= 0)
+ : {
+ : SmartScheduleIdle = FALSE;
+ : SmartScheduleIdleCount = 0;
+ : if (SmartScheduleTimerStopped)
+ : (void) SmartScheduleStartTimer ();
+ : }
+ :#endif
+ : if (i <= 0) /* An error or timeout occurred */
+ : {
+ : if (dispatchException)
+ : return 0;
+ : if (i < 0)
+ : {
+ : if (selecterr == EBADF) /* Some client disconnected */
+ : {
+ : CheckConnections ();
+ : if (! XFD_ANYSET (&AllClients))
+ : return 0;
+ : }
+ : else if (selecterr == EINVAL)
+ : {
+ : FatalError("WaitForSomething(): select: errno=%d\n",
+ : selecterr);
+ : }
+ : else if (selecterr != EINTR)
+ : {
+ : ErrorF("WaitForSomething(): select: errno=%d\n",
+ : selecterr);
+ : }
+ : }
+ :#ifdef SMART_SCHEDULE
+ : else if (someReady)
+ : {
+ : /*
+ : * If no-one else is home, bail quickly
+ : */
+ : XFD_COPYSET(&ClientsWithInput, &LastSelectMask);
+ : XFD_COPYSET(&ClientsWithInput, &clientsReadable);
+ : break;
+ : }
+ :#endif
+ : if (*checkForInput[0] != *checkForInput[1])
+ : return 0;
+ :
+ : if (timers)
+ : {
+ : int expired = 0;
+ : now = GetTimeInMillis();
+ : if ((int) (timers->expires - now) <= 0)
+ : expired = 1;
+ :
+ : while (timers && (int) (timers->expires - now) <= 0)
+ : DoTimer(timers, now, &timers);
+ :
+ : if (expired)
+ : return 0;
+ : }
+ : }
+ : else
+ : {
+ : fd_set tmp_set;
+ :
+ : if (*checkForInput[0] == *checkForInput[1]) {
+ : if (timers)
+ : {
+ : int expired = 0;
+ : now = GetTimeInMillis();
+ : if ((int) (timers->expires - now) <= 0)
+ : expired = 1;
+ :
+ : while (timers && (int) (timers->expires - now) <= 0)
+ : DoTimer(timers, now, &timers);
+ :
+ : if (expired)
+ : return 0;
+ : }
+ : }
+ :#ifdef SMART_SCHEDULE
+ : if (someReady)
+ : XFD_ORSET(&LastSelectMask, &ClientsWithInput, &LastSelectMask);
+ :#endif
+ : if (AnyClientsWriteBlocked && XFD_ANYSET (&clientsWritable))
+ : {
+ : NewOutputPending = TRUE;
+ : XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending);
+ : XFD_UNSET(&ClientsWriteBlocked, &clientsWritable);
+ : if (! XFD_ANYSET(&ClientsWriteBlocked))
+ : AnyClientsWriteBlocked = FALSE;
+ : }
+ :
+ : XFD_ANDSET(&devicesReadable, &LastSelectMask, &EnabledDevices);
+ : XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients);
+ : XFD_ANDSET(&tmp_set, &LastSelectMask, &WellKnownConnections);
+ : if (XFD_ANYSET(&tmp_set))
+ : QueueWorkProc(EstablishNewConnections, NULL,
+ : (pointer)&LastSelectMask);
+ :
+ : if (XFD_ANYSET (&devicesReadable) || XFD_ANYSET (&clientsReadable))
+ : break;
+ :#ifdef WIN32
+ : /* Windows keyboard and mouse events are added to the input queue
+ : in Block- and WakupHandlers. There is no device to check if
+ : data is ready. So check here if new input is available */
+ : if (*checkForInput[0] != *checkForInput[1])
+ : return 0;
+ :#endif
+ : }
+ : }
+ :
+ : nready = 0;
+ : if (XFD_ANYSET (&clientsReadable))
+ : {
+ :#ifndef WIN32
+ : for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++)
+ : {
+ : int highest_priority = 0;
+ :
+ : while (clientsReadable.fds_bits[i])
+ : {
+ : int client_priority, client_index;
+ :
+ : curclient = ffs (clientsReadable.fds_bits[i]) - 1;
+ 1 0.0011 : client_index = /* raphael: modified */
+ : ConnectionTranslation[curclient + (i * (sizeof(fd_mask) * 8))];
+ :#else
+ : int highest_priority = 0;
+ : fd_set savedClientsReadable;
+ : XFD_COPYSET(&clientsReadable, &savedClientsReadable);
+ : for (i = 0; i < XFD_SETCOUNT(&savedClientsReadable); i++)
+ : {
+ : int client_priority, client_index;
+ :
+ : curclient = XFD_FD(&savedClientsReadable, i);
+ : client_index = GetConnectionTranslation(curclient);
+ :#endif
+ :#ifdef XSYNC
+ : /* We implement "strict" priorities.
+ : * Only the highest priority client is returned to
+ : * dix. If multiple clients at the same priority are
+ : * ready, they are all returned. This means that an
+ : * aggressive client could take over the server.
+ : * This was not considered a big problem because
+ : * aggressive clients can hose the server in so many
+ : * other ways :)
+ : */
+ : client_priority = clients[client_index]->priority;
+ : if (nready == 0 || client_priority > highest_priority)
+ : {
+ : /* Either we found the first client, or we found
+ : * a client whose priority is greater than all others
+ : * that have been found so far. Either way, we want
+ : * to initialize the list of clients to contain just
+ : * this client.
+ : */
+ : pClientsReady[0] = client_index;
+ : highest_priority = client_priority;
+ : nready = 1;
+ : }
+ : /* the following if makes sure that multiple same-priority
+ : * clients get batched together
+ : */
+ : else if (client_priority == highest_priority)
+ :#endif
+ : {
+ : pClientsReady[nready++] = client_index;
+ : }
+ :#ifndef WIN32
+ : clientsReadable.fds_bits[i] &= ~(((fd_mask)1L) << curclient);
+ : }
+ :#else
+ : FD_CLR(curclient, &clientsReadable);
+ :#endif
+ : }
+ : }
+ : return nready;
+ :}
+ :
+ :#if 0
+ :/*
+ : * This is not always a macro.
+ : */
+ :ANYSET(FdMask *src)
+ :{
+ : int i;
+ :
+ : for (i=0; i<mskcnt; i++)
+ : if (src[ i ])
+ : return (TRUE);
+ : return (FALSE);
+ :}
+ :#endif
+ :
+ :/* If time has rewound, re-run every affected timer.
+ : * Timers might drop out of the list, so we have to restart every time. */
+ :static void
+ :CheckAllTimers(void)
+ :{
+ : OsTimerPtr timer;
+ : CARD32 now;
+ :
+ :start:
+ : now = GetTimeInMillis();
+ :
+ : for (timer = timers; timer; timer = timer->next) {
+ : if (timer->expires - now > timer->delta + 250) {
+ : TimerForce(timer);
+ : goto start;
+ : }
+ : }
+ :}
+ :
+ :static void
+ :DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev)
+ :{
+ : CARD32 newTime;
+ :
+ : *prev = timer->next;
+ : timer->next = NULL;
+ : newTime = (*timer->callback)(timer, now, timer->arg);
+ : if (newTime)
+ : TimerSet(timer, 0, newTime, timer->callback, timer->arg);
+ :}
+ :
+ :_X_EXPORT OsTimerPtr
+ :TimerSet(OsTimerPtr timer, int flags, CARD32 millis,
+ : OsTimerCallback func, pointer arg)
+ :{
+ : register OsTimerPtr *prev;
+ : CARD32 now = GetTimeInMillis();
+ :
+ : if (!timer)
+ : {
+ : timer = (OsTimerPtr)xalloc(sizeof(struct _OsTimerRec));
+ : if (!timer)
+ : return NULL;
+ : }
+ : else
+ : {
+ : for (prev = &timers; *prev; prev = &(*prev)->next)
+ : {
+ : if (*prev == timer)
+ : {
+ : *prev = timer->next;
+ : if (flags & TimerForceOld)
+ : (void)(*timer->callback)(timer, now, timer->arg);
+ : break;
+ : }
+ : }
+ : }
+ : if (!millis)
+ : return timer;
+ : if (flags & TimerAbsolute) {
+ : timer->delta = millis - now;
+ : }
+ : else {
+ : timer->delta = millis;
+ : millis += now;
+ : }
+ : timer->expires = millis;
+ : timer->callback = func;
+ : timer->arg = arg;
+ : if ((int) (millis - now) <= 0)
+ : {
+ : timer->next = NULL;
+ : millis = (*timer->callback)(timer, now, timer->arg);
+ : if (!millis)
+ : return timer;
+ : }
+ : for (prev = &timers;
+ : *prev && (int) ((*prev)->expires - millis) <= 0;
+ : prev = &(*prev)->next)
+ : ;
+ : timer->next = *prev;
+ : *prev = timer;
+ : return timer;
+ :}
+ :
+ :Bool
+ :TimerForce(OsTimerPtr timer)
+ :{
+ : OsTimerPtr *prev;
+ :
+ : for (prev = &timers; *prev; prev = &(*prev)->next)
+ : {
+ : if (*prev == timer)
+ : {
+ : DoTimer(timer, GetTimeInMillis(), prev);
+ : return TRUE;
+ : }
+ : }
+ : return FALSE;
+ :}
+ :
+ :
+ :_X_EXPORT void
+ :TimerCancel(OsTimerPtr timer)
+ :{
+ : OsTimerPtr *prev;
+ :
+ : if (!timer)
+ : return;
+ : for (prev = &timers; *prev; prev = &(*prev)->next)
+ : {
+ : if (*prev == timer)
+ : {
+ : *prev = timer->next;
+ : break;
+ : }
+ : }
+ :}
+ :
+ :_X_EXPORT void
+ :TimerFree(OsTimerPtr timer)
+ :{
+ : if (!timer)
+ : return;
+ : TimerCancel(timer);
+ : xfree(timer);
+ :}
+ :
+ :void
+ :TimerCheck(void)
+ :{
+ : CARD32 now = GetTimeInMillis();
+ :
+ : while (timers && (int) (timers->expires - now) <= 0)
+ : DoTimer(timers, now, &timers);
+ :}
+ :
+ :void
+ :TimerInit(void)
+ :{
+ : OsTimerPtr timer;
+ :
+ : while ((timer = timers))
+ : {
+ : timers = timer->next;
+ : xfree(timer);
+ : }
+ :}
+ :
+ :#ifdef DPMSExtension
+ :
+ :#define DPMS_CHECK_MODE(mode,time)\
+ : if (time > 0 && DPMSPowerLevel < mode && timeout >= time)\
+ : DPMSSet(mode);
+ :
+ :#define DPMS_CHECK_TIMEOUT(time)\
+ : if (time > 0 && (time - timeout) > 0)\
+ : return time - timeout;
+ :
+ :static CARD32
+ :NextDPMSTimeout(INT32 timeout)
+ :{
+ : /*
+ : * Return the amount of time remaining until we should set
+ : * the next power level. Fallthroughs are intentional.
+ : */
+ : switch (DPMSPowerLevel)
+ : {
+ : case DPMSModeOn:
+ : DPMS_CHECK_TIMEOUT(DPMSStandbyTime)
+ :
+ : case DPMSModeStandby:
+ : DPMS_CHECK_TIMEOUT(DPMSSuspendTime)
+ :
+ : case DPMSModeSuspend:
+ : DPMS_CHECK_TIMEOUT(DPMSOffTime)
+ :
+ : default: /* DPMSModeOff */
+ : return 0;
+ : }
+ :}
+ :#endif /* DPMSExtension */
+ :
+ :static CARD32
+ :ScreenSaverTimeoutExpire(OsTimerPtr timer,CARD32 now,pointer arg)
+ :{
+ : INT32 timeout = now - lastDeviceEventTime.milliseconds;
+ : CARD32 nextTimeout = 0;
+ :
+ :#ifdef DPMSExtension
+ : /*
+ : * Check each mode lowest to highest, since a lower mode can
+ : * have the same timeout as a higher one.
+ : */
+ : if (DPMSEnabled)
+ : {
+ : DPMS_CHECK_MODE(DPMSModeOff, DPMSOffTime)
+ : DPMS_CHECK_MODE(DPMSModeSuspend, DPMSSuspendTime)
+ : DPMS_CHECK_MODE(DPMSModeStandby, DPMSStandbyTime)
+ :
+ : nextTimeout = NextDPMSTimeout(timeout);
+ : }
+ :
+ : /*
+ : * Only do the screensaver checks if we're not in a DPMS
+ : * power saving mode
+ : */
+ : if (DPMSPowerLevel != DPMSModeOn)
+ : return nextTimeout;
+ :#endif /* DPMSExtension */
+ :
+ : if (!ScreenSaverTime)
+ : return nextTimeout;
+ :
+ : if (timeout < ScreenSaverTime)
+ : {
+ : return nextTimeout > 0 ?
+ : min(ScreenSaverTime - timeout, nextTimeout) :
+ : ScreenSaverTime - timeout;
+ : }
+ :
+ : ResetOsBuffers(); /* not ideal, but better than nothing */
+ : SaveScreens(SCREEN_SAVER_ON, ScreenSaverActive);
+ :
+ : if (ScreenSaverInterval > 0)
+ : {
+ : nextTimeout = nextTimeout > 0 ?
+ : min(ScreenSaverInterval, nextTimeout) :
+ : ScreenSaverInterval;
+ : }
+ :
+ : return nextTimeout;
+ :}
+ :
+ :static OsTimerPtr ScreenSaverTimer = NULL;
+ :
+ :void
+ :FreeScreenSaverTimer(void)
+ :{
+ : if (ScreenSaverTimer) {
+ : TimerFree(ScreenSaverTimer);
+ : ScreenSaverTimer = NULL;
+ : }
+ :}
+ :
+ :void
+ :SetScreenSaverTimer(void)
+ :{
+ : CARD32 timeout = 0;
+ :
+ :#ifdef DPMSExtension
+ : if (DPMSEnabled)
+ : {
+ : /*
+ : * A higher DPMS level has a timeout that's either less
+ : * than or equal to that of a lower DPMS level.
+ : */
+ : if (DPMSStandbyTime > 0)
+ : timeout = DPMSStandbyTime;
+ :
+ : else if (DPMSSuspendTime > 0)
+ : timeout = DPMSSuspendTime;
+ :
+ : else if (DPMSOffTime > 0)
+ : timeout = DPMSOffTime;
+ : }
+ :#endif
+ :
+ : if (ScreenSaverTime > 0)
+ : {
+ : timeout = timeout > 0 ?
+ : min(ScreenSaverTime, timeout) :
+ : ScreenSaverTime;
+ : }
+ :
+ :#ifdef SCREENSAVER
+ : if (timeout && !screenSaverSuspended) {
+ :#else
+ : if (timeout) {
+ :#endif
+ : ScreenSaverTimer = TimerSet(ScreenSaverTimer, 0, timeout,
+ : ScreenSaverTimeoutExpire, NULL);
+ : }
+ : else if (ScreenSaverTimer) {
+ : FreeScreenSaverTimer();
+ : }
+ :}
+ :
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/fb/fballpriv.c"
+ *
+ * 2 0.0022
+ */
+
+
+ :/*
+ : * Copyright © 1998 Keith Packard
+ : *
+ : * 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 Keith Packard not be used in
+ : * advertising or publicity pertaining to distribution of the software without
+ : * specific, written prior permission. Keith Packard makes no
+ : * representations about the suitability of this software for any purpose. It
+ : * is provided "as is" without express or implied warranty.
+ : *
+ : * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ : * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ : * EVENT SHALL KEITH PACKARD 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.
+ : */
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include "fb.h"
+ :
+ :#ifdef FB_SCREEN_PRIVATE
+ :int fbScreenPrivateIndex;
+ :int fbGetScreenPrivateIndex(void)
+ :{
+ : return fbScreenPrivateIndex;
+ :}
+ :#endif
+ :int fbGCPrivateIndex;
+ :int fbGetGCPrivateIndex(void)
+ 2 0.0022 :{ /* fbGetGCPrivateIndex total: 2 0.0022 */
+ : return fbGCPrivateIndex;
+ :}
+ :#ifndef FB_NO_WINDOW_PIXMAPS
+ :int fbWinPrivateIndex;
+ :int fbGetWinPrivateIndex(void)
+ :{
+ : return fbWinPrivateIndex;
+ :}
+ :#endif
+ :int fbGeneration;
+ :
+ :#ifdef FB_OLD_SCREEN
+ :#define miAllocateGCPrivateIndex() AllocateGCPrivateIndex()
+ :#endif
+ :
+ :Bool
+ :fbAllocatePrivates(ScreenPtr pScreen, int *pGCIndex)
+ :{
+ : if (fbGeneration != serverGeneration)
+ : {
+ : fbGCPrivateIndex = miAllocateGCPrivateIndex ();
+ :#ifndef FB_NO_WINDOW_PIXMAPS
+ : fbWinPrivateIndex = AllocateWindowPrivateIndex();
+ :#endif
+ :#ifdef FB_SCREEN_PRIVATE
+ : fbScreenPrivateIndex = AllocateScreenPrivateIndex ();
+ : if (fbScreenPrivateIndex == -1)
+ : return FALSE;
+ :#endif
+ :
+ : fbGeneration = serverGeneration;
+ : }
+ : if (pGCIndex)
+ : *pGCIndex = fbGCPrivateIndex;
+ : if (!AllocateGCPrivate(pScreen, fbGCPrivateIndex, sizeof(FbGCPrivRec)))
+ : return FALSE;
+ :#ifndef FB_NO_WINDOW_PIXMAPS
+ : if (!AllocateWindowPrivate(pScreen, fbWinPrivateIndex, 0))
+ : return FALSE;
+ :#endif
+ :#ifdef FB_SCREEN_PRIVATE
+ : {
+ : FbScreenPrivPtr pScreenPriv;
+ :
+ : pScreenPriv = (FbScreenPrivPtr) xalloc (sizeof (FbScreenPrivRec));
+ : if (!pScreenPriv)
+ : return FALSE;
+ : pScreen->devPrivates[fbScreenPrivateIndex].ptr = (pointer) pScreenPriv;
+ : }
+ :#endif
+ : return TRUE;
+ :}
+ :
+ :#ifdef FB_ACCESS_WRAPPER
+ :ReadMemoryProcPtr wfbReadMemory;
+ :WriteMemoryProcPtr wfbWriteMemory;
+ :#endif
+/*
+ * Total samples for file : "/home/cworth/opt/xorg//include/X11/Xtrans/Xtranssock.c"
+ *
+ * 2 0.0022
+ */
+
+
+ :/* $XdotOrg: lib/xtrans/Xtranssock.c,v 1.11 2005/11/08 06:33:26 jkj Exp $ */
+ :/* $Xorg: Xtranssock.c,v 1.11 2001/02/09 02:04:06 xorgcvs Exp $ */
+ :/*
+ :
+ :Copyright 1993, 1994, 1998 The Open Group
+ :Copyright 2002 Sun Microsystems, Inc. All rights reserved.
+ :
+ :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.
+ :
+ :The above copyright notice and this permission notice shall be included
+ :in all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ :OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ :MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ :IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ :OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ :ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ :OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of the copyright holders shall
+ :not be used in advertising or otherwise to promote the sale, use or
+ :other dealings in this Software without prior written authorization
+ :from the copyright holders.
+ :
+ :*/
+ :/* $XFree86: xc/lib/xtrans/Xtranssock.c,v 3.68 2004/01/07 04:28:02 dawes Exp $ */
+ :
+ :/* Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA
+ : *
+ : * All Rights Reserved
+ : *
+ : * Permission to use, copy, modify, and distribute this software and its
+ : * documentation for any purpose and without fee is hereby granted, 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 NCR not be used in advertising
+ : * or publicity pertaining to distribution of the software without specific,
+ : * written prior permission. NCR makes no representations about the
+ : * suitability of this software for any purpose. It is provided "as is"
+ : * without express or implied warranty.
+ : *
+ : * NCR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ : * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ : * NO EVENT SHALL NCR 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.
+ : */
+ :
+ :#include <ctype.h>
+ :#ifdef XTHREADS
+ :#include <X11/Xthreads.h>
+ :#endif
+ :
+ :#ifndef WIN32
+ :
+ :#if defined(TCPCONN) || defined(UNIXCONN)
+ :#include <sys/socket.h>
+ :#include <netinet/in.h>
+ :#include <arpa/inet.h>
+ :#endif
+ :
+ :#if defined(TCPCONN) || defined(UNIXCONN)
+ :#define X_INCLUDE_NETDB_H
+ :#define XOS_USE_NO_LOCKING
+ :#include <X11/Xos_r.h>
+ :#endif
+ :
+ :#ifdef UNIXCONN
+ :#ifndef X_NO_SYS_UN
+ :#ifndef Lynx
+ :#include <sys/un.h>
+ :#else
+ :#include <un.h>
+ :#endif
+ :#endif
+ :#include <sys/stat.h>
+ :#endif
+ :
+ :#if defined(hpux) || (defined(MOTOROLA) && defined(SYSV))
+ :#define NO_TCP_H
+ :#endif
+ :
+ :#ifndef NO_TCP_H
+ :#if defined(__osf__) || defined(linux) || defined(__GLIBC__) || defined(AIXV5)
+ :#include <sys/param.h>
+ :#endif /* osf */
+ :#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
+ :#include <sys/param.h>
+ :#include <machine/endian.h>
+ :#endif /* __NetBSD__ || __OpenBSD__ || __FreeBSD__ || __DragonFly__ */
+ :#include <netinet/tcp.h>
+ :#endif /* !NO_TCP_H */
+ :
+ :#include <sys/ioctl.h>
+ :#if defined(SVR4) && !defined(DGUX) && !defined(_SEQUENT_)
+ :#include <sys/filio.h>
+ :#endif
+ :
+ :#if (defined(i386) && defined(SYSV)) && !defined(SCO325) && !defined(sun)
+ :#include <net/errno.h>
+ :#endif
+ :
+ :#if (defined(i386) && defined(SYSV)) && (!defined(ISC) || !defined(I_NREAD) || defined(SCO325)) || defined(_SEQUENT_)
+ :#include <sys/stropts.h>
+ :#endif
+ :
+ :#else /* !WIN32 */
+ :
+ :#include <X11/Xwinsock.h>
+ :#include <X11/Xwindows.h>
+ :#include <X11/Xw32defs.h>
+ :#undef close
+ :#define close closesocket
+ :#define ECONNREFUSED WSAECONNREFUSED
+ :#define EADDRINUSE WSAEADDRINUSE
+ :#define EPROTOTYPE WSAEPROTOTYPE
+ :#undef EWOULDBLOCK
+ :#define EWOULDBLOCK WSAEWOULDBLOCK
+ :#define EINPROGRESS WSAEINPROGRESS
+ :#undef EINTR
+ :#define EINTR WSAEINTR
+ :#define X_INCLUDE_NETDB_H
+ :#define XOS_USE_MTSAFE_NETDBAPI
+ :#include <X11/Xos_r.h>
+ :#endif /* WIN32 */
+ :
+ :#if defined(SO_DONTLINGER) && defined(SO_LINGER)
+ :#undef SO_DONTLINGER
+ :#endif
+ :
+ :#if defined(__UNIXOS2__)
+ :#if defined(NOT_EMX09A)
+ :static int IBMsockInit = 0;
+ :#define SocketInitOnce()\
+ : if (!IBMsockInit) {\
+ : sock_init();\
+ : IBMsockInit = 1;\
+ : }
+ :#undef EINTR
+ :#define EINTR SOCEINTR
+ :#undef EINVAL
+ :#define EINVAL SOCEINVAL
+ :#undef errno
+ :#define errno sock_errno()
+ :#undef close
+ :#define close soclose
+ :#undef ioctl
+ :#define ioctl sockioctl
+ :#else
+ :#define SocketInitOnce() /**/
+ :#endif
+ :/* this is still not there */
+ :#define SOCKET int
+ :#else
+ :/* others don't need this */
+ :#define SocketInitOnce() /**/
+ :#endif
+ :
+ :#define MIN_BACKLOG 128
+ :#ifdef SOMAXCONN
+ :#if SOMAXCONN > MIN_BACKLOG
+ :#define BACKLOG SOMAXCONN
+ :#endif
+ :#endif
+ :#ifndef BACKLOG
+ :#define BACKLOG MIN_BACKLOG
+ :#endif
+ :/*
+ : * This is the Socket implementation of the X Transport service layer
+ : *
+ : * This file contains the implementation for both the UNIX and INET domains,
+ : * and can be built for either one, or both.
+ : *
+ : */
+ :
+ :typedef struct _Sockettrans2dev {
+ : char *transname;
+ : int family;
+ : int devcotsname;
+ : int devcltsname;
+ : int protocol;
+ :} Sockettrans2dev;
+ :
+ :static Sockettrans2dev Sockettrans2devtab[] = {
+ :#ifdef TCPCONN
+ : {"inet",AF_INET,SOCK_STREAM,SOCK_DGRAM,0},
+ :#if !defined(IPv6) || !defined(AF_INET6)
+ : {"tcp",AF_INET,SOCK_STREAM,SOCK_DGRAM,0},
+ :#else /* IPv6 */
+ : {"tcp",AF_INET6,SOCK_STREAM,SOCK_DGRAM,0},
+ : {"tcp",AF_INET,SOCK_STREAM,SOCK_DGRAM,0}, /* fallback */
+ : {"inet6",AF_INET6,SOCK_STREAM,SOCK_DGRAM,0},
+ :#endif
+ :#endif /* TCPCONN */
+ :#ifdef UNIXCONN
+ : {"unix",AF_UNIX,SOCK_STREAM,SOCK_DGRAM,0},
+ :#if !defined(LOCALCONN)
+ : {"local",AF_UNIX,SOCK_STREAM,SOCK_DGRAM,0},
+ :#endif /* !LOCALCONN */
+ :#endif /* UNIXCONN */
+ :};
+ :
+ :#define NUMSOCKETFAMILIES (sizeof(Sockettrans2devtab)/sizeof(Sockettrans2dev))
+ :
+ :#ifdef TCPCONN
+ :static int TRANS(SocketINETClose) (XtransConnInfo ciptr);
+ :#endif
+ :
+ :#ifdef UNIXCONN
+ :
+ :#ifdef hpux
+ :
+ :#if defined(X11_t)
+ :#define UNIX_PATH "/usr/spool/sockets/X11/"
+ :#define UNIX_DIR "/usr/spool/sockets/X11"
+ :#define OLD_UNIX_PATH "/tmp/.X11-unix/X"
+ :#endif /* X11_t */
+ :#if defined(XIM_t)
+ :#define UNIX_PATH "/usr/spool/sockets/XIM/"
+ :#define UNIX_DIR "/usr/spool/sockets/XIM"
+ :#define OLD_UNIX_PATH "/tmp/.XIM-unix/XIM"
+ :#endif /* XIM_t */
+ :#if defined(FS_t) || defined(FONT_t)
+ :#define UNIX_PATH "/usr/spool/sockets/fontserv/"
+ :#define UNIX_DIR "/usr/spool/sockets/fontserv"
+ :#endif /* FS_t || FONT_t */
+ :#if defined(ICE_t)
+ :#define UNIX_PATH "/usr/spool/sockets/ICE/"
+ :#define UNIX_DIR "/usr/spool/sockets/ICE"
+ :#endif /* ICE_t */
+ :#if defined(TEST_t)
+ :#define UNIX_PATH "/usr/spool/sockets/xtrans_test/"
+ :#define UNIX_DIR "/usr/spool/sockets/xtrans_test"
+ :#endif
+ :#if defined(LBXPROXY_t)
+ :#define UNIX_PATH "/usr/spool/sockets/X11/"
+ :#define UNIX_DIR "/usr/spool/sockets/X11"
+ :#endif
+ :
+ :#else /* !hpux */
+ :
+ :#if defined(X11_t)
+ :#define UNIX_PATH "/tmp/.X11-unix/X"
+ :#define UNIX_DIR "/tmp/.X11-unix"
+ :#endif /* X11_t */
+ :#if defined(XIM_t)
+ :#define UNIX_PATH "/tmp/.XIM-unix/XIM"
+ :#define UNIX_DIR "/tmp/.XIM-unix"
+ :#endif /* XIM_t */
+ :#if defined(FS_t) || defined(FONT_t)
+ :#define UNIX_PATH "/tmp/.font-unix/fs"
+ :#define UNIX_DIR "/tmp/.font-unix"
+ :#endif /* FS_t || FONT_t */
+ :#if defined(ICE_t)
+ :#define UNIX_PATH "/tmp/.ICE-unix/"
+ :#define UNIX_DIR "/tmp/.ICE-unix"
+ :#endif /* ICE_t */
+ :#if defined(TEST_t)
+ :#define UNIX_PATH "/tmp/.Test-unix/test"
+ :#define UNIX_DIR "/tmp/.Test-unix"
+ :#endif
+ :#if defined(LBXPROXY_t)
+ :#define UNIX_PATH "/tmp/.X11-unix/X"
+ :#define UNIX_DIR "/tmp/.X11-unix"
+ :#endif
+ :
+ :#endif /* hpux */
+ :
+ :#endif /* UNIXCONN */
+ :
+ :#define PORTBUFSIZE 32
+ :
+ :#ifndef MAXHOSTNAMELEN
+ :#define MAXHOSTNAMELEN 255
+ :#endif
+ :
+ :/*
+ : * This provides compatibility for apps linked against system libraries
+ : * that don't have IPv6 support.
+ : */
+ :#if defined(IPv6) && defined(AF_INET6)
+ :static const struct in6_addr local_in6addr_any = IN6ADDR_ANY_INIT;
+ :#pragma weak in6addr_any = local_in6addr_any
+ :#ifndef __USLC__
+ :#pragma weak getaddrinfo
+ :#endif
+ :static int haveIPv6 = 1;
+ :#endif
+ :
+ :/*
+ : * These are some utility function used by the real interface function below.
+ : */
+ :
+ :static int
+ :TRANS(SocketSelectFamily) (int first, char *family)
+ :
+ :{
+ : int i;
+ :
+ : PRMSG (3,"SocketSelectFamily(%s)\n", family, 0, 0);
+ :
+ : for (i = first + 1; i < NUMSOCKETFAMILIES;i++)
+ : {
+ : if (!strcmp (family, Sockettrans2devtab[i].transname))
+ : return i;
+ : }
+ :
+ : return (first == -1 ? -2 : -1);
+ :}
+ :
+ :
+ :/*
+ : * This function gets the local address of the socket and stores it in the
+ : * XtransConnInfo structure for the connection.
+ : */
+ :
+ :static int
+ :TRANS(SocketINETGetAddr) (XtransConnInfo ciptr)
+ :
+ :{
+ :#if defined(IPv6) && defined(AF_INET6)
+ : struct sockaddr_storage socknamev6;
+ :#endif
+ : struct sockaddr_in socknamev4;
+ : void *socknamePtr;
+ :#if defined(SVR4) || defined(__SCO__)
+ : size_t namelen;
+ :#else
+ : int namelen;
+ :#endif
+ :
+ : PRMSG (3,"SocketINETGetAddr(%p)\n", ciptr, 0, 0);
+ :
+ :#if defined(IPv6) && defined(AF_INET6)
+ : if (haveIPv6)
+ : {
+ : namelen = sizeof(socknamev6);
+ : socknamePtr = &socknamev6;
+ : }
+ : else
+ :#endif
+ : {
+ : namelen = sizeof(socknamev4);
+ : socknamePtr = &socknamev4;
+ : }
+ :
+ : bzero(socknamePtr, namelen);
+ :
+ : if (getsockname (ciptr->fd,(struct sockaddr *) socknamePtr,
+ : (void *)&namelen) < 0)
+ : {
+ :#ifdef WIN32
+ : errno = WSAGetLastError();
+ :#endif
+ : PRMSG (1,"SocketINETGetAddr: getsockname() failed: %d\n",
+ : EGET(),0, 0);
+ : return -1;
+ : }
+ :
+ : /*
+ : * Everything looks good: fill in the XtransConnInfo structure.
+ : */
+ :
+ : if ((ciptr->addr = (char *) xalloc (namelen)) == NULL)
+ : {
+ : PRMSG (1,
+ : "SocketINETGetAddr: Can't allocate space for the addr\n",
+ : 0, 0, 0);
+ : return -1;
+ : }
+ :
+ :#if defined(IPv6) && defined(AF_INET6)
+ : if (haveIPv6)
+ : {
+ : ciptr->family = ((struct sockaddr *)socknamePtr)->sa_family;
+ : }
+ : else
+ :#endif
+ : {
+ : ciptr->family = socknamev4.sin_family;
+ : }
+ : ciptr->addrlen = namelen;
+ : memcpy (ciptr->addr, socknamePtr, ciptr->addrlen);
+ :
+ : return 0;
+ :}
+ :
+ :
+ :/*
+ : * This function gets the remote address of the socket and stores it in the
+ : * XtransConnInfo structure for the connection.
+ : */
+ :
+ :static int
+ :TRANS(SocketINETGetPeerAddr) (XtransConnInfo ciptr)
+ :
+ :{
+ :#if defined(IPv6) && defined(AF_INET6)
+ : struct sockaddr_storage socknamev6;
+ :#endif
+ : struct sockaddr_in socknamev4;
+ : void *socknamePtr;
+ :#if defined(SVR4) || defined(__SCO__)
+ : size_t namelen;
+ :#else
+ : int namelen;
+ :#endif
+ :
+ :#if defined(IPv6) && defined(AF_INET6)
+ : if (haveIPv6 && ciptr->family == AF_INET6)
+ : {
+ : namelen = sizeof(socknamev6);
+ : socknamePtr = &socknamev6;
+ : }
+ : else
+ :#endif
+ : {
+ : namelen = sizeof(socknamev4);
+ : socknamePtr = &socknamev4;
+ : }
+ :
+ : bzero(socknamePtr, namelen);
+ :
+ : PRMSG (3,"SocketINETGetPeerAddr(%p)\n", ciptr, 0, 0);
+ :
+ : if (getpeername (ciptr->fd, (struct sockaddr *) socknamePtr,
+ : (void *)&namelen) < 0)
+ : {
+ :#ifdef WIN32
+ : errno = WSAGetLastError();
+ :#endif
+ : PRMSG (1,"SocketINETGetPeerAddr: getpeername() failed: %d\n",
+ : EGET(), 0, 0);
+ : return -1;
+ : }
+ :
+ : /*
+ : * Everything looks good: fill in the XtransConnInfo structure.
+ : */
+ :
+ : if ((ciptr->peeraddr = (char *) xalloc (namelen)) == NULL)
+ : {
+ : PRMSG (1,
+ : "SocketINETGetPeerAddr: Can't allocate space for the addr\n",
+ : 0, 0, 0);
+ : return -1;
+ : }
+ :
+ : ciptr->peeraddrlen = namelen;
+ : memcpy (ciptr->peeraddr, socknamePtr, ciptr->peeraddrlen);
+ :
+ : return 0;
+ :}
+ :
+ :
+ :static XtransConnInfo
+ :TRANS(SocketOpen) (int i, int type)
+ :
+ :{
+ : XtransConnInfo ciptr;
+ :
+ : PRMSG (3,"SocketOpen(%d,%d)\n", i, type, 0);
+ :
+ :#if defined(IPv6) && defined(AF_INET6)
+ : if (getaddrinfo == NULL)
+ : haveIPv6 = 0;
+ :
+ : if (!haveIPv6 && Sockettrans2devtab[i].family == AF_INET6)
+ : return NULL;
+ :#endif
+ :
+ : if ((ciptr = (XtransConnInfo) xcalloc (
+ : 1, sizeof(struct _XtransConnInfo))) == NULL)
+ : {
+ : PRMSG (1, "SocketOpen: malloc failed\n", 0, 0, 0);
+ : return NULL;
+ : }
+ :
+ : if ((ciptr->fd = socket(Sockettrans2devtab[i].family, type,
+ : Sockettrans2devtab[i].protocol)) < 0
+ :#ifndef WIN32
+ :#if (defined(X11_t) && !defined(USE_POLL)) || defined(FS_t) || defined(FONT_t)
+ : || ciptr->fd >= TRANS_OPEN_MAX
+ :#endif
+ :#endif
+ : ) {
+ :#ifdef WIN32
+ : errno = WSAGetLastError();
+ :#endif
+ : PRMSG (2, "SocketOpen: socket() failed for %s\n",
+ : Sockettrans2devtab[i].transname, 0, 0);
+ :
+ : xfree ((char *) ciptr);
+ : return NULL;
+ : }
+ :
+ :#ifdef TCP_NODELAY
+ : if (Sockettrans2devtab[i].family == AF_INET
+ :#if defined(IPv6) && defined(AF_INET6)
+ : || Sockettrans2devtab[i].family == AF_INET6
+ :#endif
+ : )
+ : {
+ : /*
+ : * turn off TCP coalescence for INET sockets
+ : */
+ :
+ : int tmp = 1;
+ : setsockopt (ciptr->fd, IPPROTO_TCP, TCP_NODELAY,
+ : (char *) &tmp, sizeof (int));
+ : }
+ :#endif
+ :
+ : return ciptr;
+ :}
+ :
+ :
+ :#ifdef TRANS_REOPEN
+ :
+ :static XtransConnInfo
+ :TRANS(SocketReopen) (int i, int type, int fd, char *port)
+ :
+ :{
+ : XtransConnInfo ciptr;
+ :
+ : PRMSG (3,"SocketReopen(%d,%d,%s)\n", type, fd, port);
+ :
+ : if ((ciptr = (XtransConnInfo) xcalloc (
+ : 1, sizeof(struct _XtransConnInfo))) == NULL)
+ : {
+ : PRMSG (1, "SocketReopen: malloc failed\n", 0, 0, 0);
+ : return NULL;
+ : }
+ :
+ : ciptr->fd = fd;
+ :
+ : return ciptr;
+ :}
+ :
+ :#endif /* TRANS_REOPEN */
+ :
+ :
+ :/*
+ : * These functions are the interface supplied in the Xtransport structure
+ : */
+ :
+ :#ifdef TRANS_CLIENT
+ :
+ :static XtransConnInfo
+ :TRANS(SocketOpenCOTSClientBase) (char *transname, char *protocol,
+ : char *host, char *port, int previndex)
+ :{
+ : XtransConnInfo ciptr;
+ : int i = previndex;
+ :
+ : PRMSG (2, "SocketOpenCOTSClient(%s,%s,%s)\n",
+ : protocol, host, port);
+ :
+ : SocketInitOnce();
+ :
+ : while ((i = TRANS(SocketSelectFamily) (i, transname)) >= 0) {
+ : if ((ciptr = TRANS(SocketOpen) (
+ : i, Sockettrans2devtab[i].devcotsname)) != NULL)
+ : break;
+ : }
+ : if (i < 0) {
+ : if (i == -1)
+ : PRMSG (1,"SocketOpenCOTSClient: Unable to open socket for %s\n",
+ : transname, 0, 0);
+ : else
+ : PRMSG (1,"SocketOpenCOTSClient: Unable to determine socket type for %s\n",
+ : transname, 0, 0);
+ : return NULL;
+ : }
+ :
+ : /* Save the index for later use */
+ :
+ : ciptr->index = i;
+ :
+ : return ciptr;
+ :}
+ :
+ :static XtransConnInfo
+ :TRANS(SocketOpenCOTSClient) (Xtransport *thistrans, char *protocol,
+ : char *host, char *port)
+ :{
+ : return TRANS(SocketOpenCOTSClientBase)(
+ : thistrans->TransName, protocol, host, port, -1);
+ :}
+ :
+ :
+ :#endif /* TRANS_CLIENT */
+ :
+ :
+ :#ifdef TRANS_SERVER
+ :
+ :static XtransConnInfo
+ :TRANS(SocketOpenCOTSServer) (Xtransport *thistrans, char *protocol,
+ : char *host, char *port)
+ :
+ :{
+ : XtransConnInfo ciptr;
+ : int i = -1;
+ :
+ : PRMSG (2,"SocketOpenCOTSServer(%s,%s,%s)\n", protocol, host, port);
+ :
+ : SocketInitOnce();
+ :
+ : while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
+ : if ((ciptr = TRANS(SocketOpen) (
+ : i, Sockettrans2devtab[i].devcotsname)) != NULL)
+ : break;
+ : }
+ : if (i < 0) {
+ : if (i == -1)
+ : PRMSG (1,"SocketOpenCOTSServer: Unable to open socket for %s\n",
+ : thistrans->TransName, 0, 0);
+ : else
+ : PRMSG (1,"SocketOpenCOTSServer: Unable to determine socket type for %s\n",
+ : thistrans->TransName, 0, 0);
+ : return NULL;
+ : }
+ :
+ : /*
+ : * Using this prevents the bind() check for an existing server listening
+ : * on the same port, but it is required for other reasons.
+ : */
+ :#ifdef SO_REUSEADDR
+ :
+ : /*
+ : * SO_REUSEADDR only applied to AF_INET && AF_INET6
+ : */
+ :
+ : if (Sockettrans2devtab[i].family == AF_INET
+ :#if defined(IPv6) && defined(AF_INET6)
+ : || Sockettrans2devtab[i].family == AF_INET6
+ :#endif
+ : )
+ : {
+ : int one = 1;
+ : setsockopt (ciptr->fd, SOL_SOCKET, SO_REUSEADDR,
+ : (char *) &one, sizeof (int));
+ : }
+ :#endif
+ :#ifdef IPV6_V6ONLY
+ : if (Sockettrans2devtab[i].family == AF_INET6)
+ : {
+ : int one = 1;
+ : setsockopt(ciptr->fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(int));
+ : }
+ :#endif
+ : /* Save the index for later use */
+ :
+ : ciptr->index = i;
+ :
+ : return ciptr;
+ :}
+ :
+ :#endif /* TRANS_SERVER */
+ :
+ :
+ :#ifdef TRANS_CLIENT
+ :
+ :static XtransConnInfo
+ :TRANS(SocketOpenCLTSClient) (Xtransport *thistrans, char *protocol,
+ : char *host, char *port)
+ :
+ :{
+ : XtransConnInfo ciptr;
+ : int i = -1;
+ :
+ : PRMSG (2,"SocketOpenCLTSClient(%s,%s,%s)\n", protocol, host, port);
+ :
+ : SocketInitOnce();
+ :
+ : while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
+ : if ((ciptr = TRANS(SocketOpen) (
+ : i, Sockettrans2devtab[i].devcotsname)) != NULL)
+ : break;
+ : }
+ : if (i < 0) {
+ : if (i == -1)
+ : PRMSG (1,"SocketOpenCLTSClient: Unable to open socket for %s\n",
+ : thistrans->TransName, 0, 0);
+ : else
+ : PRMSG (1,"SocketOpenCLTSClient: Unable to determine socket type for %s\n",
+ : thistrans->TransName, 0, 0);
+ : return NULL;
+ : }
+ :
+ : /* Save the index for later use */
+ :
+ : ciptr->index = i;
+ :
+ : return ciptr;
+ :}
+ :
+ :#endif /* TRANS_CLIENT */
+ :
+ :
+ :#ifdef TRANS_SERVER
+ :
+ :static XtransConnInfo
+ :TRANS(SocketOpenCLTSServer) (Xtransport *thistrans, char *protocol,
+ : char *host, char *port)
+ :
+ :{
+ : XtransConnInfo ciptr;
+ : int i = -1;
+ :
+ : PRMSG (2,"SocketOpenCLTSServer(%s,%s,%s)\n", protocol, host, port);
+ :
+ : SocketInitOnce();
+ :
+ : while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
+ : if ((ciptr = TRANS(SocketOpen) (
+ : i, Sockettrans2devtab[i].devcotsname)) != NULL)
+ : break;
+ : }
+ : if (i < 0) {
+ : if (i == -1)
+ : PRMSG (1,"SocketOpenCLTSServer: Unable to open socket for %s\n",
+ : thistrans->TransName, 0, 0);
+ : else
+ : PRMSG (1,"SocketOpenCLTSServer: Unable to determine socket type for %s\n",
+ : thistrans->TransName, 0, 0);
+ : return NULL;
+ : }
+ :
+ :#ifdef IPV6_V6ONLY
+ : if (Sockettrans2devtab[i].family == AF_INET6)
+ : {
+ : int one = 1;
+ : setsockopt(ciptr->fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(int));
+ : }
+ :#endif
+ : /* Save the index for later use */
+ :
+ : ciptr->index = i;
+ :
+ : return ciptr;
+ :}
+ :
+ :#endif /* TRANS_SERVER */
+ :
+ :
+ :#ifdef TRANS_REOPEN
+ :
+ :static XtransConnInfo
+ :TRANS(SocketReopenCOTSServer) (Xtransport *thistrans, int fd, char *port)
+ :
+ :{
+ : XtransConnInfo ciptr;
+ : int i = -1;
+ :
+ : PRMSG (2,
+ : "SocketReopenCOTSServer(%d, %s)\n", fd, port, 0);
+ :
+ : SocketInitOnce();
+ :
+ : while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
+ : if ((ciptr = TRANS(SocketReopen) (
+ : i, Sockettrans2devtab[i].devcotsname, fd, port)) != NULL)
+ : break;
+ : }
+ : if (i < 0) {
+ : if (i == -1)
+ : PRMSG (1,"SocketReopenCOTSServer: Unable to open socket for %s\n",
+ : thistrans->TransName, 0, 0);
+ : else
+ : PRMSG (1,"SocketReopenCOTSServer: Unable to determine socket type for %s\n",
+ : thistrans->TransName, 0, 0);
+ : return NULL;
+ : }
+ :
+ : /* Save the index for later use */
+ :
+ : ciptr->index = i;
+ :
+ : return ciptr;
+ :}
+ :
+ :static XtransConnInfo
+ :TRANS(SocketReopenCLTSServer) (Xtransport *thistrans, int fd, char *port)
+ :
+ :{
+ : XtransConnInfo ciptr;
+ : int i = -1;
+ :
+ : PRMSG (2,
+ : "SocketReopenCLTSServer(%d, %s)\n", fd, port, 0);
+ :
+ : SocketInitOnce();
+ :
+ : while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
+ : if ((ciptr = TRANS(SocketReopen) (
+ : i, Sockettrans2devtab[i].devcotsname, fd, port)) != NULL)
+ : break;
+ : }
+ : if (i < 0) {
+ : if (i == -1)
+ : PRMSG (1,"SocketReopenCLTSServer: Unable to open socket for %s\n",
+ : thistrans->TransName, 0, 0);
+ : else
+ : PRMSG (1,"SocketReopenCLTSServer: Unable to determine socket type for %s\n",
+ : thistrans->TransName, 0, 0);
+ : return NULL;
+ : }
+ :
+ : /* Save the index for later use */
+ :
+ : ciptr->index = i;
+ :
+ : return ciptr;
+ :}
+ :
+ :#endif /* TRANS_REOPEN */
+ :
+ :
+ :static int
+ :TRANS(SocketSetOption) (XtransConnInfo ciptr, int option, int arg)
+ :
+ :{
+ : PRMSG (2,"SocketSetOption(%d,%d,%d)\n", ciptr->fd, option, arg);
+ :
+ : return -1;
+ :}
+ :
+ :#ifdef UNIXCONN
+ :static int
+ :set_sun_path(const char *port, const char *upath, char *path)
+ :{
+ : struct sockaddr_un s;
+ : int maxlen = sizeof(s.sun_path) - 1;
+ :
+ : if (!port || !*port || !path)
+ : return -1;
+ :
+ : if (*port == '/') { /* a full pathname */
+ : if (strlen(port) > maxlen)
+ : return -1;
+ : sprintf(path, "%s", port);
+ : } else {
+ : if (strlen(port) + strlen(upath) > maxlen)
+ : return -1;
+ : sprintf(path, "%s%s", upath, port);
+ : }
+ : return 0;
+ :}
+ :#endif
+ :
+ :#ifdef TRANS_SERVER
+ :
+ :static int
+ :TRANS(SocketCreateListener) (XtransConnInfo ciptr,
+ : struct sockaddr *sockname,
+ : int socknamelen, unsigned int flags)
+ :
+ :{
+ : int namelen = socknamelen;
+ : int fd = ciptr->fd;
+ : int retry;
+ :
+ : PRMSG (3, "SocketCreateListener(%x,%p)\n", ciptr, fd, 0);
+ :
+ : if (Sockettrans2devtab[ciptr->index].family == AF_INET
+ :#if defined(IPv6) && defined(AF_INET6)
+ : || Sockettrans2devtab[ciptr->index].family == AF_INET6
+ :#endif
+ : )
+ : retry = 20;
+ : else
+ : retry = 0;
+ :
+ : while (bind (fd, (struct sockaddr *) sockname, namelen) < 0)
+ : {
+ : if (errno == EADDRINUSE) {
+ : if (flags & ADDR_IN_USE_ALLOWED)
+ : break;
+ : else
+ : return TRANS_ADDR_IN_USE;
+ : }
+ :
+ : if (retry-- == 0) {
+ : PRMSG (1, "SocketCreateListener: failed to bind listener\n",
+ : 0, 0, 0);
+ : close (fd);
+ : return TRANS_CREATE_LISTENER_FAILED;
+ : }
+ :#ifdef SO_REUSEADDR
+ : sleep (1);
+ :#else
+ : sleep (10);
+ :#endif /* SO_REUSEDADDR */
+ : }
+ :
+ : if (Sockettrans2devtab[ciptr->index].family == AF_INET
+ :#if defined(IPv6) && defined(AF_INET6)
+ : || Sockettrans2devtab[ciptr->index].family == AF_INET6
+ :#endif
+ : ) {
+ :#ifdef SO_DONTLINGER
+ : setsockopt (fd, SOL_SOCKET, SO_DONTLINGER, (char *) NULL, 0);
+ :#else
+ :#ifdef SO_LINGER
+ : {
+ : static int linger[2] = { 0, 0 };
+ : setsockopt (fd, SOL_SOCKET, SO_LINGER,
+ : (char *) linger, sizeof (linger));
+ : }
+ :#endif
+ :#endif
+ :}
+ :
+ : if (listen (fd, BACKLOG) < 0)
+ : {
+ : PRMSG (1, "SocketCreateListener: listen() failed\n", 0, 0, 0);
+ : close (fd);
+ : return TRANS_CREATE_LISTENER_FAILED;
+ : }
+ :
+ : /* Set a flag to indicate that this connection is a listener */
+ :
+ : ciptr->flags = 1 | (ciptr->flags & TRANS_KEEPFLAGS);
+ :
+ : return 0;
+ :}
+ :
+ :#ifdef TCPCONN
+ :static int
+ :TRANS(SocketINETCreateListener) (XtransConnInfo ciptr, char *port, unsigned int flags)
+ :
+ :{
+ :#if defined(IPv6) && defined(AF_INET6)
+ : struct sockaddr_storage sockname;
+ :#else
+ : struct sockaddr_in sockname;
+ :#endif
+ : unsigned short sport;
+ : int namelen = sizeof(sockname);
+ : int status;
+ : long tmpport;
+ :#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
+ : _Xgetservbynameparams sparams;
+ :#endif
+ : struct servent *servp;
+ :
+ :#ifdef X11_t
+ : char portbuf[PORTBUFSIZE];
+ :#endif
+ :
+ : PRMSG (2, "SocketINETCreateListener(%s)\n", port, 0, 0);
+ :
+ :#ifdef X11_t
+ : /*
+ : * X has a well known port, that is transport dependent. It is easier
+ : * to handle it here, than try and come up with a transport independent
+ : * representation that can be passed in and resolved the usual way.
+ : *
+ : * The port that is passed here is really a string containing the idisplay
+ : * from ConnectDisplay().
+ : */
+ :
+ : if (is_numeric (port))
+ : {
+ : /* fixup the server port address */
+ : tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10);
+ : sprintf (portbuf,"%lu", tmpport);
+ : port = portbuf;
+ : }
+ :#endif
+ :
+ : if (port && *port)
+ : {
+ : /* Check to see if the port string is just a number (handles X11) */
+ :
+ : if (!is_numeric (port))
+ : {
+ : if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL)
+ : {
+ : PRMSG (1,
+ : "SocketINETCreateListener: Unable to get service for %s\n",
+ : port, 0, 0);
+ : return TRANS_CREATE_LISTENER_FAILED;
+ : }
+ : /* we trust getservbyname to return a valid number */
+ : sport = servp->s_port;
+ : }
+ : else
+ : {
+ : tmpport = strtol (port, (char**)NULL, 10);
+ : /*
+ : * check that somehow the port address isn't negative or in
+ : * the range of reserved port addresses. This can happen and
+ : * be very bad if the server is suid-root and the user does
+ : * something (dumb) like `X :60049`.
+ : */
+ : if (tmpport < 1024 || tmpport > USHRT_MAX)
+ : return TRANS_CREATE_LISTENER_FAILED;
+ :
+ : sport = (unsigned short) tmpport;
+ : }
+ : }
+ : else
+ : sport = 0;
+ :
+ : bzero(&sockname, sizeof(sockname));
+ :#if defined(IPv6) && defined(AF_INET6)
+ : if (Sockettrans2devtab[ciptr->index].family == AF_INET) {
+ : namelen = sizeof (struct sockaddr_in);
+ :#ifdef BSD44SOCKETS
+ : ((struct sockaddr_in *)&sockname)->sin_len = namelen;
+ :#endif
+ : ((struct sockaddr_in *)&sockname)->sin_family = AF_INET;
+ : ((struct sockaddr_in *)&sockname)->sin_port = htons(sport);
+ : ((struct sockaddr_in *)&sockname)->sin_addr.s_addr = htonl(INADDR_ANY);
+ : } else {
+ : namelen = sizeof (struct sockaddr_in6);
+ :#ifdef SIN6_LEN
+ : ((struct sockaddr_in6 *)&sockname)->sin6_len = sizeof(sockname);
+ :#endif
+ : ((struct sockaddr_in6 *)&sockname)->sin6_family = AF_INET6;
+ : ((struct sockaddr_in6 *)&sockname)->sin6_port = htons(sport);
+ : ((struct sockaddr_in6 *)&sockname)->sin6_addr = in6addr_any;
+ : }
+ :#else
+ :#ifdef BSD44SOCKETS
+ : sockname.sin_len = sizeof (sockname);
+ :#endif
+ : sockname.sin_family = AF_INET;
+ : sockname.sin_port = htons (sport);
+ : sockname.sin_addr.s_addr = htonl (INADDR_ANY);
+ :#endif
+ :
+ : if ((status = TRANS(SocketCreateListener) (ciptr,
+ : (struct sockaddr *) &sockname, namelen, flags)) < 0)
+ : {
+ : PRMSG (1,
+ : "SocketINETCreateListener: ...SocketCreateListener() failed\n",
+ : 0, 0, 0);
+ : return status;
+ : }
+ :
+ : if (TRANS(SocketINETGetAddr) (ciptr) < 0)
+ : {
+ : PRMSG (1,
+ : "SocketINETCreateListener: ...SocketINETGetAddr() failed\n",
+ : 0, 0, 0);
+ : return TRANS_CREATE_LISTENER_FAILED;
+ : }
+ :
+ : return 0;
+ :}
+ :
+ :#endif /* TCPCONN */
+ :
+ :
+ :#ifdef UNIXCONN
+ :
+ :static int
+ :TRANS(SocketUNIXCreateListener) (XtransConnInfo ciptr, char *port,
+ : unsigned int flags)
+ :
+ :{
+ : struct sockaddr_un sockname;
+ : int namelen;
+ : int oldUmask;
+ : int status;
+ : unsigned int mode;
+ :
+ : PRMSG (2, "SocketUNIXCreateListener(%s)\n",
+ : port ? port : "NULL", 0, 0);
+ :
+ : /* Make sure the directory is created */
+ :
+ : oldUmask = umask (0);
+ :
+ :#ifdef UNIX_DIR
+ :#ifdef HAS_STICKY_DIR_BIT
+ : mode = 01777;
+ :#else
+ : mode = 0777;
+ :#endif
+ : if (trans_mkdir(UNIX_DIR, mode) == -1) {
+ : PRMSG (1, "SocketUNIXCreateListener: mkdir(%s) failed, errno = %d\n",
+ : UNIX_DIR, errno, 0);
+ : (void) umask (oldUmask);
+ : return TRANS_CREATE_LISTENER_FAILED;
+ : }
+ :#endif
+ :
+ : sockname.sun_family = AF_UNIX;
+ :
+ : if (port && *port) {
+ : if (set_sun_path(port, UNIX_PATH, sockname.sun_path) != 0) {
+ : PRMSG (1, "SocketUNIXCreateListener: path too long\n", 0, 0, 0);
+ : return TRANS_CREATE_LISTENER_FAILED;
+ : }
+ : } else {
+ : snprintf (sockname.sun_path, sizeof(sockname.sun_path),
+ : "%s%ld", UNIX_PATH, (long)getpid());
+ : }
+ :
+ :#if (defined(BSD44SOCKETS) || defined(__UNIXWARE__)) && !defined(Lynx)
+ : sockname.sun_len = strlen(sockname.sun_path);
+ :#endif
+ :
+ :#if defined(BSD44SOCKETS) || defined(SUN_LEN)
+ : namelen = SUN_LEN(&sockname);
+ :#else
+ : namelen = strlen(sockname.sun_path) + offsetof(struct sockaddr_un, sun_path);
+ :#endif
+ :
+ : unlink (sockname.sun_path);
+ :
+ : if ((status = TRANS(SocketCreateListener) (ciptr,
+ : (struct sockaddr *) &sockname, namelen, flags)) < 0)
+ : {
+ : PRMSG (1,
+ : "SocketUNIXCreateListener: ...SocketCreateListener() failed\n",
+ : 0, 0, 0);
+ : (void) umask (oldUmask);
+ : return status;
+ : }
+ :
+ : /*
+ : * Now that the listener is esablished, create the addr info for
+ : * this connection. getpeername() doesn't work for UNIX Domain Sockets
+ : * on some systems (hpux at least), so we will just do it manually, instead
+ : * of calling something like TRANS(SocketUNIXGetAddr).
+ : */
+ :
+ : namelen = sizeof (sockname); /* this will always make it the same size */
+ :
+ : if ((ciptr->addr = (char *) xalloc (namelen)) == NULL)
+ : {
+ : PRMSG (1,
+ : "SocketUNIXCreateListener: Can't allocate space for the addr\n",
+ : 0, 0, 0);
+ : (void) umask (oldUmask);
+ : return TRANS_CREATE_LISTENER_FAILED;
+ : }
+ :
+ : ciptr->family = sockname.sun_family;
+ : ciptr->addrlen = namelen;
+ : memcpy (ciptr->addr, &sockname, ciptr->addrlen);
+ :
+ : (void) umask (oldUmask);
+ :
+ : return 0;
+ :}
+ :
+ :
+ :static int
+ :TRANS(SocketUNIXResetListener) (XtransConnInfo ciptr)
+ :
+ :{
+ : /*
+ : * See if the unix domain socket has disappeared. If it has, recreate it.
+ : */
+ :
+ : struct sockaddr_un *unsock = (struct sockaddr_un *) ciptr->addr;
+ : struct stat statb;
+ : int status = TRANS_RESET_NOOP;
+ : unsigned int mode;
+ :
+ : PRMSG (3, "SocketUNIXResetListener(%p,%d)\n", ciptr, ciptr->fd, 0);
+ :
+ : if (stat (unsock->sun_path, &statb) == -1 ||
+ : ((statb.st_mode & S_IFMT) !=
+ :#if (defined (sun) && defined(SVR4)) || defined(NCR) || defined(SCO325) || !defined(S_IFSOCK)
+ : S_IFIFO))
+ :#else
+ : S_IFSOCK))
+ :#endif
+ : {
+ : int oldUmask = umask (0);
+ :
+ :#ifdef UNIX_DIR
+ :#ifdef HAS_STICKY_DIR_BIT
+ : mode = 01777;
+ :#else
+ : mode = 0777;
+ :#endif
+ : if (trans_mkdir(UNIX_DIR, mode) == -1) {
+ : PRMSG (1, "SocketUNIXResetListener: mkdir(%s) failed, errno = %d\n",
+ : UNIX_DIR, errno, 0);
+ : (void) umask (oldUmask);
+ : return TRANS_RESET_FAILURE;
+ : }
+ :#endif
+ :
+ : close (ciptr->fd);
+ : unlink (unsock->sun_path);
+ :
+ : if ((ciptr->fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
+ : {
+ : TRANS(FreeConnInfo) (ciptr);
+ : (void) umask (oldUmask);
+ : return TRANS_RESET_FAILURE;
+ : }
+ :
+ : if (bind (ciptr->fd, (struct sockaddr *) unsock, ciptr->addrlen) < 0)
+ : {
+ : close (ciptr->fd);
+ : TRANS(FreeConnInfo) (ciptr);
+ : return TRANS_RESET_FAILURE;
+ : }
+ :
+ : if (listen (ciptr->fd, BACKLOG) < 0)
+ : {
+ : close (ciptr->fd);
+ : TRANS(FreeConnInfo) (ciptr);
+ : (void) umask (oldUmask);
+ : return TRANS_RESET_FAILURE;
+ : }
+ :
+ : umask (oldUmask);
+ :
+ : status = TRANS_RESET_NEW_FD;
+ : }
+ :
+ : return status;
+ :}
+ :
+ :#endif /* UNIXCONN */
+ :
+ :
+ :#ifdef TCPCONN
+ :
+ :static XtransConnInfo
+ :TRANS(SocketINETAccept) (XtransConnInfo ciptr, int *status)
+ :
+ :{
+ : XtransConnInfo newciptr;
+ : struct sockaddr_in sockname;
+ : int namelen = sizeof(sockname);
+ :
+ : PRMSG (2, "SocketINETAccept(%p,%d)\n", ciptr, ciptr->fd, 0);
+ :
+ : if ((newciptr = (XtransConnInfo) xcalloc (
+ : 1, sizeof(struct _XtransConnInfo))) == NULL)
+ : {
+ : PRMSG (1, "SocketINETAccept: malloc failed\n", 0, 0, 0);
+ : *status = TRANS_ACCEPT_BAD_MALLOC;
+ : return NULL;
+ : }
+ :
+ : if ((newciptr->fd = accept (ciptr->fd,
+ : (struct sockaddr *) &sockname, (void *)&namelen)) < 0)
+ : {
+ :#ifdef WIN32
+ : errno = WSAGetLastError();
+ :#endif
+ : PRMSG (1, "SocketINETAccept: accept() failed\n", 0, 0, 0);
+ : xfree (newciptr);
+ : *status = TRANS_ACCEPT_FAILED;
+ : return NULL;
+ : }
+ :
+ :#ifdef TCP_NODELAY
+ : {
+ : /*
+ : * turn off TCP coalescence for INET sockets
+ : */
+ :
+ : int tmp = 1;
+ : setsockopt (newciptr->fd, IPPROTO_TCP, TCP_NODELAY,
+ : (char *) &tmp, sizeof (int));
+ : }
+ :#endif
+ :
+ : /*
+ : * Get this address again because the transport may give a more
+ : * specific address now that a connection is established.
+ : */
+ :
+ : if (TRANS(SocketINETGetAddr) (newciptr) < 0)
+ : {
+ : PRMSG (1,
+ : "SocketINETAccept: ...SocketINETGetAddr() failed:\n",
+ : 0, 0, 0);
+ : close (newciptr->fd);
+ : xfree (newciptr);
+ : *status = TRANS_ACCEPT_MISC_ERROR;
+ : return NULL;
+ : }
+ :
+ : if (TRANS(SocketINETGetPeerAddr) (newciptr) < 0)
+ : {
+ : PRMSG (1,
+ : "SocketINETAccept: ...SocketINETGetPeerAddr() failed:\n",
+ : 0, 0, 0);
+ : close (newciptr->fd);
+ : if (newciptr->addr) xfree (newciptr->addr);
+ : xfree (newciptr);
+ : *status = TRANS_ACCEPT_MISC_ERROR;
+ : return NULL;
+ : }
+ :
+ : *status = 0;
+ :
+ : return newciptr;
+ :}
+ :
+ :#endif /* TCPCONN */
+ :
+ :
+ :#ifdef UNIXCONN
+ :static XtransConnInfo
+ :TRANS(SocketUNIXAccept) (XtransConnInfo ciptr, int *status)
+ :
+ :{
+ : XtransConnInfo newciptr;
+ : struct sockaddr_un sockname;
+ :#if defined(SVR4) || defined(__SCO__)
+ : size_t namelen = sizeof sockname;
+ :#else
+ : int namelen = sizeof sockname;
+ :#endif
+ :
+ : PRMSG (2, "SocketUNIXAccept(%p,%d)\n", ciptr, ciptr->fd, 0);
+ :
+ : if ((newciptr = (XtransConnInfo) xcalloc (
+ : 1, sizeof(struct _XtransConnInfo))) == NULL)
+ : {
+ : PRMSG (1, "SocketUNIXAccept: malloc() failed\n", 0, 0, 0);
+ : *status = TRANS_ACCEPT_BAD_MALLOC;
+ : return NULL;
+ : }
+ :
+ : if ((newciptr->fd = accept (ciptr->fd,
+ : (struct sockaddr *) &sockname, (void *)&namelen)) < 0)
+ : {
+ : PRMSG (1, "SocketUNIXAccept: accept() failed\n", 0, 0, 0);
+ : xfree (newciptr);
+ : *status = TRANS_ACCEPT_FAILED;
+ : return NULL;
+ : }
+ :
+ : /*
+ : * Get the socket name and the peer name from the listener socket,
+ : * since this is unix domain.
+ : */
+ :
+ : if ((newciptr->addr = (char *) xalloc (ciptr->addrlen)) == NULL)
+ : {
+ : PRMSG (1,
+ : "SocketUNIXAccept: Can't allocate space for the addr\n",
+ : 0, 0, 0);
+ : close (newciptr->fd);
+ : xfree (newciptr);
+ : *status = TRANS_ACCEPT_BAD_MALLOC;
+ : return NULL;
+ : }
+ :
+ :
+ : newciptr->addrlen = ciptr->addrlen;
+ : memcpy (newciptr->addr, ciptr->addr, newciptr->addrlen);
+ :
+ : if ((newciptr->peeraddr = (char *) xalloc (ciptr->addrlen)) == NULL)
+ : {
+ : PRMSG (1,
+ : "SocketUNIXAccept: Can't allocate space for the addr\n",
+ : 0, 0, 0);
+ : close (newciptr->fd);
+ : if (newciptr->addr) xfree (newciptr->addr);
+ : xfree (newciptr);
+ : *status = TRANS_ACCEPT_BAD_MALLOC;
+ : return NULL;
+ : }
+ :
+ : newciptr->peeraddrlen = ciptr->addrlen;
+ : memcpy (newciptr->peeraddr, ciptr->addr, newciptr->addrlen);
+ :
+ : newciptr->family = AF_UNIX;
+ :
+ : *status = 0;
+ :
+ : return newciptr;
+ :}
+ :
+ :#endif /* UNIXCONN */
+ :
+ :#endif /* TRANS_SERVER */
+ :
+ :
+ :#ifdef TRANS_CLIENT
+ :
+ :#ifdef TCPCONN
+ :
+ :#if defined(IPv6) && defined(AF_INET6)
+ :struct addrlist {
+ : struct addrinfo * addr;
+ : struct addrinfo * firstaddr;
+ : char port[PORTBUFSIZE];
+ : char host[MAXHOSTNAMELEN];
+ :};
+ :static struct addrlist *addrlist = NULL;
+ :#endif
+ :
+ :
+ :static int
+ :TRANS(SocketINETConnect) (XtransConnInfo ciptr, char *host, char *port)
+ :
+ :{
+ : struct sockaddr * socketaddr = NULL;
+ : int socketaddrlen = 0;
+ : int res;
+ :#if defined(IPv6) && defined(AF_INET6)
+ : struct addrinfo hints;
+ : char ntopbuf[INET6_ADDRSTRLEN];
+ : int resetonce = 0;
+ :#endif
+ : struct sockaddr_in sockname;
+ :#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
+ : _Xgethostbynameparams hparams;
+ : _Xgetservbynameparams sparams;
+ :#endif
+ : struct hostent *hostp;
+ : struct servent *servp;
+ : unsigned long tmpaddr;
+ :#ifdef X11_t
+ : char portbuf[PORTBUFSIZE];
+ :#endif
+ :
+ : long tmpport;
+ : char hostnamebuf[256]; /* tmp space */
+ :
+ : PRMSG (2,"SocketINETConnect(%d,%s,%s)\n", ciptr->fd, host, port);
+ :
+ : if (!host)
+ : {
+ : hostnamebuf[0] = '\0';
+ : (void) TRANS(GetHostname) (hostnamebuf, sizeof hostnamebuf);
+ : host = hostnamebuf;
+ : }
+ :
+ :#ifdef X11_t
+ : /*
+ : * X has a well known port, that is transport dependent. It is easier
+ : * to handle it here, than try and come up with a transport independent
+ : * representation that can be passed in and resolved the usual way.
+ : *
+ : * The port that is passed here is really a string containing the idisplay
+ : * from ConnectDisplay().
+ : */
+ :
+ : if (is_numeric (port))
+ : {
+ : tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10);
+ : sprintf (portbuf, "%lu", tmpport);
+ : port = portbuf;
+ : }
+ :#endif
+ :
+ :#if defined(IPv6) && defined(AF_INET6)
+ : if (haveIPv6) {
+ : if (addrlist != NULL) {
+ : if (strcmp(host,addrlist->host) || strcmp(port,addrlist->port)) {
+ : if (addrlist->firstaddr)
+ : freeaddrinfo(addrlist->firstaddr);
+ : addrlist->firstaddr = NULL;
+ : }
+ : } else {
+ : addrlist = malloc(sizeof(struct addrlist));
+ : addrlist->firstaddr = NULL;
+ : }
+ :
+ : if (addrlist->firstaddr == NULL) {
+ : strncpy(addrlist->port, port, sizeof(addrlist->port));
+ : addrlist->port[sizeof(addrlist->port) - 1] = '\0';
+ : strncpy(addrlist->host, host, sizeof(addrlist->host));
+ : addrlist->host[sizeof(addrlist->host) - 1] = '\0';
+ :
+ : bzero(&hints,sizeof(hints));
+ : hints.ai_socktype = Sockettrans2devtab[ciptr->index].devcotsname;
+ :
+ : res = getaddrinfo(host,port,&hints,&addrlist->firstaddr);
+ : if (res != 0) {
+ : PRMSG (1, "SocketINETConnect() can't get address "
+ : "for %s:%s: %s\n", host, port, gai_strerror(res));
+ : ESET(EINVAL);
+ : return TRANS_CONNECT_FAILED;
+ : }
+ : for (res = 0, addrlist->addr = addrlist->firstaddr;
+ : addrlist->addr ; res++) {
+ : addrlist->addr = addrlist->addr->ai_next;
+ : }
+ : PRMSG(4,"Got New Address list with %d addresses\n", res, 0, 0);
+ : res = 0;
+ : addrlist->addr = NULL;
+ : }
+ :
+ : while (socketaddr == NULL) {
+ : if (addrlist->addr == NULL) {
+ : if (resetonce) {
+ : /* Already checked entire list - no usable addresses */
+ : PRMSG (1, "SocketINETConnect() no usable address "
+ : "for %s:%s\n", host, port, 0);
+ : return TRANS_CONNECT_FAILED;
+ : } else {
+ : /* Go back to beginning of list */
+ : resetonce = 1;
+ : addrlist->addr = addrlist->firstaddr;
+ : }
+ : }
+ :
+ : socketaddr = addrlist->addr->ai_addr;
+ : socketaddrlen = addrlist->addr->ai_addrlen;
+ :
+ : if (addrlist->addr->ai_family == AF_INET) {
+ : struct sockaddr_in *sin = (struct sockaddr_in *) socketaddr;
+ :
+ : PRMSG (4,"SocketINETConnect() sockname.sin_addr = %s\n",
+ : inet_ntop(addrlist->addr->ai_family,&sin->sin_addr,
+ : ntopbuf,sizeof(ntopbuf)), 0, 0);
+ :
+ : PRMSG (4,"SocketINETConnect() sockname.sin_port = %d\n",
+ : ntohs(sin->sin_port), 0, 0);
+ :
+ : if (Sockettrans2devtab[ciptr->index].family == AF_INET6) {
+ : if (strcmp(Sockettrans2devtab[ciptr->index].transname,
+ : "tcp") == 0) {
+ : XtransConnInfo newciptr;
+ :
+ : /*
+ : * Our socket is an IPv6 socket, but the address is
+ : * IPv4. Close it and get an IPv4 socket. This is
+ : * needed for IPv4 connections to work on platforms
+ : * that don't allow IPv4 over IPv6 sockets.
+ : */
+ : TRANS(SocketINETClose)(ciptr);
+ : newciptr = TRANS(SocketOpenCOTSClientBase)(
+ : "tcp", "tcp", host, port, ciptr->index);
+ : if (newciptr)
+ : ciptr->fd = newciptr->fd;
+ : if (!newciptr ||
+ : Sockettrans2devtab[newciptr->index].family !=
+ : AF_INET) {
+ : socketaddr = NULL;
+ : PRMSG (4,"SocketINETConnect() Cannot get IPv4 "
+ : " socketfor IPv4 address\n", 0,0,0);
+ : }
+ : if (newciptr)
+ : xfree(newciptr);
+ : } else {
+ : socketaddr = NULL;
+ : PRMSG (4,"SocketINETConnect Skipping IPv4 address\n",
+ : 0,0,0);
+ : }
+ : }
+ : } else if (addrlist->addr->ai_family == AF_INET6) {
+ : struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) socketaddr;
+ :
+ : PRMSG (4,"SocketINETConnect() sockname.sin6_addr = %s\n",
+ : inet_ntop(addrlist->addr->ai_family,
+ : &sin6->sin6_addr,ntopbuf,sizeof(ntopbuf)),
+ : 0, 0);
+ : PRMSG (4,"SocketINETConnect() sockname.sin6_port = %d\n",
+ : ntohs(sin6->sin6_port), 0, 0);
+ :
+ : if (Sockettrans2devtab[ciptr->index].family == AF_INET) {
+ : if (strcmp(Sockettrans2devtab[ciptr->index].transname,
+ : "tcp") == 0) {
+ : XtransConnInfo newciptr;
+ :
+ : /*
+ : * Close the IPv4 socket and try to open an IPv6 socket.
+ : */
+ : TRANS(SocketINETClose)(ciptr);
+ : newciptr = TRANS(SocketOpenCOTSClientBase)(
+ : "tcp", "tcp", host, port, -1);
+ : if (newciptr)
+ : ciptr->fd = newciptr->fd;
+ : if (!newciptr ||
+ : Sockettrans2devtab[newciptr->index].family !=
+ : AF_INET6) {
+ : socketaddr = NULL;
+ : PRMSG (4,"SocketINETConnect() Cannot get IPv6 "
+ : "socket for IPv6 address\n", 0,0,0);
+ : }
+ : if (newciptr)
+ : xfree(newciptr);
+ : }
+ : else
+ : {
+ : socketaddr = NULL;
+ : PRMSG (4,"SocketINETConnect() Skipping IPv6 address\n",
+ : 0,0,0);
+ : }
+ : }
+ : } else {
+ : socketaddr = NULL; /* Unsupported address type */
+ : }
+ : if (socketaddr == NULL) {
+ : addrlist->addr = addrlist->addr->ai_next;
+ : }
+ : }
+ : } else
+ :#endif
+ : {
+ : /*
+ : * Build the socket name.
+ : */
+ :
+ :#ifdef BSD44SOCKETS
+ : sockname.sin_len = sizeof (struct sockaddr_in);
+ :#endif
+ : sockname.sin_family = AF_INET;
+ :
+ : /*
+ : * fill in sin_addr
+ : */
+ :
+ :#ifndef INADDR_NONE
+ :#define INADDR_NONE ((in_addr_t) 0xffffffff)
+ :#endif
+ :
+ : /* check for ww.xx.yy.zz host string */
+ :
+ : if (isascii (host[0]) && isdigit (host[0])) {
+ : tmpaddr = inet_addr (host); /* returns network byte order */
+ : } else {
+ : tmpaddr = INADDR_NONE;
+ : }
+ :
+ : PRMSG (4,"SocketINETConnect() inet_addr(%s) = %x\n", host, tmpaddr, 0);
+ :
+ : if (tmpaddr == INADDR_NONE) {
+ : if ((hostp = _XGethostbyname(host,hparams)) == NULL) {
+ : PRMSG (1,"SocketINETConnect: Can't get address for %s\n",
+ : host, 0, 0);
+ : ESET(EINVAL);
+ : return TRANS_CONNECT_FAILED;
+ : }
+ : if (hostp->h_addrtype != AF_INET) { /* is IP host? */
+ : PRMSG (1,"SocketINETConnect: not INET host%s\n", host, 0, 0);
+ : ESET(EPROTOTYPE);
+ : return TRANS_CONNECT_FAILED;
+ : }
+ :
+ :#if defined(CRAY) && defined(OLDTCP)
+ : /* Only Cray UNICOS3 and UNICOS4 will define this */
+ : {
+ : long t;
+ : memcpy ((char *)&t, (char *) hostp->h_addr, sizeof (t));
+ : sockname.sin_addr = t;
+ : }
+ :#else
+ : memcpy ((char *) &sockname.sin_addr, (char *) hostp->h_addr,
+ : sizeof (sockname.sin_addr));
+ :#endif /* CRAY and OLDTCP */
+ :
+ : } else {
+ :#if defined(CRAY) && defined(OLDTCP)
+ : /* Only Cray UNICOS3 and UNICOS4 will define this */
+ : sockname.sin_addr = tmpaddr;
+ :#else
+ : sockname.sin_addr.s_addr = tmpaddr;
+ :#endif /* CRAY and OLDTCP */
+ : }
+ :
+ : /*
+ : * fill in sin_port
+ : */
+ :
+ : /* Check for number in the port string */
+ :
+ : if (!is_numeric (port)) {
+ : if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL) {
+ : PRMSG (1,"SocketINETConnect: can't get service for %s\n",
+ : port, 0, 0);
+ : return TRANS_CONNECT_FAILED;
+ : }
+ : sockname.sin_port = htons (servp->s_port);
+ : } else {
+ : tmpport = strtol (port, (char**)NULL, 10);
+ : if (tmpport < 1024 || tmpport > USHRT_MAX)
+ : return TRANS_CONNECT_FAILED;
+ : sockname.sin_port = htons (((unsigned short) tmpport));
+ : }
+ :
+ : PRMSG (4,"SocketINETConnect: sockname.sin_port = %d\n",
+ : ntohs(sockname.sin_port), 0, 0);
+ : socketaddr = (struct sockaddr *) &sockname;
+ : socketaddrlen = sizeof(sockname);
+ : }
+ :
+ : /*
+ : * Turn on socket keepalive so the client process will eventually
+ : * be notified with a SIGPIPE signal if the display server fails
+ : * to respond to a periodic transmission of messages
+ : * on the connected socket.
+ : * This is useful to avoid hung application processes when the
+ : * processes are not spawned from the xdm session and
+ : * the display server terminates abnormally.
+ : * (Someone turned off the power switch.)
+ : */
+ :
+ : {
+ : int tmp = 1;
+ : setsockopt (ciptr->fd, SOL_SOCKET, SO_KEEPALIVE,
+ : (char *) &tmp, sizeof (int));
+ : }
+ :
+ : /*
+ : * Do the connect()
+ : */
+ :
+ : if (connect (ciptr->fd, socketaddr, socketaddrlen ) < 0)
+ : {
+ :#ifdef WIN32
+ : int olderrno = WSAGetLastError();
+ :#else
+ : int olderrno = errno;
+ :#endif
+ :
+ : /*
+ : * If the error was ECONNREFUSED, the server may be overloaded
+ : * and we should try again.
+ : *
+ : * If the error was EWOULDBLOCK or EINPROGRESS then the socket
+ : * was non-blocking and we should poll using select
+ : *
+ : * If the error was EINTR, the connect was interrupted and we
+ : * should try again.
+ : *
+ : * If multiple addresses are found for a host then we should
+ : * try to connect again with a different address for a larger
+ : * number of errors that made us quit before, since those
+ : * could be caused by trying to use an IPv6 address to contact
+ : * a machine with an IPv4-only server or other reasons that
+ : * only affect one of a set of addresses.
+ : */
+ :
+ : if (olderrno == ECONNREFUSED || olderrno == EINTR
+ :#if defined(IPv6) && defined(AF_INET6)
+ : || (haveIPv6 && ((addrlist->addr->ai_next != NULL) ||
+ : (addrlist->addr != addrlist->firstaddr)) &&
+ : (olderrno == ENETUNREACH || olderrno == EAFNOSUPPORT ||
+ : olderrno == EADDRNOTAVAIL || olderrno == ETIMEDOUT
+ :#if defined(EHOSTDOWN)
+ : || olderrno == EHOSTDOWN
+ :#endif
+ : ))
+ :#endif
+ : )
+ : res = TRANS_TRY_CONNECT_AGAIN;
+ : else if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS)
+ : res = TRANS_IN_PROGRESS;
+ : else
+ : {
+ : PRMSG (2,"SocketINETConnect: Can't connect: errno = %d\n",
+ : olderrno,0, 0);
+ :
+ : res = TRANS_CONNECT_FAILED;
+ : }
+ : } else {
+ : res = 0;
+ :
+ :
+ : /*
+ : * Sync up the address fields of ciptr.
+ : */
+ :
+ : if (TRANS(SocketINETGetAddr) (ciptr) < 0)
+ : {
+ : PRMSG (1,
+ : "SocketINETConnect: ...SocketINETGetAddr() failed:\n",
+ : 0, 0, 0);
+ : res = TRANS_CONNECT_FAILED;
+ : }
+ :
+ : else if (TRANS(SocketINETGetPeerAddr) (ciptr) < 0)
+ : {
+ : PRMSG (1,
+ : "SocketINETConnect: ...SocketINETGetPeerAddr() failed:\n",
+ : 0, 0, 0);
+ : res = TRANS_CONNECT_FAILED;
+ : }
+ : }
+ :
+ :#if defined(IPv6) && defined(AF_INET6)
+ : if (haveIPv6 && res != 0) {
+ : addrlist->addr = addrlist->addr->ai_next;
+ : }
+ :#endif
+ :
+ : return res;
+ :}
+ :
+ :#endif /* TCPCONN */
+ :
+ :
+ :\f
+ :#ifdef UNIXCONN
+ :
+ :/*
+ : * Make sure 'host' is really local.
+ : */
+ :
+ :static int
+ :UnixHostReallyLocal (char *host)
+ :
+ :{
+ : char hostnamebuf[256];
+ :
+ :#if defined(IPv6) && defined(AF_INET6)
+ : if (getaddrinfo == NULL)
+ : haveIPv6 = 0;
+ :#endif
+ :
+ : TRANS(GetHostname) (hostnamebuf, sizeof (hostnamebuf));
+ :
+ : if (strcmp (hostnamebuf, host) == 0)
+ : {
+ : return (1);
+ : }
+ :#if defined(IPv6) && defined(AF_INET6)
+ : else if (haveIPv6)
+ : {
+ : struct addrinfo *localhostaddr;
+ : struct addrinfo *otherhostaddr;
+ : struct addrinfo *i, *j;
+ : int equiv = 0;
+ :
+ : if (getaddrinfo(hostnamebuf, NULL, NULL, &localhostaddr) != 0)
+ : return 0;
+ : if (getaddrinfo(host, NULL, NULL, &otherhostaddr) != 0) {
+ : freeaddrinfo(localhostaddr);
+ : return 0;
+ : }
+ :
+ : for (i = localhostaddr; i != NULL && equiv == 0; i = i->ai_next) {
+ : for (j = otherhostaddr; j != NULL && equiv == 0; j = j->ai_next) {
+ : if (i->ai_family == j->ai_family) {
+ : if (i->ai_family == AF_INET) {
+ : struct sockaddr_in *sinA
+ : = (struct sockaddr_in *) i->ai_addr;
+ : struct sockaddr_in *sinB
+ : = (struct sockaddr_in *) j->ai_addr;
+ : struct in_addr *A = &sinA->sin_addr;
+ : struct in_addr *B = &sinB->sin_addr;
+ :
+ : if (memcmp(A,B,sizeof(struct in_addr)) == 0) {
+ : equiv = 1;
+ : }
+ : } else if (i->ai_family == AF_INET6) {
+ : struct sockaddr_in6 *sinA
+ : = (struct sockaddr_in6 *) i->ai_addr;
+ : struct sockaddr_in6 *sinB
+ : = (struct sockaddr_in6 *) j->ai_addr;
+ : struct in6_addr *A = &sinA->sin6_addr;
+ : struct in6_addr *B = &sinB->sin6_addr;
+ :
+ : if (memcmp(A,B,sizeof(struct in6_addr)) == 0) {
+ : equiv = 1;
+ : }
+ : }
+ : }
+ : }
+ : }
+ :
+ : freeaddrinfo(localhostaddr);
+ : freeaddrinfo(otherhostaddr);
+ : return equiv;
+ : }
+ :#endif
+ : else
+ : {
+ : /*
+ : * A host may have more than one network address. If any of the
+ : * network addresses of 'host' (specified to the connect call)
+ : * match any of the network addresses of 'hostname' (determined
+ : * by TRANS(GetHostname)), then the two hostnames are equivalent,
+ : * and we know that 'host' is really a local host.
+ : */
+ : char specified_local_addr_list[10][4];
+ : int scount, equiv, i, j;
+ :#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
+ : _Xgethostbynameparams hparams;
+ :#endif
+ : struct hostent *hostp;
+ :
+ : if ((hostp = _XGethostbyname (host,hparams)) == NULL)
+ : return (0);
+ :
+ : scount = 0;
+ : while (hostp->h_addr_list[scount] && scount <= 8)
+ : {
+ : /*
+ : * The 2nd call to gethostname() overrides the data
+ : * from the 1st call, so we must save the address list.
+ : */
+ :
+ : specified_local_addr_list[scount][0] =
+ : hostp->h_addr_list[scount][0];
+ : specified_local_addr_list[scount][1] =
+ : hostp->h_addr_list[scount][1];
+ : specified_local_addr_list[scount][2] =
+ : hostp->h_addr_list[scount][2];
+ : specified_local_addr_list[scount][3] =
+ : hostp->h_addr_list[scount][3];
+ : scount++;
+ : }
+ : if ((hostp = _XGethostbyname (hostnamebuf,hparams)) == NULL)
+ : return (0);
+ :
+ : equiv = 0;
+ : i = 0;
+ :
+ : while (i < scount && !equiv)
+ : {
+ : j = 0;
+ :
+ : while (hostp->h_addr_list[j])
+ : {
+ : if ((specified_local_addr_list[i][0] ==
+ : hostp->h_addr_list[j][0]) &&
+ : (specified_local_addr_list[i][1] ==
+ : hostp->h_addr_list[j][1]) &&
+ : (specified_local_addr_list[i][2] ==
+ : hostp->h_addr_list[j][2]) &&
+ : (specified_local_addr_list[i][3] ==
+ : hostp->h_addr_list[j][3]))
+ : {
+ : /* They're equal, so we're done */
+ :
+ : equiv = 1;
+ : break;
+ : }
+ :
+ : j++;
+ : }
+ :
+ : i++;
+ : }
+ : return (equiv);
+ : }
+ :}
+ :
+ :static int
+ :TRANS(SocketUNIXConnect) (XtransConnInfo ciptr, char *host, char *port)
+ :
+ :{
+ : struct sockaddr_un sockname;
+ : int namelen;
+ :
+ :#if defined(hpux) && defined(X11_t)
+ : struct sockaddr_un old_sockname;
+ : int old_namelen;
+ :#endif
+ :
+ :
+ : PRMSG (2,"SocketUNIXConnect(%d,%s,%s)\n", ciptr->fd, host, port);
+ :
+ : /*
+ : * Make sure 'host' is really local. If not, we return failure.
+ : * The reason we make this check is because a process may advertise
+ : * a "local" network ID for which it can accept connections, but if
+ : * a process on a remote machine tries to connect to this network ID,
+ : * we know for sure it will fail.
+ : */
+ :
+ : if (strcmp (host, "unix") != 0 && !UnixHostReallyLocal (host))
+ : {
+ : PRMSG (1,
+ : "SocketUNIXConnect: Cannot connect to non-local host %s\n",
+ : host, 0, 0);
+ : return TRANS_CONNECT_FAILED;
+ : }
+ :
+ :
+ : /*
+ : * Check the port.
+ : */
+ :
+ : if (!port || !*port)
+ : {
+ : PRMSG (1,"SocketUNIXConnect: Missing port specification\n",
+ : 0, 0, 0);
+ : return TRANS_CONNECT_FAILED;
+ : }
+ :
+ : /*
+ : * Build the socket name.
+ : */
+ :
+ : sockname.sun_family = AF_UNIX;
+ :
+ : if (set_sun_path(port, UNIX_PATH, sockname.sun_path) != 0) {
+ : PRMSG (1, "SocketUNIXConnect: path too long\n", 0, 0, 0);
+ : return TRANS_CONNECT_FAILED;
+ : }
+ :
+ :#if (defined(BSD44SOCKETS) || defined(__UNIXWARE__)) && !defined(Lynx)
+ : sockname.sun_len = strlen (sockname.sun_path);
+ :#endif
+ :
+ :#if defined(BSD44SOCKETS) || defined(SUN_LEN)
+ : namelen = SUN_LEN (&sockname);
+ :#else
+ : namelen = strlen (sockname.sun_path) + offsetof(struct sockaddr_un, sun_path);
+ :#endif
+ :
+ :
+ :#if defined(hpux) && defined(X11_t)
+ : /*
+ : * This is gross, but it was in Xlib
+ : */
+ : old_sockname.sun_family = AF_UNIX;
+ : if (set_sun_path(port, OLD_UNIX_PATH, old_sockname.sun_path) != 0) {
+ : PRMSG (1, "SocketUNIXConnect: path too long\n", 0, 0, 0);
+ : return TRANS_CONNECT_FAILED;
+ : }
+ : old_namelen = strlen (old_sockname.sun_path) +
+ : offsetof(struct sockaddr_un, sun_path);
+ :#endif
+ :
+ :
+ : /*
+ : * Do the connect()
+ : */
+ :
+ : if (connect (ciptr->fd, (struct sockaddr *) &sockname, namelen) < 0)
+ : {
+ : int olderrno = errno;
+ : int connected = 0;
+ :
+ :#if defined(hpux) && defined(X11_t)
+ : if (olderrno == ENOENT)
+ : {
+ : if (connect (ciptr->fd,
+ : (struct sockaddr *) &old_sockname, old_namelen) >= 0)
+ : {
+ : connected = 1;
+ : }
+ : else
+ : olderrno = errno;
+ : }
+ :#endif
+ : if (!connected)
+ : {
+ : errno = olderrno;
+ :
+ : /*
+ : * If the error was ENOENT, the server may be starting up
+ : * and we should try again.
+ : *
+ : * If the error was EWOULDBLOCK or EINPROGRESS then the socket
+ : * was non-blocking and we should poll using select
+ : *
+ : * If the error was EINTR, the connect was interrupted and we
+ : * should try again.
+ : */
+ :
+ : if (olderrno == ENOENT || olderrno == EINTR)
+ : return TRANS_TRY_CONNECT_AGAIN;
+ : else if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS)
+ : return TRANS_IN_PROGRESS;
+ : else
+ : {
+ : PRMSG (2,"SocketUNIXConnect: Can't connect: errno = %d\n",
+ : EGET(),0, 0);
+ :
+ : return TRANS_CONNECT_FAILED;
+ : }
+ : }
+ : }
+ :
+ : /*
+ : * Get the socket name and the peer name from the connect socket,
+ : * since this is unix domain.
+ : */
+ :
+ : if ((ciptr->addr = (char *) xalloc(namelen)) == NULL ||
+ : (ciptr->peeraddr = (char *) xalloc(namelen)) == NULL)
+ : {
+ : PRMSG (1,
+ : "SocketUNIXCreateListener: Can't allocate space for the addr\n",
+ : 0, 0, 0);
+ : return TRANS_CONNECT_FAILED;
+ : }
+ :
+ : ciptr->family = AF_UNIX;
+ : ciptr->addrlen = namelen;
+ : ciptr->peeraddrlen = namelen;
+ : memcpy (ciptr->addr, &sockname, ciptr->addrlen);
+ : memcpy (ciptr->peeraddr, &sockname, ciptr->peeraddrlen);
+ :
+ : return 0;
+ :}
+ :
+ :#endif /* UNIXCONN */
+ :
+ :#endif /* TRANS_CLIENT */
+ :
+ :
+ :static int
+ :TRANS(SocketBytesReadable) (XtransConnInfo ciptr, BytesReadable_t *pend)
+ :
+ :{
+ : PRMSG (2,"SocketBytesReadable(%p,%d,%p)\n",
+ : ciptr, ciptr->fd, pend);
+ :#if defined(QNX4)
+ : *pend = 0L; /* FIONREAD only returns a short. Zero out upper bits */
+ :#endif
+ :#ifdef WIN32
+ : {
+ : int ret = ioctlsocket ((SOCKET) ciptr->fd, FIONREAD, (u_long *) pend);
+ : errno = WSAGetLastError();
+ : return ret;
+ : }
+ :#else
+ :#if (defined(i386) && defined(SYSV) && !defined(SCO325)) || (defined(_SEQUENT_) && _SOCKET_VERSION == 1)
+ : return ioctl (ciptr->fd, I_NREAD, (char *) pend);
+ :#else
+ :#if defined(__UNIXOS2__)
+ : return ioctl (ciptr->fd, FIONREAD, (char*) pend, sizeof(int));
+ :#else
+ : return ioctl (ciptr->fd, FIONREAD, (char *) pend);
+ :#endif /* __UNIXOS2__ */
+ :#endif /* i386 && SYSV || _SEQUENT_ && _SOCKET_VERSION == 1 */
+ :#endif /* WIN32 */
+ :}
+ :
+ :
+ :static int
+ :TRANS(SocketRead) (XtransConnInfo ciptr, char *buf, int size)
+ :
+ 1 0.0011 :{ /* _XSERVTransSocketRead total: 2 0.0022 */
+ : PRMSG (2,"SocketRead(%d,%p,%d)\n", ciptr->fd, buf, size);
+ :
+ :#if defined(WIN32) || defined(__UNIXOS2__)
+ : {
+ : int ret = recv ((SOCKET)ciptr->fd, buf, size, 0);
+ :#ifdef WIN32
+ : errno = WSAGetLastError();
+ :#endif
+ : return ret;
+ : }
+ :#else
+ 1 0.0011 : return read (ciptr->fd, buf, size);
+ :#endif /* WIN32 */
+ :}
+ :
+ :
+ :static int
+ :TRANS(SocketWrite) (XtransConnInfo ciptr, char *buf, int size)
+ :
+ :{
+ : PRMSG (2,"SocketWrite(%d,%p,%d)\n", ciptr->fd, buf, size);
+ :
+ :#if defined(WIN32) || defined(__UNIXOS2__)
+ : {
+ : int ret = send ((SOCKET)ciptr->fd, buf, size, 0);
+ :#ifdef WIN32
+ : errno = WSAGetLastError();
+ :#endif
+ : return ret;
+ : }
+ :#else
+ : return write (ciptr->fd, buf, size);
+ :#endif /* WIN32 */
+ :}
+ :
+ :
+ :static int
+ :TRANS(SocketReadv) (XtransConnInfo ciptr, struct iovec *buf, int size)
+ :
+ :{
+ : PRMSG (2,"SocketReadv(%d,%p,%d)\n", ciptr->fd, buf, size);
+ :
+ : return READV (ciptr, buf, size);
+ :}
+ :
+ :
+ :static int
+ :TRANS(SocketWritev) (XtransConnInfo ciptr, struct iovec *buf, int size)
+ :
+ :{
+ : PRMSG (2,"SocketWritev(%d,%p,%d)\n", ciptr->fd, buf, size);
+ :
+ : return WRITEV (ciptr, buf, size);
+ :}
+ :
+ :
+ :static int
+ :TRANS(SocketDisconnect) (XtransConnInfo ciptr)
+ :
+ :{
+ : PRMSG (2,"SocketDisconnect(%p,%d)\n", ciptr, ciptr->fd, 0);
+ :
+ :#ifdef WIN32
+ : {
+ : int ret = shutdown (ciptr->fd, 2);
+ : errno = WSAGetLastError();
+ : return ret;
+ : }
+ :#else
+ : return shutdown (ciptr->fd, 2); /* disallow further sends and receives */
+ :#endif
+ :}
+ :
+ :
+ :#ifdef TCPCONN
+ :static int
+ :TRANS(SocketINETClose) (XtransConnInfo ciptr)
+ :
+ :{
+ : PRMSG (2,"SocketINETClose(%p,%d)\n", ciptr, ciptr->fd, 0);
+ :
+ :#ifdef WIN32
+ : {
+ : int ret = close (ciptr->fd);
+ : errno = WSAGetLastError();
+ : return ret;
+ : }
+ :#else
+ : return close (ciptr->fd);
+ :#endif
+ :}
+ :
+ :#endif /* TCPCONN */
+ :
+ :
+ :#ifdef UNIXCONN
+ :static int
+ :TRANS(SocketUNIXClose) (XtransConnInfo ciptr)
+ :
+ :{
+ : /*
+ : * If this is the server side, then once the socket is closed,
+ : * it must be unlinked to completely close it
+ : */
+ :
+ : struct sockaddr_un *sockname = (struct sockaddr_un *) ciptr->addr;
+ : int ret;
+ :
+ : PRMSG (2,"SocketUNIXClose(%p,%d)\n", ciptr, ciptr->fd, 0);
+ :
+ : ret = close(ciptr->fd);
+ :
+ : if (ciptr->flags
+ : && sockname
+ : && sockname->sun_family == AF_UNIX
+ : && sockname->sun_path[0])
+ : {
+ : if (!(ciptr->flags & TRANS_NOUNLINK))
+ : unlink (sockname->sun_path);
+ : }
+ :
+ : return ret;
+ :}
+ :
+ :static int
+ :TRANS(SocketUNIXCloseForCloning) (XtransConnInfo ciptr)
+ :
+ :{
+ : /*
+ : * Don't unlink path.
+ : */
+ :
+ : int ret;
+ :
+ : PRMSG (2,"SocketUNIXCloseForCloning(%p,%d)\n",
+ : ciptr, ciptr->fd, 0);
+ :
+ : ret = close(ciptr->fd);
+ :
+ : return ret;
+ :}
+ :
+ :#endif /* UNIXCONN */
+ :
+ :
+ :#ifdef TCPCONN
+ :# ifdef TRANS_SERVER
+ :static char* tcp_nolisten[] = {
+ : "inet",
+ :#if defined(IPv6) && defined(AF_INET6)
+ : "inet6",
+ :#endif
+ : NULL
+ :};
+ :# endif
+ :
+ :Xtransport TRANS(SocketTCPFuncs) = {
+ : /* Socket Interface */
+ : "tcp",
+ : TRANS_ALIAS,
+ :#ifdef TRANS_CLIENT
+ : TRANS(SocketOpenCOTSClient),
+ :#endif /* TRANS_CLIENT */
+ :#ifdef TRANS_SERVER
+ : tcp_nolisten,
+ : TRANS(SocketOpenCOTSServer),
+ :#endif /* TRANS_SERVER */
+ :#ifdef TRANS_CLIENT
+ : TRANS(SocketOpenCLTSClient),
+ :#endif /* TRANS_CLIENT */
+ :#ifdef TRANS_SERVER
+ : TRANS(SocketOpenCLTSServer),
+ :#endif /* TRANS_SERVER */
+ :#ifdef TRANS_REOPEN
+ : TRANS(SocketReopenCOTSServer),
+ : TRANS(SocketReopenCLTSServer),
+ :#endif
+ : TRANS(SocketSetOption),
+ :#ifdef TRANS_SERVER
+ : TRANS(SocketINETCreateListener),
+ : NULL, /* ResetListener */
+ : TRANS(SocketINETAccept),
+ :#endif /* TRANS_SERVER */
+ :#ifdef TRANS_CLIENT
+ : TRANS(SocketINETConnect),
+ :#endif /* TRANS_CLIENT */
+ : TRANS(SocketBytesReadable),
+ : TRANS(SocketRead),
+ : TRANS(SocketWrite),
+ : TRANS(SocketReadv),
+ : TRANS(SocketWritev),
+ : TRANS(SocketDisconnect),
+ : TRANS(SocketINETClose),
+ : TRANS(SocketINETClose),
+ : };
+ :
+ :Xtransport TRANS(SocketINETFuncs) = {
+ : /* Socket Interface */
+ : "inet",
+ : 0,
+ :#ifdef TRANS_CLIENT
+ : TRANS(SocketOpenCOTSClient),
+ :#endif /* TRANS_CLIENT */
+ :#ifdef TRANS_SERVER
+ : NULL,
+ : TRANS(SocketOpenCOTSServer),
+ :#endif /* TRANS_SERVER */
+ :#ifdef TRANS_CLIENT
+ : TRANS(SocketOpenCLTSClient),
+ :#endif /* TRANS_CLIENT */
+ :#ifdef TRANS_SERVER
+ : TRANS(SocketOpenCLTSServer),
+ :#endif /* TRANS_SERVER */
+ :#ifdef TRANS_REOPEN
+ : TRANS(SocketReopenCOTSServer),
+ : TRANS(SocketReopenCLTSServer),
+ :#endif
+ : TRANS(SocketSetOption),
+ :#ifdef TRANS_SERVER
+ : TRANS(SocketINETCreateListener),
+ : NULL, /* ResetListener */
+ : TRANS(SocketINETAccept),
+ :#endif /* TRANS_SERVER */
+ :#ifdef TRANS_CLIENT
+ : TRANS(SocketINETConnect),
+ :#endif /* TRANS_CLIENT */
+ : TRANS(SocketBytesReadable),
+ : TRANS(SocketRead),
+ : TRANS(SocketWrite),
+ : TRANS(SocketReadv),
+ : TRANS(SocketWritev),
+ : TRANS(SocketDisconnect),
+ : TRANS(SocketINETClose),
+ : TRANS(SocketINETClose),
+ : };
+ :
+ :#if defined(IPv6) && defined(AF_INET6)
+ :Xtransport TRANS(SocketINET6Funcs) = {
+ : /* Socket Interface */
+ : "inet6",
+ : 0,
+ :#ifdef TRANS_CLIENT
+ : TRANS(SocketOpenCOTSClient),
+ :#endif /* TRANS_CLIENT */
+ :#ifdef TRANS_SERVER
+ : NULL,
+ : TRANS(SocketOpenCOTSServer),
+ :#endif /* TRANS_SERVER */
+ :#ifdef TRANS_CLIENT
+ : TRANS(SocketOpenCLTSClient),
+ :#endif /* TRANS_CLIENT */
+ :#ifdef TRANS_SERVER
+ : TRANS(SocketOpenCLTSServer),
+ :#endif /* TRANS_SERVER */
+ :#ifdef TRANS_REOPEN
+ : TRANS(SocketReopenCOTSServer),
+ : TRANS(SocketReopenCLTSServer),
+ :#endif
+ : TRANS(SocketSetOption),
+ :#ifdef TRANS_SERVER
+ : TRANS(SocketINETCreateListener),
+ : NULL, /* ResetListener */
+ : TRANS(SocketINETAccept),
+ :#endif /* TRANS_SERVER */
+ :#ifdef TRANS_CLIENT
+ : TRANS(SocketINETConnect),
+ :#endif /* TRANS_CLIENT */
+ : TRANS(SocketBytesReadable),
+ : TRANS(SocketRead),
+ : TRANS(SocketWrite),
+ : TRANS(SocketReadv),
+ : TRANS(SocketWritev),
+ : TRANS(SocketDisconnect),
+ : TRANS(SocketINETClose),
+ : TRANS(SocketINETClose),
+ : };
+ :#endif /* IPv6 */
+ :#endif /* TCPCONN */
+ :
+ :#ifdef UNIXCONN
+ :#if !defined(LOCALCONN)
+ :Xtransport TRANS(SocketLocalFuncs) = {
+ : /* Socket Interface */
+ : "local",
+ : 0,
+ :#ifdef TRANS_CLIENT
+ : TRANS(SocketOpenCOTSClient),
+ :#endif /* TRANS_CLIENT */
+ :#ifdef TRANS_SERVER
+ : NULL,
+ : TRANS(SocketOpenCOTSServer),
+ :#endif /* TRANS_SERVER */
+ :#ifdef TRANS_CLIENT
+ : TRANS(SocketOpenCLTSClient),
+ :#endif /* TRANS_CLIENT */
+ :#ifdef TRANS_SERVER
+ : TRANS(SocketOpenCLTSServer),
+ :#endif /* TRANS_SERVER */
+ :#ifdef TRANS_REOPEN
+ : TRANS(SocketReopenCOTSServer),
+ : TRANS(SocketReopenCLTSServer),
+ :#endif
+ : TRANS(SocketSetOption),
+ :#ifdef TRANS_SERVER
+ : TRANS(SocketUNIXCreateListener),
+ : TRANS(SocketUNIXResetListener),
+ : TRANS(SocketUNIXAccept),
+ :#endif /* TRANS_SERVER */
+ :#ifdef TRANS_CLIENT
+ : TRANS(SocketUNIXConnect),
+ :#endif /* TRANS_CLIENT */
+ : TRANS(SocketBytesReadable),
+ : TRANS(SocketRead),
+ : TRANS(SocketWrite),
+ : TRANS(SocketReadv),
+ : TRANS(SocketWritev),
+ : TRANS(SocketDisconnect),
+ : TRANS(SocketUNIXClose),
+ : TRANS(SocketUNIXCloseForCloning),
+ : };
+ :#endif /* !LOCALCONN */
+ :# ifdef TRANS_SERVER
+ :# if !defined(LOCALCONN)
+ :static char* unix_nolisten[] = { "local" , NULL };
+ :# endif
+ :# endif
+ :
+ :Xtransport TRANS(SocketUNIXFuncs) = {
+ : /* Socket Interface */
+ : "unix",
+ :#if !defined(LOCALCONN)
+ : TRANS_ALIAS,
+ :#else
+ : 0,
+ :#endif
+ :#ifdef TRANS_CLIENT
+ : TRANS(SocketOpenCOTSClient),
+ :#endif /* TRANS_CLIENT */
+ :#ifdef TRANS_SERVER
+ :#if !defined(LOCALCONN)
+ : unix_nolisten,
+ :#else
+ : NULL,
+ :#endif
+ : TRANS(SocketOpenCOTSServer),
+ :#endif /* TRANS_SERVER */
+ :#ifdef TRANS_CLIENT
+ : TRANS(SocketOpenCLTSClient),
+ :#endif /* TRANS_CLIENT */
+ :#ifdef TRANS_SERVER
+ : TRANS(SocketOpenCLTSServer),
+ :#endif /* TRANS_SERVER */
+ :#ifdef TRANS_REOPEN
+ : TRANS(SocketReopenCOTSServer),
+ : TRANS(SocketReopenCLTSServer),
+ :#endif
+ : TRANS(SocketSetOption),
+ :#ifdef TRANS_SERVER
+ : TRANS(SocketUNIXCreateListener),
+ : TRANS(SocketUNIXResetListener),
+ : TRANS(SocketUNIXAccept),
+ :#endif /* TRANS_SERVER */
+ :#ifdef TRANS_CLIENT
+ : TRANS(SocketUNIXConnect),
+ :#endif /* TRANS_CLIENT */
+ : TRANS(SocketBytesReadable),
+ : TRANS(SocketRead),
+ : TRANS(SocketWrite),
+ : TRANS(SocketReadv),
+ : TRANS(SocketWritev),
+ : TRANS(SocketDisconnect),
+ : TRANS(SocketUNIXClose),
+ : TRANS(SocketUNIXCloseForCloning),
+ : };
+ :
+ :#endif /* UNIXCONN */
+/*
+ * Total samples for file : "/home/cworth/src/xorg/xserver/fb/fbtrap.c"
+ *
+ * 1 0.0011
+ */
+
+
+ :/*
+ : * Copyright © 2004 Keith Packard
+ : *
+ : * 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 Keith Packard not be used in
+ : * advertising or publicity pertaining to distribution of the software without
+ : * specific, written prior permission. Keith Packard makes no
+ : * representations about the suitability of this software for any purpose. It
+ : * is provided "as is" without express or implied warranty.
+ : *
+ : * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ : * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ : * EVENT SHALL KEITH PACKARD 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.
+ : */
+ :
+ :#ifdef HAVE_DIX_CONFIG_H
+ :#include <dix-config.h>
+ :#endif
+ :
+ :#include "fb.h"
+ :
+ :#ifdef RENDER
+ :
+ :#include "picturestr.h"
+ :#include "mipict.h"
+ :#include "renderedge.h"
+ :#include "fbpict.h"
+ :
+ :void
+ :fbAddTraps (PicturePtr pPicture,
+ : INT16 x_off,
+ : INT16 y_off,
+ : int ntrap,
+ : xTrap *traps)
+ :{
+ : pixman_image_t *image = image_from_pict (pPicture, FALSE);
+ :
+ : if (!image)
+ : return;
+ :
+ : pixman_add_traps (image, x_off, y_off, ntrap, (pixman_trap_t *)traps);
+ :
+ : fbFinishAccess (pPicture->pDrawable);
+ :
+ : pixman_image_unref (image);
+ :}
+ :
+ :void
+ :fbRasterizeTrapezoid (PicturePtr pPicture,
+ : xTrapezoid *trap,
+ : int x_off,
+ : int y_off)
+ :{ /* fbRasterizeTrapezoid total: 1 0.0011 */
+ : pixman_image_t *image = image_from_pict (pPicture, FALSE);
+ :
+ : if (!image)
+ : return;
+ :
+ : pixman_rasterize_trapezoid (image, (pixman_trapezoid_t *)trap, x_off, y_off);
+ :
+ : fbFinishAccess (pPicture->pDrawable);
+ :
+ 1 0.0011 : pixman_image_unref (image);
+ :}
+ :
+ :static int
+ :_GreaterY (xPointFixed *a, xPointFixed *b)
+ :{
+ : if (a->y == b->y)
+ : return a->x > b->x;
+ : return a->y > b->y;
+ :}
+ :
+ :/*
+ : * Note that the definition of this function is a bit odd because
+ : * of the X coordinate space (y increasing downwards).
+ : */
+ :static int
+ :_Clockwise (xPointFixed *ref, xPointFixed *a, xPointFixed *b)
+ :{
+ : xPointFixed ad, bd;
+ :
+ : ad.x = a->x - ref->x;
+ : ad.y = a->y - ref->y;
+ : bd.x = b->x - ref->x;
+ : bd.y = b->y - ref->y;
+ :
+ : return ((xFixed_32_32) bd.y * ad.x - (xFixed_32_32) ad.y * bd.x) < 0;
+ :}
+ :
+ :/* FIXME -- this could be made more efficient */
+ :void
+ :fbAddTriangles (PicturePtr pPicture,
+ : INT16 x_off,
+ : INT16 y_off,
+ : int ntri,
+ : xTriangle *tris)
+ :{
+ : xPointFixed *top, *left, *right, *tmp;
+ : xTrapezoid trap;
+ :
+ : for (; ntri; ntri--, tris++)
+ : {
+ : top = &tris->p1;
+ : left = &tris->p2;
+ : right = &tris->p3;
+ : if (_GreaterY (top, left)) {
+ : tmp = left; left = top; top = tmp;
+ : }
+ : if (_GreaterY (top, right)) {
+ : tmp = right; right = top; top = tmp;
+ : }
+ : if (_Clockwise (top, right, left)) {
+ : tmp = right; right = left; left = tmp;
+ : }
+ :
+ : /*
+ : * Two cases:
+ : *
+ : * + +
+ : * / \ / \
+ : * / \ / \
+ : * / + + \
+ : * / -- -- \
+ : * / -- -- \
+ : * / --- --- \
+ : * +-- --+
+ : */
+ :
+ : trap.top = top->y;
+ : trap.left.p1 = *top;
+ : trap.left.p2 = *left;
+ : trap.right.p1 = *top;
+ : trap.right.p2 = *right;
+ : if (right->y < left->y)
+ : trap.bottom = right->y;
+ : else
+ : trap.bottom = left->y;
+ : fbRasterizeTrapezoid (pPicture, &trap, x_off, y_off);
+ : if (right->y < left->y)
+ : {
+ : trap.top = right->y;
+ : trap.bottom = left->y;
+ : trap.right.p1 = *right;
+ : trap.right.p2 = *left;
+ : }
+ : else
+ : {
+ : trap.top = left->y;
+ : trap.bottom = right->y;
+ : trap.left.p1 = *left;
+ : trap.left.p2 = *right;
+ : }
+ : fbRasterizeTrapezoid (pPicture, &trap, x_off, y_off);
+ : }
+ :}
+ :
+ :#endif /* RENDER */
+/*
+ * Total samples for file : "/home/cworth/opt/xorg//include/X11/Xtrans/Xtrans.c"
+ *
+ * 1 0.0011
+ */
+
+
+ :/* $XdotOrg: xc/lib/xtrans/Xtrans.c,v 1.4 2004/11/15 15:06:56 ago Exp $ */
+ :/* $Xorg: Xtrans.c,v 1.4 2001/02/09 02:04:06 xorgcvs Exp $ */
+ :/*
+ :
+ :Copyright 1993, 1994, 1998 The Open Group
+ :
+ :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.
+ :
+ :The above copyright notice and this permission notice shall be included
+ :in all copies or substantial portions of the Software.
+ :
+ :THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ :OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ :MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ :IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ :OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ :ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ :OTHER DEALINGS IN THE SOFTWARE.
+ :
+ :Except as contained in this notice, the name of The Open Group shall
+ :not be used in advertising or otherwise to promote the sale, use or
+ :other dealings in this Software without prior written authorization
+ :from The Open Group.
+ :
+ :*/
+ :/* $XFree86: xc/lib/xtrans/Xtrans.c,v 3.33 2003/08/11 17:41:29 eich Exp $ */
+ :
+ :/* Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA
+ : *
+ : * All Rights Reserved
+ : *
+ : * Permission to use, copy, modify, and distribute this software and its
+ : * documentation for any purpose and without fee is hereby granted, 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 NCR not be used in advertising
+ : * or publicity pertaining to distribution of the software without specific,
+ : * written prior permission. NCR makes no representations about the
+ : * suitability of this software for any purpose. It is provided "as is"
+ : * without express or implied warranty.
+ : *
+ : * NCR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ : * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ : * NO EVENT SHALL NCR 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.
+ : */
+ :
+ :#include <ctype.h>
+ :
+ :/*
+ : * The transport table contains a definition for every transport (protocol)
+ : * family. All operations that can be made on the transport go through this
+ : * table.
+ : *
+ : * Each transport is assigned a unique transport id.
+ : *
+ : * New transports can be added by adding an entry in this table.
+ : * For compatiblity, the transport ids should never be renumbered.
+ : * Always add to the end of the list.
+ : */
+ :
+ :#define TRANS_TLI_INET_INDEX 1
+ :#define TRANS_TLI_TCP_INDEX 2
+ :#define TRANS_TLI_TLI_INDEX 3
+ :#define TRANS_SOCKET_UNIX_INDEX 4
+ :#define TRANS_SOCKET_LOCAL_INDEX 5
+ :#define TRANS_SOCKET_INET_INDEX 6
+ :#define TRANS_SOCKET_TCP_INDEX 7
+ :#define TRANS_DNET_INDEX 8
+ :#define TRANS_LOCAL_LOCAL_INDEX 9
+ :#define TRANS_LOCAL_PTS_INDEX 10
+ :#define TRANS_LOCAL_NAMED_INDEX 11
+ :#define TRANS_LOCAL_ISC_INDEX 12
+ :#define TRANS_LOCAL_SCO_INDEX 13
+ :#define TRANS_SOCKET_INET6_INDEX 14
+ :#define TRANS_LOCAL_PIPE_INDEX 15
+ :
+ :
+ :static
+ :Xtransport_table Xtransports[] = {
+ :#if defined(STREAMSCONN)
+ : { &TRANS(TLITCPFuncs), TRANS_TLI_TCP_INDEX },
+ : { &TRANS(TLIINETFuncs), TRANS_TLI_INET_INDEX },
+ : { &TRANS(TLITLIFuncs), TRANS_TLI_TLI_INDEX },
+ :#endif /* STREAMSCONN */
+ :#if defined(TCPCONN)
+ : { &TRANS(SocketTCPFuncs), TRANS_SOCKET_TCP_INDEX },
+ :#if defined(IPv6) && defined(AF_INET6)
+ : { &TRANS(SocketINET6Funcs), TRANS_SOCKET_INET6_INDEX },
+ :#endif /* IPv6 */
+ : { &TRANS(SocketINETFuncs), TRANS_SOCKET_INET_INDEX },
+ :#endif /* TCPCONN */
+ :#if defined(DNETCONN)
+ : { &TRANS(DNETFuncs), TRANS_DNET_INDEX },
+ :#endif /* DNETCONN */
+ :#if defined(UNIXCONN)
+ :#if !defined(LOCALCONN)
+ : { &TRANS(SocketLocalFuncs), TRANS_SOCKET_LOCAL_INDEX },
+ :#endif /* !LOCALCONN */
+ : { &TRANS(SocketUNIXFuncs), TRANS_SOCKET_UNIX_INDEX },
+ :#endif /* UNIXCONN */
+ :#if defined(OS2PIPECONN)
+ : { &TRANS(OS2LocalFuncs), TRANS_LOCAL_LOCAL_INDEX },
+ :#endif /* OS2PIPECONN */
+ :#if defined(LOCALCONN)
+ : { &TRANS(LocalFuncs), TRANS_LOCAL_LOCAL_INDEX },
+ :#ifndef sun
+ : { &TRANS(PTSFuncs), TRANS_LOCAL_PTS_INDEX },
+ :#endif /* sun */
+ :#ifdef SVR4
+ : { &TRANS(NAMEDFuncs), TRANS_LOCAL_NAMED_INDEX },
+ :#endif
+ :#ifdef sun
+ : { &TRANS(PIPEFuncs), TRANS_LOCAL_PIPE_INDEX },
+ :#else /* !sun */
+ :#if !defined(__SCO__) && !defined(__UNIXWARE__)
+ : { &TRANS(ISCFuncs), TRANS_LOCAL_ISC_INDEX },
+ :#endif
+ : { &TRANS(SCOFuncs), TRANS_LOCAL_SCO_INDEX },
+ :#endif /* sun */
+ :#endif /* LOCALCONN */
+ :};
+ :
+ :#define NUMTRANS (sizeof(Xtransports)/sizeof(Xtransport_table))
+ :
+ :
+ :#ifdef WIN32
+ :#define ioctl ioctlsocket
+ :#endif
+ :
+ :
+ :\f
+ :/*
+ : * These are a few utility function used by the public interface functions.
+ : */
+ :
+ :void
+ :TRANS(FreeConnInfo) (XtransConnInfo ciptr)
+ :
+ :{
+ : PRMSG (3,"FreeConnInfo(%p)\n", ciptr, 0, 0);
+ :
+ : if (ciptr->addr)
+ : xfree (ciptr->addr);
+ :
+ : if (ciptr->peeraddr)
+ : xfree (ciptr->peeraddr);
+ :
+ : if (ciptr->port)
+ : xfree (ciptr->port);
+ :
+ : xfree ((char *) ciptr);
+ :}
+ :
+ :
+ :#define PROTOBUFSIZE 20
+ :
+ :static Xtransport *
+ :TRANS(SelectTransport) (char *protocol)
+ :
+ :{
+ : char protobuf[PROTOBUFSIZE];
+ : int i;
+ :
+ : PRMSG (3,"SelectTransport(%s)\n", protocol, 0, 0);
+ :
+ : /*
+ : * Force Protocol to be lowercase as a way of doing
+ : * a case insensitive match.
+ : */
+ :
+ : strncpy (protobuf, protocol, PROTOBUFSIZE - 1);
+ : protobuf[PROTOBUFSIZE-1] = '\0';
+ :
+ : for (i = 0; i < PROTOBUFSIZE && protobuf[i] != '\0'; i++)
+ : if (isupper (protobuf[i]))
+ : protobuf[i] = tolower (protobuf[i]);
+ :
+ : /* Look at all of the configured protocols */
+ :
+ : for (i = 0; i < NUMTRANS; i++)
+ : {
+ : if (!strcmp (protobuf, Xtransports[i].transport->TransName))
+ : return Xtransports[i].transport;
+ : }
+ :
+ : return NULL;
+ :}
+ :
+ :#ifndef TEST_t
+ :static
+ :#endif /* TEST_t */
+ :int
+ :TRANS(ParseAddress) (char *address, char **protocol, char **host, char **port)
+ :
+ :{
+ : /*
+ : * For the font library, the address is a string formatted
+ : * as "protocol/host:port[/catalogue]". Note that the catologue
+ : * is optional. At this time, the catologue info is ignored, but
+ : * we have to parse it anyways.
+ : *
+ : * Other than fontlib, the address is a string formatted
+ : * as "protocol/host:port".
+ : *
+ : * If the protocol part is missing, then assume TCP.
+ : * If the protocol part and host part are missing, then assume local.
+ : * If a "::" is found then assume DNET.
+ : */
+ :
+ : char *mybuf, *tmpptr;
+ : char *_protocol, *_host, *_port;
+ : char hostnamebuf[256];
+ : int _host_len;
+ :
+ : PRMSG (3,"ParseAddress(%s)\n", address, 0, 0);
+ :
+ : /* Copy the string so it can be changed */
+ :
+ : tmpptr = mybuf = (char *) xalloc (strlen (address) + 1);
+ : strcpy (mybuf, address);
+ :
+ : /* Parse the string to get each component */
+ :
+ : /* Get the protocol part */
+ :
+ : _protocol = mybuf;
+ :
+ :
+ : if ( ((mybuf = strchr (mybuf,'/')) == NULL) &&
+ : ((mybuf = strrchr (tmpptr,':')) == NULL) )
+ : {
+ : /* address is in a bad format */
+ : *protocol = NULL;
+ : *host = NULL;
+ : *port = NULL;
+ : xfree (tmpptr);
+ : return 0;
+ : }
+ :
+ : if (*mybuf == ':')
+ : {
+ : /*
+ : * If there is a hostname, then assume tcp, otherwise
+ : * it must be local.
+ : */
+ : if (mybuf == tmpptr)
+ : {
+ : /* There is neither a protocol or host specified */
+ : _protocol = "local";
+ : }
+ : else
+ : {
+ : /* There is a hostname specified */
+ : _protocol = "tcp";
+ : mybuf = tmpptr; /* reset to the begining of the host ptr */
+ : }
+ : }
+ : else
+ : {
+ : /* *mybuf == '/' */
+ :
+ : *mybuf ++= '\0'; /* put a null at the end of the protocol */
+ :
+ : if (strlen(_protocol) == 0)
+ : {
+ : /*
+ : * If there is a hostname, then assume tcp, otherwise
+ : * it must be local.
+ : */
+ : if (*mybuf != ':')
+ : _protocol = "tcp";
+ : else
+ : _protocol = "local";
+ : }
+ : }
+ :
+ : /* Get the host part */
+ :
+ : _host = mybuf;
+ :
+ : if ((mybuf = strrchr (mybuf,':')) == NULL)
+ : {
+ : *protocol = NULL;
+ : *host = NULL;
+ : *port = NULL;
+ : xfree (tmpptr);
+ : return 0;
+ : }
+ :
+ : /* Check for DECnet */
+ :
+ : if ((mybuf != _host) && (*(mybuf - 1) == ':')
+ :#if defined(IPv6) && defined(AF_INET6)
+ : /* An IPv6 address can end in :: so three : in a row is assumed to be
+ : an IPv6 host and not a DECnet node with a : in it's name, unless
+ : DECnet is specifically requested */
+ : && ( ((mybuf - 1) == _host) || (*(mybuf - 2) != ':') ||
+ : ((_protocol != NULL) && (strcmp(_protocol, "dnet") == 0)) )
+ :#endif
+ : )
+ : {
+ : _protocol = "dnet";
+ : *(mybuf - 1) = '\0';
+ : }
+ :
+ : *mybuf ++= '\0';
+ :
+ : _host_len = strlen(_host);
+ : if (_host_len == 0)
+ : {
+ : TRANS(GetHostname) (hostnamebuf, sizeof (hostnamebuf));
+ : _host = hostnamebuf;
+ : }
+ :#if defined(IPv6) && defined(AF_INET6)
+ : /* hostname in IPv6 [numeric_addr]:0 form? */
+ : else if ( (_host_len > 3) &&
+ : ((strcmp(_protocol, "tcp") == 0) || (strcmp(_protocol, "inet6") == 0))
+ : && (*_host == '[') && (*(_host + _host_len - 1) == ']') ) {
+ : struct sockaddr_in6 sin6;
+ :
+ : *(_host + _host_len - 1) = '\0';
+ :
+ : /* Verify address is valid IPv6 numeric form */
+ : if (inet_pton(AF_INET6, _host + 1, &sin6) == 1) {
+ : /* It is. Use it as such. */
+ : _host++;
+ : _protocol = "inet6";
+ : } else {
+ : /* It's not, restore it just in case some other code can use it. */
+ : *(_host + _host_len - 1) = ']';
+ : }
+ : }
+ :#endif
+ :
+ :
+ : /* Get the port */
+ :
+ : _port = mybuf;
+ :
+ :#if defined(FONT_t) || defined(FS_t)
+ : /*
+ : * Is there an optional catalogue list?
+ : */
+ :
+ : if ((mybuf = strchr (mybuf,'/')) != NULL)
+ : *mybuf ++= '\0';
+ :
+ : /*
+ : * The rest, if any, is the (currently unused) catalogue list.
+ : *
+ : * _catalogue = mybuf;
+ : */
+ :#endif
+ :
+ : /*
+ : * Now that we have all of the components, allocate new
+ : * string space for them.
+ : */
+ :
+ : if ((*protocol = (char *) xalloc(strlen (_protocol) + 1)) == NULL)
+ : {
+ : /* Malloc failed */
+ : *port = NULL;
+ : *host = NULL;
+ : *protocol = NULL;
+ : xfree (tmpptr);
+ : return 0;
+ : }
+ : else
+ : strcpy (*protocol, _protocol);
+ :
+ : if ((*host = (char *) xalloc (strlen (_host) + 1)) == NULL)
+ : {
+ : /* Malloc failed */
+ : *port = NULL;
+ : *host = NULL;
+ : xfree (*protocol);
+ : *protocol = NULL;
+ : xfree (tmpptr);
+ : return 0;
+ : }
+ : else
+ : strcpy (*host, _host);
+ :
+ : if ((*port = (char *) xalloc (strlen (_port) + 1)) == NULL)
+ : {
+ : /* Malloc failed */
+ : *port = NULL;
+ : xfree (*host);
+ : *host = NULL;
+ : xfree (*protocol);
+ : *protocol = NULL;
+ : xfree (tmpptr);
+ : return 0;
+ : }
+ : else
+ : strcpy (*port, _port);
+ :
+ : xfree (tmpptr);
+ :
+ : return 1;
+ :}
+ :
+ :
+ :/*
+ : * TRANS(Open) does all of the real work opening a connection. The only
+ : * funny part about this is the type parameter which is used to decide which
+ : * type of open to perform.
+ : */
+ :
+ :static XtransConnInfo
+ :TRANS(Open) (int type, char *address)
+ :
+ :{
+ : char *protocol = NULL, *host = NULL, *port = NULL;
+ : XtransConnInfo ciptr = NULL;
+ : Xtransport *thistrans;
+ :
+ : PRMSG (2,"Open(%d,%s)\n", type, address, 0);
+ :
+ :#if defined(WIN32) && (defined(TCPCONN) || defined(DNETCONN))
+ : if (TRANS(WSAStartup)())
+ : {
+ : PRMSG (1,"Open: WSAStartup failed\n", 0, 0, 0);
+ : return NULL;
+ : }
+ :#endif
+ :
+ : /* Parse the Address */
+ :
+ : if (TRANS(ParseAddress) (address, &protocol, &host, &port) == 0)
+ : {
+ : PRMSG (1,"Open: Unable to Parse address %s\n", address, 0, 0);
+ : return NULL;
+ : }
+ :
+ : /* Determine the transport type */
+ :
+ : if ((thistrans = TRANS(SelectTransport) (protocol)) == NULL)
+ : {
+ : PRMSG (1,"Open: Unable to find transport for %s\n",
+ : protocol, 0, 0);
+ :
+ : xfree (protocol);
+ : xfree (host);
+ : xfree (port);
+ : return NULL;
+ : }
+ :
+ : /* Open the transport */
+ :
+ : switch (type)
+ : {
+ : case XTRANS_OPEN_COTS_CLIENT:
+ :#ifdef TRANS_CLIENT
+ : ciptr = thistrans->OpenCOTSClient(thistrans, protocol, host, port);
+ :#endif /* TRANS_CLIENT */
+ : break;
+ : case XTRANS_OPEN_COTS_SERVER:
+ :#ifdef TRANS_SERVER
+ : ciptr = thistrans->OpenCOTSServer(thistrans, protocol, host, port);
+ :#endif /* TRANS_SERVER */
+ : break;
+ : case XTRANS_OPEN_CLTS_CLIENT:
+ :#ifdef TRANS_CLIENT
+ : ciptr = thistrans->OpenCLTSClient(thistrans, protocol, host, port);
+ :#endif /* TRANS_CLIENT */
+ : break;
+ : case XTRANS_OPEN_CLTS_SERVER:
+ :#ifdef TRANS_SERVER
+ : ciptr = thistrans->OpenCLTSServer(thistrans, protocol, host, port);
+ :#endif /* TRANS_SERVER */
+ : break;
+ : default:
+ : PRMSG (1,"Open: Unknown Open type %d\n", type, 0, 0);
+ : }
+ :
+ : if (ciptr == NULL)
+ : {
+ : if (!(thistrans->flags & TRANS_DISABLED))
+ : {
+ : PRMSG (1,"Open: transport open failed for %s/%s:%s\n",
+ : protocol, host, port);
+ : }
+ : xfree (protocol);
+ : xfree (host);
+ : xfree (port);
+ : return NULL;
+ : }
+ :
+ : ciptr->transptr = thistrans;
+ : ciptr->port = port; /* We need this for TRANS(Reopen) */
+ :
+ : xfree (protocol);
+ : xfree (host);
+ :
+ : return ciptr;
+ :}
+ :
+ :
+ :#ifdef TRANS_REOPEN
+ :
+ :/*
+ : * We might want to create an XtransConnInfo object based on a previously
+ : * opened connection. For example, the font server may clone itself and
+ : * pass file descriptors to the parent.
+ : */
+ :
+ :static XtransConnInfo
+ :TRANS(Reopen) (int type, int trans_id, int fd, char *port)
+ :
+ :{
+ : XtransConnInfo ciptr = NULL;
+ : Xtransport *thistrans = NULL;
+ : char *save_port;
+ : int i;
+ :
+ : PRMSG (2,"Reopen(%d,%d,%s)\n", trans_id, fd, port);
+ :
+ : /* Determine the transport type */
+ :
+ : for (i = 0; i < NUMTRANS; i++)
+ : if (Xtransports[i].transport_id == trans_id)
+ : {
+ : thistrans = Xtransports[i].transport;
+ : break;
+ : }
+ :
+ : if (thistrans == NULL)
+ : {
+ : PRMSG (1,"Reopen: Unable to find transport id %d\n",
+ : trans_id, 0, 0);
+ :
+ : return NULL;
+ : }
+ :
+ : if ((save_port = (char *) xalloc (strlen (port) + 1)) == NULL)
+ : {
+ : PRMSG (1,"Reopen: Unable to malloc port string\n", 0, 0, 0);
+ :
+ : return NULL;
+ : }
+ :
+ : strcpy (save_port, port);
+ :
+ : /* Get a new XtransConnInfo object */
+ :
+ : switch (type)
+ : {
+ : case XTRANS_OPEN_COTS_SERVER:
+ : ciptr = thistrans->ReopenCOTSServer(thistrans, fd, port);
+ : break;
+ : case XTRANS_OPEN_CLTS_SERVER:
+ : ciptr = thistrans->ReopenCLTSServer(thistrans, fd, port);
+ : break;
+ : default:
+ : PRMSG (1,"Reopen: Bad Open type %d\n", type, 0, 0);
+ : }
+ :
+ : if (ciptr == NULL)
+ : {
+ : PRMSG (1,"Reopen: transport open failed\n", 0, 0, 0);
+ : return NULL;
+ : }
+ :
+ : ciptr->transptr = thistrans;
+ : ciptr->port = save_port;
+ :
+ : return ciptr;
+ :}
+ :
+ :#endif /* TRANS_REOPEN */
+ :
+ :
+ :\f
+ :/*
+ : * These are the public interfaces to this Transport interface.
+ : * These are the only functions that should have knowledge of the transport
+ : * table.
+ : */
+ :
+ :#ifdef TRANS_CLIENT
+ :
+ :XtransConnInfo
+ :TRANS(OpenCOTSClient) (char *address)
+ :
+ :{
+ : PRMSG (2,"OpenCOTSClient(%s)\n", address, 0, 0);
+ : return TRANS(Open) (XTRANS_OPEN_COTS_CLIENT, address);
+ :}
+ :
+ :#endif /* TRANS_CLIENT */
+ :
+ :
+ :#ifdef TRANS_SERVER
+ :
+ :XtransConnInfo
+ :TRANS(OpenCOTSServer) (char *address)
+ :
+ :{
+ : PRMSG (2,"OpenCOTSServer(%s)\n", address, 0, 0);
+ : return TRANS(Open) (XTRANS_OPEN_COTS_SERVER, address);
+ :}
+ :
+ :#endif /* TRANS_SERVER */
+ :
+ :
+ :#ifdef TRANS_CLIENT
+ :
+ :XtransConnInfo
+ :TRANS(OpenCLTSClient) (char *address)
+ :
+ :{
+ : PRMSG (2,"OpenCLTSClient(%s)\n", address, 0, 0);
+ : return TRANS(Open) (XTRANS_OPEN_CLTS_CLIENT, address);
+ :}
+ :
+ :#endif /* TRANS_CLIENT */
+ :
+ :
+ :#ifdef TRANS_SERVER
+ :
+ :XtransConnInfo
+ :TRANS(OpenCLTSServer) (char *address)
+ :
+ :{
+ : PRMSG (2,"OpenCLTSServer(%s)\n", address, 0, 0);
+ : return TRANS(Open) (XTRANS_OPEN_CLTS_SERVER, address);
+ :}
+ :
+ :#endif /* TRANS_SERVER */
+ :
+ :
+ :#ifdef TRANS_REOPEN
+ :
+ :XtransConnInfo
+ :TRANS(ReopenCOTSServer) (int trans_id, int fd, char *port)
+ :
+ :{
+ : PRMSG (2,"ReopenCOTSServer(%d, %d, %s)\n", trans_id, fd, port);
+ : return TRANS(Reopen) (XTRANS_OPEN_COTS_SERVER, trans_id, fd, port);
+ :}
+ :
+ :XtransConnInfo
+ :TRANS(ReopenCLTSServer) (int trans_id, int fd, char *port)
+ :
+ :{
+ : PRMSG (2,"ReopenCLTSServer(%d, %d, %s)\n", trans_id, fd, port);
+ : return TRANS(Reopen) (XTRANS_OPEN_CLTS_SERVER, trans_id, fd, port);
+ :}
+ :
+ :
+ :int
+ :TRANS(GetReopenInfo) (XtransConnInfo ciptr,
+ : int *trans_id, int *fd, char **port)
+ :
+ :{
+ : int i;
+ :
+ : for (i = 0; i < NUMTRANS; i++)
+ : if (Xtransports[i].transport == ciptr->transptr)
+ : {
+ : *trans_id = Xtransports[i].transport_id;
+ : *fd = ciptr->fd;
+ :
+ : if ((*port = (char *) xalloc (strlen (ciptr->port) + 1)) == NULL)
+ : return 0;
+ : else
+ : {
+ : strcpy (*port, ciptr->port);
+ : return 1;
+ : }
+ : }
+ :
+ : return 0;
+ :}
+ :
+ :#endif /* TRANS_REOPEN */
+ :
+ :
+ :int
+ :TRANS(SetOption) (XtransConnInfo ciptr, int option, int arg)
+ :
+ :{
+ : int fd = ciptr->fd;
+ : int ret = 0;
+ :
+ : PRMSG (2,"SetOption(%d,%d,%d)\n", fd, option, arg);
+ :
+ : /*
+ : * For now, all transport type use the same stuff for setting options.
+ : * As long as this is true, we can put the common code here. Once a more
+ : * complicated transport such as shared memory or an OSI implementation
+ : * that uses the session and application libraries is implemented, this
+ : * code may have to move to a transport dependent function.
+ : *
+ : * ret = ciptr->transptr->SetOption (ciptr, option, arg);
+ : */
+ :
+ : switch (option)
+ : {
+ : case TRANS_NONBLOCKING:
+ : switch (arg)
+ : {
+ : case 0:
+ : /* Set to blocking mode */
+ : break;
+ : case 1: /* Set to non-blocking mode */
+ :
+ :#if defined(O_NONBLOCK) && (!defined(ultrix) && !defined(hpux) && !defined(AIXV3) && !defined(uniosu) && !defined(__UNIXOS2__) && !defined(SCO325)) && !defined(__QNX__)
+ : ret = fcntl (fd, F_GETFL, 0);
+ : if (ret != -1)
+ : ret = fcntl (fd, F_SETFL, ret | O_NONBLOCK);
+ :#else
+ :#ifdef FIOSNBIO
+ : {
+ : int arg;
+ : arg = 1;
+ : ret = ioctl (fd, FIOSNBIO, &arg);
+ : }
+ :#else
+ :#if (defined(AIXV3) || defined(uniosu) || defined(WIN32) || defined(__UNIXOS2__) || defined(__QNX__)) && defined(FIONBIO)
+ : {
+ :#ifdef WIN32
+ : u_long arg;
+ :#else
+ : int arg;
+ :#endif
+ : arg = 1;
+ :/* IBM TCP/IP understands this option too well: it causes TRANS(Read) to fail
+ : * eventually with EWOULDBLOCK */
+ :#ifndef __UNIXOS2__
+ : ret = ioctl (fd, FIONBIO, &arg);
+ :#else
+ :/* ret = ioctl(fd, FIONBIO, &arg, sizeof(int));*/
+ :#endif
+ : }
+ :#else
+ : ret = fcntl (fd, F_GETFL, 0);
+ :#ifdef FNDELAY
+ : ret = fcntl (fd, F_SETFL, ret | FNDELAY);
+ :#else
+ : ret = fcntl (fd, F_SETFL, ret | O_NDELAY);
+ :#endif
+ :#endif /* AIXV3 || uniosu */
+ :#endif /* FIOSNBIO */
+ :#endif /* O_NONBLOCK */
+ : break;
+ : default:
+ : /* Unknown option */
+ : break;
+ : }
+ : break;
+ : case TRANS_CLOSEONEXEC:
+ :#ifdef F_SETFD
+ :#ifdef FD_CLOEXEC
+ : ret = fcntl (fd, F_SETFD, FD_CLOEXEC);
+ :#else
+ : ret = fcntl (fd, F_SETFD, 1);
+ :#endif /* FD_CLOEXEC */
+ :#endif /* F_SETFD */
+ : break;
+ : }
+ :
+ : return ret;
+ :}
+ :
+ :#ifdef TRANS_SERVER
+ :
+ :int
+ :TRANS(CreateListener) (XtransConnInfo ciptr, char *port, unsigned int flags)
+ :
+ :{
+ : return ciptr->transptr->CreateListener (ciptr, port, flags);
+ :}
+ :
+ :int
+ :TRANS(NoListen) (char * protocol)
+ :
+ :{
+ : Xtransport *trans;
+ : int i = 0, ret = 0;
+ :
+ : if ((trans = TRANS(SelectTransport)(protocol)) == NULL)
+ : {
+ : PRMSG (1,"TransNoListen: unable to find transport: %s\n",
+ : protocol, 0, 0);
+ :
+ : return -1;
+ : }
+ : if (trans->flags & TRANS_ALIAS) {
+ : if (trans->nolisten)
+ : while (trans->nolisten[i]) {
+ : ret |= TRANS(NoListen)(trans->nolisten[i]);
+ : i++;
+ : }
+ : }
+ :
+ : trans->flags |= TRANS_NOLISTEN;
+ : return ret;
+ :}
+ :
+ :int
+ :TRANS(ResetListener) (XtransConnInfo ciptr)
+ :
+ :{
+ : if (ciptr->transptr->ResetListener)
+ : return ciptr->transptr->ResetListener (ciptr);
+ : else
+ : return TRANS_RESET_NOOP;
+ :}
+ :
+ :
+ :XtransConnInfo
+ :TRANS(Accept) (XtransConnInfo ciptr, int *status)
+ :
+ :{
+ : XtransConnInfo newciptr;
+ :
+ : PRMSG (2,"Accept(%d)\n", ciptr->fd, 0, 0);
+ :
+ : newciptr = ciptr->transptr->Accept (ciptr, status);
+ :
+ : if (newciptr)
+ : newciptr->transptr = ciptr->transptr;
+ :
+ : return newciptr;
+ :}
+ :
+ :#endif /* TRANS_SERVER */
+ :
+ :
+ :#ifdef TRANS_CLIENT
+ :
+ :int
+ :TRANS(Connect) (XtransConnInfo ciptr, char *address)
+ :
+ :{
+ : char *protocol;
+ : char *host;
+ : char *port;
+ : int ret;
+ :
+ : PRMSG (2,"Connect(%d,%s)\n", ciptr->fd, address, 0);
+ :
+ : if (TRANS(ParseAddress) (address, &protocol, &host, &port) == 0)
+ : {
+ : PRMSG (1,"Connect: Unable to Parse address %s\n",
+ : address, 0, 0);
+ : return -1;
+ : }
+ :
+ : if (!port || !*port)
+ : {
+ : PRMSG (1,"Connect: Missing port specification in %s\n",
+ : address, 0, 0);
+ : if (protocol) xfree (protocol);
+ : if (host) xfree (host);
+ : return -1;
+ : }
+ :
+ : ret = ciptr->transptr->Connect (ciptr, host, port);
+ :
+ : if (protocol) xfree (protocol);
+ : if (host) xfree (host);
+ : if (port) xfree (port);
+ :
+ : return ret;
+ :}
+ :
+ :#endif /* TRANS_CLIENT */
+ :
+ :
+ :int
+ :TRANS(BytesReadable) (XtransConnInfo ciptr, BytesReadable_t *pend)
+ :
+ :{
+ : return ciptr->transptr->BytesReadable (ciptr, pend);
+ :}
+ :
+ :int
+ :TRANS(Read) (XtransConnInfo ciptr, char *buf, int size)
+ :
+ :{ /* _XSERVTransRead total: 1 0.0011 */
+ 1 0.0011 : return ciptr->transptr->Read (ciptr, buf, size);
+ :}
+ :
+ :int
+ :TRANS(Write) (XtransConnInfo ciptr, char *buf, int size)
+ :
+ :{
+ : return ciptr->transptr->Write (ciptr, buf, size);
+ :}
+ :
+ :int
+ :TRANS(Readv) (XtransConnInfo ciptr, struct iovec *buf, int size)
+ :
+ :{
+ : return ciptr->transptr->Readv (ciptr, buf, size);
+ :}
+ :
+ :int
+ :TRANS(Writev) (XtransConnInfo ciptr, struct iovec *buf, int size)
+ :
+ :{
+ : return ciptr->transptr->Writev (ciptr, buf, size);
+ :}
+ :
+ :int
+ :TRANS(Disconnect) (XtransConnInfo ciptr)
+ :
+ :{
+ : return ciptr->transptr->Disconnect (ciptr);
+ :}
+ :
+ :int
+ :TRANS(Close) (XtransConnInfo ciptr)
+ :
+ :{
+ : int ret;
+ :
+ : PRMSG (2,"Close(%d)\n", ciptr->fd, 0, 0);
+ :
+ : ret = ciptr->transptr->Close (ciptr);
+ :
+ : TRANS(FreeConnInfo) (ciptr);
+ :
+ : return ret;
+ :}
+ :
+ :int
+ :TRANS(CloseForCloning) (XtransConnInfo ciptr)
+ :
+ :{
+ : int ret;
+ :
+ : PRMSG (2,"CloseForCloning(%d)\n", ciptr->fd, 0, 0);
+ :
+ : ret = ciptr->transptr->CloseForCloning (ciptr);
+ :
+ : TRANS(FreeConnInfo) (ciptr);
+ :
+ : return ret;
+ :}
+ :
+ :int
+ :TRANS(IsLocal) (XtransConnInfo ciptr)
+ :
+ :{
+ : return (ciptr->family == AF_UNIX);
+ :}
+ :
+ :
+ :int
+ :TRANS(GetMyAddr) (XtransConnInfo ciptr, int *familyp, int *addrlenp,
+ : Xtransaddr **addrp)
+ :
+ :{
+ : PRMSG (2,"GetMyAddr(%d)\n", ciptr->fd, 0, 0);
+ :
+ : *familyp = ciptr->family;
+ : *addrlenp = ciptr->addrlen;
+ :
+ : if ((*addrp = (Xtransaddr *) xalloc (ciptr->addrlen)) == NULL)
+ : {
+ : PRMSG (1,"GetMyAddr: malloc failed\n", 0, 0, 0);
+ : return -1;
+ : }
+ : memcpy(*addrp, ciptr->addr, ciptr->addrlen);
+ :
+ : return 0;
+ :}
+ :
+ :int
+ :TRANS(GetPeerAddr) (XtransConnInfo ciptr, int *familyp, int *addrlenp,
+ : Xtransaddr **addrp)
+ :
+ :{
+ : PRMSG (2,"GetPeerAddr(%d)\n", ciptr->fd, 0, 0);
+ :
+ : *familyp = ciptr->family;
+ : *addrlenp = ciptr->peeraddrlen;
+ :
+ : if ((*addrp = (Xtransaddr *) xalloc (ciptr->peeraddrlen)) == NULL)
+ : {
+ : PRMSG (1,"GetPeerAddr: malloc failed\n", 0, 0, 0);
+ : return -1;
+ : }
+ : memcpy(*addrp, ciptr->peeraddr, ciptr->peeraddrlen);
+ :
+ : return 0;
+ :}
+ :
+ :
+ :int
+ :TRANS(GetConnectionNumber) (XtransConnInfo ciptr)
+ :
+ :{
+ : return ciptr->fd;
+ :}
+ :
+ :\f
+ :/*
+ : * These functions are really utility functions, but they require knowledge
+ : * of the internal data structures, so they have to be part of the Transport
+ : * Independant API.
+ : */
+ :
+ :#ifdef TRANS_SERVER
+ :
+ :static int
+ :complete_network_count (void)
+ :
+ :{
+ : int count = 0;
+ : int found_local = 0;
+ : int i;
+ :
+ : /*
+ : * For a complete network, we only need one LOCALCONN transport to work
+ : */
+ :
+ : for (i = 0; i < NUMTRANS; i++)
+ : {
+ : if (Xtransports[i].transport->flags & TRANS_ALIAS
+ : || Xtransports[i].transport->flags & TRANS_NOLISTEN)
+ : continue;
+ :
+ : if (Xtransports[i].transport->flags & TRANS_LOCAL)
+ : found_local = 1;
+ : else
+ : count++;
+ : }
+ :
+ : return (count + found_local);
+ :}
+ :
+ :
+ :
+ :int
+ :TRANS(MakeAllCOTSServerListeners) (char *port, int *partial, int *count_ret,
+ : XtransConnInfo **ciptrs_ret)
+ :
+ :{
+ : char buffer[256]; /* ??? What size ?? */
+ : XtransConnInfo ciptr, temp_ciptrs[NUMTRANS];
+ : int status, i, j;
+ :#if defined(IPv6) && defined(AF_INET6)
+ : int ipv6_succ = 0;
+ :#endif
+ :
+ : PRMSG (2,"MakeAllCOTSServerListeners(%s,%p)\n",
+ : port ? port : "NULL", ciptrs_ret, 0);
+ :
+ : *count_ret = 0;
+ :
+ : for (i = 0; i < NUMTRANS; i++)
+ : {
+ : Xtransport *trans = Xtransports[i].transport;
+ : unsigned int flags = 0;
+ :
+ : if (trans->flags&TRANS_ALIAS || trans->flags&TRANS_NOLISTEN)
+ : continue;
+ :
+ : snprintf(buffer, sizeof(buffer), "%s/:%s",
+ : trans->TransName, port ? port : "");
+ :
+ : PRMSG (5,"MakeAllCOTSServerListeners: opening %s\n",
+ : buffer, 0, 0);
+ :
+ : if ((ciptr = TRANS(OpenCOTSServer(buffer))) == NULL)
+ : {
+ : if (trans->flags & TRANS_DISABLED)
+ : continue;
+ :
+ : PRMSG (1,
+ : "MakeAllCOTSServerListeners: failed to open listener for %s\n",
+ : trans->TransName, 0, 0);
+ : continue;
+ : }
+ :#if defined(IPv6) && defined(AF_INET6)
+ : if ((Xtransports[i].transport_id == TRANS_SOCKET_INET_INDEX
+ : && ipv6_succ))
+ : flags |= ADDR_IN_USE_ALLOWED;
+ :#endif
+ :
+ : if ((status = TRANS(CreateListener (ciptr, port, flags))) < 0)
+ : {
+ : if (status == TRANS_ADDR_IN_USE)
+ : {
+ : /*
+ : * We failed to bind to the specified address because the
+ : * address is in use. It must be that a server is already
+ : * running at this address, and this function should fail.
+ : */
+ :
+ : PRMSG (1,
+ : "MakeAllCOTSServerListeners: server already running\n",
+ : 0, 0, 0);
+ :
+ : for (j = 0; j < *count_ret; j++)
+ : TRANS(Close) (temp_ciptrs[j]);
+ :
+ : *count_ret = 0;
+ : *ciptrs_ret = NULL;
+ : *partial = 0;
+ : return -1;
+ : }
+ : else
+ : {
+ : PRMSG (1,
+ : "MakeAllCOTSServerListeners: failed to create listener for %s\n",
+ : trans->TransName, 0, 0);
+ :
+ : continue;
+ : }
+ : }
+ :
+ :#if defined(IPv6) && defined(AF_INET6)
+ : if (Xtransports[i].transport_id == TRANS_SOCKET_INET6_INDEX)
+ : ipv6_succ = 1;
+ :#endif
+ :
+ : PRMSG (5,
+ : "MakeAllCOTSServerListeners: opened listener for %s, %d\n",
+ : trans->TransName, ciptr->fd, 0);
+ :
+ : temp_ciptrs[*count_ret] = ciptr;
+ : (*count_ret)++;
+ : }
+ :
+ : *partial = (*count_ret < complete_network_count());
+ :
+ : PRMSG (5,
+ : "MakeAllCOTSServerListeners: partial=%d, actual=%d, complete=%d \n",
+ : *partial, *count_ret, complete_network_count());
+ :
+ : if (*count_ret > 0)
+ : {
+ : if ((*ciptrs_ret = (XtransConnInfo *) xalloc (
+ : *count_ret * sizeof (XtransConnInfo))) == NULL)
+ : {
+ : return -1;
+ : }
+ :
+ : for (i = 0; i < *count_ret; i++)
+ : {
+ : (*ciptrs_ret)[i] = temp_ciptrs[i];
+ : }
+ : }
+ : else
+ : *ciptrs_ret = NULL;
+ :
+ : return 0;
+ :}
+ :
+ :int
+ :TRANS(MakeAllCLTSServerListeners) (char *port, int *partial, int *count_ret,
+ : XtransConnInfo **ciptrs_ret)
+ :
+ :{
+ : char buffer[256]; /* ??? What size ?? */
+ : XtransConnInfo ciptr, temp_ciptrs[NUMTRANS];
+ : int status, i, j;
+ :
+ : PRMSG (2,"MakeAllCLTSServerListeners(%s,%p)\n",
+ : port ? port : "NULL", ciptrs_ret, 0);
+ :
+ : *count_ret = 0;
+ :
+ : for (i = 0; i < NUMTRANS; i++)
+ : {
+ : Xtransport *trans = Xtransports[i].transport;
+ :
+ : if (trans->flags&TRANS_ALIAS || trans->flags&TRANS_NOLISTEN)
+ : continue;
+ :
+ : snprintf(buffer, sizeof(buffer), "%s/:%s",
+ : trans->TransName, port ? port : "");
+ :
+ : PRMSG (5,"MakeAllCLTSServerListeners: opening %s\n",
+ : buffer, 0, 0);
+ :
+ : if ((ciptr = TRANS(OpenCLTSServer (buffer))) == NULL)
+ : {
+ : PRMSG (1,
+ : "MakeAllCLTSServerListeners: failed to open listener for %s\n",
+ : trans->TransName, 0, 0);
+ : continue;
+ : }
+ :
+ : if ((status = TRANS(CreateListener (ciptr, port, 0))) < 0)
+ : {
+ : if (status == TRANS_ADDR_IN_USE)
+ : {
+ : /*
+ : * We failed to bind to the specified address because the
+ : * address is in use. It must be that a server is already
+ : * running at this address, and this function should fail.
+ : */
+ :
+ : PRMSG (1,
+ : "MakeAllCLTSServerListeners: server already running\n",
+ : 0, 0, 0);
+ :
+ : for (j = 0; j < *count_ret; j++)
+ : TRANS(Close) (temp_ciptrs[j]);
+ :
+ : *count_ret = 0;
+ : *ciptrs_ret = NULL;
+ : *partial = 0;
+ : return -1;
+ : }
+ : else
+ : {
+ : PRMSG (1,
+ : "MakeAllCLTSServerListeners: failed to create listener for %s\n",
+ : trans->TransName, 0, 0);
+ :
+ : continue;
+ : }
+ : }
+ :
+ : PRMSG (5,
+ : "MakeAllCLTSServerListeners: opened listener for %s, %d\n",
+ : trans->TransName, ciptr->fd, 0);
+ : temp_ciptrs[*count_ret] = ciptr;
+ : (*count_ret)++;
+ : }
+ :
+ : *partial = (*count_ret < complete_network_count());
+ :
+ : PRMSG (5,
+ : "MakeAllCLTSServerListeners: partial=%d, actual=%d, complete=%d \n",
+ : *partial, *count_ret, complete_network_count());
+ :
+ : if (*count_ret > 0)
+ : {
+ : if ((*ciptrs_ret = (XtransConnInfo *) xalloc (
+ : *count_ret * sizeof (XtransConnInfo))) == NULL)
+ : {
+ : return -1;
+ : }
+ :
+ : for (i = 0; i < *count_ret; i++)
+ : {
+ : (*ciptrs_ret)[i] = temp_ciptrs[i];
+ : }
+ : }
+ : else
+ : *ciptrs_ret = NULL;
+ :
+ : return 0;
+ :}
+ :
+ :#endif /* TRANS_SERVER */
+ :
+ :
+ :\f
+ :/*
+ : * These routines are not part of the X Transport Interface, but they
+ : * may be used by it.
+ : */
+ :
+ :#ifdef CRAY
+ :
+ :/*
+ : * Cray UniCOS does not have readv and writev so we emulate
+ : */
+ :
+ :static int TRANS(ReadV) (XtransConnInfo ciptr, struct iovec *iov, int iovcnt)
+ :
+ :{
+ : struct msghdr hdr;
+ :
+ : hdr.msg_iov = iov;
+ : hdr.msg_iovlen = iovcnt;
+ : hdr.msg_accrights = 0;
+ : hdr.msg_accrightslen = 0;
+ : hdr.msg_name = 0;
+ : hdr.msg_namelen = 0;
+ :
+ : return (recvmsg (ciptr->fd, &hdr, 0));
+ :}
+ :
+ :static int TRANS(WriteV) (XtransConnInfo ciptr, struct iovec *iov, int iovcnt)
+ :
+ :{
+ : struct msghdr hdr;
+ :
+ : hdr.msg_iov = iov;
+ : hdr.msg_iovlen = iovcnt;
+ : hdr.msg_accrights = 0;
+ : hdr.msg_accrightslen = 0;
+ : hdr.msg_name = 0;
+ : hdr.msg_namelen = 0;
+ :
+ : return (sendmsg (ciptr->fd, &hdr, 0));
+ :}
+ :
+ :#endif /* CRAY */
+ :
+ :#if (defined(SYSV) && defined(i386) && !defined(__SCO__) && !defined(sun)) || defined(WIN32) || defined(__sxg__) || defined(__UNIXOS2__)
+ :
+ :/*
+ : * emulate readv
+ : */
+ :
+ :static int TRANS(ReadV) (XtransConnInfo ciptr, struct iovec *iov, int iovcnt)
+ :
+ :{
+ : int i, len, total;
+ : char *base;
+ :
+ : ESET(0);
+ : for (i = 0, total = 0; i < iovcnt; i++, iov++) {
+ : len = iov->iov_len;
+ : base = iov->iov_base;
+ : while (len > 0) {
+ : register int nbytes;
+ : nbytes = TRANS(Read) (ciptr, base, len);
+ : if (nbytes < 0 && total == 0) return -1;
+ : if (nbytes <= 0) return total;
+ : ESET(0);
+ : len -= nbytes;
+ : total += nbytes;
+ : base += nbytes;
+ : }
+ : }
+ : return total;
+ :}
+ :
+ :#endif /* SYSV && i386 || WIN32 || __sxg__ */
+ :
+ :#if (defined(SYSV) && defined(i386) && !defined(__SCO__) && !defined(sun)) || defined(WIN32) || defined(__sxg__) || defined(__UNIXOS2__)
+ :
+ :/*
+ : * emulate writev
+ : */
+ :
+ :static int TRANS(WriteV) (XtransConnInfo ciptr, struct iovec *iov, int iovcnt)
+ :
+ :{
+ : int i, len, total;
+ : char *base;
+ :
+ : ESET(0);
+ : for (i = 0, total = 0; i < iovcnt; i++, iov++) {
+ : len = iov->iov_len;
+ : base = iov->iov_base;
+ : while (len > 0) {
+ : register int nbytes;
+ : nbytes = TRANS(Write) (ciptr, base, len);
+ : if (nbytes < 0 && total == 0) return -1;
+ : if (nbytes <= 0) return total;
+ : ESET(0);
+ : len -= nbytes;
+ : total += nbytes;
+ : base += nbytes;
+ : }
+ : }
+ : return total;
+ :}
+ :
+ :#endif /* SYSV && i386 || WIN32 || __sxg__ */
+ :
+ :
+ :#if (defined(_POSIX_SOURCE) && !defined(AIXV3) && !defined(__QNX__)) || defined(hpux) || defined(USG) || defined(SVR4) || defined(__SCO__)
+ :#ifndef NEED_UTSNAME
+ :#define NEED_UTSNAME
+ :#endif
+ :#include <sys/utsname.h>
+ :#endif
+ :
+ :/*
+ : * TRANS(GetHostname) - similar to gethostname but allows special processing.
+ : */
+ :
+ :int TRANS(GetHostname) (char *buf, int maxlen)
+ :
+ :{
+ : int len;
+ :
+ :#ifdef NEED_UTSNAME
+ : struct utsname name;
+ :
+ : uname (&name);
+ : len = strlen (name.nodename);
+ : if (len >= maxlen) len = maxlen - 1;
+ : strncpy (buf, name.nodename, len);
+ : buf[len] = '\0';
+ :#else
+ : buf[0] = '\0';
+ : (void) gethostname (buf, maxlen);
+ : buf [maxlen - 1] = '\0';
+ : len = strlen(buf);
+ :#endif /* NEED_UTSNAME */
+ : return len;
+ :}