summaryrefslogtreecommitdiff
path: root/xserver/mi
diff options
context:
space:
mode:
authorMatthieu Herrb <matthieu@cvs.openbsd.org>2006-11-26 18:19:47 +0000
committerMatthieu Herrb <matthieu@cvs.openbsd.org>2006-11-26 18:19:47 +0000
commit04f51aaa1f5b0cac419d2891812446c790b9c581 (patch)
tree7d104a653aff8d7488bc039ba435118115c18807 /xserver/mi
parent4a168ba45f33263ee86fc398ff32f108cffb1330 (diff)
Importing xserver from X.Org 7.2RC2
Diffstat (limited to 'xserver/mi')
-rw-r--r--xserver/mi/Makefile.am75
-rw-r--r--xserver/mi/Makefile.in943
-rw-r--r--xserver/mi/cbrt.c46
-rw-r--r--xserver/mi/mi.h625
-rw-r--r--xserver/mi/miarc.c3720
-rw-r--r--xserver/mi/mibank.c2573
-rw-r--r--xserver/mi/mibank.h118
-rw-r--r--xserver/mi/mibitblt.c843
-rw-r--r--xserver/mi/mibstore.c3879
-rw-r--r--xserver/mi/mibstore.h28
-rw-r--r--xserver/mi/mibstorest.h91
-rw-r--r--xserver/mi/micmap.c697
-rw-r--r--xserver/mi/micmap.h64
-rw-r--r--xserver/mi/micoord.h70
-rw-r--r--xserver/mi/micursor.c75
-rw-r--r--xserver/mi/midash.c313
-rw-r--r--xserver/mi/midispcur.c816
-rw-r--r--xserver/mi/mieq.c194
-rw-r--r--xserver/mi/miexpose.c902
-rw-r--r--xserver/mi/mifillarc.c815
-rw-r--r--xserver/mi/mifillarc.h214
-rw-r--r--xserver/mi/mifillrct.c142
-rw-r--r--xserver/mi/mifpoly.h109
-rw-r--r--xserver/mi/mifpolycon.c282
-rw-r--r--xserver/mi/migc.c299
-rw-r--r--xserver/mi/migc.h72
-rw-r--r--xserver/mi/miglblt.c253
-rw-r--r--xserver/mi/miinitext.c798
-rw-r--r--xserver/mi/miline.h172
-rw-r--r--xserver/mi/mioverlay.c2077
-rw-r--r--xserver/mi/mioverlay.h32
-rw-r--r--xserver/mi/mipointer.c529
-rw-r--r--xserver/mi/mipointer.h151
-rw-r--r--xserver/mi/mipointrst.h62
-rw-r--r--xserver/mi/mipoly.c128
-rw-r--r--xserver/mi/mipoly.h215
-rw-r--r--xserver/mi/mipolycon.c246
-rw-r--r--xserver/mi/mipolygen.c230
-rw-r--r--xserver/mi/mipolypnt.c123
-rw-r--r--xserver/mi/mipolyrect.c191
-rw-r--r--xserver/mi/mipolyseg.c83
-rw-r--r--xserver/mi/mipolytext.c200
-rw-r--r--xserver/mi/mipolyutil.c399
-rw-r--r--xserver/mi/mipushpxl.c259
-rw-r--r--xserver/mi/miregion.c2561
-rw-r--r--xserver/mi/miscanfill.h147
-rw-r--r--xserver/mi/miscrinit.c344
-rw-r--r--xserver/mi/mispans.c561
-rw-r--r--xserver/mi/mispans.h115
-rw-r--r--xserver/mi/misprite.c829
-rw-r--r--xserver/mi/misprite.h94
-rw-r--r--xserver/mi/mispritest.h132
-rw-r--r--xserver/mi/mistruct.h64
-rw-r--r--xserver/mi/mivalidate.h54
-rw-r--r--xserver/mi/mivaltree.c823
-rw-r--r--xserver/mi/miwideline.c2231
-rw-r--r--xserver/mi/miwideline.h222
-rw-r--r--xserver/mi/miwindow.c1182
-rw-r--r--xserver/mi/mizerarc.c853
-rw-r--r--xserver/mi/mizerarc.h132
-rw-r--r--xserver/mi/mizerclip.c635
-rw-r--r--xserver/mi/mizerline.c378
62 files changed, 35510 insertions, 0 deletions
diff --git a/xserver/mi/Makefile.am b/xserver/mi/Makefile.am
new file mode 100644
index 000000000..42f75ae73
--- /dev/null
+++ b/xserver/mi/Makefile.am
@@ -0,0 +1,75 @@
+noinst_LTLIBRARIES = libminimi.la libmi.la
+
+if XORG
+sdk_HEADERS = mibank.h micmap.h miline.h mipointer.h mi.h mibstore.h \
+ migc.h mipointrst.h mizerarc.h micoord.h mifillarc.h \
+ mispans.h miwideline.h mistruct.h mifpoly.h
+endif
+
+AM_CFLAGS = $(DIX_CFLAGS)
+
+# libminimi is for dmx - it has different defines for miinitext.c
+libminimi_la_SOURCES = \
+ cbrt.c \
+ mi.h \
+ miarc.c \
+ mibank.c \
+ mibank.h \
+ mibitblt.c \
+ mibstore.c \
+ mibstore.h \
+ mibstorest.h \
+ micmap.c \
+ micmap.h \
+ micoord.h \
+ micursor.c \
+ midash.c \
+ midispcur.c \
+ mieq.c \
+ miexpose.c \
+ mifillarc.c \
+ mifillarc.h \
+ mifillrct.c \
+ mifpolycon.c \
+ mifpoly.h \
+ migc.c \
+ migc.h \
+ miglblt.c \
+ miline.h \
+ mioverlay.c \
+ mioverlay.h \
+ mipointer.c \
+ mipointer.h \
+ mipointrst.h \
+ mipoly.c \
+ mipoly.h \
+ mipolycon.c \
+ mipolygen.c \
+ mipolypnt.c \
+ mipolyrect.c \
+ mipolyseg.c \
+ mipolytext.c \
+ mipolyutil.c \
+ mipushpxl.c \
+ miregion.c \
+ miscanfill.h \
+ miscrinit.c \
+ mispans.c \
+ mispans.h \
+ misprite.c \
+ misprite.h \
+ mispritest.h \
+ mistruct.h \
+ mivaltree.c \
+ mivalidate.h \
+ miwideline.c \
+ miwideline.h \
+ miwindow.c \
+ mizerarc.c \
+ mizerarc.h \
+ mizerclip.c \
+ mizerline.c
+
+libmi_la_SOURCES = $(libminimi_la_SOURCES)
+
+INCLUDES = -I$(top_srcdir)/mfb
diff --git a/xserver/mi/Makefile.in b/xserver/mi/Makefile.in
new file mode 100644
index 000000000..1779a625e
--- /dev/null
+++ b/xserver/mi/Makefile.in
@@ -0,0 +1,943 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = mi
+DIST_COMMON = $(am__sdk_HEADERS_DIST) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/include/do-not-use-config.h \
+ $(top_builddir)/include/xorg-server.h \
+ $(top_builddir)/include/dix-config.h \
+ $(top_builddir)/include/xgl-config.h \
+ $(top_builddir)/include/xorg-config.h \
+ $(top_builddir)/include/xkb-config.h \
+ $(top_builddir)/include/xwin-config.h \
+ $(top_builddir)/include/kdrive-config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libmi_la_LIBADD =
+am__objects_1 = cbrt.lo miarc.lo mibank.lo mibitblt.lo mibstore.lo \
+ micmap.lo micursor.lo midash.lo midispcur.lo mieq.lo \
+ miexpose.lo mifillarc.lo mifillrct.lo mifpolycon.lo migc.lo \
+ miglblt.lo mioverlay.lo mipointer.lo mipoly.lo mipolycon.lo \
+ mipolygen.lo mipolypnt.lo mipolyrect.lo mipolyseg.lo \
+ mipolytext.lo mipolyutil.lo mipushpxl.lo miregion.lo \
+ miscrinit.lo mispans.lo misprite.lo mivaltree.lo miwideline.lo \
+ miwindow.lo mizerarc.lo mizerclip.lo mizerline.lo
+am_libmi_la_OBJECTS = $(am__objects_1)
+libmi_la_OBJECTS = $(am_libmi_la_OBJECTS)
+libminimi_la_LIBADD =
+am_libminimi_la_OBJECTS = cbrt.lo miarc.lo mibank.lo mibitblt.lo \
+ mibstore.lo micmap.lo micursor.lo midash.lo midispcur.lo \
+ mieq.lo miexpose.lo mifillarc.lo mifillrct.lo mifpolycon.lo \
+ migc.lo miglblt.lo mioverlay.lo mipointer.lo mipoly.lo \
+ mipolycon.lo mipolygen.lo mipolypnt.lo mipolyrect.lo \
+ mipolyseg.lo mipolytext.lo mipolyutil.lo mipushpxl.lo \
+ miregion.lo miscrinit.lo mispans.lo misprite.lo mivaltree.lo \
+ miwideline.lo miwindow.lo mizerarc.lo mizerclip.lo \
+ mizerline.lo
+libminimi_la_OBJECTS = $(am_libminimi_la_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libmi_la_SOURCES) $(libminimi_la_SOURCES)
+DIST_SOURCES = $(libmi_la_SOURCES) $(libminimi_la_SOURCES)
+am__sdk_HEADERS_DIST = mibank.h micmap.h miline.h mipointer.h mi.h \
+ mibstore.h migc.h mipointrst.h mizerarc.h micoord.h \
+ mifillarc.h mispans.h miwideline.h mistruct.h mifpoly.h
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(sdkdir)"
+sdkHEADERS_INSTALL = $(INSTALL_HEADER)
+HEADERS = $(sdk_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ADMIN_MAN_DIR = @ADMIN_MAN_DIR@
+ADMIN_MAN_SUFFIX = @ADMIN_MAN_SUFFIX@
+AFB_FALSE = @AFB_FALSE@
+AFB_TRUE = @AFB_TRUE@
+AGP_FALSE = @AGP_FALSE@
+AGP_TRUE = @AGP_TRUE@
+AIGLX_FALSE = @AIGLX_FALSE@
+AIGLX_TRUE = @AIGLX_TRUE@
+ALLOCA = @ALLOCA@
+ALPHA_VIDEO_FALSE = @ALPHA_VIDEO_FALSE@
+ALPHA_VIDEO_TRUE = @ALPHA_VIDEO_TRUE@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+APPDEFAULTDIR = @APPDEFAULTDIR@
+APPGROUP_FALSE = @APPGROUP_FALSE@
+APPGROUP_TRUE = @APPGROUP_TRUE@
+APP_MAN_DIR = @APP_MAN_DIR@
+APP_MAN_SUFFIX = @APP_MAN_SUFFIX@
+AR = @AR@
+ARM_VIDEO_FALSE = @ARM_VIDEO_FALSE@
+ARM_VIDEO_TRUE = @ARM_VIDEO_TRUE@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BASE_FONT_PATH = @BASE_FONT_PATH@
+BSD_KBD_MODE_FALSE = @BSD_KBD_MODE_FALSE@
+BSD_KBD_MODE_TRUE = @BSD_KBD_MODE_TRUE@
+BUILDDOCS_FALSE = @BUILDDOCS_FALSE@
+BUILDDOCS_TRUE = @BUILDDOCS_TRUE@
+BUILD_DATE = @BUILD_DATE@
+BUILD_KBD_MODE_FALSE = @BUILD_KBD_MODE_FALSE@
+BUILD_KBD_MODE_TRUE = @BUILD_KBD_MODE_TRUE@
+BUILD_LINUXDOC_FALSE = @BUILD_LINUXDOC_FALSE@
+BUILD_LINUXDOC_TRUE = @BUILD_LINUXDOC_TRUE@
+BUILD_PDFDOC_FALSE = @BUILD_PDFDOC_FALSE@
+BUILD_PDFDOC_TRUE = @BUILD_PDFDOC_TRUE@
+BUILD_XORGCFG_FALSE = @BUILD_XORGCFG_FALSE@
+BUILD_XORGCFG_TRUE = @BUILD_XORGCFG_TRUE@
+CC = @CC@
+CCAS = @CCAS@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFB_FALSE = @CFB_FALSE@
+CFB_TRUE = @CFB_TRUE@
+CFLAGS = @CFLAGS@
+COMPILEDDEFAULTFONTPATH = @COMPILEDDEFAULTFONTPATH@
+COMPOSITE_FALSE = @COMPOSITE_FALSE@
+COMPOSITE_TRUE = @COMPOSITE_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CUP_FALSE = @CUP_FALSE@
+CUP_TRUE = @CUP_TRUE@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBE_FALSE = @DBE_FALSE@
+DBE_TRUE = @DBE_TRUE@
+DEBUG_FALSE = @DEBUG_FALSE@
+DEBUG_TRUE = @DEBUG_TRUE@
+DEFAULT_LOGPREFIX = @DEFAULT_LOGPREFIX@
+DEFAULT_MODULE_PATH = @DEFAULT_MODULE_PATH@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DGA_FALSE = @DGA_FALSE@
+DGA_TRUE = @DGA_TRUE@
+DIX_CFLAGS = @DIX_CFLAGS@
+DLLTOOL = @DLLTOOL@
+DMXEXAMPLES_DEP_CFLAGS = @DMXEXAMPLES_DEP_CFLAGS@
+DMXEXAMPLES_DEP_LIBS = @DMXEXAMPLES_DEP_LIBS@
+DMXMODULES_CFLAGS = @DMXMODULES_CFLAGS@
+DMXMODULES_LIBS = @DMXMODULES_LIBS@
+DMXXIEXAMPLES_DEP_CFLAGS = @DMXXIEXAMPLES_DEP_CFLAGS@
+DMXXIEXAMPLES_DEP_LIBS = @DMXXIEXAMPLES_DEP_LIBS@
+DMXXMUEXAMPLES_DEP_CFLAGS = @DMXXMUEXAMPLES_DEP_CFLAGS@
+DMXXMUEXAMPLES_DEP_LIBS = @DMXXMUEXAMPLES_DEP_LIBS@
+DMX_BUILD_LNX_FALSE = @DMX_BUILD_LNX_FALSE@
+DMX_BUILD_LNX_TRUE = @DMX_BUILD_LNX_TRUE@
+DMX_BUILD_USB_FALSE = @DMX_BUILD_USB_FALSE@
+DMX_BUILD_USB_TRUE = @DMX_BUILD_USB_TRUE@
+DMX_FALSE = @DMX_FALSE@
+DMX_TRUE = @DMX_TRUE@
+DPMSExtension_FALSE = @DPMSExtension_FALSE@
+DPMSExtension_TRUE = @DPMSExtension_TRUE@
+DRIPROTO_CFLAGS = @DRIPROTO_CFLAGS@
+DRIPROTO_LIBS = @DRIPROTO_LIBS@
+DRIVER_MAN_DIR = @DRIVER_MAN_DIR@
+DRIVER_MAN_SUFFIX = @DRIVER_MAN_SUFFIX@
+DRI_DRIVER_PATH = @DRI_DRIVER_PATH@
+DRI_FALSE = @DRI_FALSE@
+DRI_TRUE = @DRI_TRUE@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EVI_FALSE = @EVI_FALSE@
+EVI_TRUE = @EVI_TRUE@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FBDEVHW_FALSE = @FBDEVHW_FALSE@
+FBDEVHW_TRUE = @FBDEVHW_TRUE@
+FFLAGS = @FFLAGS@
+FILE_MAN_DIR = @FILE_MAN_DIR@
+FILE_MAN_SUFFIX = @FILE_MAN_SUFFIX@
+FONTCACHE_FALSE = @FONTCACHE_FALSE@
+FONTCACHE_TRUE = @FONTCACHE_TRUE@
+FREEBSD_KLDLOAD_FALSE = @FREEBSD_KLDLOAD_FALSE@
+FREEBSD_KLDLOAD_TRUE = @FREEBSD_KLDLOAD_TRUE@
+FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
+FREETYPE_LIBS = @FREETYPE_LIBS@
+FREETYPE_REQUIRES = @FREETYPE_REQUIRES@
+GLX_DEFINES = @GLX_DEFINES@
+GLX_FALSE = @GLX_FALSE@
+GLX_TRUE = @GLX_TRUE@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+H3600_TS_FALSE = @H3600_TS_FALSE@
+H3600_TS_TRUE = @H3600_TS_TRUE@
+I386_VIDEO_FALSE = @I386_VIDEO_FALSE@
+I386_VIDEO_TRUE = @I386_VIDEO_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_LIBXF86CONFIG_FALSE = @INSTALL_LIBXF86CONFIG_FALSE@
+INSTALL_LIBXF86CONFIG_TRUE = @INSTALL_LIBXF86CONFIG_TRUE@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_SETUID_FALSE = @INSTALL_SETUID_FALSE@
+INSTALL_SETUID_TRUE = @INSTALL_SETUID_TRUE@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INT10_STUB_FALSE = @INT10_STUB_FALSE@
+INT10_STUB_TRUE = @INT10_STUB_TRUE@
+INT10_VM86_FALSE = @INT10_VM86_FALSE@
+INT10_VM86_TRUE = @INT10_VM86_TRUE@
+INT10_X86EMU_FALSE = @INT10_X86EMU_FALSE@
+INT10_X86EMU_TRUE = @INT10_X86EMU_TRUE@
+KDRIVEFBDEV_FALSE = @KDRIVEFBDEV_FALSE@
+KDRIVEFBDEV_TRUE = @KDRIVEFBDEV_TRUE@
+KDRIVEVESA_FALSE = @KDRIVEVESA_FALSE@
+KDRIVEVESA_TRUE = @KDRIVEVESA_TRUE@
+KDRIVE_CFLAGS = @KDRIVE_CFLAGS@
+KDRIVE_FALSE = @KDRIVE_FALSE@
+KDRIVE_HW_FALSE = @KDRIVE_HW_FALSE@
+KDRIVE_HW_TRUE = @KDRIVE_HW_TRUE@
+KDRIVE_INCS = @KDRIVE_INCS@
+KDRIVE_LIBS = @KDRIVE_LIBS@
+KDRIVE_PURE_INCS = @KDRIVE_PURE_INCS@
+KDRIVE_PURE_LIBS = @KDRIVE_PURE_LIBS@
+KDRIVE_TRUE = @KDRIVE_TRUE@
+LDFLAGS = @LDFLAGS@
+LD_EXPORT_SYMBOLS_FLAG = @LD_EXPORT_SYMBOLS_FLAG@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBDRM_CFLAGS = @LIBDRM_CFLAGS@
+LIBDRM_LIBS = @LIBDRM_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_MAN_DIR = @LIB_MAN_DIR@
+LIB_MAN_SUFFIX = @LIB_MAN_SUFFIX@
+LINUXDOC = @LINUXDOC@
+LINUX_ALPHA_FALSE = @LINUX_ALPHA_FALSE@
+LINUX_ALPHA_TRUE = @LINUX_ALPHA_TRUE@
+LINUX_IA64_FALSE = @LINUX_IA64_FALSE@
+LINUX_IA64_TRUE = @LINUX_IA64_TRUE@
+LNXACPI_FALSE = @LNXACPI_FALSE@
+LNXACPI_TRUE = @LNXACPI_TRUE@
+LNXAPM_FALSE = @LNXAPM_FALSE@
+LNXAPM_TRUE = @LNXAPM_TRUE@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MAKE_HTML = @MAKE_HTML@
+MAKE_PDF = @MAKE_PDF@
+MAKE_PS = @MAKE_PS@
+MAKE_TEXT = @MAKE_TEXT@
+MESA_SOURCE = @MESA_SOURCE@
+MFB_FALSE = @MFB_FALSE@
+MFB_TRUE = @MFB_TRUE@
+MISC_MAN_DIR = @MISC_MAN_DIR@
+MISC_MAN_SUFFIX = @MISC_MAN_SUFFIX@
+MITSHM_FALSE = @MITSHM_FALSE@
+MITSHM_TRUE = @MITSHM_TRUE@
+MKFONTDIR = @MKFONTDIR@
+MKFONTSCALE = @MKFONTSCALE@
+MMX_CAPABLE_FALSE = @MMX_CAPABLE_FALSE@
+MMX_CAPABLE_TRUE = @MMX_CAPABLE_TRUE@
+MULTIBUFFER_FALSE = @MULTIBUFFER_FALSE@
+MULTIBUFFER_TRUE = @MULTIBUFFER_TRUE@
+NEED_STRLCAT_FALSE = @NEED_STRLCAT_FALSE@
+NEED_STRLCAT_TRUE = @NEED_STRLCAT_TRUE@
+NEED_VSNPRINTF_FALSE = @NEED_VSNPRINTF_FALSE@
+NEED_VSNPRINTF_TRUE = @NEED_VSNPRINTF_TRUE@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PPC_VIDEO_FALSE = @PPC_VIDEO_FALSE@
+PPC_VIDEO_TRUE = @PPC_VIDEO_TRUE@
+PROJECTROOT = @PROJECTROOT@
+PS2PDF = @PS2PDF@
+RANLIB = @RANLIB@
+RAWCPP = @RAWCPP@
+RAWCPPFLAGS = @RAWCPPFLAGS@
+RECORD_FALSE = @RECORD_FALSE@
+RECORD_TRUE = @RECORD_TRUE@
+RES_FALSE = @RES_FALSE@
+RES_TRUE = @RES_TRUE@
+RGB_DB = @RGB_DB@
+SCREENSAVER_FALSE = @SCREENSAVER_FALSE@
+SCREENSAVER_TRUE = @SCREENSAVER_TRUE@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOLARIS_ASM_CFLAGS = @SOLARIS_ASM_CFLAGS@
+SOLARIS_ASM_INLINE_FALSE = @SOLARIS_ASM_INLINE_FALSE@
+SOLARIS_ASM_INLINE_TRUE = @SOLARIS_ASM_INLINE_TRUE@
+SOLARIS_INOUT_ARCH = @SOLARIS_INOUT_ARCH@
+SOLARIS_USL_CONSOLE_FALSE = @SOLARIS_USL_CONSOLE_FALSE@
+SOLARIS_USL_CONSOLE_TRUE = @SOLARIS_USL_CONSOLE_TRUE@
+SPARC64_VIDEO_FALSE = @SPARC64_VIDEO_FALSE@
+SPARC64_VIDEO_TRUE = @SPARC64_VIDEO_TRUE@
+STRIP = @STRIP@
+SUN_KBD_MODE_FALSE = @SUN_KBD_MODE_FALSE@
+SUN_KBD_MODE_TRUE = @SUN_KBD_MODE_TRUE@
+SYS_LIBS = @SYS_LIBS@
+TSLIB_CFLAGS = @TSLIB_CFLAGS@
+TSLIB_FALSE = @TSLIB_FALSE@
+TSLIB_LIBS = @TSLIB_LIBS@
+TSLIB_TRUE = @TSLIB_TRUE@
+USE_CURSES_FALSE = @USE_CURSES_FALSE@
+USE_CURSES_TRUE = @USE_CURSES_TRUE@
+USE_RGB_BUILTIN_FALSE = @USE_RGB_BUILTIN_FALSE@
+USE_RGB_BUILTIN_TRUE = @USE_RGB_BUILTIN_TRUE@
+VENDOR_MAN_VERSION = @VENDOR_MAN_VERSION@
+VENDOR_RELEASE = @VENDOR_RELEASE@
+VENDOR_STRING = @VENDOR_STRING@
+VENDOR_STRING_SHORT = @VENDOR_STRING_SHORT@
+VERSION = @VERSION@
+X11EXAMPLES_DEP_CFLAGS = @X11EXAMPLES_DEP_CFLAGS@
+X11EXAMPLES_DEP_LIBS = @X11EXAMPLES_DEP_LIBS@
+XACE_FALSE = @XACE_FALSE@
+XACE_TRUE = @XACE_TRUE@
+XCALIBRATE_FALSE = @XCALIBRATE_FALSE@
+XCALIBRATE_TRUE = @XCALIBRATE_TRUE@
+XCSECURITY_FALSE = @XCSECURITY_FALSE@
+XCSECURITY_TRUE = @XCSECURITY_TRUE@
+XDMAUTH_FALSE = @XDMAUTH_FALSE@
+XDMAUTH_TRUE = @XDMAUTH_TRUE@
+XDMCP_CFLAGS = @XDMCP_CFLAGS@
+XDMCP_FALSE = @XDMCP_FALSE@
+XDMCP_LIBS = @XDMCP_LIBS@
+XDMCP_TRUE = @XDMCP_TRUE@
+XDMXCONFIG_DEP_CFLAGS = @XDMXCONFIG_DEP_CFLAGS@
+XDMXCONFIG_DEP_LIBS = @XDMXCONFIG_DEP_LIBS@
+XDMX_LIBS = @XDMX_LIBS@
+XEGLMODULES_CFLAGS = @XEGLMODULES_CFLAGS@
+XEGLMODULES_LIBS = @XEGLMODULES_LIBS@
+XEGL_FALSE = @XEGL_FALSE@
+XEGL_LIBS = @XEGL_LIBS@
+XEGL_TRUE = @XEGL_TRUE@
+XEPHYR_CFLAGS = @XEPHYR_CFLAGS@
+XEPHYR_FALSE = @XEPHYR_FALSE@
+XEPHYR_INCS = @XEPHYR_INCS@
+XEPHYR_LIBS = @XEPHYR_LIBS@
+XEPHYR_TRUE = @XEPHYR_TRUE@
+XEVIE_FALSE = @XEVIE_FALSE@
+XEVIE_TRUE = @XEVIE_TRUE@
+XF86BIGFONT_FALSE = @XF86BIGFONT_FALSE@
+XF86BIGFONT_TRUE = @XF86BIGFONT_TRUE@
+XF86CONFIGFILE = @XF86CONFIGFILE@
+XF86UTILS_FALSE = @XF86UTILS_FALSE@
+XF86UTILS_TRUE = @XF86UTILS_TRUE@
+XGLMODULES_CFLAGS = @XGLMODULES_CFLAGS@
+XGLMODULES_LIBS = @XGLMODULES_LIBS@
+XGLXMODULES_CFLAGS = @XGLXMODULES_CFLAGS@
+XGLXMODULES_LIBS = @XGLXMODULES_LIBS@
+XGLX_FALSE = @XGLX_FALSE@
+XGLX_LIBS = @XGLX_LIBS@
+XGLX_TRUE = @XGLX_TRUE@
+XGL_FALSE = @XGL_FALSE@
+XGL_LIBS = @XGL_LIBS@
+XGL_MODULE_PATH = @XGL_MODULE_PATH@
+XGL_TRUE = @XGL_TRUE@
+XINERAMA_FALSE = @XINERAMA_FALSE@
+XINERAMA_TRUE = @XINERAMA_TRUE@
+XINPUT_FALSE = @XINPUT_FALSE@
+XINPUT_TRUE = @XINPUT_TRUE@
+XKB_BASE_DIRECTORY = @XKB_BASE_DIRECTORY@
+XKB_BIN_DIRECTORY = @XKB_BIN_DIRECTORY@
+XKB_COMPILED_DIR = @XKB_COMPILED_DIR@
+XKM_OUTPUT_DIR = @XKM_OUTPUT_DIR@
+XLIB_CFLAGS = @XLIB_CFLAGS@
+XLIB_LIBS = @XLIB_LIBS@
+XNESTMODULES_CFLAGS = @XNESTMODULES_CFLAGS@
+XNESTMODULES_LIBS = @XNESTMODULES_LIBS@
+XNEST_FALSE = @XNEST_FALSE@
+XNEST_LIBS = @XNEST_LIBS@
+XNEST_TRUE = @XNEST_TRUE@
+XORGCFG_DEP_CFLAGS = @XORGCFG_DEP_CFLAGS@
+XORGCFG_DEP_LIBS = @XORGCFG_DEP_LIBS@
+XORGCONFIG_DEP_CFLAGS = @XORGCONFIG_DEP_CFLAGS@
+XORGCONFIG_DEP_LIBS = @XORGCONFIG_DEP_LIBS@
+XORG_BUS_FREEBSDPCI_FALSE = @XORG_BUS_FREEBSDPCI_FALSE@
+XORG_BUS_FREEBSDPCI_TRUE = @XORG_BUS_FREEBSDPCI_TRUE@
+XORG_BUS_IX86PCI_FALSE = @XORG_BUS_IX86PCI_FALSE@
+XORG_BUS_IX86PCI_TRUE = @XORG_BUS_IX86PCI_TRUE@
+XORG_BUS_LINUXPCI_FALSE = @XORG_BUS_LINUXPCI_FALSE@
+XORG_BUS_LINUXPCI_TRUE = @XORG_BUS_LINUXPCI_TRUE@
+XORG_BUS_NETBSDPCI_FALSE = @XORG_BUS_NETBSDPCI_FALSE@
+XORG_BUS_NETBSDPCI_TRUE = @XORG_BUS_NETBSDPCI_TRUE@
+XORG_BUS_PPCPCI_FALSE = @XORG_BUS_PPCPCI_FALSE@
+XORG_BUS_PPCPCI_TRUE = @XORG_BUS_PPCPCI_TRUE@
+XORG_BUS_SPARCPCI_FALSE = @XORG_BUS_SPARCPCI_FALSE@
+XORG_BUS_SPARCPCI_TRUE = @XORG_BUS_SPARCPCI_TRUE@
+XORG_BUS_SPARC_FALSE = @XORG_BUS_SPARC_FALSE@
+XORG_BUS_SPARC_TRUE = @XORG_BUS_SPARC_TRUE@
+XORG_CFLAGS = @XORG_CFLAGS@
+XORG_CORE_LIBS = @XORG_CORE_LIBS@
+XORG_FALSE = @XORG_FALSE@
+XORG_INCS = @XORG_INCS@
+XORG_LIBS = @XORG_LIBS@
+XORG_LOADER_SPARC_FALSE = @XORG_LOADER_SPARC_FALSE@
+XORG_LOADER_SPARC_TRUE = @XORG_LOADER_SPARC_TRUE@
+XORG_OS = @XORG_OS@
+XORG_OS_KBD = @XORG_OS_KBD@
+XORG_OS_SUBDIR = @XORG_OS_SUBDIR@
+XORG_TRUE = @XORG_TRUE@
+XPRINTPROTO_CFLAGS = @XPRINTPROTO_CFLAGS@
+XPRINTPROTO_LIBS = @XPRINTPROTO_LIBS@
+XPRINT_CFLAGS = @XPRINT_CFLAGS@
+XPRINT_FALSE = @XPRINT_FALSE@
+XPRINT_LIBS = @XPRINT_LIBS@
+XPRINT_TRUE = @XPRINT_TRUE@
+XP_USE_FREETYPE_FALSE = @XP_USE_FREETYPE_FALSE@
+XP_USE_FREETYPE_TRUE = @XP_USE_FREETYPE_TRUE@
+XRESEXAMPLES_DEP_CFLAGS = @XRESEXAMPLES_DEP_CFLAGS@
+XRESEXAMPLES_DEP_LIBS = @XRESEXAMPLES_DEP_LIBS@
+XSDLSERVER_FALSE = @XSDLSERVER_FALSE@
+XSDLSERVER_TRUE = @XSDLSERVER_TRUE@
+XSDL_INCS = @XSDL_INCS@
+XSDL_LIBS = @XSDL_LIBS@
+XSERVERCFLAGS_CFLAGS = @XSERVERCFLAGS_CFLAGS@
+XSERVERCFLAGS_LIBS = @XSERVERCFLAGS_LIBS@
+XSERVERLIBS_CFLAGS = @XSERVERLIBS_CFLAGS@
+XSERVERLIBS_LIBS = @XSERVERLIBS_LIBS@
+XSERVER_LIBS = @XSERVER_LIBS@
+XTRAP_FALSE = @XTRAP_FALSE@
+XTRAP_TRUE = @XTRAP_TRUE@
+XTSTEXAMPLES_DEP_CFLAGS = @XTSTEXAMPLES_DEP_CFLAGS@
+XTSTEXAMPLES_DEP_LIBS = @XTSTEXAMPLES_DEP_LIBS@
+XVFB_FALSE = @XVFB_FALSE@
+XVFB_LIBS = @XVFB_LIBS@
+XVFB_TRUE = @XVFB_TRUE@
+XVMC_FALSE = @XVMC_FALSE@
+XVMC_TRUE = @XVMC_TRUE@
+XV_FALSE = @XV_FALSE@
+XV_TRUE = @XV_TRUE@
+XWINMODULES_CFLAGS = @XWINMODULES_CFLAGS@
+XWINMODULES_LIBS = @XWINMODULES_LIBS@
+XWIN_CLIPBOARD_FALSE = @XWIN_CLIPBOARD_FALSE@
+XWIN_CLIPBOARD_TRUE = @XWIN_CLIPBOARD_TRUE@
+XWIN_FALSE = @XWIN_FALSE@
+XWIN_GLX_WINDOWS_FALSE = @XWIN_GLX_WINDOWS_FALSE@
+XWIN_GLX_WINDOWS_TRUE = @XWIN_GLX_WINDOWS_TRUE@
+XWIN_LIBS = @XWIN_LIBS@
+XWIN_MULTIWINDOWEXTWM_FALSE = @XWIN_MULTIWINDOWEXTWM_FALSE@
+XWIN_MULTIWINDOWEXTWM_TRUE = @XWIN_MULTIWINDOWEXTWM_TRUE@
+XWIN_MULTIWINDOW_FALSE = @XWIN_MULTIWINDOW_FALSE@
+XWIN_MULTIWINDOW_TRUE = @XWIN_MULTIWINDOW_TRUE@
+XWIN_NATIVEGDI_FALSE = @XWIN_NATIVEGDI_FALSE@
+XWIN_NATIVEGDI_TRUE = @XWIN_NATIVEGDI_TRUE@
+XWIN_PRIMARYFB_FALSE = @XWIN_PRIMARYFB_FALSE@
+XWIN_PRIMARYFB_TRUE = @XWIN_PRIMARYFB_TRUE@
+XWIN_RANDR_FALSE = @XWIN_RANDR_FALSE@
+XWIN_RANDR_TRUE = @XWIN_RANDR_TRUE@
+XWIN_SERVER_NAME = @XWIN_SERVER_NAME@
+XWIN_SYSTEM_LIBS = @XWIN_SYSTEM_LIBS@
+XWIN_TRUE = @XWIN_TRUE@
+XWIN_XV_FALSE = @XWIN_XV_FALSE@
+XWIN_XV_TRUE = @XWIN_XV_TRUE@
+YACC = @YACC@
+__XCONFIGFILE__ = @__XCONFIGFILE__@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_AS = @ac_ct_AS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DLLTOOL = @ac_ct_DLLTOOL@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_OBJDUMP = @ac_ct_OBJDUMP@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+ac_pt_PKG_CONFIG = @ac_pt_PKG_CONFIG@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+driverdir = @driverdir@
+exec_prefix = @exec_prefix@
+extdir = @extdir@
+ft_config = @ft_config@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sdkdir = @sdkdir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+xglmoduledir = @xglmoduledir@
+xpconfigdir = @xpconfigdir@
+noinst_LTLIBRARIES = libminimi.la libmi.la
+@XORG_TRUE@sdk_HEADERS = mibank.h micmap.h miline.h mipointer.h mi.h mibstore.h \
+@XORG_TRUE@ migc.h mipointrst.h mizerarc.h micoord.h mifillarc.h \
+@XORG_TRUE@ mispans.h miwideline.h mistruct.h mifpoly.h
+
+AM_CFLAGS = $(DIX_CFLAGS)
+
+# libminimi is for dmx - it has different defines for miinitext.c
+libminimi_la_SOURCES = \
+ cbrt.c \
+ mi.h \
+ miarc.c \
+ mibank.c \
+ mibank.h \
+ mibitblt.c \
+ mibstore.c \
+ mibstore.h \
+ mibstorest.h \
+ micmap.c \
+ micmap.h \
+ micoord.h \
+ micursor.c \
+ midash.c \
+ midispcur.c \
+ mieq.c \
+ miexpose.c \
+ mifillarc.c \
+ mifillarc.h \
+ mifillrct.c \
+ mifpolycon.c \
+ mifpoly.h \
+ migc.c \
+ migc.h \
+ miglblt.c \
+ miline.h \
+ mioverlay.c \
+ mioverlay.h \
+ mipointer.c \
+ mipointer.h \
+ mipointrst.h \
+ mipoly.c \
+ mipoly.h \
+ mipolycon.c \
+ mipolygen.c \
+ mipolypnt.c \
+ mipolyrect.c \
+ mipolyseg.c \
+ mipolytext.c \
+ mipolyutil.c \
+ mipushpxl.c \
+ miregion.c \
+ miscanfill.h \
+ miscrinit.c \
+ mispans.c \
+ mispans.h \
+ misprite.c \
+ misprite.h \
+ mispritest.h \
+ mistruct.h \
+ mivaltree.c \
+ mivalidate.h \
+ miwideline.c \
+ miwideline.h \
+ miwindow.c \
+ mizerarc.c \
+ mizerarc.h \
+ mizerclip.c \
+ mizerline.c
+
+libmi_la_SOURCES = $(libminimi_la_SOURCES)
+INCLUDES = -I$(top_srcdir)/mfb
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign mi/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign mi/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libmi.la: $(libmi_la_OBJECTS) $(libmi_la_DEPENDENCIES)
+ $(LINK) $(libmi_la_LDFLAGS) $(libmi_la_OBJECTS) $(libmi_la_LIBADD) $(LIBS)
+libminimi.la: $(libminimi_la_OBJECTS) $(libminimi_la_DEPENDENCIES)
+ $(LINK) $(libminimi_la_LDFLAGS) $(libminimi_la_OBJECTS) $(libminimi_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cbrt.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/miarc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mibank.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mibitblt.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mibstore.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/micmap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/micursor.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/midash.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/midispcur.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mieq.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/miexpose.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mifillarc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mifillrct.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mifpolycon.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/migc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/miglblt.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mioverlay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mipointer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mipoly.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mipolycon.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mipolygen.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mipolypnt.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mipolyrect.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mipolyseg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mipolytext.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mipolyutil.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mipushpxl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/miregion.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/miscrinit.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mispans.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misprite.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mivaltree.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/miwideline.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/miwindow.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mizerarc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mizerclip.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mizerline.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+install-sdkHEADERS: $(sdk_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(sdkdir)" || $(mkdir_p) "$(DESTDIR)$(sdkdir)"
+ @list='$(sdk_HEADERS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(sdkHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(sdkdir)/$$f'"; \
+ $(sdkHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(sdkdir)/$$f"; \
+ done
+
+uninstall-sdkHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sdk_HEADERS)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(sdkdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(sdkdir)/$$f"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(sdkdir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-sdkHEADERS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-sdkHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-sdkHEADERS install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-info-am uninstall-sdkHEADERS
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/xserver/mi/cbrt.c b/xserver/mi/cbrt.c
new file mode 100644
index 000000000..c703fd9d2
--- /dev/null
+++ b/xserver/mi/cbrt.c
@@ -0,0 +1,46 @@
+/*
+
+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.
+
+*/
+
+/* simple cbrt, in case your math library doesn't have a good one */
+
+/*
+ * Would normally include <math.h> for this, but for the sake of compiler
+ * warnings, we don't want to get duplicate declarations for cbrt().
+ */
+
+double pow(double, double);
+double cbrt(double);
+
+double
+cbrt(double x)
+{
+ if (x > 0.0)
+ return pow(x, 1.0/3.0);
+ else
+ return -pow(-x, 1.0/3.0);
+}
diff --git a/xserver/mi/mi.h b/xserver/mi/mi.h
new file mode 100644
index 000000000..97e1b6f3a
--- /dev/null
+++ b/xserver/mi/mi.h
@@ -0,0 +1,625 @@
+/***********************************************************
+
+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.
+
+******************************************************************/
+
+#ifndef MI_H
+#define MI_H
+#include <X11/X.h>
+#include "region.h"
+#include "validate.h"
+#include "window.h"
+#include "gc.h"
+#include <X11/fonts/font.h>
+#include "input.h"
+#include "cursor.h"
+
+#define MiBits CARD32
+
+typedef struct _miDash *miDashPtr;
+#define EVEN_DASH 0
+#define ODD_DASH ~0
+
+/* miarc.c */
+
+extern void miPolyArc(
+ DrawablePtr /*pDraw*/,
+ GCPtr /*pGC*/,
+ int /*narcs*/,
+ xArc * /*parcs*/
+);
+
+/* mibitblt.c */
+
+extern RegionPtr miCopyArea(
+ DrawablePtr /*pSrcDrawable*/,
+ DrawablePtr /*pDstDrawable*/,
+ GCPtr /*pGC*/,
+ int /*xIn*/,
+ int /*yIn*/,
+ int /*widthSrc*/,
+ int /*heightSrc*/,
+ int /*xOut*/,
+ int /*yOut*/
+);
+
+extern void miOpqStipDrawable(
+ DrawablePtr /*pDraw*/,
+ GCPtr /*pGC*/,
+ RegionPtr /*prgnSrc*/,
+ MiBits * /*pbits*/,
+ int /*srcx*/,
+ int /*w*/,
+ int /*h*/,
+ int /*dstx*/,
+ int /*dsty*/
+);
+
+extern RegionPtr miCopyPlane(
+ DrawablePtr /*pSrcDrawable*/,
+ DrawablePtr /*pDstDrawable*/,
+ GCPtr /*pGC*/,
+ int /*srcx*/,
+ int /*srcy*/,
+ int /*width*/,
+ int /*height*/,
+ int /*dstx*/,
+ int /*dsty*/,
+ unsigned long /*bitPlane*/
+);
+
+extern void miGetImage(
+ DrawablePtr /*pDraw*/,
+ int /*sx*/,
+ int /*sy*/,
+ int /*w*/,
+ int /*h*/,
+ unsigned int /*format*/,
+ unsigned long /*planeMask*/,
+ char * /*pdstLine*/
+);
+
+extern void miPutImage(
+ DrawablePtr /*pDraw*/,
+ GCPtr /*pGC*/,
+ int /*depth*/,
+ int /*x*/,
+ int /*y*/,
+ int /*w*/,
+ int /*h*/,
+ int /*leftPad*/,
+ int /*format*/,
+ char * /*pImage*/
+);
+
+/* micursor.c */
+
+extern void miRecolorCursor(
+ ScreenPtr /*pScr*/,
+ CursorPtr /*pCurs*/,
+ Bool /*displayed*/
+);
+
+/* midash.c */
+
+extern miDashPtr miDashLine(
+ int /*npt*/,
+ DDXPointPtr /*ppt*/,
+ unsigned int /*nDash*/,
+ unsigned char * /*pDash*/,
+ unsigned int /*offset*/,
+ int * /*pnseg*/
+);
+
+extern void miStepDash(
+ int /*dist*/,
+ int * /*pDashIndex*/,
+ unsigned char * /*pDash*/,
+ int /*numInDashList*/,
+ int * /*pDashOffset*/
+);
+
+/* mieq.c */
+
+
+#ifndef INPUT_H
+typedef struct _DeviceRec *DevicePtr;
+#endif
+
+extern Bool mieqInit(
+ DevicePtr /*pKbd*/,
+ DevicePtr /*pPtr*/
+);
+
+extern void mieqEnqueue(
+ xEventPtr /*e*/
+);
+
+extern void mieqSwitchScreen(
+ ScreenPtr /*pScreen*/,
+ Bool /*fromDIX*/
+);
+
+extern void mieqProcessInputEvents(
+ void
+);
+
+/* miexpose.c */
+
+extern RegionPtr miHandleExposures(
+ DrawablePtr /*pSrcDrawable*/,
+ DrawablePtr /*pDstDrawable*/,
+ GCPtr /*pGC*/,
+ int /*srcx*/,
+ int /*srcy*/,
+ int /*width*/,
+ int /*height*/,
+ int /*dstx*/,
+ int /*dsty*/,
+ unsigned long /*plane*/
+);
+
+extern void miSendGraphicsExpose(
+ ClientPtr /*client*/,
+ RegionPtr /*pRgn*/,
+ XID /*drawable*/,
+ int /*major*/,
+ int /*minor*/
+);
+
+extern void miSendExposures(
+ WindowPtr /*pWin*/,
+ RegionPtr /*pRgn*/,
+ int /*dx*/,
+ int /*dy*/
+);
+
+extern void miWindowExposures(
+ WindowPtr /*pWin*/,
+ RegionPtr /*prgn*/,
+ RegionPtr /*other_exposed*/
+);
+
+extern void miPaintWindow(
+ WindowPtr /*pWin*/,
+ RegionPtr /*prgn*/,
+ int /*what*/
+);
+
+extern void miClearDrawable(
+ DrawablePtr /*pDraw*/,
+ GCPtr /*pGC*/
+);
+
+/* mifillrct.c */
+
+extern void miPolyFillRect(
+ DrawablePtr /*pDrawable*/,
+ GCPtr /*pGC*/,
+ int /*nrectFill*/,
+ xRectangle * /*prectInit*/
+);
+
+/* miglblt.c */
+
+extern void miPolyGlyphBlt(
+ DrawablePtr /*pDrawable*/,
+ GCPtr /*pGC*/,
+ int /*x*/,
+ int /*y*/,
+ unsigned int /*nglyph*/,
+ CharInfoPtr * /*ppci*/,
+ pointer /*pglyphBase*/
+);
+
+extern void miImageGlyphBlt(
+ DrawablePtr /*pDrawable*/,
+ GCPtr /*pGC*/,
+ int /*x*/,
+ int /*y*/,
+ unsigned int /*nglyph*/,
+ CharInfoPtr * /*ppci*/,
+ pointer /*pglyphBase*/
+);
+
+/* mipoly.c */
+
+extern void miFillPolygon(
+ DrawablePtr /*dst*/,
+ GCPtr /*pgc*/,
+ int /*shape*/,
+ int /*mode*/,
+ int /*count*/,
+ DDXPointPtr /*pPts*/
+);
+
+/* mipolycon.c */
+
+extern Bool miFillConvexPoly(
+ DrawablePtr /*dst*/,
+ GCPtr /*pgc*/,
+ int /*count*/,
+ DDXPointPtr /*ptsIn*/
+);
+
+/* mipolygen.c */
+
+extern Bool miFillGeneralPoly(
+ DrawablePtr /*dst*/,
+ GCPtr /*pgc*/,
+ int /*count*/,
+ DDXPointPtr /*ptsIn*/
+);
+
+/* mipolypnt.c */
+
+extern void miPolyPoint(
+ DrawablePtr /*pDrawable*/,
+ GCPtr /*pGC*/,
+ int /*mode*/,
+ int /*npt*/,
+ xPoint * /*pptInit*/
+);
+
+/* mipolyrect.c */
+
+extern void miPolyRectangle(
+ DrawablePtr /*pDraw*/,
+ GCPtr /*pGC*/,
+ int /*nrects*/,
+ xRectangle * /*pRects*/
+);
+
+/* mipolyseg.c */
+
+extern void miPolySegment(
+ DrawablePtr /*pDraw*/,
+ GCPtr /*pGC*/,
+ int /*nseg*/,
+ xSegment * /*pSegs*/
+);
+
+/* mipolytext.c */
+
+extern int miPolyText(
+ DrawablePtr /*pDraw*/,
+ GCPtr /*pGC*/,
+ int /*x*/,
+ int /*y*/,
+ int /*count*/,
+ char * /*chars*/,
+ FontEncoding /*fontEncoding*/
+);
+
+extern int miPolyText8(
+ DrawablePtr /*pDraw*/,
+ GCPtr /*pGC*/,
+ int /*x*/,
+ int /*y*/,
+ int /*count*/,
+ char * /*chars*/
+);
+
+extern int miPolyText16(
+ DrawablePtr /*pDraw*/,
+ GCPtr /*pGC*/,
+ int /*x*/,
+ int /*y*/,
+ int /*count*/,
+ unsigned short * /*chars*/
+);
+
+extern int miImageText(
+ DrawablePtr /*pDraw*/,
+ GCPtr /*pGC*/,
+ int /*x*/,
+ int /*y*/,
+ int /*count*/,
+ char * /*chars*/,
+ FontEncoding /*fontEncoding*/
+);
+
+extern void miImageText8(
+ DrawablePtr /*pDraw*/,
+ GCPtr /*pGC*/,
+ int /*x*/,
+ int /*y*/,
+ int /*count*/,
+ char * /*chars*/
+);
+
+extern void miImageText16(
+ DrawablePtr /*pDraw*/,
+ GCPtr /*pGC*/,
+ int /*x*/,
+ int /*y*/,
+ int /*count*/,
+ unsigned short * /*chars*/
+);
+
+/* mipushpxl.c */
+
+extern void miPushPixels(
+ GCPtr /*pGC*/,
+ PixmapPtr /*pBitMap*/,
+ DrawablePtr /*pDrawable*/,
+ int /*dx*/,
+ int /*dy*/,
+ int /*xOrg*/,
+ int /*yOrg*/
+);
+
+/* miregion.c */
+
+/* see also region.h */
+
+extern Bool miRectAlloc(
+ RegionPtr /*pRgn*/,
+ int /*n*/
+);
+
+extern void miSetExtents(
+ RegionPtr /*pReg*/
+);
+
+extern int miFindMaxBand(
+ RegionPtr /*prgn*/
+);
+
+#ifdef DEBUG
+extern Bool miValidRegion(
+ RegionPtr /*prgn*/
+);
+#endif
+
+extern Bool miRegionDataCopy(RegionPtr dst, RegionPtr src);
+extern Bool miRegionBroken(RegionPtr pReg);
+
+/* miscrinit.c */
+
+extern Bool miModifyPixmapHeader(
+ PixmapPtr /*pPixmap*/,
+ int /*width*/,
+ int /*height*/,
+ int /*depth*/,
+ int /*bitsPerPixel*/,
+ int /*devKind*/,
+ pointer /*pPixData*/
+);
+
+extern Bool miCloseScreen(
+ int /*index*/,
+ ScreenPtr /*pScreen*/
+);
+
+extern Bool miCreateScreenResources(
+ ScreenPtr /*pScreen*/
+);
+
+extern Bool miScreenDevPrivateInit(
+ ScreenPtr /*pScreen*/,
+ int /*width*/,
+ pointer /*pbits*/
+);
+
+extern Bool miScreenInit(
+ ScreenPtr /*pScreen*/,
+ pointer /*pbits*/,
+ int /*xsize*/,
+ int /*ysize*/,
+ int /*dpix*/,
+ int /*dpiy*/,
+ int /*width*/,
+ int /*rootDepth*/,
+ int /*numDepths*/,
+ DepthPtr /*depths*/,
+ VisualID /*rootVisual*/,
+ int /*numVisuals*/,
+ VisualPtr /*visuals*/
+);
+
+extern int miAllocateGCPrivateIndex(
+ void
+);
+
+extern PixmapPtr miGetScreenPixmap(
+ ScreenPtr pScreen
+);
+
+extern void miSetScreenPixmap(
+ PixmapPtr pPix
+);
+
+/* mivaltree.c */
+
+extern int miShapedWindowIn(
+ ScreenPtr /*pScreen*/,
+ RegionPtr /*universe*/,
+ RegionPtr /*bounding*/,
+ BoxPtr /*rect*/,
+ int /*x*/,
+ int /*y*/
+);
+
+typedef void
+(*SetRedirectBorderClipProcPtr) (WindowPtr pWindow, RegionPtr pRegion);
+
+typedef RegionPtr
+(*GetRedirectBorderClipProcPtr) (WindowPtr pWindow);
+
+void
+miRegisterRedirectBorderClipProc (SetRedirectBorderClipProcPtr setBorderClip,
+ GetRedirectBorderClipProcPtr getBorderClip);
+
+extern int miValidateTree(
+ WindowPtr /*pParent*/,
+ WindowPtr /*pChild*/,
+ VTKind /*kind*/
+);
+
+extern void miWideLine(
+ DrawablePtr /*pDrawable*/,
+ GCPtr /*pGC*/,
+ int /*mode*/,
+ int /*npt*/,
+ DDXPointPtr /*pPts*/
+);
+
+extern void miWideDash(
+ DrawablePtr /*pDrawable*/,
+ GCPtr /*pGC*/,
+ int /*mode*/,
+ int /*npt*/,
+ DDXPointPtr /*pPts*/
+);
+
+/* miwindow.c */
+
+extern void miClearToBackground(
+ WindowPtr /*pWin*/,
+ int /*x*/,
+ int /*y*/,
+ int /*w*/,
+ int /*h*/,
+ Bool /*generateExposures*/
+);
+
+extern Bool miChangeSaveUnder(
+ WindowPtr /*pWin*/,
+ WindowPtr /*first*/
+);
+
+extern void miPostChangeSaveUnder(
+ WindowPtr /*pWin*/,
+ WindowPtr /*pFirst*/
+);
+
+extern void miMarkWindow(
+ WindowPtr /*pWin*/
+);
+
+extern Bool miMarkOverlappedWindows(
+ WindowPtr /*pWin*/,
+ WindowPtr /*pFirst*/,
+ WindowPtr * /*ppLayerWin*/
+);
+
+extern void miHandleValidateExposures(
+ WindowPtr /*pWin*/
+);
+
+extern void miMoveWindow(
+ WindowPtr /*pWin*/,
+ int /*x*/,
+ int /*y*/,
+ WindowPtr /*pNextSib*/,
+ VTKind /*kind*/
+);
+
+extern void miSlideAndSizeWindow(
+ WindowPtr /*pWin*/,
+ int /*x*/,
+ int /*y*/,
+ unsigned int /*w*/,
+ unsigned int /*h*/,
+ WindowPtr /*pSib*/
+);
+
+extern WindowPtr miGetLayerWindow(
+ WindowPtr /*pWin*/
+);
+
+extern void miSetShape(
+ WindowPtr /*pWin*/
+);
+
+extern void miChangeBorderWidth(
+ WindowPtr /*pWin*/,
+ unsigned int /*width*/
+);
+
+extern void miMarkUnrealizedWindow(
+ WindowPtr /*pChild*/,
+ WindowPtr /*pWin*/,
+ Bool /*fromConfigure*/
+);
+
+extern void miSegregateChildren(WindowPtr pWin, RegionPtr pReg, int depth);
+
+/* mizerarc.c */
+
+extern void miZeroPolyArc(
+ DrawablePtr /*pDraw*/,
+ GCPtr /*pGC*/,
+ int /*narcs*/,
+ xArc * /*parcs*/
+);
+
+/* mizerline.c */
+
+extern void miZeroLine(
+ DrawablePtr /*dst*/,
+ GCPtr /*pgc*/,
+ int /*mode*/,
+ int /*nptInit*/,
+ DDXPointRec * /*pptInit*/
+);
+
+extern void miZeroDashLine(
+ DrawablePtr /*dst*/,
+ GCPtr /*pgc*/,
+ int /*mode*/,
+ int /*nptInit*/,
+ DDXPointRec * /*pptInit*/
+);
+
+extern void miPolyFillArc(
+ DrawablePtr /*pDraw*/,
+ GCPtr /*pGC*/,
+ int /*narcs*/,
+ xArc * /*parcs*/
+);
+
+#endif /* MI_H */
diff --git a/xserver/mi/miarc.c b/xserver/mi/miarc.c
new file mode 100644
index 000000000..2b3a0cbbc
--- /dev/null
+++ b/xserver/mi/miarc.c
@@ -0,0 +1,3720 @@
+/***********************************************************
+
+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.
+
+******************************************************************/
+/* Author: Keith Packard and Bob Scheifler */
+/* Warning: this code is toxic, do not dally very long here. */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#if defined(_XOPEN_SOURCE) || defined(__QNXNTO__) \
+ || (defined(sun) && defined(__SVR4))
+#include <math.h>
+#else
+#define _XOPEN_SOURCE /* to get prototype for hypot on some systems */
+#include <math.h>
+#undef _XOPEN_SOURCE
+#endif
+#include <X11/X.h>
+#include <X11/Xprotostr.h>
+#include "misc.h"
+#include "gcstruct.h"
+#include "scrnintstr.h"
+#include "pixmapstr.h"
+#include "windowstr.h"
+#include "mifpoly.h"
+#include "mi.h"
+#include "mifillarc.h"
+#include <X11/Xfuncproto.h>
+
+static double miDsin(double a);
+static double miDcos(double a);
+static double miDasin(double v);
+static double miDatan2(double dy, double dx);
+double cbrt(double);
+
+#ifdef ICEILTEMPDECL
+ICEILTEMPDECL
+#endif
+
+/*
+ * some interesting sematic interpretation of the protocol:
+ *
+ * Self intersecting arcs (i.e. those spanning 360 degrees)
+ * never join with other arcs, and are drawn without caps
+ * (unless on/off dashed, in which case each dash segment
+ * is capped, except when the last segment meets the
+ * first segment, when no caps are drawn)
+ *
+ * double dash arcs are drawn in two parts, first the
+ * odd dashes (drawn in background) then the even dashes
+ * (drawn in foreground). This means that overlapping
+ * sections of foreground/background are drawn twice,
+ * first in background then in foreground. The double-draw
+ * occurs even when the function uses the destination values
+ * (e.g. xor mode). This is the same way the wide-line
+ * code works and should be "fixed".
+ *
+ */
+
+#undef max
+#undef min
+
+#if defined (__GNUC__) && !defined (__STRICT_ANSI__)
+#define USE_INLINE
+#endif
+
+#ifdef USE_INLINE
+inline static int max (const int x, const int y)
+{
+ return x>y? x:y;
+}
+
+inline static int min (const int x, const int y)
+{
+ return x<y? x:y;
+}
+
+#else
+
+static int
+max (int x, int y)
+{
+ return x>y? x:y;
+}
+
+static int
+min (int x, int y)
+{
+ return x<y? x:y;
+}
+
+#endif
+
+struct bound {
+ double min, max;
+};
+
+struct ibound {
+ int min, max;
+};
+
+#define boundedLe(value, bounds)\
+ ((bounds).min <= (value) && (value) <= (bounds).max)
+
+struct line {
+ double m, b;
+ int valid;
+};
+
+#define intersectLine(y,line) (line.m * (y) + line.b)
+
+/*
+ * these are all y value bounds
+ */
+
+struct arc_bound {
+ struct bound ellipse;
+ struct bound inner;
+ struct bound outer;
+ struct bound right;
+ struct bound left;
+ struct ibound inneri;
+ struct ibound outeri;
+};
+
+struct accelerators {
+ double tail_y;
+ double h2;
+ double w2;
+ double h4;
+ double w4;
+ double h2mw2;
+ double h2l;
+ double w2l;
+ double fromIntX;
+ double fromIntY;
+ struct line left, right;
+ int yorgu;
+ int yorgl;
+ int xorg;
+};
+
+struct arc_def {
+ double w, h, l;
+ double a0, a1;
+};
+
+# define todeg(xAngle) (((double) (xAngle)) / 64.0)
+
+# define RIGHT_END 0
+# define LEFT_END 1
+
+typedef struct _miArcJoin {
+ int arcIndex0, arcIndex1;
+ int phase0, phase1;
+ int end0, end1;
+} miArcJoinRec, *miArcJoinPtr;
+
+typedef struct _miArcCap {
+ int arcIndex;
+ int end;
+} miArcCapRec, *miArcCapPtr;
+
+typedef struct _miArcFace {
+ SppPointRec clock;
+ SppPointRec center;
+ SppPointRec counterClock;
+} miArcFaceRec, *miArcFacePtr;
+
+typedef struct _miArcData {
+ xArc arc;
+ int render; /* non-zero means render after drawing */
+ int join; /* related join */
+ int cap; /* related cap */
+ int selfJoin; /* final dash meets first dash */
+ miArcFaceRec bounds[2];
+ double x0, y0, x1, y1;
+} miArcDataRec, *miArcDataPtr;
+
+/*
+ * This is an entire sequence of arcs, computed and categorized according
+ * to operation. miDashArcs generates either one or two of these.
+ */
+
+typedef struct _miPolyArc {
+ int narcs;
+ miArcDataPtr arcs;
+ int ncaps;
+ miArcCapPtr caps;
+ int njoins;
+ miArcJoinPtr joins;
+} miPolyArcRec, *miPolyArcPtr;
+
+#define GCValsFunction 0
+#define GCValsForeground 1
+#define GCValsBackground 2
+#define GCValsLineWidth 3
+#define GCValsCapStyle 4
+#define GCValsJoinStyle 5
+#define GCValsMask (GCFunction | GCForeground | GCBackground | \
+ GCLineWidth | GCCapStyle | GCJoinStyle)
+static CARD32 gcvals[6];
+
+static void fillSpans(DrawablePtr pDrawable, GCPtr pGC);
+static void newFinalSpan(int y, register int xmin, register int xmax);
+static void drawArc(xArc *tarc, int l, int a0, int a1, miArcFacePtr right,
+ miArcFacePtr left);
+static void drawZeroArc(DrawablePtr pDraw, GCPtr pGC, xArc *tarc, int lw,
+ miArcFacePtr left, miArcFacePtr right);
+static void miArcJoin(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pLeft,
+ miArcFacePtr pRight, int xOrgLeft, int yOrgLeft,
+ double xFtransLeft, double yFtransLeft,
+ int xOrgRight, int yOrgRight,
+ double xFtransRight, double yFtransRight);
+static void miArcCap(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pFace,
+ int end, int xOrg, int yOrg, double xFtrans,
+ double yFtrans);
+static void miRoundCap(DrawablePtr pDraw, GCPtr pGC, SppPointRec pCenter,
+ SppPointRec pEnd, SppPointRec pCorner,
+ SppPointRec pOtherCorner, int fLineEnd,
+ int xOrg, int yOrg, double xFtrans, double yFtrans);
+static void miFreeArcs(miPolyArcPtr arcs, GCPtr pGC);
+static miPolyArcPtr miComputeArcs(xArc *parcs, int narcs, GCPtr pGC);
+static int miGetArcPts(SppArcPtr parc, int cpt, SppPointPtr *ppPts);
+
+# define CUBED_ROOT_2 1.2599210498948732038115849718451499938964
+# define CUBED_ROOT_4 1.5874010519681993173435330390930175781250
+
+/*
+ * draw one segment of the arc using the arc spans generation routines
+ */
+
+static void
+miArcSegment(
+ DrawablePtr pDraw,
+ GCPtr pGC,
+ xArc tarc,
+ miArcFacePtr right,
+ miArcFacePtr left)
+{
+ int l = pGC->lineWidth;
+ int a0, a1, startAngle, endAngle;
+ miArcFacePtr temp;
+
+ if (!l)
+ l = 1;
+
+ if (tarc.width == 0 || tarc.height == 0) {
+ drawZeroArc (pDraw, pGC, &tarc, l, left, right);
+ return;
+ }
+
+ if (pGC->miTranslate) {
+ tarc.x += pDraw->x;
+ tarc.y += pDraw->y;
+ }
+
+ a0 = tarc.angle1;
+ a1 = tarc.angle2;
+ if (a1 > FULLCIRCLE)
+ a1 = FULLCIRCLE;
+ else if (a1 < -FULLCIRCLE)
+ a1 = -FULLCIRCLE;
+ if (a1 < 0) {
+ startAngle = a0 + a1;
+ endAngle = a0;
+ temp = right;
+ right = left;
+ left = temp;
+ } else {
+ startAngle = a0;
+ endAngle = a0 + a1;
+ }
+ /*
+ * bounds check the two angles
+ */
+ if (startAngle < 0)
+ startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
+ if (startAngle >= FULLCIRCLE)
+ startAngle = startAngle % FULLCIRCLE;
+ if (endAngle < 0)
+ endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE;
+ if (endAngle > FULLCIRCLE)
+ endAngle = (endAngle-1) % FULLCIRCLE + 1;
+ if ((startAngle == endAngle) && a1) {
+ startAngle = 0;
+ endAngle = FULLCIRCLE;
+ }
+
+ drawArc (&tarc, l, startAngle, endAngle, right, left);
+}
+
+/*
+
+Three equations combine to describe the boundaries of the arc
+
+x^2/w^2 + y^2/h^2 = 1 ellipse itself
+(X-x)^2 + (Y-y)^2 = r^2 circle at (x, y) on the ellipse
+(Y-y) = (X-x)*w^2*y/(h^2*x) normal at (x, y) on the ellipse
+
+These lead to a quartic relating Y and y
+
+y^4 - (2Y)y^3 + (Y^2 + (h^4 - w^2*r^2)/(w^2 - h^2))y^2
+ - (2Y*h^4/(w^2 - h^2))y + (Y^2*h^4)/(w^2 - h^2) = 0
+
+The reducible cubic obtained from this quartic is
+
+z^3 - (3N)z^2 - 2V = 0
+
+where
+
+N = (Y^2 + (h^4 - w^2*r^2/(w^2 - h^2)))/6
+V = w^2*r^2*Y^2*h^4/(4 *(w^2 - h^2)^2)
+
+Let
+
+t = z - N
+p = -N^2
+q = -N^3 - V
+
+Then we get
+
+t^3 + 3pt + 2q = 0
+
+The discriminant of this cubic is
+
+D = q^2 + p^3
+
+When D > 0, a real root is obtained as
+
+z = N + cbrt(-q+sqrt(D)) + cbrt(-q-sqrt(D))
+
+When D < 0, a real root is obtained as
+
+z = N - 2m*cos(acos(-q/m^3)/3)
+
+where
+
+m = sqrt(|p|) * sign(q)
+
+Given a real root Z of the cubic, the roots of the quartic are the roots
+of the two quadratics
+
+y^2 + ((b+A)/2)y + (Z + (bZ - d)/A) = 0
+
+where
+
+A = +/- sqrt(8Z + b^2 - 4c)
+b, c, d are the cubic, quadratic, and linear coefficients of the quartic
+
+Some experimentation is then required to determine which solutions
+correspond to the inner and outer boundaries.
+
+*/
+
+typedef struct {
+ short lx, lw, rx, rw;
+} miArcSpan;
+
+typedef struct {
+ miArcSpan *spans;
+ int count1, count2, k;
+ char top, bot, hole;
+} miArcSpanData;
+
+typedef struct {
+ unsigned long lrustamp;
+ unsigned short lw;
+ unsigned short width, height;
+ miArcSpanData *spdata;
+} arcCacheRec;
+
+#define CACHESIZE 25
+
+static void drawQuadrant(struct arc_def *def, struct accelerators *acc,
+ int a0, int a1, int mask, miArcFacePtr right,
+ miArcFacePtr left, miArcSpanData *spdata);
+
+static arcCacheRec arcCache[CACHESIZE];
+static unsigned long lrustamp;
+static arcCacheRec *lastCacheHit = &arcCache[0];
+static RESTYPE cacheType;
+
+/*
+ * External so it can be called when low on memory.
+ * Call with a zero ID in that case.
+ */
+/*ARGSUSED*/
+int
+miFreeArcCache (data, id)
+ pointer data;
+ XID id;
+{
+ int k;
+ arcCacheRec *cent;
+
+ if (id)
+ cacheType = 0;
+
+ for (k = CACHESIZE, cent = &arcCache[0]; --k >= 0; cent++)
+ {
+ if (cent->spdata)
+ {
+ cent->lrustamp = 0;
+ cent->lw = 0;
+ xfree(cent->spdata);
+ cent->spdata = NULL;
+ }
+ }
+ lrustamp = 0;
+ return Success;
+}
+
+static void
+miComputeCircleSpans(
+ int lw,
+ xArc *parc,
+ miArcSpanData *spdata)
+{
+ register miArcSpan *span;
+ int doinner;
+ register int x, y, e;
+ int xk, yk, xm, ym, dx, dy;
+ register int slw, inslw;
+ int inx = 0, iny, ine = 0;
+ int inxk = 0, inyk = 0, inxm = 0, inym = 0;
+
+ doinner = -lw;
+ slw = parc->width - doinner;
+ y = parc->height >> 1;
+ dy = parc->height & 1;
+ dx = 1 - dy;
+ MIWIDEARCSETUP(x, y, dy, slw, e, xk, xm, yk, ym);
+ inslw = parc->width + doinner;
+ if (inslw > 0)
+ {
+ spdata->hole = spdata->top;
+ MIWIDEARCSETUP(inx, iny, dy, inslw, ine, inxk, inxm, inyk, inym);
+ }
+ else
+ {
+ spdata->hole = FALSE;
+ doinner = -y;
+ }
+ spdata->count1 = -doinner - spdata->top;
+ spdata->count2 = y + doinner;
+ span = spdata->spans;
+ while (y)
+ {
+ MIFILLARCSTEP(slw);
+ span->lx = dy - x;
+ if (++doinner <= 0)
+ {
+ span->lw = slw;
+ span->rx = 0;
+ span->rw = span->lx + slw;
+ }
+ else
+ {
+ MIFILLINARCSTEP(inslw);
+ span->lw = x - inx;
+ span->rx = dy - inx + inslw;
+ span->rw = inx - x + slw - inslw;
+ }
+ span++;
+ }
+ if (spdata->bot)
+ {
+ if (spdata->count2)
+ spdata->count2--;
+ else
+ {
+ if (lw > (int)parc->height)
+ span[-1].rx = span[-1].rw = -((lw - (int)parc->height) >> 1);
+ else
+ span[-1].rw = 0;
+ spdata->count1--;
+ }
+ }
+}
+
+static void
+miComputeEllipseSpans(
+ int lw,
+ xArc *parc,
+ miArcSpanData *spdata)
+{
+ register miArcSpan *span;
+ double w, h, r, xorg;
+ double Hs, Hf, WH, K, Vk, Nk, Fk, Vr, N, Nc, Z, rs;
+ double A, T, b, d, x, y, t, inx, outx = 0.0, hepp, hepm;
+ int flip, solution;
+
+ w = (double)parc->width / 2.0;
+ h = (double)parc->height / 2.0;
+ r = lw / 2.0;
+ rs = r * r;
+ Hs = h * h;
+ WH = w * w - Hs;
+ Nk = w * r;
+ Vk = (Nk * Hs) / (WH + WH);
+ Hf = Hs * Hs;
+ Nk = (Hf - Nk * Nk) / WH;
+ Fk = Hf / WH;
+ hepp = h + EPSILON;
+ hepm = h - EPSILON;
+ K = h + ((lw - 1) >> 1);
+ span = spdata->spans;
+ if (parc->width & 1)
+ xorg = .5;
+ else
+ xorg = 0.0;
+ if (spdata->top)
+ {
+ span->lx = 0;
+ span->lw = 1;
+ span++;
+ }
+ spdata->count1 = 0;
+ spdata->count2 = 0;
+ spdata->hole = (spdata->top &&
+ (int)parc->height * lw <= (int)(parc->width * parc->width) &&
+ lw < (int)parc->height);
+ for (; K > 0.0; K -= 1.0)
+ {
+ N = (K * K + Nk) / 6.0;
+ Nc = N * N * N;
+ Vr = Vk * K;
+ t = Nc + Vr * Vr;
+ d = Nc + t;
+ if (d < 0.0) {
+ d = Nc;
+ b = N;
+ if ( (b < 0.0) == (t < 0.0) )
+ {
+ b = -b;
+ d = -d;
+ }
+ Z = N - 2.0 * b * cos(acos(-t / d) / 3.0);
+ if ( (Z < 0.0) == (Vr < 0.0) )
+ flip = 2;
+ else
+ flip = 1;
+ }
+ else
+ {
+ d = Vr * sqrt(d);
+ Z = N + cbrt(t + d) + cbrt(t - d);
+ flip = 0;
+ }
+ A = sqrt((Z + Z) - Nk);
+ T = (Fk - Z) * K / A;
+ inx = 0.0;
+ solution = FALSE;
+ b = -A + K;
+ d = b * b - 4 * (Z + T);
+ if (d >= 0)
+ {
+ d = sqrt(d);
+ y = (b + d) / 2;
+ if ((y >= 0.0) && (y < hepp))
+ {
+ solution = TRUE;
+ if (y > hepm)
+ y = h;
+ t = y / h;
+ x = w * sqrt(1 - (t * t));
+ t = K - y;
+ if (rs - (t * t) >= 0)
+ t = sqrt(rs - (t * t));
+ else
+ t = 0;
+ if (flip == 2)
+ inx = x - t;
+ else
+ outx = x + t;
+ }
+ }
+ b = A + K;
+ d = b * b - 4 * (Z - T);
+ /* Because of the large magnitudes involved, we lose enough precision
+ * that sometimes we end up with a negative value near the axis, when
+ * it should be positive. This is a workaround.
+ */
+ if (d < 0 && !solution)
+ d = 0.0;
+ if (d >= 0) {
+ d = sqrt(d);
+ y = (b + d) / 2;
+ if (y < hepp)
+ {
+ if (y > hepm)
+ y = h;
+ t = y / h;
+ x = w * sqrt(1 - (t * t));
+ t = K - y;
+ if (rs - (t * t) >= 0)
+ inx = x - sqrt(rs - (t * t));
+ else
+ inx = x;
+ }
+ y = (b - d) / 2;
+ if (y >= 0.0)
+ {
+ if (y > hepm)
+ y = h;
+ t = y / h;
+ x = w * sqrt(1 - (t * t));
+ t = K - y;
+ if (rs - (t * t) >= 0)
+ t = sqrt(rs - (t * t));
+ else
+ t = 0;
+ if (flip == 1)
+ inx = x - t;
+ else
+ outx = x + t;
+ }
+ }
+ span->lx = ICEIL(xorg - outx);
+ if (inx <= 0.0)
+ {
+ spdata->count1++;
+ span->lw = ICEIL(xorg + outx) - span->lx;
+ span->rx = ICEIL(xorg + inx);
+ span->rw = -ICEIL(xorg - inx);
+ }
+ else
+ {
+ spdata->count2++;
+ span->lw = ICEIL(xorg - inx) - span->lx;
+ span->rx = ICEIL(xorg + inx);
+ span->rw = ICEIL(xorg + outx) - span->rx;
+ }
+ span++;
+ }
+ if (spdata->bot)
+ {
+ outx = w + r;
+ if (r >= h && r <= w)
+ inx = 0.0;
+ else if (Nk < 0.0 && -Nk < Hs)
+ {
+ inx = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk);
+ if (inx > w - r)
+ inx = w - r;
+ }
+ else
+ inx = w - r;
+ span->lx = ICEIL(xorg - outx);
+ if (inx <= 0.0)
+ {
+ span->lw = ICEIL(xorg + outx) - span->lx;
+ span->rx = ICEIL(xorg + inx);
+ span->rw = -ICEIL(xorg - inx);
+ }
+ else
+ {
+ span->lw = ICEIL(xorg - inx) - span->lx;
+ span->rx = ICEIL(xorg + inx);
+ span->rw = ICEIL(xorg + outx) - span->rx;
+ }
+ }
+ if (spdata->hole)
+ {
+ span = &spdata->spans[spdata->count1];
+ span->lw = -span->lx;
+ span->rx = 1;
+ span->rw = span->lw;
+ spdata->count1--;
+ spdata->count2++;
+ }
+}
+
+static double
+tailX(
+ double K,
+ struct arc_def *def,
+ struct arc_bound *bounds,
+ struct accelerators *acc)
+{
+ double w, h, r;
+ double Hs, Hf, WH, Vk, Nk, Fk, Vr, N, Nc, Z, rs;
+ double A, T, b, d, x, y, t, hepp, hepm;
+ int flip, solution;
+ double xs[2];
+ double *xp;
+
+ w = def->w;
+ h = def->h;
+ r = def->l;
+ rs = r * r;
+ Hs = acc->h2;
+ WH = -acc->h2mw2;
+ Nk = def->w * r;
+ Vk = (Nk * Hs) / (WH + WH);
+ Hf = acc->h4;
+ Nk = (Hf - Nk * Nk) / WH;
+ if (K == 0.0) {
+ if (Nk < 0.0 && -Nk < Hs) {
+ xs[0] = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk);
+ xs[1] = w - r;
+ if (acc->left.valid && boundedLe(K, bounds->left) &&
+ !boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0)
+ return xs[1];
+ if (acc->right.valid && boundedLe(K, bounds->right) &&
+ !boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0)
+ return xs[1];
+ return xs[0];
+ }
+ return w - r;
+ }
+ Fk = Hf / WH;
+ hepp = h + EPSILON;
+ hepm = h - EPSILON;
+ N = (K * K + Nk) / 6.0;
+ Nc = N * N * N;
+ Vr = Vk * K;
+ xp = xs;
+ xs[0] = 0.0;
+ t = Nc + Vr * Vr;
+ d = Nc + t;
+ if (d < 0.0) {
+ d = Nc;
+ b = N;
+ if ( (b < 0.0) == (t < 0.0) )
+ {
+ b = -b;
+ d = -d;
+ }
+ Z = N - 2.0 * b * cos(acos(-t / d) / 3.0);
+ if ( (Z < 0.0) == (Vr < 0.0) )
+ flip = 2;
+ else
+ flip = 1;
+ }
+ else
+ {
+ d = Vr * sqrt(d);
+ Z = N + cbrt(t + d) + cbrt(t - d);
+ flip = 0;
+ }
+ A = sqrt((Z + Z) - Nk);
+ T = (Fk - Z) * K / A;
+ solution = FALSE;
+ b = -A + K;
+ d = b * b - 4 * (Z + T);
+ if (d >= 0 && flip == 2)
+ {
+ d = sqrt(d);
+ y = (b + d) / 2;
+ if ((y >= 0.0) && (y < hepp))
+ {
+ solution = TRUE;
+ if (y > hepm)
+ y = h;
+ t = y / h;
+ x = w * sqrt(1 - (t * t));
+ t = K - y;
+ if (rs - (t * t) >= 0)
+ t = sqrt(rs - (t * t));
+ else
+ t = 0;
+ *xp++ = x - t;
+ }
+ }
+ b = A + K;
+ d = b * b - 4 * (Z - T);
+ /* Because of the large magnitudes involved, we lose enough precision
+ * that sometimes we end up with a negative value near the axis, when
+ * it should be positive. This is a workaround.
+ */
+ if (d < 0 && !solution)
+ d = 0.0;
+ if (d >= 0) {
+ d = sqrt(d);
+ y = (b + d) / 2;
+ if (y < hepp)
+ {
+ if (y > hepm)
+ y = h;
+ t = y / h;
+ x = w * sqrt(1 - (t * t));
+ t = K - y;
+ if (rs - (t * t) >= 0)
+ *xp++ = x - sqrt(rs - (t * t));
+ else
+ *xp++ = x;
+ }
+ y = (b - d) / 2;
+ if (y >= 0.0 && flip == 1)
+ {
+ if (y > hepm)
+ y = h;
+ t = y / h;
+ x = w * sqrt(1 - (t * t));
+ t = K - y;
+ if (rs - (t * t) >= 0)
+ t = sqrt(rs - (t * t));
+ else
+ t = 0;
+ *xp++ = x - t;
+ }
+ }
+ if (xp > &xs[1]) {
+ if (acc->left.valid && boundedLe(K, bounds->left) &&
+ !boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0)
+ return xs[1];
+ if (acc->right.valid && boundedLe(K, bounds->right) &&
+ !boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0)
+ return xs[1];
+ }
+ return xs[0];
+}
+
+static miArcSpanData *
+miComputeWideEllipse(
+ int lw,
+ register xArc *parc,
+ Bool *mustFree)
+{
+ register miArcSpanData *spdata;
+ register arcCacheRec *cent, *lruent;
+ register int k;
+ arcCacheRec fakeent;
+
+ if (!lw)
+ lw = 1;
+ if (parc->height <= 1500)
+ {
+ *mustFree = FALSE;
+ cent = lastCacheHit;
+ if (cent->lw == lw &&
+ cent->width == parc->width && cent->height == parc->height)
+ {
+ cent->lrustamp = ++lrustamp;
+ return cent->spdata;
+ }
+ lruent = &arcCache[0];
+ for (k = CACHESIZE, cent = lruent; --k >= 0; cent++)
+ {
+ if (cent->lw == lw &&
+ cent->width == parc->width && cent->height == parc->height)
+ {
+ cent->lrustamp = ++lrustamp;
+ lastCacheHit = cent;
+ return cent->spdata;
+ }
+ if (cent->lrustamp < lruent->lrustamp)
+ lruent = cent;
+ }
+ if (!cacheType)
+ {
+ cacheType = CreateNewResourceType(miFreeArcCache);
+ (void) AddResource(FakeClientID(0), cacheType, NULL);
+ }
+ } else {
+ lruent = &fakeent;
+ lruent->spdata = NULL;
+ *mustFree = TRUE;
+ }
+ k = (parc->height >> 1) + ((lw - 1) >> 1);
+ spdata = lruent->spdata;
+ if (!spdata || spdata->k != k)
+ {
+ if (spdata)
+ xfree(spdata);
+ spdata = (miArcSpanData *)xalloc(sizeof(miArcSpanData) +
+ sizeof(miArcSpan) * (k + 2));
+ lruent->spdata = spdata;
+ if (!spdata)
+ {
+ lruent->lrustamp = 0;
+ lruent->lw = 0;
+ return spdata;
+ }
+ spdata->spans = (miArcSpan *)(spdata + 1);
+ spdata->k = k;
+ }
+ spdata->top = !(lw & 1) && !(parc->width & 1);
+ spdata->bot = !(parc->height & 1);
+ lruent->lrustamp = ++lrustamp;
+ lruent->lw = lw;
+ lruent->width = parc->width;
+ lruent->height = parc->height;
+ if (lruent != &fakeent)
+ lastCacheHit = lruent;
+ if (parc->width == parc->height)
+ miComputeCircleSpans(lw, parc, spdata);
+ else
+ miComputeEllipseSpans(lw, parc, spdata);
+ return spdata;
+}
+
+static void
+miFillWideEllipse(
+ DrawablePtr pDraw,
+ GCPtr pGC,
+ xArc *parc)
+{
+ DDXPointPtr points;
+ register DDXPointPtr pts;
+ int *widths;
+ register int *wids;
+ miArcSpanData *spdata;
+ Bool mustFree;
+ register miArcSpan *span;
+ register int xorg, yorgu, yorgl;
+ register int n;
+
+ yorgu = parc->height + pGC->lineWidth;
+ n = (sizeof(int) * 2) * yorgu;
+ widths = (int *)ALLOCATE_LOCAL(n + (sizeof(DDXPointRec) * 2) * yorgu);
+ if (!widths)
+ return;
+ points = (DDXPointPtr)((char *)widths + n);
+ spdata = miComputeWideEllipse((int)pGC->lineWidth, parc, &mustFree);
+ if (!spdata)
+ {
+ DEALLOCATE_LOCAL(widths);
+ return;
+ }
+ pts = points;
+ wids = widths;
+ span = spdata->spans;
+ xorg = parc->x + (parc->width >> 1);
+ yorgu = parc->y + (parc->height >> 1);
+ yorgl = yorgu + (parc->height & 1);
+ if (pGC->miTranslate)
+ {
+ xorg += pDraw->x;
+ yorgu += pDraw->y;
+ yorgl += pDraw->y;
+ }
+ yorgu -= spdata->k;
+ yorgl += spdata->k;
+ if (spdata->top)
+ {
+ pts->x = xorg;
+ pts->y = yorgu - 1;
+ pts++;
+ *wids++ = 1;
+ span++;
+ }
+ for (n = spdata->count1; --n >= 0; )
+ {
+ pts[0].x = xorg + span->lx;
+ pts[0].y = yorgu;
+ wids[0] = span->lw;
+ pts[1].x = pts[0].x;
+ pts[1].y = yorgl;
+ wids[1] = wids[0];
+ yorgu++;
+ yorgl--;
+ pts += 2;
+ wids += 2;
+ span++;
+ }
+ if (spdata->hole)
+ {
+ pts[0].x = xorg;
+ pts[0].y = yorgl;
+ wids[0] = 1;
+ pts++;
+ wids++;
+ }
+ for (n = spdata->count2; --n >= 0; )
+ {
+ pts[0].x = xorg + span->lx;
+ pts[0].y = yorgu;
+ wids[0] = span->lw;
+ pts[1].x = xorg + span->rx;
+ pts[1].y = pts[0].y;
+ wids[1] = span->rw;
+ pts[2].x = pts[0].x;
+ pts[2].y = yorgl;
+ wids[2] = wids[0];
+ pts[3].x = pts[1].x;
+ pts[3].y = pts[2].y;
+ wids[3] = wids[1];
+ yorgu++;
+ yorgl--;
+ pts += 4;
+ wids += 4;
+ span++;
+ }
+ if (spdata->bot)
+ {
+ if (span->rw <= 0)
+ {
+ pts[0].x = xorg + span->lx;
+ pts[0].y = yorgu;
+ wids[0] = span->lw;
+ pts++;
+ wids++;
+ }
+ else
+ {
+ pts[0].x = xorg + span->lx;
+ pts[0].y = yorgu;
+ wids[0] = span->lw;
+ pts[1].x = xorg + span->rx;
+ pts[1].y = pts[0].y;
+ wids[1] = span->rw;
+ pts += 2;
+ wids += 2;
+ }
+ }
+ if (mustFree)
+ xfree(spdata);
+ (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE);
+
+ DEALLOCATE_LOCAL(widths);
+}
+
+/*
+ * miPolyArc strategy:
+ *
+ * If arc is zero width and solid, we don't have to worry about the rasterop
+ * or join styles. For wide solid circles, we use a fast integer algorithm.
+ * For wide solid ellipses, we use special case floating point code.
+ * Otherwise, we set up pDrawTo and pGCTo according to the rasterop, then
+ * draw using pGCTo and pDrawTo. If the raster-op was "tricky," that is,
+ * if it involves the destination, then we use PushPixels to move the bits
+ * from the scratch drawable to pDraw. (See the wide line code for a
+ * fuller explanation of this.)
+ */
+
+_X_EXPORT void
+miPolyArc(pDraw, pGC, narcs, parcs)
+ DrawablePtr pDraw;
+ GCPtr pGC;
+ int narcs;
+ xArc *parcs;
+{
+ register int i;
+ xArc *parc;
+ int xMin, xMax, yMin, yMax;
+ int pixmapWidth = 0, pixmapHeight = 0;
+ int xOrg = 0, yOrg = 0;
+ int width;
+ Bool fTricky;
+ DrawablePtr pDrawTo;
+ CARD32 fg, bg;
+ GCPtr pGCTo;
+ miPolyArcPtr polyArcs;
+ int cap[2], join[2];
+ int iphase;
+ int halfWidth;
+
+ width = pGC->lineWidth;
+ if(width == 0 && pGC->lineStyle == LineSolid)
+ {
+ for(i = narcs, parc = parcs; --i >= 0; parc++)
+ miArcSegment( pDraw, pGC, *parc,
+ (miArcFacePtr) 0, (miArcFacePtr) 0 );
+ fillSpans (pDraw, pGC);
+ }
+ else
+ {
+ if ((pGC->lineStyle == LineSolid) && narcs)
+ {
+ while (parcs->width && parcs->height &&
+ (parcs->angle2 >= FULLCIRCLE ||
+ parcs->angle2 <= -FULLCIRCLE))
+ {
+ miFillWideEllipse(pDraw, pGC, parcs);
+ if (!--narcs)
+ return;
+ parcs++;
+ }
+ }
+
+ /* Set up pDrawTo and pGCTo based on the rasterop */
+ switch(pGC->alu)
+ {
+ case GXclear: /* 0 */
+ case GXcopy: /* src */
+ case GXcopyInverted: /* NOT src */
+ case GXset: /* 1 */
+ fTricky = FALSE;
+ pDrawTo = pDraw;
+ pGCTo = pGC;
+ break;
+ default:
+ fTricky = TRUE;
+
+ /* find bounding box around arcs */
+ xMin = yMin = MAXSHORT;
+ xMax = yMax = MINSHORT;
+
+ for(i = narcs, parc = parcs; --i >= 0; parc++)
+ {
+ xMin = min (xMin, parc->x);
+ yMin = min (yMin, parc->y);
+ xMax = max (xMax, (parc->x + (int) parc->width));
+ yMax = max (yMax, (parc->y + (int) parc->height));
+ }
+
+ /* expand box to deal with line widths */
+ halfWidth = (width + 1)/2;
+ xMin -= halfWidth;
+ yMin -= halfWidth;
+ xMax += halfWidth;
+ yMax += halfWidth;
+
+ /* compute pixmap size; limit it to size of drawable */
+ xOrg = max(xMin, 0);
+ yOrg = max(yMin, 0);
+ pixmapWidth = min(xMax, pDraw->width) - xOrg;
+ pixmapHeight = min(yMax, pDraw->height) - yOrg;
+
+ /* if nothing left, return */
+ if ( (pixmapWidth <= 0) || (pixmapHeight <= 0) ) return;
+
+ for(i = narcs, parc = parcs; --i >= 0; parc++)
+ {
+ parc->x -= xOrg;
+ parc->y -= yOrg;
+ }
+ if (pGC->miTranslate)
+ {
+ xOrg += pDraw->x;
+ yOrg += pDraw->y;
+ }
+
+ /* set up scratch GC */
+
+ pGCTo = GetScratchGC(1, pDraw->pScreen);
+ if (!pGCTo)
+ return;
+ gcvals[GCValsFunction] = GXcopy;
+ gcvals[GCValsForeground] = 1;
+ gcvals[GCValsBackground] = 0;
+ gcvals[GCValsLineWidth] = pGC->lineWidth;
+ gcvals[GCValsCapStyle] = pGC->capStyle;
+ gcvals[GCValsJoinStyle] = pGC->joinStyle;
+ dixChangeGC(NullClient, pGCTo, GCValsMask, gcvals, NULL);
+
+ /* allocate a 1 bit deep pixmap of the appropriate size, and
+ * validate it */
+ pDrawTo = (DrawablePtr)(*pDraw->pScreen->CreatePixmap)
+ (pDraw->pScreen, pixmapWidth, pixmapHeight, 1);
+ if (!pDrawTo)
+ {
+ FreeScratchGC(pGCTo);
+ return;
+ }
+ ValidateGC(pDrawTo, pGCTo);
+ miClearDrawable(pDrawTo, pGCTo);
+ }
+
+ fg = pGC->fgPixel;
+ bg = pGC->bgPixel;
+ if ((pGC->fillStyle == FillTiled) ||
+ (pGC->fillStyle == FillOpaqueStippled))
+ bg = fg; /* the protocol sez these don't cause color changes */
+
+ polyArcs = miComputeArcs (parcs, narcs, pGC);
+
+ if (!polyArcs)
+ {
+ if (fTricky) {
+ (*pDraw->pScreen->DestroyPixmap) ((PixmapPtr)pDrawTo);
+ FreeScratchGC (pGCTo);
+ }
+ return;
+ }
+
+ cap[0] = cap[1] = 0;
+ join[0] = join[1] = 0;
+ for (iphase = ((pGC->lineStyle == LineDoubleDash) ? 1 : 0);
+ iphase >= 0;
+ iphase--)
+ {
+ if (iphase == 1) {
+ dixChangeGC (NullClient, pGC, GCForeground, &bg, NULL);
+ ValidateGC (pDraw, pGC);
+ } else if (pGC->lineStyle == LineDoubleDash) {
+ dixChangeGC (NullClient, pGC, GCForeground, &fg, NULL);
+ ValidateGC (pDraw, pGC);
+ }
+ for (i = 0; i < polyArcs[iphase].narcs; i++) {
+ miArcDataPtr arcData;
+
+ arcData = &polyArcs[iphase].arcs[i];
+ miArcSegment(pDrawTo, pGCTo, arcData->arc,
+ &arcData->bounds[RIGHT_END],
+ &arcData->bounds[LEFT_END]);
+ if (polyArcs[iphase].arcs[i].render) {
+ fillSpans (pDrawTo, pGCTo);
+ /*
+ * don't cap self-joining arcs
+ */
+ if (polyArcs[iphase].arcs[i].selfJoin &&
+ cap[iphase] < polyArcs[iphase].arcs[i].cap)
+ cap[iphase]++;
+ while (cap[iphase] < polyArcs[iphase].arcs[i].cap) {
+ int arcIndex, end;
+ miArcDataPtr arcData0;
+
+ arcIndex = polyArcs[iphase].caps[cap[iphase]].arcIndex;
+ end = polyArcs[iphase].caps[cap[iphase]].end;
+ arcData0 = &polyArcs[iphase].arcs[arcIndex];
+ miArcCap (pDrawTo, pGCTo,
+ &arcData0->bounds[end], end,
+ arcData0->arc.x, arcData0->arc.y,
+ (double) arcData0->arc.width / 2.0,
+ (double) arcData0->arc.height / 2.0);
+ ++cap[iphase];
+ }
+ while (join[iphase] < polyArcs[iphase].arcs[i].join) {
+ int arcIndex0, arcIndex1, end0, end1;
+ int phase0, phase1;
+ miArcDataPtr arcData0, arcData1;
+ miArcJoinPtr joinp;
+
+ joinp = &polyArcs[iphase].joins[join[iphase]];
+ arcIndex0 = joinp->arcIndex0;
+ end0 = joinp->end0;
+ arcIndex1 = joinp->arcIndex1;
+ end1 = joinp->end1;
+ phase0 = joinp->phase0;
+ phase1 = joinp->phase1;
+ arcData0 = &polyArcs[phase0].arcs[arcIndex0];
+ arcData1 = &polyArcs[phase1].arcs[arcIndex1];
+ miArcJoin (pDrawTo, pGCTo,
+ &arcData0->bounds[end0],
+ &arcData1->bounds[end1],
+ arcData0->arc.x, arcData0->arc.y,
+ (double) arcData0->arc.width / 2.0,
+ (double) arcData0->arc.height / 2.0,
+ arcData1->arc.x, arcData1->arc.y,
+ (double) arcData1->arc.width / 2.0,
+ (double) arcData1->arc.height / 2.0);
+ ++join[iphase];
+ }
+ if (fTricky) {
+ if (pGC->serialNumber != pDraw->serialNumber)
+ ValidateGC (pDraw, pGC);
+ (*pGC->ops->PushPixels) (pGC, (PixmapPtr)pDrawTo,
+ pDraw, pixmapWidth, pixmapHeight, xOrg, yOrg);
+ miClearDrawable ((DrawablePtr) pDrawTo, pGCTo);
+ }
+ }
+ }
+ }
+ miFreeArcs(polyArcs, pGC);
+
+ if(fTricky)
+ {
+ (*pGCTo->pScreen->DestroyPixmap)((PixmapPtr)pDrawTo);
+ FreeScratchGC(pGCTo);
+ }
+ }
+}
+
+static double
+angleBetween (SppPointRec center, SppPointRec point1, SppPointRec point2)
+{
+ double a1, a2, a;
+
+ /*
+ * reflect from X coordinates back to ellipse
+ * coordinates -- y increasing upwards
+ */
+ a1 = miDatan2 (- (point1.y - center.y), point1.x - center.x);
+ a2 = miDatan2 (- (point2.y - center.y), point2.x - center.x);
+ a = a2 - a1;
+ if (a <= -180.0)
+ a += 360.0;
+ else if (a > 180.0)
+ a -= 360.0;
+ return a;
+}
+
+static void
+translateBounds (
+ miArcFacePtr b,
+ int x,
+ int y,
+ double fx,
+ double fy)
+{
+ fx += x;
+ fy += y;
+ b->clock.x -= fx;
+ b->clock.y -= fy;
+ b->center.x -= fx;
+ b->center.y -= fy;
+ b->counterClock.x -= fx;
+ b->counterClock.y -= fy;
+}
+
+static void
+miArcJoin(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pLeft,
+ miArcFacePtr pRight, int xOrgLeft, int yOrgLeft,
+ double xFtransLeft, double yFtransLeft,
+ int xOrgRight, int yOrgRight,
+ double xFtransRight, double yFtransRight)
+{
+ SppPointRec center, corner, otherCorner;
+ SppPointRec poly[5], e;
+ SppPointPtr pArcPts;
+ int cpt;
+ SppArcRec arc;
+ miArcFaceRec Right, Left;
+ int polyLen = 0;
+ int xOrg, yOrg;
+ double xFtrans, yFtrans;
+ double a;
+ double ae, ac2, ec2, bc2, de;
+ double width;
+
+ xOrg = (xOrgRight + xOrgLeft) / 2;
+ yOrg = (yOrgRight + yOrgLeft) / 2;
+ xFtrans = (xFtransLeft + xFtransRight) / 2;
+ yFtrans = (yFtransLeft + yFtransRight) / 2;
+ Right = *pRight;
+ translateBounds (&Right, xOrg - xOrgRight, yOrg - yOrgRight,
+ xFtrans - xFtransRight, yFtrans - yFtransRight);
+ Left = *pLeft;
+ translateBounds (&Left, xOrg - xOrgLeft, yOrg - yOrgLeft,
+ xFtrans - xFtransLeft, yFtrans - yFtransLeft);
+ pRight = &Right;
+ pLeft = &Left;
+
+ if (pRight->clock.x == pLeft->counterClock.x &&
+ pRight->clock.y == pLeft->counterClock.y)
+ return;
+ center = pRight->center;
+ if (0 <= (a = angleBetween (center, pRight->clock, pLeft->counterClock))
+ && a <= 180.0)
+ {
+ corner = pRight->clock;
+ otherCorner = pLeft->counterClock;
+ } else {
+ a = angleBetween (center, pLeft->clock, pRight->counterClock);
+ corner = pLeft->clock;
+ otherCorner = pRight->counterClock;
+ }
+ switch (pGC->joinStyle) {
+ case JoinRound:
+ width = (pGC->lineWidth ? (double)pGC->lineWidth : (double)1);
+
+ arc.x = center.x - width/2;
+ arc.y = center.y - width/2;
+ arc.width = width;
+ arc.height = width;
+ arc.angle1 = -miDatan2 (corner.y - center.y, corner.x - center.x);
+ arc.angle2 = a;
+ pArcPts = (SppPointPtr) xalloc (3 * sizeof (SppPointRec));
+ if (!pArcPts)
+ return;
+ pArcPts[0].x = otherCorner.x;
+ pArcPts[0].y = otherCorner.y;
+ pArcPts[1].x = center.x;
+ pArcPts[1].y = center.y;
+ pArcPts[2].x = corner.x;
+ pArcPts[2].y = corner.y;
+ if( (cpt = miGetArcPts(&arc, 3, &pArcPts)) )
+ {
+ /* by drawing with miFillSppPoly and setting the endpoints of the arc
+ * to be the corners, we assure that the cap will meet up with the
+ * rest of the line */
+ miFillSppPoly(pDraw, pGC, cpt, pArcPts, xOrg, yOrg, xFtrans, yFtrans);
+ }
+ xfree(pArcPts);
+ return;
+ case JoinMiter:
+ /*
+ * don't miter arcs with less than 11 degrees between them
+ */
+ if (a < 169.0) {
+ poly[0] = corner;
+ poly[1] = center;
+ poly[2] = otherCorner;
+ bc2 = (corner.x - otherCorner.x) * (corner.x - otherCorner.x) +
+ (corner.y - otherCorner.y) * (corner.y - otherCorner.y);
+ ec2 = bc2 / 4;
+ ac2 = (corner.x - center.x) * (corner.x - center.x) +
+ (corner.y - center.y) * (corner.y - center.y);
+ ae = sqrt (ac2 - ec2);
+ de = ec2 / ae;
+ e.x = (corner.x + otherCorner.x) / 2;
+ e.y = (corner.y + otherCorner.y) / 2;
+ poly[3].x = e.x + de * (e.x - center.x) / ae;
+ poly[3].y = e.y + de * (e.y - center.y) / ae;
+ poly[4] = corner;
+ polyLen = 5;
+ break;
+ }
+ case JoinBevel:
+ poly[0] = corner;
+ poly[1] = center;
+ poly[2] = otherCorner;
+ poly[3] = corner;
+ polyLen = 4;
+ break;
+ }
+ miFillSppPoly (pDraw, pGC, polyLen, poly, xOrg, yOrg, xFtrans, yFtrans);
+}
+
+/*ARGSUSED*/
+static void
+miArcCap (
+ DrawablePtr pDraw,
+ GCPtr pGC,
+ miArcFacePtr pFace,
+ int end,
+ int xOrg,
+ int yOrg,
+ double xFtrans,
+ double yFtrans)
+{
+ SppPointRec corner, otherCorner, center, endPoint, poly[5];
+
+ corner = pFace->clock;
+ otherCorner = pFace->counterClock;
+ center = pFace->center;
+ switch (pGC->capStyle) {
+ case CapProjecting:
+ poly[0].x = otherCorner.x;
+ poly[0].y = otherCorner.y;
+ poly[1].x = corner.x;
+ poly[1].y = corner.y;
+ poly[2].x = corner.x -
+ (center.y - corner.y);
+ poly[2].y = corner.y +
+ (center.x - corner.x);
+ poly[3].x = otherCorner.x -
+ (otherCorner.y - center.y);
+ poly[3].y = otherCorner.y +
+ (otherCorner.x - center.x);
+ poly[4].x = otherCorner.x;
+ poly[4].y = otherCorner.y;
+ miFillSppPoly (pDraw, pGC, 5, poly, xOrg, yOrg, xFtrans, yFtrans);
+ break;
+ case CapRound:
+ /*
+ * miRoundCap just needs these to be unequal.
+ */
+ endPoint = center;
+ endPoint.x = endPoint.x + 100;
+ miRoundCap (pDraw, pGC, center, endPoint, corner, otherCorner, 0,
+ -xOrg, -yOrg, xFtrans, yFtrans);
+ break;
+ }
+}
+
+/* MIROUNDCAP -- a private helper function
+ * Put Rounded cap on end. pCenter is the center of this end of the line
+ * pEnd is the center of the other end of the line. pCorner is one of the
+ * two corners at this end of the line.
+ * NOTE: pOtherCorner must be counter-clockwise from pCorner.
+ */
+/*ARGSUSED*/
+static void
+miRoundCap(
+ DrawablePtr pDraw,
+ GCPtr pGC,
+ SppPointRec pCenter,
+ SppPointRec pEnd,
+ SppPointRec pCorner,
+ SppPointRec pOtherCorner,
+ int fLineEnd,
+ int xOrg,
+ int yOrg,
+ double xFtrans,
+ double yFtrans)
+{
+ int cpt;
+ double width;
+ SppArcRec arc;
+ SppPointPtr pArcPts;
+
+ width = (pGC->lineWidth ? (double)pGC->lineWidth : (double)1);
+
+ arc.x = pCenter.x - width/2;
+ arc.y = pCenter.y - width/2;
+ arc.width = width;
+ arc.height = width;
+ arc.angle1 = -miDatan2 (pCorner.y - pCenter.y, pCorner.x - pCenter.x);
+ if(PTISEQUAL(pCenter, pEnd))
+ arc.angle2 = - 180.0;
+ else {
+ arc.angle2 = -miDatan2 (pOtherCorner.y - pCenter.y, pOtherCorner.x - pCenter.x) - arc.angle1;
+ if (arc.angle2 < 0)
+ arc.angle2 += 360.0;
+ }
+ pArcPts = (SppPointPtr) NULL;
+ if( (cpt = miGetArcPts(&arc, 0, &pArcPts)) )
+ {
+ /* by drawing with miFillSppPoly and setting the endpoints of the arc
+ * to be the corners, we assure that the cap will meet up with the
+ * rest of the line */
+ miFillSppPoly(pDraw, pGC, cpt, pArcPts, -xOrg, -yOrg, xFtrans, yFtrans);
+ }
+ xfree(pArcPts);
+}
+
+/*
+ * To avoid inaccuracy at the cardinal points, use trig functions
+ * which are exact for those angles
+ */
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+#ifndef M_PI_2
+#define M_PI_2 1.57079632679489661923
+#endif
+
+# define Dsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
+# define Dcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
+# define mod(a,b) ((a) >= 0 ? (a) % (b) : (b) - (-a) % (b))
+
+static double
+miDcos (double a)
+{
+ int i;
+
+ if (floor (a/90) == a/90) {
+ i = (int) (a/90.0);
+ switch (mod (i, 4)) {
+ case 0: return 1;
+ case 1: return 0;
+ case 2: return -1;
+ case 3: return 0;
+ }
+ }
+ return cos (a * M_PI / 180.0);
+}
+
+static double
+miDsin (double a)
+{
+ int i;
+
+ if (floor (a/90) == a/90) {
+ i = (int) (a/90.0);
+ switch (mod (i, 4)) {
+ case 0: return 0;
+ case 1: return 1;
+ case 2: return 0;
+ case 3: return -1;
+ }
+ }
+ return sin (a * M_PI / 180.0);
+}
+
+static double
+miDasin (double v)
+{
+ if (v == 0)
+ return 0.0;
+ if (v == 1.0)
+ return 90.0;
+ if (v == -1.0)
+ return -90.0;
+ return asin(v) * (180.0 / M_PI);
+}
+
+static double
+miDatan2 (double dy, double dx)
+{
+ if (dy == 0) {
+ if (dx >= 0)
+ return 0.0;
+ return 180.0;
+ } else if (dx == 0) {
+ if (dy > 0)
+ return 90.0;
+ return -90.0;
+ } else if (Fabs (dy) == Fabs (dx)) {
+ if (dy > 0) {
+ if (dx > 0)
+ return 45.0;
+ return 135.0;
+ } else {
+ if (dx > 0)
+ return 315.0;
+ return 225.0;
+ }
+ } else {
+ return atan2 (dy, dx) * (180.0 / M_PI);
+ }
+}
+
+/* MIGETARCPTS -- Converts an arc into a set of line segments -- a helper
+ * routine for filled arc and line (round cap) code.
+ * Returns the number of points in the arc. Note that it takes a pointer
+ * to a pointer to where it should put the points and an index (cpt).
+ * This procedure allocates the space necessary to fit the arc points.
+ * Sometimes it's convenient for those points to be at the end of an existing
+ * array. (For example, if we want to leave a spare point to make sectors
+ * instead of segments.) So we pass in the xalloc()ed chunk that contains the
+ * array and an index saying where we should start stashing the points.
+ * If there isn't an array already, we just pass in a null pointer and
+ * count on xrealloc() to handle the null pointer correctly.
+ */
+static int
+miGetArcPts(
+ SppArcPtr parc, /* points to an arc */
+ int cpt, /* number of points already in arc list */
+ SppPointPtr *ppPts) /* pointer to pointer to arc-list -- modified */
+{
+ double st, /* Start Theta, start angle */
+ et, /* End Theta, offset from start theta */
+ dt, /* Delta Theta, angle to sweep ellipse */
+ cdt, /* Cos Delta Theta, actually 2 cos(dt) */
+ x0, y0, /* the recurrence formula needs two points to start */
+ x1, y1,
+ x2, y2, /* this will be the new point generated */
+ xc, yc; /* the center point */
+ int count, i;
+ SppPointPtr poly;
+
+ /* The spec says that positive angles indicate counterclockwise motion.
+ * Given our coordinate system (with 0,0 in the upper left corner),
+ * the screen appears flipped in Y. The easiest fix is to negate the
+ * angles given */
+
+ st = - parc->angle1;
+
+ et = - parc->angle2;
+
+ /* Try to get a delta theta that is within 1/2 pixel. Then adjust it
+ * so that it divides evenly into the total.
+ * I'm just using cdt 'cause I'm lazy.
+ */
+ cdt = parc->width;
+ if (parc->height > cdt)
+ cdt = parc->height;
+ cdt /= 2.0;
+ if(cdt <= 0)
+ return 0;
+ if (cdt < 1.0)
+ cdt = 1.0;
+ dt = miDasin ( 1.0 / cdt ); /* minimum step necessary */
+ count = et/dt;
+ count = abs(count) + 1;
+ dt = et/count;
+ count++;
+
+ cdt = 2 * miDcos(dt);
+ if (!(poly = (SppPointPtr) xrealloc((pointer)*ppPts,
+ (cpt + count) * sizeof(SppPointRec))))
+ return(0);
+ *ppPts = poly;
+
+ xc = parc->width/2.0; /* store half width and half height */
+ yc = parc->height/2.0;
+
+ x0 = xc * miDcos(st);
+ y0 = yc * miDsin(st);
+ x1 = xc * miDcos(st + dt);
+ y1 = yc * miDsin(st + dt);
+ xc += parc->x; /* by adding initial point, these become */
+ yc += parc->y; /* the center point */
+
+ poly[cpt].x = (xc + x0);
+ poly[cpt].y = (yc + y0);
+ poly[cpt + 1].x = (xc + x1);
+ poly[cpt + 1].y = (yc + y1);
+
+ for(i = 2; i < count; i++)
+ {
+ x2 = cdt * x1 - x0;
+ y2 = cdt * y1 - y0;
+
+ poly[cpt + i].x = (xc + x2);
+ poly[cpt + i].y = (yc + y2);
+
+ x0 = x1; y0 = y1;
+ x1 = x2; y1 = y2;
+ }
+ /* adjust the last point */
+ if (abs(parc->angle2) >= 360.0)
+ poly[cpt +i -1] = poly[0];
+ else {
+ poly[cpt +i -1].x = (miDcos(st + et) * parc->width/2.0 + xc);
+ poly[cpt +i -1].y = (miDsin(st + et) * parc->height/2.0 + yc);
+ }
+
+ return(count);
+}
+
+struct arcData {
+ double x0, y0, x1, y1;
+ int selfJoin;
+};
+
+# define ADD_REALLOC_STEP 20
+
+static void
+addCap (
+ miArcCapPtr *capsp,
+ int *ncapsp,
+ int *sizep,
+ int end,
+ int arcIndex)
+{
+ int newsize;
+ miArcCapPtr cap;
+
+ if (*ncapsp == *sizep)
+ {
+ newsize = *sizep + ADD_REALLOC_STEP;
+ cap = (miArcCapPtr) xrealloc (*capsp,
+ newsize * sizeof (**capsp));
+ if (!cap)
+ return;
+ *sizep = newsize;
+ *capsp = cap;
+ }
+ cap = &(*capsp)[*ncapsp];
+ cap->end = end;
+ cap->arcIndex = arcIndex;
+ ++*ncapsp;
+}
+
+static void
+addJoin (
+ miArcJoinPtr *joinsp,
+ int *njoinsp,
+ int *sizep,
+ int end0,
+ int index0,
+ int phase0,
+ int end1,
+ int index1,
+ int phase1)
+{
+ int newsize;
+ miArcJoinPtr join;
+
+ if (*njoinsp == *sizep)
+ {
+ newsize = *sizep + ADD_REALLOC_STEP;
+ join = (miArcJoinPtr) xrealloc (*joinsp,
+ newsize * sizeof (**joinsp));
+ if (!join)
+ return;
+ *sizep = newsize;
+ *joinsp = join;
+ }
+ join = &(*joinsp)[*njoinsp];
+ join->end0 = end0;
+ join->arcIndex0 = index0;
+ join->phase0 = phase0;
+ join->end1 = end1;
+ join->arcIndex1 = index1;
+ join->phase1 = phase1;
+ ++*njoinsp;
+}
+
+static miArcDataPtr
+addArc (
+ miArcDataPtr *arcsp,
+ int *narcsp,
+ int *sizep,
+ xArc *xarc)
+{
+ int newsize;
+ miArcDataPtr arc;
+
+ if (*narcsp == *sizep)
+ {
+ newsize = *sizep + ADD_REALLOC_STEP;
+ arc = (miArcDataPtr) xrealloc (*arcsp,
+ newsize * sizeof (**arcsp));
+ if (!arc)
+ return (miArcDataPtr)NULL;
+ *sizep = newsize;
+ *arcsp = arc;
+ }
+ arc = &(*arcsp)[*narcsp];
+ arc->arc = *xarc;
+ ++*narcsp;
+ return arc;
+}
+
+static void
+miFreeArcs(
+ miPolyArcPtr arcs,
+ GCPtr pGC)
+{
+ int iphase;
+
+ for (iphase = ((pGC->lineStyle == LineDoubleDash) ? 1 : 0);
+ iphase >= 0;
+ iphase--)
+ {
+ if (arcs[iphase].narcs > 0)
+ xfree(arcs[iphase].arcs);
+ if (arcs[iphase].njoins > 0)
+ xfree(arcs[iphase].joins);
+ if (arcs[iphase].ncaps > 0)
+ xfree(arcs[iphase].caps);
+ }
+ xfree(arcs);
+}
+
+/*
+ * map angles to radial distance. This only deals with the first quadrant
+ */
+
+/*
+ * a polygonal approximation to the arc for computing arc lengths
+ */
+
+# define DASH_MAP_SIZE 91
+
+# define dashIndexToAngle(di) ((((double) (di)) * 90.0) / ((double) DASH_MAP_SIZE - 1))
+# define xAngleToDashIndex(xa) ((((long) (xa)) * (DASH_MAP_SIZE - 1)) / (90 * 64))
+# define dashIndexToXAngle(di) ((((long) (di)) * (90 * 64)) / (DASH_MAP_SIZE - 1))
+# define dashXAngleStep (((double) (90 * 64)) / ((double) (DASH_MAP_SIZE - 1)))
+
+typedef struct {
+ double map[DASH_MAP_SIZE];
+} dashMap;
+
+static int computeAngleFromPath(int startAngle, int endAngle, dashMap *map,
+ int *lenp, int backwards);
+
+static void
+computeDashMap (
+ xArc *arcp,
+ dashMap *map)
+{
+ int di;
+ double a, x, y, prevx = 0.0, prevy = 0.0, dist;
+
+ for (di = 0; di < DASH_MAP_SIZE; di++) {
+ a = dashIndexToAngle (di);
+ x = ((double) arcp->width / 2.0) * miDcos (a);
+ y = ((double) arcp->height / 2.0) * miDsin (a);
+ if (di == 0) {
+ map->map[di] = 0.0;
+ } else {
+ dist = hypot (x - prevx, y - prevy);
+ map->map[di] = map->map[di - 1] + dist;
+ }
+ prevx = x;
+ prevy = y;
+ }
+}
+
+typedef enum {HORIZONTAL, VERTICAL, OTHER} arcTypes;
+
+/* this routine is a bit gory */
+
+static miPolyArcPtr
+miComputeArcs (
+ xArc *parcs,
+ int narcs,
+ GCPtr pGC)
+{
+ int isDashed, isDoubleDash;
+ int dashOffset;
+ miPolyArcPtr arcs;
+ int start, i, j, k = 0, nexti, nextk = 0;
+ int joinSize[2];
+ int capSize[2];
+ int arcSize[2];
+ int angle2;
+ double a0, a1;
+ struct arcData *data;
+ miArcDataPtr arc;
+ xArc xarc;
+ int iphase, prevphase = 0, joinphase;
+ int arcsJoin;
+ int selfJoin;
+
+ int iDash = 0, dashRemaining;
+ int iDashStart = 0, dashRemainingStart = 0, iphaseStart;
+ int startAngle, spanAngle, endAngle, backwards = 0;
+ int prevDashAngle, dashAngle;
+ dashMap map;
+
+ isDashed = !(pGC->lineStyle == LineSolid);
+ isDoubleDash = (pGC->lineStyle == LineDoubleDash);
+ dashOffset = pGC->dashOffset;
+
+ data = (struct arcData *) ALLOCATE_LOCAL (narcs * sizeof (struct arcData));
+ if (!data)
+ return (miPolyArcPtr)NULL;
+ arcs = (miPolyArcPtr) xalloc (sizeof (*arcs) * (isDoubleDash ? 2 : 1));
+ if (!arcs)
+ {
+ DEALLOCATE_LOCAL(data);
+ return (miPolyArcPtr)NULL;
+ }
+ for (i = 0; i < narcs; i++) {
+ a0 = todeg (parcs[i].angle1);
+ angle2 = parcs[i].angle2;
+ if (angle2 > FULLCIRCLE)
+ angle2 = FULLCIRCLE;
+ else if (angle2 < -FULLCIRCLE)
+ angle2 = -FULLCIRCLE;
+ data[i].selfJoin = angle2 == FULLCIRCLE || angle2 == -FULLCIRCLE;
+ a1 = todeg (parcs[i].angle1 + angle2);
+ data[i].x0 = parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos (a0));
+ data[i].y0 = parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin (a0));
+ data[i].x1 = parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos (a1));
+ data[i].y1 = parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin (a1));
+ }
+
+ for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++) {
+ arcs[iphase].njoins = 0;
+ arcs[iphase].joins = 0;
+ joinSize[iphase] = 0;
+
+ arcs[iphase].ncaps = 0;
+ arcs[iphase].caps = 0;
+ capSize[iphase] = 0;
+
+ arcs[iphase].narcs = 0;
+ arcs[iphase].arcs = 0;
+ arcSize[iphase] = 0;
+ }
+
+ iphase = 0;
+ if (isDashed) {
+ iDash = 0;
+ dashRemaining = pGC->dash[0];
+ while (dashOffset > 0) {
+ if (dashOffset >= dashRemaining) {
+ dashOffset -= dashRemaining;
+ iphase = iphase ? 0 : 1;
+ iDash++;
+ if (iDash == pGC->numInDashList)
+ iDash = 0;
+ dashRemaining = pGC->dash[iDash];
+ } else {
+ dashRemaining -= dashOffset;
+ dashOffset = 0;
+ }
+ }
+ iDashStart = iDash;
+ dashRemainingStart = dashRemaining;
+ }
+ iphaseStart = iphase;
+
+ for (i = narcs - 1; i >= 0; i--) {
+ j = i + 1;
+ if (j == narcs)
+ j = 0;
+ if (data[i].selfJoin || i == j ||
+ (UNEQUAL (data[i].x1, data[j].x0) ||
+ UNEQUAL (data[i].y1, data[j].y0)))
+ {
+ if (iphase == 0 || isDoubleDash)
+ addCap (&arcs[iphase].caps, &arcs[iphase].ncaps,
+ &capSize[iphase], RIGHT_END, 0);
+ break;
+ }
+ }
+ start = i + 1;
+ if (start == narcs)
+ start = 0;
+ i = start;
+ for (;;) {
+ j = i + 1;
+ if (j == narcs)
+ j = 0;
+ nexti = i+1;
+ if (nexti == narcs)
+ nexti = 0;
+ if (isDashed) {
+ /*
+ ** deal with dashed arcs. Use special rules for certain 0 area arcs.
+ ** Presumably, the other 0 area arcs still aren't done right.
+ */
+ arcTypes arcType = OTHER;
+ CARD16 thisLength;
+
+ if (parcs[i].height == 0
+ && (parcs[i].angle1 % FULLCIRCLE) == 0x2d00
+ && parcs[i].angle2 == 0x2d00)
+ arcType = HORIZONTAL;
+ else if (parcs[i].width == 0
+ && (parcs[i].angle1 % FULLCIRCLE) == 0x1680
+ && parcs[i].angle2 == 0x2d00)
+ arcType = VERTICAL;
+ if (arcType == OTHER) {
+ /*
+ * precompute an approximation map
+ */
+ computeDashMap (&parcs[i], &map);
+ /*
+ * compute each individual dash segment using the path
+ * length function
+ */
+ startAngle = parcs[i].angle1;
+ spanAngle = parcs[i].angle2;
+ if (spanAngle > FULLCIRCLE)
+ spanAngle = FULLCIRCLE;
+ else if (spanAngle < -FULLCIRCLE)
+ spanAngle = -FULLCIRCLE;
+ if (startAngle < 0)
+ startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
+ if (startAngle >= FULLCIRCLE)
+ startAngle = startAngle % FULLCIRCLE;
+ endAngle = startAngle + spanAngle;
+ backwards = spanAngle < 0;
+ } else {
+ xarc = parcs[i];
+ if (arcType == VERTICAL) {
+ xarc.angle1 = 0x1680;
+ startAngle = parcs[i].y;
+ endAngle = startAngle + parcs[i].height;
+ } else {
+ xarc.angle1 = 0x2d00;
+ startAngle = parcs[i].x;
+ endAngle = startAngle + parcs[i].width;
+ }
+ }
+ dashAngle = startAngle;
+ selfJoin = data[i].selfJoin &&
+ (iphase == 0 || isDoubleDash);
+ /*
+ * add dashed arcs to each bucket
+ */
+ arc = 0;
+ while (dashAngle != endAngle) {
+ prevDashAngle = dashAngle;
+ if (arcType == OTHER) {
+ dashAngle = computeAngleFromPath (prevDashAngle, endAngle,
+ &map, &dashRemaining, backwards);
+ /* avoid troubles with huge arcs and small dashes */
+ if (dashAngle == prevDashAngle) {
+ if (backwards)
+ dashAngle--;
+ else
+ dashAngle++;
+ }
+ } else {
+ thisLength = (dashAngle + dashRemaining <= endAngle) ?
+ dashRemaining : endAngle - dashAngle;
+ if (arcType == VERTICAL) {
+ xarc.y = dashAngle;
+ xarc.height = thisLength;
+ } else {
+ xarc.x = dashAngle;
+ xarc.width = thisLength;
+ }
+ dashAngle += thisLength;
+ dashRemaining -= thisLength;
+ }
+ if (iphase == 0 || isDoubleDash) {
+ if (arcType == OTHER) {
+ xarc = parcs[i];
+ spanAngle = prevDashAngle;
+ if (spanAngle < 0)
+ spanAngle = FULLCIRCLE - (-spanAngle) % FULLCIRCLE;
+ if (spanAngle >= FULLCIRCLE)
+ spanAngle = spanAngle % FULLCIRCLE;
+ xarc.angle1 = spanAngle;
+ spanAngle = dashAngle - prevDashAngle;
+ if (backwards) {
+ if (dashAngle > prevDashAngle)
+ spanAngle = - FULLCIRCLE + spanAngle;
+ } else {
+ if (dashAngle < prevDashAngle)
+ spanAngle = FULLCIRCLE + spanAngle;
+ }
+ if (spanAngle > FULLCIRCLE)
+ spanAngle = FULLCIRCLE;
+ if (spanAngle < -FULLCIRCLE)
+ spanAngle = -FULLCIRCLE;
+ xarc.angle2 = spanAngle;
+ }
+ arc = addArc (&arcs[iphase].arcs, &arcs[iphase].narcs,
+ &arcSize[iphase], &xarc);
+ if (!arc)
+ goto arcfail;
+ /*
+ * cap each end of an on/off dash
+ */
+ if (!isDoubleDash) {
+ if (prevDashAngle != startAngle) {
+ addCap (&arcs[iphase].caps,
+ &arcs[iphase].ncaps,
+ &capSize[iphase], RIGHT_END,
+ arc - arcs[iphase].arcs);
+
+ }
+ if (dashAngle != endAngle) {
+ addCap (&arcs[iphase].caps,
+ &arcs[iphase].ncaps,
+ &capSize[iphase], LEFT_END,
+ arc - arcs[iphase].arcs);
+ }
+ }
+ arc->cap = arcs[iphase].ncaps;
+ arc->join = arcs[iphase].njoins;
+ arc->render = 0;
+ arc->selfJoin = 0;
+ if (dashAngle == endAngle)
+ arc->selfJoin = selfJoin;
+ }
+ prevphase = iphase;
+ if (dashRemaining <= 0) {
+ ++iDash;
+ if (iDash == pGC->numInDashList)
+ iDash = 0;
+ iphase = iphase ? 0:1;
+ dashRemaining = pGC->dash[iDash];
+ }
+ }
+ /*
+ * make sure a place exists for the position data when
+ * drawing a zero-length arc
+ */
+ if (startAngle == endAngle) {
+ prevphase = iphase;
+ if (!isDoubleDash && iphase == 1)
+ prevphase = 0;
+ arc = addArc (&arcs[prevphase].arcs, &arcs[prevphase].narcs,
+ &arcSize[prevphase], &parcs[i]);
+ if (!arc)
+ goto arcfail;
+ arc->join = arcs[prevphase].njoins;
+ arc->cap = arcs[prevphase].ncaps;
+ arc->selfJoin = data[i].selfJoin;
+ }
+ } else {
+ arc = addArc (&arcs[iphase].arcs, &arcs[iphase].narcs,
+ &arcSize[iphase], &parcs[i]);
+ if (!arc)
+ goto arcfail;
+ arc->join = arcs[iphase].njoins;
+ arc->cap = arcs[iphase].ncaps;
+ arc->selfJoin = data[i].selfJoin;
+ prevphase = iphase;
+ }
+ if (prevphase == 0 || isDoubleDash)
+ k = arcs[prevphase].narcs - 1;
+ if (iphase == 0 || isDoubleDash)
+ nextk = arcs[iphase].narcs;
+ if (nexti == start) {
+ nextk = 0;
+ if (isDashed) {
+ iDash = iDashStart;
+ iphase = iphaseStart;
+ dashRemaining = dashRemainingStart;
+ }
+ }
+ arcsJoin = narcs > 1 && i != j &&
+ ISEQUAL (data[i].x1, data[j].x0) &&
+ ISEQUAL (data[i].y1, data[j].y0) &&
+ !data[i].selfJoin && !data[j].selfJoin;
+ if (arc)
+ {
+ if (arcsJoin)
+ arc->render = 0;
+ else
+ arc->render = 1;
+ }
+ if (arcsJoin &&
+ (prevphase == 0 || isDoubleDash) &&
+ (iphase == 0 || isDoubleDash))
+ {
+ joinphase = iphase;
+ if (isDoubleDash) {
+ if (nexti == start)
+ joinphase = iphaseStart;
+ /*
+ * if the join is right at the dash,
+ * draw the join in foreground
+ * This is because the foreground
+ * arcs are computed second, the results
+ * of which are needed to draw the join
+ */
+ if (joinphase != prevphase)
+ joinphase = 0;
+ }
+ if (joinphase == 0 || isDoubleDash) {
+ addJoin (&arcs[joinphase].joins,
+ &arcs[joinphase].njoins,
+ &joinSize[joinphase],
+ LEFT_END, k, prevphase,
+ RIGHT_END, nextk, iphase);
+ arc->join = arcs[prevphase].njoins;
+ }
+ } else {
+ /*
+ * cap the left end of this arc
+ * unless it joins itself
+ */
+ if ((prevphase == 0 || isDoubleDash) &&
+ !arc->selfJoin)
+ {
+ addCap (&arcs[prevphase].caps, &arcs[prevphase].ncaps,
+ &capSize[prevphase], LEFT_END, k);
+ arc->cap = arcs[prevphase].ncaps;
+ }
+ if (isDashed && !arcsJoin) {
+ iDash = iDashStart;
+ iphase = iphaseStart;
+ dashRemaining = dashRemainingStart;
+ }
+ nextk = arcs[iphase].narcs;
+ if (nexti == start) {
+ nextk = 0;
+ iDash = iDashStart;
+ iphase = iphaseStart;
+ dashRemaining = dashRemainingStart;
+ }
+ /*
+ * cap the right end of the next arc. If the
+ * next arc is actually the first arc, only
+ * cap it if it joins with this arc. This
+ * case will occur when the final dash segment
+ * of an on/off dash is off. Of course, this
+ * cap will be drawn at a strange time, but that
+ * hardly matters...
+ */
+ if ((iphase == 0 || isDoubleDash) &&
+ (nexti != start || (arcsJoin && isDashed)))
+ addCap (&arcs[iphase].caps, &arcs[iphase].ncaps,
+ &capSize[iphase], RIGHT_END, nextk);
+ }
+ i = nexti;
+ if (i == start)
+ break;
+ }
+ /*
+ * make sure the last section is rendered
+ */
+ for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++)
+ if (arcs[iphase].narcs > 0) {
+ arcs[iphase].arcs[arcs[iphase].narcs-1].render = 1;
+ arcs[iphase].arcs[arcs[iphase].narcs-1].join =
+ arcs[iphase].njoins;
+ arcs[iphase].arcs[arcs[iphase].narcs-1].cap =
+ arcs[iphase].ncaps;
+ }
+ DEALLOCATE_LOCAL(data);
+ return arcs;
+arcfail:
+ miFreeArcs(arcs, pGC);
+ DEALLOCATE_LOCAL(data);
+ return (miPolyArcPtr)NULL;
+}
+
+static double
+angleToLength (
+ int angle,
+ dashMap *map)
+{
+ double len, excesslen, sidelen = map->map[DASH_MAP_SIZE - 1], totallen;
+ int di;
+ int excess;
+ Bool oddSide = FALSE;
+
+ totallen = 0;
+ if (angle >= 0) {
+ while (angle >= 90 * 64) {
+ angle -= 90 * 64;
+ totallen += sidelen;
+ oddSide = !oddSide;
+ }
+ } else {
+ while (angle < 0) {
+ angle += 90 * 64;
+ totallen -= sidelen;
+ oddSide = !oddSide;
+ }
+ }
+ if (oddSide)
+ angle = 90 * 64 - angle;
+
+ di = xAngleToDashIndex (angle);
+ excess = angle - dashIndexToXAngle (di);
+
+ len = map->map[di];
+ /*
+ * linearly interpolate between this point and the next
+ */
+ if (excess > 0) {
+ excesslen = (map->map[di + 1] - map->map[di]) *
+ ((double) excess) / dashXAngleStep;
+ len += excesslen;
+ }
+ if (oddSide)
+ totallen += (sidelen - len);
+ else
+ totallen += len;
+ return totallen;
+}
+
+/*
+ * len is along the arc, but may be more than one rotation
+ */
+
+static int
+lengthToAngle (
+ double len,
+ dashMap *map)
+{
+ double sidelen = map->map[DASH_MAP_SIZE - 1];
+ int angle, angleexcess;
+ Bool oddSide = FALSE;
+ int a0, a1, a;
+
+ angle = 0;
+ /*
+ * step around the ellipse, subtracting sidelens and
+ * adding 90 degrees. oddSide will tell if the
+ * map should be interpolated in reverse
+ */
+ if (len >= 0) {
+ if (sidelen == 0)
+ return 2 * FULLCIRCLE; /* infinity */
+ while (len >= sidelen) {
+ angle += 90 * 64;
+ len -= sidelen;
+ oddSide = !oddSide;
+ }
+ } else {
+ if (sidelen == 0)
+ return -2 * FULLCIRCLE; /* infinity */
+ while (len < 0) {
+ angle -= 90 * 64;
+ len += sidelen;
+ oddSide = !oddSide;
+ }
+ }
+ if (oddSide)
+ len = sidelen - len;
+ a0 = 0;
+ a1 = DASH_MAP_SIZE - 1;
+ /*
+ * binary search for the closest pre-computed length
+ */
+ while (a1 - a0 > 1) {
+ a = (a0 + a1) / 2;
+ if (len > map->map[a])
+ a0 = a;
+ else
+ a1 = a;
+ }
+ angleexcess = dashIndexToXAngle (a0);
+ /*
+ * linearly interpolate to the next point
+ */
+ angleexcess += (len - map->map[a0]) /
+ (map->map[a0+1] - map->map[a0]) * dashXAngleStep;
+ if (oddSide)
+ angle += (90 * 64) - angleexcess;
+ else
+ angle += angleexcess;
+ return angle;
+}
+
+/*
+ * compute the angle of an ellipse which cooresponds to
+ * the given path length. Note that the correct solution
+ * to this problem is an eliptic integral, we'll punt and
+ * approximate (it's only for dashes anyway). This
+ * approximation uses a polygon.
+ *
+ * The remaining portion of len is stored in *lenp -
+ * this will be negative if the arc extends beyond
+ * len and positive if len extends beyond the arc.
+ */
+
+static int
+computeAngleFromPath (
+ int startAngle,
+ int endAngle, /* normalized absolute angles in *64 degrees */
+ dashMap *map,
+ int *lenp,
+ int backwards)
+{
+ int a0, a1, a;
+ double len0;
+ int len;
+
+ a0 = startAngle;
+ a1 = endAngle;
+ len = *lenp;
+ if (backwards) {
+ /*
+ * flip the problem around to always be
+ * forwards
+ */
+ a0 = FULLCIRCLE - a0;
+ a1 = FULLCIRCLE - a1;
+ }
+ if (a1 < a0)
+ a1 += FULLCIRCLE;
+ len0 = angleToLength (a0, map);
+ a = lengthToAngle (len0 + len, map);
+ if (a > a1) {
+ a = a1;
+ len -= angleToLength (a1, map) - len0;
+ } else
+ len = 0;
+ if (backwards)
+ a = FULLCIRCLE - a;
+ *lenp = len;
+ return a;
+}
+
+/*
+ * scan convert wide arcs.
+ */
+
+/*
+ * draw zero width/height arcs
+ */
+
+static void
+drawZeroArc (
+ DrawablePtr pDraw,
+ GCPtr pGC,
+ xArc *tarc,
+ int lw,
+ miArcFacePtr left,
+ miArcFacePtr right)
+{
+ double x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0, w, h, x, y;
+ double xmax, ymax, xmin, ymin;
+ int a0, a1;
+ double a, startAngle, endAngle;
+ double l, lx, ly;
+
+ l = lw / 2.0;
+ a0 = tarc->angle1;
+ a1 = tarc->angle2;
+ if (a1 > FULLCIRCLE)
+ a1 = FULLCIRCLE;
+ else if (a1 < -FULLCIRCLE)
+ a1 = -FULLCIRCLE;
+ w = (double)tarc->width / 2.0;
+ h = (double)tarc->height / 2.0;
+ /*
+ * play in X coordinates right away
+ */
+ startAngle = - ((double) a0 / 64.0);
+ endAngle = - ((double) (a0 + a1) / 64.0);
+
+ xmax = -w;
+ xmin = w;
+ ymax = -h;
+ ymin = h;
+ a = startAngle;
+ for (;;)
+ {
+ x = w * miDcos(a);
+ y = h * miDsin(a);
+ if (a == startAngle)
+ {
+ x0 = x;
+ y0 = y;
+ }
+ if (a == endAngle)
+ {
+ x1 = x;
+ y1 = y;
+ }
+ if (x > xmax)
+ xmax = x;
+ if (x < xmin)
+ xmin = x;
+ if (y > ymax)
+ ymax = y;
+ if (y < ymin)
+ ymin = y;
+ if (a == endAngle)
+ break;
+ if (a1 < 0) /* clockwise */
+ {
+ if (floor (a / 90.0) == floor (endAngle / 90.0))
+ a = endAngle;
+ else
+ a = 90 * (floor (a/90.0) + 1);
+ }
+ else
+ {
+ if (ceil (a / 90.0) == ceil (endAngle / 90.0))
+ a = endAngle;
+ else
+ a = 90 * (ceil (a/90.0) - 1);
+ }
+ }
+ lx = ly = l;
+ if ((x1 - x0) + (y1 - y0) < 0)
+ lx = ly = -l;
+ if (h)
+ {
+ ly = 0.0;
+ lx = -lx;
+ }
+ else
+ lx = 0.0;
+ if (right)
+ {
+ right->center.x = x0;
+ right->center.y = y0;
+ right->clock.x = x0 - lx;
+ right->clock.y = y0 - ly;
+ right->counterClock.x = x0 + lx;
+ right->counterClock.y = y0 + ly;
+ }
+ if (left)
+ {
+ left->center.x = x1;
+ left->center.y = y1;
+ left->clock.x = x1 + lx;
+ left->clock.y = y1 + ly;
+ left->counterClock.x = x1 - lx;
+ left->counterClock.y = y1 - ly;
+ }
+
+ x0 = xmin;
+ x1 = xmax;
+ y0 = ymin;
+ y1 = ymax;
+ if (ymin != y1) {
+ xmin = -l;
+ xmax = l;
+ } else {
+ ymin = -l;
+ ymax = l;
+ }
+ if (xmax != xmin && ymax != ymin) {
+ int minx, maxx, miny, maxy;
+ xRectangle rect;
+
+ minx = ICEIL (xmin + w) + tarc->x;
+ maxx = ICEIL (xmax + w) + tarc->x;
+ miny = ICEIL (ymin + h) + tarc->y;
+ maxy = ICEIL (ymax + h) + tarc->y;
+ rect.x = minx;
+ rect.y = miny;
+ rect.width = maxx - minx;
+ rect.height = maxy - miny;
+ (*pGC->ops->PolyFillRect) (pDraw, pGC, 1, &rect);
+ }
+}
+
+/*
+ * this computes the ellipse y value associated with the
+ * bottom of the tail.
+ */
+
+static void
+tailEllipseY (
+ struct arc_def *def,
+ struct accelerators *acc)
+{
+ double t;
+
+ acc->tail_y = 0.0;
+ if (def->w == def->h)
+ return;
+ t = def->l * def->w;
+ if (def->w > def->h) {
+ if (t < acc->h2)
+ return;
+ } else {
+ if (t > acc->h2)
+ return;
+ }
+ t = 2.0 * def->h * t;
+ t = (CUBED_ROOT_4 * acc->h2 - cbrt(t * t)) / acc->h2mw2;
+ if (t > 0.0)
+ acc->tail_y = def->h / CUBED_ROOT_2 * sqrt(t);
+}
+
+/*
+ * inverse functions -- compute edge coordinates
+ * from the ellipse
+ */
+
+static double
+outerXfromXY (
+ double x,
+ double y,
+ struct arc_def *def,
+ struct accelerators *acc)
+{
+ return x + (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
+}
+
+static double
+outerYfromXY (
+ double x,
+ double y,
+ struct arc_def *def,
+ struct accelerators *acc)
+{
+ return y + (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
+}
+
+static double
+innerXfromXY (
+ double x,
+ double y,
+ struct arc_def *def,
+ struct accelerators *acc)
+{
+ return x - (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
+}
+
+static double
+innerYfromXY (
+ double x,
+ double y,
+ struct arc_def *def,
+ struct accelerators *acc)
+{
+ return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
+}
+
+static double
+innerYfromY (
+ double y,
+ struct arc_def *def,
+ struct accelerators *acc)
+{
+ double x;
+
+ x = (def->w / def->h) * sqrt (acc->h2 - y*y);
+
+ return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
+}
+
+static void
+computeLine (
+ double x1,
+ double y1,
+ double x2,
+ double y2,
+ struct line *line)
+{
+ if (y1 == y2)
+ line->valid = 0;
+ else {
+ line->m = (x1 - x2) / (y1 - y2);
+ line->b = x1 - y1 * line->m;
+ line->valid = 1;
+ }
+}
+
+/*
+ * compute various accelerators for an ellipse. These
+ * are simply values that are used repeatedly in
+ * the computations
+ */
+
+static void
+computeAcc (
+ xArc *tarc,
+ int lw,
+ struct arc_def *def,
+ struct accelerators *acc)
+{
+ def->w = ((double) tarc->width) / 2.0;
+ def->h = ((double) tarc->height) / 2.0;
+ def->l = ((double) lw) / 2.0;
+ acc->h2 = def->h * def->h;
+ acc->w2 = def->w * def->w;
+ acc->h4 = acc->h2 * acc->h2;
+ acc->w4 = acc->w2 * acc->w2;
+ acc->h2l = acc->h2 * def->l;
+ acc->w2l = acc->w2 * def->l;
+ acc->h2mw2 = acc->h2 - acc->w2;
+ acc->fromIntX = (tarc->width & 1) ? 0.5 : 0.0;
+ acc->fromIntY = (tarc->height & 1) ? 0.5 : 0.0;
+ acc->xorg = tarc->x + (tarc->width >> 1);
+ acc->yorgu = tarc->y + (tarc->height >> 1);
+ acc->yorgl = acc->yorgu + (tarc->height & 1);
+ tailEllipseY (def, acc);
+}
+
+/*
+ * compute y value bounds of various portions of the arc,
+ * the outer edge, the ellipse and the inner edge.
+ */
+
+static void
+computeBound (
+ struct arc_def *def,
+ struct arc_bound *bound,
+ struct accelerators *acc,
+ miArcFacePtr right,
+ miArcFacePtr left)
+{
+ double t;
+ double innerTaily;
+ double tail_y;
+ struct bound innerx, outerx;
+ struct bound ellipsex;
+
+ bound->ellipse.min = Dsin (def->a0) * def->h;
+ bound->ellipse.max = Dsin (def->a1) * def->h;
+ if (def->a0 == 45 && def->w == def->h)
+ ellipsex.min = bound->ellipse.min;
+ else
+ ellipsex.min = Dcos (def->a0) * def->w;
+ if (def->a1 == 45 && def->w == def->h)
+ ellipsex.max = bound->ellipse.max;
+ else
+ ellipsex.max = Dcos (def->a1) * def->w;
+ bound->outer.min = outerYfromXY (ellipsex.min, bound->ellipse.min, def, acc);
+ bound->outer.max = outerYfromXY (ellipsex.max, bound->ellipse.max, def, acc);
+ bound->inner.min = innerYfromXY (ellipsex.min, bound->ellipse.min, def, acc);
+ bound->inner.max = innerYfromXY (ellipsex.max, bound->ellipse.max, def, acc);
+
+ outerx.min = outerXfromXY (ellipsex.min, bound->ellipse.min, def, acc);
+ outerx.max = outerXfromXY (ellipsex.max, bound->ellipse.max, def, acc);
+ innerx.min = innerXfromXY (ellipsex.min, bound->ellipse.min, def, acc);
+ innerx.max = innerXfromXY (ellipsex.max, bound->ellipse.max, def, acc);
+
+ /*
+ * save the line end points for the
+ * cap code to use. Careful here, these are
+ * in cartesean coordinates (y increasing upwards)
+ * while the cap code uses inverted coordinates
+ * (y increasing downwards)
+ */
+
+ if (right) {
+ right->counterClock.y = bound->outer.min;
+ right->counterClock.x = outerx.min;
+ right->center.y = bound->ellipse.min;
+ right->center.x = ellipsex.min;
+ right->clock.y = bound->inner.min;
+ right->clock.x = innerx.min;
+ }
+
+ if (left) {
+ left->clock.y = bound->outer.max;
+ left->clock.x = outerx.max;
+ left->center.y = bound->ellipse.max;
+ left->center.x = ellipsex.max;
+ left->counterClock.y = bound->inner.max;
+ left->counterClock.x = innerx.max;
+ }
+
+ bound->left.min = bound->inner.max;
+ bound->left.max = bound->outer.max;
+ bound->right.min = bound->inner.min;
+ bound->right.max = bound->outer.min;
+
+ computeLine (innerx.min, bound->inner.min, outerx.min, bound->outer.min,
+ &acc->right);
+ computeLine (innerx.max, bound->inner.max, outerx.max, bound->outer.max,
+ &acc->left);
+
+ if (bound->inner.min > bound->inner.max) {
+ t = bound->inner.min;
+ bound->inner.min = bound->inner.max;
+ bound->inner.max = t;
+ }
+ tail_y = acc->tail_y;
+ if (tail_y > bound->ellipse.max)
+ tail_y = bound->ellipse.max;
+ else if (tail_y < bound->ellipse.min)
+ tail_y = bound->ellipse.min;
+ innerTaily = innerYfromY (tail_y, def, acc);
+ if (bound->inner.min > innerTaily)
+ bound->inner.min = innerTaily;
+ if (bound->inner.max < innerTaily)
+ bound->inner.max = innerTaily;
+ bound->inneri.min = ICEIL(bound->inner.min - acc->fromIntY);
+ bound->inneri.max = floor(bound->inner.max - acc->fromIntY);
+ bound->outeri.min = ICEIL(bound->outer.min - acc->fromIntY);
+ bound->outeri.max = floor(bound->outer.max - acc->fromIntY);
+}
+
+/*
+ * this section computes the x value of the span at y
+ * intersected with the specified face of the ellipse.
+ *
+ * this is the min/max X value over the set of normal
+ * lines to the entire ellipse, the equation of the
+ * normal lines is:
+ *
+ * ellipse_x h^2 h^2
+ * x = ------------ y + ellipse_x (1 - --- )
+ * ellipse_y w^2 w^2
+ *
+ * compute the derivative with-respect-to ellipse_y and solve
+ * for zero:
+ *
+ * (w^2 - h^2) ellipse_y^3 + h^4 y
+ * 0 = - ----------------------------------
+ * h w ellipse_y^2 sqrt (h^2 - ellipse_y^2)
+ *
+ * ( h^4 y )
+ * ellipse_y = ( ---------- ) ^ (1/3)
+ * ( (h^2 - w^2) )
+ *
+ * The other two solutions to the equation are imaginary.
+ *
+ * This gives the position on the ellipse which generates
+ * the normal with the largest/smallest x intersection point.
+ *
+ * Now compute the second derivative to check whether
+ * the intersection is a minimum or maximum:
+ *
+ * h (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2))
+ * - -------------------------------------------
+ * w y0^3 (sqrt (h^2 - y^2)) ^ 3
+ *
+ * as we only care about the sign,
+ *
+ * - (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2))
+ *
+ * or (to use accelerators),
+ *
+ * y0^3 (h^2 - w^2) - h^2 y (3y0^2 - 2h^2)
+ *
+ */
+
+/*
+ * computes the position on the ellipse whose normal line
+ * intersects the given scan line maximally
+ */
+
+static double
+hookEllipseY (
+ double scan_y,
+ struct arc_bound *bound,
+ struct accelerators *acc,
+ int left)
+{
+ double ret;
+
+ if (acc->h2mw2 == 0) {
+ if ( (scan_y > 0 && !left) || (scan_y < 0 && left) )
+ return bound->ellipse.min;
+ return bound->ellipse.max;
+ }
+ ret = (acc->h4 * scan_y) / (acc->h2mw2);
+ if (ret >= 0)
+ return cbrt (ret);
+ else
+ return -cbrt (-ret);
+}
+
+/*
+ * computes the X value of the intersection of the
+ * given scan line with the right side of the lower hook
+ */
+
+static double
+hookX (
+ double scan_y,
+ struct arc_def *def,
+ struct arc_bound *bound,
+ struct accelerators *acc,
+ int left)
+{
+ double ellipse_y, x;
+ double maxMin;
+
+ if (def->w != def->h) {
+ ellipse_y = hookEllipseY (scan_y, bound, acc, left);
+ if (boundedLe (ellipse_y, bound->ellipse)) {
+ /*
+ * compute the value of the second
+ * derivative
+ */
+ maxMin = ellipse_y*ellipse_y*ellipse_y * acc->h2mw2 -
+ acc->h2 * scan_y * (3 * ellipse_y*ellipse_y - 2*acc->h2);
+ if ((left && maxMin > 0) || (!left && maxMin < 0)) {
+ if (ellipse_y == 0)
+ return def->w + left ? -def->l : def->l;
+ x = (acc->h2 * scan_y - ellipse_y * acc->h2mw2) *
+ sqrt (acc->h2 - ellipse_y * ellipse_y) /
+ (def->h * def->w * ellipse_y);
+ return x;
+ }
+ }
+ }
+ if (left) {
+ if (acc->left.valid && boundedLe (scan_y, bound->left)) {
+ x = intersectLine (scan_y, acc->left);
+ } else {
+ if (acc->right.valid)
+ x = intersectLine (scan_y, acc->right);
+ else
+ x = def->w - def->l;
+ }
+ } else {
+ if (acc->right.valid && boundedLe (scan_y, bound->right)) {
+ x = intersectLine (scan_y, acc->right);
+ } else {
+ if (acc->left.valid)
+ x = intersectLine (scan_y, acc->left);
+ else
+ x = def->w - def->l;
+ }
+ }
+ return x;
+}
+
+/*
+ * generate the set of spans with
+ * the given y coordinate
+ */
+
+static void
+arcSpan (
+ int y,
+ int lx,
+ int lw,
+ int rx,
+ int rw,
+ struct arc_def *def,
+ struct arc_bound *bounds,
+ struct accelerators *acc,
+ int mask)
+{
+ int linx, loutx, rinx, routx;
+ double x, altx;
+
+ if (boundedLe (y, bounds->inneri)) {
+ linx = -(lx + lw);
+ rinx = rx;
+ } else {
+ /*
+ * intersection with left face
+ */
+ x = hookX (y + acc->fromIntY, def, bounds, acc, 1);
+ if (acc->right.valid &&
+ boundedLe (y + acc->fromIntY, bounds->right))
+ {
+ altx = intersectLine (y + acc->fromIntY, acc->right);
+ if (altx < x)
+ x = altx;
+ }
+ linx = -ICEIL(acc->fromIntX - x);
+ rinx = ICEIL(acc->fromIntX + x);
+ }
+ if (boundedLe (y, bounds->outeri)) {
+ loutx = -lx;
+ routx = rx + rw;
+ } else {
+ /*
+ * intersection with right face
+ */
+ x = hookX (y + acc->fromIntY, def, bounds, acc, 0);
+ if (acc->left.valid &&
+ boundedLe (y + acc->fromIntY, bounds->left))
+ {
+ altx = x;
+ x = intersectLine (y + acc->fromIntY, acc->left);
+ if (x < altx)
+ x = altx;
+ }
+ loutx = -ICEIL(acc->fromIntX - x);
+ routx = ICEIL(acc->fromIntX + x);
+ }
+ if (routx > rinx) {
+ if (mask & 1)
+ newFinalSpan (acc->yorgu - y,
+ acc->xorg + rinx, acc->xorg + routx);
+ if (mask & 8)
+ newFinalSpan (acc->yorgl + y,
+ acc->xorg + rinx, acc->xorg + routx);
+ }
+ if (loutx > linx) {
+ if (mask & 2)
+ newFinalSpan (acc->yorgu - y,
+ acc->xorg - loutx, acc->xorg - linx);
+ if (mask & 4)
+ newFinalSpan (acc->yorgl + y,
+ acc->xorg - loutx, acc->xorg - linx);
+ }
+}
+
+static void
+arcSpan0 (
+ int lx,
+ int lw,
+ int rx,
+ int rw,
+ struct arc_def *def,
+ struct arc_bound *bounds,
+ struct accelerators *acc,
+ int mask)
+{
+ double x;
+
+ if (boundedLe (0, bounds->inneri) &&
+ acc->left.valid && boundedLe (0, bounds->left) &&
+ acc->left.b > 0)
+ {
+ x = def->w - def->l;
+ if (acc->left.b < x)
+ x = acc->left.b;
+ lw = ICEIL(acc->fromIntX - x) - lx;
+ rw += rx;
+ rx = ICEIL(acc->fromIntX + x);
+ rw -= rx;
+ }
+ arcSpan (0, lx, lw, rx, rw, def, bounds, acc, mask);
+}
+
+static void
+tailSpan (
+ int y,
+ int lw,
+ int rw,
+ struct arc_def *def,
+ struct arc_bound *bounds,
+ struct accelerators *acc,
+ int mask)
+{
+ double yy, xalt, x, lx, rx;
+ int n;
+
+ if (boundedLe(y, bounds->outeri))
+ arcSpan (y, 0, lw, -rw, rw, def, bounds, acc, mask);
+ else if (def->w != def->h) {
+ yy = y + acc->fromIntY;
+ x = tailX(yy, def, bounds, acc);
+ if (yy == 0.0 && x == -rw - acc->fromIntX)
+ return;
+ if (acc->right.valid && boundedLe (yy, bounds->right)) {
+ rx = x;
+ lx = -x;
+ xalt = intersectLine (yy, acc->right);
+ if (xalt >= -rw - acc->fromIntX && xalt <= rx)
+ rx = xalt;
+ n = ICEIL(acc->fromIntX + lx);
+ if (lw > n) {
+ if (mask & 2)
+ newFinalSpan (acc->yorgu - y,
+ acc->xorg + n, acc->xorg + lw);
+ if (mask & 4)
+ newFinalSpan (acc->yorgl + y,
+ acc->xorg + n, acc->xorg + lw);
+ }
+ n = ICEIL(acc->fromIntX + rx);
+ if (n > -rw) {
+ if (mask & 1)
+ newFinalSpan (acc->yorgu - y,
+ acc->xorg - rw, acc->xorg + n);
+ if (mask & 8)
+ newFinalSpan (acc->yorgl + y,
+ acc->xorg - rw, acc->xorg + n);
+ }
+ }
+ arcSpan (y,
+ ICEIL(acc->fromIntX - x), 0,
+ ICEIL(acc->fromIntX + x), 0,
+ def, bounds, acc, mask);
+ }
+}
+
+/*
+ * create whole arcs out of pieces. This code is
+ * very bad.
+ */
+
+static struct finalSpan **finalSpans = NULL;
+static int finalMiny = 0, finalMaxy = -1;
+static int finalSize = 0;
+
+static int nspans = 0; /* total spans, not just y coords */
+
+struct finalSpan {
+ struct finalSpan *next;
+ int min, max; /* x values */
+};
+
+static struct finalSpan *freeFinalSpans, *tmpFinalSpan;
+
+# define allocFinalSpan() (freeFinalSpans ?\
+ ((tmpFinalSpan = freeFinalSpans), \
+ (freeFinalSpans = freeFinalSpans->next), \
+ (tmpFinalSpan->next = 0), \
+ tmpFinalSpan) : \
+ realAllocSpan ())
+
+# define SPAN_CHUNK_SIZE 128
+
+struct finalSpanChunk {
+ struct finalSpan data[SPAN_CHUNK_SIZE];
+ struct finalSpanChunk *next;
+};
+
+static struct finalSpanChunk *chunks;
+
+struct finalSpan *
+realAllocSpan ()
+{
+ register struct finalSpanChunk *newChunk;
+ register struct finalSpan *span;
+ register int i;
+
+ newChunk = (struct finalSpanChunk *) xalloc (sizeof (struct finalSpanChunk));
+ if (!newChunk)
+ return (struct finalSpan *) NULL;
+ newChunk->next = chunks;
+ chunks = newChunk;
+ freeFinalSpans = span = newChunk->data + 1;
+ for (i = 1; i < SPAN_CHUNK_SIZE-1; i++) {
+ span->next = span+1;
+ span++;
+ }
+ span->next = 0;
+ span = newChunk->data;
+ span->next = 0;
+ return span;
+}
+
+static void
+disposeFinalSpans (void)
+{
+ struct finalSpanChunk *chunk, *next;
+
+ for (chunk = chunks; chunk; chunk = next) {
+ next = chunk->next;
+ xfree (chunk);
+ }
+ chunks = 0;
+ freeFinalSpans = 0;
+ xfree(finalSpans);
+ finalSpans = 0;
+}
+
+static void
+fillSpans (
+ DrawablePtr pDrawable,
+ GCPtr pGC)
+{
+ register struct finalSpan *span;
+ register DDXPointPtr xSpan;
+ register int *xWidth;
+ register int i;
+ register struct finalSpan **f;
+ register int spany;
+ DDXPointPtr xSpans;
+ int *xWidths;
+
+ if (nspans == 0)
+ return;
+ xSpan = xSpans = (DDXPointPtr) ALLOCATE_LOCAL (nspans * sizeof (DDXPointRec));
+ xWidth = xWidths = (int *) ALLOCATE_LOCAL (nspans * sizeof (int));
+ if (xSpans && xWidths)
+ {
+ i = 0;
+ f = finalSpans;
+ for (spany = finalMiny; spany <= finalMaxy; spany++, f++) {
+ for (span = *f; span; span=span->next) {
+ if (span->max <= span->min)
+ continue;
+ xSpan->x = span->min;
+ xSpan->y = spany;
+ ++xSpan;
+ *xWidth++ = span->max - span->min;
+ ++i;
+ }
+ }
+ (*pGC->ops->FillSpans) (pDrawable, pGC, i, xSpans, xWidths, TRUE);
+ }
+ disposeFinalSpans ();
+ if (xSpans)
+ DEALLOCATE_LOCAL (xSpans);
+ if (xWidths)
+ DEALLOCATE_LOCAL (xWidths);
+ finalMiny = 0;
+ finalMaxy = -1;
+ finalSize = 0;
+ nspans = 0;
+}
+
+# define SPAN_REALLOC 100
+
+# define findSpan(y) ((finalMiny <= (y) && (y) <= finalMaxy) ? \
+ &finalSpans[(y) - finalMiny] : \
+ realFindSpan (y))
+
+static struct finalSpan **
+realFindSpan (int y)
+{
+ struct finalSpan **newSpans;
+ int newSize, newMiny, newMaxy;
+ int change;
+ int i;
+
+ if (y < finalMiny || y > finalMaxy) {
+ if (!finalSize) {
+ finalMiny = y;
+ finalMaxy = y - 1;
+ }
+ if (y < finalMiny)
+ change = finalMiny - y;
+ else
+ change = y - finalMaxy;
+ if (change >= SPAN_REALLOC)
+ change += SPAN_REALLOC;
+ else
+ change = SPAN_REALLOC;
+ newSize = finalSize + change;
+ newSpans = (struct finalSpan **) xalloc
+ (newSize * sizeof (struct finalSpan *));
+ if (!newSpans)
+ return (struct finalSpan **)NULL;
+ newMiny = finalMiny;
+ newMaxy = finalMaxy;
+ if (y < finalMiny)
+ newMiny = finalMiny - change;
+ else
+ newMaxy = finalMaxy + change;
+ if (finalSpans) {
+ memmove(((char *) newSpans) + (finalMiny-newMiny) * sizeof (struct finalSpan *),
+ (char *) finalSpans,
+ finalSize * sizeof (struct finalSpan *));
+ xfree (finalSpans);
+ }
+ if ((i = finalMiny - newMiny) > 0)
+ bzero ((char *)newSpans, i * sizeof (struct finalSpan *));
+ if ((i = newMaxy - finalMaxy) > 0)
+ bzero ((char *)(newSpans + newSize - i),
+ i * sizeof (struct finalSpan *));
+ finalSpans = newSpans;
+ finalMaxy = newMaxy;
+ finalMiny = newMiny;
+ finalSize = newSize;
+ }
+ return &finalSpans[y - finalMiny];
+}
+
+static void
+newFinalSpan (
+ int y,
+ register int xmin,
+ register int xmax)
+{
+ register struct finalSpan *x;
+ register struct finalSpan **f;
+ struct finalSpan *oldx;
+ struct finalSpan *prev;
+
+ f = findSpan (y);
+ if (!f)
+ return;
+ oldx = 0;
+ for (;;) {
+ prev = 0;
+ for (x = *f; x; x=x->next) {
+ if (x == oldx) {
+ prev = x;
+ continue;
+ }
+ if (x->min <= xmax && xmin <= x->max) {
+ if (oldx) {
+ oldx->min = min (x->min, xmin);
+ oldx->max = max (x->max, xmax);
+ if (prev)
+ prev->next = x->next;
+ else
+ *f = x->next;
+ --nspans;
+ } else {
+ x->min = min (x->min, xmin);
+ x->max = max (x->max, xmax);
+ oldx = x;
+ }
+ xmin = oldx->min;
+ xmax = oldx->max;
+ break;
+ }
+ prev = x;
+ }
+ if (!x)
+ break;
+ }
+ if (!oldx) {
+ x = allocFinalSpan ();
+ if (x)
+ {
+ x->min = xmin;
+ x->max = xmax;
+ x->next = *f;
+ *f = x;
+ ++nspans;
+ }
+ }
+}
+
+static void
+mirrorSppPoint (
+ int quadrant,
+ SppPointPtr sppPoint)
+{
+ switch (quadrant) {
+ case 0:
+ break;
+ case 1:
+ sppPoint->x = -sppPoint->x;
+ break;
+ case 2:
+ sppPoint->x = -sppPoint->x;
+ sppPoint->y = -sppPoint->y;
+ break;
+ case 3:
+ sppPoint->y = -sppPoint->y;
+ break;
+ }
+ /*
+ * and translate to X coordinate system
+ */
+ sppPoint->y = -sppPoint->y;
+}
+
+/*
+ * split an arc into pieces which are scan-converted
+ * in the first-quadrant and mirrored into position.
+ * This is necessary as the scan-conversion code can
+ * only deal with arcs completely contained in the
+ * first quadrant.
+ */
+
+static void
+drawArc (
+ xArc *tarc,
+ int l,
+ int a0,
+ int a1,
+ miArcFacePtr right,
+ miArcFacePtr left) /* save end line points */
+{
+ struct arc_def def;
+ struct accelerators acc;
+ int startq, endq, curq;
+ int rightq, leftq = 0, righta = 0, lefta = 0;
+ miArcFacePtr passRight, passLeft;
+ int q0 = 0, q1 = 0, mask;
+ struct band {
+ int a0, a1;
+ int mask;
+ } band[5], sweep[20];
+ int bandno, sweepno;
+ int i, j;
+ int flipRight = 0, flipLeft = 0;
+ int copyEnd = 0;
+ miArcSpanData *spdata;
+ Bool mustFree;
+
+ spdata = miComputeWideEllipse(l, tarc, &mustFree);
+ if (!spdata)
+ return;
+
+ if (a1 < a0)
+ a1 += 360 * 64;
+ startq = a0 / (90 * 64);
+ if (a0 == a1)
+ endq = startq;
+ else
+ endq = (a1-1) / (90 * 64);
+ bandno = 0;
+ curq = startq;
+ rightq = -1;
+ for (;;) {
+ switch (curq) {
+ case 0:
+ if (a0 > 90 * 64)
+ q0 = 0;
+ else
+ q0 = a0;
+ if (a1 < 360 * 64)
+ q1 = min (a1, 90 * 64);
+ else
+ q1 = 90 * 64;
+ if (curq == startq && a0 == q0 && rightq < 0) {
+ righta = q0;
+ rightq = curq;
+ }
+ if (curq == endq && a1 == q1) {
+ lefta = q1;
+ leftq = curq;
+ }
+ break;
+ case 1:
+ if (a1 < 90 * 64)
+ q0 = 0;
+ else
+ q0 = 180 * 64 - min (a1, 180 * 64);
+ if (a0 > 180 * 64)
+ q1 = 90 * 64;
+ else
+ q1 = 180 * 64 - max (a0, 90 * 64);
+ if (curq == startq && 180 * 64 - a0 == q1) {
+ righta = q1;
+ rightq = curq;
+ }
+ if (curq == endq && 180 * 64 - a1 == q0) {
+ lefta = q0;
+ leftq = curq;
+ }
+ break;
+ case 2:
+ if (a0 > 270 * 64)
+ q0 = 0;
+ else
+ q0 = max (a0, 180 * 64) - 180 * 64;
+ if (a1 < 180 * 64)
+ q1 = 90 * 64;
+ else
+ q1 = min (a1, 270 * 64) - 180 * 64;
+ if (curq == startq && a0 - 180*64 == q0) {
+ righta = q0;
+ rightq = curq;
+ }
+ if (curq == endq && a1 - 180 * 64 == q1) {
+ lefta = q1;
+ leftq = curq;
+ }
+ break;
+ case 3:
+ if (a1 < 270 * 64)
+ q0 = 0;
+ else
+ q0 = 360 * 64 - min (a1, 360 * 64);
+ q1 = 360 * 64 - max (a0, 270 * 64);
+ if (curq == startq && 360 * 64 - a0 == q1) {
+ righta = q1;
+ rightq = curq;
+ }
+ if (curq == endq && 360 * 64 - a1 == q0) {
+ lefta = q0;
+ leftq = curq;
+ }
+ break;
+ }
+ band[bandno].a0 = q0;
+ band[bandno].a1 = q1;
+ band[bandno].mask = 1 << curq;
+ bandno++;
+ if (curq == endq)
+ break;
+ curq++;
+ if (curq == 4) {
+ a0 = 0;
+ a1 -= 360 * 64;
+ curq = 0;
+ endq -= 4;
+ }
+ }
+ sweepno = 0;
+ for (;;) {
+ q0 = 90 * 64;
+ mask = 0;
+ /*
+ * find left-most point
+ */
+ for (i = 0; i < bandno; i++)
+ if (band[i].a0 <= q0) {
+ q0 = band[i].a0;
+ q1 = band[i].a1;
+ mask = band[i].mask;
+ }
+ if (!mask)
+ break;
+ /*
+ * locate next point of change
+ */
+ for (i = 0; i < bandno; i++)
+ if (!(mask & band[i].mask)) {
+ if (band[i].a0 == q0) {
+ if (band[i].a1 < q1)
+ q1 = band[i].a1;
+ mask |= band[i].mask;
+ } else if (band[i].a0 < q1)
+ q1 = band[i].a0;
+ }
+ /*
+ * create a new sweep
+ */
+ sweep[sweepno].a0 = q0;
+ sweep[sweepno].a1 = q1;
+ sweep[sweepno].mask = mask;
+ sweepno++;
+ /*
+ * subtract the sweep from the affected bands
+ */
+ for (i = 0; i < bandno; i++)
+ if (band[i].a0 == q0) {
+ band[i].a0 = q1;
+ /*
+ * check if this band is empty
+ */
+ if (band[i].a0 == band[i].a1)
+ band[i].a1 = band[i].a0 = 90 * 64 + 1;
+ }
+ }
+ computeAcc (tarc, l, &def, &acc);
+ for (j = 0; j < sweepno; j++) {
+ mask = sweep[j].mask;
+ passRight = passLeft = 0;
+ if (mask & (1 << rightq)) {
+ if (sweep[j].a0 == righta)
+ passRight = right;
+ else if (sweep[j].a1 == righta) {
+ passLeft = right;
+ flipRight = 1;
+ }
+ }
+ if (mask & (1 << leftq)) {
+ if (sweep[j].a1 == lefta)
+ {
+ if (passLeft)
+ copyEnd = 1;
+ passLeft = left;
+ }
+ else if (sweep[j].a0 == lefta) {
+ if (passRight)
+ copyEnd = 1;
+ passRight = left;
+ flipLeft = 1;
+ }
+ }
+ drawQuadrant (&def, &acc, sweep[j].a0, sweep[j].a1, mask,
+ passRight, passLeft, spdata);
+ }
+ /*
+ * when copyEnd is set, both ends of the arc were computed
+ * at the same time; drawQuadrant only takes one end though,
+ * so the left end will be the only one holding the data. Copy
+ * it from there.
+ */
+ if (copyEnd)
+ *right = *left;
+ /*
+ * mirror the coordinates generated for the
+ * faces of the arc
+ */
+ if (right) {
+ mirrorSppPoint (rightq, &right->clock);
+ mirrorSppPoint (rightq, &right->center);
+ mirrorSppPoint (rightq, &right->counterClock);
+ if (flipRight) {
+ SppPointRec temp;
+
+ temp = right->clock;
+ right->clock = right->counterClock;
+ right->counterClock = temp;
+ }
+ }
+ if (left) {
+ mirrorSppPoint (leftq, &left->counterClock);
+ mirrorSppPoint (leftq, &left->center);
+ mirrorSppPoint (leftq, &left->clock);
+ if (flipLeft) {
+ SppPointRec temp;
+
+ temp = left->clock;
+ left->clock = left->counterClock;
+ left->counterClock = temp;
+ }
+ }
+ if (mustFree)
+ xfree(spdata);
+}
+
+static void
+drawQuadrant (
+ struct arc_def *def,
+ struct accelerators *acc,
+ int a0,
+ int a1,
+ int mask,
+ miArcFacePtr right,
+ miArcFacePtr left,
+ miArcSpanData *spdata)
+{
+ struct arc_bound bound;
+ double yy, x, xalt;
+ int y, miny, maxy;
+ int n;
+ miArcSpan *span;
+
+ def->a0 = ((double) a0) / 64.0;
+ def->a1 = ((double) a1) / 64.0;
+ computeBound (def, &bound, acc, right, left);
+ yy = bound.inner.min;
+ if (bound.outer.min < yy)
+ yy = bound.outer.min;
+ miny = ICEIL(yy - acc->fromIntY);
+ yy = bound.inner.max;
+ if (bound.outer.max > yy)
+ yy = bound.outer.max;
+ maxy = floor(yy - acc->fromIntY);
+ y = spdata->k;
+ span = spdata->spans;
+ if (spdata->top)
+ {
+ if (a1 == 90 * 64 && (mask & 1))
+ newFinalSpan (acc->yorgu - y - 1, acc->xorg, acc->xorg + 1);
+ span++;
+ }
+ for (n = spdata->count1; --n >= 0; )
+ {
+ if (y < miny)
+ return;
+ if (y <= maxy) {
+ arcSpan (y,
+ span->lx, -span->lx, 0, span->lx + span->lw,
+ def, &bound, acc, mask);
+ if (span->rw + span->rx)
+ tailSpan (y, -span->rw, -span->rx, def, &bound, acc, mask);
+ }
+ y--;
+ span++;
+ }
+ if (y < miny)
+ return;
+ if (spdata->hole)
+ {
+ if (y <= maxy)
+ arcSpan (y, 0, 0, 0, 1, def, &bound, acc, mask & 0xc);
+ }
+ for (n = spdata->count2; --n >= 0; )
+ {
+ if (y < miny)
+ return;
+ if (y <= maxy)
+ arcSpan (y, span->lx, span->lw, span->rx, span->rw,
+ def, &bound, acc, mask);
+ y--;
+ span++;
+ }
+ if (spdata->bot && miny <= y && y <= maxy)
+ {
+ n = mask;
+ if (y == miny)
+ n &= 0xc;
+ if (span->rw <= 0) {
+ arcSpan0 (span->lx, -span->lx, 0, span->lx + span->lw,
+ def, &bound, acc, n);
+ if (span->rw + span->rx)
+ tailSpan (y, -span->rw, -span->rx, def, &bound, acc, n);
+ }
+ else
+ arcSpan0 (span->lx, span->lw, span->rx, span->rw,
+ def, &bound, acc, n);
+ y--;
+ }
+ while (y >= miny) {
+ yy = y + acc->fromIntY;
+ if (def->w == def->h) {
+ xalt = def->w - def->l;
+ x = -sqrt(xalt * xalt - yy * yy);
+ } else {
+ x = tailX(yy, def, &bound, acc);
+ if (acc->left.valid && boundedLe (yy, bound.left)) {
+ xalt = intersectLine (yy, acc->left);
+ if (xalt < x)
+ x = xalt;
+ }
+ if (acc->right.valid && boundedLe (yy, bound.right)) {
+ xalt = intersectLine (yy, acc->right);
+ if (xalt < x)
+ x = xalt;
+ }
+ }
+ arcSpan (y,
+ ICEIL(acc->fromIntX - x), 0,
+ ICEIL(acc->fromIntX + x), 0,
+ def, &bound, acc, mask);
+ y--;
+ }
+}
diff --git a/xserver/mi/mibank.c b/xserver/mi/mibank.c
new file mode 100644
index 000000000..32e963fab
--- /dev/null
+++ b/xserver/mi/mibank.c
@@ -0,0 +1,2573 @@
+/*
+ * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
+ *
+ * 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 Marc Aurele La France not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Marc Aurele La France makes no representations
+ * about the suitability of this software for any purpose. It is provided
+ * "as-is" without express or implied warranty.
+ *
+ * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
+ * EVENT SHALL MARC AURELE LA FRANCE 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.
+ */
+
+/*
+ * Copyright 1990,91,92,93 by Thomas Roell, Germany.
+ * Copyright 1991,92,93 by SGCS (Snitily Graphics Consulting Services), USA.
+ *
+ * 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 Thomas Roell nor
+ * SGCS be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission.
+ * Thomas Roell nor SGCS makes no representations about the suitability
+ * of this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ *
+ * THOMAS ROELL AND SGCS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR SGCS 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.
+ */
+
+
+/*
+ * This thing originated from an idea of Edwin Goei and his bank switching
+ * code for the DEC TX board.
+ */
+
+/*
+ * Heavily modified for the XFree86 Project to turn this into an mi wrapper.
+ * --- Marc Aurele La France (tsi@xfree86.org)
+ */
+
+/*
+ * "Heavily modified", indeed! By the time this is finalized, there probably
+ * won't be much left of Roell's code...
+ *
+ * Miscellaneous notes:
+ * - Pixels with imbedded bank boundaries are required to be off-screen. There
+ * >might< be a way to fool the underlying framebuffer into dealing with
+ * partial pixels.
+ * - Plans to generalise this to do (hardware) colour plane switching have been
+ * dropped due to colour flashing concerns.
+ *
+ * TODO:
+ * - Allow miModifyBanking() to change BankSize and nBankDepth.
+ * - Re-instate shared and double banking for framebuffers whose pixmap formats
+ * don't describe how the server "sees" the screen.
+ * - Remove remaining assumptions that a pixmap's devPrivate field points
+ * directly to its pixel data.
+ */
+
+/* #define NO_ALLOCA 1 */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "servermd.h"
+#include "gcstruct.h"
+#include "pixmapstr.h"
+#include "scrnintstr.h"
+#include "windowstr.h"
+#include "mi.h"
+#include "mibank.h"
+
+#define BANK_SINGLE 0
+#define BANK_SHARED 1
+#define BANK_DOUBLE 2
+#define BANK_NOBANK 3
+
+typedef struct _miBankScreen
+{
+ miBankInfoRec BankInfo;
+ unsigned int nBankBPP;
+ unsigned int type;
+
+ unsigned long nBitsPerBank;
+ unsigned long nBitsPerScanline;
+ unsigned long nPixelsPerScanlinePadUnit;
+
+ PixmapPtr pScreenPixmap;
+ PixmapPtr pBankPixmap;
+ GCPtr pBankGC;
+
+ int nBanks, maxRects;
+ RegionPtr *pBanks;
+
+ pointer pbits;
+
+ /*
+ * Screen Wrappers
+ */
+ CreateScreenResourcesProcPtr CreateScreenResources;
+ ModifyPixmapHeaderProcPtr ModifyPixmapHeader;
+ CloseScreenProcPtr CloseScreen;
+ GetImageProcPtr GetImage;
+ GetSpansProcPtr GetSpans;
+ CreateGCProcPtr CreateGC;
+ PaintWindowBackgroundProcPtr PaintWindowBackground;
+ PaintWindowBorderProcPtr PaintWindowBorder;
+ CopyWindowProcPtr CopyWindow;
+ BSFuncRec BackingStoreFuncs;
+} miBankScreenRec, *miBankScreenPtr;
+
+typedef struct _miBankGC
+{
+ GCOps *wrappedOps, *unwrappedOps;
+ GCFuncs *wrappedFuncs, *unwrappedFuncs;
+
+ Bool fastCopy, fastPlane;
+
+ RegionPtr pBankedClips[1];
+} miBankGCRec, *miBankGCPtr;
+
+typedef struct _miBankQueue
+{
+ Bool fastBlit;
+ unsigned short srcBankNo;
+ unsigned short dstBankNo;
+ short x;
+ short y;
+ short w;
+ short h;
+} miBankQueue;
+
+/*
+ * CAVEAT: This banking scheme requires that the DDX store Pixmap data in the
+ * server's address space.
+ */
+
+#define ModifyPixmap(_pPix, _width, _devKind, _pbits) \
+ (*pScreen->ModifyPixmapHeader)((_pPix), \
+ (_width), -1, -1, -1, (_devKind), (_pbits))
+
+#define SET_SINGLE_BANK(_pPix, _width, _devKind, _no) \
+ ModifyPixmap(_pPix, _width, _devKind, \
+ (char *)pScreenPriv->BankInfo.pBankA + \
+ (*pScreenPriv->BankInfo.SetSourceAndDestinationBanks)(pScreen, (_no)) - \
+ (pScreenPriv->BankInfo.BankSize * (_no)))
+
+#define SET_SOURCE_BANK(_pPix, _width, _devKind, _no) \
+ ModifyPixmap(_pPix, _width, _devKind, \
+ (char *)pScreenPriv->BankInfo.pBankA + \
+ (*pScreenPriv->BankInfo.SetSourceBank)(pScreen, (_no)) - \
+ (pScreenPriv->BankInfo.BankSize * (_no)))
+
+#define SET_DESTINATION_BANK(_pPix, _width, _devKind, _no) \
+ ModifyPixmap(_pPix, _width, _devKind, \
+ (char *)pScreenPriv->BankInfo.pBankB + \
+ (*pScreenPriv->BankInfo.SetDestinationBank)(pScreen, (_no)) - \
+ (pScreenPriv->BankInfo.BankSize * (_no)))
+
+#define ALLOCATE_LOCAL_ARRAY(atype, ntype) \
+ (atype *)ALLOCATE_LOCAL((ntype) * sizeof(atype))
+
+static int miBankScreenIndex;
+static int miBankGCIndex;
+static unsigned long miBankGeneration = 0;
+
+#define BANK_SCRPRIVLVAL pScreen->devPrivates[miBankScreenIndex].ptr
+
+#define BANK_SCRPRIVATE ((miBankScreenPtr)(BANK_SCRPRIVLVAL))
+
+#define BANK_GCPRIVLVAL(pGC) (pGC)->devPrivates[miBankGCIndex].ptr
+
+#define BANK_GCPRIVATE(pGC) ((miBankGCPtr)(BANK_GCPRIVLVAL(pGC)))
+
+#define PIXMAP_STATUS(_pPix) \
+ pointer pbits = (_pPix)->devPrivate.ptr
+
+#define PIXMAP_SAVE(_pPix) \
+ PIXMAP_STATUS(_pPix); \
+ if (pbits == (pointer)pScreenPriv) \
+ (_pPix)->devPrivate.ptr = pScreenPriv->pbits
+
+#define PIXMAP_RESTORE(_pPix) \
+ (_pPix)->devPrivate.ptr = pbits
+
+#define BANK_SAVE \
+ int width = pScreenPriv->pBankPixmap->drawable.width; \
+ int devKind = pScreenPriv->pBankPixmap->devKind; \
+ PIXMAP_SAVE(pScreenPriv->pBankPixmap)
+
+#define BANK_RESTORE \
+ pScreenPriv->pBankPixmap->drawable.width = width; \
+ pScreenPriv->pBankPixmap->devKind = devKind; \
+ PIXMAP_RESTORE(pScreenPriv->pBankPixmap)
+
+#define SCREEN_STATUS \
+ PIXMAP_STATUS(pScreenPriv->pScreenPixmap)
+
+#define SCREEN_SAVE \
+ PIXMAP_SAVE(pScreenPriv->pScreenPixmap)
+
+#define SCREEN_RESTORE \
+ PIXMAP_RESTORE(pScreenPriv->pScreenPixmap)
+
+#define SCREEN_INIT \
+ miBankScreenPtr pScreenPriv = BANK_SCRPRIVATE
+
+#define SCREEN_UNWRAP(field) \
+ pScreen->field = pScreenPriv->field
+
+#define SCREEN_WRAP(field, wrapper) \
+ pScreenPriv->field = pScreen->field; \
+ pScreen->field = wrapper
+
+#define GC_INIT(pGC) \
+ miBankGCPtr pGCPriv = BANK_GCPRIVATE(pGC)
+
+#define GC_UNWRAP(pGC) \
+ pGCPriv->unwrappedOps = (pGC)->ops; \
+ pGCPriv->unwrappedFuncs = (pGC)->funcs; \
+ (pGC)->ops = pGCPriv->wrappedOps; \
+ (pGC)->funcs = pGCPriv->wrappedFuncs
+
+#define GC_WRAP(pGC) \
+ pGCPriv->wrappedOps = (pGC)->ops; \
+ pGCPriv->wrappedFuncs = (pGC)->funcs; \
+ (pGC)->ops = pGCPriv->unwrappedOps; \
+ (pGC)->funcs = pGCPriv->unwrappedFuncs
+
+#define IS_BANKED(pDrawable) \
+ ((pbits == (pointer)pScreenPriv) && \
+ (((DrawablePtr)(pDrawable))->type == DRAWABLE_WINDOW))
+
+#define CLIP_SAVE \
+ RegionPtr pOrigCompositeClip = pGC->pCompositeClip
+
+#define CLIP_RESTORE \
+ pGC->pCompositeClip = pOrigCompositeClip
+
+#define GCOP_INIT \
+ ScreenPtr pScreen = pGC->pScreen; \
+ SCREEN_INIT; \
+ GC_INIT(pGC)
+
+#define GCOP_UNWRAP \
+ GC_UNWRAP(pGC)
+
+#define GCOP_WRAP \
+ GC_WRAP(pGC)
+
+#define GCOP_TOP_PART \
+ for (i = 0; i < pScreenPriv->nBanks; i++) \
+ { \
+ if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[i])) \
+ continue; \
+ GCOP_UNWRAP; \
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i)
+
+#define GCOP_BOTTOM_PART \
+ GCOP_WRAP; \
+ }
+
+#define GCOP_SIMPLE(statement) \
+ if (nArray > 0) \
+ { \
+ GCOP_INIT; \
+ SCREEN_SAVE; \
+ if (!IS_BANKED(pDrawable)) \
+ { \
+ GCOP_UNWRAP; \
+ statement; \
+ GCOP_WRAP; \
+ } \
+ else \
+ { \
+ int i; \
+ CLIP_SAVE; \
+ GCOP_TOP_PART; \
+ statement; \
+ GCOP_BOTTOM_PART; \
+ CLIP_RESTORE; \
+ } \
+ SCREEN_RESTORE; \
+ }
+
+#define GCOP_0D_ARGS mode,
+#define GCOP_1D_ARGS
+#define GCOP_2D_ARGS shape, mode,
+
+#define GCOP_COMPLEX(aop, atype) \
+ if (nArray > 0) \
+ { \
+ GCOP_INIT; \
+ SCREEN_SAVE; \
+ if (!IS_BANKED(pDrawable)) \
+ { \
+ GCOP_UNWRAP; \
+ (*pGC->ops->aop)(pDrawable, pGC, GCOP_ARGS nArray, pArray); \
+ GCOP_WRAP; \
+ } \
+ else \
+ { \
+ atype *aarg = pArray, *acopy; \
+ int i; \
+ CLIP_SAVE; \
+ if ((acopy = ALLOCATE_LOCAL_ARRAY(atype, nArray))) \
+ aarg = acopy; \
+ GCOP_TOP_PART; \
+ if (acopy) \
+ memcpy(acopy, pArray, nArray * sizeof(atype)); \
+ (*pGC->ops->aop)(pDrawable, pGC, GCOP_ARGS nArray, aarg); \
+ GCOP_BOTTOM_PART; \
+ DEALLOCATE_LOCAL(acopy); \
+ CLIP_RESTORE; \
+ } \
+ SCREEN_RESTORE; \
+ }
+
+/*********************
+ * Utility functions *
+ *********************/
+
+static int
+miBankOf(
+ miBankScreenPtr pScreenPriv,
+ int x,
+ int y
+)
+{
+ int iBank = ((x * (int)pScreenPriv->nBankBPP) +
+ (y * (long)pScreenPriv->nBitsPerScanline)) /
+ (long)pScreenPriv->nBitsPerBank;
+
+ if (iBank < 0)
+ iBank = 0;
+ else if (iBank >= pScreenPriv->nBanks)
+ iBank = pScreenPriv->nBanks - 1;
+
+ return iBank;
+}
+
+#define FirstBankOf(_x, _y) miBankOf(pScreenPriv, (_x), (_y))
+#define LastBankOf(_x, _y) miBankOf(pScreenPriv, (_x) - 1, (_y))
+
+/* Determine banking type from the BankInfoRec */
+static unsigned int
+miBankDeriveType(
+ ScreenPtr pScreen,
+ miBankInfoPtr pBankInfo
+)
+{
+ unsigned int type;
+
+ if (pBankInfo->pBankA == pBankInfo->pBankB)
+ {
+ if (pBankInfo->SetSourceBank == pBankInfo->SetDestinationBank)
+ {
+ if (pBankInfo->SetSourceAndDestinationBanks !=
+ pBankInfo->SetSourceBank)
+ return BANK_NOBANK;
+
+ type = BANK_SINGLE;
+ }
+ else
+ {
+ if (pBankInfo->SetSourceAndDestinationBanks ==
+ pBankInfo->SetDestinationBank)
+ return BANK_NOBANK;
+ if (pBankInfo->SetSourceAndDestinationBanks ==
+ pBankInfo->SetSourceBank)
+ return BANK_NOBANK;
+
+ type = BANK_SHARED;
+ }
+ }
+ else
+ {
+ if ((unsigned long)abs((char *)pBankInfo->pBankA -
+ (char *)pBankInfo->pBankB) < pBankInfo->BankSize)
+ return BANK_NOBANK;
+
+ if (pBankInfo->SetSourceBank == pBankInfo->SetDestinationBank)
+ {
+ if (pBankInfo->SetSourceAndDestinationBanks !=
+ pBankInfo->SetSourceBank)
+ return BANK_NOBANK;
+ }
+ else
+ {
+ if (pBankInfo->SetSourceAndDestinationBanks ==
+ pBankInfo->SetDestinationBank)
+ return BANK_NOBANK;
+ }
+
+ type = BANK_DOUBLE;
+ }
+
+ /*
+ * Internal limitation: Currently, only single banking is supported when
+ * the pixmap format and the screen's pixel format are different. The
+ * following test is only partially successful at detecting this condition.
+ */
+ if (pBankInfo->nBankDepth != pScreen->rootDepth)
+ type = BANK_SINGLE;
+
+ return type;
+}
+
+/* Least common multiple */
+static unsigned int
+miLCM(
+ unsigned int x,
+ unsigned int y
+)
+{
+ unsigned int m = x, n = y, o;
+
+ while ((o = m % n))
+ {
+ m = n;
+ n = o;
+ }
+
+ return (x / n) * y;
+}
+
+/******************
+ * GCOps wrappers *
+ ******************/
+
+static void
+miBankFillSpans(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int nArray,
+ DDXPointPtr pptInit,
+ int *pwidthInit,
+ int fSorted
+)
+{
+ GCOP_SIMPLE((*pGC->ops->FillSpans)(pDrawable, pGC,
+ nArray, pptInit, pwidthInit, fSorted));
+}
+
+static void
+miBankSetSpans(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ char *psrc,
+ DDXPointPtr ppt,
+ int *pwidth,
+ int nArray,
+ int fSorted
+)
+{
+ GCOP_SIMPLE((*pGC->ops->SetSpans)(pDrawable, pGC, psrc,
+ ppt, pwidth, nArray, fSorted));
+}
+
+static void
+miBankPutImage(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int depth,
+ int x,
+ int y,
+ int w,
+ int h,
+ int leftPad,
+ int format,
+ char *pImage
+)
+{
+ if ((w > 0) && (h > 0))
+ {
+ GCOP_INIT;
+ SCREEN_SAVE;
+
+ if (!IS_BANKED(pDrawable))
+ {
+ GCOP_UNWRAP;
+
+ (*pGC->ops->PutImage)(pDrawable, pGC, depth, x, y, w, h,
+ leftPad, format, pImage);
+
+ GCOP_WRAP;
+ }
+ else
+ {
+ int i, j;
+
+ CLIP_SAVE;
+
+ i = FirstBankOf(x + pDrawable->x, y + pDrawable->y);
+ j = LastBankOf(x + pDrawable->x + w, y + pDrawable->y + h);
+ for (; i <= j; i++)
+ {
+ if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[i]))
+ continue;
+
+ GCOP_UNWRAP;
+
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i);
+
+ (*pGC->ops->PutImage)(pDrawable, pGC, depth, x, y, w, h,
+ leftPad, format, pImage);
+
+ GCOP_WRAP;
+ }
+
+ CLIP_RESTORE;
+ }
+
+ SCREEN_RESTORE;
+ }
+}
+
+/*
+ * Here the CopyArea/CopyPlane wrappers. First off, we have to clip against
+ * the source in order to make the minimal number of copies in case of slow
+ * systems. Also the exposure handling is quite tricky. Special attention
+ * is to be given to the way the copies are sequenced. The list of boxes after
+ * the source clip is used to build a workqueue, that contains the atomic
+ * copies (i.e. only from one bank to one bank). Doing so produces a minimal
+ * list of things to do.
+ */
+static RegionPtr
+miBankCopy(
+ DrawablePtr pSrc,
+ DrawablePtr pDst,
+ GCPtr pGC,
+ int srcx,
+ int srcy,
+ int w,
+ int h,
+ int dstx,
+ int dsty,
+ unsigned long plane,
+ Bool SinglePlane
+)
+{
+ int cx1, cy1, cx2, cy2;
+ int ns, nd, nse, nde, dx, dy, xorg = 0, yorg = 0;
+ int maxWidth = 0, maxHeight = 0, paddedWidth = 0;
+ int nBox, nBoxClipSrc, nBoxClipDst, nQueue;
+ BoxPtr pBox, pBoxClipSrc, pBoxClipDst;
+ BoxRec fastBox, ccBox;
+ RegionPtr ret = NULL, prgnSrcClip = NULL;
+ RegionRec rgnDst;
+ char *pImage = NULL;
+ miBankQueue *pQueue, *pQueueNew, *Queue;
+ miBankQueue *pQueueTmp, *pQueueNext, *pQueueBase;
+ Bool fastBlit, freeSrcClip, fastClip;
+ Bool fExpose = FALSE, fastExpose = FALSE;
+
+ GCOP_INIT;
+ SCREEN_SAVE;
+
+ if (!IS_BANKED(pSrc) && !IS_BANKED(pDst))
+ {
+ GCOP_UNWRAP;
+
+ if (SinglePlane)
+ ret = (*pGC->ops->CopyPlane)(pSrc, pDst, pGC,
+ srcx, srcy, w, h, dstx, dsty, plane);
+ else
+ ret = (*pGC->ops->CopyArea)(pSrc, pDst, pGC,
+ srcx, srcy, w, h, dstx, dsty);
+
+ GCOP_WRAP;
+ }
+ else if (!IS_BANKED(pDst))
+ {
+ fExpose = pGC->fExpose;
+ pGC->fExpose = FALSE;
+
+ xorg = pSrc->x;
+ yorg = pSrc->y;
+ dx = dstx - srcx;
+ dy = dsty - srcy;
+ srcx += xorg;
+ srcy += yorg;
+
+ ns = FirstBankOf(srcx, srcy);
+ nse = LastBankOf(srcx + w, srcy + h);
+ for (; ns <= nse; ns++)
+ {
+ if (!pScreenPriv->pBanks[ns])
+ continue;
+
+ nBox = REGION_NUM_RECTS(pScreenPriv->pBanks[ns]);
+ pBox = REGION_RECTS(pScreenPriv->pBanks[ns]);
+
+ for (; nBox--; pBox++)
+ {
+ cx1 = max(pBox->x1, srcx);
+ cy1 = max(pBox->y1, srcy);
+ cx2 = min(pBox->x2, srcx + w);
+ cy2 = min(pBox->y2, srcy + h);
+
+ if ((cx1 >= cx2) || (cy1 >= cy2))
+ continue;
+
+ GCOP_UNWRAP;
+
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, ns);
+
+ if (SinglePlane)
+ (*pGC->ops->CopyPlane)(pSrc, pDst, pGC,
+ cx1 - xorg, cy1 - yorg,
+ cx2 - cx1, cy2 - cy1,
+ cx1 + dx - xorg, cy1 + dy - yorg, plane);
+ else
+ (*pGC->ops->CopyArea)(pSrc, pDst, pGC,
+ cx1 - xorg, cy1 - yorg,
+ cx2 - cx1, cy2 - cy1,
+ cx1 + dx - xorg, cy1 + dy - yorg);
+
+ GCOP_WRAP;
+ }
+ }
+
+ pGC->fExpose = fExpose;
+ srcx -= xorg;
+ srcy -= yorg;
+ }
+ else if (!IS_BANKED(pSrc))
+ {
+ CLIP_SAVE;
+
+ if (pGC->miTranslate)
+ {
+ xorg = pDst->x;
+ yorg = pDst->y;
+ }
+ dx = srcx - dstx;
+ dy = srcy - dsty;
+ dstx += xorg;
+ dsty += yorg;
+
+ nd = FirstBankOf(dstx, dsty);
+ nde = LastBankOf(dstx + w, dsty + h);
+ for (; nd <= nde; nd++)
+ {
+ if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[nd]))
+ continue;
+
+ /*
+ * It's faster to let the lower-level CopyArea do the clipping
+ * within each bank.
+ */
+ nBox = REGION_NUM_RECTS(pScreenPriv->pBanks[nd]);
+ pBox = REGION_RECTS(pScreenPriv->pBanks[nd]);
+
+ for (; nBox--; pBox++)
+ {
+ cx1 = max(pBox->x1, dstx);
+ cy1 = max(pBox->y1, dsty);
+ cx2 = min(pBox->x2, dstx + w);
+ cy2 = min(pBox->y2, dsty + h);
+
+ if ((cx1 >= cx2) || (cy1 >= cy2))
+ continue;
+
+ GCOP_UNWRAP;
+
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, nd);
+
+ if (SinglePlane)
+ (*pGC->ops->CopyPlane)(pSrc, pDst, pGC,
+ cx1 + dx - xorg, cy1 + dy - yorg,
+ cx2 - cx1, cy2 - cy1,
+ cx1 - xorg, cy1 - yorg, plane);
+ else
+ (*pGC->ops->CopyArea)(pSrc, pDst, pGC,
+ cx1 + dx - xorg, cy1 + dy - yorg,
+ cx2 - cx1, cy2 - cy1,
+ cx1 - xorg, cy1 - yorg);
+
+ GCOP_WRAP;
+ }
+ }
+
+ CLIP_RESTORE;
+ }
+ else /* IS_BANKED(pSrc) && IS_BANKED(pDst) */
+ {
+ CLIP_SAVE;
+
+ fExpose = pGC->fExpose;
+
+ fastBox.x1 = srcx + pSrc->x;
+ fastBox.y1 = srcy + pSrc->y;
+ fastBox.x2 = fastBox.x1 + w;
+ fastBox.y2 = fastBox.y1 + h;
+
+ dx = dstx - fastBox.x1;
+ dy = dsty - fastBox.y1;
+ if (pGC->miTranslate)
+ {
+ xorg = pDst->x;
+ yorg = pDst->y;
+ }
+
+ /*
+ * Clip against the source. Otherwise we will blit too much for SINGLE
+ * and SHARED banked systems.
+ */
+ freeSrcClip = FALSE;
+ fastClip = FALSE;
+ fastExpose = FALSE;
+
+ if (pGC->subWindowMode != IncludeInferiors)
+ prgnSrcClip = &((WindowPtr)pSrc)->clipList;
+ else if (!((WindowPtr)pSrc)->parent)
+ fastClip = TRUE;
+ else if ((pSrc == pDst) && (pGC->clientClipType == CT_NONE))
+ prgnSrcClip = pGC->pCompositeClip;
+ else
+ {
+ prgnSrcClip = NotClippedByChildren((WindowPtr)pSrc);
+ freeSrcClip = TRUE;
+ }
+
+ if (fastClip)
+ {
+ fastExpose = TRUE;
+
+ /*
+ * Clip the source. If regions extend beyond the source size, make
+ * sure exposure events get sent.
+ */
+ if (fastBox.x1 < pSrc->x)
+ {
+ fastBox.x1 = pSrc->x;
+ fastExpose = FALSE;
+ }
+ if (fastBox.y1 < pSrc->y)
+ {
+ fastBox.y1 = pSrc->y;
+ fastExpose = FALSE;
+ }
+ if (fastBox.x2 > pSrc->x + (int) pSrc->width)
+ {
+ fastBox.x2 = pSrc->x + (int) pSrc->width;
+ fastExpose = FALSE;
+ }
+ if (fastBox.y2 > pSrc->y + (int) pSrc->height)
+ {
+ fastBox.y2 = pSrc->y + (int) pSrc->height;
+ fastExpose = FALSE;
+ }
+
+ nBox = 1;
+ pBox = &fastBox;
+ }
+ else
+ {
+ REGION_INIT(pScreen, &rgnDst, &fastBox, 1);
+ REGION_INTERSECT(pScreen, &rgnDst, &rgnDst, prgnSrcClip);
+ pBox = REGION_RECTS(&rgnDst);
+ nBox = REGION_NUM_RECTS(&rgnDst);
+ }
+
+ /*
+ * fastBlit can only be TRUE if we don't need to worry about attempts
+ * to read partial pixels through the destination bank.
+ */
+ if (SinglePlane)
+ fastBlit = pGCPriv->fastPlane;
+ else
+ fastBlit = pGCPriv->fastCopy;
+
+ nQueue = nBox * pScreenPriv->maxRects * 2;
+ pQueue = Queue = ALLOCATE_LOCAL_ARRAY(miBankQueue, nQueue);
+
+ if (Queue)
+ {
+ for (; nBox--; pBox++)
+ {
+ ns = FirstBankOf(pBox->x1, pBox->y1);
+ nse = LastBankOf(pBox->x2, pBox->y2);
+ for (; ns <= nse; ns++)
+ {
+ if (!pScreenPriv->pBanks[ns])
+ continue;
+
+ nBoxClipSrc = REGION_NUM_RECTS(pScreenPriv->pBanks[ns]);
+ pBoxClipSrc = REGION_RECTS(pScreenPriv->pBanks[ns]);
+
+ for (; nBoxClipSrc--; pBoxClipSrc++)
+ {
+ cx1 = max(pBox->x1, pBoxClipSrc->x1);
+ cy1 = max(pBox->y1, pBoxClipSrc->y1);
+ cx2 = min(pBox->x2, pBoxClipSrc->x2);
+ cy2 = min(pBox->y2, pBoxClipSrc->y2);
+
+ /* Check to see if the region is empty */
+ if ((cx1 >= cx2) || (cy1 >= cy2))
+ continue;
+
+ /* Translate c[xy]* to destination coordinates */
+ cx1 += dx + xorg;
+ cy1 += dy + yorg;
+ cx2 += dx + xorg;
+ cy2 += dy + yorg;
+
+ nd = FirstBankOf(cx1, cy1);
+ nde = LastBankOf(cx2, cy2);
+ for (; nd <= nde; nd++)
+ {
+ if (!pGCPriv->pBankedClips[nd])
+ continue;
+
+ /*
+ * Clients can send quite large clip descriptions,
+ * so use the bank clips here instead.
+ */
+ nBoxClipDst =
+ REGION_NUM_RECTS(pScreenPriv->pBanks[nd]);
+ pBoxClipDst =
+ REGION_RECTS(pScreenPriv->pBanks[nd]);
+
+ for (; nBoxClipDst--; pBoxClipDst++)
+ {
+ ccBox.x1 = max(cx1, pBoxClipDst->x1);
+ ccBox.y1 = max(cy1, pBoxClipDst->y1);
+ ccBox.x2 = min(cx2, pBoxClipDst->x2);
+ ccBox.y2 = min(cy2, pBoxClipDst->y2);
+
+ /* Check to see if the region is empty */
+ if ((ccBox.x1 >= ccBox.x2) ||
+ (ccBox.y1 >= ccBox.y2))
+ continue;
+
+ pQueue->srcBankNo = ns;
+ pQueue->dstBankNo = nd;
+ pQueue->x = ccBox.x1 - xorg;
+ pQueue->y = ccBox.y1 - yorg;
+ pQueue->w = ccBox.x2 - ccBox.x1;
+ pQueue->h = ccBox.y2 - ccBox.y1;
+
+ if (maxWidth < pQueue->w)
+ maxWidth = pQueue->w;
+ if (maxHeight < pQueue->h)
+ maxHeight = pQueue->h;
+
+ /*
+ * When shared banking is used and the source
+ * and destination banks differ, prevent
+ * attempts to fetch partial scanline pad units
+ * through the destination bank.
+ */
+ pQueue->fastBlit = fastBlit;
+ if (fastBlit &&
+ (pScreenPriv->type == BANK_SHARED) &&
+ (ns != nd) &&
+ ((ccBox.x1 %
+ pScreenPriv->nPixelsPerScanlinePadUnit) ||
+ (ccBox.x2 %
+ pScreenPriv->nPixelsPerScanlinePadUnit) ||
+ (RECT_IN_REGION(pScreen,
+ pGCPriv->pBankedClips[nd], &ccBox) !=
+ rgnIN)))
+ pQueue->fastBlit = FALSE;
+ pQueue++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!fastClip)
+ {
+ REGION_UNINIT(pScreen, &rgnDst);
+ if (freeSrcClip)
+ REGION_DESTROY(pScreen, prgnSrcClip);
+ }
+
+ pQueueNew = pQueue;
+ nQueue = pQueue - Queue;
+
+ if (nQueue > 0)
+ {
+ BANK_SAVE;
+
+ pQueue = Queue;
+
+ if ((nQueue > 1) &&
+ ((pSrc == pDst) || (pGC->subWindowMode == IncludeInferiors)))
+ {
+ if ((srcy + pSrc->y) < (dsty + yorg))
+ {
+ /* Sort from bottom to top */
+ pQueueBase = pQueueNext = pQueue + nQueue - 1;
+
+ while (pQueueBase >= pQueue)
+ {
+ while ((pQueueNext >= pQueue) &&
+ (pQueueBase->y == pQueueNext->y))
+ pQueueNext--;
+
+ pQueueTmp = pQueueNext + 1;
+ while (pQueueTmp <= pQueueBase)
+ *pQueueNew++ = *pQueueTmp++;
+
+ pQueueBase = pQueueNext;
+ }
+
+ pQueueNew -= nQueue;
+ pQueue = pQueueNew;
+ pQueueNew = Queue;
+ }
+
+ if ((srcx + pSrc->x) < (dstx + xorg))
+ {
+ /* Sort from right to left */
+ pQueueBase = pQueueNext = pQueue;
+
+ while (pQueueBase < pQueue + nQueue)
+ {
+ while ((pQueueNext < pQueue + nQueue) &&
+ (pQueueNext->y == pQueueBase->y))
+ pQueueNext++;
+
+ pQueueTmp = pQueueNext;
+ while (pQueueTmp != pQueueBase)
+ *pQueueNew++ = *--pQueueTmp;
+
+ pQueueBase = pQueueNext;
+ }
+
+ pQueueNew -= nQueue;
+ pQueue = pQueueNew;
+ }
+ }
+
+ paddedWidth = PixmapBytePad(maxWidth,
+ pScreenPriv->pScreenPixmap->drawable.depth);
+ pImage = (char *)ALLOCATE_LOCAL(paddedWidth * maxHeight);
+
+ pGC->fExpose = FALSE;
+
+ while (nQueue--)
+ {
+ pGC->pCompositeClip = pGCPriv->pBankedClips[pQueue->dstBankNo];
+
+ GCOP_UNWRAP;
+
+ if (pQueue->srcBankNo == pQueue->dstBankNo)
+ {
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap,
+ -1, -1, pQueue->srcBankNo);
+
+ if (SinglePlane)
+ (*pGC->ops->CopyPlane)(pSrc, pDst, pGC,
+ pQueue->x - dx - pSrc->x, pQueue->y - dy - pSrc->y,
+ pQueue->w, pQueue->h, pQueue->x, pQueue->y, plane);
+ else
+ (*pGC->ops->CopyArea)(pSrc, pDst, pGC,
+ pQueue->x - dx - pSrc->x, pQueue->y - dy - pSrc->y,
+ pQueue->w, pQueue->h, pQueue->x, pQueue->y);
+ }
+ else if (pQueue->fastBlit)
+ {
+ SET_SOURCE_BANK (pScreenPriv->pBankPixmap,
+ pScreenPriv->pScreenPixmap->drawable.width,
+ pScreenPriv->pScreenPixmap->devKind,
+ pQueue->srcBankNo);
+ SET_DESTINATION_BANK(pScreenPriv->pScreenPixmap,
+ -1, -1, pQueue->dstBankNo);
+
+ if (SinglePlane)
+ (*pGC->ops->CopyPlane)(
+ (DrawablePtr)pScreenPriv->pBankPixmap, pDst, pGC,
+ pQueue->x - dx, pQueue->y - dy,
+ pQueue->w, pQueue->h, pQueue->x, pQueue->y, plane);
+ else
+ (*pGC->ops->CopyArea)(
+ (DrawablePtr)pScreenPriv->pBankPixmap, pDst, pGC,
+ pQueue->x - dx, pQueue->y - dy,
+ pQueue->w, pQueue->h, pQueue->x, pQueue->y);
+ }
+ else if (pImage)
+ {
+ ModifyPixmap(pScreenPriv->pBankPixmap,
+ maxWidth, paddedWidth, pImage);
+
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap,
+ -1, -1, pQueue->srcBankNo);
+
+ (*pScreenPriv->pBankGC->ops->CopyArea)(
+ pSrc, (DrawablePtr)pScreenPriv->pBankPixmap,
+ pScreenPriv->pBankGC,
+ pQueue->x - dx - pSrc->x, pQueue->y - dy - pSrc->y,
+ pQueue->w, pQueue->h, 0, 0);
+
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap,
+ -1, -1, pQueue->dstBankNo);
+
+ if (SinglePlane)
+ (*pGC->ops->CopyPlane)(
+ (DrawablePtr)pScreenPriv->pBankPixmap,
+ pDst, pGC, 0, 0, pQueue->w, pQueue->h,
+ pQueue->x, pQueue->y, plane);
+ else
+ (*pGC->ops->CopyArea)(
+ (DrawablePtr)pScreenPriv->pBankPixmap,
+ pDst, pGC, 0, 0, pQueue->w, pQueue->h,
+ pQueue->x, pQueue->y);
+ }
+
+ GCOP_WRAP;
+
+ pQueue++;
+ }
+
+ DEALLOCATE_LOCAL(pImage);
+
+ BANK_RESTORE;
+ }
+
+ CLIP_RESTORE;
+
+ pGC->fExpose = fExpose;
+
+ DEALLOCATE_LOCAL(Queue);
+ }
+
+ SCREEN_RESTORE;
+
+ if (!fExpose || fastExpose)
+ return ret;
+
+ return miHandleExposures(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, 0);
+}
+
+static RegionPtr
+miBankCopyArea(
+ DrawablePtr pSrc,
+ DrawablePtr pDst,
+ GCPtr pGC,
+ int srcx,
+ int srcy,
+ int w,
+ int h,
+ int dstx,
+ int dsty
+)
+{
+ return miBankCopy(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, 0, FALSE);
+}
+
+static RegionPtr
+miBankCopyPlane(
+ DrawablePtr pSrc,
+ DrawablePtr pDst,
+ GCPtr pGC,
+ int srcx,
+ int srcy,
+ int w,
+ int h,
+ int dstx,
+ int dsty,
+ unsigned long plane
+)
+{
+ return
+ miBankCopy(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane, TRUE);
+}
+
+static void
+miBankPolyPoint(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int mode,
+ int nArray,
+ xPoint *pArray
+)
+{
+# define GCOP_ARGS GCOP_0D_ARGS
+ GCOP_COMPLEX(PolyPoint, xPoint);
+# undef GCOP_ARGS
+}
+
+static void
+miBankPolylines(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int mode,
+ int nArray,
+ DDXPointPtr pArray
+)
+{
+# define GCOP_ARGS GCOP_0D_ARGS
+ GCOP_COMPLEX(Polylines, DDXPointRec);
+# undef GCOP_ARGS
+}
+
+static void
+miBankPolySegment(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int nArray,
+ xSegment *pArray
+)
+{
+# define GCOP_ARGS GCOP_1D_ARGS
+ GCOP_COMPLEX(PolySegment, xSegment);
+# undef GCOP_ARGS
+}
+
+static void
+miBankPolyRectangle(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int nArray,
+ xRectangle *pArray
+)
+{
+# define GCOP_ARGS GCOP_1D_ARGS
+ GCOP_COMPLEX(PolyRectangle, xRectangle);
+# undef GCOP_ARGS
+}
+
+static void
+miBankPolyArc(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int nArray,
+ xArc *pArray
+)
+{
+# define GCOP_ARGS GCOP_1D_ARGS
+ GCOP_COMPLEX(PolyArc, xArc);
+# undef GCOP_ARGS
+}
+
+static void
+miBankFillPolygon(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int shape,
+ int mode,
+ int nArray,
+ DDXPointRec *pArray
+)
+{
+# define GCOP_ARGS GCOP_2D_ARGS
+ GCOP_COMPLEX(FillPolygon, DDXPointRec);
+# undef GCOP_ARGS
+}
+
+static void
+miBankPolyFillRect(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int nArray,
+ xRectangle *pArray
+)
+{
+# define GCOP_ARGS GCOP_1D_ARGS
+ GCOP_COMPLEX(PolyFillRect, xRectangle);
+# undef GCOP_ARGS
+}
+
+static void
+miBankPolyFillArc(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int nArray,
+ xArc *pArray
+)
+{
+# define GCOP_ARGS GCOP_1D_ARGS
+ GCOP_COMPLEX(PolyFillArc, xArc);
+# undef GCOP_ARGS
+}
+
+static int
+miBankPolyText8(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x,
+ int y,
+ int nArray,
+ char *pchar
+)
+{
+ int retval = x;
+
+ GCOP_SIMPLE(retval =
+ (*pGC->ops->PolyText8)(pDrawable, pGC, x, y, nArray, pchar));
+
+ return retval;
+}
+
+static int
+miBankPolyText16(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x,
+ int y,
+ int nArray,
+ unsigned short *pchar
+)
+{
+ int retval = x;
+
+ GCOP_SIMPLE(retval =
+ (*pGC->ops->PolyText16)(pDrawable, pGC, x, y, nArray, pchar));
+
+ return retval;
+}
+
+static void
+miBankImageText8(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x,
+ int y,
+ int nArray,
+ char *pchar
+)
+{
+ GCOP_SIMPLE((*pGC->ops->ImageText8)(pDrawable, pGC, x, y, nArray, pchar));
+}
+
+static void
+miBankImageText16(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x,
+ int y,
+ int nArray,
+ unsigned short *pchar
+)
+{
+ GCOP_SIMPLE((*pGC->ops->ImageText16)(pDrawable, pGC, x, y, nArray, pchar));
+}
+
+static void
+miBankImageGlyphBlt(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x,
+ int y,
+ unsigned int nArray,
+ CharInfoPtr *ppci,
+ pointer pglyphBase
+)
+{
+ GCOP_SIMPLE((*pGC->ops->ImageGlyphBlt)(pDrawable, pGC,
+ x, y, nArray, ppci, pglyphBase));
+}
+
+static void
+miBankPolyGlyphBlt(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x,
+ int y,
+ unsigned int nArray,
+ CharInfoPtr *ppci,
+ pointer pglyphBase
+)
+{
+ GCOP_SIMPLE((*pGC->ops->PolyGlyphBlt)(pDrawable, pGC,
+ x, y, nArray, ppci, pglyphBase));
+}
+
+static void
+miBankPushPixels(
+ GCPtr pGC,
+ PixmapPtr pBitmap,
+ DrawablePtr pDrawable,
+ int w,
+ int h,
+ int x,
+ int y
+)
+{
+ if ((w > 0) && (h > 0))
+ {
+ GCOP_INIT;
+ SCREEN_SAVE;
+
+ if (!IS_BANKED(pDrawable))
+ {
+ GCOP_UNWRAP;
+
+ (*pGC->ops->PushPixels)(pGC, pBitmap, pDrawable, w, h, x, y);
+
+ GCOP_WRAP;
+ }
+ else
+ {
+ int i, j;
+
+ CLIP_SAVE;
+
+ i = FirstBankOf(x, y);
+ j = LastBankOf(x + w, y + h);
+ for (; i <= j; i++)
+ {
+ if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[i]))
+ continue;
+
+ GCOP_UNWRAP;
+
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i);
+
+ (*pGC->ops->PushPixels)(pGC, pBitmap, pDrawable, w, h, x, y);
+
+ GCOP_WRAP;
+ }
+
+ CLIP_RESTORE;
+ }
+
+ SCREEN_RESTORE;
+ }
+}
+
+static GCOps miBankGCOps =
+{
+ miBankFillSpans,
+ miBankSetSpans,
+ miBankPutImage,
+ miBankCopyArea,
+ miBankCopyPlane,
+ miBankPolyPoint,
+ miBankPolylines,
+ miBankPolySegment,
+ miBankPolyRectangle,
+ miBankPolyArc,
+ miBankFillPolygon,
+ miBankPolyFillRect,
+ miBankPolyFillArc,
+ miBankPolyText8,
+ miBankPolyText16,
+ miBankImageText8,
+ miBankImageText16,
+ miBankImageGlyphBlt,
+ miBankPolyGlyphBlt,
+ miBankPushPixels,
+ {NULL} /* devPrivate */
+};
+
+/********************
+ * GCFuncs wrappers *
+ ********************/
+
+static void
+miBankValidateGC(
+ GCPtr pGC,
+ unsigned long changes,
+ DrawablePtr pDrawable
+)
+{
+ GC_INIT(pGC);
+ GC_UNWRAP(pGC);
+
+ (*pGC->funcs->ValidateGC)(pGC, changes, pDrawable);
+
+ if ((changes & (GCClipXOrigin|GCClipYOrigin|GCClipMask|GCSubwindowMode)) ||
+ (pDrawable->serialNumber != (pGC->serialNumber & DRAWABLE_SERIAL_BITS)))
+ {
+ ScreenPtr pScreen = pGC->pScreen;
+ RegionPtr prgnClip;
+ unsigned long planemask;
+ int i;
+
+ SCREEN_INIT;
+ SCREEN_SAVE;
+
+ if (IS_BANKED(pDrawable))
+ {
+ for (i = 0; i < pScreenPriv->nBanks; i++)
+ {
+ if (!pScreenPriv->pBanks[i])
+ continue;
+
+ if (!(prgnClip = pGCPriv->pBankedClips[i]))
+ prgnClip = REGION_CREATE(pScreen, NULL, 1);
+
+ REGION_INTERSECT(pScreen, prgnClip,
+ pScreenPriv->pBanks[i], pGC->pCompositeClip);
+
+ if ((REGION_NUM_RECTS(prgnClip) <= 1) &&
+ ((prgnClip->extents.x1 == prgnClip->extents.x2) ||
+ (prgnClip->extents.y1 == prgnClip->extents.y2)))
+ {
+ REGION_DESTROY(pScreen, prgnClip);
+ pGCPriv->pBankedClips[i] = NULL;
+ }
+ else
+ pGCPriv->pBankedClips[i] = prgnClip;
+ }
+
+ /*
+ * fastCopy and fastPlane can only be TRUE if we don't need to
+ * worry about attempts to read partial pixels through the
+ * destination bank.
+ */
+ switch (pScreenPriv->type)
+ {
+ case BANK_SHARED:
+ pGCPriv->fastCopy = pGCPriv->fastPlane = FALSE;
+
+ if ((pGC->alu != GXclear) && (pGC->alu != GXcopy) &&
+ (pGC->alu != GXcopyInverted) && (pGC->alu != GXset))
+ break;
+
+ if (pScreen->rootDepth == 1)
+ pGCPriv->fastPlane = TRUE;
+
+ /* This is probably paranoia */
+ if ((pDrawable->depth != pScreen->rootDepth) ||
+ (pDrawable->depth != pGC->depth))
+ break;
+
+ planemask = (1 << pGC->depth) - 1;
+ if ((pGC->planemask & planemask) == planemask)
+ pGCPriv->fastCopy = TRUE;
+
+ break;
+
+ case BANK_DOUBLE:
+ pGCPriv->fastCopy = pGCPriv->fastPlane = TRUE;
+ break;
+
+ default:
+ pGCPriv->fastCopy = pGCPriv->fastPlane = FALSE;
+ break;
+ }
+ }
+ else
+ {
+ /*
+ * Here we are on a pixmap and don't need all that special clipping
+ * stuff, hence free it.
+ */
+ for (i = 0; i < pScreenPriv->nBanks; i++)
+ {
+ if (!pGCPriv->pBankedClips[i])
+ continue;
+
+ REGION_DESTROY(pScreen, pGCPriv->pBankedClips[i]);
+ pGCPriv->pBankedClips[i] = NULL;
+ }
+ }
+
+ SCREEN_RESTORE;
+ }
+
+ GC_WRAP(pGC);
+}
+
+static void
+miBankChangeGC(
+ GCPtr pGC,
+ unsigned long mask
+)
+{
+ GC_INIT(pGC);
+ GC_UNWRAP(pGC);
+
+ (*pGC->funcs->ChangeGC)(pGC, mask);
+
+ GC_WRAP(pGC);
+}
+
+static void
+miBankCopyGC(
+ GCPtr pGCSrc,
+ unsigned long mask,
+ GCPtr pGCDst
+)
+{
+ GC_INIT(pGCDst);
+ GC_UNWRAP(pGCDst);
+
+ (*pGCDst->funcs->CopyGC)(pGCSrc, mask, pGCDst);
+
+ GC_WRAP(pGCDst);
+}
+
+static void
+miBankDestroyGC(
+ GCPtr pGC
+)
+{
+ ScreenPtr pScreen = pGC->pScreen;
+ int i;
+
+ SCREEN_INIT;
+ GC_INIT(pGC);
+ GC_UNWRAP(pGC);
+
+ (*pGC->funcs->DestroyGC)(pGC);
+
+ for (i = 0; i < pScreenPriv->nBanks; i++)
+ {
+ if (!pGCPriv->pBankedClips[i])
+ continue;
+
+ REGION_DESTROY(pScreen, pGCPriv->pBankedClips[i]);
+ pGCPriv->pBankedClips[i] = NULL;
+ }
+
+ GC_WRAP(pGC);
+}
+
+static void
+miBankChangeClip(
+ GCPtr pGC,
+ int type,
+ pointer pvalue,
+ int nrects
+)
+{
+ GC_INIT(pGC);
+ GC_UNWRAP(pGC);
+
+ (*pGC->funcs->ChangeClip)(pGC, type, pvalue, nrects);
+
+ GC_WRAP(pGC);
+}
+
+static void
+miBankDestroyClip(
+ GCPtr pGC
+)
+{
+ GC_INIT(pGC);
+ GC_UNWRAP(pGC);
+
+ (*pGC->funcs->DestroyClip)(pGC);
+
+ GC_WRAP(pGC);
+}
+
+static void
+miBankCopyClip(
+ GCPtr pGCDst,
+ GCPtr pGCSrc
+)
+{
+ GC_INIT(pGCDst);
+ GC_UNWRAP(pGCDst);
+
+ (*pGCDst->funcs->CopyClip)(pGCDst, pGCSrc);
+
+ GC_WRAP(pGCDst);
+}
+
+static GCFuncs miBankGCFuncs =
+{
+ miBankValidateGC,
+ miBankChangeGC,
+ miBankCopyGC,
+ miBankDestroyGC,
+ miBankChangeClip,
+ miBankDestroyClip,
+ miBankCopyClip
+};
+
+/*******************
+ * Screen Wrappers *
+ *******************/
+
+static Bool
+miBankCreateScreenResources(
+ ScreenPtr pScreen
+)
+{
+ Bool retval;
+
+ SCREEN_INIT;
+ SCREEN_UNWRAP(CreateScreenResources);
+
+ if ((retval = (*pScreen->CreateScreenResources)(pScreen)))
+ {
+ /* Set screen buffer address to something recognizable */
+ pScreenPriv->pScreenPixmap = (*pScreen->GetScreenPixmap)(pScreen);
+ pScreenPriv->pbits = pScreenPriv->pScreenPixmap->devPrivate.ptr;
+ pScreenPriv->pScreenPixmap->devPrivate.ptr = (pointer)pScreenPriv;
+
+ /* Get shadow pixmap; width & height of 0 means no pixmap data */
+ pScreenPriv->pBankPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0,
+ pScreenPriv->pScreenPixmap->drawable.depth);
+ if (!pScreenPriv->pBankPixmap)
+ retval = FALSE;
+ }
+
+ /* Shadow the screen */
+ if (retval)
+ retval = (*pScreen->ModifyPixmapHeader)(pScreenPriv->pBankPixmap,
+ pScreenPriv->pScreenPixmap->drawable.width,
+ pScreenPriv->pScreenPixmap->drawable.height,
+ pScreenPriv->pScreenPixmap->drawable.depth,
+ pScreenPriv->pScreenPixmap->drawable.bitsPerPixel,
+ pScreenPriv->pScreenPixmap->devKind, NULL);
+
+ /* Create shadow GC */
+ if (retval)
+ {
+ pScreenPriv->pBankGC = CreateScratchGC(pScreen,
+ pScreenPriv->pBankPixmap->drawable.depth);
+ if (!pScreenPriv->pBankGC)
+ retval = FALSE;
+ }
+
+ /* Validate shadow GC */
+ if (retval)
+ {
+ pScreenPriv->pBankGC->graphicsExposures = FALSE;
+ pScreenPriv->pBankGC->subWindowMode = IncludeInferiors;
+ ValidateGC((DrawablePtr)pScreenPriv->pBankPixmap,
+ pScreenPriv->pBankGC);
+ }
+
+ SCREEN_WRAP(CreateScreenResources, miBankCreateScreenResources);
+
+ return retval;
+}
+
+static Bool
+miBankModifyPixmapHeader(
+ PixmapPtr pPixmap,
+ int width,
+ int height,
+ int depth,
+ int bitsPerPixel,
+ int devKind,
+ pointer pPixData
+)
+{
+ Bool retval = FALSE;
+
+ if (pPixmap)
+ {
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+
+ SCREEN_INIT;
+ PIXMAP_SAVE(pPixmap);
+ SCREEN_UNWRAP(ModifyPixmapHeader);
+
+ retval = (*pScreen->ModifyPixmapHeader)(pPixmap, width, height,
+ depth, bitsPerPixel, devKind, pPixData);
+
+ SCREEN_WRAP(ModifyPixmapHeader, miBankModifyPixmapHeader);
+
+ if (pbits == (pointer)pScreenPriv)
+ {
+ pScreenPriv->pbits = pPixmap->devPrivate.ptr;
+ pPixmap->devPrivate.ptr = pbits;
+ }
+ }
+
+ return retval;
+}
+
+static Bool
+miBankCloseScreen(
+ int nIndex,
+ ScreenPtr pScreen
+)
+{
+ int i;
+
+ SCREEN_INIT;
+
+ /* Free shadow GC */
+ FreeScratchGC(pScreenPriv->pBankGC);
+
+ /* Free shadow pixmap */
+ (*pScreen->DestroyPixmap)(pScreenPriv->pBankPixmap);
+
+ /* Restore screen pixmap devPrivate pointer */
+ pScreenPriv->pScreenPixmap->devPrivate.ptr = pScreenPriv->pbits;
+
+ /* Delete bank clips */
+ for (i = 0; i < pScreenPriv->nBanks; i++)
+ if (pScreenPriv->pBanks[i])
+ REGION_DESTROY(pScreen, pScreenPriv->pBanks[i]);
+
+ Xfree(pScreenPriv->pBanks);
+
+ SCREEN_UNWRAP(CreateScreenResources);
+ SCREEN_UNWRAP(ModifyPixmapHeader);
+ SCREEN_UNWRAP(CloseScreen);
+ SCREEN_UNWRAP(GetImage);
+ SCREEN_UNWRAP(GetSpans);
+ SCREEN_UNWRAP(CreateGC);
+ SCREEN_UNWRAP(PaintWindowBackground);
+ SCREEN_UNWRAP(PaintWindowBorder);
+ SCREEN_UNWRAP(CopyWindow);
+ SCREEN_UNWRAP(BackingStoreFuncs);
+
+ Xfree(pScreenPriv);
+ return (*pScreen->CloseScreen)(nIndex, pScreen);
+}
+
+static void
+miBankGetImage(
+ DrawablePtr pDrawable,
+ int sx,
+ int sy,
+ int w,
+ int h,
+ unsigned int format,
+ unsigned long planemask,
+ char *pImage
+)
+{
+ if ((w > 0) && (h > 0))
+ {
+ ScreenPtr pScreen = pDrawable->pScreen;
+
+ SCREEN_INIT;
+ SCREEN_STATUS;
+ SCREEN_UNWRAP(GetImage);
+
+ if (!IS_BANKED(pDrawable))
+ {
+ (*pScreen->GetImage)(pDrawable, sx, sy, w, h,
+ format, planemask, pImage);
+ }
+ else
+ {
+ int paddedWidth;
+ char *pBankImage;
+
+ paddedWidth = PixmapBytePad(w,
+ pScreenPriv->pScreenPixmap->drawable.depth);
+ pBankImage = (char *)ALLOCATE_LOCAL(paddedWidth * h);
+
+ if (pBankImage)
+ {
+ BANK_SAVE;
+
+ ModifyPixmap(pScreenPriv->pBankPixmap, w, paddedWidth,
+ pBankImage);
+
+ (*pScreenPriv->pBankGC->ops->CopyArea)(
+ (DrawablePtr)WindowTable[pScreen->myNum],
+ (DrawablePtr)pScreenPriv->pBankPixmap,
+ pScreenPriv->pBankGC,
+ sx + pDrawable->x, sy + pDrawable->y, w, h, 0, 0);
+
+ (*pScreen->GetImage)((DrawablePtr)pScreenPriv->pBankPixmap,
+ 0, 0, w, h, format, planemask, pImage);
+
+ BANK_RESTORE;
+
+ DEALLOCATE_LOCAL(pBankImage);
+ }
+ }
+
+ SCREEN_WRAP(GetImage, miBankGetImage);
+ }
+}
+
+static void
+miBankGetSpans(
+ DrawablePtr pDrawable,
+ int wMax,
+ DDXPointPtr ppt,
+ int *pwidth,
+ int nspans,
+ char *pImage
+)
+{
+ if (nspans > 0)
+ {
+ ScreenPtr pScreen = pDrawable->pScreen;
+
+ SCREEN_INIT;
+ SCREEN_STATUS;
+ SCREEN_UNWRAP(GetSpans);
+
+ if (!IS_BANKED(pDrawable))
+ {
+ (*pScreen->GetSpans)(pDrawable, wMax, ppt, pwidth, nspans, pImage);
+ }
+ else
+ {
+ char *pBankImage;
+ int paddedWidth;
+ DDXPointRec pt;
+
+ pt.x = pt.y = 0;
+
+ paddedWidth =
+ PixmapBytePad(pScreenPriv->pScreenPixmap->drawable.width,
+ pScreenPriv->pScreenPixmap->drawable.depth);
+ pBankImage = (char *)ALLOCATE_LOCAL(paddedWidth);
+
+ if (pBankImage)
+ {
+ BANK_SAVE;
+
+ ModifyPixmap(pScreenPriv->pBankPixmap,
+ pScreenPriv->pScreenPixmap->drawable.width,
+ paddedWidth, pBankImage);
+
+ for (; nspans--; ppt++, pwidth++)
+ {
+ if (*pwidth <= 0)
+ continue;
+
+ (*pScreenPriv->pBankGC->ops->CopyArea)(
+ (DrawablePtr)WindowTable[pScreen->myNum],
+ (DrawablePtr)pScreenPriv->pBankPixmap,
+ pScreenPriv->pBankGC,
+ ppt->x, ppt->y, *pwidth, 1, 0, 0);
+
+ (*pScreen->GetSpans)((DrawablePtr)pScreenPriv->pBankPixmap,
+ wMax, &pt, pwidth, 1, pImage);
+
+ pImage = pImage + PixmapBytePad(*pwidth, pDrawable->depth);
+ }
+
+ BANK_RESTORE;
+
+ DEALLOCATE_LOCAL(pBankImage);
+ }
+ }
+
+ SCREEN_WRAP(GetSpans, miBankGetSpans);
+ }
+}
+
+static Bool
+miBankCreateGC(
+ GCPtr pGC
+)
+{
+ ScreenPtr pScreen = pGC->pScreen;
+ miBankGCPtr pGCPriv = BANK_GCPRIVATE(pGC);
+ Bool ret;
+
+ SCREEN_INIT;
+ SCREEN_UNWRAP(CreateGC);
+
+ if ((ret = (*pScreen->CreateGC)(pGC)))
+ {
+ pGCPriv->unwrappedOps = &miBankGCOps;
+ pGCPriv->unwrappedFuncs = &miBankGCFuncs;
+ GC_WRAP(pGC);
+
+ memset(&pGCPriv->pBankedClips, 0,
+ pScreenPriv->nBanks * sizeof(pGCPriv->pBankedClips));
+ }
+
+ SCREEN_WRAP(CreateGC, miBankCreateGC);
+
+ return ret;
+}
+
+static void
+miBankPaintWindow(
+ WindowPtr pWin,
+ RegionPtr pRegion,
+ int what
+)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ RegionRec tmpReg;
+ int i;
+ PaintWindowProcPtr PaintWindow;
+
+ SCREEN_INIT;
+ SCREEN_SAVE;
+
+ if (what == PW_BORDER)
+ {
+ SCREEN_UNWRAP(PaintWindowBorder);
+ PaintWindow = pScreen->PaintWindowBorder;
+ }
+ else
+ {
+ SCREEN_UNWRAP(PaintWindowBackground);
+ PaintWindow = pScreen->PaintWindowBackground;
+ }
+
+ if (!IS_BANKED(pWin))
+ {
+ (*PaintWindow)(pWin, pRegion, what);
+ }
+ else
+ {
+ REGION_NULL(pScreen, &tmpReg);
+
+ for (i = 0; i < pScreenPriv->nBanks; i++)
+ {
+ if (!pScreenPriv->pBanks[i])
+ continue;
+
+ REGION_INTERSECT(pScreen, &tmpReg, pRegion,
+ pScreenPriv->pBanks[i]);
+
+ if (REGION_NIL(&tmpReg))
+ continue;
+
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i);
+
+ (*PaintWindow)(pWin, &tmpReg, what);
+ }
+
+ REGION_UNINIT(pScreen, &tmpReg);
+ }
+
+ if (what == PW_BORDER)
+ {
+ SCREEN_WRAP(PaintWindowBorder, miBankPaintWindow);
+ }
+ else
+ {
+ SCREEN_WRAP(PaintWindowBackground, miBankPaintWindow);
+ }
+
+ SCREEN_RESTORE;
+}
+
+static void
+miBankCopyWindow(
+ WindowPtr pWindow,
+ DDXPointRec ptOldOrg,
+ RegionPtr pRgnSrc
+)
+{
+ ScreenPtr pScreen = pWindow->drawable.pScreen;
+ GCPtr pGC;
+ int dx, dy, nBox;
+ DrawablePtr pDrawable = (DrawablePtr)WindowTable[pScreen->myNum];
+ RegionPtr pRgnDst;
+ BoxPtr pBox, pBoxTmp, pBoxNext, pBoxBase, pBoxNew1, pBoxNew2;
+ XID subWindowMode = IncludeInferiors;
+
+ pGC = GetScratchGC(pDrawable->depth, pScreen);
+
+ ChangeGC(pGC, GCSubwindowMode, &subWindowMode);
+ ValidateGC(pDrawable, pGC);
+
+ pRgnDst = REGION_CREATE(pScreen, NULL, 1);
+
+ dx = ptOldOrg.x - pWindow->drawable.x;
+ dy = ptOldOrg.y - pWindow->drawable.y;
+ REGION_TRANSLATE(pScreen, pRgnSrc, -dx, -dy);
+ REGION_INTERSECT(pScreen, pRgnDst, &pWindow->borderClip, pRgnSrc);
+
+ pBox = REGION_RECTS(pRgnDst);
+ nBox = REGION_NUM_RECTS(pRgnDst);
+
+ pBoxNew1 = NULL;
+ pBoxNew2 = NULL;
+
+ if (nBox > 1)
+ {
+ if (dy < 0)
+ {
+ /* Sort boxes from bottom to top */
+ pBoxNew1 = ALLOCATE_LOCAL_ARRAY(BoxRec, nBox);
+
+ if (pBoxNew1)
+ {
+ 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;
+ }
+ }
+
+ if (dx < 0)
+ {
+ /* Sort boxes from right to left */
+ pBoxNew2 = ALLOCATE_LOCAL_ARRAY(BoxRec, nBox);
+
+ if (pBoxNew2)
+ {
+ 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;
+ }
+
+ pBoxNew2 -= nBox;
+ pBox = pBoxNew2;
+ }
+ }
+ }
+
+ while (nBox--)
+ {
+ (*pGC->ops->CopyArea)(pDrawable, pDrawable, pGC,
+ pBox->x1 + dx, pBox->y1 + dy,
+ pBox->x2 - pBox->x1, pBox->y2 - pBox->y1,
+ pBox->x1, pBox->y1);
+
+ pBox++;
+ }
+
+ FreeScratchGC(pGC);
+
+ REGION_DESTROY(pScreen, pRgnDst);
+
+ DEALLOCATE_LOCAL(pBoxNew2);
+ DEALLOCATE_LOCAL(pBoxNew1);
+}
+
+/**************************
+ * Backing store wrappers *
+ **************************/
+
+static void
+miBankSaveAreas(
+ PixmapPtr pPixmap,
+ RegionPtr prgnSave,
+ int xorg,
+ int yorg,
+ WindowPtr pWin
+)
+{
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ RegionRec rgnClipped;
+ int i;
+
+ SCREEN_INIT;
+ SCREEN_SAVE;
+ SCREEN_UNWRAP(BackingStoreFuncs.SaveAreas);
+
+ if (!IS_BANKED(pWin))
+ {
+ (*pScreen->BackingStoreFuncs.SaveAreas)(pPixmap, prgnSave, xorg, yorg,
+ pWin);
+ }
+ else
+ {
+ REGION_NULL(pScreen, &rgnClipped);
+ REGION_TRANSLATE(pScreen, prgnSave, xorg, yorg);
+
+ for (i = 0; i < pScreenPriv->nBanks; i++)
+ {
+ if (!pScreenPriv->pBanks[i])
+ continue;
+
+ REGION_INTERSECT(pScreen, &rgnClipped,
+ prgnSave, pScreenPriv->pBanks[i]);
+
+ if (REGION_NIL(&rgnClipped))
+ continue;
+
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i);
+
+ REGION_TRANSLATE(pScreen, &rgnClipped, -xorg, -yorg);
+
+ (*pScreen->BackingStoreFuncs.SaveAreas)(pPixmap, &rgnClipped,
+ xorg, yorg, pWin);
+ }
+
+ REGION_TRANSLATE(pScreen, prgnSave, -xorg, -yorg);
+ REGION_UNINIT(pScreen, &rgnClipped);
+ }
+
+ SCREEN_WRAP(BackingStoreFuncs.SaveAreas, miBankSaveAreas);
+ SCREEN_RESTORE;
+}
+
+static void
+miBankRestoreAreas(
+ PixmapPtr pPixmap,
+ RegionPtr prgnRestore,
+ int xorg,
+ int yorg,
+ WindowPtr pWin
+)
+{
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ RegionRec rgnClipped;
+ int i;
+
+ SCREEN_INIT;
+ SCREEN_SAVE;
+ SCREEN_UNWRAP(BackingStoreFuncs.RestoreAreas);
+
+ if (!IS_BANKED(pWin))
+ {
+ (*pScreen->BackingStoreFuncs.RestoreAreas)(pPixmap, prgnRestore,
+ xorg, yorg, pWin);
+ }
+ else
+ {
+ REGION_NULL(pScreen, &rgnClipped);
+
+ for (i = 0; i < pScreenPriv->nBanks; i++)
+ {
+ if (!pScreenPriv->pBanks[i])
+ continue;
+
+ REGION_INTERSECT(pScreen, &rgnClipped,
+ prgnRestore, pScreenPriv->pBanks[i]);
+
+ if (REGION_NIL(&rgnClipped))
+ continue;
+
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i);
+
+ (*pScreen->BackingStoreFuncs.RestoreAreas)(pPixmap, &rgnClipped,
+ xorg, yorg, pWin);
+ }
+
+ REGION_UNINIT(pScreen, &rgnClipped);
+ }
+
+ SCREEN_WRAP(BackingStoreFuncs.RestoreAreas, miBankRestoreAreas);
+ SCREEN_RESTORE;
+}
+
+_X_EXPORT Bool
+miInitializeBanking(
+ ScreenPtr pScreen,
+ unsigned int xsize,
+ unsigned int ysize,
+ unsigned int width,
+ miBankInfoPtr pBankInfo
+)
+{
+ miBankScreenPtr pScreenPriv;
+ unsigned long nBitsPerBank, nBitsPerScanline, nPixelsPerScanlinePadUnit;
+ unsigned long BankBase, ServerPad;
+ unsigned int type, iBank, nBanks, maxRects, we, nBankBPP;
+ int i;
+
+ if (!pBankInfo || !pBankInfo->BankSize)
+ return TRUE; /* No banking required */
+
+ /* Sanity checks */
+
+ if (!pScreen || !xsize || !ysize || (xsize > width) ||
+ !pBankInfo->SetSourceBank || !pBankInfo->SetDestinationBank ||
+ !pBankInfo->SetSourceAndDestinationBanks ||
+ !pBankInfo->pBankA || !pBankInfo->pBankB ||
+ !pBankInfo->nBankDepth)
+ return FALSE;
+
+ /*
+ * DDX *must* have registered a pixmap format whose depth is
+ * pBankInfo->nBankDepth. This is not necessarily the rootDepth
+ * pixmap format.
+ */
+ i = 0;
+ while (screenInfo.formats[i].depth != pBankInfo->nBankDepth)
+ if (++i >= screenInfo.numPixmapFormats)
+ return FALSE;
+ nBankBPP = screenInfo.formats[i].bitsPerPixel;
+
+ i = 0;
+ while (screenInfo.formats[i].depth != pScreen->rootDepth)
+ if (++i >= screenInfo.numPixmapFormats)
+ return FALSE;
+
+ if (nBankBPP > screenInfo.formats[i].bitsPerPixel)
+ return FALSE;
+
+ /* Determine banking type */
+ if ((type = miBankDeriveType(pScreen, pBankInfo)) == BANK_NOBANK)
+ return FALSE;
+
+ /* Internal data */
+
+ nBitsPerBank = pBankInfo->BankSize * 8;
+ ServerPad = PixmapBytePad(1, pBankInfo->nBankDepth) * 8;
+ if (nBitsPerBank % ServerPad)
+ return FALSE;
+ nBitsPerScanline = PixmapBytePad(width, pBankInfo->nBankDepth) * 8;
+ nBanks = ((nBitsPerScanline * (ysize - 1)) +
+ (nBankBPP * xsize) + nBitsPerBank - 1) / nBitsPerBank;
+ nPixelsPerScanlinePadUnit = miLCM(ServerPad, nBankBPP) / nBankBPP;
+
+ /* Private areas */
+
+ if (miBankGeneration != serverGeneration)
+ {
+ if (((miBankScreenIndex = AllocateScreenPrivateIndex()) < 0) ||
+ ((miBankGCIndex = AllocateGCPrivateIndex()) < 0))
+ return FALSE;
+
+ miBankGeneration = serverGeneration;
+ }
+
+ if (!AllocateGCPrivate(pScreen, miBankGCIndex,
+ (nBanks * sizeof(RegionPtr)) +
+ (sizeof(miBankGCRec) - sizeof(RegionPtr))))
+ return FALSE;
+
+ if (!(pScreenPriv = (miBankScreenPtr)Xcalloc(sizeof(miBankScreenRec))))
+ return FALSE;
+
+ if (!(pScreenPriv->pBanks = /* Allocate and clear */
+ (RegionPtr *)Xcalloc(nBanks * sizeof(RegionPtr))))
+ {
+ Xfree(pScreenPriv);
+ return FALSE;
+ }
+
+ /*
+ * Translate banks into clipping regions which are themselves clipped
+ * against the screen. This also ensures that pixels with imbedded bank
+ * boundaries are off-screen.
+ */
+
+ BankBase = 0;
+ maxRects = 0;
+ we = 0;
+ for (iBank = 0; iBank < nBanks; iBank++)
+ {
+ xRectangle pRects[3], *pRect = pRects;
+ unsigned int xb, yb, xe, ye;
+
+ xb = ((BankBase + nBankBPP - 1) % nBitsPerScanline) / nBankBPP;
+ yb = (BankBase + nBankBPP - 1) / nBitsPerScanline;
+ if (xb >= xsize)
+ {
+ xb = we = 0;
+ yb++;
+ }
+ if (yb >= ysize)
+ {
+ we = 0;
+ break;
+ }
+
+ if (we)
+ break;
+
+ BankBase += nBitsPerBank;
+
+ we = (BankBase % nBitsPerScanline) % nBankBPP;
+ xe = (BankBase % nBitsPerScanline) / nBankBPP;
+ ye = BankBase / nBitsPerScanline;
+ if (xe >= xsize)
+ {
+ we = xe = 0;
+ ye++;
+ }
+ if (ye >= ysize)
+ {
+ we = xe = 0;
+ ye = ysize;
+ }
+
+ if (yb == ye)
+ {
+ if (xb >= xe)
+ continue;
+
+ pRect->x = xb;
+ pRect->y = yb;
+ pRect->width = xe - xb;
+ pRect->height = 1;
+ maxRects += 2;
+ pRect++;
+ }
+ else
+ {
+ if (xb)
+ {
+ pRect->x = xb;
+ pRect->y = yb++;
+ pRect->width = xsize - xb;
+ pRect->height = 1;
+ maxRects += 2;
+ pRect++;
+ }
+
+ if (yb < ye)
+ {
+ pRect->x = 0;
+ pRect->y = yb;
+ pRect->width = xsize;
+ pRect->height = ye - yb;
+ maxRects += min(pRect->height, 3) + 1;
+ pRect++;
+ }
+
+ if (xe)
+ {
+ pRect->x = 0;
+ pRect->y = ye;
+ pRect->width = xe;
+ pRect->height = 1;
+ maxRects += 2;
+ pRect++;
+ }
+ }
+
+ pScreenPriv->pBanks[iBank] =
+ RECTS_TO_REGION(pScreen, pRect - pRects, pRects, 0);
+ if (!pScreenPriv->pBanks[iBank] ||
+ REGION_NAR(pScreenPriv->pBanks[iBank]))
+ {
+ we = 1;
+ break;
+ }
+ }
+
+ if (we && (iBank < nBanks))
+ {
+ for (i = iBank; i >= 0; i--)
+ if (pScreenPriv->pBanks[i])
+ REGION_DESTROY(pScreen, pScreenPriv->pBanks[i]);
+
+ Xfree(pScreenPriv->pBanks);
+ Xfree(pScreenPriv);
+
+ return FALSE;
+ }
+
+ /* Open for business */
+
+ pScreenPriv->type = type;
+ pScreenPriv->nBanks = nBanks;
+ pScreenPriv->maxRects = maxRects;
+ pScreenPriv->nBankBPP = nBankBPP;
+ pScreenPriv->BankInfo = *pBankInfo;
+ pScreenPriv->nBitsPerBank = nBitsPerBank;
+ pScreenPriv->nBitsPerScanline = nBitsPerScanline;
+ pScreenPriv->nPixelsPerScanlinePadUnit = nPixelsPerScanlinePadUnit;
+
+ SCREEN_WRAP(CreateScreenResources, miBankCreateScreenResources);
+ SCREEN_WRAP(ModifyPixmapHeader, miBankModifyPixmapHeader);
+ SCREEN_WRAP(CloseScreen, miBankCloseScreen);
+ SCREEN_WRAP(GetImage, miBankGetImage);
+ SCREEN_WRAP(GetSpans, miBankGetSpans);
+ SCREEN_WRAP(CreateGC, miBankCreateGC);
+ SCREEN_WRAP(PaintWindowBackground, miBankPaintWindow);
+ SCREEN_WRAP(PaintWindowBorder, miBankPaintWindow);
+ SCREEN_WRAP(CopyWindow, miBankCopyWindow);
+
+ pScreenPriv->BackingStoreFuncs = pScreen->BackingStoreFuncs;
+
+ pScreen->BackingStoreFuncs.SaveAreas = miBankSaveAreas;
+ pScreen->BackingStoreFuncs.RestoreAreas = miBankRestoreAreas;
+ /* ??????????????????????????????????????????????????????????????
+ pScreen->BackingStoreFuncs.SetClipmaskRgn = miBankSetClipmaskRgn;
+ ?????????????????????????????????????????????????????????????? */
+
+ BANK_SCRPRIVLVAL = (pointer)pScreenPriv;
+
+ return TRUE;
+}
+
+/* This is used to force GC revalidation when the banking type is changed */
+/*ARGSUSED*/
+static int
+miBankNewSerialNumber(
+ WindowPtr pWin,
+ pointer unused
+)
+{
+ pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ return WT_WALKCHILDREN;
+}
+
+/* This entry modifies the banking interface */
+_X_EXPORT Bool
+miModifyBanking(
+ ScreenPtr pScreen,
+ miBankInfoPtr pBankInfo
+)
+{
+ unsigned int type;
+
+ if (!pScreen)
+ return FALSE;
+
+ if (miBankGeneration == serverGeneration)
+ {
+ SCREEN_INIT;
+
+ if (pScreenPriv)
+ {
+ if (!pBankInfo || !pBankInfo->BankSize ||
+ !pBankInfo->pBankA || !pBankInfo->pBankB ||
+ !pBankInfo->SetSourceBank || !pBankInfo->SetDestinationBank ||
+ !pBankInfo->SetSourceAndDestinationBanks)
+ return FALSE;
+
+ /* BankSize and nBankDepth cannot, as yet, be changed */
+ if ((pScreenPriv->BankInfo.BankSize != pBankInfo->BankSize) ||
+ (pScreenPriv->BankInfo.nBankDepth != pBankInfo->nBankDepth))
+ return FALSE;
+
+ if ((type = miBankDeriveType(pScreen, pBankInfo)) == BANK_NOBANK)
+ return FALSE;
+
+ /* Reset banking info */
+ pScreenPriv->BankInfo = *pBankInfo;
+ if (type != pScreenPriv->type)
+ {
+ /*
+ * Banking type is changing. Revalidate all window GC's.
+ */
+ pScreenPriv->type = type;
+ WalkTree(pScreen, miBankNewSerialNumber, 0);
+ }
+
+ return TRUE;
+ }
+ }
+
+ if (!pBankInfo || !pBankInfo->BankSize)
+ return TRUE; /* No change requested */
+
+ return FALSE;
+}
+
+/*
+ * Given various screen attributes, determine the minimum scanline width such
+ * that each scanline is server and DDX padded and any pixels with imbedded
+ * bank boundaries are off-screen. This function returns -1 if such a width
+ * cannot exist. This function exists because the DDX needs to be able to
+ * determine this width before initializing a frame buffer.
+ */
+int
+miScanLineWidth(
+ unsigned int xsize, /* pixels */
+ unsigned int ysize, /* pixels */
+ unsigned int width, /* pixels */
+ unsigned long BankSize, /* char's */
+ PixmapFormatRec *pBankFormat,
+ unsigned int nWidthUnit /* bits */
+)
+{
+ unsigned long nBitsPerBank, nBitsPerScanline, nBitsPerScanlinePadUnit;
+ unsigned long minBitsPerScanline, maxBitsPerScanline;
+
+ /* Sanity checks */
+
+ if (!nWidthUnit || !pBankFormat)
+ return -1;
+
+ nBitsPerBank = BankSize * 8;
+ if (nBitsPerBank % pBankFormat->scanlinePad)
+ return -1;
+
+ if (xsize > width)
+ width = xsize;
+ nBitsPerScanlinePadUnit = miLCM(pBankFormat->scanlinePad, nWidthUnit);
+ nBitsPerScanline =
+ (((width * pBankFormat->bitsPerPixel) + nBitsPerScanlinePadUnit - 1) /
+ nBitsPerScanlinePadUnit) * nBitsPerScanlinePadUnit;
+ width = nBitsPerScanline / pBankFormat->bitsPerPixel;
+
+ if (!xsize || !(nBitsPerBank % pBankFormat->bitsPerPixel))
+ return (int)width;
+
+ /*
+ * Scanlines will be server-pad aligned at this point. They will also be
+ * a multiple of nWidthUnit bits long. Ensure that pixels with imbedded
+ * bank boundaries are off-screen.
+ *
+ * It seems reasonable to limit total frame buffer size to 1/16 of the
+ * theoretical maximum address space size. On a machine with 32-bit
+ * addresses (to 8-bit quantities) this turns out to be 256MB. Not only
+ * does this provide a simple limiting condition for the loops below, but
+ * it also prevents unsigned long wraparounds.
+ */
+ if (!ysize)
+ return -1;
+
+ minBitsPerScanline = xsize * pBankFormat->bitsPerPixel;
+ if (minBitsPerScanline > nBitsPerBank)
+ return -1;
+
+ if (ysize == 1)
+ return (int)width;
+
+ maxBitsPerScanline =
+ (((unsigned long)(-1) >> 1) - minBitsPerScanline) / (ysize - 1);
+ while (nBitsPerScanline <= maxBitsPerScanline)
+ {
+ unsigned long BankBase, BankUnit;
+
+ BankUnit = ((nBitsPerBank + nBitsPerScanline - 1) / nBitsPerBank) *
+ nBitsPerBank;
+ if (!(BankUnit % nBitsPerScanline))
+ return (int)width;
+
+ for (BankBase = BankUnit; ; BankBase += nBitsPerBank)
+ {
+ unsigned long x, y;
+
+ y = BankBase / nBitsPerScanline;
+ if (y >= ysize)
+ return (int)width;
+
+ x = BankBase % nBitsPerScanline;
+ if (!(x % pBankFormat->bitsPerPixel))
+ continue;
+
+ if (x < minBitsPerScanline)
+ {
+ /*
+ * Skip ahead certain widths by dividing the excess scanline
+ * amongst the y's.
+ */
+ y *= nBitsPerScanlinePadUnit;
+ nBitsPerScanline +=
+ ((x + y - 1) / y) * nBitsPerScanlinePadUnit;
+ width = nBitsPerScanline / pBankFormat->bitsPerPixel;
+ break;
+ }
+
+ if (BankBase != BankUnit)
+ continue;
+
+ if (!(nBitsPerScanline % x))
+ return (int)width;
+
+ BankBase = ((nBitsPerScanline - minBitsPerScanline) /
+ (nBitsPerScanline - x)) * BankUnit;
+ }
+ }
+
+ return -1;
+}
diff --git a/xserver/mi/mibank.h b/xserver/mi/mibank.h
new file mode 100644
index 000000000..fe93ab41b
--- /dev/null
+++ b/xserver/mi/mibank.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
+ *
+ * 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 Marc Aurele La France not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Marc Aurele La France makes no representations
+ * about the suitability of this software for any purpose. It is provided
+ * "as-is" without express or implied warranty.
+ *
+ * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
+ * EVENT SHALL MARC AURELE LA FRANCE 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.
+ */
+
+
+#ifndef __MIBANK_H__
+#define __MIBANK_H__ 1
+
+#include "scrnintstr.h"
+
+/*
+ * Banking external interface.
+ */
+
+/*
+ * This is the banking function type. The return value is normally zero.
+ * Non-zero returns can be used to implement the likes of scanline interleave,
+ * etc.
+ */
+typedef int miBankProc(
+ ScreenPtr /*pScreen*/,
+ unsigned int /*iBank*/
+);
+
+typedef miBankProc *miBankProcPtr;
+
+typedef struct _miBankInfo
+{
+ /*
+ * Banking refers to the use of one or more apertures (in the server's
+ * address space) to access various parts of a potentially larger hardware
+ * frame buffer.
+ *
+ * Three different banking schemes are supported:
+ *
+ * Single banking is indicated when pBankA and pBankB are equal and all
+ * three miBankProcPtr's point to the same function. Here, both reads and
+ * writes through the aperture access the same hardware location.
+ *
+ * Shared banking is indicated when pBankA and pBankB are equal but the
+ * source and destination functions differ. Here reads through the
+ * aperture do not necessarily access the same hardware location as writes.
+ *
+ * Double banking is indicated when pBankA and pBankB differ. Here two
+ * independent apertures are used to provide read/write access to
+ * potentially different hardware locations.
+ *
+ * Any other combination will result in no banking.
+ */
+ miBankProcPtr SetSourceBank; /* Set pBankA bank number */
+ miBankProcPtr SetDestinationBank; /* Set pBankB bank number */
+ miBankProcPtr SetSourceAndDestinationBanks; /* Set both bank numbers */
+
+ pointer pBankA; /* First aperture location */
+ pointer pBankB; /* First or second aperture location */
+
+ /*
+ * BankSize is in units of sizeof(char) and is the size of each bank.
+ */
+ unsigned long BankSize;
+
+ /*
+ * nBankDepth is the colour depth associated with the maximum number of a
+ * pixel's bits that are simultaneously accessible through the frame buffer
+ * aperture.
+ */
+ unsigned int nBankDepth;
+} miBankInfoRec, *miBankInfoPtr;
+
+Bool
+miInitializeBanking(
+ ScreenPtr /*pScreen*/,
+ unsigned int /*xsize*/,
+ unsigned int /*ysize*/,
+ unsigned int /*width*/,
+ miBankInfoPtr /*pBankInfo*/
+);
+
+Bool
+miModifyBanking(
+ ScreenPtr /*pScreen*/,
+ miBankInfoPtr /*pBankInfo*/
+);
+
+/*
+ * This function determines the minimum screen width, given a initial estimate
+ * and various screen attributes. DDX needs to determine this width before
+ * initializing the screen.
+ */
+int
+miScanLineWidth(
+ unsigned int /*xsize*/,
+ unsigned int /*ysize*/,
+ unsigned int /*width*/,
+ unsigned long /*BankSize*/,
+ PixmapFormatRec * /*pBankFormat*/,
+ unsigned int /*nWidthUnit*/
+);
+
+#endif /* __MIBANK_H__ */
diff --git a/xserver/mi/mibitblt.c b/xserver/mi/mibitblt.c
new file mode 100644
index 000000000..bf0e29ac0
--- /dev/null
+++ b/xserver/mi/mibitblt.c
@@ -0,0 +1,843 @@
+/***********************************************************
+
+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.
+
+******************************************************************/
+/* Author: Todd Newman (aided and abetted by Mr. Drewry) */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/Xprotostr.h>
+
+#include "misc.h"
+#include "gcstruct.h"
+#include "pixmapstr.h"
+#include "windowstr.h"
+#include "scrnintstr.h"
+#include "mi.h"
+#include "regionstr.h"
+#include <X11/Xmd.h>
+#include "servermd.h"
+
+#ifndef HAS_FFS
+extern int ffs(int);
+#endif
+
+/* MICOPYAREA -- public entry for the CopyArea request
+ * For each rectangle in the source region
+ * get the pixels with GetSpans
+ * set them in the destination with SetSpans
+ * We let SetSpans worry about clipping to the destination.
+ */
+_X_EXPORT RegionPtr
+miCopyArea(pSrcDrawable, pDstDrawable,
+ pGC, xIn, yIn, widthSrc, heightSrc, xOut, yOut)
+ register DrawablePtr pSrcDrawable;
+ register DrawablePtr pDstDrawable;
+ GCPtr pGC;
+ int xIn, yIn;
+ int widthSrc, heightSrc;
+ int xOut, yOut;
+{
+ DDXPointPtr ppt, pptFirst;
+ unsigned int *pwidthFirst, *pwidth, *pbits;
+ BoxRec srcBox, *prect;
+ /* may be a new region, or just a copy */
+ RegionPtr prgnSrcClip;
+ /* non-0 if we've created a src clip */
+ RegionPtr prgnExposed;
+ int realSrcClip = 0;
+ int srcx, srcy, dstx, dsty, i, j, y, width, height,
+ xMin, xMax, yMin, yMax;
+ unsigned int *ordering;
+ int numRects;
+ BoxPtr boxes;
+
+ srcx = xIn + pSrcDrawable->x;
+ srcy = yIn + pSrcDrawable->y;
+
+ /* If the destination isn't realized, this is easy */
+ if (pDstDrawable->type == DRAWABLE_WINDOW &&
+ !((WindowPtr)pDstDrawable)->realized)
+ return (RegionPtr)NULL;
+
+ /* clip the source */
+ if (pSrcDrawable->type == DRAWABLE_PIXMAP)
+ {
+ BoxRec box;
+
+ box.x1 = pSrcDrawable->x;
+ box.y1 = pSrcDrawable->y;
+ box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
+ box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
+
+ prgnSrcClip = REGION_CREATE(pGC->pScreen, &box, 1);
+ realSrcClip = 1;
+ }
+ else
+ {
+ if (pGC->subWindowMode == IncludeInferiors) {
+ prgnSrcClip = NotClippedByChildren ((WindowPtr) pSrcDrawable);
+ realSrcClip = 1;
+ } else
+ prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList;
+ }
+
+ /* If the src drawable is a window, we need to translate the srcBox so
+ * that we can compare it with the window's clip region later on. */
+ srcBox.x1 = srcx;
+ srcBox.y1 = srcy;
+ srcBox.x2 = srcx + widthSrc;
+ srcBox.y2 = srcy + heightSrc;
+
+ dstx = xOut;
+ dsty = yOut;
+ if (pGC->miTranslate)
+ {
+ dstx += pDstDrawable->x;
+ dsty += pDstDrawable->y;
+ }
+
+ pptFirst = ppt = (DDXPointPtr)
+ ALLOCATE_LOCAL(heightSrc * sizeof(DDXPointRec));
+ pwidthFirst = pwidth = (unsigned int *)
+ ALLOCATE_LOCAL(heightSrc * sizeof(unsigned int));
+ numRects = REGION_NUM_RECTS(prgnSrcClip);
+ boxes = REGION_RECTS(prgnSrcClip);
+ ordering = (unsigned int *)
+ ALLOCATE_LOCAL(numRects * sizeof(unsigned int));
+ if(!pptFirst || !pwidthFirst || !ordering)
+ {
+ if (ordering)
+ DEALLOCATE_LOCAL(ordering);
+ if (pwidthFirst)
+ DEALLOCATE_LOCAL(pwidthFirst);
+ if (pptFirst)
+ DEALLOCATE_LOCAL(pptFirst);
+ return (RegionPtr)NULL;
+ }
+
+ /* If not the same drawable then order of move doesn't matter.
+ Following assumes that boxes are sorted from top
+ to bottom and left to right.
+ */
+ if ((pSrcDrawable != pDstDrawable) &&
+ ((pGC->subWindowMode != IncludeInferiors) ||
+ (pSrcDrawable->type == DRAWABLE_PIXMAP) ||
+ (pDstDrawable->type == DRAWABLE_PIXMAP)))
+ for (i=0; i < numRects; i++)
+ ordering[i] = i;
+ else { /* within same drawable, must sequence moves carefully! */
+ if (dsty <= srcBox.y1) { /* Scroll up or stationary vertical.
+ Vertical order OK */
+ if (dstx <= srcBox.x1) /* Scroll left or stationary horizontal.
+ Horizontal order OK as well */
+ for (i=0; i < numRects; i++)
+ ordering[i] = i;
+ else { /* scroll right. must reverse horizontal banding of rects. */
+ for (i=0, j=1, xMax=0; i < numRects; j=i+1, xMax=i) {
+ /* find extent of current horizontal band */
+ y=boxes[i].y1; /* band has this y coordinate */
+ while ((j < numRects) && (boxes[j].y1 == y))
+ j++;
+ /* reverse the horizontal band in the output ordering */
+ for (j-- ; j >= xMax; j--, i++)
+ ordering[i] = j;
+ }
+ }
+ }
+ else { /* Scroll down. Must reverse vertical banding. */
+ if (dstx < srcBox.x1) { /* Scroll left. Horizontal order OK. */
+ for (i=numRects-1, j=i-1, yMin=i, yMax=0;
+ i >= 0;
+ j=i-1, yMin=i) {
+ /* find extent of current horizontal band */
+ y=boxes[i].y1; /* band has this y coordinate */
+ while ((j >= 0) && (boxes[j].y1 == y))
+ j--;
+ /* reverse the horizontal band in the output ordering */
+ for (j++ ; j <= yMin; j++, i--, yMax++)
+ ordering[yMax] = 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=numRects-1; i < numRects; i++, j--)
+ ordering[i] = j;
+ }
+ }
+
+ for(i = 0; i < numRects; i++)
+ {
+ prect = &boxes[ordering[i]];
+ xMin = max(prect->x1, srcBox.x1);
+ xMax = min(prect->x2, srcBox.x2);
+ yMin = max(prect->y1, srcBox.y1);
+ yMax = min(prect->y2, srcBox.y2);
+ /* is there anything visible here? */
+ if(xMax <= xMin || yMax <= yMin)
+ continue;
+
+ ppt = pptFirst;
+ pwidth = pwidthFirst;
+ y = yMin;
+ height = yMax - yMin;
+ width = xMax - xMin;
+
+ for(j = 0; j < height; j++)
+ {
+ /* We must untranslate before calling GetSpans */
+ ppt->x = xMin;
+ ppt++->y = y++;
+ *pwidth++ = width;
+ }
+ pbits = (unsigned int *)xalloc(height * PixmapBytePad(width,
+ pSrcDrawable->depth));
+ if (pbits)
+ {
+ (*pSrcDrawable->pScreen->GetSpans)(pSrcDrawable, width, pptFirst,
+ (int *)pwidthFirst, height, (char *)pbits);
+ ppt = pptFirst;
+ pwidth = pwidthFirst;
+ xMin -= (srcx - dstx);
+ y = yMin - (srcy - dsty);
+ for(j = 0; j < height; j++)
+ {
+ ppt->x = xMin;
+ ppt++->y = y++;
+ *pwidth++ = width;
+ }
+
+ (*pGC->ops->SetSpans)(pDstDrawable, pGC, (char *)pbits, pptFirst,
+ (int *)pwidthFirst, height, TRUE);
+ xfree(pbits);
+ }
+ }
+ prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, xIn, yIn,
+ widthSrc, heightSrc, xOut, yOut, (unsigned long)0);
+ if(realSrcClip)
+ REGION_DESTROY(pGC->pScreen, prgnSrcClip);
+
+ DEALLOCATE_LOCAL(ordering);
+ DEALLOCATE_LOCAL(pwidthFirst);
+ DEALLOCATE_LOCAL(pptFirst);
+ return prgnExposed;
+}
+
+/* MIGETPLANE -- gets a bitmap representing one plane of pDraw
+ * A helper used for CopyPlane and XY format GetImage
+ * No clever strategy here, we grab a scanline at a time, pull out the
+ * bits and then stuff them in a 1 bit deep map.
+ */
+/*
+ * This should be replaced with something more general. mi shouldn't have to
+ * care about such things as scanline padding et alia.
+ */
+static
+MiBits *
+miGetPlane(
+ DrawablePtr pDraw,
+ int planeNum, /* number of the bitPlane */
+ int sx,
+ int sy,
+ int w,
+ int h,
+ MiBits *result)
+{
+ int i, j, k, width, bitsPerPixel, widthInBytes;
+ DDXPointRec pt = {0, 0};
+ MiBits pixel;
+ MiBits bit;
+ unsigned char *pCharsOut = NULL;
+
+#if BITMAP_SCANLINE_UNIT == 8
+#define OUT_TYPE unsigned char
+#endif
+#if BITMAP_SCANLINE_UNIT == 16
+#define OUT_TYPE CARD16
+#endif
+#if BITMAP_SCANLINE_UNIT == 32
+#define OUT_TYPE CARD32
+#endif
+#if BITMAP_SCANLINE_UNIT == 64
+#define OUT_TYPE CARD64
+#endif
+
+ OUT_TYPE *pOut;
+ int delta = 0;
+
+ sx += pDraw->x;
+ sy += pDraw->y;
+ widthInBytes = BitmapBytePad(w);
+ if(!result)
+ result = (MiBits *)xalloc(h * widthInBytes);
+ if (!result)
+ return (MiBits *)NULL;
+ bitsPerPixel = pDraw->bitsPerPixel;
+ bzero((char *)result, h * widthInBytes);
+ pOut = (OUT_TYPE *) result;
+ if(bitsPerPixel == 1)
+ {
+ pCharsOut = (unsigned char *) result;
+ width = w;
+ }
+ else
+ {
+ delta = (widthInBytes / (BITMAP_SCANLINE_UNIT / 8)) -
+ (w / BITMAP_SCANLINE_UNIT);
+ width = 1;
+#if IMAGE_BYTE_ORDER == MSBFirst
+ planeNum += (32 - bitsPerPixel);
+#endif
+ }
+ pt.y = sy;
+ for (i = h; --i >= 0; pt.y++)
+ {
+ pt.x = sx;
+ if(bitsPerPixel == 1)
+ {
+ (*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1,
+ (char *)pCharsOut);
+ pCharsOut += widthInBytes;
+ }
+ else
+ {
+ k = 0;
+ for(j = w; --j >= 0; pt.x++)
+ {
+ /* Fetch the next pixel */
+ (*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1,
+ (char *)&pixel);
+ /*
+ * Now get the bit and insert into a bitmap in XY format.
+ */
+ bit = (pixel >> planeNum) & 1;
+#if 0
+ /* XXX assuming bit order == byte order */
+#if BITMAP_BIT_ORDER == LSBFirst
+ bit <<= k;
+#else
+ bit <<= ((BITMAP_SCANLINE_UNIT - 1) - k);
+#endif
+#else
+ /* XXX assuming byte order == LSBFirst */
+ if (screenInfo.bitmapBitOrder == LSBFirst)
+ bit <<= k;
+ else
+ bit <<= ((screenInfo.bitmapScanlineUnit - 1) -
+ (k % screenInfo.bitmapScanlineUnit)) +
+ ((k / screenInfo.bitmapScanlineUnit) *
+ screenInfo.bitmapScanlineUnit);
+#endif
+ *pOut |= (OUT_TYPE) bit;
+ k++;
+ if (k == BITMAP_SCANLINE_UNIT)
+ {
+ pOut++;
+ k = 0;
+ }
+ }
+ pOut += delta;
+ }
+ }
+ return(result);
+
+}
+
+/* MIOPQSTIPDRAWABLE -- use pbits as an opaque stipple for pDraw.
+ * Drawing through the clip mask we SetSpans() the bits into a
+ * bitmap and stipple those bits onto the destination drawable by doing a
+ * PolyFillRect over the whole drawable,
+ * then we invert the bitmap by copying it onto itself with an alu of
+ * GXinvert, invert the foreground/background colors of the gc, and draw
+ * the background bits.
+ * Note how the clipped out bits of the bitmap are always the background
+ * color so that the stipple never causes FillRect to draw them.
+ */
+void
+miOpqStipDrawable(pDraw, pGC, prgnSrc, pbits, srcx, w, h, dstx, dsty)
+ DrawablePtr pDraw;
+ GCPtr pGC;
+ RegionPtr prgnSrc;
+ MiBits *pbits;
+ int srcx, w, h, dstx, dsty;
+{
+ int oldfill, i;
+ unsigned long oldfg;
+ int *pwidth, *pwidthFirst;
+ ChangeGCVal gcv[6];
+ PixmapPtr pStipple, pPixmap;
+ DDXPointRec oldOrg;
+ GCPtr pGCT;
+ DDXPointPtr ppt, pptFirst;
+ xRectangle rect;
+ RegionPtr prgnSrcClip;
+
+ pPixmap = (*pDraw->pScreen->CreatePixmap)
+ (pDraw->pScreen, w + srcx, h, 1);
+ if (!pPixmap)
+ return;
+
+ /* Put the image into a 1 bit deep pixmap */
+ pGCT = GetScratchGC(1, pDraw->pScreen);
+ if (!pGCT)
+ {
+ (*pDraw->pScreen->DestroyPixmap)(pPixmap);
+ return;
+ }
+ /* First set the whole pixmap to 0 */
+ gcv[0].val = 0;
+ dixChangeGC(NullClient, pGCT, GCBackground, NULL, gcv);
+ ValidateGC((DrawablePtr)pPixmap, pGCT);
+ miClearDrawable((DrawablePtr)pPixmap, pGCT);
+ ppt = pptFirst = (DDXPointPtr)ALLOCATE_LOCAL(h * sizeof(DDXPointRec));
+ pwidth = pwidthFirst = (int *)ALLOCATE_LOCAL(h * sizeof(int));
+ if(!pptFirst || !pwidthFirst)
+ {
+ if (pwidthFirst) DEALLOCATE_LOCAL(pwidthFirst);
+ if (pptFirst) DEALLOCATE_LOCAL(pptFirst);
+ FreeScratchGC(pGCT);
+ return;
+ }
+
+ /* we need a temporary region because ChangeClip must be assumed
+ to destroy what it's sent. note that this means we don't
+ have to free prgnSrcClip ourselves.
+ */
+ prgnSrcClip = REGION_CREATE(pGCT->pScreen, NULL, 0);
+ REGION_COPY(pGCT->pScreen, prgnSrcClip, prgnSrc);
+ REGION_TRANSLATE(pGCT->pScreen, prgnSrcClip, srcx, 0);
+ (*pGCT->funcs->ChangeClip)(pGCT, CT_REGION, prgnSrcClip, 0);
+ ValidateGC((DrawablePtr)pPixmap, pGCT);
+
+ /* Since we know pDraw is always a pixmap, we never need to think
+ * about translation here */
+ for(i = 0; i < h; i++)
+ {
+ ppt->x = 0;
+ ppt++->y = i;
+ *pwidth++ = w + srcx;
+ }
+
+ (*pGCT->ops->SetSpans)((DrawablePtr)pPixmap, pGCT, (char *)pbits,
+ pptFirst, pwidthFirst, h, TRUE);
+ DEALLOCATE_LOCAL(pwidthFirst);
+ DEALLOCATE_LOCAL(pptFirst);
+
+
+ /* Save current values from the client GC */
+ oldfill = pGC->fillStyle;
+ pStipple = pGC->stipple;
+ if(pStipple)
+ pStipple->refcnt++;
+ oldOrg = pGC->patOrg;
+
+ /* Set a new stipple in the drawable */
+ gcv[0].val = FillStippled;
+ gcv[1].ptr = pPixmap;
+ gcv[2].val = dstx - srcx;
+ gcv[3].val = dsty;
+
+ dixChangeGC(NullClient, pGC,
+ GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin,
+ NULL, gcv);
+ ValidateGC(pDraw, pGC);
+
+ /* Fill the drawable with the stipple. This will draw the
+ * foreground color whereever 1 bits are set, leaving everything
+ * with 0 bits untouched. Note that the part outside the clip
+ * region is all 0s. */
+ rect.x = dstx;
+ rect.y = dsty;
+ rect.width = w;
+ rect.height = h;
+ (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect);
+
+ /* Invert the tiling pixmap. This sets 0s for 1s and 1s for 0s, only
+ * within the clipping region, the part outside is still all 0s */
+ gcv[0].val = GXinvert;
+ dixChangeGC(NullClient, pGCT, GCFunction, NULL, gcv);
+ ValidateGC((DrawablePtr)pPixmap, pGCT);
+ (*pGCT->ops->CopyArea)((DrawablePtr)pPixmap, (DrawablePtr)pPixmap,
+ pGCT, 0, 0, w + srcx, h, 0, 0);
+
+ /* Swap foreground and background colors on the GC for the drawable.
+ * Now when we fill the drawable, we will fill in the "Background"
+ * values */
+ oldfg = pGC->fgPixel;
+ gcv[0].val = pGC->bgPixel;
+ gcv[1].val = oldfg;
+ gcv[2].ptr = pPixmap;
+ dixChangeGC(NullClient, pGC, GCForeground | GCBackground | GCStipple,
+ NULL, gcv);
+ ValidateGC(pDraw, pGC);
+ /* PolyFillRect might have bashed the rectangle */
+ rect.x = dstx;
+ rect.y = dsty;
+ rect.width = w;
+ rect.height = h;
+ (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect);
+
+ /* Now put things back */
+ if(pStipple)
+ pStipple->refcnt--;
+ gcv[0].val = oldfg;
+ gcv[1].val = pGC->fgPixel;
+ gcv[2].val = oldfill;
+ gcv[3].ptr = pStipple;
+ gcv[4].val = oldOrg.x;
+ gcv[5].val = oldOrg.y;
+ dixChangeGC(NullClient, pGC,
+ GCForeground | GCBackground | GCFillStyle | GCStipple |
+ GCTileStipXOrigin | GCTileStipYOrigin, NULL, gcv);
+
+ ValidateGC(pDraw, pGC);
+ /* put what we hope is a smaller clip region back in the scratch gc */
+ (*pGCT->funcs->ChangeClip)(pGCT, CT_NONE, NULL, 0);
+ FreeScratchGC(pGCT);
+ (*pDraw->pScreen->DestroyPixmap)(pPixmap);
+
+}
+
+/* MICOPYPLANE -- public entry for the CopyPlane request.
+ * strategy:
+ * First build up a bitmap out of the bits requested
+ * build a source clip
+ * Use the bitmap we've built up as a Stipple for the destination
+ */
+_X_EXPORT RegionPtr
+miCopyPlane(pSrcDrawable, pDstDrawable,
+ pGC, srcx, srcy, width, height, dstx, dsty, bitPlane)
+ DrawablePtr pSrcDrawable;
+ DrawablePtr pDstDrawable;
+ GCPtr pGC;
+ int srcx, srcy;
+ int width, height;
+ int dstx, dsty;
+ unsigned long bitPlane;
+{
+ MiBits *ptile;
+ BoxRec box;
+ RegionPtr prgnSrc, prgnExposed;
+
+ /* incorporate the source clip */
+
+ box.x1 = srcx + pSrcDrawable->x;
+ box.y1 = srcy + pSrcDrawable->y;
+ box.x2 = box.x1 + width;
+ box.y2 = box.y1 + height;
+ /* clip to visible drawable */
+ if (box.x1 < pSrcDrawable->x)
+ box.x1 = pSrcDrawable->x;
+ if (box.y1 < pSrcDrawable->y)
+ box.y1 = pSrcDrawable->y;
+ if (box.x2 > pSrcDrawable->x + (int) pSrcDrawable->width)
+ box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
+ if (box.y2 > pSrcDrawable->y + (int) pSrcDrawable->height)
+ box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
+ if (box.x1 > box.x2)
+ box.x2 = box.x1;
+ if (box.y1 > box.y2)
+ box.y2 = box.y1;
+ prgnSrc = REGION_CREATE(pGC->pScreen, &box, 1);
+
+ if (pSrcDrawable->type != DRAWABLE_PIXMAP) {
+ /* clip to visible drawable */
+
+ if (pGC->subWindowMode == IncludeInferiors)
+ {
+ RegionPtr clipList = NotClippedByChildren ((WindowPtr) pSrcDrawable);
+ REGION_INTERSECT(pGC->pScreen, prgnSrc, prgnSrc, clipList);
+ REGION_DESTROY(pGC->pScreen, clipList);
+ } else
+ REGION_INTERSECT(pGC->pScreen, prgnSrc, prgnSrc,
+ &((WindowPtr)pSrcDrawable)->clipList);
+ }
+
+ box = *REGION_EXTENTS(pGC->pScreen, prgnSrc);
+ REGION_TRANSLATE(pGC->pScreen, prgnSrc, -box.x1, -box.y1);
+
+ if ((box.x2 > box.x1) && (box.y2 > box.y1))
+ {
+ /* minimize the size of the data extracted */
+ /* note that we convert the plane mask bitPlane into a plane number */
+ box.x1 -= pSrcDrawable->x;
+ box.x2 -= pSrcDrawable->x;
+ box.y1 -= pSrcDrawable->y;
+ box.y2 -= pSrcDrawable->y;
+ ptile = miGetPlane(pSrcDrawable, ffs(bitPlane) - 1,
+ box.x1, box.y1,
+ box.x2 - box.x1, box.y2 - box.y1,
+ (MiBits *) NULL);
+ if (ptile)
+ {
+ miOpqStipDrawable(pDstDrawable, pGC, prgnSrc, ptile, 0,
+ box.x2 - box.x1, box.y2 - box.y1,
+ dstx + box.x1 - srcx, dsty + box.y1 - srcy);
+ xfree(ptile);
+ }
+ }
+ prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, srcx, srcy,
+ width, height, dstx, dsty, bitPlane);
+ REGION_DESTROY(pGC->pScreen, prgnSrc);
+ return prgnExposed;
+}
+
+/* MIGETIMAGE -- public entry for the GetImage Request
+ * We're getting the image into a memory buffer. While we have to use GetSpans
+ * to read a line from the device (since we don't know what that looks like),
+ * we can just write into the destination buffer
+ *
+ * two different strategies are used, depending on whether we're getting the
+ * image in Z format or XY format
+ * Z format:
+ * Line at a time, GetSpans a line into the destination buffer, then if the
+ * planemask is not all ones, we do a SetSpans into a temporary buffer (to get
+ * bits turned off) and then another GetSpans to get stuff back (because
+ * pixmaps are opaque, and we are passed in the memory to write into). This is
+ * pretty ugly and slow but works. Life is hard.
+ * XY format:
+ * get the single plane specified in planemask
+ */
+_X_EXPORT void
+miGetImage(pDraw, sx, sy, w, h, format, planeMask, pDst)
+ DrawablePtr pDraw;
+ int sx, sy, w, h;
+ unsigned int format;
+ unsigned long planeMask;
+ char * pDst;
+{
+ unsigned char depth;
+ int i, linelength, width, srcx, srcy;
+ DDXPointRec pt = {0, 0};
+ XID gcv[2];
+ PixmapPtr pPixmap = (PixmapPtr)NULL;
+ GCPtr pGC = NULL;
+
+ depth = pDraw->depth;
+ if(format == ZPixmap)
+ {
+ if ( (((1<<depth)-1)&planeMask) != (1<<depth)-1 )
+ {
+ xPoint pt;
+
+ pGC = GetScratchGC(depth, pDraw->pScreen);
+ if (!pGC)
+ return;
+ pPixmap = (*pDraw->pScreen->CreatePixmap)
+ (pDraw->pScreen, w, 1, depth);
+ if (!pPixmap)
+ {
+ FreeScratchGC(pGC);
+ return;
+ }
+ /*
+ * Clear the pixmap before doing anything else
+ */
+ ValidateGC((DrawablePtr)pPixmap, pGC);
+ pt.x = pt.y = 0;
+ width = w;
+ (*pGC->ops->FillSpans)((DrawablePtr)pPixmap, pGC, 1, &pt, &width,
+ TRUE);
+
+ /* alu is already GXCopy */
+ gcv[0] = (XID)planeMask;
+ DoChangeGC(pGC, GCPlaneMask, gcv, 0);
+ ValidateGC((DrawablePtr)pPixmap, pGC);
+ }
+
+ linelength = PixmapBytePad(w, depth);
+ srcx = sx + pDraw->x;
+ srcy = sy + pDraw->y;
+ for(i = 0; i < h; i++)
+ {
+ pt.x = srcx;
+ pt.y = srcy + i;
+ width = w;
+ (*pDraw->pScreen->GetSpans)(pDraw, w, &pt, &width, 1, pDst);
+ if (pPixmap)
+ {
+ pt.x = 0;
+ pt.y = 0;
+ width = w;
+ (*pGC->ops->SetSpans)((DrawablePtr)pPixmap, pGC, pDst,
+ &pt, &width, 1, TRUE);
+ (*pDraw->pScreen->GetSpans)((DrawablePtr)pPixmap, w, &pt,
+ &width, 1, pDst);
+ }
+ pDst += linelength;
+ }
+ if (pPixmap)
+ {
+ (*pGC->pScreen->DestroyPixmap)(pPixmap);
+ FreeScratchGC(pGC);
+ }
+ }
+ else
+ {
+ (void) miGetPlane(pDraw, ffs(planeMask) - 1, sx, sy, w, h,
+ (MiBits *)pDst);
+ }
+}
+
+/* MIPUTIMAGE -- public entry for the PutImage request
+ * Here we benefit from knowing the format of the bits pointed to by pImage,
+ * even if we don't know how pDraw represents them.
+ * Three different strategies are used depending on the format
+ * XYBitmap Format:
+ * we just use the Opaque Stipple helper function to cover the destination
+ * Note that this covers all the planes of the drawable with the
+ * foreground color (masked with the GC planemask) where there are 1 bits
+ * and the background color (masked with the GC planemask) where there are
+ * 0 bits
+ * XYPixmap format:
+ * what we're called with is a series of XYBitmaps, but we only want
+ * each XYPixmap to update 1 plane, instead of updating all of them.
+ * we set the foreground color to be all 1s and the background to all 0s
+ * then for each plane, we set the plane mask to only effect that one
+ * plane and recursive call ourself with the format set to XYBitmap
+ * (This clever idea courtesy of RGD.)
+ * ZPixmap format:
+ * This part is simple, just call SetSpans
+ */
+_X_EXPORT void
+miPutImage(pDraw, pGC, depth, x, y, w, h, leftPad, format, pImage)
+ DrawablePtr pDraw;
+ GCPtr pGC;
+ int depth, x, y, w, h, leftPad;
+ int format;
+ char *pImage;
+{
+ DDXPointPtr pptFirst, ppt;
+ int *pwidthFirst, *pwidth;
+ RegionPtr prgnSrc;
+ BoxRec box;
+ unsigned long oldFg, oldBg;
+ XID gcv[3];
+ unsigned long oldPlanemask;
+ unsigned long i;
+ long bytesPer;
+
+ if (!w || !h)
+ return;
+ switch(format)
+ {
+ case XYBitmap:
+
+ box.x1 = 0;
+ box.y1 = 0;
+ box.x2 = w;
+ box.y2 = h;
+ prgnSrc = REGION_CREATE(pGC->pScreen, &box, 1);
+
+ miOpqStipDrawable(pDraw, pGC, prgnSrc, (MiBits *) pImage,
+ leftPad, w, h, x, y);
+ REGION_DESTROY(pGC->pScreen, prgnSrc);
+ break;
+
+ case XYPixmap:
+ depth = pGC->depth;
+ oldPlanemask = pGC->planemask;
+ oldFg = pGC->fgPixel;
+ oldBg = pGC->bgPixel;
+ gcv[0] = (XID)~0;
+ gcv[1] = (XID)0;
+ DoChangeGC(pGC, GCForeground | GCBackground, gcv, 0);
+ bytesPer = (long)h * BitmapBytePad(w + leftPad);
+
+ for (i = 1 << (depth-1); i != 0; i >>= 1, pImage += bytesPer)
+ {
+ if (i & oldPlanemask)
+ {
+ gcv[0] = (XID)i;
+ DoChangeGC(pGC, GCPlaneMask, gcv, 0);
+ ValidateGC(pDraw, pGC);
+ (*pGC->ops->PutImage)(pDraw, pGC, 1, x, y, w, h, leftPad,
+ XYBitmap, (char *)pImage);
+ }
+ }
+ gcv[0] = (XID)oldPlanemask;
+ gcv[1] = (XID)oldFg;
+ gcv[2] = (XID)oldBg;
+ DoChangeGC(pGC, GCPlaneMask | GCForeground | GCBackground, gcv, 0);
+ ValidateGC(pDraw, pGC);
+ break;
+
+ case ZPixmap:
+ ppt = pptFirst = (DDXPointPtr)ALLOCATE_LOCAL(h * sizeof(DDXPointRec));
+ pwidth = pwidthFirst = (int *)ALLOCATE_LOCAL(h * sizeof(int));
+ if(!pptFirst || !pwidthFirst)
+ {
+ if (pwidthFirst)
+ DEALLOCATE_LOCAL(pwidthFirst);
+ if (pptFirst)
+ DEALLOCATE_LOCAL(pptFirst);
+ return;
+ }
+ if (pGC->miTranslate)
+ {
+ x += pDraw->x;
+ y += pDraw->y;
+ }
+
+ for(i = 0; i < h; i++)
+ {
+ ppt->x = x;
+ ppt->y = y + i;
+ ppt++;
+ *pwidth++ = w;
+ }
+
+ (*pGC->ops->SetSpans)(pDraw, pGC, (char *)pImage, pptFirst,
+ pwidthFirst, h, TRUE);
+ DEALLOCATE_LOCAL(pwidthFirst);
+ DEALLOCATE_LOCAL(pptFirst);
+ break;
+ }
+}
diff --git a/xserver/mi/mibstore.c b/xserver/mi/mibstore.c
new file mode 100644
index 000000000..6653c2345
--- /dev/null
+++ b/xserver/mi/mibstore.c
@@ -0,0 +1,3879 @@
+/***********************************************************
+
+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) \
+{ \
+ register short *srcCopy = (short *)(src); \
+ register short *dstCopy = (short *)(dst); \
+ register int i; \
+ register int bsx = pBackingStore->x; \
+ register 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;
+{
+ CHEAP_FUNC_PROLOGUE (pGC);
+
+ 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;
+
+ CHEAP_FUNC_EPILOGUE (pGC);
+ }
+}
+
+static void
+miBSCheapChangeGC (pGC, mask)
+ GCPtr pGC;
+ unsigned long mask;
+{
+ 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;
+{
+ CHEAP_FUNC_PROLOGUE (pGC);
+
+ (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
+
+ CHEAP_FUNC_EPILOGUE (pGC);
+}
+
+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;
+ register 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 */
+ register int i, j, k, l, y;
+ register 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;
+ register 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;
+ register GCPtr pGC;
+ int shape, mode;
+ register 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;
+{
+ register miBSWindowPtr pBackingStore;
+ register 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;
+ register 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)
+ register 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)
+ register WindowPtr pWin;
+ RegionPtr prgnExposed;
+{
+ PixmapPtr pBackingPixmap;
+ miBSWindowPtr pBackingStore;
+ RegionPtr prgnSaved;
+ RegionPtr prgnRestored;
+ register 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;
+{
+ register miBSWindowPtr pBackingStore;
+ register RegionPtr pSavedRegion;
+ register RegionPtr newSaved, doomed;
+ register 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;
+ register BoxPtr pBox;
+ register int i;
+ register 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);
+}
diff --git a/xserver/mi/mibstore.h b/xserver/mi/mibstore.h
new file mode 100644
index 000000000..23abde26e
--- /dev/null
+++ b/xserver/mi/mibstore.h
@@ -0,0 +1,28 @@
+/*-
+ * mibstore.h --
+ * Header file for users of the MI backing-store scheme.
+ *
+ * Copyright (c) 1987 by the Regents of the University of California
+ *
+ * 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. 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.
+ *
+ */
+
+
+
+#ifndef _MIBSTORE_H
+#define _MIBSTORE_H
+
+#include "screenint.h"
+
+extern void miInitializeBackingStore(
+ ScreenPtr /*pScreen*/
+);
+
+#endif /* _MIBSTORE_H */
diff --git a/xserver/mi/mibstorest.h b/xserver/mi/mibstorest.h
new file mode 100644
index 000000000..ccf4fb701
--- /dev/null
+++ b/xserver/mi/mibstorest.h
@@ -0,0 +1,91 @@
+/*
+ * mibstorest.h
+ *
+ * internal structure definitions for mi backing store
+ */
+
+
+/*
+
+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 "mibstore.h"
+#include "regionstr.h"
+
+/*
+ * One of these structures is allocated per GC used with a backing-store
+ * drawable.
+ */
+
+typedef struct {
+ GCPtr pBackingGC; /* Copy of the GC but with graphicsExposures
+ * set FALSE and the clientClip set to
+ * clip output to the valid regions of the
+ * backing pixmap. */
+ int guarantee; /* GuaranteeNothing, etc. */
+ unsigned long serialNumber; /* clientClip computed time */
+ unsigned long stateChanges; /* changes in parent gc since last copy */
+ GCOps *wrapOps; /* wrapped ops */
+ GCFuncs *wrapFuncs; /* wrapped funcs */
+} miBSGCRec, *miBSGCPtr;
+
+/*
+ * one of these structures is allocated per Window with backing store
+ */
+
+typedef struct {
+ PixmapPtr pBackingPixmap; /* Pixmap for saved areas */
+ short x; /* origin of pixmap relative to window */
+ short y;
+ RegionRec SavedRegion; /* Valid area in pBackingPixmap */
+ char viewable; /* Tracks pWin->viewable so SavedRegion may
+ * be initialized correctly when the window
+ * is first mapped */
+ char status; /* StatusNoPixmap, etc. */
+ char backgroundState; /* background type */
+ PixUnion background; /* background pattern */
+} miBSWindowRec, *miBSWindowPtr;
+
+#define StatusNoPixmap 1 /* pixmap has not been created */
+#define StatusVirtual 2 /* pixmap is virtual, tiled with background */
+#define StatusVDirty 3 /* pixmap is virtual, visiblt has contents */
+#define StatusBadAlloc 4 /* pixmap create failed, do not try again */
+#define StatusContents 5 /* pixmap is created, has valid contents */
+
+typedef struct {
+ /*
+ * screen func wrappers
+ */
+ CloseScreenProcPtr CloseScreen;
+ GetImageProcPtr GetImage;
+ GetSpansProcPtr GetSpans;
+ ChangeWindowAttributesProcPtr ChangeWindowAttributes;
+ CreateGCProcPtr CreateGC;
+ DestroyWindowProcPtr DestroyWindow;
+} miBSScreenRec, *miBSScreenPtr;
diff --git a/xserver/mi/micmap.c b/xserver/mi/micmap.c
new file mode 100644
index 000000000..987affe96
--- /dev/null
+++ b/xserver/mi/micmap.c
@@ -0,0 +1,697 @@
+/************************************************************
+Copyright 1987 by Sun Microsystems, Inc. Mountain View, CA.
+
+ 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 no-
+tice appear in all copies and that both that copyright no-
+tice and this permission notice appear in supporting docu-
+mentation, and that the names of Sun or X Consortium
+not be used in advertising or publicity pertaining to
+distribution of the software without specific prior
+written permission. Sun and X Consortium make no
+representations about the suitability of this software for
+any purpose. It is provided "as is" without any express or
+implied warranty.
+
+SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
+NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI-
+ABLE 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.
+
+********************************************************/
+
+/*
+ * This is based on cfbcmap.c. The functions here are useful independently
+ * of cfb, which is the reason for including them here. How "mi" these
+ * are may be debatable.
+ */
+
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include "scrnintstr.h"
+#include "colormapst.h"
+#include "resource.h"
+#include "globals.h"
+#include "micmap.h"
+
+_X_EXPORT ColormapPtr miInstalledMaps[MAXSCREENS];
+
+static Bool miDoInitVisuals(VisualPtr *visualp, DepthPtr *depthp, int *nvisualp,
+ int *ndepthp, int *rootDepthp, VisualID *defaultVisp,
+ unsigned long sizes, int bitsPerRGB, int preferredVis);
+
+_X_EXPORT miInitVisualsProcPtr miInitVisualsProc = miDoInitVisuals;
+
+_X_EXPORT int
+miListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps)
+{
+ if (miInstalledMaps[pScreen->myNum]) {
+ *pmaps = miInstalledMaps[pScreen->myNum]->mid;
+ return (1);
+ }
+ return 0;
+}
+
+_X_EXPORT void
+miInstallColormap(ColormapPtr pmap)
+{
+ int index = pmap->pScreen->myNum;
+ ColormapPtr oldpmap = miInstalledMaps[index];
+
+ if(pmap != oldpmap)
+ {
+ /* Uninstall pInstalledMap. No hardware changes required, just
+ * notify all interested parties. */
+ if(oldpmap != (ColormapPtr)None)
+ WalkTree(pmap->pScreen, TellLostMap, (char *)&oldpmap->mid);
+ /* Install pmap */
+ miInstalledMaps[index] = pmap;
+ WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid);
+
+ }
+}
+
+_X_EXPORT void
+miUninstallColormap(ColormapPtr pmap)
+{
+ int index = pmap->pScreen->myNum;
+ ColormapPtr curpmap = miInstalledMaps[index];
+
+ if(pmap == curpmap)
+ {
+ if (pmap->mid != pmap->pScreen->defColormap)
+ {
+ curpmap = (ColormapPtr) LookupIDByType(pmap->pScreen->defColormap,
+ RT_COLORMAP);
+ (*pmap->pScreen->InstallColormap)(curpmap);
+ }
+ }
+}
+
+_X_EXPORT void
+miResolveColor(unsigned short *pred, unsigned short *pgreen,
+ unsigned short *pblue, VisualPtr pVisual)
+{
+ int shift = 16 - pVisual->bitsPerRGBValue;
+ unsigned lim = (1 << pVisual->bitsPerRGBValue) - 1;
+
+ if ((pVisual->class | DynamicClass) == GrayScale)
+ {
+ /* rescale to gray then rgb bits */
+ *pred = (30L * *pred + 59L * *pgreen + 11L * *pblue) / 100;
+ *pblue = *pgreen = *pred = ((*pred >> shift) * 65535) / lim;
+ }
+ else
+ {
+ /* rescale to rgb bits */
+ *pred = ((*pred >> shift) * 65535) / lim;
+ *pgreen = ((*pgreen >> shift) * 65535) / lim;
+ *pblue = ((*pblue >> shift) * 65535) / lim;
+ }
+}
+
+_X_EXPORT Bool
+miInitializeColormap(ColormapPtr pmap)
+{
+ register unsigned i;
+ register VisualPtr pVisual;
+ unsigned lim, maxent, shift;
+
+ pVisual = pmap->pVisual;
+ lim = (1 << pVisual->bitsPerRGBValue) - 1;
+ shift = 16 - pVisual->bitsPerRGBValue;
+ maxent = pVisual->ColormapEntries - 1;
+ if (pVisual->class == TrueColor)
+ {
+ unsigned limr, limg, limb;
+
+ limr = pVisual->redMask >> pVisual->offsetRed;
+ limg = pVisual->greenMask >> pVisual->offsetGreen;
+ limb = pVisual->blueMask >> pVisual->offsetBlue;
+ for(i = 0; i <= maxent; i++)
+ {
+ /* rescale to [0..65535] then rgb bits */
+ pmap->red[i].co.local.red =
+ ((((i * 65535) / limr) >> shift) * 65535) / lim;
+ pmap->green[i].co.local.green =
+ ((((i * 65535) / limg) >> shift) * 65535) / lim;
+ pmap->blue[i].co.local.blue =
+ ((((i * 65535) / limb) >> shift) * 65535) / lim;
+ }
+ }
+ else if (pVisual->class == StaticColor)
+ {
+ unsigned limr, limg, limb;
+
+ limr = pVisual->redMask >> pVisual->offsetRed;
+ limg = pVisual->greenMask >> pVisual->offsetGreen;
+ limb = pVisual->blueMask >> pVisual->offsetBlue;
+ for(i = 0; i <= maxent; i++)
+ {
+ /* rescale to [0..65535] then rgb bits */
+ pmap->red[i].co.local.red =
+ ((((((i & pVisual->redMask) >> pVisual->offsetRed)
+ * 65535) / limr) >> shift) * 65535) / lim;
+ pmap->red[i].co.local.green =
+ ((((((i & pVisual->greenMask) >> pVisual->offsetGreen)
+ * 65535) / limg) >> shift) * 65535) / lim;
+ pmap->red[i].co.local.blue =
+ ((((((i & pVisual->blueMask) >> pVisual->offsetBlue)
+ * 65535) / limb) >> shift) * 65535) / lim;
+ }
+ }
+ else if (pVisual->class == StaticGray)
+ {
+ for(i = 0; i <= maxent; i++)
+ {
+ /* rescale to [0..65535] then rgb bits */
+ pmap->red[i].co.local.red = ((((i * 65535) / maxent) >> shift)
+ * 65535) / lim;
+ pmap->red[i].co.local.green = pmap->red[i].co.local.red;
+ pmap->red[i].co.local.blue = pmap->red[i].co.local.red;
+ }
+ }
+ return TRUE;
+}
+
+/* When simulating DirectColor on PseudoColor hardware, multiple
+ entries of the colormap must be updated
+ */
+
+#define AddElement(mask) { \
+ pixel = red | green | blue; \
+ for (i = 0; i < nresult; i++) \
+ if (outdefs[i].pixel == pixel) \
+ break; \
+ if (i == nresult) \
+ { \
+ nresult++; \
+ outdefs[i].pixel = pixel; \
+ outdefs[i].flags = 0; \
+ } \
+ outdefs[i].flags |= (mask); \
+ outdefs[i].red = pmap->red[red >> pVisual->offsetRed].co.local.red; \
+ outdefs[i].green = pmap->green[green >> pVisual->offsetGreen].co.local.green; \
+ outdefs[i].blue = pmap->blue[blue >> pVisual->offsetBlue].co.local.blue; \
+}
+
+_X_EXPORT int
+miExpandDirectColors(ColormapPtr pmap, int ndef, xColorItem *indefs,
+ xColorItem *outdefs)
+{
+ register int red, green, blue;
+ int maxred, maxgreen, maxblue;
+ int stepred, stepgreen, stepblue;
+ VisualPtr pVisual;
+ register int pixel;
+ register int nresult;
+ register int i;
+
+ pVisual = pmap->pVisual;
+
+ stepred = 1 << pVisual->offsetRed;
+ stepgreen = 1 << pVisual->offsetGreen;
+ stepblue = 1 << pVisual->offsetBlue;
+ maxred = pVisual->redMask;
+ maxgreen = pVisual->greenMask;
+ maxblue = pVisual->blueMask;
+ nresult = 0;
+ for (;ndef--; indefs++)
+ {
+ if (indefs->flags & DoRed)
+ {
+ red = indefs->pixel & pVisual->redMask;
+ for (green = 0; green <= maxgreen; green += stepgreen)
+ {
+ for (blue = 0; blue <= maxblue; blue += stepblue)
+ {
+ AddElement (DoRed)
+ }
+ }
+ }
+ if (indefs->flags & DoGreen)
+ {
+ green = indefs->pixel & pVisual->greenMask;
+ for (red = 0; red <= maxred; red += stepred)
+ {
+ for (blue = 0; blue <= maxblue; blue += stepblue)
+ {
+ AddElement (DoGreen)
+ }
+ }
+ }
+ if (indefs->flags & DoBlue)
+ {
+ blue = indefs->pixel & pVisual->blueMask;
+ for (red = 0; red <= maxred; red += stepred)
+ {
+ for (green = 0; green <= maxgreen; green += stepgreen)
+ {
+ AddElement (DoBlue)
+ }
+ }
+ }
+ }
+ return nresult;
+}
+
+_X_EXPORT Bool
+miCreateDefColormap(ScreenPtr pScreen)
+{
+/*
+ * In the following sources PC X server vendors may want to delete
+ * "_not_tog" from "#ifdef WIN32_not_tog"
+ */
+#ifdef WIN32_not_tog
+ /*
+ * these are the MS-Windows desktop colors, adjusted for X's 16-bit
+ * color specifications.
+ */
+ static xColorItem citems[] = {
+ { 0, 0, 0, 0, 0, 0 },
+ { 1, 0x8000, 0, 0, 0, 0 },
+ { 2, 0, 0x8000, 0, 0, 0 },
+ { 3, 0x8000, 0x8000, 0, 0, 0 },
+ { 4, 0, 0, 0x8000, 0, 0 },
+ { 5, 0x8000, 0, 0x8000, 0, 0 },
+ { 6, 0, 0x8000, 0x8000, 0, 0 },
+ { 7, 0xc000, 0xc000, 0xc000, 0, 0 },
+ { 8, 0xc000, 0xdc00, 0xc000, 0, 0 },
+ { 9, 0xa600, 0xca00, 0xf000, 0, 0 },
+ { 246, 0xff00, 0xfb00, 0xf000, 0, 0 },
+ { 247, 0xa000, 0xa000, 0xa400, 0, 0 },
+ { 248, 0x8000, 0x8000, 0x8000, 0, 0 },
+ { 249, 0xff00, 0, 0, 0, 0 },
+ { 250, 0, 0xff00, 0, 0, 0 },
+ { 251, 0xff00, 0xff00, 0, 0, 0 },
+ { 252, 0, 0, 0xff00, 0, 0 },
+ { 253, 0xff00, 0, 0xff00, 0, 0 },
+ { 254, 0, 0xff00, 0xff00, 0, 0 },
+ { 255, 0xff00, 0xff00, 0xff00, 0, 0 }
+ };
+#define NUM_DESKTOP_COLORS sizeof citems / sizeof citems[0]
+ int i;
+#else
+ unsigned short zero = 0, ones = 0xFFFF;
+#endif
+ Pixel wp, bp;
+ VisualPtr pVisual;
+ ColormapPtr cmap;
+ int alloctype;
+
+ for (pVisual = pScreen->visuals;
+ pVisual->vid != pScreen->rootVisual;
+ pVisual++)
+ ;
+
+ if (pScreen->rootDepth == 1 || (pVisual->class & DynamicClass))
+ alloctype = AllocNone;
+ else
+ alloctype = AllocAll;
+
+ if (CreateColormap(pScreen->defColormap, pScreen, pVisual, &cmap,
+ alloctype, 0) != Success)
+ return FALSE;
+
+ if (pScreen->rootDepth > 1) {
+ wp = pScreen->whitePixel;
+ bp = pScreen->blackPixel;
+#ifdef WIN32_not_tog
+ for (i = 0; i < NUM_DESKTOP_COLORS; i++) {
+ if (AllocColor (cmap,
+ &citems[i].red, &citems[i].green, &citems[i].blue,
+ &citems[i].pixel, 0) != Success)
+ return FALSE;
+ }
+#else
+ if ((AllocColor(cmap, &ones, &ones, &ones, &wp, 0) !=
+ Success) ||
+ (AllocColor(cmap, &zero, &zero, &zero, &bp, 0) !=
+ Success))
+ return FALSE;
+ pScreen->whitePixel = wp;
+ pScreen->blackPixel = bp;
+#endif
+ }
+
+ (*pScreen->InstallColormap)(cmap);
+ return TRUE;
+}
+
+/*
+ * Default true color bitmasks, should be overridden by
+ * driver
+ */
+
+#define _RZ(d) ((d + 2) / 3)
+#define _RS(d) 0
+#define _RM(d) ((1 << _RZ(d)) - 1)
+#define _GZ(d) ((d - _RZ(d) + 1) / 2)
+#define _GS(d) _RZ(d)
+#define _GM(d) (((1 << _GZ(d)) - 1) << _GS(d))
+#define _BZ(d) (d - _RZ(d) - _GZ(d))
+#define _BS(d) (_RZ(d) + _GZ(d))
+#define _BM(d) (((1 << _BZ(d)) - 1) << _BS(d))
+#define _CE(d) (1 << _RZ(d))
+
+typedef struct _miVisuals {
+ struct _miVisuals *next;
+ int depth;
+ int bitsPerRGB;
+ int visuals;
+ int count;
+ int preferredCVC;
+ Pixel redMask, greenMask, blueMask;
+} miVisualsRec, *miVisualsPtr;
+
+static int miVisualPriority[] = {
+ PseudoColor, GrayScale, StaticColor, TrueColor, DirectColor, StaticGray
+};
+
+#define NUM_PRIORITY 6
+
+static miVisualsPtr miVisuals;
+
+_X_EXPORT void
+miClearVisualTypes()
+{
+ miVisualsPtr v;
+
+ while ((v = miVisuals)) {
+ miVisuals = v->next;
+ xfree(v);
+ }
+}
+
+
+_X_EXPORT Bool
+miSetVisualTypesAndMasks(int depth, int visuals, int bitsPerRGB,
+ int preferredCVC,
+ Pixel redMask, Pixel greenMask, Pixel blueMask)
+{
+ miVisualsPtr new, *prev, v;
+ int count;
+
+ new = (miVisualsPtr) xalloc (sizeof *new);
+ if (!new)
+ return FALSE;
+ if (!redMask || !greenMask || !blueMask)
+ {
+ redMask = _RM(depth);
+ greenMask = _GM(depth);
+ blueMask = _BM(depth);
+ }
+ new->next = 0;
+ new->depth = depth;
+ new->visuals = visuals;
+ new->bitsPerRGB = bitsPerRGB;
+ new->preferredCVC = preferredCVC;
+ new->redMask = redMask;
+ new->greenMask = greenMask;
+ new->blueMask = blueMask;
+ count = (visuals >> 1) & 033333333333;
+ count = visuals - count - ((count >> 1) & 033333333333);
+ count = (((count + (count >> 3)) & 030707070707) % 077); /* HAKMEM 169 */
+ new->count = count;
+ for (prev = &miVisuals; (v = *prev); prev = &v->next);
+ *prev = new;
+ return TRUE;
+}
+
+_X_EXPORT Bool
+miSetVisualTypes(int depth, int visuals, int bitsPerRGB, int preferredCVC)
+{
+ return miSetVisualTypesAndMasks (depth, visuals, bitsPerRGB,
+ preferredCVC, 0, 0, 0);
+}
+
+_X_EXPORT int
+miGetDefaultVisualMask(int depth)
+{
+ if (depth > MAX_PSEUDO_DEPTH)
+ return LARGE_VISUALS;
+ else if (depth >= MIN_TRUE_DEPTH)
+ return ALL_VISUALS;
+ else if (depth == 1)
+ return StaticGrayMask;
+ else
+ return SMALL_VISUALS;
+}
+
+static Bool
+miVisualTypesSet (int depth)
+{
+ miVisualsPtr visuals;
+
+ for (visuals = miVisuals; visuals; visuals = visuals->next)
+ if (visuals->depth == depth)
+ return TRUE;
+ return FALSE;
+}
+
+_X_EXPORT Bool
+miSetPixmapDepths (void)
+{
+ int d, f;
+
+ /* Add any unlisted depths from the pixmap formats */
+ for (f = 0; f < screenInfo.numPixmapFormats; f++)
+ {
+ d = screenInfo.formats[f].depth;
+ if (!miVisualTypesSet (d))
+ {
+ if (!miSetVisualTypes (d, 0, 0, -1))
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+_X_EXPORT Bool
+miInitVisuals(VisualPtr *visualp, DepthPtr *depthp, int *nvisualp,
+ int *ndepthp, int *rootDepthp, VisualID *defaultVisp,
+ unsigned long sizes, int bitsPerRGB, int preferredVis)
+
+{
+ if (miInitVisualsProc)
+ return miInitVisualsProc(visualp, depthp, nvisualp, ndepthp,
+ rootDepthp, defaultVisp, sizes, bitsPerRGB,
+ preferredVis);
+ else
+ return FALSE;
+}
+
+/*
+ * Distance to least significant one bit
+ */
+static int
+maskShift (Pixel p)
+{
+ int s;
+
+ if (!p) return 0;
+ s = 0;
+ while (!(p & 1))
+ {
+ s++;
+ p >>= 1;
+ }
+ return s;
+}
+
+/*
+ * Given a list of formats for a screen, create a list
+ * of visuals and depths for the screen which corespond to
+ * the set which can be used with this version of cfb.
+ */
+
+static Bool
+miDoInitVisuals(VisualPtr *visualp, DepthPtr *depthp, int *nvisualp,
+ int *ndepthp, int *rootDepthp, VisualID *defaultVisp,
+ unsigned long sizes, int bitsPerRGB, int preferredVis)
+{
+ int i, j = 0, k;
+ VisualPtr visual;
+ DepthPtr depth;
+ VisualID *vid;
+ int d, b;
+ int f;
+ int ndepth, nvisual;
+ int nvtype;
+ int vtype;
+ miVisualsPtr visuals, nextVisuals;
+ int *preferredCVCs, *prefp;
+ int first_depth;
+
+ /* none specified, we'll guess from pixmap formats */
+ if (!miVisuals)
+ {
+ for (f = 0; f < screenInfo.numPixmapFormats; f++)
+ {
+ d = screenInfo.formats[f].depth;
+ b = screenInfo.formats[f].bitsPerPixel;
+ if (sizes & (1 << (b - 1)))
+ vtype = miGetDefaultVisualMask(d);
+ else
+ vtype = 0;
+ if (!miSetVisualTypes (d, vtype, bitsPerRGB, -1))
+ return FALSE;
+ }
+ }
+ nvisual = 0;
+ ndepth = 0;
+ for (visuals = miVisuals; visuals; visuals = nextVisuals)
+ {
+ nextVisuals = visuals->next;
+ ndepth++;
+ nvisual += visuals->count;
+ }
+ depth = (DepthPtr) xalloc (ndepth * sizeof (DepthRec));
+ visual = (VisualPtr) xalloc (nvisual * sizeof (VisualRec));
+ preferredCVCs = (int *)xalloc(ndepth * sizeof(int));
+ if (!depth || !visual || !preferredCVCs)
+ {
+ xfree (depth);
+ xfree (visual);
+ xfree (preferredCVCs);
+ return FALSE;
+ }
+ *depthp = depth;
+ *visualp = visual;
+ *ndepthp = ndepth;
+ *nvisualp = nvisual;
+ prefp = preferredCVCs;
+ for (visuals = miVisuals; visuals; visuals = nextVisuals)
+ {
+ nextVisuals = visuals->next;
+ d = visuals->depth;
+ vtype = visuals->visuals;
+ nvtype = visuals->count;
+ *prefp = visuals->preferredCVC;
+ prefp++;
+ vid = NULL;
+ if (nvtype)
+ {
+ vid = (VisualID *) xalloc (nvtype * sizeof (VisualID));
+ if (!vid) {
+ xfree(preferredCVCs);
+ return FALSE;
+ }
+ }
+ depth->depth = d;
+ depth->numVids = nvtype;
+ depth->vids = vid;
+ depth++;
+ for (i = 0; i < NUM_PRIORITY; i++) {
+ if (! (vtype & (1 << miVisualPriority[i])))
+ continue;
+ visual->class = miVisualPriority[i];
+ visual->bitsPerRGBValue = visuals->bitsPerRGB;
+ visual->ColormapEntries = 1 << d;
+ visual->nplanes = d;
+ visual->vid = *vid = FakeClientID (0);
+ switch (visual->class) {
+ case PseudoColor:
+ case GrayScale:
+ case StaticGray:
+ visual->redMask = 0;
+ visual->greenMask = 0;
+ visual->blueMask = 0;
+ visual->offsetRed = 0;
+ visual->offsetGreen = 0;
+ visual->offsetBlue = 0;
+ break;
+ case DirectColor:
+ case TrueColor:
+ visual->ColormapEntries = _CE(d);
+ /* fall through */
+ case StaticColor:
+ visual->redMask = visuals->redMask;
+ visual->greenMask = visuals->greenMask;
+ visual->blueMask = visuals->blueMask;
+ visual->offsetRed = maskShift (visuals->redMask);
+ visual->offsetGreen = maskShift (visuals->greenMask);
+ visual->offsetBlue = maskShift (visuals->blueMask);
+ }
+ vid++;
+ visual++;
+ }
+ xfree (visuals);
+ }
+ miVisuals = NULL;
+ visual = *visualp;
+ depth = *depthp;
+
+ /*
+ * if we did not supplyied by a preferred visual class
+ * check if there is a preferred class in one of the depth
+ * structures - if there is, we want to start looking for the
+ * default visual/depth from that depth.
+ */
+ first_depth = 0;
+ if (preferredVis < 0 && defaultColorVisualClass < 0 ) {
+ for (i = 0; i < ndepth; i++) {
+ if (preferredCVCs[i] >= 0) {
+ first_depth = i;
+ break;
+ }
+ }
+ }
+
+ for (i = first_depth; i < ndepth; i++)
+ {
+ int prefColorVisualClass = -1;
+
+ if (defaultColorVisualClass >= 0)
+ prefColorVisualClass = defaultColorVisualClass;
+ else if (preferredVis >= 0)
+ prefColorVisualClass = preferredVis;
+ else if (preferredCVCs[i] >= 0)
+ prefColorVisualClass = preferredCVCs[i];
+
+ if (*rootDepthp && *rootDepthp != depth[i].depth)
+ continue;
+
+ for (j = 0; j < depth[i].numVids; j++)
+ {
+ for (k = 0; k < nvisual; k++)
+ if (visual[k].vid == depth[i].vids[j])
+ break;
+ if (k == nvisual)
+ continue;
+ if (prefColorVisualClass < 0 ||
+ visual[k].class == prefColorVisualClass)
+ break;
+ }
+ if (j != depth[i].numVids)
+ break;
+ }
+ if (i == ndepth) {
+ i = 0;
+ j = 0;
+ }
+ *rootDepthp = depth[i].depth;
+ *defaultVisp = depth[i].vids[j];
+ xfree(preferredCVCs);
+
+ return TRUE;
+}
+
+void
+miResetInitVisuals()
+{
+ miInitVisualsProc = miDoInitVisuals;
+}
+
diff --git a/xserver/mi/micmap.h b/xserver/mi/micmap.h
new file mode 100644
index 000000000..9ee9f4ae4
--- /dev/null
+++ b/xserver/mi/micmap.h
@@ -0,0 +1,64 @@
+
+#include "colormapst.h"
+
+#ifndef _MICMAP_H_
+#define _MICMAP_H_
+
+extern ColormapPtr miInstalledMaps[MAXSCREENS];
+
+typedef Bool (* miInitVisualsProcPtr)(VisualPtr *, DepthPtr *, int *, int *,
+ int *, VisualID *, unsigned long, int,
+ int);
+
+extern miInitVisualsProcPtr miInitVisualsProc;
+
+int miListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps);
+void miInstallColormap(ColormapPtr pmap);
+void miUninstallColormap(ColormapPtr pmap);
+
+void miResolveColor(unsigned short *, unsigned short *, unsigned short *,
+ VisualPtr);
+Bool miInitializeColormap(ColormapPtr);
+int miExpandDirectColors(ColormapPtr, int, xColorItem *, xColorItem *);
+Bool miCreateDefColormap(ScreenPtr);
+void miClearVisualTypes(void);
+Bool miSetVisualTypes(int, int, int, int);
+Bool miSetPixmapDepths(void);
+Bool miSetVisualTypesAndMasks(int depth, int visuals, int bitsPerRGB,
+ int preferredCVC,
+ Pixel redMask, Pixel greenMask, Pixel blueMask);
+int miGetDefaultVisualMask(int);
+Bool miInitVisuals(VisualPtr *, DepthPtr *, int *, int *, int *, VisualID *,
+ unsigned long, int, int);
+void miResetInitVisuals(void);
+
+void miHookInitVisuals(void (**old)(miInitVisualsProcPtr *),
+ void (*new)(miInitVisualsProcPtr *));
+
+
+#define MAX_PSEUDO_DEPTH 10
+#define MIN_TRUE_DEPTH 6
+
+#define StaticGrayMask (1 << StaticGray)
+#define GrayScaleMask (1 << GrayScale)
+#define StaticColorMask (1 << StaticColor)
+#define PseudoColorMask (1 << PseudoColor)
+#define TrueColorMask (1 << TrueColor)
+#define DirectColorMask (1 << DirectColor)
+
+#define ALL_VISUALS (StaticGrayMask|\
+ GrayScaleMask|\
+ StaticColorMask|\
+ PseudoColorMask|\
+ TrueColorMask|\
+ DirectColorMask)
+
+#define LARGE_VISUALS (TrueColorMask|\
+ DirectColorMask)
+
+#define SMALL_VISUALS (StaticGrayMask|\
+ GrayScaleMask|\
+ StaticColorMask|\
+ PseudoColorMask)
+
+#endif /* _MICMAP_H_ */
diff --git a/xserver/mi/micoord.h b/xserver/mi/micoord.h
new file mode 100644
index 000000000..b3d725b73
--- /dev/null
+++ b/xserver/mi/micoord.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2000 The XFree86 Project, 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, 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 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
+ * XFREE86 PROJECT 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 XFree86 Project 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
+ * XFree86 Project.
+ *
+ */
+
+#ifndef _MICOORD_H_
+#define _MICOORD_H_ 1
+
+#include "servermd.h"
+
+/* Macros which handle a coordinate in a single register */
+
+/*
+ * Most compilers will convert divisions by 65536 into shifts, if signed
+ * shifts exist. If your machine does arithmetic shifts and your compiler
+ * can't get it right, add to this line.
+ */
+
+/*
+ * mips compiler - what a joke - it CSEs the 65536 constant into a reg
+ * forcing as to use div instead of shift. Let's be explicit.
+ */
+
+#if defined(mips) || defined(sgi) || \
+ defined(sparc) || defined(__sparc64__) || \
+ defined(__alpha) || defined(__alpha__) || \
+ defined(__i386__) || defined(i386) || \
+ defined(__ia64__) || defined(ia64) || \
+ defined(__s390x__) || defined(__s390__) || \
+ defined(__amd64__) || defined(amd64) || defined(__amd64)
+#define GetHighWord(x) (((int) (x)) >> 16)
+#else
+#define GetHighWord(x) (((int) (x)) / 65536)
+#endif
+
+#if IMAGE_BYTE_ORDER == MSBFirst
+#define intToCoord(i,x,y) (((x) = GetHighWord(i)), ((y) = (int) ((short) (i))))
+#define coordToInt(x,y) (((x) << 16) | ((y) & 0xffff))
+#define intToX(i) (GetHighWord(i))
+#define intToY(i) ((int) ((short) i))
+#else
+#define intToCoord(i,x,y) (((x) = (int) ((short) (i))), ((y) = GetHighWord(i)))
+#define coordToInt(x,y) (((y) << 16) | ((x) & 0xffff))
+#define intToX(i) ((int) ((short) (i)))
+#define intToY(i) (GetHighWord(i))
+#endif
+
+#endif /* _MICOORD_H_ */
diff --git a/xserver/mi/micursor.c b/xserver/mi/micursor.c
new file mode 100644
index 000000000..6e06fbc07
--- /dev/null
+++ b/xserver/mi/micursor.c
@@ -0,0 +1,75 @@
+/***********************************************************
+
+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 "scrnintstr.h"
+#include "cursor.h"
+#include "misc.h"
+#include "mi.h"
+
+extern Bool Must_have_memory;
+
+_X_EXPORT void
+miRecolorCursor( pScr, pCurs, displayed)
+ ScreenPtr pScr;
+ CursorPtr pCurs;
+ Bool displayed;
+{
+ /*
+ * This is guaranteed to correct any color-dependent state which may have
+ * been bound up in private state created by RealizeCursor
+ */
+ (* pScr->UnrealizeCursor)( pScr, pCurs);
+ Must_have_memory = TRUE; /* XXX */
+ (* pScr->RealizeCursor)( pScr, pCurs);
+ Must_have_memory = FALSE; /* XXX */
+ if ( displayed)
+ (* pScr->DisplayCursor)( pScr, pCurs);
+
+}
diff --git a/xserver/mi/midash.c b/xserver/mi/midash.c
new file mode 100644
index 000000000..6dd161a39
--- /dev/null
+++ b/xserver/mi/midash.c
@@ -0,0 +1,313 @@
+/***********************************************************
+
+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 "regionstr.h"
+#include "mistruct.h"
+#include "mifpoly.h"
+
+static miDashPtr CheckDashStorage(miDashPtr *ppseg, int nseg, int *pnsegMax);
+
+/* return a list of DashRec. there will be an extra
+entry at the end holding the last point of the polyline.
+ this means that the code that actually draws dashes can
+get a pair of points for every dash. only the point in the last
+dash record is useful; the other fields are not used.
+ nseg is the number of segments, not the number of points.
+
+example:
+
+ dash1.start
+ dash2.start
+ dash3.start
+ last-point
+
+defines a list of segments
+ (dash1.pt, dash2.pt)
+ (dash2.pt, dash3.pt)
+ (dash3.pt, last-point)
+and nseg == 3.
+
+NOTE:
+ EVEN_DASH == ~ODD_DASH
+
+NOTE ALSO:
+ miDashLines may return 0 segments, going from pt[0] to pt[0] with one dash.
+*/
+
+miDashPtr
+miDashLine(npt, ppt, nDash, pDash, offset, pnseg)
+int npt;
+DDXPointPtr ppt;
+unsigned int nDash;
+unsigned char *pDash;
+unsigned int offset;
+int *pnseg;
+{
+ DDXPointRec pt1, pt2;
+ int lenCur; /* npt used from this dash */
+ int lenMax; /* npt in this dash */
+ int iDash = 0; /* index of current dash */
+ int which; /* EVEN_DASH or ODD_DASH */
+ miDashPtr pseg; /* list of dash segments */
+ miDashPtr psegBase; /* start of list */
+ int nseg = 0; /* number of dashes so far */
+ int nsegMax = 0; /* num segs we can fit in this list */
+
+ int x, y, len;
+ int adx, ady, signdx, signdy;
+ int du, dv, e1, e2, e, base_e = 0;
+
+ lenCur = offset;
+ which = EVEN_DASH;
+ while(lenCur >= pDash[iDash])
+ {
+ lenCur -= pDash[iDash];
+ iDash++;
+ if (iDash >= nDash)
+ iDash = 0;
+ which = ~which;
+ }
+ lenMax = pDash[iDash];
+
+ psegBase = (miDashPtr)NULL;
+ pt2 = ppt[0]; /* just in case there is only one point */
+
+ while(--npt)
+ {
+ if (PtEqual(ppt[0], ppt[1]))
+ {
+ ppt++;
+ continue; /* no duplicated points in polyline */
+ }
+ pt1 = *ppt++;
+ pt2 = *ppt;
+
+ adx = pt2.x - pt1.x;
+ ady = pt2.y - pt1.y;
+ signdx = sign(adx);
+ signdy = sign(ady);
+ adx = abs(adx);
+ ady = abs(ady);
+
+ if (adx > ady)
+ {
+ du = adx;
+ dv = ady;
+ len = adx;
+ }
+ else
+ {
+ du = ady;
+ dv = adx;
+ len = ady;
+ }
+
+ e1 = dv * 2;
+ e2 = e1 - 2*du;
+ e = e1 - du;
+ x = pt1.x;
+ y = pt1.y;
+
+ nseg++;
+ pseg = CheckDashStorage(&psegBase, nseg, &nsegMax);
+ if (!pseg)
+ return (miDashPtr)NULL;
+ pseg->pt = pt1;
+ pseg->e1 = e1;
+ pseg->e2 = e2;
+ base_e = pseg->e = e;
+ pseg->which = which;
+ pseg->newLine = 1;
+
+ while (len--)
+ {
+ if (adx > ady)
+ {
+ /* X_AXIS */
+ if (((signdx > 0) && (e < 0)) ||
+ ((signdx <=0) && (e <=0))
+ )
+ {
+ e += e1;
+ }
+ else
+ {
+ y += signdy;
+ e += e2;
+ }
+ x += signdx;
+ }
+ else
+ {
+ /* Y_AXIS */
+ if (((signdx > 0) && (e < 0)) ||
+ ((signdx <=0) && (e <=0))
+ )
+ {
+ e +=e1;
+ }
+ else
+ {
+ x += signdx;
+ e += e2;
+ }
+ y += signdy;
+ }
+
+ lenCur++;
+ if (lenCur >= lenMax && (len || npt <= 1))
+ {
+ nseg++;
+ pseg = CheckDashStorage(&psegBase, nseg, &nsegMax);
+ if (!pseg)
+ return (miDashPtr)NULL;
+ pseg->pt.x = x;
+ pseg->pt.y = y;
+ pseg->e1 = e1;
+ pseg->e2 = e2;
+ pseg->e = e;
+ which = ~which;
+ pseg->which = which;
+ pseg->newLine = 0;
+
+ /* move on to next dash */
+ iDash++;
+ if (iDash >= nDash)
+ iDash = 0;
+ lenMax = pDash[iDash];
+ lenCur = 0;
+ }
+ } /* while len-- */
+ } /* while --npt */
+
+ if (lenCur == 0 && nseg != 0)
+ {
+ nseg--;
+ which = ~which;
+ }
+ *pnseg = nseg;
+ pseg = CheckDashStorage(&psegBase, nseg+1, &nsegMax);
+ if (!pseg)
+ return (miDashPtr)NULL;
+ pseg->pt = pt2;
+ pseg->e = base_e;
+ pseg->which = which;
+ pseg->newLine = 0;
+ return psegBase;
+}
+
+
+#define NSEGDELTA 16
+
+/* returns a pointer to the pseg[nseg-1], growing the storage as
+necessary. this interface seems unnecessarily cumbersome.
+
+*/
+
+static
+miDashPtr
+CheckDashStorage(
+ miDashPtr *ppseg, /* base pointer */
+ int nseg, /* number of segment we want to write to */
+ int *pnsegMax) /* size (in segments) of list so far */
+{
+ if (nseg > *pnsegMax)
+ {
+ miDashPtr newppseg;
+
+ *pnsegMax += NSEGDELTA;
+ newppseg = (miDashPtr)xrealloc(*ppseg,
+ (*pnsegMax)*sizeof(miDashRec));
+ if (!newppseg)
+ {
+ xfree(*ppseg);
+ return (miDashPtr)NULL;
+ }
+ *ppseg = newppseg;
+ }
+ return(*ppseg+(nseg-1));
+}
+
+_X_EXPORT void
+miStepDash (dist, pDashIndex, pDash, numInDashList, pDashOffset)
+ int dist; /* distance to step */
+ int *pDashIndex; /* current dash */
+ unsigned char *pDash; /* dash list */
+ int numInDashList; /* total length of dash list */
+ int *pDashOffset; /* offset into current dash */
+{
+ int dashIndex, dashOffset;
+ int totallen;
+ int i;
+
+ dashIndex = *pDashIndex;
+ dashOffset = *pDashOffset;
+ if (dist < pDash[dashIndex] - dashOffset)
+ {
+ *pDashOffset = dashOffset + dist;
+ return;
+ }
+ dist -= pDash[dashIndex] - dashOffset;
+ if (++dashIndex == numInDashList)
+ dashIndex = 0;
+ totallen = 0;
+ for (i = 0; i < numInDashList; i++)
+ totallen += pDash[i];
+ if (totallen <= dist)
+ dist = dist % totallen;
+ while (dist >= pDash[dashIndex])
+ {
+ dist -= pDash[dashIndex];
+ if (++dashIndex == numInDashList)
+ dashIndex = 0;
+ }
+ *pDashIndex = dashIndex;
+ *pDashOffset = dist;
+}
diff --git a/xserver/mi/midispcur.c b/xserver/mi/midispcur.c
new file mode 100644
index 000000000..de009cbaf
--- /dev/null
+++ b/xserver/mi/midispcur.c
@@ -0,0 +1,816 @@
+/*
+ * midispcur.c
+ *
+ * machine independent cursor display 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
+
+#define NEED_EVENTS
+# include <X11/X.h>
+# include "misc.h"
+# include "input.h"
+# include "cursorstr.h"
+# include "windowstr.h"
+# include "regionstr.h"
+# include "dixstruct.h"
+# include "scrnintstr.h"
+# include "servermd.h"
+# include "mipointer.h"
+# include "misprite.h"
+# include "gcstruct.h"
+
+#ifdef ARGB_CURSOR
+# include "picturestr.h"
+#endif
+
+/* per-screen private data */
+
+static int miDCScreenIndex;
+static unsigned long miDCGeneration = 0;
+
+static Bool miDCCloseScreen(int index, ScreenPtr pScreen);
+
+typedef struct {
+ GCPtr pSourceGC, pMaskGC;
+ GCPtr pSaveGC, pRestoreGC;
+ GCPtr pMoveGC;
+ GCPtr pPixSourceGC, pPixMaskGC;
+ CloseScreenProcPtr CloseScreen;
+ PixmapPtr pSave, pTemp;
+#ifdef ARGB_CURSOR
+ PicturePtr pRootPicture;
+ PicturePtr pTempPicture;
+#endif
+} miDCScreenRec, *miDCScreenPtr;
+
+/* per-cursor per-screen private data */
+typedef struct {
+ PixmapPtr sourceBits; /* source bits */
+ PixmapPtr maskBits; /* mask bits */
+#ifdef ARGB_CURSOR
+ PicturePtr pPicture;
+#endif
+} miDCCursorRec, *miDCCursorPtr;
+
+/*
+ * sprite/cursor method table
+ */
+
+static Bool miDCRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor);
+static Bool miDCUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor);
+static Bool miDCPutUpCursor(ScreenPtr pScreen, CursorPtr pCursor,
+ int x, int y, unsigned long source,
+ unsigned long mask);
+static Bool miDCSaveUnderCursor(ScreenPtr pScreen, int x, int y,
+ int w, int h);
+static Bool miDCRestoreUnderCursor(ScreenPtr pScreen, int x, int y,
+ int w, int h);
+static Bool miDCMoveCursor(ScreenPtr pScreen, CursorPtr pCursor,
+ int x, int y, int w, int h, int dx, int dy,
+ unsigned long source, unsigned long mask);
+static Bool miDCChangeSave(ScreenPtr pScreen, int x, int y, int w, int h,
+ int dx, int dy);
+
+static miSpriteCursorFuncRec miDCFuncs = {
+ miDCRealizeCursor,
+ miDCUnrealizeCursor,
+ miDCPutUpCursor,
+ miDCSaveUnderCursor,
+ miDCRestoreUnderCursor,
+ miDCMoveCursor,
+ miDCChangeSave,
+};
+
+_X_EXPORT Bool
+miDCInitialize (pScreen, screenFuncs)
+ ScreenPtr pScreen;
+ miPointerScreenFuncPtr screenFuncs;
+{
+ miDCScreenPtr pScreenPriv;
+
+ if (miDCGeneration != serverGeneration)
+ {
+ miDCScreenIndex = AllocateScreenPrivateIndex ();
+ if (miDCScreenIndex < 0)
+ return FALSE;
+ miDCGeneration = serverGeneration;
+ }
+ pScreenPriv = (miDCScreenPtr) xalloc (sizeof (miDCScreenRec));
+ if (!pScreenPriv)
+ return FALSE;
+
+ /*
+ * initialize the entire private structure to zeros
+ */
+
+ pScreenPriv->pSourceGC =
+ pScreenPriv->pMaskGC =
+ pScreenPriv->pSaveGC =
+ pScreenPriv->pRestoreGC =
+ pScreenPriv->pMoveGC =
+ pScreenPriv->pPixSourceGC =
+ pScreenPriv->pPixMaskGC = NULL;
+#ifdef ARGB_CURSOR
+ pScreenPriv->pRootPicture = NULL;
+ pScreenPriv->pTempPicture = NULL;
+#endif
+
+ pScreenPriv->pSave = pScreenPriv->pTemp = NULL;
+
+ pScreenPriv->CloseScreen = pScreen->CloseScreen;
+ pScreen->CloseScreen = miDCCloseScreen;
+
+ pScreen->devPrivates[miDCScreenIndex].ptr = (pointer) pScreenPriv;
+
+ if (!miSpriteInitialize (pScreen, &miDCFuncs, screenFuncs))
+ {
+ xfree ((pointer) pScreenPriv);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+#define tossGC(gc) (gc ? FreeGC (gc, (GContext) 0) : 0)
+#define tossPix(pix) (pix ? (*pScreen->DestroyPixmap) (pix) : TRUE)
+#define tossPict(pict) (pict ? FreePicture (pict, 0) : 0)
+
+static Bool
+miDCCloseScreen (index, pScreen)
+ int index;
+ ScreenPtr pScreen;
+{
+ miDCScreenPtr pScreenPriv;
+
+ pScreenPriv = (miDCScreenPtr) pScreen->devPrivates[miDCScreenIndex].ptr;
+ pScreen->CloseScreen = pScreenPriv->CloseScreen;
+ tossGC (pScreenPriv->pSourceGC);
+ tossGC (pScreenPriv->pMaskGC);
+ tossGC (pScreenPriv->pSaveGC);
+ tossGC (pScreenPriv->pRestoreGC);
+ tossGC (pScreenPriv->pMoveGC);
+ tossGC (pScreenPriv->pPixSourceGC);
+ tossGC (pScreenPriv->pPixMaskGC);
+ tossPix (pScreenPriv->pSave);
+ tossPix (pScreenPriv->pTemp);
+#ifdef ARGB_CURSOR
+#if 0 /* This has been free()d before */
+ tossPict (pScreenPriv->pRootPicture);
+#endif
+ tossPict (pScreenPriv->pTempPicture);
+#endif
+ xfree ((pointer) pScreenPriv);
+ return (*pScreen->CloseScreen) (index, pScreen);
+}
+
+static Bool
+miDCRealizeCursor (pScreen, pCursor)
+ ScreenPtr pScreen;
+ CursorPtr pCursor;
+{
+ if (pCursor->bits->refcnt <= 1)
+ pCursor->bits->devPriv[pScreen->myNum] = (pointer)NULL;
+ return TRUE;
+}
+
+#ifdef ARGB_CURSOR
+#define EnsurePicture(picture,draw,win) (picture || miDCMakePicture(&picture,draw,win))
+
+static VisualPtr
+miDCGetWindowVisual (WindowPtr pWin)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ VisualID vid = wVisual (pWin);
+ int i;
+
+ for (i = 0; i < pScreen->numVisuals; i++)
+ if (pScreen->visuals[i].vid == vid)
+ return &pScreen->visuals[i];
+ return 0;
+}
+
+static PicturePtr
+miDCMakePicture (PicturePtr *ppPicture, DrawablePtr pDraw, WindowPtr pWin)
+{
+ ScreenPtr pScreen = pDraw->pScreen;
+ VisualPtr pVisual;
+ PictFormatPtr pFormat;
+ XID subwindow_mode = IncludeInferiors;
+ PicturePtr pPicture;
+ int error;
+
+ pVisual = miDCGetWindowVisual (pWin);
+ if (!pVisual)
+ return 0;
+ pFormat = PictureMatchVisual (pScreen, pDraw->depth, pVisual);
+ if (!pFormat)
+ return 0;
+ pPicture = CreatePicture (0, pDraw, pFormat,
+ CPSubwindowMode, &subwindow_mode,
+ serverClient, &error);
+ *ppPicture = pPicture;
+ return pPicture;
+}
+#endif
+
+static miDCCursorPtr
+miDCRealize (
+ ScreenPtr pScreen,
+ CursorPtr pCursor)
+{
+ miDCCursorPtr pPriv;
+ GCPtr pGC;
+ XID gcvals[3];
+
+ pPriv = (miDCCursorPtr) xalloc (sizeof (miDCCursorRec));
+ if (!pPriv)
+ return (miDCCursorPtr)NULL;
+#ifdef ARGB_CURSOR
+ if (pCursor->bits->argb)
+ {
+ PixmapPtr pPixmap;
+ PictFormatPtr pFormat;
+ int error;
+
+ pFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8);
+ if (!pFormat)
+ {
+ xfree ((pointer) pPriv);
+ return (miDCCursorPtr)NULL;
+ }
+
+ pPriv->sourceBits = 0;
+ pPriv->maskBits = 0;
+ pPixmap = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width,
+ pCursor->bits->height, 32);
+ if (!pPixmap)
+ {
+ xfree ((pointer) pPriv);
+ return (miDCCursorPtr)NULL;
+ }
+ pGC = GetScratchGC (32, pScreen);
+ if (!pGC)
+ {
+ (*pScreen->DestroyPixmap) (pPixmap);
+ xfree ((pointer) pPriv);
+ return (miDCCursorPtr)NULL;
+ }
+ ValidateGC (&pPixmap->drawable, pGC);
+ (*pGC->ops->PutImage) (&pPixmap->drawable, pGC, 32,
+ 0, 0, pCursor->bits->width,
+ pCursor->bits->height,
+ 0, ZPixmap, (char *) pCursor->bits->argb);
+ FreeScratchGC (pGC);
+ pPriv->pPicture = CreatePicture (0, &pPixmap->drawable,
+ pFormat, 0, 0, serverClient, &error);
+ (*pScreen->DestroyPixmap) (pPixmap);
+ if (!pPriv->pPicture)
+ {
+ xfree ((pointer) pPriv);
+ return (miDCCursorPtr)NULL;
+ }
+ pCursor->bits->devPriv[pScreen->myNum] = (pointer) pPriv;
+ return pPriv;
+ }
+ pPriv->pPicture = 0;
+#endif
+ pPriv->sourceBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1);
+ if (!pPriv->sourceBits)
+ {
+ xfree ((pointer) pPriv);
+ return (miDCCursorPtr)NULL;
+ }
+ pPriv->maskBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1);
+ if (!pPriv->maskBits)
+ {
+ (*pScreen->DestroyPixmap) (pPriv->sourceBits);
+ xfree ((pointer) pPriv);
+ return (miDCCursorPtr)NULL;
+ }
+ pCursor->bits->devPriv[pScreen->myNum] = (pointer) pPriv;
+
+ /* create the two sets of bits, clipping as appropriate */
+
+ pGC = GetScratchGC (1, pScreen);
+ if (!pGC)
+ {
+ (void) miDCUnrealizeCursor (pScreen, pCursor);
+ return (miDCCursorPtr)NULL;
+ }
+
+ ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC);
+ (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1,
+ 0, 0, pCursor->bits->width, pCursor->bits->height,
+ 0, XYPixmap, (char *)pCursor->bits->source);
+ gcvals[0] = GXand;
+ ChangeGC (pGC, GCFunction, gcvals);
+ ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC);
+ (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1,
+ 0, 0, pCursor->bits->width, pCursor->bits->height,
+ 0, XYPixmap, (char *)pCursor->bits->mask);
+
+ /* mask bits -- pCursor->mask & ~pCursor->source */
+ gcvals[0] = GXcopy;
+ ChangeGC (pGC, GCFunction, gcvals);
+ ValidateGC ((DrawablePtr)pPriv->maskBits, pGC);
+ (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1,
+ 0, 0, pCursor->bits->width, pCursor->bits->height,
+ 0, XYPixmap, (char *)pCursor->bits->mask);
+ gcvals[0] = GXandInverted;
+ ChangeGC (pGC, GCFunction, gcvals);
+ ValidateGC ((DrawablePtr)pPriv->maskBits, pGC);
+ (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1,
+ 0, 0, pCursor->bits->width, pCursor->bits->height,
+ 0, XYPixmap, (char *)pCursor->bits->source);
+ FreeScratchGC (pGC);
+ return pPriv;
+}
+
+static Bool
+miDCUnrealizeCursor (pScreen, pCursor)
+ ScreenPtr pScreen;
+ CursorPtr pCursor;
+{
+ miDCCursorPtr pPriv;
+
+ pPriv = (miDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum];
+ if (pPriv && (pCursor->bits->refcnt <= 1))
+ {
+ if (pPriv->sourceBits)
+ (*pScreen->DestroyPixmap) (pPriv->sourceBits);
+ if (pPriv->maskBits)
+ (*pScreen->DestroyPixmap) (pPriv->maskBits);
+#ifdef ARGB_CURSOR
+ if (pPriv->pPicture)
+ FreePicture (pPriv->pPicture, 0);
+#endif
+ xfree ((pointer) pPriv);
+ pCursor->bits->devPriv[pScreen->myNum] = (pointer)NULL;
+ }
+ return TRUE;
+}
+
+static void
+miDCPutBits (
+ DrawablePtr pDrawable,
+ miDCCursorPtr pPriv,
+ GCPtr sourceGC,
+ GCPtr maskGC,
+ int x_org,
+ int y_org,
+ unsigned w,
+ unsigned h,
+ unsigned long source,
+ unsigned long mask)
+{
+ XID gcvals[1];
+ int x, y;
+
+ if (sourceGC->fgPixel != source)
+ {
+ gcvals[0] = source;
+ DoChangeGC (sourceGC, GCForeground, gcvals, 0);
+ }
+ if (sourceGC->serialNumber != pDrawable->serialNumber)
+ ValidateGC (pDrawable, sourceGC);
+
+ if(sourceGC->miTranslate)
+ {
+ x = pDrawable->x + x_org;
+ y = pDrawable->y + y_org;
+ }
+ else
+ {
+ x = x_org;
+ y = y_org;
+ }
+
+ (*sourceGC->ops->PushPixels) (sourceGC, pPriv->sourceBits, pDrawable, w, h, x, y);
+ if (maskGC->fgPixel != mask)
+ {
+ gcvals[0] = mask;
+ DoChangeGC (maskGC, GCForeground, gcvals, 0);
+ }
+ if (maskGC->serialNumber != pDrawable->serialNumber)
+ ValidateGC (pDrawable, maskGC);
+
+ if(maskGC->miTranslate)
+ {
+ x = pDrawable->x + x_org;
+ y = pDrawable->y + y_org;
+ }
+ else
+ {
+ x = x_org;
+ y = y_org;
+ }
+
+ (*maskGC->ops->PushPixels) (maskGC, pPriv->maskBits, pDrawable, w, h, x, y);
+}
+
+#define EnsureGC(gc,win) (gc || miDCMakeGC(&gc, win))
+
+static GCPtr
+miDCMakeGC(
+ GCPtr *ppGC,
+ WindowPtr pWin)
+{
+ GCPtr pGC;
+ int status;
+ XID gcvals[2];
+
+ gcvals[0] = IncludeInferiors;
+ gcvals[1] = FALSE;
+ pGC = CreateGC((DrawablePtr)pWin,
+ GCSubwindowMode|GCGraphicsExposures, gcvals, &status);
+ if (pGC && pWin->drawable.pScreen->DrawGuarantee)
+ (*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeVisBack);
+ *ppGC = pGC;
+ return pGC;
+}
+
+
+static Bool
+miDCPutUpCursor (pScreen, pCursor, x, y, source, mask)
+ ScreenPtr pScreen;
+ CursorPtr pCursor;
+ int x, y;
+ unsigned long source, mask;
+{
+ miDCScreenPtr pScreenPriv;
+ miDCCursorPtr pPriv;
+ WindowPtr pWin;
+
+ pPriv = (miDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum];
+ if (!pPriv)
+ {
+ pPriv = miDCRealize(pScreen, pCursor);
+ if (!pPriv)
+ return FALSE;
+ }
+ pScreenPriv = (miDCScreenPtr) pScreen->devPrivates[miDCScreenIndex].ptr;
+ pWin = WindowTable[pScreen->myNum];
+#ifdef ARGB_CURSOR
+ if (pPriv->pPicture)
+ {
+ if (!EnsurePicture(pScreenPriv->pRootPicture, &pWin->drawable, pWin))
+ return FALSE;
+ CompositePicture (PictOpOver,
+ pPriv->pPicture,
+ NULL,
+ pScreenPriv->pRootPicture,
+ 0, 0, 0, 0,
+ x, y,
+ pCursor->bits->width,
+ pCursor->bits->height);
+ }
+ else
+#endif
+ {
+ if (!EnsureGC(pScreenPriv->pSourceGC, pWin))
+ return FALSE;
+ if (!EnsureGC(pScreenPriv->pMaskGC, pWin))
+ {
+ FreeGC (pScreenPriv->pSourceGC, (GContext) 0);
+ pScreenPriv->pSourceGC = 0;
+ return FALSE;
+ }
+ miDCPutBits ((DrawablePtr)pWin, pPriv,
+ pScreenPriv->pSourceGC, pScreenPriv->pMaskGC,
+ x, y, pCursor->bits->width, pCursor->bits->height,
+ source, mask);
+ }
+ return TRUE;
+}
+
+static Bool
+miDCSaveUnderCursor (pScreen, x, y, w, h)
+ ScreenPtr pScreen;
+ int x, y, w, h;
+{
+ miDCScreenPtr pScreenPriv;
+ PixmapPtr pSave;
+ WindowPtr pWin;
+ GCPtr pGC;
+
+ pScreenPriv = (miDCScreenPtr) pScreen->devPrivates[miDCScreenIndex].ptr;
+ pSave = pScreenPriv->pSave;
+ pWin = WindowTable[pScreen->myNum];
+ if (!pSave || pSave->drawable.width < w || pSave->drawable.height < h)
+ {
+ if (pSave)
+ (*pScreen->DestroyPixmap) (pSave);
+ pScreenPriv->pSave = pSave =
+ (*pScreen->CreatePixmap) (pScreen, w, h, pScreen->rootDepth);
+ if (!pSave)
+ return FALSE;
+ }
+ if (!EnsureGC(pScreenPriv->pSaveGC, pWin))
+ return FALSE;
+ pGC = pScreenPriv->pSaveGC;
+ if (pSave->drawable.serialNumber != pGC->serialNumber)
+ ValidateGC ((DrawablePtr) pSave, pGC);
+ (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
+ x, y, w, h, 0, 0);
+ return TRUE;
+}
+
+static Bool
+miDCRestoreUnderCursor (pScreen, x, y, w, h)
+ ScreenPtr pScreen;
+ int x, y, w, h;
+{
+ miDCScreenPtr pScreenPriv;
+ PixmapPtr pSave;
+ WindowPtr pWin;
+ GCPtr pGC;
+
+ pScreenPriv = (miDCScreenPtr) pScreen->devPrivates[miDCScreenIndex].ptr;
+ pSave = pScreenPriv->pSave;
+ pWin = WindowTable[pScreen->myNum];
+ if (!pSave)
+ return FALSE;
+ if (!EnsureGC(pScreenPriv->pRestoreGC, pWin))
+ return FALSE;
+ pGC = pScreenPriv->pRestoreGC;
+ if (pWin->drawable.serialNumber != pGC->serialNumber)
+ ValidateGC ((DrawablePtr) pWin, pGC);
+ (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
+ 0, 0, w, h, x, y);
+ return TRUE;
+}
+
+static Bool
+miDCChangeSave (pScreen, x, y, w, h, dx, dy)
+ ScreenPtr pScreen;
+ int x, y, w, h, dx, dy;
+{
+ miDCScreenPtr pScreenPriv;
+ PixmapPtr pSave;
+ WindowPtr pWin;
+ GCPtr pGC;
+ int sourcex, sourcey, destx, desty, copyw, copyh;
+
+ pScreenPriv = (miDCScreenPtr) pScreen->devPrivates[miDCScreenIndex].ptr;
+ pSave = pScreenPriv->pSave;
+ pWin = WindowTable[pScreen->myNum];
+ /*
+ * restore the bits which are about to get trashed
+ */
+ if (!pSave)
+ return FALSE;
+ if (!EnsureGC(pScreenPriv->pRestoreGC, pWin))
+ return FALSE;
+ pGC = pScreenPriv->pRestoreGC;
+ if (pWin->drawable.serialNumber != pGC->serialNumber)
+ ValidateGC ((DrawablePtr) pWin, pGC);
+ /*
+ * copy the old bits to the screen.
+ */
+ if (dy > 0)
+ {
+ (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
+ 0, h - dy, w, dy, x + dx, y + h);
+ }
+ else if (dy < 0)
+ {
+ (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
+ 0, 0, w, -dy, x + dx, y + dy);
+ }
+ if (dy >= 0)
+ {
+ desty = y + dy;
+ sourcey = 0;
+ copyh = h - dy;
+ }
+ else
+ {
+ desty = y;
+ sourcey = - dy;
+ copyh = h + dy;
+ }
+ if (dx > 0)
+ {
+ (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
+ w - dx, sourcey, dx, copyh, x + w, desty);
+ }
+ else if (dx < 0)
+ {
+ (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
+ 0, sourcey, -dx, copyh, x + dx, desty);
+ }
+ if (!EnsureGC(pScreenPriv->pSaveGC, pWin))
+ return FALSE;
+ pGC = pScreenPriv->pSaveGC;
+ if (pSave->drawable.serialNumber != pGC->serialNumber)
+ ValidateGC ((DrawablePtr) pSave, pGC);
+ /*
+ * move the bits that are still valid within the pixmap
+ */
+ if (dx >= 0)
+ {
+ sourcex = 0;
+ destx = dx;
+ copyw = w - dx;
+ }
+ else
+ {
+ destx = 0;
+ sourcex = - dx;
+ copyw = w + dx;
+ }
+ if (dy >= 0)
+ {
+ sourcey = 0;
+ desty = dy;
+ copyh = h - dy;
+ }
+ else
+ {
+ desty = 0;
+ sourcey = -dy;
+ copyh = h + dy;
+ }
+ (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pSave, pGC,
+ sourcex, sourcey, copyw, copyh, destx, desty);
+ /*
+ * copy the new bits from the screen into the remaining areas of the
+ * pixmap
+ */
+ if (dy > 0)
+ {
+ (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
+ x, y, w, dy, 0, 0);
+ }
+ else if (dy < 0)
+ {
+ (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
+ x, y + h + dy, w, -dy, 0, h + dy);
+ }
+ if (dy >= 0)
+ {
+ desty = dy;
+ sourcey = y + dy;
+ copyh = h - dy;
+ }
+ else
+ {
+ desty = 0;
+ sourcey = y;
+ copyh = h + dy;
+ }
+ if (dx > 0)
+ {
+ (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
+ x, sourcey, dx, copyh, 0, desty);
+ }
+ else if (dx < 0)
+ {
+ (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
+ x + w + dx, sourcey, -dx, copyh, w + dx, desty);
+ }
+ return TRUE;
+}
+
+static Bool
+miDCMoveCursor (pScreen, pCursor, x, y, w, h, dx, dy, source, mask)
+ ScreenPtr pScreen;
+ CursorPtr pCursor;
+ int x, y, w, h, dx, dy;
+ unsigned long source, mask;
+{
+ miDCCursorPtr pPriv;
+ miDCScreenPtr pScreenPriv;
+ int status;
+ WindowPtr pWin;
+ GCPtr pGC;
+ XID gcval = FALSE;
+ PixmapPtr pTemp;
+
+ pPriv = (miDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum];
+ if (!pPriv)
+ {
+ pPriv = miDCRealize(pScreen, pCursor);
+ if (!pPriv)
+ return FALSE;
+ }
+ pScreenPriv = (miDCScreenPtr) pScreen->devPrivates[miDCScreenIndex].ptr;
+ pWin = WindowTable[pScreen->myNum];
+ pTemp = pScreenPriv->pTemp;
+ if (!pTemp ||
+ pTemp->drawable.width != pScreenPriv->pSave->drawable.width ||
+ pTemp->drawable.height != pScreenPriv->pSave->drawable.height)
+ {
+ if (pTemp)
+ (*pScreen->DestroyPixmap) (pTemp);
+#ifdef ARGB_CURSOR
+ if (pScreenPriv->pTempPicture)
+ {
+ FreePicture (pScreenPriv->pTempPicture, 0);
+ pScreenPriv->pTempPicture = 0;
+ }
+#endif
+ pScreenPriv->pTemp = pTemp = (*pScreen->CreatePixmap)
+ (pScreen, w, h, pScreenPriv->pSave->drawable.depth);
+ if (!pTemp)
+ return FALSE;
+ }
+ if (!pScreenPriv->pMoveGC)
+ {
+ pScreenPriv->pMoveGC = CreateGC ((DrawablePtr)pTemp,
+ GCGraphicsExposures, &gcval, &status);
+ if (!pScreenPriv->pMoveGC)
+ return FALSE;
+ }
+ /*
+ * copy the saved area to a temporary pixmap
+ */
+ pGC = pScreenPriv->pMoveGC;
+ if (pGC->serialNumber != pTemp->drawable.serialNumber)
+ ValidateGC ((DrawablePtr) pTemp, pGC);
+ (*pGC->ops->CopyArea)((DrawablePtr)pScreenPriv->pSave,
+ (DrawablePtr)pTemp, pGC, 0, 0, w, h, 0, 0);
+
+ /*
+ * draw the cursor in the temporary pixmap
+ */
+#ifdef ARGB_CURSOR
+ if (pPriv->pPicture)
+ {
+ if (!EnsurePicture(pScreenPriv->pTempPicture, &pTemp->drawable, pWin))
+ return FALSE;
+ CompositePicture (PictOpOver,
+ pPriv->pPicture,
+ NULL,
+ pScreenPriv->pTempPicture,
+ 0, 0, 0, 0,
+ dx, dy,
+ pCursor->bits->width,
+ pCursor->bits->height);
+ }
+ else
+#endif
+ {
+ if (!pScreenPriv->pPixSourceGC)
+ {
+ pScreenPriv->pPixSourceGC = CreateGC ((DrawablePtr)pTemp,
+ GCGraphicsExposures, &gcval, &status);
+ if (!pScreenPriv->pPixSourceGC)
+ return FALSE;
+ }
+ if (!pScreenPriv->pPixMaskGC)
+ {
+ pScreenPriv->pPixMaskGC = CreateGC ((DrawablePtr)pTemp,
+ GCGraphicsExposures, &gcval, &status);
+ if (!pScreenPriv->pPixMaskGC)
+ return FALSE;
+ }
+ miDCPutBits ((DrawablePtr)pTemp, pPriv,
+ pScreenPriv->pPixSourceGC, pScreenPriv->pPixMaskGC,
+ dx, dy, pCursor->bits->width, pCursor->bits->height,
+ source, mask);
+ }
+
+ /*
+ * copy the temporary pixmap onto the screen
+ */
+
+ if (!EnsureGC(pScreenPriv->pRestoreGC, pWin))
+ return FALSE;
+ pGC = pScreenPriv->pRestoreGC;
+ if (pWin->drawable.serialNumber != pGC->serialNumber)
+ ValidateGC ((DrawablePtr) pWin, pGC);
+
+ (*pGC->ops->CopyArea) ((DrawablePtr) pTemp, (DrawablePtr) pWin,
+ pGC,
+ 0, 0, w, h, x, y);
+ return TRUE;
+}
diff --git a/xserver/mi/mieq.c b/xserver/mi/mieq.c
new file mode 100644
index 000000000..a69ce7037
--- /dev/null
+++ b/xserver/mi/mieq.c
@@ -0,0 +1,194 @@
+/*
+ *
+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.
+ *
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+/*
+ * mieq.c
+ *
+ * Machine independent event queue
+ *
+ */
+
+#if HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+# define NEED_EVENTS
+# include <X11/X.h>
+# include <X11/Xmd.h>
+# include <X11/Xproto.h>
+# include "misc.h"
+# include "windowstr.h"
+# include "pixmapstr.h"
+# include "inputstr.h"
+# include "mi.h"
+# include "scrnintstr.h"
+
+#define QUEUE_SIZE 256
+
+typedef struct _Event {
+ xEvent event;
+ ScreenPtr pScreen;
+} EventRec, *EventPtr;
+
+typedef struct _EventQueue {
+ HWEventQueueType head, tail; /* long for SetInputCheck */
+ CARD32 lastEventTime; /* to avoid time running backwards */
+ Bool lastMotion;
+ EventRec events[QUEUE_SIZE]; /* static allocation for signals */
+ DevicePtr pKbd, pPtr; /* device pointer, to get funcs */
+ ScreenPtr pEnqueueScreen; /* screen events are being delivered to */
+ ScreenPtr pDequeueScreen; /* screen events are being dispatched to */
+} EventQueueRec, *EventQueuePtr;
+
+static EventQueueRec miEventQueue;
+
+Bool
+mieqInit (pKbd, pPtr)
+ DevicePtr pKbd, pPtr;
+{
+ miEventQueue.head = miEventQueue.tail = 0;
+ miEventQueue.lastEventTime = GetTimeInMillis ();
+ miEventQueue.pKbd = pKbd;
+ miEventQueue.pPtr = pPtr;
+ miEventQueue.lastMotion = FALSE;
+ miEventQueue.pEnqueueScreen = screenInfo.screens[0];
+ miEventQueue.pDequeueScreen = miEventQueue.pEnqueueScreen;
+ SetInputCheck (&miEventQueue.head, &miEventQueue.tail);
+ return TRUE;
+}
+
+/*
+ * Must be reentrant with ProcessInputEvents. Assumption: mieqEnqueue
+ * will never be interrupted. If this is called from both signal
+ * handlers and regular code, make sure the signal is suspended when
+ * called from regular code.
+ */
+
+void
+mieqEnqueue (e)
+ xEvent *e;
+{
+ HWEventQueueType oldtail, newtail;
+ Bool isMotion;
+
+ oldtail = miEventQueue.tail;
+ isMotion = e->u.u.type == MotionNotify;
+ if (isMotion && miEventQueue.lastMotion && oldtail != miEventQueue.head)
+ {
+ if (oldtail == 0)
+ oldtail = QUEUE_SIZE;
+ oldtail = oldtail - 1;
+ }
+ else
+ {
+ newtail = oldtail + 1;
+ if (newtail == QUEUE_SIZE)
+ newtail = 0;
+ /* Toss events which come in late */
+ if (newtail == miEventQueue.head)
+ return;
+ miEventQueue.tail = newtail;
+ }
+ miEventQueue.lastMotion = isMotion;
+ miEventQueue.events[oldtail].event = *e;
+ /*
+ * Make sure that event times don't go backwards - this
+ * is "unnecessary", but very useful
+ */
+ if (e->u.keyButtonPointer.time < miEventQueue.lastEventTime &&
+ miEventQueue.lastEventTime - e->u.keyButtonPointer.time < 10000)
+ {
+ miEventQueue.events[oldtail].event.u.keyButtonPointer.time =
+ miEventQueue.lastEventTime;
+ }
+ miEventQueue.lastEventTime =
+ miEventQueue.events[oldtail].event.u.keyButtonPointer.time;
+ miEventQueue.events[oldtail].pScreen = miEventQueue.pEnqueueScreen;
+}
+
+void
+mieqSwitchScreen (pScreen, fromDIX)
+ ScreenPtr pScreen;
+ Bool fromDIX;
+{
+ miEventQueue.pEnqueueScreen = pScreen;
+ if (fromDIX)
+ miEventQueue.pDequeueScreen = pScreen;
+}
+
+/*
+ * Call this from ProcessInputEvents()
+ */
+
+void mieqProcessInputEvents ()
+{
+ EventRec *e;
+ int x, y;
+ xEvent xe;
+
+ while (miEventQueue.head != miEventQueue.tail)
+ {
+ if (screenIsSaved == SCREEN_SAVER_ON)
+ SaveScreens (SCREEN_SAVER_OFF, ScreenSaverReset);
+
+ e = &miEventQueue.events[miEventQueue.head];
+ /*
+ * Assumption - screen switching can only occur on motion events
+ */
+ if (e->pScreen != miEventQueue.pDequeueScreen)
+ {
+ miEventQueue.pDequeueScreen = e->pScreen;
+ x = e->event.u.keyButtonPointer.rootX;
+ y = e->event.u.keyButtonPointer.rootY;
+ if (miEventQueue.head == QUEUE_SIZE - 1)
+ miEventQueue.head = 0;
+ else
+ ++miEventQueue.head;
+ NewCurrentScreen (miEventQueue.pDequeueScreen, x, y);
+ }
+ else
+ {
+ xe = e->event;
+ if (miEventQueue.head == QUEUE_SIZE - 1)
+ miEventQueue.head = 0;
+ else
+ ++miEventQueue.head;
+ switch (xe.u.u.type)
+ {
+ case KeyPress:
+ case KeyRelease:
+ (*miEventQueue.pKbd->processInputProc)
+ (&xe, (DeviceIntPtr)miEventQueue.pKbd, 1);
+ break;
+ default:
+ (*miEventQueue.pPtr->processInputProc)
+ (&xe, (DeviceIntPtr)miEventQueue.pPtr, 1);
+ break;
+ }
+ }
+ }
+}
diff --git a/xserver/mi/miexpose.c b/xserver/mi/miexpose.c
new file mode 100644
index 000000000..1ca5fc965
--- /dev/null
+++ b/xserver/mi/miexpose.c
@@ -0,0 +1,902 @@
+/***********************************************************
+
+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.
+
+******************************************************************/
+/*****************************************************************
+
+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 <X11/X.h>
+#define NEED_EVENTS
+#include <X11/Xproto.h>
+#include <X11/Xprotostr.h>
+
+#include "misc.h"
+#include "regionstr.h"
+#include "scrnintstr.h"
+#include "gcstruct.h"
+#include "windowstr.h"
+#include "pixmap.h"
+#include "input.h"
+
+#include "dixstruct.h"
+#include "mi.h"
+#include <X11/Xmd.h>
+
+#include "globals.h"
+
+#ifdef PANORAMIX
+#include "panoramiX.h"
+#include "panoramiXsrv.h"
+#endif
+
+/*
+ machine-independent graphics exposure code. any device that uses
+the region package can call this.
+*/
+
+#ifndef RECTLIMIT
+#define RECTLIMIT 25 /* pick a number, any number > 8 */
+#endif
+
+/* miHandleExposures
+ generate a region for exposures for areas that were copied from obscured or
+non-existent areas to non-obscured areas of the destination. Paint the
+background for the region, if the destination is a window.
+
+NOTE:
+ this should generally be called, even if graphicsExposures is false,
+because this is where bits get recovered from backing store.
+
+NOTE:
+ added argument 'plane' is used to indicate how exposures from backing
+store should be accomplished. If plane is 0 (i.e. no bit plane), CopyArea
+should be used, else a CopyPlane of the indicated plane will be used. The
+exposing is done by the backing store's GraphicsExpose function, of course.
+
+*/
+
+_X_EXPORT RegionPtr
+miHandleExposures(pSrcDrawable, pDstDrawable,
+ pGC, srcx, srcy, width, height, dstx, dsty, plane)
+ register DrawablePtr pSrcDrawable;
+ register DrawablePtr pDstDrawable;
+ GCPtr pGC;
+ int srcx, srcy;
+ int width, height;
+ int dstx, dsty;
+ unsigned long plane;
+{
+ register ScreenPtr pscr;
+ RegionPtr prgnSrcClip; /* drawable-relative source clip */
+ RegionRec rgnSrcRec;
+ RegionPtr prgnDstClip; /* drawable-relative dest clip */
+ RegionRec rgnDstRec;
+ BoxRec srcBox; /* unclipped source */
+ RegionRec rgnExposed; /* exposed region, calculated source-
+ relative, made dst relative to
+ intersect with visible parts of
+ dest and send events to client,
+ and then screen relative to paint
+ the window background
+ */
+ WindowPtr pSrcWin;
+ BoxRec expBox;
+ Bool extents;
+
+ /* This prevents warning about pscr not being used. */
+ pGC->pScreen = pscr = pGC->pScreen;
+
+ /* avoid work if we can */
+ if (!pGC->graphicsExposures &&
+ (pDstDrawable->type == DRAWABLE_PIXMAP) &&
+ ((pSrcDrawable->type == DRAWABLE_PIXMAP) ||
+ (((WindowPtr)pSrcDrawable)->backStorage == NULL)))
+ return NULL;
+
+ srcBox.x1 = srcx;
+ srcBox.y1 = srcy;
+ srcBox.x2 = srcx+width;
+ srcBox.y2 = srcy+height;
+
+ if (pSrcDrawable->type != DRAWABLE_PIXMAP)
+ {
+ BoxRec TsrcBox;
+
+ TsrcBox.x1 = srcx + pSrcDrawable->x;
+ TsrcBox.y1 = srcy + pSrcDrawable->y;
+ TsrcBox.x2 = TsrcBox.x1 + width;
+ TsrcBox.y2 = TsrcBox.y1 + height;
+ pSrcWin = (WindowPtr) pSrcDrawable;
+ if (pGC->subWindowMode == IncludeInferiors)
+ {
+ prgnSrcClip = NotClippedByChildren (pSrcWin);
+ if ((RECT_IN_REGION(pscr, prgnSrcClip, &TsrcBox)) == rgnIN)
+ {
+ REGION_DESTROY(pscr, prgnSrcClip);
+ return NULL;
+ }
+ }
+ else
+ {
+ if ((RECT_IN_REGION(pscr, &pSrcWin->clipList, &TsrcBox)) == rgnIN)
+ return NULL;
+ prgnSrcClip = &rgnSrcRec;
+ REGION_NULL(pscr, prgnSrcClip);
+ REGION_COPY(pscr, prgnSrcClip, &pSrcWin->clipList);
+ }
+ REGION_TRANSLATE(pscr, prgnSrcClip,
+ -pSrcDrawable->x, -pSrcDrawable->y);
+ }
+ else
+ {
+ BoxRec box;
+
+ if ((srcBox.x1 >= 0) && (srcBox.y1 >= 0) &&
+ (srcBox.x2 <= pSrcDrawable->width) &&
+ (srcBox.y2 <= pSrcDrawable->height))
+ return NULL;
+
+ box.x1 = 0;
+ box.y1 = 0;
+ box.x2 = pSrcDrawable->width;
+ box.y2 = pSrcDrawable->height;
+ prgnSrcClip = &rgnSrcRec;
+ REGION_INIT(pscr, prgnSrcClip, &box, 1);
+ pSrcWin = (WindowPtr)NULL;
+ }
+
+ if (pDstDrawable == pSrcDrawable)
+ {
+ prgnDstClip = prgnSrcClip;
+ }
+ else if (pDstDrawable->type != DRAWABLE_PIXMAP)
+ {
+ if (pGC->subWindowMode == IncludeInferiors)
+ {
+ prgnDstClip = NotClippedByChildren((WindowPtr)pDstDrawable);
+ }
+ else
+ {
+ prgnDstClip = &rgnDstRec;
+ REGION_NULL(pscr, prgnDstClip);
+ REGION_COPY(pscr, prgnDstClip,
+ &((WindowPtr)pDstDrawable)->clipList);
+ }
+ REGION_TRANSLATE(pscr, prgnDstClip,
+ -pDstDrawable->x, -pDstDrawable->y);
+ }
+ else
+ {
+ BoxRec box;
+
+ box.x1 = 0;
+ box.y1 = 0;
+ box.x2 = pDstDrawable->width;
+ box.y2 = pDstDrawable->height;
+ prgnDstClip = &rgnDstRec;
+ REGION_INIT(pscr, prgnDstClip, &box, 1);
+ }
+
+ /* drawable-relative source region */
+ REGION_INIT(pscr, &rgnExposed, &srcBox, 1);
+
+ /* now get the hidden parts of the source box*/
+ REGION_SUBTRACT(pscr, &rgnExposed, &rgnExposed, prgnSrcClip);
+
+ if (pSrcWin && pSrcWin->backStorage)
+ {
+ /*
+ * Copy any areas from the source backing store. Modifies
+ * rgnExposed.
+ */
+ (* pSrcWin->drawable.pScreen->ExposeCopy) ((WindowPtr)pSrcDrawable,
+ pDstDrawable,
+ pGC,
+ &rgnExposed,
+ srcx, srcy,
+ dstx, dsty,
+ plane);
+ }
+
+ /* move them over the destination */
+ REGION_TRANSLATE(pscr, &rgnExposed, dstx-srcx, dsty-srcy);
+
+ /* intersect with visible areas of dest */
+ REGION_INTERSECT(pscr, &rgnExposed, &rgnExposed, prgnDstClip);
+
+ /*
+ * If we have LOTS of rectangles, we decide to take the extents
+ * and force an exposure on that. This should require much less
+ * work overall, on both client and server. This is cheating, but
+ * isn't prohibited by the protocol ("spontaneous combustion" :-)
+ * for windows.
+ */
+ extents = pGC->graphicsExposures &&
+ (REGION_NUM_RECTS(&rgnExposed) > RECTLIMIT) &&
+ (pDstDrawable->type != DRAWABLE_PIXMAP);
+#ifdef SHAPE
+ if (pSrcWin)
+ {
+ RegionPtr region;
+ if (!(region = wClipShape (pSrcWin)))
+ region = wBoundingShape (pSrcWin);
+ /*
+ * If you try to CopyArea the extents of a shaped window, compacting the
+ * exposed region will undo all our work!
+ */
+ if (extents && pSrcWin && region &&
+ (RECT_IN_REGION(pscr, region, &srcBox) != rgnIN))
+ extents = FALSE;
+ }
+#endif
+ if (extents)
+ {
+ WindowPtr pWin = (WindowPtr)pDstDrawable;
+
+ expBox = *REGION_EXTENTS(pscr, &rgnExposed);
+ REGION_RESET(pscr, &rgnExposed, &expBox);
+ /* need to clear out new areas of backing store */
+ if (pWin->backStorage)
+ (void) (* pWin->drawable.pScreen->ClearBackingStore)(
+ pWin,
+ expBox.x1,
+ expBox.y1,
+ expBox.x2 - expBox.x1,
+ expBox.y2 - expBox.y1,
+ FALSE);
+ }
+ if ((pDstDrawable->type != DRAWABLE_PIXMAP) &&
+ (((WindowPtr)pDstDrawable)->backgroundState != None))
+ {
+ WindowPtr pWin = (WindowPtr)pDstDrawable;
+
+ /* make the exposed area screen-relative */
+ REGION_TRANSLATE(pscr, &rgnExposed,
+ pDstDrawable->x, pDstDrawable->y);
+
+ if (extents)
+ {
+ /* PaintWindowBackground doesn't clip, so we have to */
+ REGION_INTERSECT(pscr, &rgnExposed, &rgnExposed, &pWin->clipList);
+ }
+ (*pWin->drawable.pScreen->PaintWindowBackground)(
+ (WindowPtr)pDstDrawable, &rgnExposed, PW_BACKGROUND);
+
+ if (extents)
+ {
+ REGION_RESET(pscr, &rgnExposed, &expBox);
+ }
+ else
+ REGION_TRANSLATE(pscr, &rgnExposed,
+ -pDstDrawable->x, -pDstDrawable->y);
+ }
+ if (prgnDstClip == &rgnDstRec)
+ {
+ REGION_UNINIT(pscr, prgnDstClip);
+ }
+ else if (prgnDstClip != prgnSrcClip)
+ {
+ REGION_DESTROY(pscr, prgnDstClip);
+ }
+
+ if (prgnSrcClip == &rgnSrcRec)
+ {
+ REGION_UNINIT(pscr, prgnSrcClip);
+ }
+ else
+ {
+ REGION_DESTROY(pscr, prgnSrcClip);
+ }
+
+ if (pGC->graphicsExposures)
+ {
+ /* don't look */
+ RegionPtr exposed = REGION_CREATE(pscr, NullBox, 0);
+ *exposed = rgnExposed;
+ return exposed;
+ }
+ else
+ {
+ REGION_UNINIT(pscr, &rgnExposed);
+ return NULL;
+ }
+}
+
+/* send GraphicsExpose events, or a NoExpose event, based on the region */
+
+_X_EXPORT void
+miSendGraphicsExpose (client, pRgn, drawable, major, minor)
+ ClientPtr client;
+ RegionPtr pRgn;
+ XID drawable;
+ int major;
+ int minor;
+{
+ if (pRgn && !REGION_NIL(pRgn))
+ {
+ xEvent *pEvent;
+ register xEvent *pe;
+ register BoxPtr pBox;
+ register int i;
+ int numRects;
+
+ numRects = REGION_NUM_RECTS(pRgn);
+ pBox = REGION_RECTS(pRgn);
+ if(!(pEvent = (xEvent *)ALLOCATE_LOCAL(numRects * sizeof(xEvent))))
+ return;
+ pe = pEvent;
+
+ for (i=1; i<=numRects; i++, pe++, pBox++)
+ {
+ pe->u.u.type = GraphicsExpose;
+ pe->u.graphicsExposure.drawable = drawable;
+ pe->u.graphicsExposure.x = pBox->x1;
+ pe->u.graphicsExposure.y = pBox->y1;
+ pe->u.graphicsExposure.width = pBox->x2 - pBox->x1;
+ pe->u.graphicsExposure.height = pBox->y2 - pBox->y1;
+ pe->u.graphicsExposure.count = numRects - i;
+ pe->u.graphicsExposure.majorEvent = major;
+ pe->u.graphicsExposure.minorEvent = minor;
+ }
+ TryClientEvents(client, pEvent, numRects,
+ (Mask)0, NoEventMask, NullGrab);
+ DEALLOCATE_LOCAL(pEvent);
+ }
+ else
+ {
+ xEvent event;
+ event.u.u.type = NoExpose;
+ event.u.noExposure.drawable = drawable;
+ event.u.noExposure.majorEvent = major;
+ event.u.noExposure.minorEvent = minor;
+ TryClientEvents(client, &event, 1,
+ (Mask)0, NoEventMask, NullGrab);
+ }
+}
+
+
+void
+miSendExposures(pWin, pRgn, dx, dy)
+ WindowPtr pWin;
+ RegionPtr pRgn;
+ register int dx, dy;
+{
+ register BoxPtr pBox;
+ int numRects;
+ register xEvent *pEvent, *pe;
+ register int i;
+
+ pBox = REGION_RECTS(pRgn);
+ numRects = REGION_NUM_RECTS(pRgn);
+ if(!(pEvent = (xEvent *) ALLOCATE_LOCAL(numRects * sizeof(xEvent))))
+ return;
+
+ for (i=numRects, pe = pEvent; --i >= 0; pe++, pBox++)
+ {
+ pe->u.u.type = Expose;
+ pe->u.expose.window = pWin->drawable.id;
+ pe->u.expose.x = pBox->x1 - dx;
+ pe->u.expose.y = pBox->y1 - dy;
+ pe->u.expose.width = pBox->x2 - pBox->x1;
+ pe->u.expose.height = pBox->y2 - pBox->y1;
+ pe->u.expose.count = i;
+ }
+
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension) {
+ int scrnum = pWin->drawable.pScreen->myNum;
+ int x = 0, y = 0;
+ XID realWin = 0;
+
+ if(!pWin->parent) {
+ x = panoramiXdataPtr[scrnum].x;
+ y = panoramiXdataPtr[scrnum].y;
+ pWin = WindowTable[0];
+ realWin = pWin->drawable.id;
+ } else if (scrnum) {
+ PanoramiXRes *win;
+ win = PanoramiXFindIDByScrnum(XRT_WINDOW,
+ pWin->drawable.id, scrnum);
+ if(!win) {
+ DEALLOCATE_LOCAL(pEvent);
+ return;
+ }
+ realWin = win->info[0].id;
+ pWin = LookupIDByType(realWin, RT_WINDOW);
+ }
+ if(x || y || scrnum)
+ for (i = 0; i < numRects; i++) {
+ pEvent[i].u.expose.window = realWin;
+ pEvent[i].u.expose.x += x;
+ pEvent[i].u.expose.y += y;
+ }
+ }
+#endif
+
+ DeliverEvents(pWin, pEvent, numRects, NullWindow);
+
+ DEALLOCATE_LOCAL(pEvent);
+}
+
+_X_EXPORT void
+miWindowExposures(pWin, prgn, other_exposed)
+ WindowPtr pWin;
+ register RegionPtr prgn, other_exposed;
+{
+ RegionPtr exposures = prgn;
+ if (pWin->backStorage && prgn)
+ /*
+ * in some cases, backing store will cause a different
+ * region to be exposed than needs to be repainted
+ * (like when a window is mapped). RestoreAreas is
+ * allowed to return a region other than prgn,
+ * in which case this routine will free the resultant
+ * region. If exposures is null, then no events will
+ * be sent to the client; if prgn is empty
+ * no areas will be repainted.
+ */
+ exposures = (*pWin->drawable.pScreen->RestoreAreas)(pWin, prgn);
+ if ((prgn && !REGION_NIL(prgn)) ||
+ (exposures && !REGION_NIL(exposures)) || other_exposed)
+ {
+ RegionRec expRec;
+ int clientInterested;
+
+ /*
+ * Restore from backing-store FIRST.
+ */
+ clientInterested = (pWin->eventMask|wOtherEventMasks(pWin)) & ExposureMask;
+ if (other_exposed)
+ {
+ if (exposures)
+ {
+ REGION_UNION(pWin->drawable.pScreen, other_exposed,
+ exposures,
+ other_exposed);
+ if (exposures != prgn)
+ REGION_DESTROY(pWin->drawable.pScreen, exposures);
+ }
+ exposures = other_exposed;
+ }
+ if (clientInterested && exposures && (REGION_NUM_RECTS(exposures) > RECTLIMIT))
+ {
+ /*
+ * If we have LOTS of rectangles, we decide to take the extents
+ * and force an exposure on that. This should require much less
+ * work overall, on both client and server. This is cheating, but
+ * isn't prohibited by the protocol ("spontaneous combustion" :-).
+ */
+ BoxRec box;
+
+ box = *REGION_EXTENTS( pWin->drawable.pScreen, exposures);
+ if (exposures == prgn) {
+ exposures = &expRec;
+ REGION_INIT( pWin->drawable.pScreen, exposures, &box, 1);
+ REGION_RESET( pWin->drawable.pScreen, prgn, &box);
+ } else {
+ REGION_RESET( pWin->drawable.pScreen, exposures, &box);
+ REGION_UNION( pWin->drawable.pScreen, prgn, prgn, exposures);
+ }
+ /* PaintWindowBackground doesn't clip, so we have to */
+ REGION_INTERSECT( pWin->drawable.pScreen, prgn, prgn, &pWin->clipList);
+ /* need to clear out new areas of backing store, too */
+ if (pWin->backStorage)
+ (void) (* pWin->drawable.pScreen->ClearBackingStore)(
+ pWin,
+ box.x1 - pWin->drawable.x,
+ box.y1 - pWin->drawable.y,
+ box.x2 - box.x1,
+ box.y2 - box.y1,
+ FALSE);
+ }
+ if (prgn && !REGION_NIL(prgn))
+ (*pWin->drawable.pScreen->PaintWindowBackground)(pWin, prgn, PW_BACKGROUND);
+ if (clientInterested && exposures && !REGION_NIL(exposures))
+ miSendExposures(pWin, exposures,
+ pWin->drawable.x, pWin->drawable.y);
+ if (exposures == &expRec)
+ {
+ REGION_UNINIT( pWin->drawable.pScreen, exposures);
+ }
+ else if (exposures && exposures != prgn && exposures != other_exposed)
+ REGION_DESTROY( pWin->drawable.pScreen, exposures);
+ if (prgn)
+ REGION_EMPTY( pWin->drawable.pScreen, prgn);
+ }
+ else if (exposures && exposures != prgn)
+ REGION_DESTROY( pWin->drawable.pScreen, exposures);
+}
+
+
+/*
+ this code is highly unlikely. it is not haile selassie.
+
+ there is some hair here. we can't just use the window's
+clip region as it is, because if we are painting the border,
+the border is not in the client area and so we will be excluded
+when we validate the GC, and if we are painting a parent-relative
+background, the area we want to paint is in some other window.
+since we trust the code calling us to tell us to paint only areas
+that are really ours, we will temporarily give the window a
+clipList the size of the whole screen and an origin at (0,0).
+this more or less assumes that ddX code will do translation
+based on the window's absolute position, and that ValidateGC will
+look at clipList, and that no other fields from the
+window will be used. it's not possible to just draw
+in the root because it may be a different depth.
+
+to get the tile to align correctly we set the GC's tile origin to
+be the (x,y) of the window's upper left corner, after which we
+get the right bits when drawing into the root.
+
+because the clip_mask is being set to None, we may call DoChangeGC with
+fPointer set true, thus we no longer need to install the background or
+border tile in the resource table.
+*/
+
+static RESTYPE ResType = 0;
+static int numGCs = 0;
+static GCPtr screenContext[MAXSCREENS];
+
+/*ARGSUSED*/
+static int
+tossGC (
+ pointer value,
+ XID id)
+{
+ GCPtr pGC = (GCPtr)value;
+ screenContext[pGC->pScreen->myNum] = (GCPtr)NULL;
+ FreeGC (pGC, id);
+ numGCs--;
+ if (!numGCs)
+ ResType = 0;
+
+ return 0;
+}
+
+
+_X_EXPORT void
+miPaintWindow(pWin, prgn, what)
+register WindowPtr pWin;
+RegionPtr prgn;
+int what;
+{
+ int status;
+
+ Bool usingScratchGC = FALSE;
+ WindowPtr pRoot;
+
+#define FUNCTION 0
+#define FOREGROUND 1
+#define TILE 2
+#define FILLSTYLE 3
+#define ABSX 4
+#define ABSY 5
+#define CLIPMASK 6
+#define SUBWINDOW 7
+#define COUNT_BITS 8
+
+ ChangeGCVal gcval[7];
+ ChangeGCVal newValues [COUNT_BITS];
+
+ BITS32 gcmask, index, mask;
+ RegionRec prgnWin;
+ DDXPointRec oldCorner;
+ BoxRec box;
+ WindowPtr pBgWin;
+ GCPtr pGC;
+ register int i;
+ register BoxPtr pbox;
+ register ScreenPtr pScreen = pWin->drawable.pScreen;
+ register xRectangle *prect;
+ int numRects;
+
+ gcmask = 0;
+
+ if (what == PW_BACKGROUND)
+ {
+ switch (pWin->backgroundState) {
+ case None:
+ return;
+ case ParentRelative:
+ (*pWin->parent->drawable.pScreen->PaintWindowBackground)(pWin->parent, prgn, what);
+ return;
+ case BackgroundPixel:
+ newValues[FOREGROUND].val = pWin->background.pixel;
+ newValues[FILLSTYLE].val = FillSolid;
+ gcmask |= GCForeground | GCFillStyle;
+ break;
+ case BackgroundPixmap:
+ newValues[TILE].ptr = (pointer)pWin->background.pixmap;
+ newValues[FILLSTYLE].val = FillTiled;
+ gcmask |= GCTile | GCFillStyle | GCTileStipXOrigin | GCTileStipYOrigin;
+ break;
+ }
+ }
+ else
+ {
+ if (pWin->borderIsPixel)
+ {
+ newValues[FOREGROUND].val = pWin->border.pixel;
+ newValues[FILLSTYLE].val = FillSolid;
+ gcmask |= GCForeground | GCFillStyle;
+ }
+ else
+ {
+ newValues[TILE].ptr = (pointer)pWin->border.pixmap;
+ newValues[FILLSTYLE].val = FillTiled;
+ gcmask |= GCTile | GCFillStyle | GCTileStipXOrigin | GCTileStipYOrigin;
+ }
+ }
+
+ prect = (xRectangle *)ALLOCATE_LOCAL(REGION_NUM_RECTS(prgn) *
+ sizeof(xRectangle));
+ if (!prect)
+ return;
+
+ newValues[FUNCTION].val = GXcopy;
+ gcmask |= GCFunction | GCClipMask;
+
+ i = pScreen->myNum;
+ pRoot = WindowTable[i];
+
+ pBgWin = pWin;
+ if (what == PW_BORDER)
+ {
+ while (pBgWin->backgroundState == ParentRelative)
+ pBgWin = pBgWin->parent;
+ }
+
+ if ((pWin->drawable.depth != pRoot->drawable.depth) ||
+ (pWin->drawable.bitsPerPixel != pRoot->drawable.bitsPerPixel))
+ {
+ usingScratchGC = TRUE;
+ pGC = GetScratchGC(pWin->drawable.depth, pWin->drawable.pScreen);
+ if (!pGC)
+ {
+ DEALLOCATE_LOCAL(prect);
+ return;
+ }
+ /*
+ * mash the clip list so we can paint the border by
+ * mangling the window in place, pretending it
+ * spans the entire screen
+ */
+ if (what == PW_BORDER)
+ {
+ prgnWin = pWin->clipList;
+ oldCorner.x = pWin->drawable.x;
+ oldCorner.y = pWin->drawable.y;
+ pWin->drawable.x = pWin->drawable.y = 0;
+ box.x1 = 0;
+ box.y1 = 0;
+ box.x2 = pScreen->width;
+ box.y2 = pScreen->height;
+ REGION_INIT(pScreen, &pWin->clipList, &box, 1);
+ pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ newValues[ABSX].val = pBgWin->drawable.x;
+ newValues[ABSY].val = pBgWin->drawable.y;
+ }
+ else
+ {
+ newValues[ABSX].val = 0;
+ newValues[ABSY].val = 0;
+ }
+ } else {
+ /*
+ * draw the background to the root window
+ */
+ if (screenContext[i] == (GCPtr)NULL)
+ {
+ if (!ResType && !(ResType = CreateNewResourceType(tossGC)))
+ return;
+ screenContext[i] = CreateGC((DrawablePtr)pWin, (BITS32) 0,
+ (XID *)NULL, &status);
+ if (!screenContext[i])
+ return;
+ numGCs++;
+ if (!AddResource(FakeClientID(0), ResType,
+ (pointer)screenContext[i]))
+ return;
+ }
+ pGC = screenContext[i];
+ newValues[SUBWINDOW].val = IncludeInferiors;
+ newValues[ABSX].val = pBgWin->drawable.x;
+ newValues[ABSY].val = pBgWin->drawable.y;
+ gcmask |= GCSubwindowMode;
+ pWin = pRoot;
+ }
+
+ if (pWin->backStorage)
+ (*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeVisBack);
+
+ mask = gcmask;
+ gcmask = 0;
+ i = 0;
+ while (mask) {
+ index = lowbit (mask);
+ mask &= ~index;
+ switch (index) {
+ case GCFunction:
+ if (pGC->alu != newValues[FUNCTION].val) {
+ gcmask |= index;
+ gcval[i++].val = newValues[FUNCTION].val;
+ }
+ break;
+ case GCTileStipXOrigin:
+ if ( pGC->patOrg.x != newValues[ABSX].val) {
+ gcmask |= index;
+ gcval[i++].val = newValues[ABSX].val;
+ }
+ break;
+ case GCTileStipYOrigin:
+ if ( pGC->patOrg.y != newValues[ABSY].val) {
+ gcmask |= index;
+ gcval[i++].val = newValues[ABSY].val;
+ }
+ break;
+ case GCClipMask:
+ if ( pGC->clientClipType != CT_NONE) {
+ gcmask |= index;
+ gcval[i++].val = CT_NONE;
+ }
+ break;
+ case GCSubwindowMode:
+ if ( pGC->subWindowMode != newValues[SUBWINDOW].val) {
+ gcmask |= index;
+ gcval[i++].val = newValues[SUBWINDOW].val;
+ }
+ break;
+ case GCTile:
+ if (pGC->tileIsPixel || pGC->tile.pixmap != newValues[TILE].ptr)
+ {
+ gcmask |= index;
+ gcval[i++].ptr = newValues[TILE].ptr;
+ }
+ break;
+ case GCFillStyle:
+ if ( pGC->fillStyle != newValues[FILLSTYLE].val) {
+ gcmask |= index;
+ gcval[i++].val = newValues[FILLSTYLE].val;
+ }
+ break;
+ case GCForeground:
+ if ( pGC->fgPixel != newValues[FOREGROUND].val) {
+ gcmask |= index;
+ gcval[i++].val = newValues[FOREGROUND].val;
+ }
+ break;
+ }
+ }
+
+ if (gcmask)
+ dixChangeGC(NullClient, pGC, gcmask, NULL, gcval);
+
+ if (pWin->drawable.serialNumber != pGC->serialNumber)
+ ValidateGC((DrawablePtr)pWin, pGC);
+
+ numRects = REGION_NUM_RECTS(prgn);
+ pbox = REGION_RECTS(prgn);
+ for (i= numRects; --i >= 0; pbox++, prect++)
+ {
+ prect->x = pbox->x1 - pWin->drawable.x;
+ prect->y = pbox->y1 - pWin->drawable.y;
+ prect->width = pbox->x2 - pbox->x1;
+ prect->height = pbox->y2 - pbox->y1;
+ }
+ prect -= numRects;
+ (*pGC->ops->PolyFillRect)((DrawablePtr)pWin, pGC, numRects, prect);
+ DEALLOCATE_LOCAL(prect);
+
+ if (pWin->backStorage)
+ (*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeNothing);
+
+ if (usingScratchGC)
+ {
+ if (what == PW_BORDER)
+ {
+ REGION_UNINIT(pScreen, &pWin->clipList);
+ pWin->clipList = prgnWin;
+ pWin->drawable.x = oldCorner.x;
+ pWin->drawable.y = oldCorner.y;
+ pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ }
+ FreeScratchGC(pGC);
+ }
+}
+
+
+/* MICLEARDRAWABLE -- sets the entire drawable to the background color of
+ * the GC. Useful when we have a scratch drawable and need to initialize
+ * it. */
+_X_EXPORT void
+miClearDrawable(pDraw, pGC)
+ DrawablePtr pDraw;
+ GCPtr pGC;
+{
+ XID fg = pGC->fgPixel;
+ XID bg = pGC->bgPixel;
+ xRectangle rect;
+
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = pDraw->width;
+ rect.height = pDraw->height;
+ DoChangeGC(pGC, GCForeground, &bg, 0);
+ ValidateGC(pDraw, pGC);
+ (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect);
+ DoChangeGC(pGC, GCForeground, &fg, 0);
+ ValidateGC(pDraw, pGC);
+}
diff --git a/xserver/mi/mifillarc.c b/xserver/mi/mifillarc.c
new file mode 100644
index 000000000..66063166a
--- /dev/null
+++ b/xserver/mi/mifillarc.c
@@ -0,0 +1,815 @@
+/************************************************************
+
+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.
+
+Author: Bob Scheifler, MIT X Consortium
+
+********************************************************/
+
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <math.h>
+#include <X11/X.h>
+#include <X11/Xprotostr.h>
+#include "regionstr.h"
+#include "gcstruct.h"
+#include "pixmapstr.h"
+#include "mifpoly.h"
+#include "mi.h"
+#include "mifillarc.h"
+
+#define QUADRANT (90 * 64)
+#define HALFCIRCLE (180 * 64)
+#define QUADRANT3 (270 * 64)
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#define Dsin(d) sin((double)d*(M_PI/11520.0))
+#define Dcos(d) cos((double)d*(M_PI/11520.0))
+
+_X_EXPORT void
+miFillArcSetup(arc, info)
+ register xArc *arc;
+ register miFillArcRec *info;
+{
+ info->y = arc->height >> 1;
+ info->dy = arc->height & 1;
+ info->yorg = arc->y + info->y;
+ info->dx = arc->width & 1;
+ info->xorg = arc->x + (arc->width >> 1) + info->dx;
+ info->dx = 1 - info->dx;
+ if (arc->width == arc->height)
+ {
+ /* (2x - 2xorg)^2 = d^2 - (2y - 2yorg)^2 */
+ /* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */
+ info->ym = 8;
+ info->xm = 8;
+ info->yk = info->y << 3;
+ if (!info->dx)
+ {
+ info->xk = 0;
+ info->e = -1;
+ }
+ else
+ {
+ info->y++;
+ info->yk += 4;
+ info->xk = -4;
+ info->e = - (info->y << 3);
+ }
+ }
+ else
+ {
+ /* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */
+ /* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */
+ info->ym = (arc->width * arc->width) << 3;
+ info->xm = (arc->height * arc->height) << 3;
+ info->yk = info->y * info->ym;
+ if (!info->dy)
+ info->yk -= info->ym >> 1;
+ if (!info->dx)
+ {
+ info->xk = 0;
+ info->e = - (info->xm >> 3);
+ }
+ else
+ {
+ info->y++;
+ info->yk += info->ym;
+ info->xk = -(info->xm >> 1);
+ info->e = info->xk - info->yk;
+ }
+ }
+}
+
+void
+miFillArcDSetup(arc, info)
+ register xArc *arc;
+ register miFillArcDRec *info;
+{
+ /* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */
+ /* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */
+ info->y = arc->height >> 1;
+ info->dy = arc->height & 1;
+ info->yorg = arc->y + info->y;
+ info->dx = arc->width & 1;
+ info->xorg = arc->x + (arc->width >> 1) + info->dx;
+ info->dx = 1 - info->dx;
+ info->ym = ((double)arc->width) * (arc->width * 8);
+ info->xm = ((double)arc->height) * (arc->height * 8);
+ info->yk = info->y * info->ym;
+ if (!info->dy)
+ info->yk -= info->ym / 2.0;
+ if (!info->dx)
+ {
+ info->xk = 0;
+ info->e = - (info->xm / 8.0);
+ }
+ else
+ {
+ info->y++;
+ info->yk += info->ym;
+ info->xk = -info->xm / 2.0;
+ info->e = info->xk - info->yk;
+ }
+}
+
+static void
+miGetArcEdge(
+ register xArc *arc,
+ register miSliceEdgePtr edge,
+ int k,
+ Bool top,
+ Bool left )
+{
+ register int xady, y;
+
+ y = arc->height >> 1;
+ if (!(arc->width & 1))
+ y++;
+ if (!top)
+ {
+ y = -y;
+ if (arc->height & 1)
+ y--;
+ }
+ xady = k + y * edge->dx;
+ if (xady <= 0)
+ edge->x = - ((-xady) / edge->dy + 1);
+ else
+ edge->x = (xady - 1) / edge->dy;
+ edge->e = xady - edge->x * edge->dy;
+ if ((top && (edge->dx < 0)) || (!top && (edge->dx > 0)))
+ edge->e = edge->dy - edge->e + 1;
+ if (left)
+ edge->x++;
+ edge->x += arc->x + (arc->width >> 1);
+ if (edge->dx > 0)
+ {
+ edge->deltax = 1;
+ edge->stepx = edge->dx / edge->dy;
+ edge->dx = edge->dx % edge->dy;
+ }
+ else
+ {
+ edge->deltax = -1;
+ edge->stepx = - ((-edge->dx) / edge->dy);
+ edge->dx = (-edge->dx) % edge->dy;
+ }
+ if (!top)
+ {
+ edge->deltax = -edge->deltax;
+ edge->stepx = -edge->stepx;
+ }
+}
+
+void
+miEllipseAngleToSlope (angle, width, height, dxp, dyp, d_dxp, d_dyp)
+ int angle;
+ int width;
+ int height;
+ int *dxp;
+ int *dyp;
+ double *d_dxp;
+ double *d_dyp;
+{
+ int dx, dy;
+ double d_dx, d_dy, scale;
+ Bool negative_dx, negative_dy;
+
+ switch (angle) {
+ case 0:
+ *dxp = -1;
+ *dyp = 0;
+ if (d_dxp) {
+ *d_dxp = width / 2.0;
+ *d_dyp = 0;
+ }
+ break;
+ case QUADRANT:
+ *dxp = 0;
+ *dyp = 1;
+ if (d_dxp) {
+ *d_dxp = 0;
+ *d_dyp = - height / 2.0;
+ }
+ break;
+ case HALFCIRCLE:
+ *dxp = 1;
+ *dyp = 0;
+ if (d_dxp) {
+ *d_dxp = - width / 2.0;
+ *d_dyp = 0;
+ }
+ break;
+ case QUADRANT3:
+ *dxp = 0;
+ *dyp = -1;
+ if (d_dxp) {
+ *d_dxp = 0;
+ *d_dyp = height / 2.0;
+ }
+ break;
+ default:
+ d_dx = Dcos(angle) * width;
+ d_dy = Dsin(angle) * height;
+ if (d_dxp) {
+ *d_dxp = d_dx / 2.0;
+ *d_dyp = - d_dy / 2.0;
+ }
+ negative_dx = FALSE;
+ if (d_dx < 0.0)
+ {
+ d_dx = -d_dx;
+ negative_dx = TRUE;
+ }
+ negative_dy = FALSE;
+ if (d_dy < 0.0)
+ {
+ d_dy = -d_dy;
+ negative_dy = TRUE;
+ }
+ scale = d_dx;
+ if (d_dy > d_dx)
+ scale = d_dy;
+ dx = floor ((d_dx * 32768) / scale + 0.5);
+ if (negative_dx)
+ dx = -dx;
+ *dxp = dx;
+ dy = floor ((d_dy * 32768) / scale + 0.5);
+ if (negative_dy)
+ dy = -dy;
+ *dyp = dy;
+ break;
+ }
+}
+
+static void
+miGetPieEdge(
+ register xArc *arc,
+ register int angle,
+ register miSliceEdgePtr edge,
+ Bool top,
+ Bool left )
+{
+ register int k;
+ int dx, dy;
+
+ miEllipseAngleToSlope (angle, arc->width, arc->height, &dx, &dy, 0, 0);
+
+ if (dy == 0)
+ {
+ edge->x = left ? -65536 : 65536;
+ edge->stepx = 0;
+ edge->e = 0;
+ edge->dx = -1;
+ return;
+ }
+ if (dx == 0)
+ {
+ edge->x = arc->x + (arc->width >> 1);
+ if (left && (arc->width & 1))
+ edge->x++;
+ else if (!left && !(arc->width & 1))
+ edge->x--;
+ edge->stepx = 0;
+ edge->e = 0;
+ edge->dx = -1;
+ return;
+ }
+ if (dy < 0) {
+ dx = -dx;
+ dy = -dy;
+ }
+ k = (arc->height & 1) ? dx : 0;
+ if (arc->width & 1)
+ k += dy;
+ edge->dx = dx << 1;
+ edge->dy = dy << 1;
+ miGetArcEdge(arc, edge, k, top, left);
+}
+
+_X_EXPORT void
+miFillArcSliceSetup(arc, slice, pGC)
+ register xArc *arc;
+ register miArcSliceRec *slice;
+ GCPtr pGC;
+{
+ register int angle1, angle2;
+
+ angle1 = arc->angle1;
+ if (arc->angle2 < 0)
+ {
+ angle2 = angle1;
+ angle1 += arc->angle2;
+ }
+ else
+ angle2 = angle1 + arc->angle2;
+ while (angle1 < 0)
+ angle1 += FULLCIRCLE;
+ while (angle1 >= FULLCIRCLE)
+ angle1 -= FULLCIRCLE;
+ while (angle2 < 0)
+ angle2 += FULLCIRCLE;
+ while (angle2 >= FULLCIRCLE)
+ angle2 -= FULLCIRCLE;
+ slice->min_top_y = 0;
+ slice->max_top_y = arc->height >> 1;
+ slice->min_bot_y = 1 - (arc->height & 1);
+ slice->max_bot_y = slice->max_top_y - 1;
+ slice->flip_top = FALSE;
+ slice->flip_bot = FALSE;
+ if (pGC->arcMode == ArcPieSlice)
+ {
+ slice->edge1_top = (angle1 < HALFCIRCLE);
+ slice->edge2_top = (angle2 <= HALFCIRCLE);
+ if ((angle2 == 0) || (angle1 == HALFCIRCLE))
+ {
+ if (angle2 ? slice->edge2_top : slice->edge1_top)
+ slice->min_top_y = slice->min_bot_y;
+ else
+ slice->min_top_y = arc->height;
+ slice->min_bot_y = 0;
+ }
+ else if ((angle1 == 0) || (angle2 == HALFCIRCLE))
+ {
+ slice->min_top_y = slice->min_bot_y;
+ if (angle1 ? slice->edge1_top : slice->edge2_top)
+ slice->min_bot_y = arc->height;
+ else
+ slice->min_bot_y = 0;
+ }
+ else if (slice->edge1_top == slice->edge2_top)
+ {
+ if (angle2 < angle1)
+ {
+ slice->flip_top = slice->edge1_top;
+ slice->flip_bot = !slice->edge1_top;
+ }
+ else if (slice->edge1_top)
+ {
+ slice->min_top_y = 1;
+ slice->min_bot_y = arc->height;
+ }
+ else
+ {
+ slice->min_bot_y = 0;
+ slice->min_top_y = arc->height;
+ }
+ }
+ miGetPieEdge(arc, angle1, &slice->edge1,
+ slice->edge1_top, !slice->edge1_top);
+ miGetPieEdge(arc, angle2, &slice->edge2,
+ slice->edge2_top, slice->edge2_top);
+ }
+ else
+ {
+ double w2, h2, x1, y1, x2, y2, dx, dy, scale;
+ int signdx, signdy, y, k;
+ Bool isInt1 = TRUE, isInt2 = TRUE;
+
+ w2 = (double)arc->width / 2.0;
+ h2 = (double)arc->height / 2.0;
+ if ((angle1 == 0) || (angle1 == HALFCIRCLE))
+ {
+ x1 = angle1 ? -w2 : w2;
+ y1 = 0.0;
+ }
+ else if ((angle1 == QUADRANT) || (angle1 == QUADRANT3))
+ {
+ x1 = 0.0;
+ y1 = (angle1 == QUADRANT) ? h2 : -h2;
+ }
+ else
+ {
+ isInt1 = FALSE;
+ x1 = Dcos(angle1) * w2;
+ y1 = Dsin(angle1) * h2;
+ }
+ if ((angle2 == 0) || (angle2 == HALFCIRCLE))
+ {
+ x2 = angle2 ? -w2 : w2;
+ y2 = 0.0;
+ }
+ else if ((angle2 == QUADRANT) || (angle2 == QUADRANT3))
+ {
+ x2 = 0.0;
+ y2 = (angle2 == QUADRANT) ? h2 : -h2;
+ }
+ else
+ {
+ isInt2 = FALSE;
+ x2 = Dcos(angle2) * w2;
+ y2 = Dsin(angle2) * h2;
+ }
+ dx = x2 - x1;
+ dy = y2 - y1;
+ if (arc->height & 1)
+ {
+ y1 -= 0.5;
+ y2 -= 0.5;
+ }
+ if (arc->width & 1)
+ {
+ x1 += 0.5;
+ x2 += 0.5;
+ }
+ if (dy < 0.0)
+ {
+ dy = -dy;
+ signdy = -1;
+ }
+ else
+ signdy = 1;
+ if (dx < 0.0)
+ {
+ dx = -dx;
+ signdx = -1;
+ }
+ else
+ signdx = 1;
+ if (isInt1 && isInt2)
+ {
+ slice->edge1.dx = dx * 2;
+ slice->edge1.dy = dy * 2;
+ }
+ else
+ {
+ scale = (dx > dy) ? dx : dy;
+ slice->edge1.dx = floor((dx * 32768) / scale + .5);
+ slice->edge1.dy = floor((dy * 32768) / scale + .5);
+ }
+ if (!slice->edge1.dy)
+ {
+ if (signdx < 0)
+ {
+ y = floor(y1 + 1.0);
+ if (y >= 0)
+ {
+ slice->min_top_y = y;
+ slice->min_bot_y = arc->height;
+ }
+ else
+ {
+ slice->max_bot_y = -y - (arc->height & 1);
+ }
+ }
+ else
+ {
+ y = floor(y1);
+ if (y >= 0)
+ slice->max_top_y = y;
+ else
+ {
+ slice->min_top_y = arc->height;
+ slice->min_bot_y = -y - (arc->height & 1);
+ }
+ }
+ slice->edge1_top = TRUE;
+ slice->edge1.x = 65536;
+ slice->edge1.stepx = 0;
+ slice->edge1.e = 0;
+ slice->edge1.dx = -1;
+ slice->edge2 = slice->edge1;
+ slice->edge2_top = FALSE;
+ }
+ else if (!slice->edge1.dx)
+ {
+ if (signdy < 0)
+ x1 -= 1.0;
+ slice->edge1.x = ceil(x1);
+ slice->edge1_top = signdy < 0;
+ slice->edge1.x += arc->x + (arc->width >> 1);
+ slice->edge1.stepx = 0;
+ slice->edge1.e = 0;
+ slice->edge1.dx = -1;
+ slice->edge2_top = !slice->edge1_top;
+ slice->edge2 = slice->edge1;
+ }
+ else
+ {
+ if (signdx < 0)
+ slice->edge1.dx = -slice->edge1.dx;
+ if (signdy < 0)
+ slice->edge1.dx = -slice->edge1.dx;
+ k = ceil(((x1 + x2) * slice->edge1.dy - (y1 + y2) * slice->edge1.dx) / 2.0);
+ slice->edge2.dx = slice->edge1.dx;
+ slice->edge2.dy = slice->edge1.dy;
+ slice->edge1_top = signdy < 0;
+ slice->edge2_top = !slice->edge1_top;
+ miGetArcEdge(arc, &slice->edge1, k,
+ slice->edge1_top, !slice->edge1_top);
+ miGetArcEdge(arc, &slice->edge2, k,
+ slice->edge2_top, slice->edge2_top);
+ }
+ }
+}
+
+#define ADDSPANS() \
+ pts->x = xorg - x; \
+ pts->y = yorg - y; \
+ *wids = slw; \
+ pts++; \
+ wids++; \
+ if (miFillArcLower(slw)) \
+ { \
+ pts->x = xorg - x; \
+ pts->y = yorg + y + dy; \
+ pts++; \
+ *wids++ = slw; \
+ }
+
+static void
+miFillEllipseI(
+ DrawablePtr pDraw,
+ GCPtr pGC,
+ xArc *arc )
+{
+ register int x, y, e;
+ int yk, xk, ym, xm, dx, dy, xorg, yorg;
+ int slw;
+ miFillArcRec info;
+ DDXPointPtr points;
+ register DDXPointPtr pts;
+ int *widths;
+ register int *wids;
+
+ points = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * arc->height);
+ if (!points)
+ return;
+ widths = (int *)ALLOCATE_LOCAL(sizeof(int) * arc->height);
+ if (!widths)
+ {
+ DEALLOCATE_LOCAL(points);
+ return;
+ }
+ miFillArcSetup(arc, &info);
+ MIFILLARCSETUP();
+ if (pGC->miTranslate)
+ {
+ xorg += pDraw->x;
+ yorg += pDraw->y;
+ }
+ pts = points;
+ wids = widths;
+ while (y > 0)
+ {
+ MIFILLARCSTEP(slw);
+ ADDSPANS();
+ }
+ (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE);
+ DEALLOCATE_LOCAL(widths);
+ DEALLOCATE_LOCAL(points);
+}
+
+static void
+miFillEllipseD(
+ DrawablePtr pDraw,
+ GCPtr pGC,
+ xArc *arc )
+{
+ register int x, y;
+ int xorg, yorg, dx, dy, slw;
+ double e, yk, xk, ym, xm;
+ miFillArcDRec info;
+ DDXPointPtr points;
+ register DDXPointPtr pts;
+ int *widths;
+ register int *wids;
+
+ points = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * arc->height);
+ if (!points)
+ return;
+ widths = (int *)ALLOCATE_LOCAL(sizeof(int) * arc->height);
+ if (!widths)
+ {
+ DEALLOCATE_LOCAL(points);
+ return;
+ }
+ miFillArcDSetup(arc, &info);
+ MIFILLARCSETUP();
+ if (pGC->miTranslate)
+ {
+ xorg += pDraw->x;
+ yorg += pDraw->y;
+ }
+ pts = points;
+ wids = widths;
+ while (y > 0)
+ {
+ MIFILLARCSTEP(slw);
+ ADDSPANS();
+ }
+ (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE);
+ DEALLOCATE_LOCAL(widths);
+ DEALLOCATE_LOCAL(points);
+}
+
+#define ADDSPAN(l,r) \
+ if (r >= l) \
+ { \
+ pts->x = l; \
+ pts->y = ya; \
+ pts++; \
+ *wids++ = r - l + 1; \
+ }
+
+#define ADDSLICESPANS(flip) \
+ if (!flip) \
+ { \
+ ADDSPAN(xl, xr); \
+ } \
+ else \
+ { \
+ xc = xorg - x; \
+ ADDSPAN(xc, xr); \
+ xc += slw - 1; \
+ ADDSPAN(xl, xc); \
+ }
+
+static void
+miFillArcSliceI(
+ DrawablePtr pDraw,
+ GCPtr pGC,
+ xArc *arc )
+{
+ int yk, xk, ym, xm, dx, dy, xorg, yorg, slw;
+ register int x, y, e;
+ miFillArcRec info;
+ miArcSliceRec slice;
+ int ya, xl, xr, xc;
+ DDXPointPtr points;
+ register DDXPointPtr pts;
+ int *widths;
+ register int *wids;
+
+ miFillArcSetup(arc, &info);
+ miFillArcSliceSetup(arc, &slice, pGC);
+ MIFILLARCSETUP();
+ slw = arc->height;
+ if (slice.flip_top || slice.flip_bot)
+ slw += (arc->height >> 1) + 1;
+ points = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * slw);
+ if (!points)
+ return;
+ widths = (int *)ALLOCATE_LOCAL(sizeof(int) * slw);
+ if (!widths)
+ {
+ DEALLOCATE_LOCAL(points);
+ return;
+ }
+ if (pGC->miTranslate)
+ {
+ xorg += pDraw->x;
+ yorg += pDraw->y;
+ slice.edge1.x += pDraw->x;
+ slice.edge2.x += pDraw->x;
+ }
+ pts = points;
+ wids = widths;
+ while (y > 0)
+ {
+ MIFILLARCSTEP(slw);
+ MIARCSLICESTEP(slice.edge1);
+ MIARCSLICESTEP(slice.edge2);
+ if (miFillSliceUpper(slice))
+ {
+ ya = yorg - y;
+ MIARCSLICEUPPER(xl, xr, slice, slw);
+ ADDSLICESPANS(slice.flip_top);
+ }
+ if (miFillSliceLower(slice))
+ {
+ ya = yorg + y + dy;
+ MIARCSLICELOWER(xl, xr, slice, slw);
+ ADDSLICESPANS(slice.flip_bot);
+ }
+ }
+ (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE);
+ DEALLOCATE_LOCAL(widths);
+ DEALLOCATE_LOCAL(points);
+}
+
+static void
+miFillArcSliceD(
+ DrawablePtr pDraw,
+ GCPtr pGC,
+ xArc *arc )
+{
+ register int x, y;
+ int dx, dy, xorg, yorg, slw;
+ double e, yk, xk, ym, xm;
+ miFillArcDRec info;
+ miArcSliceRec slice;
+ int ya, xl, xr, xc;
+ DDXPointPtr points;
+ register DDXPointPtr pts;
+ int *widths;
+ register int *wids;
+
+ miFillArcDSetup(arc, &info);
+ miFillArcSliceSetup(arc, &slice, pGC);
+ MIFILLARCSETUP();
+ slw = arc->height;
+ if (slice.flip_top || slice.flip_bot)
+ slw += (arc->height >> 1) + 1;
+ points = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * slw);
+ if (!points)
+ return;
+ widths = (int *)ALLOCATE_LOCAL(sizeof(int) * slw);
+ if (!widths)
+ {
+ DEALLOCATE_LOCAL(points);
+ return;
+ }
+ if (pGC->miTranslate)
+ {
+ xorg += pDraw->x;
+ yorg += pDraw->y;
+ slice.edge1.x += pDraw->x;
+ slice.edge2.x += pDraw->x;
+ }
+ pts = points;
+ wids = widths;
+ while (y > 0)
+ {
+ MIFILLARCSTEP(slw);
+ MIARCSLICESTEP(slice.edge1);
+ MIARCSLICESTEP(slice.edge2);
+ if (miFillSliceUpper(slice))
+ {
+ ya = yorg - y;
+ MIARCSLICEUPPER(xl, xr, slice, slw);
+ ADDSLICESPANS(slice.flip_top);
+ }
+ if (miFillSliceLower(slice))
+ {
+ ya = yorg + y + dy;
+ MIARCSLICELOWER(xl, xr, slice, slw);
+ ADDSLICESPANS(slice.flip_bot);
+ }
+ }
+ (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE);
+ DEALLOCATE_LOCAL(widths);
+ DEALLOCATE_LOCAL(points);
+}
+
+/* MIPOLYFILLARC -- The public entry for the PolyFillArc request.
+ * Since we don't have to worry about overlapping segments, we can just
+ * fill each arc as it comes.
+ */
+_X_EXPORT void
+miPolyFillArc(pDraw, pGC, narcs, parcs)
+ DrawablePtr pDraw;
+ GCPtr pGC;
+ int narcs;
+ xArc *parcs;
+{
+ register int i;
+ register xArc *arc;
+
+ for(i = narcs, arc = parcs; --i >= 0; arc++)
+ {
+ if (miFillArcEmpty(arc))
+ continue;;
+ if ((arc->angle2 >= FULLCIRCLE) || (arc->angle2 <= -FULLCIRCLE))
+ {
+ if (miCanFillArc(arc))
+ miFillEllipseI(pDraw, pGC, arc);
+ else
+ miFillEllipseD(pDraw, pGC, arc);
+ }
+ else
+ {
+ if (miCanFillArc(arc))
+ miFillArcSliceI(pDraw, pGC, arc);
+ else
+ miFillArcSliceD(pDraw, pGC, arc);
+ }
+ }
+}
diff --git a/xserver/mi/mifillarc.h b/xserver/mi/mifillarc.h
new file mode 100644
index 000000000..53f6f23ea
--- /dev/null
+++ b/xserver/mi/mifillarc.h
@@ -0,0 +1,214 @@
+/************************************************************
+
+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.
+
+********************************************************/
+
+
+#ifndef __MIFILLARC_H__
+#define __MIFILLARC_H__
+
+#define FULLCIRCLE (360 * 64)
+
+typedef struct _miFillArc {
+ int xorg, yorg;
+ int y;
+ int dx, dy;
+ int e;
+ int ym, yk, xm, xk;
+} miFillArcRec;
+
+/* could use 64-bit integers */
+typedef struct _miFillArcD {
+ int xorg, yorg;
+ int y;
+ int dx, dy;
+ double e;
+ double ym, yk, xm, xk;
+} miFillArcDRec;
+
+#define miFillArcEmpty(arc) (!(arc)->angle2 || \
+ !(arc)->width || !(arc)->height || \
+ (((arc)->width == 1) && ((arc)->height & 1)))
+
+#define miCanFillArc(arc) (((arc)->width == (arc)->height) || \
+ (((arc)->width <= 800) && ((arc)->height <= 800)))
+
+#define MIFILLARCSETUP() \
+ x = 0; \
+ y = info.y; \
+ e = info.e; \
+ xk = info.xk; \
+ xm = info.xm; \
+ yk = info.yk; \
+ ym = info.ym; \
+ dx = info.dx; \
+ dy = info.dy; \
+ xorg = info.xorg; \
+ yorg = info.yorg
+
+#define MIFILLARCSTEP(slw) \
+ e += yk; \
+ while (e >= 0) \
+ { \
+ x++; \
+ xk -= xm; \
+ e += xk; \
+ } \
+ y--; \
+ yk -= ym; \
+ slw = (x << 1) + dx; \
+ if ((e == xk) && (slw > 1)) \
+ slw--
+
+#define MIFILLCIRCSTEP(slw) MIFILLARCSTEP(slw)
+#define MIFILLELLSTEP(slw) MIFILLARCSTEP(slw)
+
+#define miFillArcLower(slw) (((y + dy) != 0) && ((slw > 1) || (e != xk)))
+
+typedef struct _miSliceEdge {
+ int x;
+ int stepx;
+ int deltax;
+ int e;
+ int dy;
+ int dx;
+} miSliceEdgeRec, *miSliceEdgePtr;
+
+typedef struct _miArcSlice {
+ miSliceEdgeRec edge1, edge2;
+ int min_top_y, max_top_y;
+ int min_bot_y, max_bot_y;
+ Bool edge1_top, edge2_top;
+ Bool flip_top, flip_bot;
+} miArcSliceRec;
+
+#define MIARCSLICESTEP(edge) \
+ edge.x -= edge.stepx; \
+ edge.e -= edge.dx; \
+ if (edge.e <= 0) \
+ { \
+ edge.x -= edge.deltax; \
+ edge.e += edge.dy; \
+ }
+
+#define miFillSliceUpper(slice) \
+ ((y >= slice.min_top_y) && (y <= slice.max_top_y))
+
+#define miFillSliceLower(slice) \
+ ((y >= slice.min_bot_y) && (y <= slice.max_bot_y))
+
+#define MIARCSLICEUPPER(xl,xr,slice,slw) \
+ xl = xorg - x; \
+ xr = xl + slw - 1; \
+ if (slice.edge1_top && (slice.edge1.x < xr)) \
+ xr = slice.edge1.x; \
+ if (slice.edge2_top && (slice.edge2.x > xl)) \
+ xl = slice.edge2.x;
+
+#define MIARCSLICELOWER(xl,xr,slice,slw) \
+ xl = xorg - x; \
+ xr = xl + slw - 1; \
+ if (!slice.edge1_top && (slice.edge1.x > xl)) \
+ xl = slice.edge1.x; \
+ if (!slice.edge2_top && (slice.edge2.x < xr)) \
+ xr = slice.edge2.x;
+
+#define MIWIDEARCSETUP(x,y,dy,slw,e,xk,xm,yk,ym) \
+ x = 0; \
+ y = slw >> 1; \
+ yk = y << 3; \
+ xm = 8; \
+ ym = 8; \
+ if (dy) \
+ { \
+ xk = 0; \
+ if (slw & 1) \
+ e = -1; \
+ else \
+ e = -(y << 2) - 2; \
+ } \
+ else \
+ { \
+ y++; \
+ yk += 4; \
+ xk = -4; \
+ if (slw & 1) \
+ e = -(y << 2) - 3; \
+ else \
+ e = - (y << 3); \
+ }
+
+#define MIFILLINARCSTEP(slw) \
+ ine += inyk; \
+ while (ine >= 0) \
+ { \
+ inx++; \
+ inxk -= inxm; \
+ ine += inxk; \
+ } \
+ iny--; \
+ inyk -= inym; \
+ slw = (inx << 1) + dx; \
+ if ((ine == inxk) && (slw > 1)) \
+ slw--
+
+#define miFillInArcLower(slw) (((iny + dy) != 0) && \
+ ((slw > 1) || (ine != inxk)))
+
+extern int miFreeArcCache(
+ pointer /*data*/,
+ XID /*id*/
+);
+
+extern struct finalSpan *realAllocSpan(
+ void
+);
+
+extern void miFillArcSetup(
+ xArc * /*arc*/,
+ miFillArcRec * /*info*/
+);
+
+extern void miFillArcDSetup(
+ xArc * /*arc*/,
+ miFillArcDRec * /*info*/
+);
+
+extern void miEllipseAngleToSlope(
+ int /*angle*/,
+ int /*width*/,
+ int /*height*/,
+ int * /*dxp*/,
+ int * /*dyp*/,
+ double * /*d_dxp*/,
+ double * /*d_dyp*/
+);
+
+extern void miFillArcSliceSetup(
+ xArc * /*arc*/,
+ miArcSliceRec * /*slice*/,
+ GCPtr /*pGC*/
+);
+
+#endif /* __MIFILLARC_H__ */
diff --git a/xserver/mi/mifillrct.c b/xserver/mi/mifillrct.c
new file mode 100644
index 000000000..78e89d69c
--- /dev/null
+++ b/xserver/mi/mifillrct.c
@@ -0,0 +1,142 @@
+/***********************************************************
+
+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/Xprotostr.h>
+#include "gcstruct.h"
+#include "windowstr.h"
+#include "pixmap.h"
+#include "mi.h"
+#include "misc.h"
+
+/* mi rectangles
+ written by newman, with debts to all and sundry
+*/
+
+/* MIPOLYFILLRECT -- public entry for PolyFillRect request
+ * very straight forward: translate rectangles if necessary
+ * then call FillSpans to fill each rectangle. We let FillSpans worry about
+ * clipping to the destination
+ */
+_X_EXPORT void
+miPolyFillRect(pDrawable, pGC, nrectFill, prectInit)
+ DrawablePtr pDrawable;
+ GCPtr pGC;
+ int nrectFill; /* number of rectangles to fill */
+ xRectangle *prectInit; /* Pointer to first rectangle to fill */
+{
+ int i;
+ register int height;
+ register int width;
+ register xRectangle *prect;
+ int xorg;
+ register int yorg;
+ int maxheight;
+ DDXPointPtr pptFirst;
+ register DDXPointPtr ppt;
+ int *pwFirst;
+ register int *pw;
+
+ if (pGC->miTranslate)
+ {
+ xorg = pDrawable->x;
+ yorg = pDrawable->y;
+ prect = prectInit;
+ maxheight = 0;
+ for (i = 0; i<nrectFill; i++, prect++)
+ {
+ prect->x += xorg;
+ prect->y += yorg;
+ maxheight = max(maxheight, prect->height);
+ }
+ }
+ else
+ {
+ prect = prectInit;
+ maxheight = 0;
+ for (i = 0; i<nrectFill; i++, prect++)
+ maxheight = max(maxheight, prect->height);
+ }
+
+ pptFirst = (DDXPointPtr) ALLOCATE_LOCAL(maxheight * sizeof(DDXPointRec));
+ pwFirst = (int *) ALLOCATE_LOCAL(maxheight * sizeof(int));
+ if(!pptFirst || !pwFirst)
+ {
+ if (pwFirst) DEALLOCATE_LOCAL(pwFirst);
+ if (pptFirst) DEALLOCATE_LOCAL(pptFirst);
+ return;
+ }
+
+ prect = prectInit;
+ while(nrectFill--)
+ {
+ ppt = pptFirst;
+ pw = pwFirst;
+ height = prect->height;
+ width = prect->width;
+ xorg = prect->x;
+ yorg = prect->y;
+ while(height--)
+ {
+ *pw++ = width;
+ ppt->x = xorg;
+ ppt->y = yorg;
+ ppt++;
+ yorg++;
+ }
+ (* pGC->ops->FillSpans)(pDrawable, pGC,
+ prect->height, pptFirst, pwFirst,
+ 1);
+ prect++;
+ }
+ DEALLOCATE_LOCAL(pwFirst);
+ DEALLOCATE_LOCAL(pptFirst);
+}
diff --git a/xserver/mi/mifpoly.h b/xserver/mi/mifpoly.h
new file mode 100644
index 000000000..8f0507601
--- /dev/null
+++ b/xserver/mi/mifpoly.h
@@ -0,0 +1,109 @@
+/***********************************************************
+
+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.
+
+******************************************************************/
+
+#ifndef __MIFPOLY_H__
+#define __MIFPOLY_H__
+
+#define EPSILON 0.000001
+#define ISEQUAL(a,b) (Fabs((a) - (b)) <= EPSILON)
+#define UNEQUAL(a,b) (Fabs((a) - (b)) > EPSILON)
+#define WITHINHALF(a, b) (((a) - (b) > 0.0) ? (a) - (b) < 0.5 : \
+ (b) - (a) <= 0.5)
+#define ROUNDTOINT(x) ((int) (((x) > 0.0) ? ((x) + 0.5) : ((x) - 0.5)))
+#define ISZERO(x) (Fabs((x)) <= EPSILON)
+#define PTISEQUAL(a,b) (ISEQUAL(a.x,b.x) && ISEQUAL(a.y,b.y))
+#define PTUNEQUAL(a,b) (UNEQUAL(a.x,b.x) || UNEQUAL(a.y,b.y))
+#define PtEqual(a, b) (((a).x == (b).x) && ((a).y == (b).y))
+
+#define NotEnd 0
+#define FirstEnd 1
+#define SecondEnd 2
+
+#define SQSECANT 108.856472512142 /* 1/sin^2(11/2) - for 11o miter cutoff */
+#define D2SECANT 5.21671526231167 /* 1/2*sin(11/2) - max extension per width */
+
+#ifdef NOINLINEICEIL
+#define ICEIL(x) ((int)ceil(x))
+#else
+#ifdef __GNUC__
+static __inline int ICEIL(double x)
+{
+ int _cTmp = x;
+ return ((x == _cTmp) || (x < 0.0)) ? _cTmp : _cTmp+1;
+}
+#else
+#define ICEIL(x) ((((x) == (_cTmp = (x))) || ((x) < 0.0)) ? _cTmp : _cTmp+1)
+#define ICEILTEMPDECL static int _cTmp;
+#endif
+#endif
+
+/* Point with sub-pixel positioning. In this case we use doubles, but
+ * see mifpolycon.c for other suggestions
+ */
+typedef struct _SppPoint {
+ double x, y;
+} SppPointRec, *SppPointPtr;
+
+typedef struct _SppArc {
+ double x, y, width, height;
+ double angle1, angle2;
+} SppArcRec, *SppArcPtr;
+
+/* mifpolycon.c */
+
+extern void miFillSppPoly(
+ DrawablePtr /*dst*/,
+ GCPtr /*pgc*/,
+ int /*count*/,
+ SppPointPtr /*ptsIn*/,
+ int /*xTrans*/,
+ int /*yTrans*/,
+ double /*xFtrans*/,
+ double /*yFtrans*/
+);
+
+#endif /* __MIFPOLY_H__ */
diff --git a/xserver/mi/mifpolycon.c b/xserver/mi/mifpolycon.c
new file mode 100644
index 000000000..57229f639
--- /dev/null
+++ b/xserver/mi/mifpolycon.c
@@ -0,0 +1,282 @@
+/***********************************************************
+
+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 <math.h>
+#include <X11/X.h>
+#include "gcstruct.h"
+#include "windowstr.h"
+#include "pixmapstr.h"
+#include "mifpoly.h"
+
+static int GetFPolyYBounds(register SppPointPtr pts, int n, double yFtrans,
+ int *by, int *ty);
+
+#ifdef ICEILTEMPDECL
+ICEILTEMPDECL
+#endif
+
+/*
+ * Written by Todd Newman; April. 1987.
+ *
+ * Fill a convex polygon. If the given polygon
+ * is not convex, then the result is undefined.
+ * The algorithm is to order the edges from smallest
+ * y to largest by partitioning the array into a left
+ * edge list and a right edge list. The algorithm used
+ * to traverse each edge is digital differencing analyzer
+ * line algorithm with y as the major axis. There's some funny linear
+ * interpolation involved because of the subpixel postioning.
+ */
+void
+miFillSppPoly(dst, pgc, count, ptsIn, xTrans, yTrans, xFtrans, yFtrans)
+ DrawablePtr dst;
+ GCPtr pgc;
+ int count; /* number of points */
+ SppPointPtr ptsIn; /* the points */
+ int xTrans, yTrans; /* Translate each point by this */
+ double xFtrans, yFtrans; /* translate before conversion
+ by this amount. This provides
+ a mechanism to match rounding
+ errors with any shape that must
+ meet the polygon exactly.
+ */
+{
+ double xl = 0.0, xr = 0.0, /* x vals of left and right edges */
+ ml = 0.0, /* left edge slope */
+ mr = 0.0, /* right edge slope */
+ dy, /* delta y */
+ i; /* loop counter */
+ int y, /* current scanline */
+ j,
+ imin, /* index of vertex with smallest y */
+ ymin, /* y-extents of polygon */
+ ymax,
+ *width,
+ *FirstWidth, /* output buffer */
+ *Marked; /* set if this vertex has been used */
+ register int left, right, /* indices to first endpoints */
+ nextleft,
+ nextright; /* indices to second endpoints */
+ DDXPointPtr ptsOut,
+ FirstPoint; /* output buffer */
+
+ if (pgc->miTranslate)
+ {
+ xTrans += dst->x;
+ yTrans += dst->y;
+ }
+
+ imin = GetFPolyYBounds(ptsIn, count, yFtrans, &ymin, &ymax);
+
+ y = ymax - ymin + 1;
+ if ((count < 3) || (y <= 0))
+ return;
+ ptsOut = FirstPoint = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * y);
+ width = FirstWidth = (int *) ALLOCATE_LOCAL(sizeof(int) * y);
+ Marked = (int *) ALLOCATE_LOCAL(sizeof(int) * count);
+
+ if(!ptsOut || !width || !Marked)
+ {
+ if (Marked) DEALLOCATE_LOCAL(Marked);
+ if (width) DEALLOCATE_LOCAL(width);
+ if (ptsOut) DEALLOCATE_LOCAL(ptsOut);
+ return;
+ }
+
+ for(j = 0; j < count; j++)
+ Marked[j] = 0;
+ nextleft = nextright = imin;
+ Marked[imin] = -1;
+ y = ICEIL(ptsIn[nextleft].y + yFtrans);
+
+ /*
+ * loop through all edges of the polygon
+ */
+ do
+ {
+ /* add a left edge if we need to */
+ if ((y > (ptsIn[nextleft].y + yFtrans) ||
+ ISEQUAL(y, ptsIn[nextleft].y + yFtrans)) &&
+ Marked[nextleft] != 1)
+ {
+ Marked[nextleft]++;
+ left = nextleft++;
+
+ /* find the next edge, considering the end conditions */
+ if (nextleft >= count)
+ nextleft = 0;
+
+ /* now compute the starting point and slope */
+ dy = ptsIn[nextleft].y - ptsIn[left].y;
+ if (dy != 0.0)
+ {
+ ml = (ptsIn[nextleft].x - ptsIn[left].x) / dy;
+ dy = y - (ptsIn[left].y + yFtrans);
+ xl = (ptsIn[left].x + xFtrans) + ml * max(dy, 0);
+ }
+ }
+
+ /* add a right edge if we need to */
+ if ((y > ptsIn[nextright].y + yFtrans) ||
+ (ISEQUAL(y, ptsIn[nextright].y + yFtrans)
+ && Marked[nextright] != 1))
+ {
+ Marked[nextright]++;
+ right = nextright--;
+
+ /* find the next edge, considering the end conditions */
+ if (nextright < 0)
+ nextright = count - 1;
+
+ /* now compute the starting point and slope */
+ dy = ptsIn[nextright].y - ptsIn[right].y;
+ if (dy != 0.0)
+ {
+ mr = (ptsIn[nextright].x - ptsIn[right].x) / dy;
+ dy = y - (ptsIn[right].y + yFtrans);
+ xr = (ptsIn[right].x + xFtrans) + mr * max(dy, 0);
+ }
+ }
+
+
+ /*
+ * generate scans to fill while we still have
+ * a right edge as well as a left edge.
+ */
+ i = (min(ptsIn[nextleft].y, ptsIn[nextright].y) + yFtrans) - y;
+
+ if (i < EPSILON)
+ {
+ if(Marked[nextleft] && Marked[nextright])
+ {
+ /* Arrgh, we're trapped! (no more points)
+ * Out, we've got to get out of here before this decadence saps
+ * our will completely! */
+ break;
+ }
+ continue;
+ }
+ else
+ {
+ j = (int) i;
+ if(!j)
+ j++;
+ }
+ while (j > 0)
+ {
+ int cxl, cxr;
+
+ ptsOut->y = (y) + yTrans;
+
+ cxl = ICEIL(xl);
+ cxr = ICEIL(xr);
+ /* reverse the edges if necessary */
+ if (xl < xr)
+ {
+ *(width++) = cxr - cxl;
+ (ptsOut++)->x = cxl + xTrans;
+ }
+ else
+ {
+ *(width++) = cxl - cxr;
+ (ptsOut++)->x = cxr + xTrans;
+ }
+ y++;
+
+ /* increment down the edges */
+ xl += ml;
+ xr += mr;
+ j--;
+ }
+ } while (y <= ymax);
+
+ /* Finally, fill the spans we've collected */
+ (*pgc->ops->FillSpans)(dst, pgc,
+ ptsOut-FirstPoint, FirstPoint, FirstWidth, 1);
+ DEALLOCATE_LOCAL(Marked);
+ DEALLOCATE_LOCAL(FirstWidth);
+ DEALLOCATE_LOCAL(FirstPoint);
+}
+
+
+/* Find the index of the point with the smallest y.also return the
+ * smallest and largest y */
+static
+int
+GetFPolyYBounds(
+ register SppPointPtr pts,
+ int n,
+ double yFtrans,
+ int *by,
+ int *ty)
+{
+ register SppPointPtr ptMin;
+ double ymin, ymax;
+ SppPointPtr ptsStart = pts;
+
+ ptMin = pts;
+ ymin = ymax = (pts++)->y;
+
+ while (--n > 0) {
+ if (pts->y < ymin)
+ {
+ ptMin = pts;
+ ymin = pts->y;
+ }
+ if(pts->y > ymax)
+ ymax = pts->y;
+
+ pts++;
+ }
+
+ *by = ICEIL(ymin + yFtrans);
+ *ty = ICEIL(ymax + yFtrans - 1);
+ return(ptMin-ptsStart);
+}
diff --git a/xserver/mi/migc.c b/xserver/mi/migc.c
new file mode 100644
index 000000000..46643ab26
--- /dev/null
+++ b/xserver/mi/migc.c
@@ -0,0 +1,299 @@
+/*
+
+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;
+{
+ 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;
+{
+ 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;
+{
+ (*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;
+ }
+ 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;
+{
+ 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
+ {
+ 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 */
+ pixbounds.x1 = pDrawable->x;
+ pixbounds.y1 = pDrawable->y;
+ pixbounds.x2 = pDrawable->x + pDrawable->width;
+ pixbounds.y2 = pDrawable->y + pDrawable->height;
+
+ if (pGC->freeCompClip)
+ {
+ 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 {
+ 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 */
+} /* end miComputeCompositeClip */
diff --git a/xserver/mi/migc.h b/xserver/mi/migc.h
new file mode 100644
index 000000000..84dc75c6c
--- /dev/null
+++ b/xserver/mi/migc.h
@@ -0,0 +1,72 @@
+/*
+
+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.
+
+*/
+
+
+extern void miChangeGC(
+ GCPtr /*pGC*/,
+ unsigned long /*mask*/
+);
+
+extern void miDestroyGC(
+ GCPtr /*pGC*/
+);
+
+extern GCOpsPtr miCreateGCOps(
+ GCOpsPtr /*prototype*/
+);
+
+extern void miDestroyGCOps(
+ GCOpsPtr /*ops*/
+);
+
+extern void miDestroyClip(
+ GCPtr /*pGC*/
+);
+
+extern void miChangeClip(
+ GCPtr /*pGC*/,
+ int /*type*/,
+ pointer /*pvalue*/,
+ int /*nrects*/
+);
+
+extern void miCopyClip(
+ GCPtr /*pgcDst*/,
+ GCPtr /*pgcSrc*/
+);
+
+extern void miCopyGC(
+ GCPtr /*pGCSrc*/,
+ unsigned long /*changes*/,
+ GCPtr /*pGCDst*/
+);
+
+extern void miComputeCompositeClip(
+ GCPtr /*pGC*/,
+ DrawablePtr /*pDrawable*/
+);
diff --git a/xserver/mi/miglblt.c b/xserver/mi/miglblt.c
new file mode 100644
index 000000000..db299a8ae
--- /dev/null
+++ b/xserver/mi/miglblt.c
@@ -0,0 +1,253 @@
+/***********************************************************
+
+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 <X11/fonts/fontstruct.h>
+#include "dixfontstr.h"
+#include "gcstruct.h"
+#include "windowstr.h"
+#include "scrnintstr.h"
+#include "pixmap.h"
+#include "servermd.h"
+#include "mi.h"
+
+/*
+ machine-independent glyph blt.
+ assumes that glyph bits in snf are written in bytes,
+have same bit order as the server's bitmap format,
+and are byte padded. this corresponds to the snf distributed
+with the sample server.
+
+ get a scratch GC.
+ in the scratch GC set alu = GXcopy, fg = 1, bg = 0
+ allocate a bitmap big enough to hold the largest glyph in the font
+ validate the scratch gc with the bitmap
+ for each glyph
+ carefully put the bits of the glyph in a buffer,
+ padded to the server pixmap scanline padding rules
+ fake a call to PutImage from the buffer into the bitmap
+ use the bitmap in a call to PushPixels
+*/
+
+_X_EXPORT void
+miPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)
+ DrawablePtr pDrawable;
+ GC *pGC;
+ int x, y;
+ unsigned int nglyph;
+ CharInfoPtr *ppci; /* array of character info */
+ pointer pglyphBase; /* start of array of glyphs */
+{
+ int width, height;
+ PixmapPtr pPixmap;
+ int nbyLine; /* bytes per line of padded pixmap */
+ FontPtr pfont;
+ GCPtr pGCtmp;
+ register int i;
+ register int j;
+ unsigned char *pbits; /* buffer for PutImage */
+ register unsigned char *pb; /* temp pointer into buffer */
+ register CharInfoPtr pci; /* currect char info */
+ register unsigned char *pglyph; /* pointer bits in glyph */
+ int gWidth, gHeight; /* width and height of glyph */
+ register int nbyGlyphWidth; /* bytes per scanline of glyph */
+ int nbyPadGlyph; /* server padded line of glyph */
+
+ XID gcvals[3];
+
+ if (pGC->miTranslate)
+ {
+ x += pDrawable->x;
+ y += pDrawable->y;
+ }
+
+ pfont = pGC->font;
+ width = FONTMAXBOUNDS(pfont,rightSideBearing) -
+ FONTMINBOUNDS(pfont,leftSideBearing);
+ height = FONTMAXBOUNDS(pfont,ascent) +
+ FONTMAXBOUNDS(pfont,descent);
+
+ pPixmap = (*pDrawable->pScreen->CreatePixmap)(pDrawable->pScreen,
+ width, height, 1);
+ if (!pPixmap)
+ return;
+
+ pGCtmp = GetScratchGC(1, pDrawable->pScreen);
+ if (!pGCtmp)
+ {
+ (*pDrawable->pScreen->DestroyPixmap)(pPixmap);
+ return;
+ }
+
+ gcvals[0] = GXcopy;
+ gcvals[1] = 1;
+ gcvals[2] = 0;
+
+ DoChangeGC(pGCtmp, GCFunction|GCForeground|GCBackground, gcvals, 0);
+
+ nbyLine = BitmapBytePad(width);
+ pbits = (unsigned char *)ALLOCATE_LOCAL(height*nbyLine);
+ if (!pbits)
+ {
+ (*pDrawable->pScreen->DestroyPixmap)(pPixmap);
+ FreeScratchGC(pGCtmp);
+ return;
+ }
+ while(nglyph--)
+ {
+ pci = *ppci++;
+ pglyph = FONTGLYPHBITS(pglyphBase, pci);
+ gWidth = GLYPHWIDTHPIXELS(pci);
+ gHeight = GLYPHHEIGHTPIXELS(pci);
+ if (gWidth && gHeight)
+ {
+ nbyGlyphWidth = GLYPHWIDTHBYTESPADDED(pci);
+ nbyPadGlyph = BitmapBytePad(gWidth);
+
+ if (nbyGlyphWidth == nbyPadGlyph
+#if GLYPHPADBYTES != 4
+ && (((int) pglyph) & 3) == 0
+#endif
+ )
+ {
+ pb = pglyph;
+ }
+ else
+ {
+ for (i=0, pb = pbits; i<gHeight; i++, pb = pbits+(i*nbyPadGlyph))
+ for (j = 0; j < nbyGlyphWidth; j++)
+ *pb++ = *pglyph++;
+ pb = pbits;
+ }
+
+ if ((pGCtmp->serialNumber) != (pPixmap->drawable.serialNumber))
+ ValidateGC((DrawablePtr)pPixmap, pGCtmp);
+ (*pGCtmp->ops->PutImage)((DrawablePtr)pPixmap, pGCtmp,
+ pPixmap->drawable.depth,
+ 0, 0, gWidth, gHeight,
+ 0, XYBitmap, (char *)pb);
+
+ if ((pGC->serialNumber) != (pDrawable->serialNumber))
+ ValidateGC(pDrawable, pGC);
+ (*pGC->ops->PushPixels)(pGC, pPixmap, pDrawable,
+ gWidth, gHeight,
+ x + pci->metrics.leftSideBearing,
+ y - pci->metrics.ascent);
+ }
+ x += pci->metrics.characterWidth;
+ }
+ (*pDrawable->pScreen->DestroyPixmap)(pPixmap);
+ DEALLOCATE_LOCAL(pbits);
+ FreeScratchGC(pGCtmp);
+}
+
+
+_X_EXPORT void
+miImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)
+ DrawablePtr pDrawable;
+ GC *pGC;
+ int x, y;
+ unsigned int nglyph;
+ CharInfoPtr *ppci; /* array of character info */
+ pointer pglyphBase; /* start of array of glyphs */
+{
+ ExtentInfoRec info; /* used by QueryGlyphExtents() */
+ XID gcvals[3];
+ int oldAlu, oldFS;
+ unsigned long oldFG;
+ xRectangle backrect;
+
+ QueryGlyphExtents(pGC->font, ppci, (unsigned long)nglyph, &info);
+
+ if (info.overallWidth >= 0)
+ {
+ backrect.x = x;
+ backrect.width = info.overallWidth;
+ }
+ else
+ {
+ backrect.x = x + info.overallWidth;
+ backrect.width = -info.overallWidth;
+ }
+ backrect.y = y - FONTASCENT(pGC->font);
+ backrect.height = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font);
+
+ oldAlu = pGC->alu;
+ oldFG = pGC->fgPixel;
+ oldFS = pGC->fillStyle;
+
+ /* fill in the background */
+ gcvals[0] = GXcopy;
+ gcvals[1] = pGC->bgPixel;
+ gcvals[2] = FillSolid;
+ DoChangeGC(pGC, GCFunction|GCForeground|GCFillStyle, gcvals, 0);
+ ValidateGC(pDrawable, pGC);
+ (*pGC->ops->PolyFillRect)(pDrawable, pGC, 1, &backrect);
+
+ /* put down the glyphs */
+ gcvals[0] = oldFG;
+ DoChangeGC(pGC, GCForeground, gcvals, 0);
+ ValidateGC(pDrawable, pGC);
+ (*pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, nglyph, ppci,
+ pglyphBase);
+
+ /* put all the toys away when done playing */
+ gcvals[0] = oldAlu;
+ gcvals[1] = oldFG;
+ gcvals[2] = oldFS;
+ DoChangeGC(pGC, GCFunction|GCForeground|GCFillStyle, gcvals, 0);
+ ValidateGC(pDrawable, pGC);
+
+}
diff --git a/xserver/mi/miinitext.c b/xserver/mi/miinitext.c
new file mode 100644
index 000000000..8fd8c9ce1
--- /dev/null
+++ b/xserver/mi/miinitext.c
@@ -0,0 +1,798 @@
+/***********************************************************
+
+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
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#ifdef HAVE_DMX_CONFIG_H
+#include <dmx-config.h>
+#endif
+
+#ifdef HAVE_XNEST_CONFIG_H
+#include <xnest-config.h>
+#undef DPMSExtension
+#endif
+
+#ifdef HAVE_KDRIVE_CONFIG_H
+#include <kdrive-config.h>
+/* there must be a better way... */
+#undef XF86MISC
+#undef XFreeXDGA
+#undef XF86DRI
+#undef XF86VIDMODE
+#endif
+
+#ifdef HAVE_XGL_CONFIG_H
+#include <xgl-config.h>
+#undef XF86MISC
+#undef XFreeXDGA
+#undef XF86DRI
+#undef XF86VIDMODE
+#endif
+
+#include "misc.h"
+#include "extension.h"
+#include "micmap.h"
+#include "globals.h"
+
+#if defined(QNX4) /* sleaze for Watcom on QNX4 ... */
+#undef GLXEXT
+#endif
+
+/* Make sure Xprt only announces extensions it supports */
+#ifdef PRINT_ONLY_SERVER
+#undef MITSHM /* this is incompatible to the vector-based Xprint DDX */
+#undef XKB
+#undef PANORAMIX
+#undef RES
+#undef XINPUT
+#undef XV
+#undef SCREENSAVER
+#undef XIDLE
+#undef XRECORD
+#undef XF86VIDMODE
+#undef XF86MISC
+#undef XFreeXDGA
+#undef XF86DRI
+#undef DPMSExtension
+#undef FONTCACHE
+#undef COMPOSITE
+#undef DAMAGE
+#undef XFIXES
+#undef XEVIE
+#else
+#ifndef LOADABLEPRINTDDX
+#undef XPRINT
+#endif /* LOADABLEPRINTDDX */
+#endif /* PRINT_ONLY_SERVER */
+
+
+extern Bool noTestExtensions;
+
+#ifdef BIGREQS
+extern Bool noBigReqExtension;
+#endif
+#ifdef COMPOSITE
+extern Bool noCompositeExtension;
+#endif
+#ifdef DBE
+extern Bool noDbeExtension;
+#endif
+#ifdef DPMSExtension
+extern Bool noDPMSExtension;
+#endif
+#ifdef EVI
+extern Bool noEVIExtension;
+#endif
+#ifdef FONTCACHE
+extern Bool noFontCacheExtension;
+#endif
+#ifdef GLXEXT
+extern Bool noGlxExtension;
+#endif
+#ifdef SCREENSAVER
+extern Bool noScreenSaverExtension;
+#endif
+#ifdef MITSHM
+extern Bool noMITShmExtension;
+#endif
+#ifdef MITMISC
+extern Bool noMITMiscExtension;
+#endif
+#ifdef MULTIBUFFER
+extern Bool noMultibufferExtension;
+#endif
+#ifdef RANDR
+extern Bool noRRExtension;
+#endif
+#ifdef RENDER
+extern Bool noRenderExtension;
+#endif
+#ifdef SHAPE
+extern Bool noShapeExtension;
+#endif
+#ifdef XCSECURITY
+extern Bool noSecurityExtension;
+#endif
+#ifdef XSYNC
+extern Bool noSyncExtension;
+#endif
+#ifdef TOGCUP
+extern Bool noXcupExtension;
+#endif
+#ifdef RES
+extern Bool noResExtension;
+#endif
+#ifdef XAPPGROUP
+extern Bool noXagExtension;
+#endif
+#ifdef XCMISC
+extern Bool noXCMiscExtension;
+#endif
+#ifdef XEVIE
+extern Bool noXevieExtension;
+#endif
+#ifdef XF86BIGFONT
+extern Bool noXFree86BigfontExtension;
+#endif
+#ifdef XFreeXDGA
+extern Bool noXFree86DGAExtension;
+#endif
+#ifdef XF86DRI
+extern Bool noXFree86DRIExtension;
+#endif
+#ifdef XF86MISC
+extern Bool noXFree86MiscExtension;
+#endif
+#ifdef XF86VIDMODE
+extern Bool noXFree86VidModeExtension;
+#endif
+#ifdef XFIXES
+extern Bool noXFixesExtension;
+#endif
+#ifdef XKB
+/* |noXkbExtension| is defined in xc/programs/Xserver/xkb/xkbInit.c */
+extern Bool noXkbExtension;
+#endif
+#ifdef PANORAMIX
+extern Bool noPanoramiXExtension;
+#endif
+#ifdef XINPUT
+extern Bool noXInputExtension;
+#endif
+#ifdef XIDLE
+extern Bool noXIdleExtension;
+#endif
+#ifdef XV
+extern Bool noXvExtension;
+#endif
+
+#ifndef XFree86LOADER
+#define INITARGS void
+typedef void (*InitExtension)(INITARGS);
+#else /* XFree86Loader */
+#include "loaderProcs.h"
+#endif
+
+#ifdef MITSHM
+#define _XSHM_SERVER_
+#include <X11/extensions/shmstr.h>
+#endif
+#ifdef XTEST
+#define _XTEST_SERVER_
+#include <X11/extensions/XTest.h>
+#endif
+#ifdef XKB
+#include <X11/extensions/XKB.h>
+#endif
+#ifdef XPRINT
+#include <X11/extensions/Print.h>
+#endif
+#ifdef XAPPGROUP
+#define _XAG_SERVER_
+#include <X11/extensions/Xagstr.h>
+#endif
+#ifdef XACE
+#include "xace.h"
+#endif
+#ifdef XCSECURITY
+#include "securitysrv.h"
+#include <X11/extensions/securstr.h>
+#endif
+#ifdef PANORAMIX
+#include <X11/extensions/panoramiXproto.h>
+#endif
+#ifdef XF86BIGFONT
+#include <X11/extensions/xf86bigfstr.h>
+#endif
+#ifdef RES
+#include <X11/extensions/XResproto.h>
+#endif
+
+/* FIXME: this whole block of externs should be from the appropriate headers */
+#ifdef EVI
+extern void EVIExtensionInit(INITARGS);
+#endif
+#ifdef MITSHM
+extern void ShmExtensionInit(INITARGS);
+#endif
+#ifdef MULTIBUFFER
+extern void MultibufferExtensionInit(INITARGS);
+#endif
+#ifdef PANORAMIX
+extern void PanoramiXExtensionInit(INITARGS);
+#endif
+#ifdef XINPUT
+extern void XInputExtensionInit(INITARGS);
+#endif
+#ifdef XTEST
+extern void XTestExtensionInit(INITARGS);
+#endif
+#ifdef BIGREQS
+extern void BigReqExtensionInit(INITARGS);
+#endif
+#ifdef MITMISC
+extern void MITMiscExtensionInit(INITARGS);
+#endif
+#ifdef XIDLE
+extern void XIdleExtensionInit(INITARGS);
+#endif
+#ifdef XTRAP
+extern void DEC_XTRAPInit(INITARGS);
+#endif
+#ifdef SCREENSAVER
+extern void ScreenSaverExtensionInit (INITARGS);
+#endif
+#ifdef XV
+extern void XvExtensionInit(INITARGS);
+extern void XvMCExtensionInit(INITARGS);
+#endif
+#ifdef XSYNC
+extern void SyncExtensionInit(INITARGS);
+#endif
+#ifdef XKB
+extern void XkbExtensionInit(INITARGS);
+#endif
+#ifdef XCMISC
+extern void XCMiscExtensionInit(INITARGS);
+#endif
+#ifdef XRECORD
+extern void RecordExtensionInit(INITARGS);
+#endif
+#ifdef DBE
+extern void DbeExtensionInit(INITARGS);
+#endif
+#ifdef XAPPGROUP
+extern void XagExtensionInit(INITARGS);
+#endif
+#ifdef XACE
+extern void XaceExtensionInit(INITARGS);
+#endif
+#ifdef XCSECURITY
+extern void SecurityExtensionSetup(INITARGS);
+extern void SecurityExtensionInit(INITARGS);
+#endif
+#ifdef XPRINT
+extern void XpExtensionInit(INITARGS);
+#endif
+#ifdef XF86BIGFONT
+extern void XFree86BigfontExtensionInit(INITARGS);
+#endif
+#ifdef XF86VIDMODE
+extern void XFree86VidModeExtensionInit(INITARGS);
+#endif
+#ifdef XF86MISC
+extern void XFree86MiscExtensionInit(INITARGS);
+#endif
+#ifdef XFreeXDGA
+extern void XFree86DGAExtensionInit(INITARGS);
+#endif
+#ifdef GLXEXT
+typedef struct __GLXprovider __GLXprovider;
+extern __GLXprovider __glXMesaProvider;
+extern void GlxPushProvider(__GLXprovider *impl);
+#ifndef __DARWIN__
+extern void GlxExtensionInit(INITARGS);
+extern void GlxWrapInitVisuals(miInitVisualsProcPtr *);
+#else
+extern void DarwinGlxExtensionInit(INITARGS);
+extern void DarwinGlxWrapInitVisuals(miInitVisualsProcPtr *);
+#endif
+#endif
+#ifdef XF86DRI
+extern void XFree86DRIExtensionInit(INITARGS);
+#endif
+#ifdef TOGCUP
+extern void XcupExtensionInit(INITARGS);
+#endif
+#ifdef DPMSExtension
+extern void DPMSExtensionInit(INITARGS);
+#endif
+#ifdef FONTCACHE
+extern void FontCacheExtensionInit(INITARGS);
+#endif
+#ifdef RENDER
+extern void RenderExtensionInit(INITARGS);
+#endif
+#ifdef RANDR
+extern void RRExtensionInit(INITARGS);
+#endif
+#ifdef RES
+extern void ResExtensionInit(INITARGS);
+#endif
+#ifdef DMXEXT
+extern void DMXExtensionInit(INITARGS);
+#endif
+#ifdef XEVIE
+extern void XevieExtensionInit(INITARGS);
+#endif
+#ifdef XFIXES
+extern void XFixesExtensionInit(INITARGS);
+#endif
+#ifdef DAMAGE
+extern void DamageExtensionInit(INITARGS);
+#endif
+#ifdef COMPOSITE
+extern void CompositeExtensionInit(INITARGS);
+#endif
+
+/* The following is only a small first step towards run-time
+ * configurable extensions.
+ */
+typedef struct {
+ char *name;
+ Bool *disablePtr;
+} ExtensionToggle;
+
+static ExtensionToggle ExtensionToggleList[] =
+{
+ /* sort order is extension name string as shown in xdpyinfo */
+#ifdef BIGREQS
+ { "BIG-REQUESTS", &noBigReqExtension },
+#endif
+#ifdef COMPOSITE
+ { "Composite", &noCompositeExtension },
+#endif
+#ifdef DAMAGE
+ { "DAMAGE", &noDamageExtension },
+#endif
+#ifdef DBE
+ { "DOUBLE-BUFFER", &noDbeExtension },
+#endif
+#ifdef DPMSExtension
+ { "DPMS", &noDPMSExtension },
+#endif
+#ifdef EVI
+ { "Extended-Visual-Information", &noEVIExtension },
+#endif
+#ifdef FONTCACHE
+ { "FontCache", &noFontCacheExtension },
+#endif
+#ifdef GLXEXT
+ { "GLX", &noGlxExtension },
+#endif
+#ifdef SCREENSAVER
+ { "MIT-SCREEN-SAVER", &noScreenSaverExtension },
+#endif
+#ifdef MITSHM
+ { SHMNAME, &noMITShmExtension },
+#endif
+#ifdef MITMISC
+ { "MIT-SUNDRY-NONSTANDARD", &noMITMiscExtension },
+#endif
+#ifdef MULTIBUFFER
+ { "Multi-Buffering", &noMultibufferExtension },
+#endif
+#ifdef RANDR
+ { "RANDR", &noRRExtension },
+#endif
+#ifdef RENDER
+ { "RENDER", &noRenderExtension },
+#endif
+#ifdef SHAPE
+ { "SHAPE", &noShapeExtension },
+#endif
+#ifdef XCSECURITY
+ { "SECURITY", &noSecurityExtension },
+#endif
+#ifdef XSYNC
+ { "SYNC", &noSyncExtension },
+#endif
+#ifdef TOGCUP
+ { "TOG-CUP", &noXcupExtension },
+#endif
+#ifdef RES
+ { "X-Resource", &noResExtension },
+#endif
+#ifdef XAPPGROUP
+ { "XC-APPGROUP", &noXagExtension },
+#endif
+#ifdef XCMISC
+ { "XC-MISC", &noXCMiscExtension },
+#endif
+#ifdef XEVIE
+ { "XEVIE", &noXevieExtension },
+#endif
+#ifdef XF86BIGFONT
+ { "XFree86-Bigfont", &noXFree86BigfontExtension },
+#endif
+#ifdef XFreeXDGA
+ { "XFree86-DGA", &noXFree86DGAExtension },
+#endif
+#ifdef XF86DRI
+ { "XFree86-DRI", &noXFree86DRIExtension },
+#endif
+#ifdef XF86MISC
+ { "XFree86-Misc", &noXFree86MiscExtension },
+#endif
+#ifdef XF86VIDMODE
+ { "XFree86-VidModeExtension", &noXFree86VidModeExtension },
+#endif
+#ifdef XFIXES
+ { "XFIXES", &noXFixesExtension },
+#endif
+#ifdef PANORAMIX
+ { "XINERAMA", &noPanoramiXExtension },
+#endif
+#ifdef XINPUT
+ { "XInputExtension", &noXInputExtension },
+#endif
+#ifdef XKB
+ { "XKEYBOARD", &noXkbExtension },
+#endif
+ { "XTEST", &noTestExtensions },
+#ifdef XV
+ { "XVideo", &noXvExtension },
+#endif
+ { NULL, NULL }
+};
+
+Bool EnableDisableExtension(char *name, Bool enable)
+{
+ ExtensionToggle *ext = &ExtensionToggleList[0];
+
+ for (ext = &ExtensionToggleList[0]; ext->name != NULL; ext++) {
+ if (strcmp(name, ext->name) == 0) {
+ *ext->disablePtr = !enable;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+void EnableDisableExtensionError(char *name, Bool enable)
+{
+ ExtensionToggle *ext = &ExtensionToggleList[0];
+
+ ErrorF("Extension \"%s\" is not recognized\n", name);
+ ErrorF("Only the following extensions can be run-time %s:\n",
+ enable ? "enabled" : "disabled");
+ for (ext = &ExtensionToggleList[0]; ext->name != NULL; ext++)
+ ErrorF(" %s\n", ext->name);
+}
+
+#ifndef XFree86LOADER
+
+/*ARGSUSED*/
+void
+InitExtensions(argc, argv)
+ int argc;
+ char *argv[];
+{
+#ifdef XCSECURITY
+ SecurityExtensionSetup();
+#endif
+#ifdef PANORAMIX
+# if !defined(PRINT_ONLY_SERVER) && !defined(NO_PANORAMIX)
+ if (!noPanoramiXExtension) PanoramiXExtensionInit();
+# endif
+#endif
+#ifdef SHAPE
+ if (!noShapeExtension) ShapeExtensionInit();
+#endif
+#ifdef MITSHM
+ if (!noMITShmExtension) ShmExtensionInit();
+#endif
+#ifdef EVI
+ if (!noEVIExtension) EVIExtensionInit();
+#endif
+#ifdef MULTIBUFFER
+ if (!noMultibufferExtension) MultibufferExtensionInit();
+#endif
+#if defined(XINPUT) && !defined(NO_HW_ONLY_EXTS)
+ if (!noXInputExtension) XInputExtensionInit();
+#endif
+#ifdef XTEST
+ if (!noTestExtensions) XTestExtensionInit();
+#endif
+#ifdef BIGREQS
+ if (!noBigReqExtension) BigReqExtensionInit();
+#endif
+#ifdef MITMISC
+ if (!noMITMiscExtension) MITMiscExtensionInit();
+#endif
+#ifdef XIDLE
+ if (!noXIdleExtension) XIdleExtensionInit();
+#endif
+#ifdef XTRAP
+ if (!noTestExtensions) DEC_XTRAPInit();
+#endif
+#if defined(SCREENSAVER) && !defined(PRINT_ONLY_SERVER)
+ if (!noScreenSaverExtension) ScreenSaverExtensionInit ();
+#endif
+#ifdef XV
+ if (!noXvExtension) {
+ XvExtensionInit();
+ XvMCExtensionInit();
+ }
+#endif
+#ifdef XSYNC
+ if (!noSyncExtension) SyncExtensionInit();
+#endif
+#if defined(XKB) && !defined(PRINT_ONLY_SERVER) && !defined(NO_HW_ONLY_EXTS)
+ if (!noXkbExtension) XkbExtensionInit();
+#endif
+#ifdef XCMISC
+ if (!noXCMiscExtension) XCMiscExtensionInit();
+#endif
+#ifdef XRECORD
+ if (!noTestExtensions) RecordExtensionInit();
+#endif
+#ifdef DBE
+ if (!noDbeExtension) DbeExtensionInit();
+#endif
+#ifdef XAPPGROUP
+ if (!noXagExtension) XagExtensionInit();
+#endif
+#ifdef XACE
+ XaceExtensionInit();
+#endif
+#ifdef XCSECURITY
+ if (!noSecurityExtension) SecurityExtensionInit();
+#endif
+#ifdef XPRINT
+ XpExtensionInit(); /* server-specific extension, cannot be disabled */
+#endif
+#ifdef TOGCUP
+ if (!noXcupExtension) XcupExtensionInit();
+#endif
+#if defined(DPMSExtension) && !defined(NO_HW_ONLY_EXTS)
+ if (!noDPMSExtension) DPMSExtensionInit();
+#endif
+#ifdef FONTCACHE
+ if (!noFontCacheExtension) FontCacheExtensionInit();
+#endif
+#ifdef XF86BIGFONT
+ if (!noXFree86BigfontExtension) XFree86BigfontExtensionInit();
+#endif
+#if !defined(PRINT_ONLY_SERVER) && !defined(NO_HW_ONLY_EXTS)
+#if defined(XF86VIDMODE)
+ if (!noXFree86VidModeExtension) XFree86VidModeExtensionInit();
+#endif
+#if defined(XF86MISC)
+ if (!noXFree86MiscExtension) XFree86MiscExtensionInit();
+#endif
+#if defined(XFreeXDGA)
+ if (!noXFree86DGAExtension) XFree86DGAExtensionInit();
+#endif
+#ifdef XF86DRI
+ if (!noXFree86DRIExtension) XFree86DRIExtensionInit();
+#endif
+#endif
+#ifdef GLXEXT
+
+ GlxPushProvider(&__glXMesaProvider);
+#ifndef __DARWIN__
+ if (!noGlxExtension) GlxExtensionInit();
+#else
+ if (!noGlxExtension) DarwinGlxExtensionInit();
+#endif
+#endif
+#ifdef XFIXES
+ /* must be before Render to layer DisplayCursor correctly */
+ if (!noXFixesExtension) XFixesExtensionInit();
+#endif
+#ifdef RENDER
+ if (!noRenderExtension) RenderExtensionInit();
+#endif
+#ifdef RANDR
+ if (!noRRExtension) RRExtensionInit();
+#endif
+#ifdef RES
+ if (!noResExtension) ResExtensionInit();
+#endif
+#ifdef DMXEXT
+ DMXExtensionInit(); /* server-specific extension, cannot be disabled */
+#endif
+#ifdef XEVIE
+ if (!noXevieExtension) XevieExtensionInit();
+#endif
+#ifdef COMPOSITE
+ if (!noCompositeExtension) CompositeExtensionInit();
+#endif
+#ifdef DAMAGE
+ if (!noDamageExtension) DamageExtensionInit();
+#endif
+}
+
+void
+InitVisualWrap()
+{
+ miResetInitVisuals();
+#ifdef GLXEXT
+#ifndef __DARWIN__
+ GlxWrapInitVisuals(&miInitVisualsProc);
+#else
+ DarwinGlxWrapInitVisuals(&miInitVisualsProc);
+#endif
+#endif
+}
+
+#else /* XFree86LOADER */
+/* List of built-in (statically linked) extensions */
+static ExtensionModule staticExtensions[] = {
+#ifdef MITSHM
+ { ShmExtensionInit, SHMNAME, &noMITShmExtension, NULL, NULL },
+#endif
+#ifdef XINPUT
+ { XInputExtensionInit, "XInputExtension", &noXInputExtension, NULL, NULL },
+#endif
+#ifdef XTEST
+ { XTestExtensionInit, XTestExtensionName, &noTestExtensions, NULL, NULL },
+#endif
+#ifdef XIDLE
+ { XIdleExtensionInit, "XIDLE", &noXIdleExtension, NULL, NULL },
+#endif
+#ifdef XKB
+ { XkbExtensionInit, XkbName, &noXkbExtension, NULL, NULL },
+#endif
+#ifdef XAPPGROUP
+ { XagExtensionInit, XAGNAME, &noXagExtension, NULL, NULL },
+#endif
+#ifdef XACE
+ { XaceExtensionInit, XACE_EXTENSION_NAME, NULL, NULL, NULL },
+#endif
+#ifdef XCSECURITY
+ { SecurityExtensionInit, SECURITY_EXTENSION_NAME, &noSecurityExtension, SecurityExtensionSetup, NULL },
+#endif
+#ifdef XPRINT
+ { XpExtensionInit, XP_PRINTNAME, NULL, NULL, NULL },
+#endif
+#ifdef PANORAMIX
+ { PanoramiXExtensionInit, PANORAMIX_PROTOCOL_NAME, &noPanoramiXExtension, NULL, NULL },
+#endif
+#ifdef XFIXES
+ /* must be before Render to layer DisplayCursor correctly */
+ { XFixesExtensionInit, "XFIXES", &noXFixesExtension, NULL, NULL },
+#endif
+#ifdef XF86BIGFONT
+ { XFree86BigfontExtensionInit, XF86BIGFONTNAME, &noXFree86BigfontExtension, NULL, NULL },
+#endif
+#ifdef RENDER
+ { RenderExtensionInit, "RENDER", &noRenderExtension, NULL, NULL },
+#endif
+#ifdef RANDR
+ { RRExtensionInit, "RANDR", &noRRExtension, NULL, NULL },
+#endif
+#ifdef COMPOSITE
+ { CompositeExtensionInit, "COMPOSITE", &noCompositeExtension, NULL },
+#endif
+#ifdef DAMAGE
+ { DamageExtensionInit, "DAMAGE", &noDamageExtension, NULL },
+#endif
+#ifdef XEVIE
+ { XevieExtensionInit, "XEVIE", &noXevieExtension, NULL },
+#endif
+ { NULL, NULL, NULL, NULL, NULL }
+};
+
+/*ARGSUSED*/
+void
+InitExtensions(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int i;
+ ExtensionModule *ext;
+ static Bool listInitialised = FALSE;
+
+ if (!listInitialised) {
+ /* Add built-in extensions to the list. */
+ for (i = 0; staticExtensions[i].name; i++)
+ LoadExtension(&staticExtensions[i], TRUE);
+
+ /* Sort the extensions according the init dependencies. */
+ LoaderSortExtensions();
+ listInitialised = TRUE;
+ } else {
+ /* Call the setup functions on subsequent server resets as well */
+ for (i = 0; ExtensionModuleList[i].name != NULL; i++) {
+ ext = &ExtensionModuleList[i];
+ if (ext->setupFunc != NULL &&
+ (ext->disablePtr == NULL ||
+ (ext->disablePtr != NULL && !*ext->disablePtr))) {
+ (ext->setupFunc)();
+ }
+ }
+ }
+
+ for (i = 0; ExtensionModuleList[i].name != NULL; i++) {
+ ext = &ExtensionModuleList[i];
+ if (ext->initFunc != NULL &&
+ (ext->disablePtr == NULL ||
+ (ext->disablePtr != NULL && !*ext->disablePtr))) {
+ (ext->initFunc)();
+ }
+ }
+}
+
+static void (*__miHookInitVisualsFunction)(miInitVisualsProcPtr *);
+
+void
+InitVisualWrap()
+{
+ miResetInitVisuals();
+ if (__miHookInitVisualsFunction)
+ (*__miHookInitVisualsFunction)(&miInitVisualsProc);
+}
+
+_X_EXPORT void
+miHookInitVisuals(void (**old)(miInitVisualsProcPtr *),
+ void (*new)(miInitVisualsProcPtr *))
+{
+ if (old)
+ *old = __miHookInitVisualsFunction;
+ __miHookInitVisualsFunction = new;
+}
+
+#endif /* XFree86LOADER */
diff --git a/xserver/mi/miline.h b/xserver/mi/miline.h
new file mode 100644
index 000000000..7028485f0
--- /dev/null
+++ b/xserver/mi/miline.h
@@ -0,0 +1,172 @@
+
+/*
+
+Copyright 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.
+
+*/
+
+#ifndef MILINE_H
+
+#include "screenint.h"
+
+/*
+ * Public definitions used for configuring basic pixelization aspects
+ * of the sample implementation line-drawing routines provided in
+ * {mfb,mi,cfb*} at run-time.
+ */
+
+#define XDECREASING 4
+#define YDECREASING 2
+#define YMAJOR 1
+
+#define OCTANT1 (1 << (YDECREASING))
+#define OCTANT2 (1 << (YDECREASING|YMAJOR))
+#define OCTANT3 (1 << (XDECREASING|YDECREASING|YMAJOR))
+#define OCTANT4 (1 << (XDECREASING|YDECREASING))
+#define OCTANT5 (1 << (XDECREASING))
+#define OCTANT6 (1 << (XDECREASING|YMAJOR))
+#define OCTANT7 (1 << (YMAJOR))
+#define OCTANT8 (1 << (0))
+
+#define XMAJOROCTANTS (OCTANT1 | OCTANT4 | OCTANT5 | OCTANT8)
+
+#define DEFAULTZEROLINEBIAS (OCTANT2 | OCTANT3 | OCTANT4 | OCTANT5)
+
+/*
+ * Devices can configure the rendering of routines in mi, mfb, and cfb*
+ * by specifying a thin line bias to be applied to a particular screen
+ * using the following function. The bias parameter is an OR'ing of
+ * the appropriate OCTANT constants defined above to indicate which
+ * octants to bias a line to prefer an axial step when the Bresenham
+ * error term is exactly zero. The octants are mapped as follows:
+ *
+ * \ | /
+ * \ 3 | 2 /
+ * \ | /
+ * 4 \ | / 1
+ * \|/
+ * -----------
+ * /|\
+ * 5 / | \ 8
+ * / | \
+ * / 6 | 7 \
+ * / | \
+ *
+ * For more information, see "Ambiguities in Incremental Line Rastering,"
+ * Jack E. Bresenham, IEEE CG&A, May 1987.
+ */
+
+extern void miSetZeroLineBias(
+ ScreenPtr /* pScreen */,
+ unsigned int /* bias */
+);
+
+/*
+ * Private definitions needed for drawing thin (zero width) lines
+ * Used by the mi, mfb, and all cfb* components.
+ */
+
+#define X_AXIS 0
+#define Y_AXIS 1
+
+#define OUT_LEFT 0x08
+#define OUT_RIGHT 0x04
+#define OUT_ABOVE 0x02
+#define OUT_BELOW 0x01
+
+#define OUTCODES(_result, _x, _y, _pbox) \
+ if ( (_x) < (_pbox)->x1) (_result) |= OUT_LEFT; \
+ else if ( (_x) >= (_pbox)->x2) (_result) |= OUT_RIGHT; \
+ if ( (_y) < (_pbox)->y1) (_result) |= OUT_ABOVE; \
+ else if ( (_y) >= (_pbox)->y2) (_result) |= OUT_BELOW;
+
+#define MIOUTCODES(outcode, x, y, xmin, ymin, xmax, ymax) \
+{\
+ if (x < xmin) outcode |= OUT_LEFT;\
+ if (x > xmax) outcode |= OUT_RIGHT;\
+ if (y < ymin) outcode |= OUT_ABOVE;\
+ if (y > ymax) outcode |= OUT_BELOW;\
+}
+
+#define SWAPINT(i, j) \
+{ register int _t = i; i = j; j = _t; }
+
+#define SWAPPT(i, j) \
+{ DDXPointRec _t; _t = i; i = j; j = _t; }
+
+#define SWAPINT_PAIR(x1, y1, x2, y2)\
+{ int t = x1; x1 = x2; x2 = t;\
+ t = y1; y1 = y2; y2 = t;\
+}
+
+#define miGetZeroLineBias(_pScreen) \
+ ((miZeroLineScreenIndex < 0) ? \
+ 0 : ((_pScreen)->devPrivates[miZeroLineScreenIndex].uval))
+
+#define CalcLineDeltas(_x1,_y1,_x2,_y2,_adx,_ady,_sx,_sy,_SX,_SY,_octant) \
+ (_octant) = 0; \
+ (_sx) = (_SX); \
+ if (((_adx) = (_x2) - (_x1)) < 0) { \
+ (_adx) = -(_adx); \
+ (_sx = -(_sx)); \
+ (_octant) |= XDECREASING; \
+ } \
+ (_sy) = (_SY); \
+ if (((_ady) = (_y2) - (_y1)) < 0) { \
+ (_ady) = -(_ady); \
+ (_sy = -(_sy)); \
+ (_octant) |= YDECREASING; \
+ }
+
+#define SetYMajorOctant(_octant) ((_octant) |= YMAJOR)
+
+#define FIXUP_ERROR(_e, _octant, _bias) \
+ (_e) -= (((_bias) >> (_octant)) & 1)
+
+#define IsXMajorOctant(_octant) (!((_octant) & YMAJOR))
+#define IsYMajorOctant(_octant) ((_octant) & YMAJOR)
+#define IsXDecreasingOctant(_octant) ((_octant) & XDECREASING)
+#define IsYDecreasingOctant(_octant) ((_octant) & YDECREASING)
+
+extern int miZeroLineScreenIndex;
+
+extern int miZeroClipLine(
+ int /*xmin*/,
+ int /*ymin*/,
+ int /*xmax*/,
+ int /*ymax*/,
+ int * /*new_x1*/,
+ int * /*new_y1*/,
+ int * /*new_x2*/,
+ int * /*new_y2*/,
+ unsigned int /*adx*/,
+ unsigned int /*ady*/,
+ int * /*pt1_clipped*/,
+ int * /*pt2_clipped*/,
+ int /*octant*/,
+ unsigned int /*bias*/,
+ int /*oc1*/,
+ int /*oc2*/
+);
+
+#endif /* MILINE_H */
diff --git a/xserver/mi/mioverlay.c b/xserver/mi/mioverlay.c
new file mode 100644
index 000000000..c02ea2dc5
--- /dev/null
+++ b/xserver/mi/mioverlay.c
@@ -0,0 +1,2077 @@
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include "scrnintstr.h"
+#include "validate.h"
+#include "windowstr.h"
+#include "mi.h"
+#include "gcstruct.h"
+#include "regionstr.h"
+#include "mivalidate.h"
+#include "mioverlay.h"
+#include "migc.h"
+
+#include "globals.h"
+
+
+typedef struct {
+ RegionRec exposed;
+ RegionRec borderExposed;
+ RegionPtr borderVisible;
+ DDXPointRec oldAbsCorner;
+} miOverlayValDataRec, *miOverlayValDataPtr;
+
+typedef struct _TreeRec {
+ WindowPtr pWin;
+ struct _TreeRec *parent;
+ struct _TreeRec *firstChild;
+ struct _TreeRec *lastChild;
+ struct _TreeRec *prevSib;
+ struct _TreeRec *nextSib;
+ RegionRec borderClip;
+ RegionRec clipList;
+ unsigned visibility;
+ miOverlayValDataPtr valdata;
+} miOverlayTreeRec, *miOverlayTreePtr;
+
+typedef struct {
+ miOverlayTreePtr tree;
+} miOverlayWindowRec, *miOverlayWindowPtr;
+
+typedef struct {
+ CloseScreenProcPtr CloseScreen;
+ CreateWindowProcPtr CreateWindow;
+ DestroyWindowProcPtr DestroyWindow;
+ UnrealizeWindowProcPtr UnrealizeWindow;
+ RealizeWindowProcPtr RealizeWindow;
+ miOverlayTransFunc MakeTransparent;
+ miOverlayInOverlayFunc InOverlay;
+ Bool underlayMarked;
+ Bool copyUnderlay;
+} miOverlayScreenRec, *miOverlayScreenPtr;
+
+static unsigned long miOverlayGeneration = 0;
+int miOverlayWindowIndex = -1;
+int miOverlayScreenIndex = -1;
+
+static void RebuildTree(WindowPtr);
+static Bool HasUnderlayChildren(WindowPtr);
+static void MarkUnderlayWindow(WindowPtr);
+static Bool CollectUnderlayChildrenRegions(WindowPtr, RegionPtr);
+
+static Bool miOverlayCloseScreen(int, ScreenPtr);
+static Bool miOverlayCreateWindow(WindowPtr);
+static Bool miOverlayDestroyWindow(WindowPtr);
+static Bool miOverlayUnrealizeWindow(WindowPtr);
+static Bool miOverlayRealizeWindow(WindowPtr);
+static void miOverlayMarkWindow(WindowPtr);
+static void miOverlayReparentWindow(WindowPtr, WindowPtr);
+static void miOverlayRestackWindow(WindowPtr, WindowPtr);
+static Bool miOverlayMarkOverlappedWindows(WindowPtr, WindowPtr, WindowPtr*);
+static void miOverlayMarkUnrealizedWindow(WindowPtr, WindowPtr, Bool);
+static int miOverlayValidateTree(WindowPtr, WindowPtr, VTKind);
+static void miOverlayHandleExposures(WindowPtr);
+static void miOverlayMoveWindow(WindowPtr, int, int, WindowPtr, VTKind);
+static void miOverlayWindowExposures(WindowPtr, RegionPtr, RegionPtr);
+static void miOverlayResizeWindow(WindowPtr, int, int, unsigned int,
+ unsigned int, WindowPtr);
+static void miOverlayClearToBackground(WindowPtr, int, int, int, int, Bool);
+
+#ifdef SHAPE
+static void miOverlaySetShape(WindowPtr);
+#endif
+static void miOverlayChangeBorderWidth(WindowPtr, unsigned int);
+
+#define MIOVERLAY_GET_SCREEN_PRIVATE(pScreen) \
+ ((miOverlayScreenPtr)((pScreen)->devPrivates[miOverlayScreenIndex].ptr))
+#define MIOVERLAY_GET_WINDOW_PRIVATE(pWin) \
+ ((miOverlayWindowPtr)((pWin)->devPrivates[miOverlayWindowIndex].ptr))
+#define MIOVERLAY_GET_WINDOW_TREE(pWin) \
+ (MIOVERLAY_GET_WINDOW_PRIVATE(pWin)->tree)
+
+#define IN_UNDERLAY(w) MIOVERLAY_GET_WINDOW_TREE(w)
+#define IN_OVERLAY(w) !MIOVERLAY_GET_WINDOW_TREE(w)
+
+#define MARK_OVERLAY(w) miMarkWindow(w)
+#define MARK_UNDERLAY(w) MarkUnderlayWindow(w)
+
+#define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \
+ HasBorder(w) && \
+ (w)->backgroundState == ParentRelative)
+
+_X_EXPORT Bool
+miInitOverlay(
+ ScreenPtr pScreen,
+ miOverlayInOverlayFunc inOverlayFunc,
+ miOverlayTransFunc transFunc
+){
+ miOverlayScreenPtr pScreenPriv;
+
+ if(!inOverlayFunc || !transFunc) return FALSE;
+
+ if(miOverlayGeneration != serverGeneration) {
+ if(((miOverlayScreenIndex = AllocateScreenPrivateIndex()) < 0) ||
+ ((miOverlayWindowIndex = AllocateWindowPrivateIndex()) < 0))
+ return FALSE;
+
+ miOverlayGeneration = serverGeneration;
+ }
+
+ if(!AllocateWindowPrivate(pScreen, miOverlayWindowIndex,
+ sizeof(miOverlayWindowRec)))
+ return FALSE;
+
+ if(!(pScreenPriv = xalloc(sizeof(miOverlayScreenRec))))
+ return FALSE;
+
+ pScreen->devPrivates[miOverlayScreenIndex].ptr = (pointer)pScreenPriv;
+
+ pScreenPriv->InOverlay = inOverlayFunc;
+ pScreenPriv->MakeTransparent = transFunc;
+ pScreenPriv->underlayMarked = FALSE;
+
+
+ pScreenPriv->CloseScreen = pScreen->CloseScreen;
+ pScreenPriv->CreateWindow = pScreen->CreateWindow;
+ pScreenPriv->DestroyWindow = pScreen->DestroyWindow;
+ pScreenPriv->UnrealizeWindow = pScreen->UnrealizeWindow;
+ pScreenPriv->RealizeWindow = pScreen->RealizeWindow;
+
+ pScreen->CloseScreen = miOverlayCloseScreen;
+ pScreen->CreateWindow = miOverlayCreateWindow;
+ pScreen->DestroyWindow = miOverlayDestroyWindow;
+ pScreen->UnrealizeWindow = miOverlayUnrealizeWindow;
+ pScreen->RealizeWindow = miOverlayRealizeWindow;
+
+ pScreen->ReparentWindow = miOverlayReparentWindow;
+ pScreen->RestackWindow = miOverlayRestackWindow;
+ pScreen->MarkOverlappedWindows = miOverlayMarkOverlappedWindows;
+ pScreen->MarkUnrealizedWindow = miOverlayMarkUnrealizedWindow;
+ pScreen->ValidateTree = miOverlayValidateTree;
+ pScreen->HandleExposures = miOverlayHandleExposures;
+ pScreen->MoveWindow = miOverlayMoveWindow;
+ pScreen->WindowExposures = miOverlayWindowExposures;
+ pScreen->ResizeWindow = miOverlayResizeWindow;
+ pScreen->MarkWindow = miOverlayMarkWindow;
+ pScreen->ClearToBackground = miOverlayClearToBackground;
+#ifdef SHAPE
+ pScreen->SetShape = miOverlaySetShape;
+#endif
+ pScreen->ChangeBorderWidth = miOverlayChangeBorderWidth;
+
+ return TRUE;
+}
+
+
+static Bool
+miOverlayCloseScreen(int i, ScreenPtr pScreen)
+{
+ miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+
+ pScreen->CloseScreen = pScreenPriv->CloseScreen;
+ pScreen->CreateWindow = pScreenPriv->CreateWindow;
+ pScreen->DestroyWindow = pScreenPriv->DestroyWindow;
+ pScreen->UnrealizeWindow = pScreenPriv->UnrealizeWindow;
+ pScreen->RealizeWindow = pScreenPriv->RealizeWindow;
+
+ xfree(pScreenPriv);
+
+ return (*pScreen->CloseScreen)(i, pScreen);
+}
+
+
+static Bool
+miOverlayCreateWindow(WindowPtr pWin)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+ miOverlayWindowPtr pWinPriv = MIOVERLAY_GET_WINDOW_PRIVATE(pWin);
+ miOverlayTreePtr pTree = NULL;
+ Bool result = TRUE;
+
+ pWinPriv->tree = NULL;
+
+ if(!pWin->parent || !((*pScreenPriv->InOverlay)(pWin))) {
+ if(!(pTree = (miOverlayTreePtr)xcalloc(1, sizeof(miOverlayTreeRec))))
+ return FALSE;
+ }
+
+ if(pScreenPriv->CreateWindow) {
+ pScreen->CreateWindow = pScreenPriv->CreateWindow;
+ result = (*pScreen->CreateWindow)(pWin);
+ pScreen->CreateWindow = miOverlayCreateWindow;
+ }
+
+ if (pTree) {
+ if(result) {
+ pTree->pWin = pWin;
+ pTree->visibility = VisibilityNotViewable;
+ pWinPriv->tree = pTree;
+ if(pWin->parent) {
+ REGION_NULL(pScreen, &(pTree->borderClip));
+ REGION_NULL(pScreen, &(pTree->clipList));
+ RebuildTree(pWin);
+ } else {
+ BoxRec fullBox;
+ fullBox.x1 = 0;
+ fullBox.y1 = 0;
+ fullBox.x2 = pScreen->width;
+ fullBox.y2 = pScreen->height;
+ REGION_INIT(pScreen, &(pTree->borderClip), &fullBox, 1);
+ REGION_INIT(pScreen, &(pTree->clipList), &fullBox, 1);
+ }
+ } else xfree(pTree);
+ }
+
+ return TRUE;
+}
+
+
+static Bool
+miOverlayDestroyWindow(WindowPtr pWin)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+ Bool result = TRUE;
+
+ if (pTree) {
+ if(pTree->prevSib)
+ pTree->prevSib->nextSib = pTree->nextSib;
+ else if(pTree->parent)
+ pTree->parent->firstChild = pTree->nextSib;
+
+ if(pTree->nextSib)
+ pTree->nextSib->prevSib = pTree->prevSib;
+ else if(pTree->parent)
+ pTree->parent->lastChild = pTree->prevSib;
+
+ REGION_UNINIT(pScreen, &(pTree->borderClip));
+ REGION_UNINIT(pScreen, &(pTree->clipList));
+ xfree(pTree);
+ }
+
+ if(pScreenPriv->DestroyWindow) {
+ pScreen->DestroyWindow = pScreenPriv->DestroyWindow;
+ result = (*pScreen->DestroyWindow)(pWin);
+ pScreen->DestroyWindow = miOverlayDestroyWindow;
+ }
+
+ return result;
+}
+
+static Bool
+miOverlayUnrealizeWindow(WindowPtr pWin)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+ Bool result = TRUE;
+
+ if(pTree) pTree->visibility = VisibilityNotViewable;
+
+ if(pScreenPriv->UnrealizeWindow) {
+ pScreen->UnrealizeWindow = pScreenPriv->UnrealizeWindow;
+ result = (*pScreen->UnrealizeWindow)(pWin);
+ pScreen->UnrealizeWindow = miOverlayUnrealizeWindow;
+ }
+
+ return result;
+}
+
+
+static Bool
+miOverlayRealizeWindow(WindowPtr pWin)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+ Bool result = TRUE;
+
+ if(pScreenPriv->RealizeWindow) {
+ pScreen->RealizeWindow = pScreenPriv->RealizeWindow;
+ result = (*pScreen->RealizeWindow)(pWin);
+ pScreen->RealizeWindow = miOverlayRealizeWindow;
+ }
+
+ /* we only need to catch the root window realization */
+
+ if(result && !pWin->parent && !((*pScreenPriv->InOverlay)(pWin)))
+ {
+ BoxRec box;
+ box.x1 = box.y1 = 0;
+ box.x2 = pWin->drawable.width;
+ box.y2 = pWin->drawable.height;
+ (*pScreenPriv->MakeTransparent)(pScreen, 1, &box);
+ }
+
+ return result;
+}
+
+
+static void
+miOverlayReparentWindow(WindowPtr pWin, WindowPtr pPriorParent)
+{
+ if(IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin)) {
+ /* This could probably be more optimal */
+ RebuildTree(WindowTable[pWin->drawable.pScreen->myNum]->firstChild);
+ }
+}
+
+static void
+miOverlayRestackWindow(WindowPtr pWin, WindowPtr oldNextSib)
+{
+ if(IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin)) {
+ /* This could probably be more optimal */
+ RebuildTree(pWin);
+ }
+}
+
+
+static Bool
+miOverlayMarkOverlappedWindows(
+ WindowPtr pWin,
+ WindowPtr pFirst,
+ WindowPtr *pLayerWin
+){
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ WindowPtr pChild, pLast;
+ Bool overMarked, underMarked, doUnderlay, markAll;
+ miOverlayTreePtr pTree = NULL, tLast, tChild;
+ BoxPtr box;
+
+ overMarked = underMarked = markAll = FALSE;
+
+ if(pLayerWin) *pLayerWin = pWin; /* hah! */
+
+ doUnderlay = (IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin));
+
+ box = REGION_EXTENTS(pScreen, &pWin->borderSize);
+
+ if((pChild = pFirst)) {
+ pLast = pChild->parent->lastChild;
+ while (1) {
+ if (pChild == pWin) markAll = TRUE;
+
+ if(doUnderlay && IN_UNDERLAY(pChild))
+ pTree = MIOVERLAY_GET_WINDOW_TREE(pChild);
+
+ if(pChild->viewable) {
+ if (REGION_BROKEN (pScreen, &pChild->winSize))
+ SetWinSize (pChild);
+ if (REGION_BROKEN (pScreen, &pChild->borderSize))
+ SetBorderSize (pChild);
+
+ if (markAll ||
+ RECT_IN_REGION(pScreen, &pChild->borderSize, box))
+ {
+ MARK_OVERLAY(pChild);
+ overMarked = TRUE;
+ if(doUnderlay && IN_UNDERLAY(pChild)) {
+ MARK_UNDERLAY(pChild);
+ underMarked = TRUE;
+ }
+ if (pChild->firstChild) {
+ pChild = pChild->firstChild;
+ continue;
+ }
+ }
+ }
+ while (!pChild->nextSib && (pChild != pLast)) {
+ pChild = pChild->parent;
+ if(doUnderlay && IN_UNDERLAY(pChild))
+ pTree = MIOVERLAY_GET_WINDOW_TREE(pChild);
+ }
+
+ if(pChild == pWin) markAll = FALSE;
+
+ if (pChild == pLast) break;
+
+ pChild = pChild->nextSib;
+ }
+ if(overMarked)
+ MARK_OVERLAY(pWin->parent);
+ }
+
+ if(doUnderlay && !pTree) {
+ if(!(pTree = MIOVERLAY_GET_WINDOW_TREE(pWin))) {
+ pChild = pWin->lastChild;
+ while(1) {
+ if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild)))
+ break;
+
+ if(pChild->lastChild) {
+ pChild = pChild->lastChild;
+ continue;
+ }
+
+ while(!pChild->prevSib) pChild = pChild->parent;
+
+ pChild = pChild->prevSib;
+ }
+ }
+ }
+
+ if(pTree && pTree->nextSib) {
+ tChild = pTree->parent->lastChild;
+ tLast = pTree->nextSib;
+
+ while(1) {
+ if(tChild->pWin->viewable) {
+ if (REGION_BROKEN (pScreen, &tChild->pWin->winSize))
+ SetWinSize (tChild->pWin);
+ if (REGION_BROKEN (pScreen, &tChild->pWin->borderSize))
+ SetBorderSize (tChild->pWin);
+
+ if(RECT_IN_REGION(pScreen, &(tChild->pWin->borderSize), box))
+ {
+ MARK_UNDERLAY(tChild->pWin);
+ underMarked = TRUE;
+ }
+ }
+
+ if(tChild->lastChild) {
+ tChild = tChild->lastChild;
+ continue;
+ }
+
+ while(!tChild->prevSib && (tChild != tLast))
+ tChild = tChild->parent;
+
+ if(tChild == tLast) break;
+
+ tChild = tChild->prevSib;
+ }
+ }
+
+ if(underMarked) {
+ MARK_UNDERLAY(pTree->parent->pWin);
+ MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->underlayMarked = TRUE;
+ }
+
+ return (underMarked || overMarked);
+}
+
+
+static void
+miOverlayComputeClips(
+ WindowPtr pParent,
+ RegionPtr universe,
+ VTKind kind,
+ RegionPtr exposed
+){
+ ScreenPtr pScreen = pParent->drawable.pScreen;
+ int oldVis, newVis, dx, dy;
+ BoxRec borderSize;
+ RegionPtr borderVisible;
+ RegionRec childUniverse, childUnion;
+ miOverlayTreePtr tParent = MIOVERLAY_GET_WINDOW_TREE(pParent);
+ miOverlayTreePtr tChild;
+ Bool overlap;
+
+ borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent);
+ borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent);
+ dx = (int) pParent->drawable.x + (int) pParent->drawable.width +
+ wBorderWidth(pParent);
+ if (dx > 32767) dx = 32767;
+ borderSize.x2 = dx;
+ dy = (int) pParent->drawable.y + (int) pParent->drawable.height +
+ wBorderWidth(pParent);
+ if (dy > 32767) dy = 32767;
+ borderSize.y2 = dy;
+
+ oldVis = tParent->visibility;
+ switch (RECT_IN_REGION( pScreen, universe, &borderSize)) {
+ case rgnIN:
+ newVis = VisibilityUnobscured;
+ break;
+ case rgnPART:
+ newVis = VisibilityPartiallyObscured;
+#ifdef SHAPE
+ {
+ RegionPtr pBounding;
+
+ if ((pBounding = wBoundingShape (pParent))) {
+ switch (miShapedWindowIn (pScreen, universe, pBounding,
+ &borderSize,
+ pParent->drawable.x,
+ pParent->drawable.y))
+ {
+ case rgnIN:
+ newVis = VisibilityUnobscured;
+ break;
+ case rgnOUT:
+ newVis = VisibilityFullyObscured;
+ break;
+ }
+ }
+ }
+#endif
+ break;
+ default:
+ newVis = VisibilityFullyObscured;
+ break;
+ }
+ tParent->visibility = newVis;
+
+ dx = pParent->drawable.x - tParent->valdata->oldAbsCorner.x;
+ dy = pParent->drawable.y - tParent->valdata->oldAbsCorner.y;
+
+ switch (kind) {
+ case VTMap:
+ case VTStack:
+ case VTUnmap:
+ break;
+ case VTMove:
+ if ((oldVis == newVis) &&
+ ((oldVis == VisibilityFullyObscured) ||
+ (oldVis == VisibilityUnobscured)))
+ {
+ tChild = tParent;
+ while (1) {
+ if (tChild->pWin->viewable) {
+ if (tChild->visibility != VisibilityFullyObscured) {
+ REGION_TRANSLATE( pScreen, &tChild->borderClip, dx, dy);
+ REGION_TRANSLATE( pScreen, &tChild->clipList, dx, dy);
+
+ tChild->pWin->drawable.serialNumber =
+ NEXT_SERIAL_NUMBER;
+ if (pScreen->ClipNotify)
+ (* pScreen->ClipNotify) (tChild->pWin, dx, dy);
+ }
+ if (tChild->valdata) {
+ REGION_NULL(pScreen, &tChild->valdata->borderExposed);
+ if (HasParentRelativeBorder(tChild->pWin)){
+ REGION_SUBTRACT(pScreen,
+ &tChild->valdata->borderExposed,
+ &tChild->borderClip,
+ &tChild->pWin->winSize);
+ }
+ REGION_NULL(pScreen, &tChild->valdata->exposed);
+ }
+ if (tChild->firstChild) {
+ tChild = tChild->firstChild;
+ continue;
+ }
+ }
+ while (!tChild->nextSib && (tChild != tParent))
+ tChild = tChild->parent;
+ if (tChild == tParent)
+ break;
+ tChild = tChild->nextSib;
+ }
+ return;
+ }
+ /* fall through */
+ default:
+ if (dx || dy) {
+ REGION_TRANSLATE( pScreen, &tParent->borderClip, dx, dy);
+ REGION_TRANSLATE( pScreen, &tParent->clipList, dx, dy);
+ }
+ break;
+ case VTBroken:
+ REGION_EMPTY (pScreen, &tParent->borderClip);
+ REGION_EMPTY (pScreen, &tParent->clipList);
+ break;
+ }
+
+ borderVisible = tParent->valdata->borderVisible;
+ REGION_NULL(pScreen, &tParent->valdata->borderExposed);
+ REGION_NULL(pScreen, &tParent->valdata->exposed);
+
+ if (HasBorder (pParent)) {
+ if (borderVisible) {
+ REGION_SUBTRACT( pScreen, exposed, universe, borderVisible);
+ REGION_DESTROY( pScreen, borderVisible);
+ } else
+ REGION_SUBTRACT( pScreen, exposed, universe, &tParent->borderClip);
+
+ if (HasParentRelativeBorder(pParent) && (dx || dy))
+ REGION_SUBTRACT( pScreen, &tParent->valdata->borderExposed,
+ universe, &pParent->winSize);
+ else
+ REGION_SUBTRACT( pScreen, &tParent->valdata->borderExposed,
+ exposed, &pParent->winSize);
+
+ REGION_COPY( pScreen, &tParent->borderClip, universe);
+ REGION_INTERSECT( pScreen, universe, universe, &pParent->winSize);
+ }
+ else
+ REGION_COPY( pScreen, &tParent->borderClip, universe);
+
+ if ((tChild = tParent->firstChild) && pParent->mapped) {
+ REGION_NULL(pScreen, &childUniverse);
+ REGION_NULL(pScreen, &childUnion);
+
+ for (; tChild; tChild = tChild->nextSib) {
+ if (tChild->pWin->viewable)
+ REGION_APPEND( pScreen, &childUnion, &tChild->pWin->borderSize);
+ }
+
+ REGION_VALIDATE( pScreen, &childUnion, &overlap);
+
+ for (tChild = tParent->firstChild;
+ tChild;
+ tChild = tChild->nextSib)
+ {
+ if (tChild->pWin->viewable) {
+ if (tChild->valdata) {
+ REGION_INTERSECT( pScreen, &childUniverse, universe,
+ &tChild->pWin->borderSize);
+ miOverlayComputeClips (tChild->pWin, &childUniverse,
+ kind, exposed);
+ }
+ if (overlap)
+ REGION_SUBTRACT( pScreen, universe, universe,
+ &tChild->pWin->borderSize);
+ }
+ }
+ if (!overlap)
+ REGION_SUBTRACT( pScreen, universe, universe, &childUnion);
+ REGION_UNINIT( pScreen, &childUnion);
+ REGION_UNINIT( pScreen, &childUniverse);
+ }
+
+ if (oldVis == VisibilityFullyObscured ||
+ oldVis == VisibilityNotViewable)
+ {
+ REGION_COPY( pScreen, &tParent->valdata->exposed, universe);
+ }
+ else if (newVis != VisibilityFullyObscured &&
+ newVis != VisibilityNotViewable)
+ {
+ REGION_SUBTRACT( pScreen, &tParent->valdata->exposed,
+ universe, &tParent->clipList);
+ }
+
+ /* HACK ALERT - copying contents of regions, instead of regions */
+ {
+ RegionRec tmp;
+
+ tmp = tParent->clipList;
+ tParent->clipList = *universe;
+ *universe = tmp;
+ }
+
+ pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+
+ if (pScreen->ClipNotify)
+ (* pScreen->ClipNotify) (pParent, dx, dy);
+}
+
+
+static void
+miOverlayMarkWindow(WindowPtr pWin)
+{
+ miOverlayTreePtr pTree = NULL;
+ WindowPtr pChild, pGrandChild;
+
+ miMarkWindow(pWin);
+
+ /* look for UnmapValdata among immediate children */
+
+ if(!(pChild = pWin->firstChild)) return;
+
+ for( ; pChild; pChild = pChild->nextSib) {
+ if(pChild->valdata == UnmapValData) {
+ if(IN_UNDERLAY(pChild)) {
+ pTree = MIOVERLAY_GET_WINDOW_TREE(pChild);
+ pTree->valdata = (miOverlayValDataPtr)UnmapValData;
+ continue;
+ } else {
+ if(!(pGrandChild = pChild->firstChild))
+ continue;
+
+ while(1) {
+ if(IN_UNDERLAY(pGrandChild)) {
+ pTree = MIOVERLAY_GET_WINDOW_TREE(pGrandChild);
+ pTree->valdata = (miOverlayValDataPtr)UnmapValData;
+ } else if(pGrandChild->firstChild) {
+ pGrandChild = pGrandChild->firstChild;
+ continue;
+ }
+
+ while(!pGrandChild->nextSib && (pGrandChild != pChild))
+ pGrandChild = pGrandChild->parent;
+
+ if(pChild == pGrandChild) break;
+
+ pGrandChild = pGrandChild->nextSib;
+ }
+ }
+ }
+ }
+
+ if(pTree) {
+ MARK_UNDERLAY(pTree->parent->pWin);
+ MIOVERLAY_GET_SCREEN_PRIVATE(
+ pWin->drawable.pScreen)->underlayMarked = TRUE;
+ }
+}
+
+static void
+miOverlayMarkUnrealizedWindow(
+ WindowPtr pChild,
+ WindowPtr pWin,
+ Bool fromConfigure
+){
+ if ((pChild != pWin) || fromConfigure) {
+ miOverlayTreePtr pTree;
+
+ REGION_EMPTY(pChild->drawable.pScreen, &pChild->clipList);
+ if (pChild->drawable.pScreen->ClipNotify)
+ (* pChild->drawable.pScreen->ClipNotify)(pChild, 0, 0);
+ REGION_EMPTY(pChild->drawable.pScreen, &pChild->borderClip);
+ if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild))) {
+ if(pTree->valdata != (miOverlayValDataPtr)UnmapValData) {
+ REGION_EMPTY(pChild->drawable.pScreen, &pTree->clipList);
+ REGION_EMPTY(pChild->drawable.pScreen, &pTree->borderClip);
+ }
+ }
+ }
+}
+
+
+static int
+miOverlayValidateTree(
+ WindowPtr pParent,
+ WindowPtr pChild, /* first child effected */
+ VTKind kind
+){
+ ScreenPtr pScreen = pParent->drawable.pScreen;
+ miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+ RegionRec totalClip, childClip, exposed;
+ miOverlayTreePtr tParent, tChild, tWin;
+ Bool overlap;
+ WindowPtr newParent;
+
+ if(!pPriv->underlayMarked)
+ goto SKIP_UNDERLAY;
+
+ if (!pChild) pChild = pParent->firstChild;
+
+ REGION_NULL(pScreen, &totalClip);
+ REGION_NULL(pScreen, &childClip);
+ REGION_NULL(pScreen, &exposed);
+
+ newParent = pParent;
+
+ while(IN_OVERLAY(newParent))
+ newParent = newParent->parent;
+
+ tParent = MIOVERLAY_GET_WINDOW_TREE(newParent);
+
+ if(IN_UNDERLAY(pChild))
+ tChild = MIOVERLAY_GET_WINDOW_TREE(pChild);
+ else
+ tChild = tParent->firstChild;
+
+ if (REGION_BROKEN (pScreen, &tParent->clipList) &&
+ !REGION_BROKEN (pScreen, &tParent->borderClip))
+ {
+ kind = VTBroken;
+ REGION_COPY (pScreen, &totalClip, &tParent->borderClip);
+ REGION_INTERSECT (pScreen, &totalClip, &totalClip,
+ &tParent->pWin->winSize);
+
+ for (tWin = tParent->firstChild; tWin != tChild; tWin = tWin->nextSib) {
+ if (tWin->pWin->viewable)
+ REGION_SUBTRACT (pScreen, &totalClip, &totalClip,
+ &tWin->pWin->borderSize);
+ }
+ REGION_EMPTY (pScreen, &tParent->clipList);
+ } else {
+ for(tWin = tChild; tWin; tWin = tWin->nextSib) {
+ if(tWin->valdata)
+ REGION_APPEND(pScreen, &totalClip, &tWin->borderClip);
+ }
+ REGION_VALIDATE(pScreen, &totalClip, &overlap);
+ }
+
+ if(kind != VTStack)
+ REGION_UNION(pScreen, &totalClip, &totalClip, &tParent->clipList);
+
+ for(tWin = tChild; tWin; tWin = tWin->nextSib) {
+ if(tWin->valdata) {
+ if(tWin->pWin->viewable) {
+ REGION_INTERSECT(pScreen, &childClip, &totalClip,
+ &tWin->pWin->borderSize);
+ miOverlayComputeClips(tWin->pWin, &childClip, kind, &exposed);
+ REGION_SUBTRACT(pScreen, &totalClip, &totalClip,
+ &tWin->pWin->borderSize);
+ } else { /* Means we are unmapping */
+ REGION_EMPTY(pScreen, &tWin->clipList);
+ REGION_EMPTY( pScreen, &tWin->borderClip);
+ tWin->valdata = NULL;
+ }
+ }
+ }
+
+ REGION_UNINIT(pScreen, &childClip);
+
+ if(!((*pPriv->InOverlay)(newParent))) {
+ REGION_NULL(pScreen, &tParent->valdata->exposed);
+ REGION_NULL(pScreen, &tParent->valdata->borderExposed);
+ }
+
+ switch (kind) {
+ case VTStack:
+ break;
+ default:
+ if(!((*pPriv->InOverlay)(newParent)))
+ REGION_SUBTRACT(pScreen, &tParent->valdata->exposed, &totalClip,
+ &tParent->clipList);
+ /* fall through */
+ case VTMap:
+ REGION_COPY( pScreen, &tParent->clipList, &totalClip);
+ if(!((*pPriv->InOverlay)(newParent)))
+ newParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ break;
+ }
+
+ REGION_UNINIT( pScreen, &totalClip);
+ REGION_UNINIT( pScreen, &exposed);
+
+SKIP_UNDERLAY:
+
+ miValidateTree(pParent, pChild, kind);
+
+ return 1;
+}
+
+
+static void
+miOverlayHandleExposures(WindowPtr pWin)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+ WindowPtr pChild;
+ ValidatePtr val;
+ void (* WindowExposures)(WindowPtr, RegionPtr, RegionPtr);
+
+ WindowExposures = pWin->drawable.pScreen->WindowExposures;
+ if(pPriv->underlayMarked) {
+ miOverlayTreePtr pTree;
+ miOverlayValDataPtr mival;
+
+ pChild = pWin;
+ while(IN_OVERLAY(pChild))
+ pChild = pChild->parent;
+
+ pTree = MIOVERLAY_GET_WINDOW_TREE(pChild);
+
+ while (1) {
+ if((mival = pTree->valdata)) {
+ if(!((*pPriv->InOverlay)(pTree->pWin))) {
+ if (REGION_NOTEMPTY(pScreen, &mival->borderExposed))
+ (*pWin->drawable.pScreen->PaintWindowBorder)(
+ pTree->pWin, &mival->borderExposed, PW_BORDER);
+ REGION_UNINIT(pScreen, &mival->borderExposed);
+
+ (*WindowExposures)(pTree->pWin,&mival->exposed,NullRegion);
+ REGION_UNINIT(pScreen, &mival->exposed);
+ }
+ xfree(mival);
+ pTree->valdata = NULL;
+ if (pTree->firstChild) {
+ pTree = pTree->firstChild;
+ continue;
+ }
+ }
+ while (!pTree->nextSib && (pTree->pWin != pChild))
+ pTree = pTree->parent;
+ if (pTree->pWin == pChild)
+ break;
+ pTree = pTree->nextSib;
+ }
+ pPriv->underlayMarked = FALSE;
+ }
+
+ pChild = pWin;
+ while (1) {
+ if ( (val = pChild->valdata) ) {
+ if(!((*pPriv->InOverlay)(pChild))) {
+ REGION_UNION(pScreen, &val->after.exposed, &val->after.exposed,
+ &val->after.borderExposed);
+
+ if (REGION_NOTEMPTY(pScreen, &val->after.exposed)) {
+ (*(MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->MakeTransparent))(
+ pScreen,
+ REGION_NUM_RECTS(&val->after.exposed),
+ REGION_RECTS(&val->after.exposed));
+ }
+ } else {
+ if (REGION_NOTEMPTY(pScreen, &val->after.borderExposed))
+ (*pChild->drawable.pScreen->PaintWindowBorder)(pChild,
+ &val->after.borderExposed,
+ PW_BORDER);
+ (*WindowExposures)(pChild, &val->after.exposed, NullRegion);
+ }
+ REGION_UNINIT(pScreen, &val->after.borderExposed);
+ REGION_UNINIT(pScreen, &val->after.exposed);
+ xfree(val);
+ pChild->valdata = (ValidatePtr)NULL;
+ if (pChild->firstChild)
+ {
+ pChild = pChild->firstChild;
+ continue;
+ }
+ }
+ while (!pChild->nextSib && (pChild != pWin))
+ pChild = pChild->parent;
+ if (pChild == pWin)
+ break;
+ pChild = pChild->nextSib;
+ }
+}
+
+
+static void
+miOverlayMoveWindow(
+ WindowPtr pWin,
+ int x,
+ int y,
+ WindowPtr pNextSib,
+ VTKind kind
+){
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+ WindowPtr pParent, windowToValidate;
+ Bool WasViewable = (Bool)(pWin->viewable);
+ short bw;
+ RegionRec overReg, underReg;
+ DDXPointRec oldpt;
+#ifdef DO_SAVE_UNDERS
+ Bool dosave = FALSE;
+#endif
+
+ if (!(pParent = pWin->parent))
+ return ;
+ bw = wBorderWidth (pWin);
+
+ oldpt.x = pWin->drawable.x;
+ oldpt.y = pWin->drawable.y;
+ if (WasViewable) {
+ REGION_NULL(pScreen, &overReg);
+ REGION_NULL(pScreen, &underReg);
+ if(pTree) {
+ REGION_COPY(pScreen, &overReg, &pWin->borderClip);
+ REGION_COPY(pScreen, &underReg, &pTree->borderClip);
+ } else {
+ REGION_COPY(pScreen, &overReg, &pWin->borderClip);
+ CollectUnderlayChildrenRegions(pWin, &underReg);
+ }
+ (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL);
+ }
+ pWin->origin.x = x + (int)bw;
+ pWin->origin.y = y + (int)bw;
+ x = pWin->drawable.x = pParent->drawable.x + x + (int)bw;
+ y = pWin->drawable.y = pParent->drawable.y + y + (int)bw;
+
+ SetWinSize (pWin);
+ SetBorderSize (pWin);
+
+ (*pScreen->PositionWindow)(pWin, x, y);
+
+ windowToValidate = MoveWindowInStack(pWin, pNextSib);
+
+ ResizeChildrenWinSize(pWin, x - oldpt.x, y - oldpt.y, 0, 0);
+
+ if (WasViewable) {
+ miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+ (*pScreen->MarkOverlappedWindows) (pWin, windowToValidate, NULL);
+
+#ifdef DO_SAVE_UNDERS
+ if (DO_SAVE_UNDERS(pWin))
+ dosave = (*pScreen->ChangeSaveUnder)(pWin, windowToValidate);
+#endif /* DO_SAVE_UNDERS */
+
+ (*pScreen->ValidateTree)(pWin->parent, NullWindow, kind);
+ if(REGION_NOTEMPTY(pScreen, &underReg)) {
+ pPriv->copyUnderlay = TRUE;
+ (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, &underReg);
+ }
+ REGION_UNINIT(pScreen, &underReg);
+ if(REGION_NOTEMPTY(pScreen, &overReg)) {
+ pPriv->copyUnderlay = FALSE;
+ (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, &overReg);
+ }
+ REGION_UNINIT(pScreen, &overReg);
+ (*pScreen->HandleExposures)(pWin->parent);
+
+#ifdef DO_SAVE_UNDERS
+ if (dosave)
+ (*pScreen->PostChangeSaveUnder)(pWin, windowToValidate);
+#endif /* DO_SAVE_UNDERS */
+ if (pScreen->PostValidateTree)
+ (*pScreen->PostValidateTree)(pWin->parent, NullWindow, kind);
+ }
+ if (pWin->realized)
+ WindowsRestructured ();
+}
+
+#ifndef RECTLIMIT
+#define RECTLIMIT 25
+#endif
+
+static void
+miOverlayWindowExposures(
+ WindowPtr pWin,
+ register RegionPtr prgn,
+ RegionPtr other_exposed
+){
+ RegionPtr exposures = prgn;
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+
+ if (pWin->backStorage && prgn)
+ exposures = (*pScreen->RestoreAreas)(pWin, prgn);
+ if ((prgn && !REGION_NIL(prgn)) ||
+ (exposures && !REGION_NIL(exposures)) || other_exposed)
+ {
+ RegionRec expRec;
+ int clientInterested;
+
+ clientInterested = (pWin->eventMask|wOtherEventMasks(pWin)) &
+ ExposureMask;
+ if (other_exposed) {
+ if (exposures) {
+ REGION_UNION(pScreen, other_exposed, exposures, other_exposed);
+ if (exposures != prgn)
+ REGION_DESTROY(pScreen, exposures);
+ }
+ exposures = other_exposed;
+ }
+ if (clientInterested && exposures &&
+ (REGION_NUM_RECTS(exposures) > RECTLIMIT))
+ {
+ miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+ BoxRec box;
+
+ box = *REGION_EXTENTS(pScreen, exposures);
+ if (exposures == prgn) {
+ exposures = &expRec;
+ REGION_INIT(pScreen, exposures, &box, 1);
+ REGION_RESET(pScreen, prgn, &box);
+ } else {
+ REGION_RESET(pScreen, exposures, &box);
+ REGION_UNION(pScreen, prgn, prgn, exposures);
+ }
+ /* This is the only reason why we are replacing mi's version
+ of this file */
+
+ if(!((*pPriv->InOverlay)(pWin))) {
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+ REGION_INTERSECT(pScreen, prgn, prgn, &pTree->clipList);
+ } else
+ REGION_INTERSECT(pScreen, prgn, prgn, &pWin->clipList);
+
+ /* need to clear out new areas of backing store, too */
+ if (pWin->backStorage)
+ (void) (*pScreen->ClearBackingStore)(
+ pWin,
+ box.x1 - pWin->drawable.x,
+ box.y1 - pWin->drawable.y,
+ box.x2 - box.x1,
+ box.y2 - box.y1,
+ FALSE);
+ }
+ if (prgn && !REGION_NIL(prgn))
+ (*pScreen->PaintWindowBackground)(
+ pWin, prgn, PW_BACKGROUND);
+ if (clientInterested && exposures && !REGION_NIL(exposures))
+ miSendExposures(pWin, exposures,
+ pWin->drawable.x, pWin->drawable.y);
+ if (exposures == &expRec) {
+ REGION_UNINIT(pScreen, exposures);
+ }
+ else if (exposures && exposures != prgn && exposures != other_exposed)
+ REGION_DESTROY(pScreen, exposures);
+ if (prgn)
+ REGION_EMPTY(pScreen, prgn);
+ }
+ else if (exposures && exposures != prgn)
+ REGION_DESTROY(pScreen, exposures);
+}
+
+
+typedef struct {
+ RegionPtr over;
+ RegionPtr under;
+} miOverlayTwoRegions;
+
+static int
+miOverlayRecomputeExposures (
+ WindowPtr pWin,
+ pointer value
+){
+ register ScreenPtr pScreen;
+ miOverlayTwoRegions *pValid = (miOverlayTwoRegions*)value;
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+
+ /* This prevents warning about pScreen not being used. */
+ pWin->drawable.pScreen = pScreen = pWin->drawable.pScreen;
+
+ if (pWin->valdata) {
+ /*
+ * compute exposed regions of this window
+ */
+ REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed,
+ &pWin->clipList, pValid->over);
+ /*
+ * compute exposed regions of the border
+ */
+ REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed,
+ &pWin->borderClip, &pWin->winSize);
+ REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed,
+ &pWin->valdata->after.borderExposed, pValid->over);
+ }
+
+ if(pTree && pTree->valdata) {
+ REGION_SUBTRACT(pScreen, &pTree->valdata->exposed,
+ &pTree->clipList, pValid->under);
+ REGION_SUBTRACT(pScreen, &pTree->valdata->borderExposed,
+ &pTree->borderClip, &pWin->winSize);
+ REGION_SUBTRACT(pScreen, &pTree->valdata->borderExposed,
+ &pTree->valdata->borderExposed, pValid->under);
+ } else if (!pWin->valdata)
+ return WT_NOMATCH;
+
+ return WT_WALKCHILDREN;
+}
+
+static void
+miOverlayResizeWindow(
+ WindowPtr pWin,
+ int x, int y,
+ unsigned int w, unsigned int h,
+ WindowPtr pSib
+){
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ WindowPtr pParent;
+ miOverlayTreePtr tChild, pTree;
+ Bool WasViewable = (Bool)(pWin->viewable);
+ unsigned short width = pWin->drawable.width;
+ unsigned short height = pWin->drawable.height;
+ short oldx = pWin->drawable.x;
+ short oldy = pWin->drawable.y;
+ int bw = wBorderWidth (pWin);
+ short dw, dh;
+ DDXPointRec oldpt;
+ RegionPtr oldRegion = NULL, oldRegion2 = NULL;
+ WindowPtr pFirstChange;
+ register WindowPtr pChild;
+ RegionPtr gravitate[StaticGravity + 1];
+ RegionPtr gravitate2[StaticGravity + 1];
+ register unsigned g;
+ int nx, ny; /* destination x,y */
+ int newx, newy; /* new inner window position */
+ RegionPtr pRegion = NULL;
+ RegionPtr destClip, destClip2;
+ RegionPtr oldWinClip = NULL, oldWinClip2 = NULL;
+ RegionPtr borderVisible = NullRegion;
+ RegionPtr borderVisible2 = NullRegion;
+ RegionPtr bsExposed = NullRegion; /* backing store exposures */
+ Bool shrunk = FALSE; /* shrunk in an inner dimension */
+ Bool moved = FALSE; /* window position changed */
+#ifdef DO_SAVE_UNDERS
+ Bool dosave = FALSE;
+#endif
+ Bool doUnderlay;
+
+ /* if this is a root window, can't be resized */
+ if (!(pParent = pWin->parent))
+ return ;
+
+ pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+ doUnderlay = ((pTree) || HasUnderlayChildren(pWin));
+ newx = pParent->drawable.x + x + bw;
+ newy = pParent->drawable.y + y + bw;
+ if (WasViewable)
+ {
+ /*
+ * save the visible region of the window
+ */
+ oldRegion = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_COPY(pScreen, oldRegion, &pWin->winSize);
+ if(doUnderlay) {
+ oldRegion2 = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_COPY(pScreen, oldRegion2, &pWin->winSize);
+ }
+
+ /*
+ * categorize child windows into regions to be moved
+ */
+ for (g = 0; g <= StaticGravity; g++)
+ gravitate[g] = gravitate2[g] = NULL;
+ for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) {
+ g = pChild->winGravity;
+ if (g != UnmapGravity) {
+ if (!gravitate[g])
+ gravitate[g] = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_UNION(pScreen, gravitate[g],
+ gravitate[g], &pChild->borderClip);
+
+ if(doUnderlay) {
+ if (!gravitate2[g])
+ gravitate2[g] = REGION_CREATE(pScreen, NullBox, 0);
+
+ if((tChild = MIOVERLAY_GET_WINDOW_TREE(pChild))) {
+ REGION_UNION(pScreen, gravitate2[g],
+ gravitate2[g], &tChild->borderClip);
+ } else
+ CollectUnderlayChildrenRegions(pChild, gravitate2[g]);
+ }
+ } else {
+ UnmapWindow(pChild, TRUE);
+ }
+ }
+ (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL);
+
+
+ oldWinClip = oldWinClip2 = NULL;
+ if (pWin->bitGravity != ForgetGravity) {
+ oldWinClip = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_COPY(pScreen, oldWinClip, &pWin->clipList);
+ if(pTree) {
+ oldWinClip2 = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_COPY(pScreen, oldWinClip2, &pTree->clipList);
+ }
+ }
+ /*
+ * if the window is changing size, borderExposed
+ * can't be computed correctly without some help.
+ */
+ if (pWin->drawable.height > h || pWin->drawable.width > w)
+ shrunk = TRUE;
+
+ if (newx != oldx || newy != oldy)
+ moved = TRUE;
+
+ if ((pWin->drawable.height != h || pWin->drawable.width != w) &&
+ HasBorder (pWin))
+ {
+ borderVisible = REGION_CREATE(pScreen, NullBox, 1);
+ if(pTree)
+ borderVisible2 = REGION_CREATE(pScreen, NullBox, 1);
+ /* for tiled borders, we punt and draw the whole thing */
+ if (pWin->borderIsPixel || !moved)
+ {
+ if (shrunk || moved)
+ REGION_SUBTRACT(pScreen, borderVisible,
+ &pWin->borderClip,
+ &pWin->winSize);
+ else
+ REGION_COPY(pScreen, borderVisible,
+ &pWin->borderClip);
+ if(pTree) {
+ if (shrunk || moved)
+ REGION_SUBTRACT(pScreen, borderVisible,
+ &pTree->borderClip,
+ &pWin->winSize);
+ else
+ REGION_COPY(pScreen, borderVisible,
+ &pTree->borderClip);
+ }
+ }
+ }
+ }
+ pWin->origin.x = x + bw;
+ pWin->origin.y = y + bw;
+ pWin->drawable.height = h;
+ pWin->drawable.width = w;
+
+ x = pWin->drawable.x = newx;
+ y = pWin->drawable.y = newy;
+
+ SetWinSize (pWin);
+ SetBorderSize (pWin);
+
+ dw = (int)w - (int)width;
+ dh = (int)h - (int)height;
+ ResizeChildrenWinSize(pWin, x - oldx, y - oldy, dw, dh);
+
+ /* let the hardware adjust background and border pixmaps, if any */
+ (*pScreen->PositionWindow)(pWin, x, y);
+
+ pFirstChange = MoveWindowInStack(pWin, pSib);
+
+ if (WasViewable) {
+ pRegion = REGION_CREATE(pScreen, NullBox, 1);
+ if (pWin->backStorage)
+ REGION_COPY(pScreen, pRegion, &pWin->clipList);
+
+ (*pScreen->MarkOverlappedWindows)(pWin, pFirstChange, NULL);
+
+ pWin->valdata->before.resized = TRUE;
+ pWin->valdata->before.borderVisible = borderVisible;
+ if(pTree)
+ pTree->valdata->borderVisible = borderVisible2;
+
+#ifdef DO_SAVE_UNDERS
+ if (DO_SAVE_UNDERS(pWin))
+ dosave = (*pScreen->ChangeSaveUnder)(pWin, pFirstChange);
+#endif /* DO_SAVE_UNDERS */
+
+ (*pScreen->ValidateTree)(pWin->parent, pFirstChange, VTOther);
+ /*
+ * the entire window is trashed unless bitGravity
+ * recovers portions of it
+ */
+ REGION_COPY(pScreen, &pWin->valdata->after.exposed, &pWin->clipList);
+ if(pTree)
+ REGION_COPY(pScreen, &pTree->valdata->exposed, &pTree->clipList);
+ }
+
+ GravityTranslate (x, y, oldx, oldy, dw, dh, pWin->bitGravity, &nx, &ny);
+
+ if (pWin->backStorage && ((pWin->backingStore == Always) || WasViewable)) {
+ if (!WasViewable)
+ pRegion = &pWin->clipList; /* a convenient empty region */
+ if (pWin->bitGravity == ForgetGravity)
+ bsExposed = (*pScreen->TranslateBackingStore)
+ (pWin, 0, 0, NullRegion, oldx, oldy);
+ else
+ bsExposed = (*pScreen->TranslateBackingStore)
+ (pWin, nx - x, ny - y, pRegion, oldx, oldy);
+ }
+
+ if (WasViewable) {
+ miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+ miOverlayTwoRegions TwoRegions;
+
+ /* avoid the border */
+ if (HasBorder (pWin)) {
+ int offx, offy, dx, dy;
+
+ /* kruft to avoid double translates for each gravity */
+ offx = 0;
+ offy = 0;
+ for (g = 0; g <= StaticGravity; g++) {
+ if (!gravitate[g] && !gravitate2[g])
+ continue;
+
+ /* align winSize to gravitate[g].
+ * winSize is in new coordinates,
+ * gravitate[g] is still in old coordinates */
+ GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny);
+
+ dx = (oldx - nx) - offx;
+ dy = (oldy - ny) - offy;
+ if (dx || dy) {
+ REGION_TRANSLATE(pScreen, &pWin->winSize, dx, dy);
+ offx += dx;
+ offy += dy;
+ }
+ if(gravitate[g])
+ REGION_INTERSECT(pScreen, gravitate[g], gravitate[g],
+ &pWin->winSize);
+ if(gravitate2[g])
+ REGION_INTERSECT(pScreen, gravitate2[g], gravitate2[g],
+ &pWin->winSize);
+ }
+ /* get winSize back where it belongs */
+ if (offx || offy)
+ REGION_TRANSLATE(pScreen, &pWin->winSize, -offx, -offy);
+ }
+ /*
+ * add screen bits to the appropriate bucket
+ */
+
+ if (oldWinClip2)
+ {
+ REGION_COPY(pScreen, pRegion, oldWinClip2);
+ REGION_TRANSLATE(pScreen, pRegion, nx - oldx, ny - oldy);
+ REGION_INTERSECT(pScreen, oldWinClip2, pRegion, &pTree->clipList);
+
+ for (g = pWin->bitGravity + 1; g <= StaticGravity; g++) {
+ if (gravitate2[g])
+ REGION_SUBTRACT(pScreen, oldWinClip2, oldWinClip2,
+ gravitate2[g]);
+ }
+ REGION_TRANSLATE(pScreen, oldWinClip2, oldx - nx, oldy - ny);
+ g = pWin->bitGravity;
+ if (!gravitate2[g])
+ gravitate2[g] = oldWinClip2;
+ else {
+ REGION_UNION(pScreen,gravitate2[g],gravitate2[g],oldWinClip2);
+ REGION_DESTROY(pScreen, oldWinClip2);
+ }
+ }
+
+ if (oldWinClip)
+ {
+ /*
+ * clip to new clipList
+ */
+ REGION_COPY(pScreen, pRegion, oldWinClip);
+ REGION_TRANSLATE(pScreen, pRegion, nx - oldx, ny - oldy);
+ REGION_INTERSECT(pScreen, oldWinClip, pRegion, &pWin->clipList);
+ /*
+ * don't step on any gravity bits which will be copied after this
+ * region. Note -- this assumes that the regions will be copied
+ * in gravity order.
+ */
+ for (g = pWin->bitGravity + 1; g <= StaticGravity; g++) {
+ if (gravitate[g])
+ REGION_SUBTRACT(pScreen, oldWinClip, oldWinClip,
+ gravitate[g]);
+ }
+ REGION_TRANSLATE(pScreen, oldWinClip, oldx - nx, oldy - ny);
+ g = pWin->bitGravity;
+ if (!gravitate[g])
+ gravitate[g] = oldWinClip;
+ else {
+ REGION_UNION(pScreen, gravitate[g], gravitate[g], oldWinClip);
+ REGION_DESTROY(pScreen, oldWinClip);
+ }
+ }
+
+ /*
+ * move the bits on the screen
+ */
+
+ destClip = destClip2 = NULL;
+
+ for (g = 0; g <= StaticGravity; g++) {
+ if (!gravitate[g] && !gravitate2[g])
+ continue;
+
+ GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny);
+
+ oldpt.x = oldx + (x - nx);
+ oldpt.y = oldy + (y - ny);
+
+ /* Note that gravitate[g] is *translated* by CopyWindow */
+
+ /* only copy the remaining useful bits */
+
+ if(gravitate[g])
+ REGION_INTERSECT(pScreen, gravitate[g],
+ gravitate[g], oldRegion);
+ if(gravitate2[g])
+ REGION_INTERSECT(pScreen, gravitate2[g],
+ gravitate2[g], oldRegion2);
+
+ /* clip to not overwrite already copied areas */
+
+ if (destClip && gravitate[g]) {
+ REGION_TRANSLATE(pScreen, destClip, oldpt.x - x, oldpt.y - y);
+ REGION_SUBTRACT(pScreen, gravitate[g], gravitate[g], destClip);
+ REGION_TRANSLATE(pScreen, destClip, x - oldpt.x, y - oldpt.y);
+ }
+ if (destClip2 && gravitate2[g]) {
+ REGION_TRANSLATE(pScreen, destClip2, oldpt.x - x, oldpt.y - y);
+ REGION_SUBTRACT(pScreen,gravitate2[g],gravitate2[g],destClip2);
+ REGION_TRANSLATE(pScreen, destClip2, x - oldpt.x, y - oldpt.y);
+ }
+
+ /* and move those bits */
+
+ if (oldpt.x != x || oldpt.y != y) {
+ if(gravitate2[g]) {
+ pPriv->copyUnderlay = TRUE;
+ (*pWin->drawable.pScreen->CopyWindow)(
+ pWin, oldpt, gravitate2[g]);
+ }
+ if(gravitate[g]) {
+ pPriv->copyUnderlay = FALSE;
+ (*pWin->drawable.pScreen->CopyWindow)(
+ pWin, oldpt, gravitate[g]);
+ }
+ }
+
+ /* remove any overwritten bits from the remaining useful bits */
+
+ if(gravitate[g])
+ REGION_SUBTRACT(pScreen, oldRegion, oldRegion, gravitate[g]);
+ if(gravitate2[g])
+ REGION_SUBTRACT(pScreen, oldRegion2, oldRegion2, gravitate2[g]);
+
+ /*
+ * recompute exposed regions of child windows
+ */
+
+
+ for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) {
+ if (pChild->winGravity != g)
+ continue;
+
+ TwoRegions.over = gravitate[g];
+ TwoRegions.under = gravitate2[g];
+
+ TraverseTree (pChild, miOverlayRecomputeExposures,
+ (pointer)(&TwoRegions));
+ }
+
+ /*
+ * remove the successfully copied regions of the
+ * window from its exposed region
+ */
+
+ if (g == pWin->bitGravity) {
+ if(gravitate[g])
+ REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed,
+ &pWin->valdata->after.exposed, gravitate[g]);
+ if(gravitate2[g] && pTree)
+ REGION_SUBTRACT(pScreen, &pTree->valdata->exposed,
+ &pTree->valdata->exposed, gravitate2[g]);
+ }
+ if(gravitate[g]) {
+ if (!destClip)
+ destClip = gravitate[g];
+ else {
+ REGION_UNION(pScreen, destClip, destClip, gravitate[g]);
+ REGION_DESTROY(pScreen, gravitate[g]);
+ }
+ }
+ if(gravitate2[g]) {
+ if (!destClip2)
+ destClip2 = gravitate2[g];
+ else {
+ REGION_UNION(pScreen, destClip2, destClip2, gravitate2[g]);
+ REGION_DESTROY(pScreen, gravitate2[g]);
+ }
+ }
+ }
+
+ REGION_DESTROY(pScreen, pRegion);
+ REGION_DESTROY(pScreen, oldRegion);
+ if(doUnderlay)
+ REGION_DESTROY(pScreen, oldRegion2);
+ if (destClip)
+ REGION_DESTROY(pScreen, destClip);
+ if (destClip2)
+ REGION_DESTROY(pScreen, destClip2);
+ if (bsExposed) {
+ RegionPtr valExposed = NullRegion;
+
+ if (pWin->valdata)
+ valExposed = &pWin->valdata->after.exposed;
+ (*pScreen->WindowExposures) (pWin, valExposed, bsExposed);
+ if (valExposed)
+ REGION_EMPTY(pScreen, valExposed);
+ REGION_DESTROY(pScreen, bsExposed);
+ }
+ (*pScreen->HandleExposures)(pWin->parent);
+#ifdef DO_SAVE_UNDERS
+ if (dosave)
+ (*pScreen->PostChangeSaveUnder)(pWin, pFirstChange);
+#endif /* DO_SAVE_UNDERS */
+ if (pScreen->PostValidateTree)
+ (*pScreen->PostValidateTree)(pWin->parent, pFirstChange, VTOther);
+ }
+ else if (bsExposed) {
+ (*pScreen->WindowExposures) (pWin, NullRegion, bsExposed);
+ REGION_DESTROY(pScreen, bsExposed);
+ }
+ if (pWin->realized)
+ WindowsRestructured ();
+}
+
+
+#ifdef SHAPE
+static void
+miOverlaySetShape(WindowPtr pWin)
+{
+ Bool WasViewable = (Bool)(pWin->viewable);
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ RegionPtr pOldClip = NULL, bsExposed;
+#ifdef DO_SAVE_UNDERS
+ Bool dosave = FALSE;
+#endif
+
+ if (WasViewable) {
+ (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL);
+
+ if (HasBorder (pWin)) {
+ RegionPtr borderVisible;
+
+ borderVisible = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_SUBTRACT(pScreen, borderVisible,
+ &pWin->borderClip, &pWin->winSize);
+ pWin->valdata->before.borderVisible = borderVisible;
+ pWin->valdata->before.resized = TRUE;
+ if(IN_UNDERLAY(pWin)) {
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+ RegionPtr borderVisible2;
+
+ borderVisible2 = REGION_CREATE(pScreen, NULL, 1);
+ REGION_SUBTRACT(pScreen, borderVisible2,
+ &pTree->borderClip, &pWin->winSize);
+ pTree->valdata->borderVisible = borderVisible2;
+ }
+ }
+ }
+
+ SetWinSize (pWin);
+ SetBorderSize (pWin);
+
+ ResizeChildrenWinSize(pWin, 0, 0, 0, 0);
+
+ if (WasViewable) {
+ if (pWin->backStorage) {
+ pOldClip = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_COPY(pScreen, pOldClip, &pWin->clipList);
+ }
+
+ (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL);
+
+#ifdef DO_SAVE_UNDERS
+ if (DO_SAVE_UNDERS(pWin))
+ dosave = (*pScreen->ChangeSaveUnder)(pWin, pWin);
+#endif /* DO_SAVE_UNDERS */
+
+ (*pScreen->ValidateTree)(pWin->parent, NullWindow, VTOther);
+ }
+
+ if (pWin->backStorage && ((pWin->backingStore == Always) || WasViewable)) {
+ if (!WasViewable)
+ pOldClip = &pWin->clipList; /* a convenient empty region */
+ bsExposed = (*pScreen->TranslateBackingStore)
+ (pWin, 0, 0, pOldClip,
+ pWin->drawable.x, pWin->drawable.y);
+ if (WasViewable)
+ REGION_DESTROY(pScreen, pOldClip);
+ if (bsExposed)
+ {
+ RegionPtr valExposed = NullRegion;
+
+ if (pWin->valdata)
+ valExposed = &pWin->valdata->after.exposed;
+ (*pScreen->WindowExposures) (pWin, valExposed, bsExposed);
+ if (valExposed)
+ REGION_EMPTY(pScreen, valExposed);
+ REGION_DESTROY(pScreen, bsExposed);
+ }
+ }
+ if (WasViewable) {
+ (*pScreen->HandleExposures)(pWin->parent);
+#ifdef DO_SAVE_UNDERS
+ if (dosave)
+ (*pScreen->PostChangeSaveUnder)(pWin, pWin);
+#endif /* DO_SAVE_UNDERS */
+ if (pScreen->PostValidateTree)
+ (*pScreen->PostValidateTree)(pWin->parent, NullWindow, VTOther);
+ }
+ if (pWin->realized)
+ WindowsRestructured ();
+ CheckCursorConfinement(pWin);
+}
+#endif
+
+
+
+static void
+miOverlayChangeBorderWidth(
+ WindowPtr pWin,
+ unsigned int width
+){
+ int oldwidth;
+ register ScreenPtr pScreen;
+ Bool WasViewable = (Bool)(pWin->viewable);
+ Bool HadBorder;
+#ifdef DO_SAVE_UNDERS
+ Bool dosave = FALSE;
+#endif
+
+ oldwidth = wBorderWidth (pWin);
+ if (oldwidth == width)
+ return;
+ HadBorder = HasBorder(pWin);
+ pScreen = pWin->drawable.pScreen;
+ if (WasViewable && (width < oldwidth))
+ (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL);
+
+ pWin->borderWidth = width;
+ SetBorderSize (pWin);
+
+ if (WasViewable) {
+ if (width > oldwidth) {
+ (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL);
+
+ if (HadBorder) {
+ RegionPtr borderVisible;
+ borderVisible = REGION_CREATE(pScreen, NULL, 1);
+ REGION_SUBTRACT(pScreen, borderVisible,
+ &pWin->borderClip, &pWin->winSize);
+ pWin->valdata->before.borderVisible = borderVisible;
+ if(IN_UNDERLAY(pWin)) {
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+ RegionPtr borderVisible2;
+
+ borderVisible2 = REGION_CREATE(pScreen, NULL, 1);
+ REGION_SUBTRACT(pScreen, borderVisible2,
+ &pTree->borderClip, &pWin->winSize);
+ pTree->valdata->borderVisible = borderVisible2;
+ }
+ }
+ }
+#ifdef DO_SAVE_UNDERS
+ if (DO_SAVE_UNDERS(pWin))
+ dosave = (*pScreen->ChangeSaveUnder)(pWin, pWin->nextSib);
+#endif /* DO_SAVE_UNDERS */
+ (*pScreen->ValidateTree)(pWin->parent, pWin, VTOther);
+ (*pScreen->HandleExposures)(pWin->parent);
+
+#ifdef DO_SAVE_UNDERS
+ if (dosave)
+ (*pScreen->PostChangeSaveUnder)(pWin, pWin->nextSib);
+#endif /* DO_SAVE_UNDERS */
+ if (pScreen->PostValidateTree)
+ (*pScreen->PostValidateTree)(pWin->parent, pWin, VTOther);
+ }
+ if (pWin->realized)
+ WindowsRestructured ();
+}
+
+/* We need this as an addition since the xf86 common code doesn't
+ know about the second tree which is static to this file. */
+
+_X_EXPORT void
+miOverlaySetRootClip(ScreenPtr pScreen, Bool enable)
+{
+ WindowPtr pRoot = WindowTable[pScreen->myNum];
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pRoot);
+
+ MARK_UNDERLAY(pRoot);
+
+ if(enable) {
+ BoxRec box;
+
+ box.x1 = 0;
+ box.y1 = 0;
+ box.x2 = pScreen->width;
+ box.y2 = pScreen->height;
+
+ REGION_RESET(pScreen, &pTree->borderClip, &box);
+ } else
+ REGION_EMPTY(pScreen, &pTree->borderClip);
+
+ REGION_BREAK(pScreen, &pTree->clipList);
+}
+
+static void
+miOverlayClearToBackground(
+ WindowPtr pWin,
+ int x, int y,
+ int w, int h,
+ Bool generateExposures
+)
+{
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+ BoxRec box;
+ RegionRec reg;
+ RegionPtr pBSReg = NullRegion;
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+ RegionPtr clipList;
+ BoxPtr extents;
+ int x1, y1, x2, y2;
+
+ x1 = pWin->drawable.x + x;
+ y1 = pWin->drawable.y + y;
+ if (w)
+ x2 = x1 + (int) w;
+ else
+ x2 = x1 + (int) pWin->drawable.width - (int) x;
+ if (h)
+ y2 = y1 + h;
+ else
+ y2 = y1 + (int) pWin->drawable.height - (int) y;
+
+ clipList = ((*pScreenPriv->InOverlay)(pWin)) ? &pWin->clipList :
+ &pTree->clipList;
+
+ extents = REGION_EXTENTS(pScreen, clipList);
+
+ if (x1 < extents->x1) x1 = extents->x1;
+ if (x2 > extents->x2) x2 = extents->x2;
+ if (y1 < extents->y1) y1 = extents->y1;
+ if (y2 > extents->y2) y2 = extents->y2;
+
+ if (x2 <= x1 || y2 <= y1)
+ x2 = x1 = y2 = y1 = 0;
+
+ box.x1 = x1; box.x2 = x2;
+ box.y1 = y1; box.y2 = y2;
+
+ REGION_INIT(pScreen, &reg, &box, 1);
+ if (pWin->backStorage) {
+ pBSReg = (* pScreen->ClearBackingStore)(pWin, x, y, w, h,
+ generateExposures);
+ }
+
+ REGION_INTERSECT(pScreen, &reg, &reg, clipList);
+ if (generateExposures)
+ (*pScreen->WindowExposures)(pWin, &reg, pBSReg);
+ else if (pWin->backgroundState != None)
+ (*pScreen->PaintWindowBackground)(pWin, &reg, PW_BACKGROUND);
+ REGION_UNINIT(pScreen, &reg);
+ if (pBSReg)
+ REGION_DESTROY(pScreen, pBSReg);
+}
+
+
+/****************************************************************/
+
+/* not used */
+_X_EXPORT Bool
+miOverlayGetPrivateClips(
+ WindowPtr pWin,
+ RegionPtr *borderClip,
+ RegionPtr *clipList
+){
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+
+ if(pTree) {
+ *borderClip = &(pTree->borderClip);
+ *clipList = &(pTree->clipList);
+ return TRUE;
+ }
+
+ *borderClip = *clipList = NULL;
+
+ return FALSE;
+}
+
+_X_EXPORT void
+miOverlaySetTransFunction (
+ ScreenPtr pScreen,
+ miOverlayTransFunc transFunc
+){
+ MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->MakeTransparent = transFunc;
+}
+
+_X_EXPORT Bool
+miOverlayCopyUnderlay(ScreenPtr pScreen)
+{
+ return MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->copyUnderlay;
+}
+
+_X_EXPORT void
+miOverlayComputeCompositeClip(GCPtr pGC, WindowPtr pWin)
+{
+ ScreenPtr pScreen = pGC->pScreen;
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+ RegionPtr pregWin;
+ Bool freeTmpClip, freeCompClip;
+
+ if(!pTree) {
+ miComputeCompositeClip(pGC, &pWin->drawable);
+ return;
+ }
+
+ if (pGC->subWindowMode == IncludeInferiors) {
+ pregWin = REGION_CREATE(pScreen, NullBox, 1);
+ freeTmpClip = TRUE;
+ if (pWin->parent || (screenIsSaved != SCREEN_SAVER_ON) ||
+ !HasSaverWindow (pScreen->myNum))
+ {
+ REGION_INTERSECT(pScreen,pregWin,&pTree->borderClip,&pWin->winSize);
+ }
+ } else {
+ pregWin = &pTree->clipList;
+ freeTmpClip = FALSE;
+ }
+ freeCompClip = pGC->freeCompClip;
+ if (pGC->clientClipType == CT_NONE) {
+ if (freeCompClip)
+ REGION_DESTROY(pScreen, pGC->pCompositeClip);
+ pGC->pCompositeClip = pregWin;
+ pGC->freeCompClip = freeTmpClip;
+ } else {
+ REGION_TRANSLATE(pScreen, pGC->clientClip,
+ pWin->drawable.x + pGC->clipOrg.x,
+ pWin->drawable.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 {
+ pGC->pCompositeClip = REGION_CREATE(pScreen, NullBox, 0);
+ REGION_INTERSECT(pScreen, pGC->pCompositeClip,
+ pregWin, pGC->clientClip);
+ }
+ pGC->freeCompClip = TRUE;
+ REGION_TRANSLATE(pScreen, pGC->clientClip,
+ -(pWin->drawable.x + pGC->clipOrg.x),
+ -(pWin->drawable.y + pGC->clipOrg.y));
+ }
+}
+
+_X_EXPORT Bool
+miOverlayCollectUnderlayRegions(
+ WindowPtr pWin,
+ RegionPtr *region
+){
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+
+ if(pTree) {
+ *region = &pTree->borderClip;
+ return FALSE;
+ }
+
+ *region = REGION_CREATE(pWin->drawable.pScreen, NullBox, 0);
+
+ CollectUnderlayChildrenRegions(pWin, *region);
+
+ return TRUE;
+}
+
+
+static miOverlayTreePtr
+DoLeaf(
+ WindowPtr pWin,
+ miOverlayTreePtr parent,
+ miOverlayTreePtr prevSib
+){
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+
+ pTree->parent = parent;
+ pTree->firstChild = NULL;
+ pTree->lastChild = NULL;
+ pTree->prevSib = prevSib;
+ pTree->nextSib = NULL;
+
+ if(prevSib)
+ prevSib->nextSib = pTree;
+
+ if(!parent->firstChild)
+ parent->firstChild = parent->lastChild = pTree;
+ else if(parent->lastChild == prevSib)
+ parent->lastChild = pTree;
+
+ return pTree;
+}
+
+static void
+RebuildTree(WindowPtr pWin)
+{
+ miOverlayTreePtr parent, prevSib, tChild;
+ WindowPtr pChild;
+
+ prevSib = tChild = NULL;
+
+ pWin = pWin->parent;
+
+ while(IN_OVERLAY(pWin))
+ pWin = pWin->parent;
+
+ parent = MIOVERLAY_GET_WINDOW_TREE(pWin);
+
+ pChild = pWin->firstChild;
+ parent->firstChild = parent->lastChild = NULL;
+
+ while(1) {
+ if(IN_UNDERLAY(pChild))
+ prevSib = tChild = DoLeaf(pChild, parent, prevSib);
+
+ if(pChild->firstChild) {
+ if(IN_UNDERLAY(pChild)) {
+ parent = tChild;
+ prevSib = NULL;
+ }
+ pChild = pChild->firstChild;
+ continue;
+ }
+
+ while(!pChild->nextSib) {
+ pChild = pChild->parent;
+ if(pChild == pWin) return;
+ if(IN_UNDERLAY(pChild)) {
+ prevSib = tChild = MIOVERLAY_GET_WINDOW_TREE(pChild);
+ parent = tChild->parent;
+ }
+ }
+
+ pChild = pChild->nextSib;
+ }
+}
+
+
+static Bool
+HasUnderlayChildren(WindowPtr pWin)
+{
+ WindowPtr pChild;
+
+ if(!(pChild = pWin->firstChild))
+ return FALSE;
+
+ while(1) {
+ if(IN_UNDERLAY(pChild))
+ return TRUE;
+
+ if(pChild->firstChild) {
+ pChild = pChild->firstChild;
+ continue;
+ }
+
+ while(!pChild->nextSib && (pWin != pChild))
+ pChild = pChild->parent;
+
+ if(pChild == pWin) break;
+
+ pChild = pChild->nextSib;
+ }
+
+ return FALSE;
+}
+
+
+static Bool
+CollectUnderlayChildrenRegions(WindowPtr pWin, RegionPtr pReg)
+{
+ WindowPtr pChild;
+ miOverlayTreePtr pTree;
+ Bool hasUnderlay;
+
+ if(!(pChild = pWin->firstChild))
+ return FALSE;
+
+ hasUnderlay = FALSE;
+
+ while(1) {
+ if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild))) {
+ REGION_APPEND(pScreen, pReg, &pTree->borderClip);
+ hasUnderlay = TRUE;
+ } else
+ if(pChild->firstChild) {
+ pChild = pChild->firstChild;
+ continue;
+ }
+
+ while(!pChild->nextSib && (pWin != pChild))
+ pChild = pChild->parent;
+
+ if(pChild == pWin) break;
+
+ pChild = pChild->nextSib;
+ }
+
+ if(hasUnderlay) {
+ Bool overlap;
+ REGION_VALIDATE(pScreen, pReg, &overlap);
+ }
+
+ return hasUnderlay;
+}
+
+
+static void
+MarkUnderlayWindow(WindowPtr pWin)
+{
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+
+ if(pTree->valdata) return;
+ pTree->valdata = (miOverlayValDataPtr)xnfalloc(sizeof(miOverlayValDataRec));
+ pTree->valdata->oldAbsCorner.x = pWin->drawable.x;
+ pTree->valdata->oldAbsCorner.y = pWin->drawable.y;
+ pTree->valdata->borderVisible = NullRegion;
+}
diff --git a/xserver/mi/mioverlay.h b/xserver/mi/mioverlay.h
new file mode 100644
index 000000000..24b74f51c
--- /dev/null
+++ b/xserver/mi/mioverlay.h
@@ -0,0 +1,32 @@
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#ifndef __MIOVERLAY_H
+#define __MIOVERLAY_H
+
+typedef void (*miOverlayTransFunc)(ScreenPtr, int, BoxPtr);
+typedef Bool (*miOverlayInOverlayFunc)(WindowPtr);
+
+Bool
+miInitOverlay(
+ ScreenPtr pScreen,
+ miOverlayInOverlayFunc inOverlay,
+ miOverlayTransFunc trans
+);
+
+Bool
+miOverlayGetPrivateClips(
+ WindowPtr pWin,
+ RegionPtr *borderClip,
+ RegionPtr *clipList
+);
+
+Bool miOverlayCollectUnderlayRegions(WindowPtr, RegionPtr*);
+void miOverlayComputeCompositeClip(GCPtr, WindowPtr);
+Bool miOverlayCopyUnderlay(ScreenPtr);
+void miOverlaySetTransFunction(ScreenPtr, miOverlayTransFunc);
+void miOverlaySetRootClip(ScreenPtr, Bool);
+
+#endif /* __MIOVERLAY_H */
diff --git a/xserver/mi/mipointer.c b/xserver/mi/mipointer.c
new file mode 100644
index 000000000..1715965fa
--- /dev/null
+++ b/xserver/mi/mipointer.c
@@ -0,0 +1,529 @@
+/*
+ * mipointer.c
+ */
+
+
+/*
+
+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
+
+# define NEED_EVENTS
+# include <X11/X.h>
+# include <X11/Xmd.h>
+# include <X11/Xproto.h>
+# include "misc.h"
+# include "windowstr.h"
+# include "pixmapstr.h"
+# include "mi.h"
+# include "scrnintstr.h"
+# include "mipointrst.h"
+# include "cursorstr.h"
+# include "dixstruct.h"
+
+_X_EXPORT int miPointerScreenIndex;
+static unsigned long miPointerGeneration = 0;
+
+#define GetScreenPrivate(s) ((miPointerScreenPtr) ((s)->devPrivates[miPointerScreenIndex].ptr))
+#define SetupScreen(s) miPointerScreenPtr pScreenPriv = GetScreenPrivate(s)
+
+/*
+ * until more than one pointer device exists.
+ */
+
+static miPointerRec miPointer;
+
+static Bool miPointerRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor);
+static Bool miPointerUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor);
+static Bool miPointerDisplayCursor(ScreenPtr pScreen, CursorPtr pCursor);
+static void miPointerConstrainCursor(ScreenPtr pScreen, BoxPtr pBox);
+static void miPointerPointerNonInterestBox(ScreenPtr pScreen, BoxPtr pBox);
+static void miPointerCursorLimits(ScreenPtr pScreen, CursorPtr pCursor,
+ BoxPtr pHotBox, BoxPtr pTopLeftBox);
+static Bool miPointerSetCursorPosition(ScreenPtr pScreen, int x, int y,
+ Bool generateEvent);
+static Bool miPointerCloseScreen(int index, ScreenPtr pScreen);
+static void miPointerMove(ScreenPtr pScreen, int x, int y, unsigned long time);
+
+_X_EXPORT Bool
+miPointerInitialize (pScreen, spriteFuncs, screenFuncs, waitForUpdate)
+ ScreenPtr pScreen;
+ miPointerSpriteFuncPtr spriteFuncs;
+ miPointerScreenFuncPtr screenFuncs;
+ Bool waitForUpdate;
+{
+ miPointerScreenPtr pScreenPriv;
+
+ if (miPointerGeneration != serverGeneration)
+ {
+ miPointerScreenIndex = AllocateScreenPrivateIndex();
+ if (miPointerScreenIndex < 0)
+ return FALSE;
+ miPointerGeneration = serverGeneration;
+ }
+ pScreenPriv = (miPointerScreenPtr) xalloc (sizeof (miPointerScreenRec));
+ if (!pScreenPriv)
+ return FALSE;
+ pScreenPriv->spriteFuncs = spriteFuncs;
+ pScreenPriv->screenFuncs = screenFuncs;
+ /*
+ * check for uninitialized methods
+ */
+ if (!screenFuncs->EnqueueEvent)
+ screenFuncs->EnqueueEvent = mieqEnqueue;
+ if (!screenFuncs->NewEventScreen)
+ screenFuncs->NewEventScreen = mieqSwitchScreen;
+ pScreenPriv->waitForUpdate = waitForUpdate;
+ pScreenPriv->showTransparent = FALSE;
+ pScreenPriv->CloseScreen = pScreen->CloseScreen;
+ pScreen->CloseScreen = miPointerCloseScreen;
+ pScreen->devPrivates[miPointerScreenIndex].ptr = (pointer) pScreenPriv;
+ /*
+ * set up screen cursor method table
+ */
+ pScreen->ConstrainCursor = miPointerConstrainCursor;
+ pScreen->CursorLimits = miPointerCursorLimits;
+ pScreen->DisplayCursor = miPointerDisplayCursor;
+ pScreen->RealizeCursor = miPointerRealizeCursor;
+ pScreen->UnrealizeCursor = miPointerUnrealizeCursor;
+ pScreen->SetCursorPosition = miPointerSetCursorPosition;
+ pScreen->RecolorCursor = miRecolorCursor;
+ pScreen->PointerNonInterestBox = miPointerPointerNonInterestBox;
+ /*
+ * set up the pointer object
+ */
+ miPointer.pScreen = NULL;
+ miPointer.pSpriteScreen = NULL;
+ miPointer.pCursor = NULL;
+ miPointer.pSpriteCursor = NULL;
+ miPointer.limits.x1 = 0;
+ miPointer.limits.x2 = 32767;
+ miPointer.limits.y1 = 0;
+ miPointer.limits.y2 = 32767;
+ miPointer.confined = FALSE;
+ miPointer.x = 0;
+ miPointer.y = 0;
+ miPointer.history_start = miPointer.history_end = 0;
+ return TRUE;
+}
+
+static Bool
+miPointerCloseScreen (index, pScreen)
+ int index;
+ ScreenPtr pScreen;
+{
+ SetupScreen(pScreen);
+
+ if (pScreen == miPointer.pScreen)
+ miPointer.pScreen = 0;
+ if (pScreen == miPointer.pSpriteScreen)
+ miPointer.pSpriteScreen = 0;
+ pScreen->CloseScreen = pScreenPriv->CloseScreen;
+ xfree ((pointer) pScreenPriv);
+ return (*pScreen->CloseScreen) (index, pScreen);
+}
+
+/*
+ * DIX/DDX interface routines
+ */
+
+static Bool
+miPointerRealizeCursor (pScreen, pCursor)
+ ScreenPtr pScreen;
+ CursorPtr pCursor;
+{
+ SetupScreen(pScreen);
+
+ return (*pScreenPriv->spriteFuncs->RealizeCursor) (pScreen, pCursor);
+}
+
+static Bool
+miPointerUnrealizeCursor (pScreen, pCursor)
+ ScreenPtr pScreen;
+ CursorPtr pCursor;
+{
+ SetupScreen(pScreen);
+
+ return (*pScreenPriv->spriteFuncs->UnrealizeCursor) (pScreen, pCursor);
+}
+
+static Bool
+miPointerDisplayCursor (pScreen, pCursor)
+ ScreenPtr pScreen;
+ CursorPtr pCursor;
+{
+ miPointer.pCursor = pCursor;
+ miPointer.pScreen = pScreen;
+ miPointerUpdate ();
+ return TRUE;
+}
+
+static void
+miPointerConstrainCursor (pScreen, pBox)
+ ScreenPtr pScreen;
+ BoxPtr pBox;
+{
+ miPointer.limits = *pBox;
+ miPointer.confined = PointerConfinedToScreen();
+}
+
+/*ARGSUSED*/
+static void
+miPointerPointerNonInterestBox (pScreen, pBox)
+ ScreenPtr pScreen;
+ BoxPtr pBox;
+{
+ /* until DIX uses this, this will remain a stub */
+}
+
+/*ARGSUSED*/
+static void
+miPointerCursorLimits(pScreen, pCursor, pHotBox, pTopLeftBox)
+ ScreenPtr pScreen;
+ CursorPtr pCursor;
+ BoxPtr pHotBox;
+ BoxPtr pTopLeftBox;
+{
+ *pTopLeftBox = *pHotBox;
+}
+
+static Bool GenerateEvent;
+
+static Bool
+miPointerSetCursorPosition(pScreen, x, y, generateEvent)
+ ScreenPtr pScreen;
+ int x, y;
+ Bool generateEvent;
+{
+ SetupScreen (pScreen);
+
+ GenerateEvent = generateEvent;
+ /* device dependent - must pend signal and call miPointerWarpCursor */
+ (*pScreenPriv->screenFuncs->WarpCursor) (pScreen, x, y);
+ if (!generateEvent)
+ miPointerUpdate();
+ return TRUE;
+}
+
+/* Once signals are ignored, the WarpCursor function can call this */
+
+_X_EXPORT void
+miPointerWarpCursor (pScreen, x, y)
+ ScreenPtr pScreen;
+ int x, y;
+{
+ SetupScreen (pScreen);
+
+ if (miPointer.pScreen != pScreen)
+ (*pScreenPriv->screenFuncs->NewEventScreen) (pScreen, TRUE);
+
+ if (GenerateEvent)
+ {
+ miPointerMove (pScreen, x, y, GetTimeInMillis());
+ }
+ else
+ {
+ /* everything from miPointerMove except the event and history */
+
+ if (!pScreenPriv->waitForUpdate && pScreen == miPointer.pSpriteScreen)
+ {
+ miPointer.devx = x;
+ miPointer.devy = y;
+ if(!miPointer.pCursor->bits->emptyMask)
+ (*pScreenPriv->spriteFuncs->MoveCursor) (pScreen, x, y);
+ }
+ miPointer.x = x;
+ miPointer.y = y;
+ miPointer.pScreen = pScreen;
+ }
+}
+
+/*
+ * Pointer/CursorDisplay interface routines
+ */
+
+_X_EXPORT int
+miPointerGetMotionBufferSize ()
+{
+ return MOTION_SIZE;
+}
+
+_X_EXPORT int
+miPointerGetMotionEvents (pPtr, coords, start, stop, pScreen)
+ DeviceIntPtr pPtr;
+ xTimecoord *coords;
+ unsigned long start, stop;
+ ScreenPtr pScreen;
+{
+ int i;
+ int count = 0;
+ miHistoryPtr h;
+
+ for (i = miPointer.history_start; i != miPointer.history_end;)
+ {
+ h = &miPointer.history[i];
+ if (h->event.time >= stop)
+ break;
+ if (h->event.time >= start)
+ {
+ *coords++ = h->event;
+ count++;
+ }
+ if (++i == MOTION_SIZE) i = 0;
+ }
+ return count;
+}
+
+
+/*
+ * miPointerUpdate
+ *
+ * Syncronize the sprite with the cursor - called from ProcessInputEvents
+ */
+
+void
+miPointerUpdate ()
+{
+ ScreenPtr pScreen;
+ miPointerScreenPtr pScreenPriv;
+ CursorPtr pCursor;
+ int x, y, devx, devy;
+
+ pScreen = miPointer.pScreen;
+ x = miPointer.x;
+ y = miPointer.y;
+ devx = miPointer.devx;
+ devy = miPointer.devy;
+ if (!pScreen)
+ return;
+ pScreenPriv = GetScreenPrivate (pScreen);
+ /*
+ * if the cursor has switched screens, disable the sprite
+ * on the old screen
+ */
+ if (pScreen != miPointer.pSpriteScreen)
+ {
+ if (miPointer.pSpriteScreen)
+ {
+ miPointerScreenPtr pOldPriv;
+
+ pOldPriv = GetScreenPrivate (miPointer.pSpriteScreen);
+ if (miPointer.pCursor)
+ {
+ (*pOldPriv->spriteFuncs->SetCursor)
+ (miPointer.pSpriteScreen, NullCursor, 0, 0);
+ }
+ (*pOldPriv->screenFuncs->CrossScreen) (miPointer.pSpriteScreen, FALSE);
+ }
+ (*pScreenPriv->screenFuncs->CrossScreen) (pScreen, TRUE);
+ (*pScreenPriv->spriteFuncs->SetCursor)
+ (pScreen, miPointer.pCursor, x, y);
+ miPointer.devx = x;
+ miPointer.devy = y;
+ miPointer.pSpriteCursor = miPointer.pCursor;
+ miPointer.pSpriteScreen = pScreen;
+ }
+ /*
+ * if the cursor has changed, display the new one
+ */
+ else if (miPointer.pCursor != miPointer.pSpriteCursor)
+ {
+ pCursor = miPointer.pCursor;
+ if (pCursor->bits->emptyMask && !pScreenPriv->showTransparent)
+ pCursor = NullCursor;
+ (*pScreenPriv->spriteFuncs->SetCursor) (pScreen, pCursor, x, y);
+
+ miPointer.devx = x;
+ miPointer.devy = y;
+ miPointer.pSpriteCursor = miPointer.pCursor;
+ }
+ else if (x != devx || y != devy)
+ {
+ miPointer.devx = x;
+ miPointer.devy = y;
+ if(!miPointer.pCursor->bits->emptyMask)
+ (*pScreenPriv->spriteFuncs->MoveCursor) (pScreen, x, y);
+ }
+}
+
+/*
+ * miPointerDeltaCursor. The pointer has moved dx,dy from it's previous
+ * position.
+ */
+
+void
+miPointerDeltaCursor (dx, dy, time)
+ int dx, dy;
+ unsigned long time;
+{
+ miPointerAbsoluteCursor (miPointer.x + dx, miPointer.y + dy, time);
+}
+
+void
+miPointerSetNewScreen(int screen_no, int x, int y)
+{
+ miPointerScreenPtr pScreenPriv;
+ ScreenPtr pScreen;
+
+ pScreen = screenInfo.screens[screen_no];
+ pScreenPriv = GetScreenPrivate (pScreen);
+ (*pScreenPriv->screenFuncs->NewEventScreen) (pScreen, FALSE);
+ NewCurrentScreen (pScreen, x, y);
+ miPointer.limits.x2 = pScreen->width;
+ miPointer.limits.y2 = pScreen->height;
+}
+
+_X_EXPORT ScreenPtr
+miPointerCurrentScreen ()
+{
+ return (miPointer.pScreen);
+}
+
+/*
+ * miPointerAbsoluteCursor. The pointer has moved to x,y
+ */
+
+_X_EXPORT void
+miPointerAbsoluteCursor (x, y, time)
+ int x, y;
+ unsigned long time;
+{
+ miPointerScreenPtr pScreenPriv;
+ ScreenPtr pScreen;
+ ScreenPtr newScreen;
+
+ pScreen = miPointer.pScreen;
+ if (!pScreen)
+ return; /* called before ready */
+ if (x < 0 || x >= pScreen->width || y < 0 || y >= pScreen->height)
+ {
+ pScreenPriv = GetScreenPrivate (pScreen);
+ if (!miPointer.confined)
+ {
+ newScreen = pScreen;
+ (*pScreenPriv->screenFuncs->CursorOffScreen) (&newScreen, &x, &y);
+ if (newScreen != pScreen)
+ {
+ pScreen = newScreen;
+ (*pScreenPriv->screenFuncs->NewEventScreen) (pScreen, FALSE);
+ pScreenPriv = GetScreenPrivate (pScreen);
+ /* Smash the confine to the new screen */
+ miPointer.limits.x2 = pScreen->width;
+ miPointer.limits.y2 = pScreen->height;
+ }
+ }
+ }
+ /*
+ * constrain the hot-spot to the current
+ * limits
+ */
+ if (x < miPointer.limits.x1)
+ x = miPointer.limits.x1;
+ if (x >= miPointer.limits.x2)
+ x = miPointer.limits.x2 - 1;
+ if (y < miPointer.limits.y1)
+ y = miPointer.limits.y1;
+ if (y >= miPointer.limits.y2)
+ y = miPointer.limits.y2 - 1;
+ if (miPointer.x == x && miPointer.y == y && miPointer.pScreen == pScreen)
+ return;
+ miPointerMove (pScreen, x, y, time);
+}
+
+_X_EXPORT void
+miPointerPosition (x, y)
+ int *x, *y;
+{
+ *x = miPointer.x;
+ *y = miPointer.y;
+}
+
+/*
+ * miPointerMove. The pointer has moved to x,y on current screen
+ */
+
+static void
+miPointerMove (pScreen, x, y, time)
+ ScreenPtr pScreen;
+ int x, y;
+ unsigned long time;
+{
+ SetupScreen(pScreen);
+ xEvent xE;
+ miHistoryPtr history;
+ int prev, end, start;
+
+ if (!pScreenPriv->waitForUpdate && pScreen == miPointer.pSpriteScreen)
+ {
+ miPointer.devx = x;
+ miPointer.devy = y;
+ if(!miPointer.pCursor->bits->emptyMask)
+ (*pScreenPriv->spriteFuncs->MoveCursor) (pScreen, x, y);
+ }
+ miPointer.x = x;
+ miPointer.y = y;
+ miPointer.pScreen = pScreen;
+
+ xE.u.u.type = MotionNotify;
+ xE.u.keyButtonPointer.rootX = x;
+ xE.u.keyButtonPointer.rootY = y;
+ xE.u.keyButtonPointer.time = time;
+ (*pScreenPriv->screenFuncs->EnqueueEvent) (&xE);
+
+ end = miPointer.history_end;
+ start = miPointer.history_start;
+ prev = end - 1;
+ if (end == 0)
+ prev = MOTION_SIZE - 1;
+ history = &miPointer.history[prev];
+ if (end == start || history->event.time != time)
+ {
+ history = &miPointer.history[end];
+ if (++end == MOTION_SIZE)
+ end = 0;
+ if (end == start)
+ {
+ start = end + 1;
+ if (start == MOTION_SIZE)
+ start = 0;
+ miPointer.history_start = start;
+ }
+ miPointer.history_end = end;
+ }
+ history->event.x = x;
+ history->event.y = y;
+ history->event.time = time;
+ history->pScreen = pScreen;
+}
+
+void
+miRegisterPointerDevice (pScreen, pDevice)
+ ScreenPtr pScreen;
+ DeviceIntPtr pDevice;
+{
+ miPointer.pPointer = (DevicePtr)pDevice;
+}
diff --git a/xserver/mi/mipointer.h b/xserver/mi/mipointer.h
new file mode 100644
index 000000000..aae38377c
--- /dev/null
+++ b/xserver/mi/mipointer.h
@@ -0,0 +1,151 @@
+/*
+ * mipointer.h
+ *
+ */
+
+
+/*
+
+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.
+*/
+
+#ifndef MIPOINTER_H
+#define MIPOINTER_H
+
+#include "cursor.h"
+#include "input.h"
+
+typedef struct _miPointerSpriteFuncRec {
+ Bool (*RealizeCursor)(
+ ScreenPtr /* pScr */,
+ CursorPtr /* pCurs */
+ );
+ Bool (*UnrealizeCursor)(
+ ScreenPtr /* pScr */,
+ CursorPtr /* pCurs */
+ );
+ void (*SetCursor)(
+ ScreenPtr /* pScr */,
+ CursorPtr /* pCurs */,
+ int /* x */,
+ int /* y */
+ );
+ void (*MoveCursor)(
+ ScreenPtr /* pScr */,
+ int /* x */,
+ int /* y */
+ );
+} miPointerSpriteFuncRec, *miPointerSpriteFuncPtr;
+
+typedef struct _miPointerScreenFuncRec {
+ Bool (*CursorOffScreen)(
+ ScreenPtr* /* ppScr */,
+ int* /* px */,
+ int* /* py */
+ );
+ void (*CrossScreen)(
+ ScreenPtr /* pScr */,
+ int /* entering */
+ );
+ void (*WarpCursor)(
+ ScreenPtr /* pScr */,
+ int /* x */,
+ int /* y */
+ );
+ void (*EnqueueEvent)(
+ xEventPtr /* event */
+ );
+ void (*NewEventScreen)(
+ ScreenPtr /* pScr */,
+ Bool /* fromDIX */
+ );
+} miPointerScreenFuncRec, *miPointerScreenFuncPtr;
+
+extern Bool miDCInitialize(
+ ScreenPtr /*pScreen*/,
+ miPointerScreenFuncPtr /*screenFuncs*/
+);
+
+extern Bool miPointerInitialize(
+ ScreenPtr /*pScreen*/,
+ miPointerSpriteFuncPtr /*spriteFuncs*/,
+ miPointerScreenFuncPtr /*screenFuncs*/,
+ Bool /*waitForUpdate*/
+);
+
+extern void miPointerWarpCursor(
+ ScreenPtr /*pScreen*/,
+ int /*x*/,
+ int /*y*/
+);
+
+extern int miPointerGetMotionBufferSize(
+ void
+);
+
+extern int miPointerGetMotionEvents(
+ DeviceIntPtr /*pPtr*/,
+ xTimecoord * /*coords*/,
+ unsigned long /*start*/,
+ unsigned long /*stop*/,
+ ScreenPtr /*pScreen*/
+);
+
+extern void miPointerUpdate(
+ void
+);
+
+extern void miPointerDeltaCursor(
+ int /*dx*/,
+ int /*dy*/,
+ unsigned long /*time*/
+);
+
+extern void miPointerAbsoluteCursor(
+ int /*x*/,
+ int /*y*/,
+ unsigned long /*time*/
+);
+
+extern void miPointerPosition(
+ int * /*x*/,
+ int * /*y*/
+);
+
+extern void miPointerSetNewScreen(
+ int, /*screen_no*/
+ int, /*x*/
+ int /*y*/
+);
+extern ScreenPtr miPointerCurrentScreen(
+ void
+);
+
+extern void miRegisterPointerDevice(
+ ScreenPtr /*pScreen*/,
+ DeviceIntPtr /*pDevice*/
+);
+
+extern int miPointerScreenIndex;
+
+#endif /* MIPOINTER_H */
diff --git a/xserver/mi/mipointrst.h b/xserver/mi/mipointrst.h
new file mode 100644
index 000000000..f1fbfe4f9
--- /dev/null
+++ b/xserver/mi/mipointrst.h
@@ -0,0 +1,62 @@
+/*
+ * mipointrst.h
+ *
+ */
+
+
+/*
+
+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.
+*/
+
+#include "mipointer.h"
+#include "scrnintstr.h"
+
+#define MOTION_SIZE 256
+
+typedef struct {
+ xTimecoord event;
+ ScreenPtr pScreen;
+} miHistoryRec, *miHistoryPtr;
+
+typedef struct {
+ ScreenPtr pScreen; /* current screen */
+ ScreenPtr pSpriteScreen;/* screen containing current sprite */
+ CursorPtr pCursor; /* current cursor */
+ CursorPtr pSpriteCursor;/* cursor on screen */
+ BoxRec limits; /* current constraints */
+ Bool confined; /* pointer can't change screens */
+ int x, y; /* hot spot location */
+ int devx, devy; /* sprite position */
+ DevicePtr pPointer; /* pointer device structure */
+ miHistoryRec history[MOTION_SIZE];
+ int history_start, history_end;
+} miPointerRec, *miPointerPtr;
+
+typedef struct {
+ miPointerSpriteFuncPtr spriteFuncs; /* sprite-specific methods */
+ miPointerScreenFuncPtr screenFuncs; /* screen-specific methods */
+ CloseScreenProcPtr CloseScreen;
+ Bool waitForUpdate; /* don't move cursor in SIGIO */
+ Bool showTransparent; /* show empty cursors */
+} miPointerScreenRec, *miPointerScreenPtr;
diff --git a/xserver/mi/mipoly.c b/xserver/mi/mipoly.c
new file mode 100644
index 000000000..b514b5ed2
--- /dev/null
+++ b/xserver/mi/mipoly.c
@@ -0,0 +1,128 @@
+/* $XFree86$ */
+/***********************************************************
+
+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.
+
+******************************************************************/
+/*
+ * mipoly.c
+ *
+ * Written by Brian Kelleher; June 1986
+ *
+ * Draw polygons. This routine translates the point by the
+ * origin if pGC->miTranslate is non-zero, and calls
+ * to the appropriate routine to actually scan convert the
+ * polygon.
+ */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include "windowstr.h"
+#include "gcstruct.h"
+#include "pixmapstr.h"
+#include "mi.h"
+#include "regionstr.h"
+
+
+_X_EXPORT void
+miFillPolygon(dst, pgc, shape, mode, count, pPts)
+ DrawablePtr dst;
+ register GCPtr pgc;
+ int shape, mode;
+ register int count;
+ DDXPointPtr pPts;
+{
+ int i;
+ register int xorg, yorg;
+ register DDXPointPtr ppt;
+
+ if (count == 0)
+ return;
+
+ ppt = pPts;
+ if (pgc->miTranslate)
+ {
+ xorg = dst->x;
+ yorg = dst->y;
+
+ if (mode == CoordModeOrigin)
+ {
+ for (i = 0; i<count; i++)
+ {
+ ppt->x += xorg;
+ ppt++->y += yorg;
+ }
+ }
+ else
+ {
+ ppt->x += xorg;
+ ppt++->y += yorg;
+ for (i = 1; i<count; i++)
+ {
+ ppt->x += (ppt-1)->x;
+ ppt->y += (ppt-1)->y;
+ ppt++;
+ }
+ }
+ }
+ else
+ {
+ if (mode == CoordModePrevious)
+ {
+ ppt++;
+ for (i = 1; i<count; i++)
+ {
+ ppt->x += (ppt-1)->x;
+ ppt->y += (ppt-1)->y;
+ ppt++;
+ }
+ }
+ }
+ if (shape == Convex)
+ miFillConvexPoly(dst, pgc, count, pPts);
+ else
+ miFillGeneralPoly(dst, pgc, count, pPts);
+}
diff --git a/xserver/mi/mipoly.h b/xserver/mi/mipoly.h
new file mode 100644
index 000000000..8e04f6737
--- /dev/null
+++ b/xserver/mi/mipoly.h
@@ -0,0 +1,215 @@
+/*
+
+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.
+
+*/
+
+
+/*
+ * fill.h
+ *
+ * Created by Brian Kelleher; Oct 1985
+ *
+ * Include file for filled polygon routines.
+ *
+ * These are the data structures needed to scan
+ * convert regions. Two different scan conversion
+ * methods are available -- the even-odd method, and
+ * the winding number method.
+ * The even-odd rule states that a point is inside
+ * the polygon if a ray drawn from that point in any
+ * direction will pass through an odd number of
+ * path segments.
+ * By the winding number rule, a point is decided
+ * to be inside the polygon if a ray drawn from that
+ * point in any direction passes through a different
+ * number of clockwise and counter-clockwise path
+ * segments.
+ *
+ * These data structures are adapted somewhat from
+ * the algorithm in (Foley/Van Dam) for scan converting
+ * polygons.
+ * The basic algorithm is to start at the top (smallest y)
+ * of the polygon, stepping down to the bottom of
+ * the polygon by incrementing the y coordinate. We
+ * keep a list of edges which the current scanline crosses,
+ * sorted by x. This list is called the Active Edge Table (AET)
+ * As we change the y-coordinate, we update each entry in
+ * in the active edge table to reflect the edges new xcoord.
+ * This list must be sorted at each scanline in case
+ * two edges intersect.
+ * We also keep a data structure known as the Edge Table (ET),
+ * which keeps track of all the edges which the current
+ * scanline has not yet reached. The ET is basically a
+ * list of ScanLineList structures containing a list of
+ * edges which are entered at a given scanline. There is one
+ * ScanLineList per scanline at which an edge is entered.
+ * When we enter a new edge, we move it from the ET to the AET.
+ *
+ * From the AET, we can implement the even-odd rule as in
+ * (Foley/Van Dam).
+ * The winding number rule is a little trickier. We also
+ * keep the EdgeTableEntries in the AET linked by the
+ * nextWETE (winding EdgeTableEntry) link. This allows
+ * the edges to be linked just as before for updating
+ * purposes, but only uses the edges linked by the nextWETE
+ * link as edges representing spans of the polygon to
+ * drawn (as with the even-odd rule).
+ */
+
+/*
+ * for the winding number rule
+ */
+#define CLOCKWISE 1
+#define COUNTERCLOCKWISE -1
+
+typedef struct _EdgeTableEntry {
+ int ymax; /* ycoord at which we exit this edge. */
+ BRESINFO bres; /* Bresenham info to run the edge */
+ struct _EdgeTableEntry *next; /* next in the list */
+ struct _EdgeTableEntry *back; /* for insertion sort */
+ struct _EdgeTableEntry *nextWETE; /* for winding num rule */
+ int ClockWise; /* flag for winding number rule */
+} EdgeTableEntry;
+
+
+typedef struct _ScanLineList{
+ int scanline; /* the scanline represented */
+ EdgeTableEntry *edgelist; /* header node */
+ struct _ScanLineList *next; /* next in the list */
+} ScanLineList;
+
+
+typedef struct {
+ int ymax; /* ymax for the polygon */
+ int ymin; /* ymin for the polygon */
+ ScanLineList scanlines; /* header node */
+} EdgeTable;
+
+
+/*
+ * Here is a struct to help with storage allocation
+ * so we can allocate a big chunk at a time, and then take
+ * pieces from this heap when we need to.
+ */
+#define SLLSPERBLOCK 25
+
+typedef struct _ScanLineListBlock {
+ ScanLineList SLLs[SLLSPERBLOCK];
+ struct _ScanLineListBlock *next;
+} ScanLineListBlock;
+
+/*
+ * number of points to buffer before sending them off
+ * to scanlines() : Must be an even number
+ */
+#define NUMPTSTOBUFFER 200
+
+
+/*
+ *
+ * a few macros for the inner loops of the fill code where
+ * performance considerations don't allow a procedure call.
+ *
+ * Evaluate the given edge at the given scanline.
+ * If the edge has expired, then we leave it and fix up
+ * the active edge table; otherwise, we increment the
+ * x value to be ready for the next scanline.
+ * The winding number rule is in effect, so we must notify
+ * the caller when the edge has been removed so he
+ * can reorder the Winding Active Edge Table.
+ */
+#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
+ if (pAET->ymax == y) { /* leaving this edge */ \
+ pPrevAET->next = pAET->next; \
+ pAET = pPrevAET->next; \
+ fixWAET = 1; \
+ if (pAET) \
+ pAET->back = pPrevAET; \
+ } \
+ else { \
+ BRESINCRPGONSTRUCT(pAET->bres); \
+ pPrevAET = pAET; \
+ pAET = pAET->next; \
+ } \
+}
+
+
+/*
+ * Evaluate the given edge at the given scanline.
+ * If the edge has expired, then we leave it and fix up
+ * the active edge table; otherwise, we increment the
+ * x value to be ready for the next scanline.
+ * The even-odd rule is in effect.
+ */
+#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
+ if (pAET->ymax == y) { /* leaving this edge */ \
+ pPrevAET->next = pAET->next; \
+ pAET = pPrevAET->next; \
+ if (pAET) \
+ pAET->back = pPrevAET; \
+ } \
+ else { \
+ BRESINCRPGONSTRUCT(pAET->bres); \
+ pPrevAET = pAET; \
+ pAET = pAET->next; \
+ } \
+}
+
+/* mipolyutil.c */
+
+extern Bool miInsertEdgeInET(
+ EdgeTable * /*ET*/,
+ EdgeTableEntry * /*ETE*/,
+ int /*scanline*/,
+ ScanLineListBlock ** /*SLLBlock*/,
+ int * /*iSLLBlock*/
+);
+
+extern Bool miCreateETandAET(
+ int /*count*/,
+ DDXPointPtr /*pts*/,
+ EdgeTable * /*ET*/,
+ EdgeTableEntry * /*AET*/,
+ EdgeTableEntry * /*pETEs*/,
+ ScanLineListBlock * /*pSLLBlock*/
+);
+
+extern void miloadAET(
+ EdgeTableEntry * /*AET*/,
+ EdgeTableEntry * /*ETEs*/
+);
+
+extern void micomputeWAET(
+ EdgeTableEntry * /*AET*/
+);
+
+extern int miInsertionSort(
+ EdgeTableEntry * /*AET*/
+);
+
+extern void miFreeStorage(
+ ScanLineListBlock * /*pSLLBlock*/
+);
diff --git a/xserver/mi/mipolycon.c b/xserver/mi/mipolycon.c
new file mode 100644
index 000000000..b5ab89364
--- /dev/null
+++ b/xserver/mi/mipolycon.c
@@ -0,0 +1,246 @@
+/***********************************************************
+
+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 "gcstruct.h"
+#include "pixmap.h"
+#include "mi.h"
+#include "miscanfill.h"
+
+static int getPolyYBounds(DDXPointPtr pts, int n, int *by, int *ty);
+
+/*
+ * convexpoly.c
+ *
+ * Written by Brian Kelleher; Dec. 1985.
+ *
+ * Fill a convex polygon. If the given polygon
+ * is not convex, then the result is undefined.
+ * The algorithm is to order the edges from smallest
+ * y to largest by partitioning the array into a left
+ * edge list and a right edge list. The algorithm used
+ * to traverse each edge is an extension of Bresenham's
+ * line algorithm with y as the major axis.
+ * For a derivation of the algorithm, see the author of
+ * this code.
+ */
+_X_EXPORT Bool
+miFillConvexPoly(dst, pgc, count, ptsIn)
+ DrawablePtr dst;
+ GCPtr pgc;
+ int count; /* number of points */
+ DDXPointPtr ptsIn; /* the points */
+{
+ register int xl = 0, xr = 0; /* x vals of left and right edges */
+ register int dl = 0, dr = 0; /* decision variables */
+ register int ml = 0, m1l = 0;/* left edge slope and slope+1 */
+ int mr = 0, m1r = 0; /* right edge slope and slope+1 */
+ int incr1l = 0, incr2l = 0; /* left edge error increments */
+ int incr1r = 0, incr2r = 0; /* right edge error increments */
+ int dy; /* delta y */
+ int y; /* current scanline */
+ int left, right; /* indices to first endpoints */
+ int i; /* loop counter */
+ int nextleft, nextright; /* indices to second endpoints */
+ DDXPointPtr ptsOut, FirstPoint; /* output buffer */
+ int *width, *FirstWidth; /* output buffer */
+ int imin; /* index of smallest vertex (in y) */
+ int ymin; /* y-extents of polygon */
+ int ymax;
+
+ /*
+ * find leftx, bottomy, rightx, topy, and the index
+ * of bottomy. Also translate the points.
+ */
+ imin = getPolyYBounds(ptsIn, count, &ymin, &ymax);
+
+ dy = ymax - ymin + 1;
+ if ((count < 3) || (dy < 0))
+ return(TRUE);
+ ptsOut = FirstPoint = (DDXPointPtr )ALLOCATE_LOCAL(sizeof(DDXPointRec)*dy);
+ width = FirstWidth = (int *)ALLOCATE_LOCAL(sizeof(int) * dy);
+ if(!FirstPoint || !FirstWidth)
+ {
+ if (FirstWidth) DEALLOCATE_LOCAL(FirstWidth);
+ if (FirstPoint) DEALLOCATE_LOCAL(FirstPoint);
+ return(FALSE);
+ }
+
+ nextleft = nextright = imin;
+ y = ptsIn[nextleft].y;
+
+ /*
+ * loop through all edges of the polygon
+ */
+ do {
+ /*
+ * add a left edge if we need to
+ */
+ if (ptsIn[nextleft].y == y) {
+ left = nextleft;
+
+ /*
+ * find the next edge, considering the end
+ * conditions of the array.
+ */
+ nextleft++;
+ if (nextleft >= count)
+ nextleft = 0;
+
+ /*
+ * now compute all of the random information
+ * needed to run the iterative algorithm.
+ */
+ BRESINITPGON(ptsIn[nextleft].y-ptsIn[left].y,
+ ptsIn[left].x,ptsIn[nextleft].x,
+ xl, dl, ml, m1l, incr1l, incr2l);
+ }
+
+ /*
+ * add a right edge if we need to
+ */
+ if (ptsIn[nextright].y == y) {
+ right = nextright;
+
+ /*
+ * find the next edge, considering the end
+ * conditions of the array.
+ */
+ nextright--;
+ if (nextright < 0)
+ nextright = count-1;
+
+ /*
+ * now compute all of the random information
+ * needed to run the iterative algorithm.
+ */
+ BRESINITPGON(ptsIn[nextright].y-ptsIn[right].y,
+ ptsIn[right].x,ptsIn[nextright].x,
+ xr, dr, mr, m1r, incr1r, incr2r);
+ }
+
+ /*
+ * generate scans to fill while we still have
+ * a right edge as well as a left edge.
+ */
+ i = min(ptsIn[nextleft].y, ptsIn[nextright].y) - y;
+ /* in case we're called with non-convex polygon */
+ if(i < 0)
+ {
+ DEALLOCATE_LOCAL(FirstWidth);
+ DEALLOCATE_LOCAL(FirstPoint);
+ return(TRUE);
+ }
+ while (i-- > 0)
+ {
+ ptsOut->y = y;
+
+ /*
+ * reverse the edges if necessary
+ */
+ if (xl < xr)
+ {
+ *(width++) = xr - xl;
+ (ptsOut++)->x = xl;
+ }
+ else
+ {
+ *(width++) = xl - xr;
+ (ptsOut++)->x = xr;
+ }
+ y++;
+
+ /* increment down the edges */
+ BRESINCRPGON(dl, xl, ml, m1l, incr1l, incr2l);
+ BRESINCRPGON(dr, xr, mr, m1r, incr1r, incr2r);
+ }
+ } while (y != ymax);
+
+ /*
+ * Finally, fill the <remaining> spans
+ */
+ (*pgc->ops->FillSpans)(dst, pgc,
+ ptsOut-FirstPoint,FirstPoint,FirstWidth,
+ 1);
+ DEALLOCATE_LOCAL(FirstWidth);
+ DEALLOCATE_LOCAL(FirstPoint);
+ return(TRUE);
+}
+
+
+/*
+ * Find the index of the point with the smallest y.
+ */
+static int
+getPolyYBounds(DDXPointPtr pts, int n, int *by, int *ty)
+{
+ register DDXPointPtr ptMin;
+ int ymin, ymax;
+ DDXPointPtr ptsStart = pts;
+
+ ptMin = pts;
+ ymin = ymax = (pts++)->y;
+
+ while (--n > 0) {
+ if (pts->y < ymin)
+ {
+ ptMin = pts;
+ ymin = pts->y;
+ }
+ if(pts->y > ymax)
+ ymax = pts->y;
+
+ pts++;
+ }
+
+ *by = ymin;
+ *ty = ymax;
+ return(ptMin-ptsStart);
+}
diff --git a/xserver/mi/mipolygen.c b/xserver/mi/mipolygen.c
new file mode 100644
index 000000000..34da21f9e
--- /dev/null
+++ b/xserver/mi/mipolygen.c
@@ -0,0 +1,230 @@
+/***********************************************************
+
+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 "gcstruct.h"
+#include "miscanfill.h"
+#include "mipoly.h"
+#include "pixmap.h"
+#include "mi.h"
+
+/*
+ *
+ * Written by Brian Kelleher; Oct. 1985
+ *
+ * Routine to fill a polygon. Two fill rules are
+ * supported: frWINDING and frEVENODD.
+ *
+ * See fillpoly.h for a complete description of the algorithm.
+ */
+
+Bool
+miFillGeneralPoly(dst, pgc, count, ptsIn)
+ DrawablePtr dst;
+ GCPtr pgc;
+ int count; /* number of points */
+ DDXPointPtr ptsIn; /* the points */
+{
+ register EdgeTableEntry *pAET; /* the Active Edge Table */
+ register int y; /* the current scanline */
+ register int nPts = 0; /* number of pts in buffer */
+ register EdgeTableEntry *pWETE; /* Winding Edge Table */
+ register ScanLineList *pSLL; /* Current ScanLineList */
+ register DDXPointPtr ptsOut; /* ptr to output buffers */
+ int *width;
+ DDXPointRec FirstPoint[NUMPTSTOBUFFER]; /* the output buffers */
+ int FirstWidth[NUMPTSTOBUFFER];
+ EdgeTableEntry *pPrevAET; /* previous AET entry */
+ EdgeTable ET; /* Edge Table header node */
+ EdgeTableEntry AET; /* Active ET header node */
+ EdgeTableEntry *pETEs; /* Edge Table Entries buff */
+ ScanLineListBlock SLLBlock; /* header for ScanLineList */
+ int fixWAET = 0;
+
+ if (count < 3)
+ return(TRUE);
+
+ if(!(pETEs = (EdgeTableEntry *)
+ ALLOCATE_LOCAL(sizeof(EdgeTableEntry) * count)))
+ return(FALSE);
+ ptsOut = FirstPoint;
+ width = FirstWidth;
+ if (!miCreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock))
+ {
+ DEALLOCATE_LOCAL(pETEs);
+ return(FALSE);
+ }
+ pSLL = ET.scanlines.next;
+
+ if (pgc->fillRule == EvenOddRule)
+ {
+ /*
+ * for each scanline
+ */
+ for (y = ET.ymin; y < ET.ymax; y++)
+ {
+ /*
+ * Add a new edge to the active edge table when we
+ * get to the next edge.
+ */
+ if (pSLL && y == pSLL->scanline)
+ {
+ miloadAET(&AET, pSLL->edgelist);
+ pSLL = pSLL->next;
+ }
+ pPrevAET = &AET;
+ pAET = AET.next;
+
+ /*
+ * for each active edge
+ */
+ while (pAET)
+ {
+ ptsOut->x = pAET->bres.minor;
+ ptsOut++->y = y;
+ *width++ = pAET->next->bres.minor - pAET->bres.minor;
+ nPts++;
+
+ /*
+ * send out the buffer when its full
+ */
+ if (nPts == NUMPTSTOBUFFER)
+ {
+ (*pgc->ops->FillSpans)(dst, pgc,
+ nPts, FirstPoint, FirstWidth,
+ 1);
+ ptsOut = FirstPoint;
+ width = FirstWidth;
+ nPts = 0;
+ }
+ EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
+ EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
+ }
+ miInsertionSort(&AET);
+ }
+ }
+ else /* default to WindingNumber */
+ {
+ /*
+ * for each scanline
+ */
+ for (y = ET.ymin; y < ET.ymax; y++)
+ {
+ /*
+ * Add a new edge to the active edge table when we
+ * get to the next edge.
+ */
+ if (pSLL && y == pSLL->scanline)
+ {
+ miloadAET(&AET, pSLL->edgelist);
+ micomputeWAET(&AET);
+ pSLL = pSLL->next;
+ }
+ pPrevAET = &AET;
+ pAET = AET.next;
+ pWETE = pAET;
+
+ /*
+ * for each active edge
+ */
+ while (pAET)
+ {
+ /*
+ * if the next edge in the active edge table is
+ * also the next edge in the winding active edge
+ * table.
+ */
+ if (pWETE == pAET)
+ {
+ ptsOut->x = pAET->bres.minor;
+ ptsOut++->y = y;
+ *width++ = pAET->nextWETE->bres.minor - pAET->bres.minor;
+ nPts++;
+
+ /*
+ * send out the buffer
+ */
+ if (nPts == NUMPTSTOBUFFER)
+ {
+ (*pgc->ops->FillSpans)(dst, pgc, nPts, FirstPoint,
+ FirstWidth, 1);
+ ptsOut = FirstPoint;
+ width = FirstWidth;
+ nPts = 0;
+ }
+
+ pWETE = pWETE->nextWETE;
+ while (pWETE != pAET)
+ EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
+ pWETE = pWETE->nextWETE;
+ }
+ EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
+ }
+
+ /*
+ * reevaluate the Winding active edge table if we
+ * just had to resort it or if we just exited an edge.
+ */
+ if (miInsertionSort(&AET) || fixWAET)
+ {
+ micomputeWAET(&AET);
+ fixWAET = 0;
+ }
+ }
+ }
+
+ /*
+ * Get any spans that we missed by buffering
+ */
+ (*pgc->ops->FillSpans)(dst, pgc, nPts, FirstPoint, FirstWidth, 1);
+ DEALLOCATE_LOCAL(pETEs);
+ miFreeStorage(SLLBlock.next);
+ return(TRUE);
+}
diff --git a/xserver/mi/mipolypnt.c b/xserver/mi/mipolypnt.c
new file mode 100644
index 000000000..245bda317
--- /dev/null
+++ b/xserver/mi/mipolypnt.c
@@ -0,0 +1,123 @@
+/***********************************************************
+
+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/Xprotostr.h>
+#include "pixmapstr.h"
+#include "gcstruct.h"
+#include "windowstr.h"
+#include "mi.h"
+
+_X_EXPORT void
+miPolyPoint(pDrawable, pGC, mode, npt, pptInit)
+ DrawablePtr pDrawable;
+ GCPtr pGC;
+ int mode; /* Origin or Previous */
+ int npt;
+ xPoint *pptInit;
+{
+
+ int xorg;
+ int yorg;
+ int nptTmp;
+ XID fsOld, fsNew;
+ int *pwidthInit, *pwidth;
+ int i;
+ register xPoint *ppt;
+
+ /* make pointlist origin relative */
+ if (mode == CoordModePrevious)
+ {
+ ppt = pptInit;
+ nptTmp = npt;
+ nptTmp--;
+ while(nptTmp--)
+ {
+ ppt++;
+ ppt->x += (ppt-1)->x;
+ ppt->y += (ppt-1)->y;
+ }
+ }
+
+ if(pGC->miTranslate)
+ {
+ ppt = pptInit;
+ nptTmp = npt;
+ xorg = pDrawable->x;
+ yorg = pDrawable->y;
+ while(nptTmp--)
+ {
+ ppt->x += xorg;
+ ppt++->y += yorg;
+ }
+ }
+
+ fsOld = pGC->fillStyle;
+ fsNew = FillSolid;
+ if(pGC->fillStyle != FillSolid)
+ {
+ DoChangeGC(pGC, GCFillStyle, &fsNew, 0);
+ ValidateGC(pDrawable, pGC);
+ }
+ if(!(pwidthInit = (int *)ALLOCATE_LOCAL(npt * sizeof(int))))
+ return;
+ pwidth = pwidthInit;
+ for(i = 0; i < npt; i++)
+ *pwidth++ = 1;
+ (*pGC->ops->FillSpans)(pDrawable, pGC, npt, pptInit, pwidthInit, FALSE);
+
+ if(fsOld != FillSolid)
+ {
+ DoChangeGC(pGC, GCFillStyle, &fsOld, 0);
+ ValidateGC(pDrawable, pGC);
+ }
+ DEALLOCATE_LOCAL(pwidthInit);
+}
+
diff --git a/xserver/mi/mipolyrect.c b/xserver/mi/mipolyrect.c
new file mode 100644
index 000000000..a9ab90928
--- /dev/null
+++ b/xserver/mi/mipolyrect.c
@@ -0,0 +1,191 @@
+/***********************************************************
+
+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/Xprotostr.h>
+#include "regionstr.h"
+#include "gcstruct.h"
+#include "pixmap.h"
+#include "mi.h"
+
+_X_EXPORT void
+miPolyRectangle(pDraw, pGC, nrects, pRects)
+ DrawablePtr pDraw;
+ GCPtr pGC;
+ int nrects;
+ xRectangle *pRects;
+{
+ int i;
+ xRectangle *pR = pRects;
+ DDXPointRec rect[5];
+ int bound_tmp;
+
+#define MINBOUND(dst,eqn) bound_tmp = eqn; \
+ if (bound_tmp < -32768) \
+ bound_tmp = -32768; \
+ dst = bound_tmp;
+
+#define MAXBOUND(dst,eqn) bound_tmp = eqn; \
+ if (bound_tmp > 32767) \
+ bound_tmp = 32767; \
+ dst = bound_tmp;
+
+#define MAXUBOUND(dst,eqn) bound_tmp = eqn; \
+ if (bound_tmp > 65535) \
+ bound_tmp = 65535; \
+ dst = bound_tmp;
+
+ if (pGC->lineStyle == LineSolid && pGC->joinStyle == JoinMiter &&
+ pGC->lineWidth != 0)
+ {
+ xRectangle *tmp, *t;
+ int ntmp;
+ int offset1, offset2, offset3;
+ int x, y, width, height;
+
+ ntmp = (nrects << 2);
+ offset2 = pGC->lineWidth;
+ offset1 = offset2 >> 1;
+ offset3 = offset2 - offset1;
+ tmp = (xRectangle *) ALLOCATE_LOCAL(ntmp * sizeof (xRectangle));
+ if (!tmp)
+ return;
+ t = tmp;
+ for (i = 0; i < nrects; i++)
+ {
+ x = pR->x;
+ y = pR->y;
+ width = pR->width;
+ height = pR->height;
+ pR++;
+ if (width == 0 && height == 0)
+ {
+ rect[0].x = x;
+ rect[0].y = y;
+ rect[1].x = x;
+ rect[1].y = y;
+ (*pGC->ops->Polylines)(pDraw, pGC, CoordModeOrigin, 2, rect);
+ }
+ else if (height < offset2 || width < offset1)
+ {
+ if (height == 0)
+ {
+ t->x = x;
+ t->width = width;
+ }
+ else
+ {
+ MINBOUND (t->x, x - offset1)
+ MAXUBOUND (t->width, width + offset2)
+ }
+ if (width == 0)
+ {
+ t->y = y;
+ t->height = height;
+ }
+ else
+ {
+ MINBOUND (t->y, y - offset1)
+ MAXUBOUND (t->height, height + offset2)
+ }
+ t++;
+ }
+ else
+ {
+ MINBOUND(t->x, x - offset1)
+ MINBOUND(t->y, y - offset1)
+ MAXUBOUND(t->width, width + offset2)
+ t->height = offset2;
+ t++;
+ MINBOUND(t->x, x - offset1)
+ MAXBOUND(t->y, y + offset3);
+ t->width = offset2;
+ t->height = height - offset2;
+ t++;
+ MAXBOUND(t->x, x + width - offset1);
+ MAXBOUND(t->y, y + offset3)
+ t->width = offset2;
+ t->height = height - offset2;
+ t++;
+ MINBOUND(t->x, x - offset1)
+ MAXBOUND(t->y, y + height - offset1)
+ MAXUBOUND(t->width, width + offset2)
+ t->height = offset2;
+ t++;
+ }
+ }
+ (*pGC->ops->PolyFillRect) (pDraw, pGC, t - tmp, tmp);
+ DEALLOCATE_LOCAL ((pointer) tmp);
+ }
+ else
+ {
+
+ for (i=0; i<nrects; i++)
+ {
+ rect[0].x = pR->x;
+ rect[0].y = pR->y;
+
+ MAXBOUND(rect[1].x, pR->x + (int) pR->width)
+ rect[1].y = rect[0].y;
+
+ rect[2].x = rect[1].x;
+ MAXBOUND(rect[2].y, pR->y + (int) pR->height);
+
+ rect[3].x = rect[0].x;
+ rect[3].y = rect[2].y;
+
+ rect[4].x = rect[0].x;
+ rect[4].y = rect[0].y;
+
+ (*pGC->ops->Polylines)(pDraw, pGC, CoordModeOrigin, 5, rect);
+ pR++;
+ }
+ }
+}
diff --git a/xserver/mi/mipolyseg.c b/xserver/mi/mipolyseg.c
new file mode 100644
index 000000000..0cd9d416e
--- /dev/null
+++ b/xserver/mi/mipolyseg.c
@@ -0,0 +1,83 @@
+/***********************************************************
+
+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/Xprotostr.h>
+#include "regionstr.h"
+#include "gcstruct.h"
+#include "pixmap.h"
+#include "mi.h"
+
+/*****************************************************************
+ * miPolySegment
+ *
+ * For each segment, draws a line between (x1, y1) and (x2, y2). The
+ * lines are drawn in the order listed.
+ *
+ * Walks the segments, compressing them into format for PolyLines.
+ *
+ *****************************************************************/
+
+
+_X_EXPORT void
+miPolySegment(pDraw, pGC, nseg, pSegs)
+ DrawablePtr pDraw;
+ GCPtr pGC;
+ int nseg;
+ xSegment *pSegs;
+{
+ int i;
+
+ for (i=0; i<nseg; i++)
+ {
+ (*pGC->ops->Polylines)(pDraw, pGC, CoordModeOrigin, 2,(DDXPointPtr)pSegs);
+ pSegs++;
+ }
+}
diff --git a/xserver/mi/mipolytext.c b/xserver/mi/mipolytext.c
new file mode 100644
index 000000000..6af02e046
--- /dev/null
+++ b/xserver/mi/mipolytext.c
@@ -0,0 +1,200 @@
+/*******************************************************************
+
+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.
+
+************************************************************************/
+/*
+ * mipolytext.c - text routines
+ *
+ * Author: haynes
+ * Digital Equipment Corporation
+ * Western Software Laboratory
+ * Date: Thu Feb 5 1987
+ */
+
+#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 "gcstruct.h"
+#include <X11/fonts/fontstruct.h>
+#include "dixfontstr.h"
+#include "mi.h"
+
+int
+miPolyText(pDraw, pGC, x, y, count, chars, fontEncoding)
+ DrawablePtr pDraw;
+ GCPtr pGC;
+ int x, y;
+ int count;
+ char *chars;
+ FontEncoding fontEncoding;
+{
+ unsigned long n, i;
+ int w;
+ CharInfoPtr charinfo[255]; /* encoding only has 1 byte for count */
+
+ GetGlyphs(pGC->font, (unsigned long)count, (unsigned char *)chars,
+ fontEncoding, &n, charinfo);
+ w = 0;
+ for (i=0; i < n; i++) w += charinfo[i]->metrics.characterWidth;
+ if (n != 0)
+ (*pGC->ops->PolyGlyphBlt)(
+ pDraw, pGC, x, y, n, charinfo, FONTGLYPHS(pGC->font));
+ return x+w;
+}
+
+
+_X_EXPORT int
+miPolyText8(pDraw, pGC, x, y, count, chars)
+ DrawablePtr pDraw;
+ GCPtr pGC;
+ int x, y;
+ int count;
+ char *chars;
+{
+ unsigned long n, i;
+ int w;
+ CharInfoPtr charinfo[255]; /* encoding only has 1 byte for count */
+
+ GetGlyphs(pGC->font, (unsigned long)count, (unsigned char *)chars,
+ Linear8Bit, &n, charinfo);
+ w = 0;
+ for (i=0; i < n; i++) w += charinfo[i]->metrics.characterWidth;
+ if (n != 0)
+ (*pGC->ops->PolyGlyphBlt)(
+ pDraw, pGC, x, y, n, charinfo, FONTGLYPHS(pGC->font));
+ return x+w;
+}
+
+
+_X_EXPORT int
+miPolyText16(pDraw, pGC, x, y, count, chars)
+ DrawablePtr pDraw;
+ GCPtr pGC;
+ int x, y;
+ int count;
+ unsigned short *chars;
+{
+ unsigned long n, i;
+ int w;
+ CharInfoPtr charinfo[255]; /* encoding only has 1 byte for count */
+
+ GetGlyphs(pGC->font, (unsigned long)count, (unsigned char *)chars,
+ (FONTLASTROW(pGC->font) == 0) ? Linear16Bit : TwoD16Bit,
+ &n, charinfo);
+ w = 0;
+ for (i=0; i < n; i++) w += charinfo[i]->metrics.characterWidth;
+ if (n != 0)
+ (*pGC->ops->PolyGlyphBlt)(
+ pDraw, pGC, x, y, n, charinfo, FONTGLYPHS(pGC->font));
+ return x+w;
+}
+
+
+int
+miImageText(pDraw, pGC, x, y, count, chars, fontEncoding)
+ DrawablePtr pDraw;
+ GCPtr pGC;
+ int x, y;
+ int count;
+ char *chars;
+ FontEncoding fontEncoding;
+{
+ unsigned long n, i;
+ FontPtr font = pGC->font;
+ int w;
+ CharInfoPtr charinfo[255];
+
+ GetGlyphs(font, (unsigned long)count, (unsigned char *)chars,
+ fontEncoding, &n, charinfo);
+ w = 0;
+ for (i=0; i < n; i++) w += charinfo[i]->metrics.characterWidth;
+ if (n !=0 )
+ (*pGC->ops->ImageGlyphBlt)(pDraw, pGC, x, y, n, charinfo, FONTGLYPHS(font));
+ return x+w;
+}
+
+
+_X_EXPORT void
+miImageText8(pDraw, pGC, x, y, count, chars)
+ DrawablePtr pDraw;
+ GCPtr pGC;
+ int x, y;
+ int count;
+ char *chars;
+{
+ unsigned long n;
+ FontPtr font = pGC->font;
+ CharInfoPtr charinfo[255]; /* encoding only has 1 byte for count */
+
+ GetGlyphs(font, (unsigned long)count, (unsigned char *)chars,
+ Linear8Bit, &n, charinfo);
+ if (n !=0 )
+ (*pGC->ops->ImageGlyphBlt)(pDraw, pGC, x, y, n, charinfo, FONTGLYPHS(font));
+}
+
+
+_X_EXPORT void
+miImageText16(pDraw, pGC, x, y, count, chars)
+ DrawablePtr pDraw;
+ GCPtr pGC;
+ int x, y;
+ int count;
+ unsigned short *chars;
+{
+ unsigned long n;
+ FontPtr font = pGC->font;
+ CharInfoPtr charinfo[255]; /* encoding only has 1 byte for count */
+
+ GetGlyphs(font, (unsigned long)count, (unsigned char *)chars,
+ (FONTLASTROW(pGC->font) == 0) ? Linear16Bit : TwoD16Bit,
+ &n, charinfo);
+ if (n !=0 )
+ (*pGC->ops->ImageGlyphBlt)(pDraw, pGC, x, y, n, charinfo, FONTGLYPHS(font));
+}
diff --git a/xserver/mi/mipolyutil.c b/xserver/mi/mipolyutil.c
new file mode 100644
index 000000000..5443ba5c3
--- /dev/null
+++ b/xserver/mi/mipolyutil.c
@@ -0,0 +1,399 @@
+/***********************************************************
+
+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 "regionstr.h"
+#include "gc.h"
+#include "miscanfill.h"
+#include "mipoly.h"
+#include "misc.h" /* MAXINT */
+
+/*
+ * fillUtils.c
+ *
+ * Written by Brian Kelleher; Oct. 1985
+ *
+ * This module contains all of the utility functions
+ * needed to scan convert a polygon.
+ *
+ */
+
+/*
+ * InsertEdgeInET
+ *
+ * Insert the given edge into the edge table.
+ * First we must find the correct bucket in the
+ * Edge table, then find the right slot in the
+ * bucket. Finally, we can insert it.
+ *
+ */
+Bool
+miInsertEdgeInET(ET, ETE, scanline, SLLBlock, iSLLBlock)
+ EdgeTable *ET;
+ EdgeTableEntry *ETE;
+ int scanline;
+ ScanLineListBlock **SLLBlock;
+ int *iSLLBlock;
+{
+ register EdgeTableEntry *start, *prev;
+ register ScanLineList *pSLL, *pPrevSLL;
+ ScanLineListBlock *tmpSLLBlock;
+
+ /*
+ * find the right bucket to put the edge into
+ */
+ pPrevSLL = &ET->scanlines;
+ pSLL = pPrevSLL->next;
+ while (pSLL && (pSLL->scanline < scanline))
+ {
+ pPrevSLL = pSLL;
+ pSLL = pSLL->next;
+ }
+
+ /*
+ * reassign pSLL (pointer to ScanLineList) if necessary
+ */
+ if ((!pSLL) || (pSLL->scanline > scanline))
+ {
+ if (*iSLLBlock > SLLSPERBLOCK-1)
+ {
+ tmpSLLBlock =
+ (ScanLineListBlock *)xalloc(sizeof(ScanLineListBlock));
+ if (!tmpSLLBlock)
+ return FALSE;
+ (*SLLBlock)->next = tmpSLLBlock;
+ tmpSLLBlock->next = (ScanLineListBlock *)NULL;
+ *SLLBlock = tmpSLLBlock;
+ *iSLLBlock = 0;
+ }
+ pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
+
+ pSLL->next = pPrevSLL->next;
+ pSLL->edgelist = (EdgeTableEntry *)NULL;
+ pPrevSLL->next = pSLL;
+ }
+ pSLL->scanline = scanline;
+
+ /*
+ * now insert the edge in the right bucket
+ */
+ prev = (EdgeTableEntry *)NULL;
+ start = pSLL->edgelist;
+ while (start && (start->bres.minor < ETE->bres.minor))
+ {
+ prev = start;
+ start = start->next;
+ }
+ ETE->next = start;
+
+ if (prev)
+ prev->next = ETE;
+ else
+ pSLL->edgelist = ETE;
+ return TRUE;
+}
+
+/*
+ * CreateEdgeTable
+ *
+ * This routine creates the edge table for
+ * scan converting polygons.
+ * The Edge Table (ET) looks like:
+ *
+ * EdgeTable
+ * --------
+ * | ymax | ScanLineLists
+ * |scanline|-->------------>-------------->...
+ * -------- |scanline| |scanline|
+ * |edgelist| |edgelist|
+ * --------- ---------
+ * | |
+ * | |
+ * V V
+ * list of ETEs list of ETEs
+ *
+ * where ETE is an EdgeTableEntry data structure,
+ * and there is one ScanLineList per scanline at
+ * which an edge is initially entered.
+ *
+ */
+
+Bool
+miCreateETandAET(count, pts, ET, AET, pETEs, pSLLBlock)
+ register int count;
+ register DDXPointPtr pts;
+ EdgeTable *ET;
+ EdgeTableEntry *AET;
+ register EdgeTableEntry *pETEs;
+ ScanLineListBlock *pSLLBlock;
+{
+ register DDXPointPtr top, bottom;
+ register DDXPointPtr PrevPt, CurrPt;
+ int iSLLBlock = 0;
+
+ int dy;
+
+ if (count < 2) return TRUE;
+
+ /*
+ * initialize the Active Edge Table
+ */
+ AET->next = (EdgeTableEntry *)NULL;
+ AET->back = (EdgeTableEntry *)NULL;
+ AET->nextWETE = (EdgeTableEntry *)NULL;
+ AET->bres.minor = MININT;
+
+ /*
+ * initialize the Edge Table.
+ */
+ ET->scanlines.next = (ScanLineList *)NULL;
+ ET->ymax = MININT;
+ ET->ymin = MAXINT;
+ pSLLBlock->next = (ScanLineListBlock *)NULL;
+
+ PrevPt = &pts[count-1];
+
+ /*
+ * for each vertex in the array of points.
+ * In this loop we are dealing with two vertices at
+ * a time -- these make up one edge of the polygon.
+ */
+ while (count--)
+ {
+ CurrPt = pts++;
+
+ /*
+ * find out which point is above and which is below.
+ */
+ if (PrevPt->y > CurrPt->y)
+ {
+ bottom = PrevPt, top = CurrPt;
+ pETEs->ClockWise = 0;
+ }
+ else
+ {
+ bottom = CurrPt, top = PrevPt;
+ pETEs->ClockWise = 1;
+ }
+
+ /*
+ * don't add horizontal edges to the Edge table.
+ */
+ if (bottom->y != top->y)
+ {
+ pETEs->ymax = bottom->y-1; /* -1 so we don't get last scanline */
+
+ /*
+ * initialize integer edge algorithm
+ */
+ dy = bottom->y - top->y;
+ BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
+
+ if (!miInsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock))
+ {
+ miFreeStorage(pSLLBlock->next);
+ return FALSE;
+ }
+
+ ET->ymax = max(ET->ymax, PrevPt->y);
+ ET->ymin = min(ET->ymin, PrevPt->y);
+ pETEs++;
+ }
+
+ PrevPt = CurrPt;
+ }
+ return TRUE;
+}
+
+/*
+ * loadAET
+ *
+ * This routine moves EdgeTableEntries from the
+ * EdgeTable into the Active Edge Table,
+ * leaving them sorted by smaller x coordinate.
+ *
+ */
+
+void
+miloadAET(AET, ETEs)
+ register EdgeTableEntry *AET, *ETEs;
+{
+ register EdgeTableEntry *pPrevAET;
+ register EdgeTableEntry *tmp;
+
+ pPrevAET = AET;
+ AET = AET->next;
+ while (ETEs)
+ {
+ while (AET && (AET->bres.minor < ETEs->bres.minor))
+ {
+ pPrevAET = AET;
+ AET = AET->next;
+ }
+ tmp = ETEs->next;
+ ETEs->next = AET;
+ if (AET)
+ AET->back = ETEs;
+ ETEs->back = pPrevAET;
+ pPrevAET->next = ETEs;
+ pPrevAET = ETEs;
+
+ ETEs = tmp;
+ }
+}
+
+/*
+ * computeWAET
+ *
+ * This routine links the AET by the
+ * nextWETE (winding EdgeTableEntry) link for
+ * use by the winding number rule. The final
+ * Active Edge Table (AET) might look something
+ * like:
+ *
+ * AET
+ * ---------- --------- ---------
+ * |ymax | |ymax | |ymax |
+ * | ... | |... | |... |
+ * |next |->|next |->|next |->...
+ * |nextWETE| |nextWETE| |nextWETE|
+ * --------- --------- ^--------
+ * | | |
+ * V-------------------> V---> ...
+ *
+ */
+void
+micomputeWAET(AET)
+ register EdgeTableEntry *AET;
+{
+ register EdgeTableEntry *pWETE;
+ register int inside = 1;
+ register int isInside = 0;
+
+ AET->nextWETE = (EdgeTableEntry *)NULL;
+ pWETE = AET;
+ AET = AET->next;
+ while (AET)
+ {
+ if (AET->ClockWise)
+ isInside++;
+ else
+ isInside--;
+
+ if ((!inside && !isInside) ||
+ ( inside && isInside))
+ {
+ pWETE->nextWETE = AET;
+ pWETE = AET;
+ inside = !inside;
+ }
+ AET = AET->next;
+ }
+ pWETE->nextWETE = (EdgeTableEntry *)NULL;
+}
+
+/*
+ * InsertionSort
+ *
+ * Just a simple insertion sort using
+ * pointers and back pointers to sort the Active
+ * Edge Table.
+ *
+ */
+
+int
+miInsertionSort(AET)
+ register EdgeTableEntry *AET;
+{
+ register EdgeTableEntry *pETEchase;
+ register EdgeTableEntry *pETEinsert;
+ register EdgeTableEntry *pETEchaseBackTMP;
+ register int changed = 0;
+
+ AET = AET->next;
+ while (AET)
+ {
+ pETEinsert = AET;
+ pETEchase = AET;
+ while (pETEchase->back->bres.minor > AET->bres.minor)
+ pETEchase = pETEchase->back;
+
+ AET = AET->next;
+ if (pETEchase != pETEinsert)
+ {
+ pETEchaseBackTMP = pETEchase->back;
+ pETEinsert->back->next = AET;
+ if (AET)
+ AET->back = pETEinsert->back;
+ pETEinsert->next = pETEchase;
+ pETEchase->back->next = pETEinsert;
+ pETEchase->back = pETEinsert;
+ pETEinsert->back = pETEchaseBackTMP;
+ changed = 1;
+ }
+ }
+ return(changed);
+}
+
+/*
+ * Clean up our act.
+ */
+void
+miFreeStorage(pSLLBlock)
+ register ScanLineListBlock *pSLLBlock;
+{
+ register ScanLineListBlock *tmpSLLBlock;
+
+ while (pSLLBlock)
+ {
+ tmpSLLBlock = pSLLBlock->next;
+ xfree(pSLLBlock);
+ pSLLBlock = tmpSLLBlock;
+ }
+}
diff --git a/xserver/mi/mipushpxl.c b/xserver/mi/mipushpxl.c
new file mode 100644
index 000000000..6526aa02b
--- /dev/null
+++ b/xserver/mi/mipushpxl.c
@@ -0,0 +1,259 @@
+/***********************************************************
+
+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 "gcstruct.h"
+#include "scrnintstr.h"
+#include "pixmapstr.h"
+#include "regionstr.h"
+#include "../mfb/maskbits.h"
+#include "mi.h"
+
+#define NPT 128
+
+/* miPushPixels -- squeegees the fill style of pGC through pBitMap
+ * into pDrawable. pBitMap is a stencil (dx by dy of it is used, it may
+ * be bigger) which is placed on the drawable at xOrg, yOrg. Where a 1 bit
+ * is set in the bitmap, the fill style is put onto the drawable using
+ * the GC's logical function. The drawable is not changed where the bitmap
+ * has a zero bit or outside the area covered by the stencil.
+
+WARNING:
+ this code works if the 1-bit deep pixmap format returned by GetSpans
+is the same as the format defined by the mfb code (i.e. 32-bit padding
+per scanline, scanline unit = 32 bits; later, this might mean
+bitsizeof(int) padding and sacnline unit == bitsizeof(int).)
+
+ */
+
+/*
+ * in order to have both (MSB_FIRST and LSB_FIRST) versions of this
+ * in the server, we need to rename one of them
+ */
+_X_EXPORT void
+miPushPixels(pGC, pBitMap, pDrawable, dx, dy, xOrg, yOrg)
+ GCPtr pGC;
+ PixmapPtr pBitMap;
+ DrawablePtr pDrawable;
+ int dx, dy, xOrg, yOrg;
+{
+ int h, dxDivPPW, ibEnd;
+ MiBits *pwLineStart;
+ register MiBits *pw, *pwEnd;
+ register MiBits msk;
+ register int ib, w;
+ register int ipt; /* index into above arrays */
+ Bool fInBox;
+ DDXPointRec pt[NPT], ptThisLine;
+ int width[NPT];
+#if 1
+ PixelType startmask;
+ if (screenInfo.bitmapBitOrder == IMAGE_BYTE_ORDER)
+ if (screenInfo.bitmapBitOrder == LSBFirst)
+ startmask = (MiBits)(-1) ^
+ LONG2CHARSSAMEORDER((MiBits)(-1) << 1);
+ else
+ startmask = (MiBits)(-1) ^
+ LONG2CHARSSAMEORDER((MiBits)(-1) >> 1);
+ else
+ if (screenInfo.bitmapBitOrder == LSBFirst)
+ startmask = (MiBits)(-1) ^
+ LONG2CHARSDIFFORDER((MiBits)(-1) << 1);
+ else
+ startmask = (MiBits)(-1) ^
+ LONG2CHARSDIFFORDER((MiBits)(-1) >> 1);
+#endif
+
+ pwLineStart = (MiBits *)xalloc(BitmapBytePad(dx));
+ if (!pwLineStart)
+ return;
+ ipt = 0;
+ dxDivPPW = dx/PPW;
+
+ for(h = 0, ptThisLine.x = 0, ptThisLine.y = 0;
+ h < dy;
+ h++, ptThisLine.y++)
+ {
+
+ (*pBitMap->drawable.pScreen->GetSpans)((DrawablePtr)pBitMap, dx,
+ &ptThisLine, &dx, 1, (char *)pwLineStart);
+
+ pw = pwLineStart;
+ /* Process all words which are fully in the pixmap */
+
+ fInBox = FALSE;
+ pwEnd = pwLineStart + dxDivPPW;
+ while(pw < pwEnd)
+ {
+ w = *pw;
+#if 1
+ msk = startmask;
+#else
+ msk = (MiBits)(-1) ^ SCRRIGHT((MiBits)(-1), 1);
+#endif
+ for(ib = 0; ib < PPW; ib++)
+ {
+ if(w & msk)
+ {
+ if(!fInBox)
+ {
+ pt[ipt].x = ((pw - pwLineStart) << PWSH) + ib + xOrg;
+ pt[ipt].y = h + yOrg;
+ /* start new box */
+ fInBox = TRUE;
+ }
+ }
+ else
+ {
+ if(fInBox)
+ {
+ width[ipt] = ((pw - pwLineStart) << PWSH) +
+ ib + xOrg - pt[ipt].x;
+ if (++ipt >= NPT)
+ {
+ (*pGC->ops->FillSpans)(pDrawable, pGC,
+ NPT, pt, width, TRUE);
+ ipt = 0;
+ }
+ /* end box */
+ fInBox = FALSE;
+ }
+ }
+#if 1
+ /* This is not quite right, but it'll do for now */
+ if (screenInfo.bitmapBitOrder == IMAGE_BYTE_ORDER)
+ if (screenInfo.bitmapBitOrder == LSBFirst)
+ msk = LONG2CHARSSAMEORDER(LONG2CHARSSAMEORDER(msk) << 1);
+ else
+ msk = LONG2CHARSSAMEORDER(LONG2CHARSSAMEORDER(msk) >> 1);
+ else
+ if (screenInfo.bitmapBitOrder == LSBFirst)
+ msk = LONG2CHARSDIFFORDER(LONG2CHARSDIFFORDER(msk) << 1);
+ else
+ msk = LONG2CHARSDIFFORDER(LONG2CHARSDIFFORDER(msk) >> 1);
+#else
+ msk = SCRRIGHT(msk, 1);
+#endif
+ }
+ pw++;
+ }
+ ibEnd = dx & PIM;
+ if(ibEnd)
+ {
+ /* Process final partial word on line */
+ w = *pw;
+#if 1
+ msk = startmask;
+#else
+ msk = (MiBits)(-1) ^ SCRRIGHT((MiBits)(-1), 1);
+#endif
+ for(ib = 0; ib < ibEnd; ib++)
+ {
+ if(w & msk)
+ {
+ if(!fInBox)
+ {
+ /* start new box */
+ pt[ipt].x = ((pw - pwLineStart) << PWSH) + ib + xOrg;
+ pt[ipt].y = h + yOrg;
+ fInBox = TRUE;
+ }
+ }
+ else
+ {
+ if(fInBox)
+ {
+ /* end box */
+ width[ipt] = ((pw - pwLineStart) << PWSH) +
+ ib + xOrg - pt[ipt].x;
+ if (++ipt >= NPT)
+ {
+ (*pGC->ops->FillSpans)(pDrawable,
+ pGC, NPT, pt, width, TRUE);
+ ipt = 0;
+ }
+ fInBox = FALSE;
+ }
+ }
+#if 1
+ /* This is not quite right, but it'll do for now */
+ if (screenInfo.bitmapBitOrder == IMAGE_BYTE_ORDER)
+ if (screenInfo.bitmapBitOrder == LSBFirst)
+ msk = LONG2CHARSSAMEORDER(LONG2CHARSSAMEORDER(msk) << 1);
+ else
+ msk = LONG2CHARSSAMEORDER(LONG2CHARSSAMEORDER(msk) >> 1);
+ else
+ if (screenInfo.bitmapBitOrder == LSBFirst)
+ msk = LONG2CHARSDIFFORDER(LONG2CHARSDIFFORDER(msk) << 1);
+ else
+ msk = LONG2CHARSDIFFORDER(LONG2CHARSDIFFORDER(msk) >> 1);
+#else
+ msk = SCRRIGHT(msk, 1);
+#endif
+ }
+ }
+ /* If scanline ended with last bit set, end the box */
+ if(fInBox)
+ {
+ width[ipt] = dx + xOrg - pt[ipt].x;
+ if (++ipt >= NPT)
+ {
+ (*pGC->ops->FillSpans)(pDrawable, pGC, NPT, pt, width, TRUE);
+ ipt = 0;
+ }
+ }
+ }
+ xfree(pwLineStart);
+ /* Flush any remaining spans */
+ if (ipt)
+ {
+ (*pGC->ops->FillSpans)(pDrawable, pGC, ipt, pt, width, TRUE);
+ }
+}
diff --git a/xserver/mi/miregion.c b/xserver/mi/miregion.c
new file mode 100644
index 000000000..fdb538c68
--- /dev/null
+++ b/xserver/mi/miregion.c
@@ -0,0 +1,2561 @@
+/***********************************************************
+
+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 "gc.h"
+#include "mi.h"
+#include "mispans.h"
+
+#if defined (__GNUC__) && !defined (NO_INLINES)
+#define INLINE __inline
+#else
+#define INLINE
+#endif
+
+#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};
+RegionRec miBrokenRegion = { { 0, 0, 0, 0 }, &miBrokenData };
+
+#ifdef DEBUG
+int
+miPrintRegion(rgn)
+ RegionPtr rgn;
+{
+ int num, size;
+ register 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");
+ return(num);
+}
+#endif /* DEBUG */
+
+_X_EXPORT Bool
+miRegionEqual(reg1, reg2)
+ RegionPtr reg1;
+ RegionPtr reg2;
+{
+ int i, num;
+ BoxPtr rects1, 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;
+
+ num = REGION_NUM_RECTS(reg1);
+ if (num != REGION_NUM_RECTS(reg2)) return FALSE;
+
+ rects1 = REGION_RECTS(reg1);
+ rects2 = REGION_RECTS(reg2);
+ for (i = 0; i != num; 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;
+}
+
+#ifdef DEBUG
+Bool
+miValidRegion(reg)
+ RegionPtr reg;
+{
+ register 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
+ {
+ register 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 */
+
+
+/*****************************************************************
+ * 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;
+{
+ register RegionPtr pReg;
+
+ pReg = (RegionPtr)xalloc(sizeof(RegionRec));
+ if (!pReg)
+ return &miBrokenRegion;
+ if (rect)
+ {
+ pReg->extents = *rect;
+ pReg->data = (RegDataPtr)NULL;
+ }
+ else
+ {
+ pReg->extents = miEmptyBox;
+ if ((size > 1) && (pReg->data = xallocData(size)))
+ {
+ pReg->data->size = size;
+ pReg->data->numRects = 0;
+ }
+ else
+ pReg->data = &miEmptyData;
+ }
+ return(pReg);
+}
+
+/*****************************************************************
+ * RegionInit(pReg, rect, size)
+ * Outer region rect is statically allocated.
+ *****************************************************************/
+
+_X_EXPORT void
+miRegionInit(pReg, rect, size)
+ RegionPtr pReg;
+ BoxPtr rect;
+ int size;
+{
+ if (rect)
+ {
+ pReg->extents = *rect;
+ pReg->data = (RegDataPtr)NULL;
+ }
+ else
+ {
+ pReg->extents = miEmptyBox;
+ if ((size > 1) && (pReg->data = xallocData(size)))
+ {
+ pReg->data->size = size;
+ pReg->data->numRects = 0;
+ }
+ else
+ pReg->data = &miEmptyData;
+ }
+}
+
+_X_EXPORT void
+miRegionDestroy(pReg)
+ RegionPtr pReg;
+{
+ good(pReg);
+ xfreeData(pReg);
+ if (pReg != &miBrokenRegion)
+ xfree(pReg);
+}
+
+_X_EXPORT void
+miRegionUninit(pReg)
+ RegionPtr pReg;
+{
+ good(pReg);
+ xfreeData(pReg);
+}
+
+Bool
+miRegionBreak (pReg)
+ RegionPtr pReg;
+{
+ xfreeData (pReg);
+ pReg->extents = miEmptyBox;
+ pReg->data = &miBrokenData;
+ return FALSE;
+}
+
+_X_EXPORT Bool
+miRectAlloc(
+ register 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)
+ register RegionPtr dst;
+ register RegionPtr src;
+{
+ good(dst);
+ good(src);
+ if (dst == src)
+ return TRUE;
+ dst->extents = src->extents;
+ if (!src->data || !src->data->size)
+ {
+ xfreeData(dst);
+ dst->data = src->data;
+ return TRUE;
+ }
+ if (!dst->data || (dst->data->size < src->data->numRects))
+ {
+ xfreeData(dst);
+ dst->data = xallocData(src->data->numRects);
+ if (!dst->data)
+ return miRegionBreak (dst);
+ dst->data->size = src->data->numRects;
+ }
+ dst->data->numRects = src->data->numRects;
+ memmove((char *)REGION_BOXPTR(dst),(char *)REGION_BOXPTR(src),
+ dst->data->numRects * sizeof(BoxRec));
+ return TRUE;
+}
+
+
+/*======================================================================
+ * 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.
+ *
+ *-----------------------------------------------------------------------
+ */
+INLINE static int
+miCoalesce (
+ register RegionPtr pReg, /* Region to coalesce */
+ int prevStart, /* Index of start of previous band */
+ int curStart) /* Index of start of current band */
+{
+ register BoxPtr pPrevBox; /* Current box in previous band */
+ register BoxPtr pCurBox; /* Current box in current band */
+ register int numRects; /* Number rectangles in both bands */
+ register 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.
+ *
+ *-----------------------------------------------------------------------
+ */
+
+INLINE static Bool
+miAppendNonO (
+ register RegionPtr pReg,
+ register BoxPtr r,
+ BoxPtr rEnd,
+ register int y1,
+ register int y2)
+{
+ register BoxPtr pNextRect;
+ register 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)
+{
+ register BoxPtr r1; /* Pointer into first region */
+ register 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 */
+ register BoxPtr r1BandEnd; /* End of current band in r1 */
+ register BoxPtr r2BandEnd; /* End of current band in r2 */
+ short top; /* Top of non-overlapping band */
+ short bot; /* Bottom of non-overlapping band*/
+ register int r1y1; /* Temps for r1->y1 and r2->y1 */
+ register 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.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+miSetExtents (pReg)
+ register RegionPtr pReg;
+{
+ register 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*/
+static Bool
+miIntersectO (
+ register RegionPtr pReg,
+ register BoxPtr r1,
+ BoxPtr r1End,
+ register BoxPtr r2,
+ BoxPtr r2End,
+ short y1,
+ short y2,
+ Bool *pOverlap)
+{
+ register int x1;
+ register int x2;
+ register BoxPtr pNextRect;
+
+ pNextRect = REGION_TOP(pReg);
+
+ 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(pReg, 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;
+}
+
+
+_X_EXPORT Bool
+miIntersect(newReg, reg1, reg2)
+ register RegionPtr newReg; /* destination Region */
+ register RegionPtr reg1;
+ register RegionPtr reg2; /* source regions */
+{
+ good(reg1);
+ good(reg2);
+ good(newReg);
+ /* check for trivial reject */
+ if (REGION_NIL(reg1) || REGION_NIL(reg2) ||
+ !EXTENTCHECK(&reg1->extents, &reg2->extents))
+ {
+ /* Covers about 20% of all cases */
+ xfreeData(newReg);
+ newReg->extents.x2 = newReg->extents.x1;
+ newReg->extents.y2 = newReg->extents.y1;
+ if (REGION_NAR(reg1) || REGION_NAR(reg2))
+ {
+ newReg->data = &miBrokenData;
+ return FALSE;
+ }
+ else
+ newReg->data = &miEmptyData;
+ }
+ else if (!reg1->data && !reg2->data)
+ {
+ /* Covers about 80% of cases that aren't trivially rejected */
+ newReg->extents.x1 = max(reg1->extents.x1, reg2->extents.x1);
+ newReg->extents.y1 = max(reg1->extents.y1, reg2->extents.y1);
+ newReg->extents.x2 = min(reg1->extents.x2, reg2->extents.x2);
+ newReg->extents.y2 = min(reg1->extents.y2, reg2->extents.y2);
+ xfreeData(newReg);
+ newReg->data = (RegDataPtr)NULL;
+ }
+ else if (!reg2->data && SUBSUMES(&reg2->extents, &reg1->extents))
+ {
+ return miRegionCopy(newReg, reg1);
+ }
+ else if (!reg1->data && SUBSUMES(&reg1->extents, &reg2->extents))
+ {
+ return miRegionCopy(newReg, reg2);
+ }
+ else if (reg1 == reg2)
+ {
+ return miRegionCopy(newReg, reg1);
+ }
+ else
+ {
+ /* General purpose intersection */
+ Bool overlap; /* result ignored */
+ if (!miRegionOp(newReg, reg1, reg2, miIntersectO, FALSE, FALSE,
+ &overlap))
+ return FALSE;
+ miSetExtents(newReg);
+ }
+
+ good(newReg);
+ return(TRUE);
+}
+
+#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 (
+ register RegionPtr pReg,
+ register BoxPtr r1,
+ BoxPtr r1End,
+ register BoxPtr r2,
+ BoxPtr r2End,
+ short y1,
+ short y2,
+ Bool *pOverlap)
+{
+ register BoxPtr pNextRect;
+ register int x1; /* left and right side of current union */
+ register 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 */
+ register RegionPtr reg1;
+ register RegionPtr reg2; /* source regions */
+{
+ Bool 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 miRegionCopy(newReg, reg1);
+ }
+
+ /*
+ * Region 1 is empty
+ */
+ if (REGION_NIL(reg1))
+ {
+ if (REGION_NAR(reg1))
+ return miRegionBreak (newReg);
+ if (newReg != reg2)
+ return miRegionCopy(newReg, reg2);
+ return TRUE;
+ }
+
+ /*
+ * Region 2 is empty
+ */
+ if (REGION_NIL(reg2))
+ {
+ if (REGION_NAR(reg2))
+ return miRegionBreak (newReg);
+ if (newReg != reg1)
+ return miRegionCopy(newReg, reg1);
+ return TRUE;
+ }
+
+ /*
+ * Region 1 completely subsumes region 2
+ */
+ if (!reg1->data && SUBSUMES(&reg1->extents, &reg2->extents))
+ {
+ if (newReg != reg1)
+ return miRegionCopy(newReg, reg1);
+ return TRUE;
+ }
+
+ /*
+ * Region 2 completely subsumes region 1
+ */
+ if (!reg2->data && SUBSUMES(&reg2->extents, &reg1->extents))
+ {
+ if (newReg != reg2)
+ return miRegionCopy(newReg, reg2);
+ return TRUE;
+ }
+
+ if (!miRegionOp(newReg, reg1, reg2, miUnionO, TRUE, TRUE, &overlap))
+ return FALSE;
+
+ newReg->extents.x1 = min(reg1->extents.x1, reg2->extents.x1);
+ newReg->extents.y1 = min(reg1->extents.y1, reg2->extents.y1);
+ newReg->extents.x2 = max(reg1->extents.x2, reg2->extents.x2);
+ newReg->extents.y2 = max(reg1->extents.y2, reg2->extents.y2);
+ good(newReg);
+ return TRUE;
+}
+
+
+/*======================================================================
+ * 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)
+ register RegionPtr dstrgn;
+ register 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)
+ {
+ register 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(
+ register BoxRec rects[],
+ register int numRects)
+{
+ register int y1;
+ register int x1;
+ register int i, j;
+ register BoxPtr 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);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * 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;
+{
+ /* 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 */
+ register int j; /* Index into ri */
+ register RegionInfo *rit; /* &ri[j] */
+ register RegionPtr reg; /* ri[j].reg */
+ register BoxPtr box; /* Current box in rects */
+ register BoxPtr riBox; /* Last box in ri[j].reg */
+ register 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;
+ }
+ 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 */
+ }
+ 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. */
+ 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 */
+ 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;
+ 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;
+ register xRectangle *prect;
+ int ctype;
+{
+ register RegionPtr pRgn;
+ register RegDataPtr pData;
+ register BoxPtr pBox;
+ register int i;
+ int x1, y1, x2, y2;
+
+ pRgn = miRegionCreate(NullBox, 0);
+ if (REGION_NAR (pRgn))
+ return pRgn;
+ if (!nrects)
+ return pRgn;
+ if (nrects == 1)
+ {
+ 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)
+ {
+ 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++;
+ }
+ }
+ 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;
+}
+
+/*======================================================================
+ * 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*/
+static Bool
+miSubtractO (
+ register RegionPtr pReg,
+ register BoxPtr r1,
+ BoxPtr r1End,
+ register BoxPtr r2,
+ BoxPtr r2End,
+ register short y1,
+ short y2,
+ Bool *pOverlap)
+{
+ register BoxPtr pNextRect;
+ register int x1;
+
+ x1 = r1->x1;
+
+ assert(y1<y2);
+ assert(r1 != r1End && r2 != r2End);
+
+ pNextRect = REGION_TOP(pReg);
+
+ 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(pReg, 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(pReg, 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(pReg, pNextRect, x1, y1, r1->x2, y2);
+ r1++;
+ if (r1 != r1End)
+ x1 = r1->x1;
+ }
+ return TRUE;
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * 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)
+ register RegionPtr regD;
+ register RegionPtr regM;
+ register RegionPtr regS;
+{
+ Bool overlap; /* result ignored */
+
+ good(regM);
+ good(regS);
+ good(regD);
+ /* check for trivial rejects */
+ if (REGION_NIL(regM) || REGION_NIL(regS) ||
+ !EXTENTCHECK(&regM->extents, &regS->extents))
+ {
+ if (REGION_NAR (regS))
+ return miRegionBreak (regD);
+ return miRegionCopy(regD, regM);
+ }
+ else if (regM == regS)
+ {
+ xfreeData(regD);
+ regD->extents.x2 = regD->extents.x1;
+ regD->extents.y2 = regD->extents.y1;
+ regD->data = &miEmptyData;
+ 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 (!miRegionOp(regD, regM, regS, miSubtractO, TRUE, FALSE, &overlap))
+ return FALSE;
+
+ /*
+ * Can't alter RegD's extents before we call miRegionOp because
+ * it might be one of the source regions and miRegionOp 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.
+ */
+ miSetExtents(regD);
+ good(regD);
+ return TRUE;
+}
+
+/*======================================================================
+ * 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 */
+{
+ RegionRec invReg; /* Quick and dirty region made from the
+ * bounding box */
+ Bool overlap; /* result ignored */
+
+ good(reg1);
+ good(newReg);
+ /* check for trivial rejects */
+ if (REGION_NIL(reg1) || !EXTENTCHECK(invRect, &reg1->extents))
+ {
+ if (REGION_NAR(reg1))
+ return miRegionBreak (newReg);
+ newReg->extents = *invRect;
+ xfreeData(newReg);
+ newReg->data = (RegDataPtr)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 = (RegDataPtr)NULL;
+ if (!miRegionOp(newReg, &invReg, reg1, miSubtractO, TRUE, FALSE, &overlap))
+ return FALSE;
+
+ /*
+ * Can't alter newReg's extents before we call miRegionOp because
+ * it might be one of the source regions and miRegionOp 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.
+ */
+ miSetExtents(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)
+ */
+
+_X_EXPORT int
+miRectIn(region, prect)
+ register RegionPtr region;
+ register BoxPtr prect;
+{
+ register int x;
+ register int y;
+ register BoxPtr pbox;
+ register BoxPtr pboxEnd;
+ int partIn, partOut;
+ int numRects;
+
+ good(region);
+ numRects = REGION_NUM_RECTS(region);
+ /* useful optimization */
+ if (!numRects || !EXTENTCHECK(&region->extents, prect))
+ return(rgnOUT);
+
+ if (numRects == 1)
+ {
+ /* We know that it must be rgnIN or rgnPART */
+ if (SUBSUMES(&region->extents, prect))
+ return(rgnIN);
+ else
+ return(rgnPART);
+ }
+
+ 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 = REGION_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;
+ }
+ }
+
+ return(partIn ? ((y < prect->y2) ? rgnPART : rgnIN) : rgnOUT);
+}
+
+/* TranslateRegion(pReg, x, y)
+ translates in place
+*/
+
+_X_EXPORT void
+miTranslateRegion(pReg, x, y)
+ register RegionPtr pReg;
+ register int x;
+ register int y;
+{
+ int x1, x2, y1, y2;
+ register int nbox;
+ register BoxPtr pbox;
+
+ good(pReg);
+ pReg->extents.x1 = x1 = pReg->extents.x1 + x;
+ pReg->extents.y1 = y1 = pReg->extents.y1 + y;
+ pReg->extents.x2 = x2 = pReg->extents.x2 + x;
+ pReg->extents.y2 = y2 = pReg->extents.y2 + y;
+ if (((x1 - MINSHORT)|(y1 - MINSHORT)|(MAXSHORT - x2)|(MAXSHORT - y2)) >= 0)
+ {
+ if (pReg->data && (nbox = pReg->data->numRects))
+ {
+ for (pbox = REGION_BOXPTR(pReg); nbox--; pbox++)
+ {
+ pbox->x1 += x;
+ pbox->y1 += y;
+ pbox->x2 += x;
+ pbox->y2 += y;
+ }
+ }
+ return;
+ }
+ if (((x2 - MINSHORT)|(y2 - MINSHORT)|(MAXSHORT - x1)|(MAXSHORT - y1)) <= 0)
+ {
+ pReg->extents.x2 = pReg->extents.x1;
+ pReg->extents.y2 = pReg->extents.y1;
+ xfreeData(pReg);
+ pReg->data = &miEmptyData;
+ return;
+ }
+ if (x1 < MINSHORT)
+ pReg->extents.x1 = MINSHORT;
+ else if (x2 > MAXSHORT)
+ pReg->extents.x2 = MAXSHORT;
+ if (y1 < MINSHORT)
+ pReg->extents.y1 = MINSHORT;
+ else if (y2 > MAXSHORT)
+ pReg->extents.y2 = MAXSHORT;
+ if (pReg->data && (nbox = pReg->data->numRects))
+ {
+ register BoxPtr pboxout;
+
+ for (pboxout = pbox = REGION_BOXPTR(pReg); 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 - MINSHORT)|(y2 - MINSHORT)|
+ (MAXSHORT - x1)|(MAXSHORT - y1)) <= 0)
+ {
+ pReg->data->numRects--;
+ continue;
+ }
+ if (x1 < MINSHORT)
+ pboxout->x1 = MINSHORT;
+ else if (x2 > MAXSHORT)
+ pboxout->x2 = MAXSHORT;
+ if (y1 < MINSHORT)
+ pboxout->y1 = MINSHORT;
+ else if (y2 > MAXSHORT)
+ pboxout->y2 = MAXSHORT;
+ pboxout++;
+ }
+ if (pboxout != pbox)
+ {
+ if (pReg->data->numRects == 1)
+ {
+ pReg->extents = *REGION_BOXPTR(pReg);
+ xfreeData(pReg);
+ pReg->data = (RegDataPtr)NULL;
+ }
+ else
+ miSetExtents(pReg);
+ }
+ }
+}
+
+Bool
+miRegionDataCopy(
+ register RegionPtr dst,
+ register RegionPtr src)
+{
+ good(dst);
+ good(src);
+ if (dst->data)
+ return TRUE;
+ if (dst == src)
+ return TRUE;
+ if (!src->data || !src->data->size)
+ {
+ xfreeData(dst);
+ dst->data = (RegDataPtr)NULL;
+ return TRUE;
+ }
+ if (!dst->data || (dst->data->size < src->data->numRects))
+ {
+ xfreeData(dst);
+ dst->data = xallocData(src->data->numRects);
+ if (!dst->data)
+ return miRegionBreak (dst);
+ }
+ dst->data->size = src->data->size;
+ dst->data->numRects = src->data->numRects;
+ return TRUE;
+}
+
+_X_EXPORT void
+miRegionReset(pReg, pBox)
+ RegionPtr pReg;
+ BoxPtr pBox;
+{
+ good(pReg);
+ assert(pBox->x1<=pBox->x2);
+ assert(pBox->y1<=pBox->y2);
+ pReg->extents = *pBox;
+ xfreeData(pReg);
+ pReg->data = (RegDataPtr)NULL;
+}
+
+_X_EXPORT Bool
+miPointInRegion(pReg, x, y, box)
+ register RegionPtr pReg;
+ register int x, y;
+ BoxPtr box; /* "return" value */
+{
+ register BoxPtr pbox, pboxEnd;
+ int numRects;
+
+ good(pReg);
+ numRects = REGION_NUM_RECTS(pReg);
+ if (!numRects || !INBOX(&pReg->extents, x, y))
+ return(FALSE);
+ if (numRects == 1)
+ {
+ *box = pReg->extents;
+ return(TRUE);
+ }
+ for (pbox = REGION_BOXPTR(pReg), 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);
+}
+
+_X_EXPORT Bool
+miRegionNotEmpty(pReg)
+ RegionPtr pReg;
+{
+ good(pReg);
+ return(!REGION_NIL(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; \
+ register 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(
+ register DDXPointRec spans[],
+ register int widths[],
+ register int numSpans)
+{
+ register int y;
+ register int i, j, m;
+ register 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 */
+ register 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,
+ register DDXPointPtr ppt,
+ register int *pwidth,
+ int nspans,
+ register DDXPointPtr pptNew,
+ int *pwidthNew,
+ int fSorted)
+{
+ register DDXPointPtr pptLast;
+ int *pwidthNewStart; /* the vengeance of Xerox! */
+ register int y, x1, x2;
+ register 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. */
+
+ register 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;
+ register BoxPtr pbox;
+ register BoxPtr pboxLast;
+ register 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 */
+ register 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;
+{
+ register int nbox;
+ register BoxPtr pbox;
+ register int nThisBand;
+ register 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);
+}
diff --git a/xserver/mi/miscanfill.h b/xserver/mi/miscanfill.h
new file mode 100644
index 000000000..e318c45b4
--- /dev/null
+++ b/xserver/mi/miscanfill.h
@@ -0,0 +1,147 @@
+/*
+
+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.
+
+*/
+
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#ifndef SCANFILLINCLUDED
+#define SCANFILLINCLUDED
+/*
+ * scanfill.h
+ *
+ * Written by Brian Kelleher; Jan 1985
+ *
+ * This file contains a few macros to help track
+ * the edge of a filled object. The object is assumed
+ * to be filled in scanline order, and thus the
+ * algorithm used is an extension of Bresenham's line
+ * drawing algorithm which assumes that y is always the
+ * major axis.
+ * Since these pieces of code are the same for any filled shape,
+ * it is more convenient to gather the library in one
+ * place, but since these pieces of code are also in
+ * the inner loops of output primitives, procedure call
+ * overhead is out of the question.
+ * See the author for a derivation if needed.
+ */
+
+
+/*
+ * In scan converting polygons, we want to choose those pixels
+ * which are inside the polygon. Thus, we add .5 to the starting
+ * x coordinate for both left and right edges. Now we choose the
+ * first pixel which is inside the pgon for the left edge and the
+ * first pixel which is outside the pgon for the right edge.
+ * Draw the left pixel, but not the right.
+ *
+ * How to add .5 to the starting x coordinate:
+ * If the edge is moving to the right, then subtract dy from the
+ * error term from the general form of the algorithm.
+ * If the edge is moving to the left, then add dy to the error term.
+ *
+ * The reason for the difference between edges moving to the left
+ * and edges moving to the right is simple: If an edge is moving
+ * to the right, then we want the algorithm to flip immediately.
+ * If it is moving to the left, then we don't want it to flip until
+ * we traverse an entire pixel.
+ */
+#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
+ int dx; /* local storage */ \
+\
+ /* \
+ * if the edge is horizontal, then it is ignored \
+ * and assumed not to be processed. Otherwise, do this stuff. \
+ */ \
+ if ((dy) != 0) { \
+ xStart = (x1); \
+ dx = (x2) - xStart; \
+ if (dx < 0) { \
+ m = dx / (dy); \
+ m1 = m - 1; \
+ incr1 = -2 * dx + 2 * (dy) * m1; \
+ incr2 = -2 * dx + 2 * (dy) * m; \
+ d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
+ } else { \
+ m = dx / (dy); \
+ m1 = m + 1; \
+ incr1 = 2 * dx - 2 * (dy) * m1; \
+ incr2 = 2 * dx - 2 * (dy) * m; \
+ d = -2 * m * (dy) + 2 * dx; \
+ } \
+ } \
+}
+
+#define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
+ if (m1 > 0) { \
+ if (d > 0) { \
+ minval += m1; \
+ d += incr1; \
+ } \
+ else { \
+ minval += m; \
+ d += incr2; \
+ } \
+ } else {\
+ if (d >= 0) { \
+ minval += m1; \
+ d += incr1; \
+ } \
+ else { \
+ minval += m; \
+ d += incr2; \
+ } \
+ } \
+}
+
+
+/*
+ * This structure contains all of the information needed
+ * to run the bresenham algorithm.
+ * The variables may be hardcoded into the declarations
+ * instead of using this structure to make use of
+ * register declarations.
+ */
+typedef struct {
+ int minor; /* minor axis */
+ int d; /* decision variable */
+ int m, m1; /* slope and slope+1 */
+ int incr1, incr2; /* error increments */
+} BRESINFO;
+
+
+#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
+ BRESINITPGON(dmaj, min1, min2, bres.minor, bres.d, \
+ bres.m, bres.m1, bres.incr1, bres.incr2)
+
+#define BRESINCRPGONSTRUCT(bres) \
+ BRESINCRPGON(bres.d, bres.minor, bres.m, bres.m1, bres.incr1, bres.incr2)
+
+
+#endif
diff --git a/xserver/mi/miscrinit.c b/xserver/mi/miscrinit.c
new file mode 100644
index 000000000..ac1b82336
--- /dev/null
+++ b/xserver/mi/miscrinit.c
@@ -0,0 +1,344 @@
+/*
+
+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;
+{
+ if (!pPixmap)
+ return FALSE;
+
+ /*
+ * If all arguments are specified, reinitialize everything (including
+ * validated state).
+ */
+ 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.
+ */
+
+ if (width > 0)
+ pPixmap->drawable.width = width;
+
+ if (height > 0)
+ pPixmap->drawable.height = height;
+
+ if (depth > 0)
+ pPixmap->drawable.depth = depth;
+
+ if (bitsPerPixel > 0)
+ pPixmap->drawable.bitsPerPixel = bitsPerPixel;
+ else if ((bitsPerPixel < 0) && (depth > 0))
+ pPixmap->drawable.bitsPerPixel = BitsPerPixel(depth);
+
+ /*
+ * CAVEAT: Non-SI DDXen may use devKind and devPrivate fields for
+ * other purposes.
+ */
+ if (devKind > 0)
+ pPixmap->devKind = devKind;
+ else if ((devKind < 0) && ((width > 0) || (depth > 0)))
+ pPixmap->devKind = PixmapBytePad(pPixmap->drawable.width,
+ pPixmap->drawable.depth);
+
+ if (pPixData)
+ pPixmap->devPrivate.ptr = pPixData;
+ }
+ return TRUE;
+}
+
+
+/*ARGSUSED*/
+Bool
+miCloseScreen (iScreen, pScreen)
+ 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)
+ register 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)
+ register 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;
+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;
+}
diff --git a/xserver/mi/mispans.c b/xserver/mi/mispans.c
new file mode 100644
index 000000000..4c8b6d698
--- /dev/null
+++ b/xserver/mi/mispans.c
@@ -0,0 +1,561 @@
+/***********************************************************
+
+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.
+
+
+Copyright 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.
+
+******************************************************************/
+
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "misc.h"
+#include "pixmapstr.h"
+#include "gcstruct.h"
+#include "mispans.h"
+
+/*
+
+These routines maintain lists of Spans, in order to implement the
+``touch-each-pixel-once'' rules of wide lines and arcs.
+
+Written by Joel McCormack, Summer 1989.
+
+*/
+
+
+void miInitSpanGroup(spanGroup)
+ SpanGroup *spanGroup;
+{
+ spanGroup->size = 0;
+ spanGroup->count = 0;
+ spanGroup->group = NULL;
+ spanGroup->ymin = MAXSHORT;
+ spanGroup->ymax = MINSHORT;
+} /* InitSpanGroup */
+
+#define YMIN(spans) (spans->points[0].y)
+#define YMAX(spans) (spans->points[spans->count-1].y)
+
+void miSubtractSpans (spanGroup, sub)
+ SpanGroup *spanGroup;
+ Spans *sub;
+{
+ int i, subCount, spansCount;
+ int ymin, ymax, xmin, xmax;
+ Spans *spans;
+ DDXPointPtr subPt, spansPt;
+ int *subWid, *spansWid;
+ int extra;
+
+ ymin = YMIN(sub);
+ ymax = YMAX(sub);
+ spans = spanGroup->group;
+ for (i = spanGroup->count; i; i--, spans++) {
+ if (YMIN(spans) <= ymax && ymin <= YMAX(spans)) {
+ subCount = sub->count;
+ subPt = sub->points;
+ subWid = sub->widths;
+ spansCount = spans->count;
+ spansPt = spans->points;
+ spansWid = spans->widths;
+ extra = 0;
+ for (;;)
+ {
+ while (spansCount && spansPt->y < subPt->y)
+ {
+ spansPt++; spansWid++; spansCount--;
+ }
+ if (!spansCount)
+ break;
+ while (subCount && subPt->y < spansPt->y)
+ {
+ subPt++; subWid++; subCount--;
+ }
+ if (!subCount)
+ break;
+ if (subPt->y == spansPt->y)
+ {
+ xmin = subPt->x;
+ xmax = xmin + *subWid;
+ if (xmin >= spansPt->x + *spansWid || spansPt->x >= xmax)
+ {
+ ;
+ }
+ else if (xmin <= spansPt->x)
+ {
+ if (xmax >= spansPt->x + *spansWid)
+ {
+ memmove (spansPt, spansPt + 1, sizeof *spansPt * (spansCount - 1));
+ memmove (spansWid, spansWid + 1, sizeof *spansWid * (spansCount - 1));
+ spansPt--;
+ spansWid--;
+ spans->count--;
+ extra++;
+ }
+ else
+ {
+ *spansWid = *spansWid - (xmax - spansPt->x);
+ spansPt->x = xmax;
+ }
+ }
+ else
+ {
+ if (xmax >= spansPt->x + *spansWid)
+ {
+ *spansWid = xmin - spansPt->x;
+ }
+ else
+ {
+ if (!extra) {
+ DDXPointPtr newPt;
+ int *newwid;
+
+#define EXTRA 8
+ newPt = (DDXPointPtr) xrealloc (spans->points, (spans->count + EXTRA) * sizeof (DDXPointRec));
+ if (!newPt)
+ break;
+ spansPt = newPt + (spansPt - spans->points);
+ spans->points = newPt;
+ newwid = (int *) xrealloc (spans->widths, (spans->count + EXTRA) * sizeof (int));
+ if (!newwid)
+ break;
+ spansWid = newwid + (spansWid - spans->widths);
+ spans->widths = newwid;
+ extra = EXTRA;
+ }
+ memmove (spansPt + 1, spansPt, sizeof *spansPt * (spansCount));
+ memmove (spansWid + 1, spansWid, sizeof *spansWid * (spansCount));
+ spans->count++;
+ extra--;
+ *spansWid = xmin - spansPt->x;
+ spansWid++;
+ spansPt++;
+ *spansWid = *spansWid - (xmax - spansPt->x);
+ spansPt->x = xmax;
+ }
+ }
+ }
+ spansPt++; spansWid++; spansCount--;
+ }
+ }
+ }
+}
+
+void miAppendSpans(spanGroup, otherGroup, spans)
+ SpanGroup *spanGroup;
+ SpanGroup *otherGroup;
+ Spans *spans;
+{
+ register int ymin, ymax;
+ register int spansCount;
+
+ spansCount = spans->count;
+ if (spansCount > 0) {
+ if (spanGroup->size == spanGroup->count) {
+ spanGroup->size = (spanGroup->size + 8) * 2;
+ spanGroup->group = (Spans *)
+ xrealloc(spanGroup->group, sizeof(Spans) * spanGroup->size);
+ }
+
+ spanGroup->group[spanGroup->count] = *spans;
+ (spanGroup->count)++;
+ ymin = spans->points[0].y;
+ if (ymin < spanGroup->ymin) spanGroup->ymin = ymin;
+ ymax = spans->points[spansCount - 1].y;
+ if (ymax > spanGroup->ymax) spanGroup->ymax = ymax;
+ if (otherGroup &&
+ otherGroup->ymin < ymax &&
+ ymin < otherGroup->ymax)
+ {
+ miSubtractSpans (otherGroup, spans);
+ }
+ }
+ else
+ {
+ xfree (spans->points);
+ xfree (spans->widths);
+ }
+} /* AppendSpans */
+
+void miFreeSpanGroup(spanGroup)
+ SpanGroup *spanGroup;
+{
+ if (spanGroup->group != NULL) xfree(spanGroup->group);
+}
+
+static void QuickSortSpansX(
+ register DDXPointRec points[],
+ register int widths[],
+ register int numSpans )
+{
+ register int x;
+ register int i, j, m;
+ register DDXPointPtr r;
+
+/* Always called with numSpans > 1 */
+/* Sorts only by x, as all y should be the same */
+
+#define ExchangeSpans(a, b) \
+{ \
+ DDXPointRec tpt; \
+ register int tw; \
+ \
+ tpt = points[a]; points[a] = points[b]; points[b] = tpt; \
+ tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \
+}
+
+ do {
+ if (numSpans < 9) {
+ /* Do insertion sort */
+ register int xprev;
+
+ xprev = points[0].x;
+ i = 1;
+ do { /* while i != numSpans */
+ x = points[i].x;
+ if (xprev > x) {
+ /* points[i] is out of order. Move into proper location. */
+ DDXPointRec tpt;
+ int tw, k;
+
+ for (j = 0; x >= points[j].x; j++) {}
+ tpt = points[i];
+ tw = widths[i];
+ for (k = i; k != j; k--) {
+ points[k] = points[k-1];
+ widths[k] = widths[k-1];
+ }
+ points[j] = tpt;
+ widths[j] = tw;
+ x = points[i].x;
+ } /* if out of order */
+ xprev = x;
+ i++;
+ } while (i != numSpans);
+ return;
+ }
+
+ /* Choose partition element, stick in location 0 */
+ m = numSpans / 2;
+ if (points[m].x > points[0].x) ExchangeSpans(m, 0);
+ if (points[m].x > points[numSpans-1].x) ExchangeSpans(m, numSpans-1);
+ if (points[m].x > points[0].x) ExchangeSpans(m, 0);
+ x = points[0].x;
+
+ /* Partition array */
+ i = 0;
+ j = numSpans;
+ do {
+ r = &(points[i]);
+ do {
+ r++;
+ i++;
+ } while (i != numSpans && r->x < x);
+ r = &(points[j]);
+ do {
+ r--;
+ j--;
+ } while (x < r->x);
+ if (i < j) ExchangeSpans(i, j);
+ } while (i < j);
+
+ /* Move partition element back to middle */
+ ExchangeSpans(0, j);
+
+ /* Recurse */
+ if (numSpans-j-1 > 1)
+ QuickSortSpansX(&points[j+1], &widths[j+1], numSpans-j-1);
+ numSpans = j;
+ } while (numSpans > 1);
+} /* QuickSortSpans */
+
+
+static int UniquifySpansX(
+ Spans *spans,
+ register DDXPointRec *newPoints,
+ register int *newWidths )
+{
+ register int newx1, newx2, oldpt, i, y;
+ register DDXPointRec *oldPoints;
+ register int *oldWidths;
+ int *startNewWidths;
+
+/* Always called with numSpans > 1 */
+/* Uniquify the spans, and stash them into newPoints and newWidths. Return the
+ number of unique spans. */
+
+
+ startNewWidths = newWidths;
+
+ oldPoints = spans->points;
+ oldWidths = spans->widths;
+
+ y = oldPoints->y;
+ newx1 = oldPoints->x;
+ newx2 = newx1 + *oldWidths;
+
+ for (i = spans->count-1; i != 0; i--) {
+ oldPoints++;
+ oldWidths++;
+ oldpt = oldPoints->x;
+ if (oldpt > newx2) {
+ /* Write current span, start a new one */
+ newPoints->x = newx1;
+ newPoints->y = y;
+ *newWidths = newx2 - newx1;
+ newPoints++;
+ newWidths++;
+ newx1 = oldpt;
+ newx2 = oldpt + *oldWidths;
+ } else {
+ /* extend current span, if old extends beyond new */
+ oldpt = oldpt + *oldWidths;
+ if (oldpt > newx2) newx2 = oldpt;
+ }
+ } /* for */
+
+ /* Write final span */
+ newPoints->x = newx1;
+ *newWidths = newx2 - newx1;
+ newPoints->y = y;
+
+ return (newWidths - startNewWidths) + 1;
+} /* UniquifySpansX */
+
+void
+miDisposeSpanGroup (spanGroup)
+ SpanGroup *spanGroup;
+{
+ int i;
+ Spans *spans;
+
+ for (i = 0; i < spanGroup->count; i++)
+ {
+ spans = spanGroup->group + i;
+ xfree (spans->points);
+ xfree (spans->widths);
+ }
+}
+
+void miFillUniqueSpanGroup(pDraw, pGC, spanGroup)
+ DrawablePtr pDraw;
+ GCPtr pGC;
+ SpanGroup *spanGroup;
+{
+ register int i;
+ register Spans *spans;
+ register Spans *yspans;
+ register int *ysizes;
+ register int ymin, ylength;
+
+ /* Outgoing spans for one big call to FillSpans */
+ register DDXPointPtr points;
+ register int *widths;
+ register int count;
+
+ if (spanGroup->count == 0) return;
+
+ if (spanGroup->count == 1) {
+ /* Already should be sorted, unique */
+ spans = spanGroup->group;
+ (*pGC->ops->FillSpans)
+ (pDraw, pGC, spans->count, spans->points, spans->widths, TRUE);
+ xfree(spans->points);
+ xfree(spans->widths);
+ }
+ else
+ {
+ /* Yuck. Gross. Radix sort into y buckets, then sort x and uniquify */
+ /* This seems to be the fastest thing to do. I've tried sorting on
+ both x and y at the same time rather than creating into all those
+ y buckets, but it was somewhat slower. */
+
+ ymin = spanGroup->ymin;
+ ylength = spanGroup->ymax - ymin + 1;
+
+ /* Allocate Spans for y buckets */
+ yspans = (Spans *) xalloc(ylength * sizeof(Spans));
+ ysizes = (int *) xalloc(ylength * sizeof (int));
+
+ if (!yspans || !ysizes)
+ {
+ if (yspans)
+ xfree (yspans);
+ if (ysizes)
+ xfree (ysizes);
+ miDisposeSpanGroup (spanGroup);
+ return;
+ }
+
+ for (i = 0; i != ylength; i++) {
+ ysizes[i] = 0;
+ yspans[i].count = 0;
+ yspans[i].points = NULL;
+ yspans[i].widths = NULL;
+ }
+
+ /* Go through every single span and put it into the correct bucket */
+ count = 0;
+ for (i = 0, spans = spanGroup->group;
+ i != spanGroup->count;
+ i++, spans++) {
+ int index;
+ int j;
+
+ for (j = 0, points = spans->points, widths = spans->widths;
+ j != spans->count;
+ j++, points++, widths++) {
+ index = points->y - ymin;
+ if (index >= 0 && index < ylength) {
+ Spans *newspans = &(yspans[index]);
+ if (newspans->count == ysizes[index]) {
+ DDXPointPtr newpoints;
+ int *newwidths;
+ ysizes[index] = (ysizes[index] + 8) * 2;
+ newpoints = (DDXPointPtr) xrealloc(
+ newspans->points,
+ ysizes[index] * sizeof(DDXPointRec));
+ newwidths = (int *) xrealloc(
+ newspans->widths,
+ ysizes[index] * sizeof(int));
+ if (!newpoints || !newwidths)
+ {
+ int i;
+
+ for (i = 0; i < ylength; i++)
+ {
+ xfree (yspans[i].points);
+ xfree (yspans[i].widths);
+ }
+ xfree (yspans);
+ xfree (ysizes);
+ miDisposeSpanGroup (spanGroup);
+ return;
+ }
+ newspans->points = newpoints;
+ newspans->widths = newwidths;
+ }
+ newspans->points[newspans->count] = *points;
+ newspans->widths[newspans->count] = *widths;
+ (newspans->count)++;
+ } /* if y value of span in range */
+ } /* for j through spans */
+ count += spans->count;
+ xfree(spans->points);
+ spans->points = NULL;
+ xfree(spans->widths);
+ spans->widths = NULL;
+ } /* for i thorough Spans */
+
+ /* Now sort by x and uniquify each bucket into the final array */
+ points = (DDXPointPtr) xalloc(count * sizeof(DDXPointRec));
+ widths = (int *) xalloc(count * sizeof(int));
+ if (!points || !widths)
+ {
+ int i;
+
+ for (i = 0; i < ylength; i++)
+ {
+ xfree (yspans[i].points);
+ xfree (yspans[i].widths);
+ }
+ xfree (yspans);
+ xfree (ysizes);
+ if (points)
+ xfree (points);
+ if (widths)
+ xfree (widths);
+ return;
+ }
+ count = 0;
+ for (i = 0; i != ylength; i++) {
+ int ycount = yspans[i].count;
+ if (ycount > 0) {
+ if (ycount > 1) {
+ QuickSortSpansX(yspans[i].points, yspans[i].widths, ycount);
+ count += UniquifySpansX
+ (&(yspans[i]), &(points[count]), &(widths[count]));
+ } else {
+ points[count] = yspans[i].points[0];
+ widths[count] = yspans[i].widths[0];
+ count++;
+ }
+ xfree(yspans[i].points);
+ xfree(yspans[i].widths);
+ }
+ }
+
+ (*pGC->ops->FillSpans) (pDraw, pGC, count, points, widths, TRUE);
+ xfree(points);
+ xfree(widths);
+ xfree(yspans);
+ xfree(ysizes); /* use (DE)ALLOCATE_LOCAL for these? */
+ }
+
+ spanGroup->count = 0;
+ spanGroup->ymin = MAXSHORT;
+ spanGroup->ymax = MINSHORT;
+}
+
+
+void miFillSpanGroup(pDraw, pGC, spanGroup)
+ DrawablePtr pDraw;
+ GCPtr pGC;
+ SpanGroup *spanGroup;
+{
+ register int i;
+ register Spans *spans;
+
+ for (i = 0, spans = spanGroup->group; i != spanGroup->count; i++, spans++) {
+ (*pGC->ops->FillSpans)
+ (pDraw, pGC, spans->count, spans->points, spans->widths, TRUE);
+ xfree(spans->points);
+ xfree(spans->widths);
+ }
+
+ spanGroup->count = 0;
+ spanGroup->ymin = MAXSHORT;
+ spanGroup->ymax = MINSHORT;
+} /* FillSpanGroup */
diff --git a/xserver/mi/mispans.h b/xserver/mi/mispans.h
new file mode 100644
index 000000000..5b141afe2
--- /dev/null
+++ b/xserver/mi/mispans.h
@@ -0,0 +1,115 @@
+/***********************************************************
+
+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.
+
+
+Copyright 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.
+
+******************************************************************/
+
+
+typedef struct {
+ int count; /* number of spans */
+ DDXPointPtr points; /* pointer to list of start points */
+ int *widths; /* pointer to list of widths */
+} Spans;
+
+typedef struct {
+ int size; /* Total number of *Spans allocated */
+ int count; /* Number of *Spans actually in group */
+ Spans *group; /* List of Spans */
+ int ymin, ymax; /* Min, max y values encountered */
+} SpanGroup;
+
+/* Initialize SpanGroup. MUST BE DONE before use. */
+extern void miInitSpanGroup(
+ SpanGroup * /*spanGroup*/
+);
+
+/* Add a Spans to a SpanGroup. The spans MUST BE in y-sorted order */
+extern void miAppendSpans(
+ SpanGroup * /*spanGroup*/,
+ SpanGroup * /*otherGroup*/,
+ Spans * /*spans*/
+);
+
+/* Paint a span group, possibly with some overlap */
+extern void miFillSpanGroup(
+ DrawablePtr /*pDraw*/,
+ GCPtr /*pGC*/,
+ SpanGroup * /*spanGroup*/
+);
+
+/* Paint a span group, insuring that each pixel is painted at most once */
+extern void miFillUniqueSpanGroup(
+ DrawablePtr /*pDraw*/,
+ GCPtr /*pGC*/,
+ SpanGroup * /*spanGroup*/
+);
+
+/* Free up data in a span group. MUST BE DONE or you'll suffer memory leaks */
+extern void miFreeSpanGroup(
+ SpanGroup * /*spanGroup*/
+);
+
+extern void miSubtractSpans(
+ SpanGroup * /*spanGroup*/,
+ Spans * /*sub*/
+);
+
+extern void miDisposeSpanGroup(
+ SpanGroup * /*spanGroup*/
+);
+
+extern int miClipSpans(
+ RegionPtr /*prgnDst*/,
+ DDXPointPtr /*ppt*/,
+ int * /*pwidth*/,
+ int /*nspans*/,
+ DDXPointPtr /*pptNew*/,
+ int * /*pwidthNew*/,
+ int /*fSorted*/
+);
+
+/* Rops which must use span groups */
+#define miSpansCarefulRop(rop) (((rop) & 0xc) == 0x8 || ((rop) & 0x3) == 0x2)
+#define miSpansEasyRop(rop) (!miSpansCarefulRop(rop))
+
diff --git a/xserver/mi/misprite.c b/xserver/mi/misprite.c
new file mode 100644
index 000000000..286c7552a
--- /dev/null
+++ b/xserver/mi/misprite.c
@@ -0,0 +1,829 @@
+/*
+ * 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)
+ {
+ register DDXPointPtr pts;
+ register int *widths;
+ register int nPts;
+ register 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;
+{
+ ScreenPtr pScreen = pDrawable->pScreen;
+ miSpriteScreenPtr pScreenPriv;
+
+ SCREEN_PROLOGUE (pScreen, SourceValidate);
+
+ 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);
+ }
+
+ if (pScreen->SourceValidate)
+ (*pScreen->SourceValidate) (pDrawable, x, y, width, height);
+
+ SCREEN_EPILOGUE (pScreen, SourceValidate);
+}
+
+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;
+}
diff --git a/xserver/mi/misprite.h b/xserver/mi/misprite.h
new file mode 100644
index 000000000..5173b7736
--- /dev/null
+++ b/xserver/mi/misprite.h
@@ -0,0 +1,94 @@
+/*
+ * misprite.h
+ *
+ * software-sprite/sprite drawing interface spec
+ *
+ * mi versions of these routines exist.
+ */
+
+
+/*
+
+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.
+*/
+
+typedef struct {
+ Bool (*RealizeCursor)(
+ ScreenPtr /*pScreen*/,
+ CursorPtr /*pCursor*/
+);
+ Bool (*UnrealizeCursor)(
+ ScreenPtr /*pScreen*/,
+ CursorPtr /*pCursor*/
+);
+ Bool (*PutUpCursor)(
+ ScreenPtr /*pScreen*/,
+ CursorPtr /*pCursor*/,
+ int /*x*/,
+ int /*y*/,
+ unsigned long /*source*/,
+ unsigned long /*mask*/
+);
+ Bool (*SaveUnderCursor)(
+ ScreenPtr /*pScreen*/,
+ int /*x*/,
+ int /*y*/,
+ int /*w*/,
+ int /*h*/
+);
+ Bool (*RestoreUnderCursor)(
+ ScreenPtr /*pScreen*/,
+ int /*x*/,
+ int /*y*/,
+ int /*w*/,
+ int /*h*/
+);
+ Bool (*MoveCursor)(
+ ScreenPtr /*pScreen*/,
+ CursorPtr /*pCursor*/,
+ int /*x*/,
+ int /*y*/,
+ int /*w*/,
+ int /*h*/,
+ int /*dx*/,
+ int /*dy*/,
+ unsigned long /*source*/,
+ unsigned long /*mask*/
+);
+ Bool (*ChangeSave)(
+ ScreenPtr /*pScreen*/,
+ int /*x*/,
+ int /*y*/,
+ int /*w*/,
+ int /*h*/,
+ int /*dx*/,
+ int /*dy*/
+);
+
+} miSpriteCursorFuncRec, *miSpriteCursorFuncPtr;
+
+extern Bool miSpriteInitialize(
+ ScreenPtr /*pScreen*/,
+ miSpriteCursorFuncPtr /*cursorFuncs*/,
+ miPointerScreenFuncPtr /*screenFuncs*/
+);
diff --git a/xserver/mi/mispritest.h b/xserver/mi/mispritest.h
new file mode 100644
index 000000000..5075f0580
--- /dev/null
+++ b/xserver/mi/mispritest.h
@@ -0,0 +1,132 @@
+/*
+ * mispritest.h
+ *
+ * mi sprite structures
+ */
+
+
+/*
+
+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
+
+#ifndef _MISPRITEST_H_
+#define _MISPRITEST_H_
+
+# include "misprite.h"
+#ifdef RENDER
+# include "picturestr.h"
+#endif
+# include "damage.h"
+
+/*
+ * per screen information
+ */
+
+typedef struct {
+ /* screen procedures */
+ CloseScreenProcPtr CloseScreen;
+ GetImageProcPtr GetImage;
+ GetSpansProcPtr GetSpans;
+ SourceValidateProcPtr SourceValidate;
+
+ /* window procedures */
+ CopyWindowProcPtr CopyWindow;
+
+ /* backing store procedures */
+ SaveDoomedAreasProcPtr SaveDoomedAreas;
+
+ /* colormap procedures */
+ InstallColormapProcPtr InstallColormap;
+ StoreColorsProcPtr StoreColors;
+
+ /* os layer procedures */
+ ScreenBlockHandlerProcPtr BlockHandler;
+
+ CursorPtr pCursor;
+ int x; /* cursor hotspot */
+ int y;
+ BoxRec saved; /* saved area from the screen */
+ Bool isUp; /* cursor in frame buffer */
+ Bool shouldBeUp; /* cursor should be displayed */
+ WindowPtr pCacheWin; /* window the cursor last seen in */
+ Bool isInCacheWin;
+ Bool checkPixels; /* check colormap collision */
+ xColorItem colors[2];
+ ColormapPtr pInstalledMap;
+ ColormapPtr pColormap;
+ VisualPtr pVisual;
+ miSpriteCursorFuncPtr funcs;
+ DamagePtr pDamage; /* damage tracking structure */
+} miSpriteScreenRec, *miSpriteScreenPtr;
+
+#define SOURCE_COLOR 0
+#define MASK_COLOR 1
+
+#define miSpriteIsUpTRUE(pScreen, pScreenPriv) if (!pScreenPriv->isUp) { \
+ pScreenPriv->isUp = TRUE; \
+ DamageRegister (&(*pScreen->GetScreenPixmap) (pScreen)->drawable, pScreenPriv->pDamage); \
+}
+
+#define miSpriteIsUpFALSE(pScreen, pScreenPriv) if (pScreenPriv->isUp) { \
+ DamageUnregister (&(*pScreen->GetScreenPixmap) (pScreen)->drawable, pScreenPriv->pDamage); \
+ pScreenPriv->isUp = FALSE; \
+}
+
+/*
+ * Overlap BoxPtr and Box elements
+ */
+#define BOX_OVERLAP(pCbox,X1,Y1,X2,Y2) \
+ (((pCbox)->x1 <= (X2)) && ((X1) <= (pCbox)->x2) && \
+ ((pCbox)->y1 <= (Y2)) && ((Y1) <= (pCbox)->y2))
+
+/*
+ * Overlap BoxPtr, origins, and rectangle
+ */
+#define ORG_OVERLAP(pCbox,xorg,yorg,x,y,w,h) \
+ BOX_OVERLAP((pCbox),(x)+(xorg),(y)+(yorg),(x)+(xorg)+(w),(y)+(yorg)+(h))
+
+/*
+ * Overlap BoxPtr, origins and RectPtr
+ */
+#define ORGRECT_OVERLAP(pCbox,xorg,yorg,pRect) \
+ ORG_OVERLAP((pCbox),(xorg),(yorg),(pRect)->x,(pRect)->y, \
+ (int)((pRect)->width), (int)((pRect)->height))
+/*
+ * Overlap BoxPtr and horizontal span
+ */
+#define SPN_OVERLAP(pCbox,y,x,w) BOX_OVERLAP((pCbox),(x),(y),(x)+(w),(y))
+
+#define LINE_SORT(x1,y1,x2,y2) \
+{ int _t; \
+ if (x1 > x2) { _t = x1; x1 = x2; x2 = _t; } \
+ if (y1 > y2) { _t = y1; y1 = y2; y2 = _t; } }
+
+#define LINE_OVERLAP(pCbox,x1,y1,x2,y2,lw2) \
+ BOX_OVERLAP((pCbox), (x1)-(lw2), (y1)-(lw2), (x2)+(lw2), (y2)+(lw2))
+
+#endif /* _MISPRITEST_H_ */
diff --git a/xserver/mi/mistruct.h b/xserver/mi/mistruct.h
new file mode 100644
index 000000000..9b9de8677
--- /dev/null
+++ b/xserver/mi/mistruct.h
@@ -0,0 +1,64 @@
+/***********************************************************
+
+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.
+
+******************************************************************/
+/* $XFree86$ */
+
+#ifndef MISTRUCT_H
+#define MISTRUCT_H
+
+#include "mi.h"
+#include "regionstr.h"
+
+/* information about dashes */
+typedef struct _miDash {
+ DDXPointRec pt;
+ int e1, e2; /* keep these, so we don't have to do it again */
+ int e; /* bresenham error term for this point on line */
+ int which;
+ int newLine;/* 0 if part of same original line as previous dash */
+ } miDashRec;
+
+#endif /* MISTRUCT_H */
diff --git a/xserver/mi/mivalidate.h b/xserver/mi/mivalidate.h
new file mode 100644
index 000000000..91858328a
--- /dev/null
+++ b/xserver/mi/mivalidate.h
@@ -0,0 +1,54 @@
+/*
+
+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.
+
+*/
+/* $XFree86$ */
+
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#ifndef MIVALIDATE_H
+#define MIVALIDATE_H
+
+#include "regionstr.h"
+
+typedef union _Validate {
+ struct BeforeValidate {
+ DDXPointRec oldAbsCorner; /* old window position */
+ RegionPtr borderVisible; /* visible region of border, */
+ /* non-null when size changes */
+ Bool resized; /* unclipped winSize has changed - */
+ /* don't call SaveDoomedAreas */
+ } before;
+ struct AfterValidate {
+ RegionRec exposed; /* exposed regions, absolute pos */
+ RegionRec borderExposed;
+ } after;
+} ValidateRec;
+
+#endif /* MIVALIDATE_H */
diff --git a/xserver/mi/mivaltree.c b/xserver/mi/mivaltree.c
new file mode 100644
index 000000000..0e5ed61e7
--- /dev/null
+++ b/xserver/mi/mivaltree.c
@@ -0,0 +1,823 @@
+/*
+ * mivaltree.c --
+ * Functions for recalculating window clip lists. Main function
+ * is miValidateTree.
+ *
+
+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.
+
+******************************************************************/
+
+
+ /*
+ * Aug '86: Susan Angebranndt -- original code
+ * July '87: Adam de Boor -- substantially modified and commented
+ * Summer '89: Joel McCormack -- so fast you wouldn't believe it possible.
+ * In particular, much improved code for window mapping and
+ * circulating.
+ * Bob Scheifler -- avoid miComputeClips for unmapped windows,
+ * valdata changes
+ */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include "scrnintstr.h"
+#include "validate.h"
+#include "windowstr.h"
+#include "mi.h"
+#include "regionstr.h"
+#include "mivalidate.h"
+
+#include "globals.h"
+
+#ifdef SHAPE
+/*
+ * Compute the visibility of a shaped window
+ */
+_X_EXPORT int
+miShapedWindowIn (pScreen, universe, bounding, rect, x, y)
+ ScreenPtr pScreen;
+ RegionPtr universe, bounding;
+ BoxPtr rect;
+ register int x, y;
+{
+ BoxRec box;
+ register BoxPtr boundBox;
+ int nbox;
+ Bool someIn, someOut;
+ register int t, x1, y1, x2, y2;
+
+ nbox = REGION_NUM_RECTS (bounding);
+ boundBox = REGION_RECTS (bounding);
+ someIn = someOut = FALSE;
+ x1 = rect->x1;
+ y1 = rect->y1;
+ x2 = rect->x2;
+ y2 = rect->y2;
+ while (nbox--)
+ {
+ if ((t = boundBox->x1 + x) < x1)
+ t = x1;
+ box.x1 = t;
+ if ((t = boundBox->y1 + y) < y1)
+ t = y1;
+ box.y1 = t;
+ if ((t = boundBox->x2 + x) > x2)
+ t = x2;
+ box.x2 = t;
+ if ((t = boundBox->y2 + y) > y2)
+ t = y2;
+ box.y2 = t;
+ if (box.x1 > box.x2)
+ box.x2 = box.x1;
+ if (box.y1 > box.y2)
+ box.y2 = box.y1;
+ switch (RECT_IN_REGION(pScreen, universe, &box))
+ {
+ case rgnIN:
+ if (someOut)
+ return rgnPART;
+ someIn = TRUE;
+ break;
+ case rgnOUT:
+ if (someIn)
+ return rgnPART;
+ someOut = TRUE;
+ break;
+ default:
+ return rgnPART;
+ }
+ boundBox++;
+ }
+ if (someIn)
+ return rgnIN;
+ return rgnOUT;
+}
+#endif
+
+static GetRedirectBorderClipProcPtr miGetRedirectBorderClipProc;
+static SetRedirectBorderClipProcPtr miSetRedirectBorderClipProc;
+
+void
+miRegisterRedirectBorderClipProc (SetRedirectBorderClipProcPtr setBorderClip,
+ GetRedirectBorderClipProcPtr getBorderClip)
+{
+ miSetRedirectBorderClipProc = setBorderClip;
+ miGetRedirectBorderClipProc = getBorderClip;
+}
+
+#define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \
+ HasBorder(w) && \
+ (w)->backgroundState == ParentRelative)
+
+
+/*
+ *-----------------------------------------------------------------------
+ * miComputeClips --
+ * Recompute the clipList, borderClip, exposed and borderExposed
+ * regions for pParent and its children. Only viewable windows are
+ * taken into account.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * clipList, borderClip, exposed and borderExposed are altered.
+ * A VisibilityNotify event may be generated on the parent window.
+ *
+ *-----------------------------------------------------------------------
+ */
+static void
+miComputeClips (
+ register WindowPtr pParent,
+ register ScreenPtr pScreen,
+ register RegionPtr universe,
+ VTKind kind,
+ RegionPtr exposed ) /* for intermediate calculations */
+{
+ int dx,
+ dy;
+ RegionRec childUniverse;
+ register WindowPtr pChild;
+ int oldVis, newVis;
+ BoxRec borderSize;
+ RegionRec childUnion;
+ Bool overlap;
+ RegionPtr borderVisible;
+ Bool resized;
+ /*
+ * Figure out the new visibility of this window.
+ * The extent of the universe should be the same as the extent of
+ * the borderSize region. If the window is unobscured, this rectangle
+ * will be completely inside the universe (the universe will cover it
+ * completely). If the window is completely obscured, none of the
+ * universe will cover the rectangle.
+ */
+ borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent);
+ borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent);
+ dx = (int) pParent->drawable.x + (int) pParent->drawable.width + wBorderWidth(pParent);
+ if (dx > 32767)
+ dx = 32767;
+ borderSize.x2 = dx;
+ dy = (int) pParent->drawable.y + (int) pParent->drawable.height + wBorderWidth(pParent);
+ if (dy > 32767)
+ dy = 32767;
+ borderSize.y2 = dy;
+
+#ifdef COMPOSITE
+ /*
+ * In redirected drawing case, reset universe to borderSize
+ */
+ if (pParent->redirectDraw)
+ {
+ if (miSetRedirectBorderClipProc)
+ (*miSetRedirectBorderClipProc) (pParent, universe);
+ REGION_COPY(pScreen, universe, &pParent->borderSize);
+ }
+#endif
+
+ oldVis = pParent->visibility;
+ switch (RECT_IN_REGION( pScreen, universe, &borderSize))
+ {
+ case rgnIN:
+ newVis = VisibilityUnobscured;
+ break;
+ case rgnPART:
+ newVis = VisibilityPartiallyObscured;
+#ifdef SHAPE
+ {
+ RegionPtr pBounding;
+
+ if ((pBounding = wBoundingShape (pParent)))
+ {
+ switch (miShapedWindowIn (pScreen, universe, pBounding,
+ &borderSize,
+ pParent->drawable.x,
+ pParent->drawable.y))
+ {
+ case rgnIN:
+ newVis = VisibilityUnobscured;
+ break;
+ case rgnOUT:
+ newVis = VisibilityFullyObscured;
+ break;
+ }
+ }
+ }
+#endif
+ break;
+ default:
+ newVis = VisibilityFullyObscured;
+ break;
+ }
+ pParent->visibility = newVis;
+ if (oldVis != newVis &&
+ ((pParent->eventMask | wOtherEventMasks(pParent)) & VisibilityChangeMask))
+ SendVisibilityNotify(pParent);
+
+ dx = pParent->drawable.x - pParent->valdata->before.oldAbsCorner.x;
+ dy = pParent->drawable.y - pParent->valdata->before.oldAbsCorner.y;
+
+ /*
+ * avoid computations when dealing with simple operations
+ */
+
+ switch (kind) {
+ case VTMap:
+ case VTStack:
+ case VTUnmap:
+ break;
+ case VTMove:
+ if ((oldVis == newVis) &&
+ ((oldVis == VisibilityFullyObscured) ||
+ (oldVis == VisibilityUnobscured)))
+ {
+ pChild = pParent;
+ while (1)
+ {
+ if (pChild->viewable)
+ {
+ if (pChild->visibility != VisibilityFullyObscured)
+ {
+ REGION_TRANSLATE( pScreen, &pChild->borderClip,
+ dx, dy);
+ REGION_TRANSLATE( pScreen, &pChild->clipList,
+ dx, dy);
+ pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ if (pScreen->ClipNotify)
+ (* pScreen->ClipNotify) (pChild, dx, dy);
+
+ }
+ if (pChild->valdata)
+ {
+ REGION_NULL(pScreen,
+ &pChild->valdata->after.borderExposed);
+ if (HasParentRelativeBorder(pChild))
+ {
+ REGION_SUBTRACT(pScreen,
+ &pChild->valdata->after.borderExposed,
+ &pChild->borderClip,
+ &pChild->winSize);
+ }
+ REGION_NULL(pScreen, &pChild->valdata->after.exposed);
+ }
+ if (pChild->firstChild)
+ {
+ pChild = pChild->firstChild;
+ continue;
+ }
+ }
+ while (!pChild->nextSib && (pChild != pParent))
+ pChild = pChild->parent;
+ if (pChild == pParent)
+ break;
+ pChild = pChild->nextSib;
+ }
+ return;
+ }
+ /* fall through */
+ default:
+ /*
+ * To calculate exposures correctly, we have to translate the old
+ * borderClip and clipList regions to the window's new location so there
+ * is a correspondence between pieces of the new and old clipping regions.
+ */
+ if (dx || dy)
+ {
+ /*
+ * We translate the old clipList because that will be exposed or copied
+ * if gravity is right.
+ */
+ REGION_TRANSLATE( pScreen, &pParent->borderClip, dx, dy);
+ REGION_TRANSLATE( pScreen, &pParent->clipList, dx, dy);
+ }
+ break;
+ case VTBroken:
+ REGION_EMPTY (pScreen, &pParent->borderClip);
+ REGION_EMPTY (pScreen, &pParent->clipList);
+ break;
+ }
+
+ borderVisible = pParent->valdata->before.borderVisible;
+ resized = pParent->valdata->before.resized;
+ REGION_NULL(pScreen, &pParent->valdata->after.borderExposed);
+ REGION_NULL(pScreen, &pParent->valdata->after.exposed);
+
+ /*
+ * Since the borderClip must not be clipped by the children, we do
+ * the border exposure first...
+ *
+ * 'universe' is the window's borderClip. To figure the exposures, remove
+ * the area that used to be exposed from the new.
+ * This leaves a region of pieces that weren't exposed before.
+ */
+
+ if (HasBorder (pParent))
+ {
+ if (borderVisible)
+ {
+ /*
+ * when the border changes shape, the old visible portions
+ * of the border will be saved by DIX in borderVisible --
+ * use that region and destroy it
+ */
+ REGION_SUBTRACT( pScreen, exposed, universe, borderVisible);
+ REGION_DESTROY( pScreen, borderVisible);
+ }
+ else
+ {
+ REGION_SUBTRACT( pScreen, exposed, universe, &pParent->borderClip);
+ }
+ if (HasParentRelativeBorder(pParent) && (dx || dy))
+ REGION_SUBTRACT( pScreen, &pParent->valdata->after.borderExposed,
+ universe,
+ &pParent->winSize);
+ else
+ REGION_SUBTRACT( pScreen, &pParent->valdata->after.borderExposed,
+ exposed, &pParent->winSize);
+
+ REGION_COPY( pScreen, &pParent->borderClip, universe);
+
+ /*
+ * To get the right clipList for the parent, and to make doubly sure
+ * that no child overlaps the parent's border, we remove the parent's
+ * border from the universe before proceeding.
+ */
+
+ REGION_INTERSECT( pScreen, universe, universe, &pParent->winSize);
+ }
+ else
+ REGION_COPY( pScreen, &pParent->borderClip, universe);
+
+ if ((pChild = pParent->firstChild) && pParent->mapped)
+ {
+ REGION_NULL(pScreen, &childUniverse);
+ REGION_NULL(pScreen, &childUnion);
+ if ((pChild->drawable.y < pParent->lastChild->drawable.y) ||
+ ((pChild->drawable.y == pParent->lastChild->drawable.y) &&
+ (pChild->drawable.x < pParent->lastChild->drawable.x)))
+ {
+ for (; pChild; pChild = pChild->nextSib)
+ {
+ if (pChild->viewable)
+ REGION_APPEND( pScreen, &childUnion, &pChild->borderSize);
+ }
+ }
+ else
+ {
+ for (pChild = pParent->lastChild; pChild; pChild = pChild->prevSib)
+ {
+ if (pChild->viewable)
+ REGION_APPEND( pScreen, &childUnion, &pChild->borderSize);
+ }
+ }
+ REGION_VALIDATE( pScreen, &childUnion, &overlap);
+
+ for (pChild = pParent->firstChild;
+ pChild;
+ pChild = pChild->nextSib)
+ {
+ if (pChild->viewable) {
+ /*
+ * If the child is viewable, we want to remove its extents
+ * from the current universe, but we only re-clip it if
+ * it's been marked.
+ */
+ if (pChild->valdata) {
+ /*
+ * Figure out the new universe from the child's
+ * perspective and recurse.
+ */
+ REGION_INTERSECT( pScreen, &childUniverse,
+ universe,
+ &pChild->borderSize);
+ miComputeClips (pChild, pScreen, &childUniverse, kind,
+ exposed);
+ }
+ /*
+ * Once the child has been processed, we remove its extents
+ * from the current universe, thus denying its space to any
+ * other sibling.
+ */
+ if (overlap)
+ REGION_SUBTRACT( pScreen, universe, universe,
+ &pChild->borderSize);
+ }
+ }
+ if (!overlap)
+ REGION_SUBTRACT( pScreen, universe, universe, &childUnion);
+ REGION_UNINIT( pScreen, &childUnion);
+ REGION_UNINIT( pScreen, &childUniverse);
+ } /* if any children */
+
+ /*
+ * 'universe' now contains the new clipList for the parent window.
+ *
+ * To figure the exposure of the window we subtract the old clip from the
+ * new, just as for the border.
+ */
+
+ if (oldVis == VisibilityFullyObscured ||
+ oldVis == VisibilityNotViewable)
+ {
+ REGION_COPY( pScreen, &pParent->valdata->after.exposed, universe);
+ }
+ else if (newVis != VisibilityFullyObscured &&
+ newVis != VisibilityNotViewable)
+ {
+ REGION_SUBTRACT( pScreen, &pParent->valdata->after.exposed,
+ universe, &pParent->clipList);
+ }
+
+ /*
+ * One last thing: backing storage. We have to try to save what parts of
+ * the window are about to be obscured. We can just subtract the universe
+ * from the old clipList and get the areas that were in the old but aren't
+ * in the new and, hence, are about to be obscured.
+ */
+ if (pParent->backStorage && !resized)
+ {
+ REGION_SUBTRACT( pScreen, exposed, &pParent->clipList, universe);
+ (* pScreen->SaveDoomedAreas)(pParent, exposed, dx, dy);
+ }
+
+ /* HACK ALERT - copying contents of regions, instead of regions */
+ {
+ RegionRec tmp;
+
+ tmp = pParent->clipList;
+ pParent->clipList = *universe;
+ *universe = tmp;
+ }
+
+#ifdef NOTDEF
+ REGION_COPY( pScreen, &pParent->clipList, universe);
+#endif
+
+ pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+
+ if (pScreen->ClipNotify)
+ (* pScreen->ClipNotify) (pParent, dx, dy);
+}
+
+static void
+miTreeObscured(
+ register WindowPtr pParent )
+{
+ register WindowPtr pChild;
+ register int oldVis;
+
+ pChild = pParent;
+ while (1)
+ {
+ if (pChild->viewable)
+ {
+ oldVis = pChild->visibility;
+ if (oldVis != (pChild->visibility = VisibilityFullyObscured) &&
+ ((pChild->eventMask | wOtherEventMasks(pChild)) & VisibilityChangeMask))
+ SendVisibilityNotify(pChild);
+ if (pChild->firstChild)
+ {
+ pChild = pChild->firstChild;
+ continue;
+ }
+ }
+ while (!pChild->nextSib && (pChild != pParent))
+ pChild = pChild->parent;
+ if (pChild == pParent)
+ break;
+ pChild = pChild->nextSib;
+ }
+}
+
+/*
+ *-----------------------------------------------------------------------
+ * miValidateTree --
+ * Recomputes the clip list for pParent and all its inferiors.
+ *
+ * Results:
+ * Always returns 1.
+ *
+ * Side Effects:
+ * The clipList, borderClip, exposed, and borderExposed regions for
+ * each marked window are altered.
+ *
+ * Notes:
+ * This routine assumes that all affected windows have been marked
+ * (valdata created) and their winSize and borderSize regions
+ * adjusted to correspond to their new positions. The borderClip and
+ * clipList regions should not have been touched.
+ *
+ * The top-most level is treated differently from all lower levels
+ * because pParent is unchanged. For the top level, we merge the
+ * regions taken up by the marked children back into the clipList
+ * for pParent, thus forming a region from which the marked children
+ * can claim their areas. For lower levels, where the old clipList
+ * and borderClip are invalid, we can't do this and have to do the
+ * extra operations done in miComputeClips, but this is much faster
+ * e.g. when only one child has moved...
+ *
+ *-----------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+int
+miValidateTree (pParent, pChild, kind)
+ WindowPtr pParent; /* Parent to validate */
+ WindowPtr pChild; /* First child of pParent that was
+ * affected */
+ VTKind kind; /* What kind of configuration caused call */
+{
+ RegionRec totalClip; /* Total clipping region available to
+ * the marked children. pParent's clipList
+ * merged with the borderClips of all
+ * the marked children. */
+ RegionRec childClip; /* The new borderClip for the current
+ * child */
+ RegionRec childUnion; /* the space covered by borderSize for
+ * all marked children */
+ RegionRec exposed; /* For intermediate calculations */
+ register ScreenPtr pScreen;
+ register WindowPtr pWin;
+ Bool overlap;
+ int viewvals;
+ Bool forward;
+
+ pScreen = pParent->drawable.pScreen;
+ if (pChild == NullWindow)
+ pChild = pParent->firstChild;
+
+ REGION_NULL(pScreen, &childClip);
+ REGION_NULL(pScreen, &exposed);
+
+ /*
+ * compute the area of the parent window occupied
+ * by the marked children + the parent itself. This
+ * is the area which can be divied up among the marked
+ * children in their new configuration.
+ */
+ REGION_NULL(pScreen, &totalClip);
+ viewvals = 0;
+ if (REGION_BROKEN (pScreen, &pParent->clipList) &&
+ !REGION_BROKEN (pScreen, &pParent->borderClip))
+ {
+ kind = VTBroken;
+ /*
+ * When rebuilding clip lists after out of memory,
+ * assume everything is busted.
+ */
+ forward = TRUE;
+ REGION_COPY (pScreen, &totalClip, &pParent->borderClip);
+ REGION_INTERSECT (pScreen, &totalClip, &totalClip, &pParent->winSize);
+
+ for (pWin = pParent->firstChild; pWin != pChild; pWin = pWin->nextSib)
+ {
+ if (pWin->viewable)
+ REGION_SUBTRACT (pScreen, &totalClip, &totalClip, &pWin->borderSize);
+ }
+ for (pWin = pChild; pWin; pWin = pWin->nextSib)
+ if (pWin->valdata && pWin->viewable)
+ viewvals++;
+
+ REGION_EMPTY (pScreen, &pParent->clipList);
+ }
+ else
+ {
+ if ((pChild->drawable.y < pParent->lastChild->drawable.y) ||
+ ((pChild->drawable.y == pParent->lastChild->drawable.y) &&
+ (pChild->drawable.x < pParent->lastChild->drawable.x)))
+ {
+ forward = TRUE;
+ for (pWin = pChild; pWin; pWin = pWin->nextSib)
+ {
+ if (pWin->valdata)
+ {
+ RegionPtr pBorderClip = &pWin->borderClip;
+#ifdef COMPOSITE
+ if (pWin->redirectDraw && miGetRedirectBorderClipProc)
+ pBorderClip = (*miGetRedirectBorderClipProc)(pWin);
+#endif
+ REGION_APPEND( pScreen, &totalClip, pBorderClip );
+ if (pWin->viewable)
+ viewvals++;
+ }
+ }
+ }
+ else
+ {
+ forward = FALSE;
+ pWin = pParent->lastChild;
+ while (1)
+ {
+ if (pWin->valdata)
+ {
+ RegionPtr pBorderClip = &pWin->borderClip;
+#ifdef COMPOSITE
+ if (pWin->redirectDraw && miGetRedirectBorderClipProc)
+ pBorderClip = (*miGetRedirectBorderClipProc)(pWin);
+#endif
+ REGION_APPEND( pScreen, &totalClip, pBorderClip );
+ if (pWin->viewable)
+ viewvals++;
+ }
+ if (pWin == pChild)
+ break;
+ pWin = pWin->prevSib;
+ }
+ }
+ REGION_VALIDATE( pScreen, &totalClip, &overlap);
+ }
+
+ /*
+ * Now go through the children of the root and figure their new
+ * borderClips from the totalClip, passing that off to miComputeClips
+ * to handle recursively. Once that's done, we remove the child
+ * from the totalClip to clip any siblings below it.
+ */
+
+ overlap = TRUE;
+ if (kind != VTStack)
+ {
+ REGION_UNION( pScreen, &totalClip, &totalClip, &pParent->clipList);
+ if (viewvals > 1)
+ {
+ /*
+ * precompute childUnion to discover whether any of them
+ * overlap. This seems redundant, but performance studies
+ * have demonstrated that the cost of this loop is
+ * lower than the cost of multiple Subtracts in the
+ * loop below.
+ */
+ REGION_NULL(pScreen, &childUnion);
+ if (forward)
+ {
+ for (pWin = pChild; pWin; pWin = pWin->nextSib)
+ if (pWin->valdata && pWin->viewable)
+ REGION_APPEND( pScreen, &childUnion,
+ &pWin->borderSize);
+ }
+ else
+ {
+ pWin = pParent->lastChild;
+ while (1)
+ {
+ if (pWin->valdata && pWin->viewable)
+ REGION_APPEND( pScreen, &childUnion,
+ &pWin->borderSize);
+ if (pWin == pChild)
+ break;
+ pWin = pWin->prevSib;
+ }
+ }
+ REGION_VALIDATE(pScreen, &childUnion, &overlap);
+ if (overlap)
+ REGION_UNINIT(pScreen, &childUnion);
+ }
+ }
+
+ for (pWin = pChild;
+ pWin != NullWindow;
+ pWin = pWin->nextSib)
+ {
+ if (pWin->viewable) {
+ if (pWin->valdata) {
+ REGION_INTERSECT( pScreen, &childClip,
+ &totalClip,
+ &pWin->borderSize);
+ miComputeClips (pWin, pScreen, &childClip, kind, &exposed);
+ if (overlap)
+ {
+ REGION_SUBTRACT( pScreen, &totalClip,
+ &totalClip,
+ &pWin->borderSize);
+ }
+ } else if (pWin->visibility == VisibilityNotViewable) {
+ miTreeObscured(pWin);
+ }
+ } else {
+ if (pWin->valdata) {
+ REGION_EMPTY( pScreen, &pWin->clipList);
+ if (pScreen->ClipNotify)
+ (* pScreen->ClipNotify) (pWin, 0, 0);
+ REGION_EMPTY( pScreen, &pWin->borderClip);
+ pWin->valdata = (ValidatePtr)NULL;
+ }
+ }
+ }
+
+ REGION_UNINIT( pScreen, &childClip);
+ if (!overlap)
+ {
+ REGION_SUBTRACT(pScreen, &totalClip, &totalClip, &childUnion);
+ REGION_UNINIT(pScreen, &childUnion);
+ }
+
+ REGION_NULL(pScreen, &pParent->valdata->after.exposed);
+ REGION_NULL(pScreen, &pParent->valdata->after.borderExposed);
+
+ /*
+ * each case below is responsible for updating the
+ * clipList and serial number for the parent window
+ */
+
+ switch (kind) {
+ case VTStack:
+ break;
+ default:
+ /*
+ * totalClip contains the new clipList for the parent. Figure out
+ * exposures and obscures as per miComputeClips and reset the parent's
+ * clipList.
+ */
+ REGION_SUBTRACT( pScreen, &pParent->valdata->after.exposed,
+ &totalClip, &pParent->clipList);
+ /* fall through */
+ case VTMap:
+ if (pParent->backStorage) {
+ REGION_SUBTRACT( pScreen, &exposed, &pParent->clipList, &totalClip);
+ (* pScreen->SaveDoomedAreas)(pParent, &exposed, 0, 0);
+ }
+
+ REGION_COPY( pScreen, &pParent->clipList, &totalClip);
+ pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ break;
+ }
+
+ REGION_UNINIT( pScreen, &totalClip);
+ REGION_UNINIT( pScreen, &exposed);
+ if (pScreen->ClipNotify)
+ (*pScreen->ClipNotify) (pParent, 0, 0);
+ return (1);
+}
diff --git a/xserver/mi/miwideline.c b/xserver/mi/miwideline.c
new file mode 100644
index 000000000..d57c2eaa7
--- /dev/null
+++ b/xserver/mi/miwideline.c
@@ -0,0 +1,2231 @@
+/*
+
+Copyright 1988, 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.
+
+*/
+
+/* Author: Keith Packard, MIT X Consortium */
+
+/*
+ * Mostly integer wideline code. Uses a technique similar to
+ * bresenham zero-width lines, except walks an X edge
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <stdio.h>
+#ifdef _XOPEN_SOURCE
+#include <math.h>
+#else
+#define _XOPEN_SOURCE /* to get prototype for hypot on some systems */
+#include <math.h>
+#undef _XOPEN_SOURCE
+#endif
+#include <X11/X.h>
+#include "windowstr.h"
+#include "gcstruct.h"
+#include "regionstr.h"
+#include "miwideline.h"
+#include "mi.h"
+
+#ifdef ICEILTEMPDECL
+ICEILTEMPDECL
+#endif
+
+static void miLineArc(DrawablePtr pDraw, register GCPtr pGC,
+ unsigned long pixel, SpanDataPtr spanData,
+ register LineFacePtr leftFace,
+ register LineFacePtr rightFace,
+ double xorg, double yorg, Bool isInt);
+
+
+/*
+ * spans-based polygon filler
+ */
+
+void
+miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, overall_height,
+ left, right, left_count, right_count)
+ DrawablePtr pDrawable;
+ GCPtr pGC;
+ unsigned long pixel;
+ SpanDataPtr spanData;
+ int y; /* start y coordinate */
+ int overall_height; /* height of entire segment */
+ PolyEdgePtr left, right;
+ int left_count, right_count;
+{
+ register int left_x = 0, left_e = 0;
+ int left_stepx = 0;
+ int left_signdx = 0;
+ int left_dy = 0, left_dx = 0;
+
+ register int right_x = 0, right_e = 0;
+ int right_stepx = 0;
+ int right_signdx = 0;
+ int right_dy = 0, right_dx = 0;
+
+ int height = 0;
+ int left_height = 0, right_height = 0;
+
+ register DDXPointPtr ppt;
+ DDXPointPtr pptInit = NULL;
+ register int *pwidth;
+ int *pwidthInit = NULL;
+ XID oldPixel;
+ int xorg;
+ Spans spanRec;
+
+ left_height = 0;
+ right_height = 0;
+
+ if (!spanData)
+ {
+ pptInit = (DDXPointPtr) ALLOCATE_LOCAL (overall_height * sizeof(*ppt));
+ if (!pptInit)
+ return;
+ pwidthInit = (int *) ALLOCATE_LOCAL (overall_height * sizeof(*pwidth));
+ if (!pwidthInit)
+ {
+ DEALLOCATE_LOCAL (pptInit);
+ return;
+ }
+ ppt = pptInit;
+ pwidth = pwidthInit;
+ oldPixel = pGC->fgPixel;
+ if (pixel != oldPixel)
+ {
+ XID tmpPixel = (XID)pixel;
+ DoChangeGC (pGC, GCForeground, &tmpPixel, FALSE);
+ ValidateGC (pDrawable, pGC);
+ }
+ }
+ else
+ {
+ spanRec.points = (DDXPointPtr) xalloc (overall_height * sizeof (*ppt));
+ if (!spanRec.points)
+ return;
+ spanRec.widths = (int *) xalloc (overall_height * sizeof (int));
+ if (!spanRec.widths)
+ {
+ xfree (spanRec.points);
+ return;
+ }
+ ppt = spanRec.points;
+ pwidth = spanRec.widths;
+ }
+
+ xorg = 0;
+ if (pGC->miTranslate)
+ {
+ y += pDrawable->y;
+ xorg = pDrawable->x;
+ }
+ while ((left_count || left_height) &&
+ (right_count || right_height))
+ {
+ MIPOLYRELOADLEFT
+ MIPOLYRELOADRIGHT
+
+ height = left_height;
+ if (height > right_height)
+ height = right_height;
+
+ left_height -= height;
+ right_height -= height;
+
+ while (--height >= 0)
+ {
+ if (right_x >= left_x)
+ {
+ ppt->y = y;
+ ppt->x = left_x + xorg;
+ ppt++;
+ *pwidth++ = right_x - left_x + 1;
+ }
+ y++;
+
+ MIPOLYSTEPLEFT
+
+ MIPOLYSTEPRIGHT
+ }
+ }
+ if (!spanData)
+ {
+ (*pGC->ops->FillSpans) (pDrawable, pGC, ppt - pptInit, pptInit, pwidthInit, TRUE);
+ DEALLOCATE_LOCAL (pwidthInit);
+ DEALLOCATE_LOCAL (pptInit);
+ if (pixel != oldPixel)
+ {
+ DoChangeGC (pGC, GCForeground, &oldPixel, FALSE);
+ ValidateGC (pDrawable, pGC);
+ }
+ }
+ else
+ {
+ spanRec.count = ppt - spanRec.points;
+ AppendSpanGroup (pGC, pixel, &spanRec, spanData)
+ }
+}
+
+static void
+miFillRectPolyHelper (
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ unsigned long pixel,
+ SpanDataPtr spanData,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ register DDXPointPtr ppt;
+ register int *pwidth;
+ XID oldPixel;
+ Spans spanRec;
+ xRectangle rect;
+
+ if (!spanData)
+ {
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+ oldPixel = pGC->fgPixel;
+ if (pixel != oldPixel)
+ {
+ XID tmpPixel = (XID)pixel;
+ DoChangeGC (pGC, GCForeground, &tmpPixel, FALSE);
+ ValidateGC (pDrawable, pGC);
+ }
+ (*pGC->ops->PolyFillRect) (pDrawable, pGC, 1, &rect);
+ if (pixel != oldPixel)
+ {
+ DoChangeGC (pGC, GCForeground, &oldPixel, FALSE);
+ ValidateGC (pDrawable, pGC);
+ }
+ }
+ else
+ {
+ spanRec.points = (DDXPointPtr) xalloc (h * sizeof (*ppt));
+ if (!spanRec.points)
+ return;
+ spanRec.widths = (int *) xalloc (h * sizeof (int));
+ if (!spanRec.widths)
+ {
+ xfree (spanRec.points);
+ return;
+ }
+ ppt = spanRec.points;
+ pwidth = spanRec.widths;
+
+ if (pGC->miTranslate)
+ {
+ y += pDrawable->y;
+ x += pDrawable->x;
+ }
+ while (h--)
+ {
+ ppt->x = x;
+ ppt->y = y;
+ ppt++;
+ *pwidth++ = w;
+ y++;
+ }
+ spanRec.count = ppt - spanRec.points;
+ AppendSpanGroup (pGC, pixel, &spanRec, spanData)
+ }
+}
+
+_X_EXPORT /* static */ int
+miPolyBuildEdge (x0, y0, k, dx, dy, xi, yi, left, edge)
+ double x0, y0;
+ double k; /* x0 * dy - y0 * dx */
+ register int dx, dy;
+ int xi, yi;
+ int left;
+ register PolyEdgePtr edge;
+{
+ int x, y, e;
+ int xady;
+
+ if (dy < 0)
+ {
+ dy = -dy;
+ dx = -dx;
+ k = -k;
+ }
+
+#ifdef NOTDEF
+ {
+ double realk, kerror;
+ realk = x0 * dy - y0 * dx;
+ kerror = Fabs (realk - k);
+ if (kerror > .1)
+ printf ("realk: %g k: %g\n", realk, k);
+ }
+#endif
+ y = ICEIL (y0);
+ xady = ICEIL (k) + y * dx;
+
+ if (xady <= 0)
+ x = - (-xady / dy) - 1;
+ else
+ x = (xady - 1) / dy;
+
+ e = xady - x * dy;
+
+ if (dx >= 0)
+ {
+ edge->signdx = 1;
+ edge->stepx = dx / dy;
+ edge->dx = dx % dy;
+ }
+ else
+ {
+ edge->signdx = -1;
+ edge->stepx = - (-dx / dy);
+ edge->dx = -dx % dy;
+ e = dy - e + 1;
+ }
+ edge->dy = dy;
+ edge->x = x + left + xi;
+ edge->e = e - dy; /* bias to compare against 0 instead of dy */
+ return y + yi;
+}
+
+#define StepAround(v, incr, max) (((v) + (incr) < 0) ? (max - 1) : ((v) + (incr) == max) ? 0 : ((v) + (incr)))
+
+_X_EXPORT /* static */ int
+miPolyBuildPoly (vertices, slopes, count, xi, yi, left, right, pnleft, pnright, h)
+ register PolyVertexPtr vertices;
+ register PolySlopePtr slopes;
+ int count;
+ int xi, yi;
+ PolyEdgePtr left, right;
+ int *pnleft, *pnright;
+ int *h;
+{
+ int top, bottom;
+ double miny, maxy;
+ register int i;
+ int j;
+ int clockwise;
+ int slopeoff;
+ register int s;
+ register int nright, nleft;
+ int y, lasty = 0, bottomy, topy = 0;
+
+ /* find the top of the polygon */
+ maxy = miny = vertices[0].y;
+ bottom = top = 0;
+ for (i = 1; i < count; i++)
+ {
+ if (vertices[i].y < miny)
+ {
+ top = i;
+ miny = vertices[i].y;
+ }
+ if (vertices[i].y >= maxy)
+ {
+ bottom = i;
+ maxy = vertices[i].y;
+ }
+ }
+ clockwise = 1;
+ slopeoff = 0;
+
+ i = top;
+ j = StepAround (top, -1, count);
+
+ if (slopes[j].dy * slopes[i].dx > slopes[i].dy * slopes[j].dx)
+ {
+ clockwise = -1;
+ slopeoff = -1;
+ }
+
+ bottomy = ICEIL (maxy) + yi;
+
+ nright = 0;
+
+ s = StepAround (top, slopeoff, count);
+ i = top;
+ while (i != bottom)
+ {
+ if (slopes[s].dy != 0)
+ {
+ y = miPolyBuildEdge (vertices[i].x, vertices[i].y,
+ slopes[s].k,
+ slopes[s].dx, slopes[s].dy,
+ xi, yi, 0,
+ &right[nright]);
+ if (nright != 0)
+ right[nright-1].height = y - lasty;
+ else
+ topy = y;
+ nright++;
+ lasty = y;
+ }
+
+ i = StepAround (i, clockwise, count);
+ s = StepAround (s, clockwise, count);
+ }
+ if (nright != 0)
+ right[nright-1].height = bottomy - lasty;
+
+ if (slopeoff == 0)
+ slopeoff = -1;
+ else
+ slopeoff = 0;
+
+ nleft = 0;
+ s = StepAround (top, slopeoff, count);
+ i = top;
+ while (i != bottom)
+ {
+ if (slopes[s].dy != 0)
+ {
+ y = miPolyBuildEdge (vertices[i].x, vertices[i].y,
+ slopes[s].k,
+ slopes[s].dx, slopes[s].dy, xi, yi, 1,
+ &left[nleft]);
+
+ if (nleft != 0)
+ left[nleft-1].height = y - lasty;
+ nleft++;
+ lasty = y;
+ }
+ i = StepAround (i, -clockwise, count);
+ s = StepAround (s, -clockwise, count);
+ }
+ if (nleft != 0)
+ left[nleft-1].height = bottomy - lasty;
+ *pnleft = nleft;
+ *pnright = nright;
+ *h = bottomy - topy;
+ return topy;
+}
+
+static void
+miLineOnePoint (
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ unsigned long pixel,
+ SpanDataPtr spanData,
+ int x,
+ int y)
+{
+ DDXPointRec pt;
+ int wid;
+ unsigned long oldPixel;
+
+ MILINESETPIXEL (pDrawable, pGC, pixel, oldPixel);
+ if (pGC->fillStyle == FillSolid)
+ {
+ pt.x = x;
+ pt.y = y;
+ (*pGC->ops->PolyPoint) (pDrawable, pGC, CoordModeOrigin, 1, &pt);
+ }
+ else
+ {
+ wid = 1;
+ if (pGC->miTranslate)
+ {
+ x += pDrawable->x;
+ y += pDrawable->y;
+ }
+ pt.x = x;
+ pt.y = y;
+ (*pGC->ops->FillSpans) (pDrawable, pGC, 1, &pt, &wid, TRUE);
+ }
+ MILINERESETPIXEL (pDrawable, pGC, pixel, oldPixel);
+}
+
+static void
+miLineJoin (
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ unsigned long pixel,
+ SpanDataPtr spanData,
+ register LineFacePtr pLeft,
+ register LineFacePtr pRight)
+{
+ double mx = 0, my = 0;
+ double denom = 0.0;
+ PolyVertexRec vertices[4];
+ PolySlopeRec slopes[4];
+ int edgecount;
+ PolyEdgeRec left[4], right[4];
+ int nleft, nright;
+ int y, height;
+ int swapslopes;
+ int joinStyle = pGC->joinStyle;
+ int lw = pGC->lineWidth;
+
+ if (lw == 1 && !spanData) {
+ /* See if one of the lines will draw the joining pixel */
+ if (pLeft->dx > 0 || (pLeft->dx == 0 && pLeft->dy > 0))
+ return;
+ if (pRight->dx > 0 || (pRight->dx == 0 && pRight->dy > 0))
+ return;
+ if (joinStyle != JoinRound) {
+ denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy;
+ if (denom == 0)
+ return; /* no join to draw */
+ }
+ if (joinStyle != JoinMiter) {
+ miLineOnePoint (pDrawable, pGC, pixel, spanData, pLeft->x, pLeft->y);
+ return;
+ }
+ } else {
+ if (joinStyle == JoinRound)
+ {
+ miLineArc(pDrawable, pGC, pixel, spanData,
+ pLeft, pRight,
+ (double)0.0, (double)0.0, TRUE);
+ return;
+ }
+ denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy;
+ if (denom == 0.0)
+ return; /* no join to draw */
+ }
+
+ swapslopes = 0;
+ if (denom > 0)
+ {
+ pLeft->xa = -pLeft->xa;
+ pLeft->ya = -pLeft->ya;
+ pLeft->dx = -pLeft->dx;
+ pLeft->dy = -pLeft->dy;
+ }
+ else
+ {
+ swapslopes = 1;
+ pRight->xa = -pRight->xa;
+ pRight->ya = -pRight->ya;
+ pRight->dx = -pRight->dx;
+ pRight->dy = -pRight->dy;
+ }
+
+ vertices[0].x = pRight->xa;
+ vertices[0].y = pRight->ya;
+ slopes[0].dx = -pRight->dy;
+ slopes[0].dy = pRight->dx;
+ slopes[0].k = 0;
+
+ vertices[1].x = 0;
+ vertices[1].y = 0;
+ slopes[1].dx = pLeft->dy;
+ slopes[1].dy = -pLeft->dx;
+ slopes[1].k = 0;
+
+ vertices[2].x = pLeft->xa;
+ vertices[2].y = pLeft->ya;
+
+ if (joinStyle == JoinMiter)
+ {
+ my = (pLeft->dy * (pRight->xa * pRight->dy - pRight->ya * pRight->dx) -
+ pRight->dy * (pLeft->xa * pLeft->dy - pLeft->ya * pLeft->dx )) /
+ denom;
+ if (pLeft->dy != 0)
+ {
+ mx = pLeft->xa + (my - pLeft->ya) *
+ (double) pLeft->dx / (double) pLeft->dy;
+ }
+ else
+ {
+ mx = pRight->xa + (my - pRight->ya) *
+ (double) pRight->dx / (double) pRight->dy;
+ }
+ /* check miter limit */
+ if ((mx * mx + my * my) * 4 > SQSECANT * lw * lw)
+ joinStyle = JoinBevel;
+ }
+
+ if (joinStyle == JoinMiter)
+ {
+ slopes[2].dx = pLeft->dx;
+ slopes[2].dy = pLeft->dy;
+ slopes[2].k = pLeft->k;
+ if (swapslopes)
+ {
+ slopes[2].dx = -slopes[2].dx;
+ slopes[2].dy = -slopes[2].dy;
+ slopes[2].k = -slopes[2].k;
+ }
+ vertices[3].x = mx;
+ vertices[3].y = my;
+ slopes[3].dx = pRight->dx;
+ slopes[3].dy = pRight->dy;
+ slopes[3].k = pRight->k;
+ if (swapslopes)
+ {
+ slopes[3].dx = -slopes[3].dx;
+ slopes[3].dy = -slopes[3].dy;
+ slopes[3].k = -slopes[3].k;
+ }
+ edgecount = 4;
+ }
+ else
+ {
+ double scale, dx, dy, adx, ady;
+
+ adx = dx = pRight->xa - pLeft->xa;
+ ady = dy = pRight->ya - pLeft->ya;
+ if (adx < 0)
+ adx = -adx;
+ if (ady < 0)
+ ady = -ady;
+ scale = ady;
+ if (adx > ady)
+ scale = adx;
+ slopes[2].dx = (dx * 65536) / scale;
+ slopes[2].dy = (dy * 65536) / scale;
+ slopes[2].k = ((pLeft->xa + pRight->xa) * slopes[2].dy -
+ (pLeft->ya + pRight->ya) * slopes[2].dx) / 2.0;
+ edgecount = 3;
+ }
+
+ y = miPolyBuildPoly (vertices, slopes, edgecount, pLeft->x, pLeft->y,
+ left, right, &nleft, &nright, &height);
+ miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, height, left, right, nleft, nright);
+}
+
+static int
+miLineArcI (
+ DrawablePtr pDraw,
+ GCPtr pGC,
+ int xorg,
+ int yorg,
+ DDXPointPtr points,
+ int *widths)
+{
+ register DDXPointPtr tpts, bpts;
+ register int *twids, *bwids;
+ register int x, y, e, ex, slw;
+
+ tpts = points;
+ twids = widths;
+ if (pGC->miTranslate)
+ {
+ xorg += pDraw->x;
+ yorg += pDraw->y;
+ }
+ slw = pGC->lineWidth;
+ if (slw == 1)
+ {
+ tpts->x = xorg;
+ tpts->y = yorg;
+ *twids = 1;
+ return 1;
+ }
+ bpts = tpts + slw;
+ bwids = twids + slw;
+ y = (slw >> 1) + 1;
+ if (slw & 1)
+ e = - ((y << 2) + 3);
+ else
+ e = - (y << 3);
+ ex = -4;
+ x = 0;
+ while (y)
+ {
+ e += (y << 3) - 4;
+ while (e >= 0)
+ {
+ x++;
+ e += (ex = -((x << 3) + 4));
+ }
+ y--;
+ slw = (x << 1) + 1;
+ if ((e == ex) && (slw > 1))
+ slw--;
+ tpts->x = xorg - x;
+ tpts->y = yorg - y;
+ tpts++;
+ *twids++ = slw;
+ if ((y != 0) && ((slw > 1) || (e != ex)))
+ {
+ bpts--;
+ bpts->x = xorg - x;
+ bpts->y = yorg + y;
+ *--bwids = slw;
+ }
+ }
+ return (pGC->lineWidth);
+}
+
+#define CLIPSTEPEDGE(edgey,edge,edgeleft) \
+ if (ybase == edgey) \
+ { \
+ if (edgeleft) \
+ { \
+ if (edge->x > xcl) \
+ xcl = edge->x; \
+ } \
+ else \
+ { \
+ if (edge->x < xcr) \
+ xcr = edge->x; \
+ } \
+ edgey++; \
+ edge->x += edge->stepx; \
+ edge->e += edge->dx; \
+ if (edge->e > 0) \
+ { \
+ edge->x += edge->signdx; \
+ edge->e -= edge->dy; \
+ } \
+ }
+
+static int
+miLineArcD (
+ DrawablePtr pDraw,
+ GCPtr pGC,
+ double xorg,
+ double yorg,
+ DDXPointPtr points,
+ int *widths,
+ PolyEdgePtr edge1,
+ int edgey1,
+ Bool edgeleft1,
+ PolyEdgePtr edge2,
+ int edgey2,
+ Bool edgeleft2)
+{
+ register DDXPointPtr pts;
+ register int *wids;
+ double radius, x0, y0, el, er, yk, xlk, xrk, k;
+ int xbase, ybase, y, boty, xl, xr, xcl, xcr;
+ int ymin, ymax;
+ Bool edge1IsMin, edge2IsMin;
+ int ymin1, ymin2;
+
+ pts = points;
+ wids = widths;
+ xbase = floor(xorg);
+ x0 = xorg - xbase;
+ ybase = ICEIL (yorg);
+ y0 = yorg - ybase;
+ if (pGC->miTranslate)
+ {
+ xbase += pDraw->x;
+ ybase += pDraw->y;
+ edge1->x += pDraw->x;
+ edge2->x += pDraw->x;
+ edgey1 += pDraw->y;
+ edgey2 += pDraw->y;
+ }
+ xlk = x0 + x0 + 1.0;
+ xrk = x0 + x0 - 1.0;
+ yk = y0 + y0 - 1.0;
+ radius = ((double)pGC->lineWidth) / 2.0;
+ y = floor(radius - y0 + 1.0);
+ ybase -= y;
+ ymin = ybase;
+ ymax = 65536;
+ edge1IsMin = FALSE;
+ ymin1 = edgey1;
+ if (edge1->dy >= 0)
+ {
+ if (!edge1->dy)
+ {
+ if (edgeleft1)
+ edge1IsMin = TRUE;
+ else
+ ymax = edgey1;
+ edgey1 = 65536;
+ }
+ else
+ {
+ if ((edge1->signdx < 0) == edgeleft1)
+ edge1IsMin = TRUE;
+ }
+ }
+ edge2IsMin = FALSE;
+ ymin2 = edgey2;
+ if (edge2->dy >= 0)
+ {
+ if (!edge2->dy)
+ {
+ if (edgeleft2)
+ edge2IsMin = TRUE;
+ else
+ ymax = edgey2;
+ edgey2 = 65536;
+ }
+ else
+ {
+ if ((edge2->signdx < 0) == edgeleft2)
+ edge2IsMin = TRUE;
+ }
+ }
+ if (edge1IsMin)
+ {
+ ymin = ymin1;
+ if (edge2IsMin && ymin1 > ymin2)
+ ymin = ymin2;
+ } else if (edge2IsMin)
+ ymin = ymin2;
+ el = radius * radius - ((y + y0) * (y + y0)) - (x0 * x0);
+ er = el + xrk;
+ xl = 1;
+ xr = 0;
+ if (x0 < 0.5)
+ {
+ xl = 0;
+ el -= xlk;
+ }
+ boty = (y0 < -0.5) ? 1 : 0;
+ if (ybase + y - boty > ymax)
+ boty = ymax - ybase - y;
+ while (y > boty)
+ {
+ k = (y << 1) + yk;
+ er += k;
+ while (er > 0.0)
+ {
+ xr++;
+ er += xrk - (xr << 1);
+ }
+ el += k;
+ while (el >= 0.0)
+ {
+ xl--;
+ el += (xl << 1) - xlk;
+ }
+ y--;
+ ybase++;
+ if (ybase < ymin)
+ continue;
+ xcl = xl + xbase;
+ xcr = xr + xbase;
+ CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
+ CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
+ if (xcr >= xcl)
+ {
+ pts->x = xcl;
+ pts->y = ybase;
+ pts++;
+ *wids++ = xcr - xcl + 1;
+ }
+ }
+ er = xrk - (xr << 1) - er;
+ el = (xl << 1) - xlk - el;
+ boty = floor(-y0 - radius + 1.0);
+ if (ybase + y - boty > ymax)
+ boty = ymax - ybase - y;
+ while (y > boty)
+ {
+ k = (y << 1) + yk;
+ er -= k;
+ while ((er >= 0.0) && (xr >= 0))
+ {
+ xr--;
+ er += xrk - (xr << 1);
+ }
+ el -= k;
+ while ((el > 0.0) && (xl <= 0))
+ {
+ xl++;
+ el += (xl << 1) - xlk;
+ }
+ y--;
+ ybase++;
+ if (ybase < ymin)
+ continue;
+ xcl = xl + xbase;
+ xcr = xr + xbase;
+ CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
+ CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
+ if (xcr >= xcl)
+ {
+ pts->x = xcl;
+ pts->y = ybase;
+ pts++;
+ *wids++ = xcr - xcl + 1;
+ }
+ }
+ return (pts - points);
+}
+
+int
+miRoundJoinFace (face, edge, leftEdge)
+ register LineFacePtr face;
+ register PolyEdgePtr edge;
+ Bool *leftEdge;
+{
+ int y;
+ int dx, dy;
+ double xa, ya;
+ Bool left;
+
+ dx = -face->dy;
+ dy = face->dx;
+ xa = face->xa;
+ ya = face->ya;
+ left = 1;
+ if (ya > 0)
+ {
+ ya = 0.0;
+ xa = 0.0;
+ }
+ if (dy < 0 || (dy == 0 && dx > 0))
+ {
+ dx = -dx;
+ dy = -dy;
+ left = !left;
+ }
+ if (dx == 0 && dy == 0)
+ dy = 1;
+ if (dy == 0)
+ {
+ y = ICEIL (face->ya) + face->y;
+ edge->x = -32767;
+ edge->stepx = 0;
+ edge->signdx = 0;
+ edge->e = -1;
+ edge->dy = 0;
+ edge->dx = 0;
+ edge->height = 0;
+ }
+ else
+ {
+ y = miPolyBuildEdge (xa, ya, 0.0, dx, dy, face->x, face->y, !left, edge);
+ edge->height = 32767;
+ }
+ *leftEdge = !left;
+ return y;
+}
+
+_X_EXPORT void
+miRoundJoinClip (pLeft, pRight, edge1, edge2, y1, y2, left1, left2)
+ register LineFacePtr pLeft, pRight;
+ PolyEdgePtr edge1, edge2;
+ int *y1, *y2;
+ Bool *left1, *left2;
+{
+ double denom;
+
+ denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy;
+
+ if (denom >= 0)
+ {
+ pLeft->xa = -pLeft->xa;
+ pLeft->ya = -pLeft->ya;
+ }
+ else
+ {
+ pRight->xa = -pRight->xa;
+ pRight->ya = -pRight->ya;
+ }
+ *y1 = miRoundJoinFace (pLeft, edge1, left1);
+ *y2 = miRoundJoinFace (pRight, edge2, left2);
+}
+
+_X_EXPORT int
+miRoundCapClip (face, isInt, edge, leftEdge)
+ register LineFacePtr face;
+ Bool isInt;
+ register PolyEdgePtr edge;
+ Bool *leftEdge;
+{
+ int y;
+ register int dx, dy;
+ double xa, ya, k;
+ Bool left;
+
+ dx = -face->dy;
+ dy = face->dx;
+ xa = face->xa;
+ ya = face->ya;
+ k = 0.0;
+ if (!isInt)
+ k = face->k;
+ left = 1;
+ if (dy < 0 || (dy == 0 && dx > 0))
+ {
+ dx = -dx;
+ dy = -dy;
+ xa = -xa;
+ ya = -ya;
+ left = !left;
+ }
+ if (dx == 0 && dy == 0)
+ dy = 1;
+ if (dy == 0)
+ {
+ y = ICEIL (face->ya) + face->y;
+ edge->x = -32767;
+ edge->stepx = 0;
+ edge->signdx = 0;
+ edge->e = -1;
+ edge->dy = 0;
+ edge->dx = 0;
+ edge->height = 0;
+ }
+ else
+ {
+ y = miPolyBuildEdge (xa, ya, k, dx, dy, face->x, face->y, !left, edge);
+ edge->height = 32767;
+ }
+ *leftEdge = !left;
+ return y;
+}
+
+static void
+miLineArc (
+ DrawablePtr pDraw,
+ register GCPtr pGC,
+ unsigned long pixel,
+ SpanDataPtr spanData,
+ register LineFacePtr leftFace,
+ register LineFacePtr rightFace,
+ double xorg,
+ double yorg,
+ Bool isInt)
+{
+ DDXPointPtr points;
+ int *widths;
+ int xorgi = 0, yorgi = 0;
+ XID oldPixel;
+ Spans spanRec;
+ int n;
+ PolyEdgeRec edge1, edge2;
+ int edgey1, edgey2;
+ Bool edgeleft1, edgeleft2;
+
+ if (isInt)
+ {
+ xorgi = leftFace ? leftFace->x : rightFace->x;
+ yorgi = leftFace ? leftFace->y : rightFace->y;
+ }
+ edgey1 = 65536;
+ edgey2 = 65536;
+ edge1.x = 0; /* not used, keep memory checkers happy */
+ edge1.dy = -1;
+ edge2.x = 0; /* not used, keep memory checkers happy */
+ edge2.dy = -1;
+ edgeleft1 = FALSE;
+ edgeleft2 = FALSE;
+ if ((pGC->lineStyle != LineSolid || pGC->lineWidth > 2) &&
+ ((pGC->capStyle == CapRound && pGC->joinStyle != JoinRound) ||
+ (pGC->joinStyle == JoinRound && pGC->capStyle == CapButt)))
+ {
+ if (isInt)
+ {
+ xorg = (double) xorgi;
+ yorg = (double) yorgi;
+ }
+ if (leftFace && rightFace)
+ {
+ miRoundJoinClip (leftFace, rightFace, &edge1, &edge2,
+ &edgey1, &edgey2, &edgeleft1, &edgeleft2);
+ }
+ else if (leftFace)
+ {
+ edgey1 = miRoundCapClip (leftFace, isInt, &edge1, &edgeleft1);
+ }
+ else if (rightFace)
+ {
+ edgey2 = miRoundCapClip (rightFace, isInt, &edge2, &edgeleft2);
+ }
+ isInt = FALSE;
+ }
+ if (!spanData)
+ {
+ points = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * pGC->lineWidth);
+ if (!points)
+ return;
+ widths = (int *)ALLOCATE_LOCAL(sizeof(int) * pGC->lineWidth);
+ if (!widths)
+ {
+ DEALLOCATE_LOCAL(points);
+ return;
+ }
+ oldPixel = pGC->fgPixel;
+ if (pixel != oldPixel)
+ {
+ XID tmpPixel = (XID)pixel;
+ DoChangeGC(pGC, GCForeground, &tmpPixel, FALSE);
+ ValidateGC (pDraw, pGC);
+ }
+ }
+ else
+ {
+ points = (DDXPointPtr) xalloc (pGC->lineWidth * sizeof (DDXPointRec));
+ if (!points)
+ return;
+ widths = (int *) xalloc (pGC->lineWidth * sizeof (int));
+ if (!widths)
+ {
+ xfree (points);
+ return;
+ }
+ spanRec.points = points;
+ spanRec.widths = widths;
+ }
+ if (isInt)
+ n = miLineArcI(pDraw, pGC, xorgi, yorgi, points, widths);
+ else
+ n = miLineArcD(pDraw, pGC, xorg, yorg, points, widths,
+ &edge1, edgey1, edgeleft1,
+ &edge2, edgey2, edgeleft2);
+
+ if (!spanData)
+ {
+ (*pGC->ops->FillSpans)(pDraw, pGC, n, points, widths, TRUE);
+ DEALLOCATE_LOCAL(widths);
+ DEALLOCATE_LOCAL(points);
+ if (pixel != oldPixel)
+ {
+ DoChangeGC(pGC, GCForeground, &oldPixel, FALSE);
+ ValidateGC (pDraw, pGC);
+ }
+ }
+ else
+ {
+ spanRec.count = n;
+ AppendSpanGroup (pGC, pixel, &spanRec, spanData)
+ }
+}
+
+void
+miLineProjectingCap (pDrawable, pGC, pixel, spanData, face, isLeft, xorg, yorg, isInt)
+ DrawablePtr pDrawable;
+ register GCPtr pGC;
+ unsigned long pixel;
+ SpanDataPtr spanData;
+ register LineFacePtr face;
+ Bool isLeft;
+ double xorg, yorg;
+ Bool isInt;
+{
+ int xorgi = 0, yorgi = 0;
+ int lw;
+ PolyEdgeRec lefts[2], rights[2];
+ int lefty, righty, topy, bottomy;
+ PolyEdgePtr left, right;
+ PolyEdgePtr top, bottom;
+ double xa,ya;
+ double k;
+ double xap, yap;
+ int dx, dy;
+ double projectXoff, projectYoff;
+ double maxy;
+ int finaly;
+
+ if (isInt)
+ {
+ xorgi = face->x;
+ yorgi = face->y;
+ }
+ lw = pGC->lineWidth;
+ dx = face->dx;
+ dy = face->dy;
+ k = face->k;
+ if (dy == 0)
+ {
+ lefts[0].height = lw;
+ lefts[0].x = xorgi;
+ if (isLeft)
+ lefts[0].x -= (lw >> 1);
+ lefts[0].stepx = 0;
+ lefts[0].signdx = 1;
+ lefts[0].e = -lw;
+ lefts[0].dx = 0;
+ lefts[0].dy = lw;
+ rights[0].height = lw;
+ rights[0].x = xorgi;
+ if (!isLeft)
+ rights[0].x += ((lw + 1) >> 1);
+ rights[0].stepx = 0;
+ rights[0].signdx = 1;
+ rights[0].e = -lw;
+ rights[0].dx = 0;
+ rights[0].dy = lw;
+ miFillPolyHelper (pDrawable, pGC, pixel, spanData, yorgi - (lw >> 1), lw,
+ lefts, rights, 1, 1);
+ }
+ else if (dx == 0)
+ {
+ if (dy < 0) {
+ dy = -dy;
+ isLeft = !isLeft;
+ }
+ topy = yorgi;
+ bottomy = yorgi + dy;
+ if (isLeft)
+ topy -= (lw >> 1);
+ else
+ bottomy += (lw >> 1);
+ lefts[0].height = bottomy - topy;
+ lefts[0].x = xorgi - (lw >> 1);
+ lefts[0].stepx = 0;
+ lefts[0].signdx = 1;
+ lefts[0].e = -dy;
+ lefts[0].dx = dx;
+ lefts[0].dy = dy;
+
+ rights[0].height = bottomy - topy;
+ rights[0].x = lefts[0].x + (lw-1);
+ rights[0].stepx = 0;
+ rights[0].signdx = 1;
+ rights[0].e = -dy;
+ rights[0].dx = dx;
+ rights[0].dy = dy;
+ miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy, bottomy - topy, lefts, rights, 1, 1);
+ }
+ else
+ {
+ xa = face->xa;
+ ya = face->ya;
+ projectXoff = -ya;
+ projectYoff = xa;
+ if (dx < 0)
+ {
+ right = &rights[1];
+ left = &lefts[0];
+ top = &rights[0];
+ bottom = &lefts[1];
+ }
+ else
+ {
+ right = &rights[0];
+ left = &lefts[1];
+ top = &lefts[0];
+ bottom = &rights[1];
+ }
+ if (isLeft)
+ {
+ righty = miPolyBuildEdge (xa, ya,
+ k, dx, dy, xorgi, yorgi, 0, right);
+
+ xa = -xa;
+ ya = -ya;
+ k = -k;
+ lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
+ k, dx, dy, xorgi, yorgi, 1, left);
+ if (dx > 0)
+ {
+ ya = -ya;
+ xa = -xa;
+ }
+ xap = xa - projectXoff;
+ yap = ya - projectYoff;
+ topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
+ -dy, dx, xorgi, yorgi, dx > 0, top);
+ bottomy = miPolyBuildEdge (xa, ya,
+ 0.0, -dy, dx, xorgi, yorgi, dx < 0, bottom);
+ maxy = -ya;
+ }
+ else
+ {
+ righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
+ k, dx, dy, xorgi, yorgi, 0, right);
+
+ xa = -xa;
+ ya = -ya;
+ k = -k;
+ lefty = miPolyBuildEdge (xa, ya,
+ k, dx, dy, xorgi, yorgi, 1, left);
+ if (dx > 0)
+ {
+ ya = -ya;
+ xa = -xa;
+ }
+ xap = xa - projectXoff;
+ yap = ya - projectYoff;
+ topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, xorgi, xorgi, dx > 0, top);
+ bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
+ -dy, dx, xorgi, xorgi, dx < 0, bottom);
+ maxy = -ya + projectYoff;
+ }
+ finaly = ICEIL(maxy) + yorgi;
+ if (dx < 0)
+ {
+ left->height = bottomy - lefty;
+ right->height = finaly - righty;
+ top->height = righty - topy;
+ }
+ else
+ {
+ right->height = bottomy - righty;
+ left->height = finaly - lefty;
+ top->height = lefty - topy;
+ }
+ bottom->height = finaly - bottomy;
+ miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy,
+ bottom->height + bottomy - topy, lefts, rights, 2, 2);
+ }
+}
+
+static void
+miWideSegment (
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ unsigned long pixel,
+ SpanDataPtr spanData,
+ register int x1,
+ register int y1,
+ register int x2,
+ register int y2,
+ Bool projectLeft,
+ Bool projectRight,
+ register LineFacePtr leftFace,
+ register LineFacePtr rightFace)
+{
+ double l, L, r;
+ double xa, ya;
+ double projectXoff = 0.0, projectYoff = 0.0;
+ double k;
+ double maxy;
+ int x, y;
+ int dx, dy;
+ int finaly;
+ PolyEdgePtr left, right;
+ PolyEdgePtr top, bottom;
+ int lefty, righty, topy, bottomy;
+ int signdx;
+ PolyEdgeRec lefts[2], rights[2];
+ LineFacePtr tface;
+ int lw = pGC->lineWidth;
+
+ /* draw top-to-bottom always */
+ if (y2 < y1 || (y2 == y1 && x2 < x1))
+ {
+ x = x1;
+ x1 = x2;
+ x2 = x;
+
+ y = y1;
+ y1 = y2;
+ y2 = y;
+
+ x = projectLeft;
+ projectLeft = projectRight;
+ projectRight = x;
+
+ tface = leftFace;
+ leftFace = rightFace;
+ rightFace = tface;
+ }
+
+ dy = y2 - y1;
+ signdx = 1;
+ dx = x2 - x1;
+ if (dx < 0)
+ signdx = -1;
+
+ leftFace->x = x1;
+ leftFace->y = y1;
+ leftFace->dx = dx;
+ leftFace->dy = dy;
+
+ rightFace->x = x2;
+ rightFace->y = y2;
+ rightFace->dx = -dx;
+ rightFace->dy = -dy;
+
+ if (dy == 0)
+ {
+ rightFace->xa = 0;
+ rightFace->ya = (double) lw / 2.0;
+ rightFace->k = -(double) (lw * dx) / 2.0;
+ leftFace->xa = 0;
+ leftFace->ya = -rightFace->ya;
+ leftFace->k = rightFace->k;
+ x = x1;
+ if (projectLeft)
+ x -= (lw >> 1);
+ y = y1 - (lw >> 1);
+ dx = x2 - x;
+ if (projectRight)
+ dx += ((lw + 1) >> 1);
+ dy = lw;
+ miFillRectPolyHelper (pDrawable, pGC, pixel, spanData,
+ x, y, dx, dy);
+ }
+ else if (dx == 0)
+ {
+ leftFace->xa = (double) lw / 2.0;
+ leftFace->ya = 0;
+ leftFace->k = (double) (lw * dy) / 2.0;
+ rightFace->xa = -leftFace->xa;
+ rightFace->ya = 0;
+ rightFace->k = leftFace->k;
+ y = y1;
+ if (projectLeft)
+ y -= lw >> 1;
+ x = x1 - (lw >> 1);
+ dy = y2 - y;
+ if (projectRight)
+ dy += ((lw + 1) >> 1);
+ dx = lw;
+ miFillRectPolyHelper (pDrawable, pGC, pixel, spanData,
+ x, y, dx, dy);
+ }
+ else
+ {
+ l = ((double) lw) / 2.0;
+ L = hypot ((double) dx, (double) dy);
+
+ if (dx < 0)
+ {
+ right = &rights[1];
+ left = &lefts[0];
+ top = &rights[0];
+ bottom = &lefts[1];
+ }
+ else
+ {
+ right = &rights[0];
+ left = &lefts[1];
+ top = &lefts[0];
+ bottom = &rights[1];
+ }
+ r = l / L;
+
+ /* coord of upper bound at integral y */
+ ya = -r * dx;
+ xa = r * dy;
+
+ if (projectLeft | projectRight)
+ {
+ projectXoff = -ya;
+ projectYoff = xa;
+ }
+
+ /* xa * dy - ya * dx */
+ k = l * L;
+
+ leftFace->xa = xa;
+ leftFace->ya = ya;
+ leftFace->k = k;
+ rightFace->xa = -xa;
+ rightFace->ya = -ya;
+ rightFace->k = k;
+
+ if (projectLeft)
+ righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
+ k, dx, dy, x1, y1, 0, right);
+ else
+ righty = miPolyBuildEdge (xa, ya,
+ k, dx, dy, x1, y1, 0, right);
+
+ /* coord of lower bound at integral y */
+ ya = -ya;
+ xa = -xa;
+
+ /* xa * dy - ya * dx */
+ k = - k;
+
+ if (projectLeft)
+ lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
+ k, dx, dy, x1, y1, 1, left);
+ else
+ lefty = miPolyBuildEdge (xa, ya,
+ k, dx, dy, x1, y1, 1, left);
+
+ /* coord of top face at integral y */
+
+ if (signdx > 0)
+ {
+ ya = -ya;
+ xa = -xa;
+ }
+
+ if (projectLeft)
+ {
+ double xap = xa - projectXoff;
+ double yap = ya - projectYoff;
+ topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
+ -dy, dx, x1, y1, dx > 0, top);
+ }
+ else
+ topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, x1, y1, dx > 0, top);
+
+ /* coord of bottom face at integral y */
+
+ if (projectRight)
+ {
+ double xap = xa + projectXoff;
+ double yap = ya + projectYoff;
+ bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
+ -dy, dx, x2, y2, dx < 0, bottom);
+ maxy = -ya + projectYoff;
+ }
+ else
+ {
+ bottomy = miPolyBuildEdge (xa, ya,
+ 0.0, -dy, dx, x2, y2, dx < 0, bottom);
+ maxy = -ya;
+ }
+
+ finaly = ICEIL (maxy) + y2;
+
+ if (dx < 0)
+ {
+ left->height = bottomy - lefty;
+ right->height = finaly - righty;
+ top->height = righty - topy;
+ }
+ else
+ {
+ right->height = bottomy - righty;
+ left->height = finaly - lefty;
+ top->height = lefty - topy;
+ }
+ bottom->height = finaly - bottomy;
+ miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy,
+ bottom->height + bottomy - topy, lefts, rights, 2, 2);
+ }
+}
+
+SpanDataPtr
+miSetupSpanData (pGC, spanData, npt)
+ register GCPtr pGC;
+ SpanDataPtr spanData;
+ int npt;
+{
+ if ((npt < 3 && pGC->capStyle != CapRound) || miSpansEasyRop(pGC->alu))
+ return (SpanDataPtr) NULL;
+ if (pGC->lineStyle == LineDoubleDash)
+ miInitSpanGroup (&spanData->bgGroup);
+ miInitSpanGroup (&spanData->fgGroup);
+ return spanData;
+}
+
+void
+miCleanupSpanData (pDrawable, pGC, spanData)
+ DrawablePtr pDrawable;
+ GCPtr pGC;
+ SpanDataPtr spanData;
+{
+ if (pGC->lineStyle == LineDoubleDash)
+ {
+ XID oldPixel, pixel;
+
+ pixel = pGC->bgPixel;
+ oldPixel = pGC->fgPixel;
+ if (pixel != oldPixel)
+ {
+ DoChangeGC (pGC, GCForeground, &pixel, FALSE);
+ ValidateGC (pDrawable, pGC);
+ }
+ miFillUniqueSpanGroup (pDrawable, pGC, &spanData->bgGroup);
+ miFreeSpanGroup (&spanData->bgGroup);
+ if (pixel != oldPixel)
+ {
+ DoChangeGC (pGC, GCForeground, &oldPixel, FALSE);
+ ValidateGC (pDrawable, pGC);
+ }
+ }
+ miFillUniqueSpanGroup (pDrawable, pGC, &spanData->fgGroup);
+ miFreeSpanGroup (&spanData->fgGroup);
+}
+
+_X_EXPORT void
+miWideLine (pDrawable, pGC, mode, npt, pPts)
+ DrawablePtr pDrawable;
+ register GCPtr pGC;
+ int mode;
+ register int npt;
+ register DDXPointPtr pPts;
+{
+ int x1, y1, x2, y2;
+ SpanDataRec spanDataRec;
+ SpanDataPtr spanData;
+ unsigned long pixel;
+ Bool projectLeft, projectRight;
+ LineFaceRec leftFace, rightFace, prevRightFace;
+ LineFaceRec firstFace;
+ register int first;
+ Bool somethingDrawn = FALSE;
+ Bool selfJoin;
+
+ spanData = miSetupSpanData (pGC, &spanDataRec, npt);
+ pixel = pGC->fgPixel;
+ x2 = pPts->x;
+ y2 = pPts->y;
+ first = TRUE;
+ selfJoin = FALSE;
+ if (npt > 1)
+ {
+ if (mode == CoordModePrevious)
+ {
+ int nptTmp;
+ DDXPointPtr pPtsTmp;
+
+ x1 = x2;
+ y1 = y2;
+ nptTmp = npt;
+ pPtsTmp = pPts + 1;
+ while (--nptTmp)
+ {
+ x1 += pPtsTmp->x;
+ y1 += pPtsTmp->y;
+ ++pPtsTmp;
+ }
+ if (x2 == x1 && y2 == y1)
+ selfJoin = TRUE;
+ }
+ else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y)
+ {
+ selfJoin = TRUE;
+ }
+ }
+ projectLeft = pGC->capStyle == CapProjecting && !selfJoin;
+ projectRight = FALSE;
+ while (--npt)
+ {
+ x1 = x2;
+ y1 = y2;
+ ++pPts;
+ x2 = pPts->x;
+ y2 = pPts->y;
+ if (mode == CoordModePrevious)
+ {
+ x2 += x1;
+ y2 += y1;
+ }
+ if (x1 != x2 || y1 != y2)
+ {
+ somethingDrawn = TRUE;
+ if (npt == 1 && pGC->capStyle == CapProjecting && !selfJoin)
+ projectRight = TRUE;
+ miWideSegment (pDrawable, pGC, pixel, spanData, x1, y1, x2, y2,
+ projectLeft, projectRight, &leftFace, &rightFace);
+ if (first)
+ {
+ if (selfJoin)
+ firstFace = leftFace;
+ else if (pGC->capStyle == CapRound)
+ {
+ if (pGC->lineWidth == 1 && !spanData)
+ miLineOnePoint (pDrawable, pGC, pixel, spanData, x1, y1);
+ else
+ miLineArc (pDrawable, pGC, pixel, spanData,
+ &leftFace, (LineFacePtr) NULL,
+ (double)0.0, (double)0.0,
+ TRUE);
+ }
+ }
+ else
+ {
+ miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace,
+ &prevRightFace);
+ }
+ prevRightFace = rightFace;
+ first = FALSE;
+ projectLeft = FALSE;
+ }
+ if (npt == 1 && somethingDrawn)
+ {
+ if (selfJoin)
+ miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace,
+ &rightFace);
+ else if (pGC->capStyle == CapRound)
+ {
+ if (pGC->lineWidth == 1 && !spanData)
+ miLineOnePoint (pDrawable, pGC, pixel, spanData, x2, y2);
+ else
+ miLineArc (pDrawable, pGC, pixel, spanData,
+ (LineFacePtr) NULL, &rightFace,
+ (double)0.0, (double)0.0,
+ TRUE);
+ }
+ }
+ }
+ /* handle crock where all points are coincedent */
+ if (!somethingDrawn)
+ {
+ projectLeft = pGC->capStyle == CapProjecting;
+ miWideSegment (pDrawable, pGC, pixel, spanData,
+ x2, y2, x2, y2, projectLeft, projectLeft,
+ &leftFace, &rightFace);
+ if (pGC->capStyle == CapRound)
+ {
+ miLineArc (pDrawable, pGC, pixel, spanData,
+ &leftFace, (LineFacePtr) NULL,
+ (double)0.0, (double)0.0,
+ TRUE);
+ rightFace.dx = -1; /* sleezy hack to make it work */
+ miLineArc (pDrawable, pGC, pixel, spanData,
+ (LineFacePtr) NULL, &rightFace,
+ (double)0.0, (double)0.0,
+ TRUE);
+ }
+ }
+ if (spanData)
+ miCleanupSpanData (pDrawable, pGC, spanData);
+}
+
+#define V_TOP 0
+#define V_RIGHT 1
+#define V_BOTTOM 2
+#define V_LEFT 3
+
+static void
+miWideDashSegment (
+ DrawablePtr pDrawable,
+ register GCPtr pGC,
+ SpanDataPtr spanData,
+ int *pDashOffset,
+ int *pDashIndex,
+ int x1,
+ int y1,
+ int x2,
+ int y2,
+ Bool projectLeft,
+ Bool projectRight,
+ LineFacePtr leftFace,
+ LineFacePtr rightFace)
+{
+ int dashIndex, dashRemain;
+ unsigned char *pDash;
+ double L, l;
+ double k;
+ PolyVertexRec vertices[4];
+ PolyVertexRec saveRight, saveBottom;
+ PolySlopeRec slopes[4];
+ PolyEdgeRec left[2], right[2];
+ LineFaceRec lcapFace, rcapFace;
+ int nleft, nright;
+ int h;
+ int y;
+ int dy, dx;
+ unsigned long pixel;
+ double LRemain;
+ double r;
+ double rdx, rdy;
+ double dashDx, dashDy;
+ double saveK = 0.0;
+ Bool first = TRUE;
+ double lcenterx, lcentery, rcenterx = 0.0, rcentery = 0.0;
+ unsigned long fgPixel, bgPixel;
+
+ dx = x2 - x1;
+ dy = y2 - y1;
+ dashIndex = *pDashIndex;
+ pDash = pGC->dash;
+ dashRemain = pDash[dashIndex] - *pDashOffset;
+ fgPixel = pGC->fgPixel;
+ bgPixel = pGC->bgPixel;
+ if (pGC->fillStyle == FillOpaqueStippled ||
+ pGC->fillStyle == FillTiled)
+ {
+ bgPixel = fgPixel;
+ }
+
+ l = ((double) pGC->lineWidth) / 2.0;
+ if (dx == 0)
+ {
+ L = dy;
+ rdx = 0;
+ rdy = l;
+ if (dy < 0)
+ {
+ L = -dy;
+ rdy = -l;
+ }
+ }
+ else if (dy == 0)
+ {
+ L = dx;
+ rdx = l;
+ rdy = 0;
+ if (dx < 0)
+ {
+ L = -dx;
+ rdx = -l;
+ }
+ }
+ else
+ {
+ L = hypot ((double) dx, (double) dy);
+ r = l / L;
+
+ rdx = r * dx;
+ rdy = r * dy;
+ }
+ k = l * L;
+ LRemain = L;
+ /* All position comments are relative to a line with dx and dy > 0,
+ * but the code does not depend on this */
+ /* top */
+ slopes[V_TOP].dx = dx;
+ slopes[V_TOP].dy = dy;
+ slopes[V_TOP].k = k;
+ /* right */
+ slopes[V_RIGHT].dx = -dy;
+ slopes[V_RIGHT].dy = dx;
+ slopes[V_RIGHT].k = 0;
+ /* bottom */
+ slopes[V_BOTTOM].dx = -dx;
+ slopes[V_BOTTOM].dy = -dy;
+ slopes[V_BOTTOM].k = k;
+ /* left */
+ slopes[V_LEFT].dx = dy;
+ slopes[V_LEFT].dy = -dx;
+ slopes[V_LEFT].k = 0;
+
+ /* preload the start coordinates */
+ vertices[V_RIGHT].x = vertices[V_TOP].x = rdy;
+ vertices[V_RIGHT].y = vertices[V_TOP].y = -rdx;
+
+ vertices[V_BOTTOM].x = vertices[V_LEFT].x = -rdy;
+ vertices[V_BOTTOM].y = vertices[V_LEFT].y = rdx;
+
+ if (projectLeft)
+ {
+ vertices[V_TOP].x -= rdx;
+ vertices[V_TOP].y -= rdy;
+
+ vertices[V_LEFT].x -= rdx;
+ vertices[V_LEFT].y -= rdy;
+
+ slopes[V_LEFT].k = rdx * dx + rdy * dy;
+ }
+
+ lcenterx = x1;
+ lcentery = y1;
+
+ if (pGC->capStyle == CapRound)
+ {
+ lcapFace.dx = dx;
+ lcapFace.dy = dy;
+ lcapFace.x = x1;
+ lcapFace.y = y1;
+
+ rcapFace.dx = -dx;
+ rcapFace.dy = -dy;
+ rcapFace.x = x1;
+ rcapFace.y = y1;
+ }
+ while (LRemain > dashRemain)
+ {
+ dashDx = (dashRemain * dx) / L;
+ dashDy = (dashRemain * dy) / L;
+
+ rcenterx = lcenterx + dashDx;
+ rcentery = lcentery + dashDy;
+
+ vertices[V_RIGHT].x += dashDx;
+ vertices[V_RIGHT].y += dashDy;
+
+ vertices[V_BOTTOM].x += dashDx;
+ vertices[V_BOTTOM].y += dashDy;
+
+ slopes[V_RIGHT].k = vertices[V_RIGHT].x * dx + vertices[V_RIGHT].y * dy;
+
+ if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1))
+ {
+ if (pGC->lineStyle == LineOnOffDash &&
+ pGC->capStyle == CapProjecting)
+ {
+ saveRight = vertices[V_RIGHT];
+ saveBottom = vertices[V_BOTTOM];
+ saveK = slopes[V_RIGHT].k;
+
+ if (!first)
+ {
+ vertices[V_TOP].x -= rdx;
+ vertices[V_TOP].y -= rdy;
+
+ vertices[V_LEFT].x -= rdx;
+ vertices[V_LEFT].y -= rdy;
+
+ slopes[V_LEFT].k = vertices[V_LEFT].x *
+ slopes[V_LEFT].dy -
+ vertices[V_LEFT].y *
+ slopes[V_LEFT].dx;
+ }
+
+ vertices[V_RIGHT].x += rdx;
+ vertices[V_RIGHT].y += rdy;
+
+ vertices[V_BOTTOM].x += rdx;
+ vertices[V_BOTTOM].y += rdy;
+
+ slopes[V_RIGHT].k = vertices[V_RIGHT].x *
+ slopes[V_RIGHT].dy -
+ vertices[V_RIGHT].y *
+ slopes[V_RIGHT].dx;
+ }
+ y = miPolyBuildPoly (vertices, slopes, 4, x1, y1,
+ left, right, &nleft, &nright, &h);
+ pixel = (dashIndex & 1) ? bgPixel : fgPixel;
+ miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright);
+
+ if (pGC->lineStyle == LineOnOffDash)
+ {
+ switch (pGC->capStyle)
+ {
+ case CapProjecting:
+ vertices[V_BOTTOM] = saveBottom;
+ vertices[V_RIGHT] = saveRight;
+ slopes[V_RIGHT].k = saveK;
+ break;
+ case CapRound:
+ if (!first)
+ {
+ if (dx < 0)
+ {
+ lcapFace.xa = -vertices[V_LEFT].x;
+ lcapFace.ya = -vertices[V_LEFT].y;
+ lcapFace.k = slopes[V_LEFT].k;
+ }
+ else
+ {
+ lcapFace.xa = vertices[V_TOP].x;
+ lcapFace.ya = vertices[V_TOP].y;
+ lcapFace.k = -slopes[V_LEFT].k;
+ }
+ miLineArc (pDrawable, pGC, pixel, spanData,
+ &lcapFace, (LineFacePtr) NULL,
+ lcenterx, lcentery, FALSE);
+ }
+ if (dx < 0)
+ {
+ rcapFace.xa = vertices[V_BOTTOM].x;
+ rcapFace.ya = vertices[V_BOTTOM].y;
+ rcapFace.k = slopes[V_RIGHT].k;
+ }
+ else
+ {
+ rcapFace.xa = -vertices[V_RIGHT].x;
+ rcapFace.ya = -vertices[V_RIGHT].y;
+ rcapFace.k = -slopes[V_RIGHT].k;
+ }
+ miLineArc (pDrawable, pGC, pixel, spanData,
+ (LineFacePtr) NULL, &rcapFace,
+ rcenterx, rcentery, FALSE);
+ break;
+ }
+ }
+ }
+ LRemain -= dashRemain;
+ ++dashIndex;
+ if (dashIndex == pGC->numInDashList)
+ dashIndex = 0;
+ dashRemain = pDash[dashIndex];
+
+ lcenterx = rcenterx;
+ lcentery = rcentery;
+
+ vertices[V_TOP] = vertices[V_RIGHT];
+ vertices[V_LEFT] = vertices[V_BOTTOM];
+ slopes[V_LEFT].k = -slopes[V_RIGHT].k;
+ first = FALSE;
+ }
+
+ if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1))
+ {
+ vertices[V_TOP].x -= dx;
+ vertices[V_TOP].y -= dy;
+
+ vertices[V_LEFT].x -= dx;
+ vertices[V_LEFT].y -= dy;
+
+ vertices[V_RIGHT].x = rdy;
+ vertices[V_RIGHT].y = -rdx;
+
+ vertices[V_BOTTOM].x = -rdy;
+ vertices[V_BOTTOM].y = rdx;
+
+
+ if (projectRight)
+ {
+ vertices[V_RIGHT].x += rdx;
+ vertices[V_RIGHT].y += rdy;
+
+ vertices[V_BOTTOM].x += rdx;
+ vertices[V_BOTTOM].y += rdy;
+ slopes[V_RIGHT].k = vertices[V_RIGHT].x *
+ slopes[V_RIGHT].dy -
+ vertices[V_RIGHT].y *
+ slopes[V_RIGHT].dx;
+ }
+ else
+ slopes[V_RIGHT].k = 0;
+
+ if (!first && pGC->lineStyle == LineOnOffDash &&
+ pGC->capStyle == CapProjecting)
+ {
+ vertices[V_TOP].x -= rdx;
+ vertices[V_TOP].y -= rdy;
+
+ vertices[V_LEFT].x -= rdx;
+ vertices[V_LEFT].y -= rdy;
+ slopes[V_LEFT].k = vertices[V_LEFT].x *
+ slopes[V_LEFT].dy -
+ vertices[V_LEFT].y *
+ slopes[V_LEFT].dx;
+ }
+ else
+ slopes[V_LEFT].k += dx * dx + dy * dy;
+
+
+ y = miPolyBuildPoly (vertices, slopes, 4, x2, y2,
+ left, right, &nleft, &nright, &h);
+
+ pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel;
+ miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright);
+ if (!first && pGC->lineStyle == LineOnOffDash &&
+ pGC->capStyle == CapRound)
+ {
+ lcapFace.x = x2;
+ lcapFace.y = y2;
+ if (dx < 0)
+ {
+ lcapFace.xa = -vertices[V_LEFT].x;
+ lcapFace.ya = -vertices[V_LEFT].y;
+ lcapFace.k = slopes[V_LEFT].k;
+ }
+ else
+ {
+ lcapFace.xa = vertices[V_TOP].x;
+ lcapFace.ya = vertices[V_TOP].y;
+ lcapFace.k = -slopes[V_LEFT].k;
+ }
+ miLineArc (pDrawable, pGC, pixel, spanData,
+ &lcapFace, (LineFacePtr) NULL,
+ rcenterx, rcentery, FALSE);
+ }
+ }
+ dashRemain = ((double) dashRemain) - LRemain;
+ if (dashRemain == 0)
+ {
+ dashIndex++;
+ if (dashIndex == pGC->numInDashList)
+ dashIndex = 0;
+ dashRemain = pDash[dashIndex];
+ }
+
+ leftFace->x = x1;
+ leftFace->y = y1;
+ leftFace->dx = dx;
+ leftFace->dy = dy;
+ leftFace->xa = rdy;
+ leftFace->ya = -rdx;
+ leftFace->k = k;
+
+ rightFace->x = x2;
+ rightFace->y = y2;
+ rightFace->dx = -dx;
+ rightFace->dy = -dy;
+ rightFace->xa = -rdy;
+ rightFace->ya = rdx;
+ rightFace->k = k;
+
+ *pDashIndex = dashIndex;
+ *pDashOffset = pDash[dashIndex] - dashRemain;
+}
+
+_X_EXPORT void
+miWideDash (pDrawable, pGC, mode, npt, pPts)
+ DrawablePtr pDrawable;
+ register GCPtr pGC;
+ int mode;
+ register int npt;
+ register DDXPointPtr pPts;
+{
+ int x1, y1, x2, y2;
+ unsigned long pixel;
+ Bool projectLeft, projectRight;
+ LineFaceRec leftFace, rightFace, prevRightFace;
+ LineFaceRec firstFace;
+ int first;
+ int dashIndex, dashOffset;
+ register int prevDashIndex;
+ SpanDataRec spanDataRec;
+ SpanDataPtr spanData;
+ Bool somethingDrawn = FALSE;
+ Bool selfJoin;
+ Bool endIsFg = FALSE, startIsFg = FALSE;
+ Bool firstIsFg = FALSE, prevIsFg = FALSE;
+
+#if 0
+ /* XXX backward compatibility */
+ if (pGC->lineWidth == 0)
+ {
+ miZeroDashLine (pDrawable, pGC, mode, npt, pPts);
+ return;
+ }
+#endif
+ if (pGC->lineStyle == LineDoubleDash &&
+ (pGC->fillStyle == FillOpaqueStippled || pGC->fillStyle == FillTiled))
+ {
+ miWideLine (pDrawable, pGC, mode, npt, pPts);
+ return;
+ }
+ if (npt == 0)
+ return;
+ spanData = miSetupSpanData (pGC, &spanDataRec, npt);
+ x2 = pPts->x;
+ y2 = pPts->y;
+ first = TRUE;
+ selfJoin = FALSE;
+ if (mode == CoordModePrevious)
+ {
+ int nptTmp;
+ DDXPointPtr pPtsTmp;
+
+ x1 = x2;
+ y1 = y2;
+ nptTmp = npt;
+ pPtsTmp = pPts + 1;
+ while (--nptTmp)
+ {
+ x1 += pPtsTmp->x;
+ y1 += pPtsTmp->y;
+ ++pPtsTmp;
+ }
+ if (x2 == x1 && y2 == y1)
+ selfJoin = TRUE;
+ }
+ else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y)
+ {
+ selfJoin = TRUE;
+ }
+ projectLeft = pGC->capStyle == CapProjecting && !selfJoin;
+ projectRight = FALSE;
+ dashIndex = 0;
+ dashOffset = 0;
+ miStepDash ((int)pGC->dashOffset, &dashIndex,
+ pGC->dash, (int)pGC->numInDashList, &dashOffset);
+ while (--npt)
+ {
+ x1 = x2;
+ y1 = y2;
+ ++pPts;
+ x2 = pPts->x;
+ y2 = pPts->y;
+ if (mode == CoordModePrevious)
+ {
+ x2 += x1;
+ y2 += y1;
+ }
+ if (x1 != x2 || y1 != y2)
+ {
+ somethingDrawn = TRUE;
+ if (npt == 1 && pGC->capStyle == CapProjecting &&
+ (!selfJoin || !firstIsFg))
+ projectRight = TRUE;
+ prevDashIndex = dashIndex;
+ miWideDashSegment (pDrawable, pGC, spanData, &dashOffset, &dashIndex,
+ x1, y1, x2, y2,
+ projectLeft, projectRight, &leftFace, &rightFace);
+ startIsFg = !(prevDashIndex & 1);
+ endIsFg = (dashIndex & 1) ^ (dashOffset != 0);
+ if (pGC->lineStyle == LineDoubleDash || startIsFg)
+ {
+ pixel = startIsFg ? pGC->fgPixel : pGC->bgPixel;
+ if (first || (pGC->lineStyle == LineOnOffDash && !prevIsFg))
+ {
+ if (first && selfJoin)
+ {
+ firstFace = leftFace;
+ firstIsFg = startIsFg;
+ }
+ else if (pGC->capStyle == CapRound)
+ miLineArc (pDrawable, pGC, pixel, spanData,
+ &leftFace, (LineFacePtr) NULL,
+ (double)0.0, (double)0.0, TRUE);
+ }
+ else
+ {
+ miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace,
+ &prevRightFace);
+ }
+ }
+ prevRightFace = rightFace;
+ prevIsFg = endIsFg;
+ first = FALSE;
+ projectLeft = FALSE;
+ }
+ if (npt == 1 && somethingDrawn)
+ {
+ if (pGC->lineStyle == LineDoubleDash || endIsFg)
+ {
+ pixel = endIsFg ? pGC->fgPixel : pGC->bgPixel;
+ if (selfJoin && (pGC->lineStyle == LineDoubleDash || firstIsFg))
+ {
+ miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace,
+ &rightFace);
+ }
+ else
+ {
+ if (pGC->capStyle == CapRound)
+ miLineArc (pDrawable, pGC, pixel, spanData,
+ (LineFacePtr) NULL, &rightFace,
+ (double)0.0, (double)0.0, TRUE);
+ }
+ }
+ else
+ {
+ /* glue a cap to the start of the line if
+ * we're OnOffDash and ended on odd dash
+ */
+ if (selfJoin && firstIsFg)
+ {
+ pixel = pGC->fgPixel;
+ if (pGC->capStyle == CapProjecting)
+ miLineProjectingCap (pDrawable, pGC, pixel, spanData,
+ &firstFace, TRUE,
+ (double)0.0, (double)0.0, TRUE);
+ else if (pGC->capStyle == CapRound)
+ miLineArc (pDrawable, pGC, pixel, spanData,
+ &firstFace, (LineFacePtr) NULL,
+ (double)0.0, (double)0.0, TRUE);
+ }
+ }
+ }
+ }
+ /* handle crock where all points are coincident */
+ if (!somethingDrawn && (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)))
+ {
+ /* not the same as endIsFg computation above */
+ pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel;
+ switch (pGC->capStyle) {
+ case CapRound:
+ miLineArc (pDrawable, pGC, pixel, spanData,
+ (LineFacePtr) NULL, (LineFacePtr) NULL,
+ (double)x2, (double)y2,
+ FALSE);
+ break;
+ case CapProjecting:
+ x1 = pGC->lineWidth;
+ miFillRectPolyHelper (pDrawable, pGC, pixel, spanData,
+ x2 - (x1 >> 1), y2 - (x1 >> 1), x1, x1);
+ break;
+ }
+ }
+ if (spanData)
+ miCleanupSpanData (pDrawable, pGC, spanData);
+}
diff --git a/xserver/mi/miwideline.h b/xserver/mi/miwideline.h
new file mode 100644
index 000000000..8cfa63008
--- /dev/null
+++ b/xserver/mi/miwideline.h
@@ -0,0 +1,222 @@
+/*
+
+Copyright 1988, 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.
+
+*/
+
+/* Author: Keith Packard, MIT X Consortium */
+
+#include "mispans.h"
+#include "mifpoly.h" /* for ICEIL */
+
+/*
+ * interface data to span-merging polygon filler
+ */
+
+typedef struct _SpanData {
+ SpanGroup fgGroup, bgGroup;
+} SpanDataRec, *SpanDataPtr;
+
+#define AppendSpanGroup(pGC, pixel, spanPtr, spanData) { \
+ SpanGroup *group, *othergroup = NULL; \
+ if (pixel == pGC->fgPixel) \
+ { \
+ group = &spanData->fgGroup; \
+ if (pGC->lineStyle == LineDoubleDash) \
+ othergroup = &spanData->bgGroup; \
+ } \
+ else \
+ { \
+ group = &spanData->bgGroup; \
+ othergroup = &spanData->fgGroup; \
+ } \
+ miAppendSpans (group, othergroup, spanPtr); \
+}
+
+/*
+ * Polygon edge description for integer wide-line routines
+ */
+
+typedef struct _PolyEdge {
+ int height; /* number of scanlines to process */
+ int x; /* starting x coordinate */
+ int stepx; /* fixed integral dx */
+ int signdx; /* variable dx sign */
+ int e; /* initial error term */
+ int dy;
+ int dx;
+} PolyEdgeRec, *PolyEdgePtr;
+
+#define SQSECANT 108.856472512142 /* 1/sin^2(11/2) - miter limit constant */
+
+/*
+ * types for general polygon routines
+ */
+
+typedef struct _PolyVertex {
+ double x, y;
+} PolyVertexRec, *PolyVertexPtr;
+
+typedef struct _PolySlope {
+ int dx, dy;
+ double k; /* x0 * dy - y0 * dx */
+} PolySlopeRec, *PolySlopePtr;
+
+/*
+ * Line face description for caps/joins
+ */
+
+typedef struct _LineFace {
+ double xa, ya;
+ int dx, dy;
+ int x, y;
+ double k;
+} LineFaceRec, *LineFacePtr;
+
+/*
+ * macros for polygon fillers
+ */
+
+#define MIPOLYRELOADLEFT if (!left_height && left_count) { \
+ left_height = left->height; \
+ left_x = left->x; \
+ left_stepx = left->stepx; \
+ left_signdx = left->signdx; \
+ left_e = left->e; \
+ left_dy = left->dy; \
+ left_dx = left->dx; \
+ --left_count; \
+ ++left; \
+ }
+
+#define MIPOLYRELOADRIGHT if (!right_height && right_count) { \
+ right_height = right->height; \
+ right_x = right->x; \
+ right_stepx = right->stepx; \
+ right_signdx = right->signdx; \
+ right_e = right->e; \
+ right_dy = right->dy; \
+ right_dx = right->dx; \
+ --right_count; \
+ ++right; \
+ }
+
+#define MIPOLYSTEPLEFT left_x += left_stepx; \
+ left_e += left_dx; \
+ if (left_e > 0) \
+ { \
+ left_x += left_signdx; \
+ left_e -= left_dy; \
+ }
+
+#define MIPOLYSTEPRIGHT right_x += right_stepx; \
+ right_e += right_dx; \
+ if (right_e > 0) \
+ { \
+ right_x += right_signdx; \
+ right_e -= right_dy; \
+ }
+
+#define MILINESETPIXEL(pDrawable, pGC, pixel, oldPixel) { \
+ oldPixel = pGC->fgPixel; \
+ if (pixel != oldPixel) { \
+ DoChangeGC (pGC, GCForeground, (XID *) &pixel, FALSE); \
+ ValidateGC (pDrawable, pGC); \
+ } \
+}
+#define MILINERESETPIXEL(pDrawable, pGC, pixel, oldPixel) { \
+ if (pixel != oldPixel) { \
+ DoChangeGC (pGC, GCForeground, (XID *) &oldPixel, FALSE); \
+ ValidateGC (pDrawable, pGC); \
+ } \
+}
+
+extern void miFillPolyHelper(
+ DrawablePtr /*pDrawable*/,
+ GCPtr /*pGC*/,
+ unsigned long /*pixel*/,
+ SpanDataPtr /*spanData*/,
+ int /*y*/,
+ int /*overall_height*/,
+ PolyEdgePtr /*left*/,
+ PolyEdgePtr /*right*/,
+ int /*left_count*/,
+ int /*right_count*/
+);
+extern int miRoundJoinFace(
+ LineFacePtr /*face*/,
+ PolyEdgePtr /*edge*/,
+ Bool * /*leftEdge*/
+);
+
+extern void miRoundJoinClip(
+ LineFacePtr /*pLeft*/,
+ LineFacePtr /*pRight*/,
+ PolyEdgePtr /*edge1*/,
+ PolyEdgePtr /*edge2*/,
+ int * /*y1*/,
+ int * /*y2*/,
+ Bool * /*left1*/,
+ Bool * /*left2*/
+);
+
+extern int miRoundCapClip(
+ LineFacePtr /*face*/,
+ Bool /*isInt*/,
+ PolyEdgePtr /*edge*/,
+ Bool * /*leftEdge*/
+);
+
+extern void miLineProjectingCap(
+ DrawablePtr /*pDrawable*/,
+ GCPtr /*pGC*/,
+ unsigned long /*pixel*/,
+ SpanDataPtr /*spanData*/,
+ LineFacePtr /*face*/,
+ Bool /*isLeft*/,
+ double /*xorg*/,
+ double /*yorg*/,
+ Bool /*isInt*/
+);
+
+extern SpanDataPtr miSetupSpanData(
+ GCPtr /*pGC*/,
+ SpanDataPtr /*spanData*/,
+ int /*npt*/
+);
+
+extern void miCleanupSpanData(
+ DrawablePtr /*pDrawable*/,
+ GCPtr /*pGC*/,
+ SpanDataPtr /*spanData*/
+);
+
+extern int miPolyBuildEdge(double x0, double y0, double k, int dx, int dy,
+ int xi, int yi, int left, PolyEdgePtr edge);
+extern int miPolyBuildPoly(PolyVertexPtr vertices, PolySlopePtr slopes,
+ int count, int xi, int yi, PolyEdgePtr left,
+ PolyEdgePtr right, int *pnleft, int *pnright,
+ int *h);
+
diff --git a/xserver/mi/miwindow.c b/xserver/mi/miwindow.c
new file mode 100644
index 000000000..cd6bb8df3
--- /dev/null
+++ b/xserver/mi/miwindow.c
@@ -0,0 +1,1182 @@
+/***********************************************************
+
+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 "regionstr.h"
+#include "region.h"
+#include "mi.h"
+#include "windowstr.h"
+#include "scrnintstr.h"
+#include "pixmapstr.h"
+#include "mivalidate.h"
+
+_X_EXPORT void
+miClearToBackground(pWin, x, y, w, h, generateExposures)
+ WindowPtr pWin;
+ int x,y;
+ int w,h;
+ Bool generateExposures;
+{
+ BoxRec box;
+ RegionRec reg;
+ RegionPtr pBSReg = NullRegion;
+ ScreenPtr pScreen;
+ BoxPtr extents;
+ int x1, y1, x2, y2;
+
+ /* compute everything using ints to avoid overflow */
+
+ x1 = pWin->drawable.x + x;
+ y1 = pWin->drawable.y + y;
+ if (w)
+ x2 = x1 + (int) w;
+ else
+ x2 = x1 + (int) pWin->drawable.width - (int) x;
+ if (h)
+ y2 = y1 + h;
+ else
+ y2 = y1 + (int) pWin->drawable.height - (int) y;
+
+ extents = &pWin->clipList.extents;
+
+ /* clip the resulting rectangle to the window clipList extents. This
+ * makes sure that the result will fit in a box, given that the
+ * screen is < 32768 on a side.
+ */
+
+ if (x1 < extents->x1)
+ x1 = extents->x1;
+ if (x2 > extents->x2)
+ x2 = extents->x2;
+ if (y1 < extents->y1)
+ y1 = extents->y1;
+ if (y2 > extents->y2)
+ y2 = extents->y2;
+
+ if (x2 <= x1 || y2 <= y1)
+ {
+ x2 = x1 = 0;
+ y2 = y1 = 0;
+ }
+
+ box.x1 = x1;
+ box.x2 = x2;
+ box.y1 = y1;
+ box.y2 = y2;
+
+ pScreen = pWin->drawable.pScreen;
+ REGION_INIT(pScreen, &reg, &box, 1);
+ if (pWin->backStorage)
+ {
+ /*
+ * If the window has backing-store on, call through the
+ * ClearToBackground vector to handle the special semantics
+ * (i.e. things backing store is to be cleared out and
+ * an Expose event is to be generated for those areas in backing
+ * store if generateExposures is TRUE).
+ */
+ pBSReg = (* pScreen->ClearBackingStore)(pWin, x, y, w, h,
+ generateExposures);
+ }
+
+ REGION_INTERSECT(pScreen, &reg, &reg, &pWin->clipList);
+ if (generateExposures)
+ (*pScreen->WindowExposures)(pWin, &reg, pBSReg);
+ else if (pWin->backgroundState != None)
+ (*pScreen->PaintWindowBackground)(pWin, &reg, PW_BACKGROUND);
+ REGION_UNINIT(pScreen, &reg);
+ if (pBSReg)
+ REGION_DESTROY(pScreen, pBSReg);
+}
+
+/*
+ * For SaveUnders using backing-store. The idea is that when a window is mapped
+ * with saveUnder set TRUE, any windows it obscures will have its backing
+ * store turned on setting the DIXsaveUnder bit,
+ * The backing-store code must be written to allow for this
+ */
+
+/*-
+ *-----------------------------------------------------------------------
+ * miCheckSubSaveUnder --
+ * Check all the inferiors of a window for coverage by saveUnder
+ * windows. Called from ChangeSaveUnder and CheckSaveUnder.
+ * This code is very inefficient.
+ *
+ * Results:
+ * TRUE if any windows need to have backing-store removed.
+ *
+ * Side Effects:
+ * Windows may have backing-store turned on or off.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Bool
+miCheckSubSaveUnder(
+ register WindowPtr pParent, /* Parent to check */
+ WindowPtr pFirst, /* first reconfigured window */
+ RegionPtr pRegion) /* Initial area obscured by saveUnder */
+{
+ register WindowPtr pChild; /* Current child */
+ register ScreenPtr pScreen; /* Screen to use */
+ RegionRec SubRegion; /* Area of children obscured */
+ Bool res = FALSE; /* result */
+ Bool subInited=FALSE;/* SubRegion initialized */
+
+ pScreen = pParent->drawable.pScreen;
+ if ( (pChild = pParent->firstChild) )
+ {
+ /*
+ * build region above first changed window
+ */
+
+ for (; pChild != pFirst; pChild = pChild->nextSib)
+ if (pChild->viewable && pChild->saveUnder)
+ REGION_UNION(pScreen, pRegion, pRegion, &pChild->borderSize);
+
+ /*
+ * check region below and including first changed window
+ */
+
+ for (; pChild; pChild = pChild->nextSib)
+ {
+ if (pChild->viewable)
+ {
+ /*
+ * don't save under nephew/niece windows;
+ * use a separate region
+ */
+
+ if (pChild->firstChild)
+ {
+ if (!subInited)
+ {
+ REGION_NULL(pScreen, &SubRegion);
+ subInited = TRUE;
+ }
+ REGION_COPY(pScreen, &SubRegion, pRegion);
+ res |= miCheckSubSaveUnder(pChild, pChild->firstChild,
+ &SubRegion);
+ }
+ else
+ {
+ res |= miCheckSubSaveUnder(pChild, pChild->firstChild,
+ pRegion);
+ }
+
+ if (pChild->saveUnder)
+ REGION_UNION(pScreen, pRegion, pRegion, &pChild->borderSize);
+ }
+ }
+
+ if (subInited)
+ REGION_UNINIT(pScreen, &SubRegion);
+ }
+
+ /*
+ * Check the state of this window. DIX save unders are
+ * enabled for viewable windows with some client expressing
+ * exposure interest and which intersect the save under region
+ */
+
+ if (pParent->viewable &&
+ ((pParent->eventMask | wOtherEventMasks(pParent)) & ExposureMask) &&
+ REGION_NOTEMPTY(pScreen, &pParent->borderSize) &&
+ RECT_IN_REGION(pScreen, pRegion, REGION_EXTENTS(pScreen,
+ &pParent->borderSize)) != rgnOUT)
+ {
+ if (!pParent->DIXsaveUnder)
+ {
+ pParent->DIXsaveUnder = TRUE;
+ (*pScreen->ChangeWindowAttributes) (pParent, CWBackingStore);
+ }
+ }
+ else
+ {
+ if (pParent->DIXsaveUnder)
+ {
+ res = TRUE;
+ pParent->DIXsaveUnder = FALSE;
+ }
+ }
+ return res;
+}
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * miChangeSaveUnder --
+ * Change the save-under state of a tree of windows. Called when
+ * a window with saveUnder TRUE is mapped/unmapped/reconfigured.
+ *
+ * Results:
+ * TRUE if any windows need to have backing-store removed (which
+ * means that PostChangeSaveUnder needs to be called later to
+ * finish the job).
+ *
+ * Side Effects:
+ * Windows may have backing-store turned on or off.
+ *
+ *-----------------------------------------------------------------------
+ */
+Bool
+miChangeSaveUnder(pWin, first)
+ register WindowPtr pWin;
+ WindowPtr first; /* First window to check.
+ * Used when pWin was restacked */
+{
+ RegionRec rgn; /* Area obscured by saveUnder windows */
+ register ScreenPtr pScreen;
+ Bool res;
+
+ if (!deltaSaveUndersViewable && !numSaveUndersViewable)
+ return FALSE;
+ numSaveUndersViewable += deltaSaveUndersViewable;
+ deltaSaveUndersViewable = 0;
+ pScreen = pWin->drawable.pScreen;
+ REGION_NULL(pScreen, &rgn);
+ res = miCheckSubSaveUnder (pWin->parent,
+ pWin->saveUnder ? first : pWin->nextSib,
+ &rgn);
+ REGION_UNINIT(pScreen, &rgn);
+ return res;
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * miPostChangeSaveUnder --
+ * Actually turn backing-store off for those windows that no longer
+ * need to have it on.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Backing-store and SAVE_UNDER_CHANGE_BIT are turned off for those
+ * windows affected.
+ *
+ *-----------------------------------------------------------------------
+ */
+void
+miPostChangeSaveUnder(pWin, pFirst)
+ WindowPtr pWin;
+ WindowPtr pFirst;
+{
+ register WindowPtr pParent, pChild;
+ ChangeWindowAttributesProcPtr ChangeWindowAttributes;
+
+ if (!(pParent = pWin->parent))
+ return;
+ ChangeWindowAttributes = pParent->drawable.pScreen->ChangeWindowAttributes;
+ if (!pParent->DIXsaveUnder &&
+ (pParent->backingStore == NotUseful) && pParent->backStorage)
+ (*ChangeWindowAttributes)(pParent, CWBackingStore);
+ if (!(pChild = pFirst))
+ return;
+ while (1)
+ {
+ if (!pChild->DIXsaveUnder &&
+ (pChild->backingStore == NotUseful) && pChild->backStorage)
+ (*ChangeWindowAttributes)(pChild, CWBackingStore);
+ if (pChild->firstChild)
+ {
+ pChild = pChild->firstChild;
+ continue;
+ }
+ while (!pChild->nextSib)
+ {
+ pChild = pChild->parent;
+ if (pChild == pParent)
+ return;
+ }
+ pChild = pChild->nextSib;
+ }
+}
+
+void
+miMarkWindow(pWin)
+ register WindowPtr pWin;
+{
+ register ValidatePtr val;
+
+ if (pWin->valdata)
+ return;
+ val = (ValidatePtr)xnfalloc(sizeof(ValidateRec));
+ val->before.oldAbsCorner.x = pWin->drawable.x;
+ val->before.oldAbsCorner.y = pWin->drawable.y;
+ val->before.borderVisible = NullRegion;
+ val->before.resized = FALSE;
+ pWin->valdata = val;
+}
+
+Bool
+miMarkOverlappedWindows(pWin, pFirst, ppLayerWin)
+ WindowPtr pWin;
+ WindowPtr pFirst;
+ WindowPtr *ppLayerWin;
+{
+ register BoxPtr box;
+ register WindowPtr pChild, pLast;
+ Bool anyMarked = FALSE;
+ MarkWindowProcPtr MarkWindow = pWin->drawable.pScreen->MarkWindow;
+ ScreenPtr pScreen;
+
+ pScreen = pWin->drawable.pScreen;
+
+ /* single layered systems are easy */
+ if (ppLayerWin) *ppLayerWin = pWin;
+
+ if (pWin == pFirst)
+ {
+ /* Blindly mark pWin and all of its inferiors. This is a slight
+ * overkill if there are mapped windows that outside pWin's border,
+ * but it's better than wasting time on RectIn checks.
+ */
+ pChild = pWin;
+ while (1)
+ {
+ if (pChild->viewable)
+ {
+ if (REGION_BROKEN (pScreen, &pChild->winSize))
+ SetWinSize (pChild);
+ if (REGION_BROKEN (pScreen, &pChild->borderSize))
+ SetBorderSize (pChild);
+ (* MarkWindow)(pChild);
+ if (pChild->firstChild)
+ {
+ pChild = pChild->firstChild;
+ continue;
+ }
+ }
+ while (!pChild->nextSib && (pChild != pWin))
+ pChild = pChild->parent;
+ if (pChild == pWin)
+ break;
+ pChild = pChild->nextSib;
+ }
+ anyMarked = TRUE;
+ pFirst = pFirst->nextSib;
+ }
+ if ( (pChild = pFirst) )
+ {
+ box = REGION_EXTENTS(pChild->drawable.pScreen, &pWin->borderSize);
+ pLast = pChild->parent->lastChild;
+ while (1)
+ {
+ if (pChild->viewable)
+ {
+ if (REGION_BROKEN (pScreen, &pChild->winSize))
+ SetWinSize (pChild);
+ if (REGION_BROKEN (pScreen, &pChild->borderSize))
+ SetBorderSize (pChild);
+ if (RECT_IN_REGION(pScreen, &pChild->borderSize, box))
+ {
+ (* MarkWindow)(pChild);
+ anyMarked = TRUE;
+ if (pChild->firstChild)
+ {
+ pChild = pChild->firstChild;
+ continue;
+ }
+ }
+ }
+ while (!pChild->nextSib && (pChild != pLast))
+ pChild = pChild->parent;
+ if (pChild == pLast)
+ break;
+ pChild = pChild->nextSib;
+ }
+ }
+ if (anyMarked)
+ (* MarkWindow)(pWin->parent);
+ return anyMarked;
+}
+
+/*****
+ * miHandleValidateExposures(pWin)
+ * starting at pWin, draw background in any windows that have exposure
+ * regions, translate the regions, restore any backing store,
+ * and then send any regions still exposed to the client
+ *****/
+_X_EXPORT void
+miHandleValidateExposures(pWin)
+ WindowPtr pWin;
+{
+ register WindowPtr pChild;
+ register ValidatePtr val;
+ ScreenPtr pScreen;
+ WindowExposuresProcPtr WindowExposures;
+
+ pScreen = pWin->drawable.pScreen;
+
+ pChild = pWin;
+ WindowExposures = pChild->drawable.pScreen->WindowExposures;
+ while (1)
+ {
+ if ( (val = pChild->valdata) )
+ {
+ if (REGION_NOTEMPTY(pScreen, &val->after.borderExposed))
+ (*pChild->drawable.pScreen->PaintWindowBorder)(pChild,
+ &val->after.borderExposed,
+ PW_BORDER);
+ REGION_UNINIT(pScreen, &val->after.borderExposed);
+ (*WindowExposures)(pChild, &val->after.exposed, NullRegion);
+ REGION_UNINIT(pScreen, &val->after.exposed);
+ xfree(val);
+ pChild->valdata = (ValidatePtr)NULL;
+ if (pChild->firstChild)
+ {
+ pChild = pChild->firstChild;
+ continue;
+ }
+ }
+ while (!pChild->nextSib && (pChild != pWin))
+ pChild = pChild->parent;
+ if (pChild == pWin)
+ break;
+ pChild = pChild->nextSib;
+ }
+}
+
+void
+miMoveWindow(pWin, x, y, pNextSib, kind)
+ register WindowPtr pWin;
+ int x,y;
+ WindowPtr pNextSib;
+ VTKind kind;
+{
+ WindowPtr pParent;
+ Bool WasViewable = (Bool)(pWin->viewable);
+ short bw;
+ RegionPtr oldRegion = NULL;
+ DDXPointRec oldpt;
+ Bool anyMarked = FALSE;
+ register ScreenPtr pScreen;
+ WindowPtr windowToValidate;
+#ifdef DO_SAVE_UNDERS
+ Bool dosave = FALSE;
+#endif
+ WindowPtr pLayerWin;
+
+ /* if this is a root window, can't be moved */
+ if (!(pParent = pWin->parent))
+ return ;
+ pScreen = pWin->drawable.pScreen;
+ bw = wBorderWidth (pWin);
+
+ oldpt.x = pWin->drawable.x;
+ oldpt.y = pWin->drawable.y;
+ if (WasViewable)
+ {
+ oldRegion = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_COPY(pScreen, oldRegion, &pWin->borderClip);
+ anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, &pLayerWin);
+ }
+ pWin->origin.x = x + (int)bw;
+ pWin->origin.y = y + (int)bw;
+ x = pWin->drawable.x = pParent->drawable.x + x + (int)bw;
+ y = pWin->drawable.y = pParent->drawable.y + y + (int)bw;
+
+ SetWinSize (pWin);
+ SetBorderSize (pWin);
+
+ (*pScreen->PositionWindow)(pWin, x, y);
+
+ windowToValidate = MoveWindowInStack(pWin, pNextSib);
+
+ ResizeChildrenWinSize(pWin, x - oldpt.x, y - oldpt.y, 0, 0);
+
+ if (WasViewable)
+ {
+ if (pLayerWin == pWin)
+ anyMarked |= (*pScreen->MarkOverlappedWindows)
+ (pWin, windowToValidate, (WindowPtr *)NULL);
+ else
+ anyMarked |= (*pScreen->MarkOverlappedWindows)
+ (pWin, pLayerWin, (WindowPtr *)NULL);
+
+#ifdef DO_SAVE_UNDERS
+ if (DO_SAVE_UNDERS(pWin))
+ {
+ dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, windowToValidate);
+ }
+#endif /* DO_SAVE_UNDERS */
+
+ if (anyMarked)
+ {
+ (*pScreen->ValidateTree)(pLayerWin->parent, NullWindow, kind);
+ (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, oldRegion);
+ REGION_DESTROY(pScreen, oldRegion);
+ /* XXX need to retile border if ParentRelative origin */
+ (*pScreen->HandleExposures)(pLayerWin->parent);
+ }
+#ifdef DO_SAVE_UNDERS
+ if (dosave)
+ (*pScreen->PostChangeSaveUnder)(pLayerWin, windowToValidate);
+#endif /* DO_SAVE_UNDERS */
+ if (anyMarked && pScreen->PostValidateTree)
+ (*pScreen->PostValidateTree)(pLayerWin->parent, NullWindow, kind);
+ }
+ if (pWin->realized)
+ WindowsRestructured ();
+}
+
+
+/*
+ * pValid is a region of the screen which has been
+ * successfully copied -- recomputed exposed regions for affected windows
+ */
+
+static int
+miRecomputeExposures (
+ register WindowPtr pWin,
+ pointer value) /* must conform to VisitWindowProcPtr */
+{
+ register ScreenPtr pScreen;
+ RegionPtr pValid = (RegionPtr)value;
+
+ if (pWin->valdata)
+ {
+ pScreen = pWin->drawable.pScreen;
+ /*
+ * compute exposed regions of this window
+ */
+ REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed,
+ &pWin->clipList, pValid);
+ /*
+ * compute exposed regions of the border
+ */
+ REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed,
+ &pWin->borderClip, &pWin->winSize);
+ REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed,
+ &pWin->valdata->after.borderExposed, pValid);
+ return WT_WALKCHILDREN;
+ }
+ return WT_NOMATCH;
+}
+
+void
+miSlideAndSizeWindow(pWin, x, y, w, h, pSib)
+ register WindowPtr pWin;
+ int x,y;
+ unsigned int w, h;
+ WindowPtr pSib;
+{
+ WindowPtr pParent;
+ Bool WasViewable = (Bool)(pWin->viewable);
+ unsigned short width = pWin->drawable.width,
+ height = pWin->drawable.height;
+ short oldx = pWin->drawable.x,
+ oldy = pWin->drawable.y;
+ int bw = wBorderWidth (pWin);
+ short dw, dh;
+ DDXPointRec oldpt;
+ RegionPtr oldRegion = NULL;
+ Bool anyMarked = FALSE;
+ register ScreenPtr pScreen;
+ WindowPtr pFirstChange;
+ register WindowPtr pChild;
+ RegionPtr gravitate[StaticGravity + 1];
+ register unsigned g;
+ int nx, ny; /* destination x,y */
+ int newx, newy; /* new inner window position */
+ RegionPtr pRegion = NULL;
+ RegionPtr destClip; /* portions of destination already written */
+ RegionPtr oldWinClip = NULL; /* old clip list for window */
+ RegionPtr borderVisible = NullRegion; /* visible area of the border */
+ RegionPtr bsExposed = NullRegion; /* backing store exposures */
+ Bool shrunk = FALSE; /* shrunk in an inner dimension */
+ Bool moved = FALSE; /* window position changed */
+#ifdef DO_SAVE_UNDERS
+ Bool dosave = FALSE;
+#endif
+ WindowPtr pLayerWin;
+
+ /* if this is a root window, can't be resized */
+ if (!(pParent = pWin->parent))
+ return ;
+
+ pScreen = pWin->drawable.pScreen;
+ newx = pParent->drawable.x + x + bw;
+ newy = pParent->drawable.y + y + bw;
+ if (WasViewable)
+ {
+ anyMarked = FALSE;
+ /*
+ * save the visible region of the window
+ */
+ oldRegion = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_COPY(pScreen, oldRegion, &pWin->winSize);
+
+ /*
+ * categorize child windows into regions to be moved
+ */
+ for (g = 0; g <= StaticGravity; g++)
+ gravitate[g] = (RegionPtr) NULL;
+ for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib)
+ {
+ g = pChild->winGravity;
+ if (g != UnmapGravity)
+ {
+ if (!gravitate[g])
+ gravitate[g] = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_UNION(pScreen, gravitate[g],
+ gravitate[g], &pChild->borderClip);
+ }
+ else
+ {
+ UnmapWindow(pChild, TRUE);
+ anyMarked = TRUE;
+ }
+ }
+ anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pWin,
+ &pLayerWin);
+
+ oldWinClip = NULL;
+ if (pWin->bitGravity != ForgetGravity)
+ {
+ oldWinClip = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_COPY(pScreen, oldWinClip, &pWin->clipList);
+ }
+ /*
+ * if the window is changing size, borderExposed
+ * can't be computed correctly without some help.
+ */
+ if (pWin->drawable.height > h || pWin->drawable.width > w)
+ shrunk = TRUE;
+
+ if (newx != oldx || newy != oldy)
+ moved = TRUE;
+
+ if ((pWin->drawable.height != h || pWin->drawable.width != w) &&
+ HasBorder (pWin))
+ {
+ borderVisible = REGION_CREATE(pScreen, NullBox, 1);
+ /* for tiled borders, we punt and draw the whole thing */
+ if (pWin->borderIsPixel || !moved)
+ {
+ if (shrunk || moved)
+ REGION_SUBTRACT(pScreen, borderVisible,
+ &pWin->borderClip,
+ &pWin->winSize);
+ else
+ REGION_COPY(pScreen, borderVisible,
+ &pWin->borderClip);
+ }
+ }
+ }
+ pWin->origin.x = x + bw;
+ pWin->origin.y = y + bw;
+ pWin->drawable.height = h;
+ pWin->drawable.width = w;
+
+ x = pWin->drawable.x = newx;
+ y = pWin->drawable.y = newy;
+
+ SetWinSize (pWin);
+ SetBorderSize (pWin);
+
+ dw = (int)w - (int)width;
+ dh = (int)h - (int)height;
+ ResizeChildrenWinSize(pWin, x - oldx, y - oldy, dw, dh);
+
+ /* let the hardware adjust background and border pixmaps, if any */
+ (*pScreen->PositionWindow)(pWin, x, y);
+
+ pFirstChange = MoveWindowInStack(pWin, pSib);
+
+ if (WasViewable)
+ {
+ pRegion = REGION_CREATE(pScreen, NullBox, 1);
+ if (pWin->backStorage)
+ REGION_COPY(pScreen, pRegion, &pWin->clipList);
+
+ if (pLayerWin == pWin)
+ anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pFirstChange,
+ (WindowPtr *)NULL);
+ else
+ anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pLayerWin,
+ (WindowPtr *)NULL);
+
+ if (pWin->valdata)
+ {
+ pWin->valdata->before.resized = TRUE;
+ pWin->valdata->before.borderVisible = borderVisible;
+ }
+
+#ifdef DO_SAVE_UNDERS
+ if (DO_SAVE_UNDERS(pWin))
+ {
+ dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pFirstChange);
+ }
+#endif /* DO_SAVE_UNDERS */
+
+ if (anyMarked)
+ (*pScreen->ValidateTree)(pLayerWin->parent, pFirstChange, VTOther);
+ /*
+ * the entire window is trashed unless bitGravity
+ * recovers portions of it
+ */
+ REGION_COPY(pScreen, &pWin->valdata->after.exposed, &pWin->clipList);
+ }
+
+ GravityTranslate (x, y, oldx, oldy, dw, dh, pWin->bitGravity, &nx, &ny);
+
+ if (pWin->backStorage &&
+ ((pWin->backingStore == Always) || WasViewable))
+ {
+ if (!WasViewable)
+ pRegion = &pWin->clipList; /* a convenient empty region */
+ if (pWin->bitGravity == ForgetGravity)
+ bsExposed = (*pScreen->TranslateBackingStore)
+ (pWin, 0, 0, NullRegion, oldx, oldy);
+ else
+ {
+ bsExposed = (*pScreen->TranslateBackingStore)
+ (pWin, nx - x, ny - y, pRegion, oldx, oldy);
+ }
+ }
+
+ if (WasViewable)
+ {
+ /* avoid the border */
+ if (HasBorder (pWin))
+ {
+ int offx, offy, dx, dy;
+
+ /* kruft to avoid double translates for each gravity */
+ offx = 0;
+ offy = 0;
+ for (g = 0; g <= StaticGravity; g++)
+ {
+ if (!gravitate[g])
+ continue;
+
+ /* align winSize to gravitate[g].
+ * winSize is in new coordinates,
+ * gravitate[g] is still in old coordinates */
+ GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny);
+
+ dx = (oldx - nx) - offx;
+ dy = (oldy - ny) - offy;
+ if (dx || dy)
+ {
+ REGION_TRANSLATE(pScreen, &pWin->winSize, dx, dy);
+ offx += dx;
+ offy += dy;
+ }
+ REGION_INTERSECT(pScreen, gravitate[g], gravitate[g],
+ &pWin->winSize);
+ }
+ /* get winSize back where it belongs */
+ if (offx || offy)
+ REGION_TRANSLATE(pScreen, &pWin->winSize, -offx, -offy);
+ }
+ /*
+ * add screen bits to the appropriate bucket
+ */
+
+ if (oldWinClip)
+ {
+ /*
+ * clip to new clipList
+ */
+ REGION_COPY(pScreen, pRegion, oldWinClip);
+ REGION_TRANSLATE(pScreen, pRegion, nx - oldx, ny - oldy);
+ REGION_INTERSECT(pScreen, oldWinClip, pRegion, &pWin->clipList);
+ /*
+ * don't step on any gravity bits which will be copied after this
+ * region. Note -- this assumes that the regions will be copied
+ * in gravity order.
+ */
+ for (g = pWin->bitGravity + 1; g <= StaticGravity; g++)
+ {
+ if (gravitate[g])
+ REGION_SUBTRACT(pScreen, oldWinClip, oldWinClip,
+ gravitate[g]);
+ }
+ REGION_TRANSLATE(pScreen, oldWinClip, oldx - nx, oldy - ny);
+ g = pWin->bitGravity;
+ if (!gravitate[g])
+ gravitate[g] = oldWinClip;
+ else
+ {
+ REGION_UNION(pScreen, gravitate[g], gravitate[g], oldWinClip);
+ REGION_DESTROY(pScreen, oldWinClip);
+ }
+ }
+
+ /*
+ * move the bits on the screen
+ */
+
+ destClip = NULL;
+
+ for (g = 0; g <= StaticGravity; g++)
+ {
+ if (!gravitate[g])
+ continue;
+
+ GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny);
+
+ oldpt.x = oldx + (x - nx);
+ oldpt.y = oldy + (y - ny);
+
+ /* Note that gravitate[g] is *translated* by CopyWindow */
+
+ /* only copy the remaining useful bits */
+
+ REGION_INTERSECT(pScreen, gravitate[g], gravitate[g], oldRegion);
+
+ /* clip to not overwrite already copied areas */
+
+ if (destClip) {
+ REGION_TRANSLATE(pScreen, destClip, oldpt.x - x, oldpt.y - y);
+ REGION_SUBTRACT(pScreen, gravitate[g], gravitate[g], destClip);
+ REGION_TRANSLATE(pScreen, destClip, x - oldpt.x, y - oldpt.y);
+ }
+
+ /* and move those bits */
+
+ if (oldpt.x != x || oldpt.y != y
+#ifdef COMPOSITE
+ || pWin->redirectDraw
+#endif
+ )
+ {
+ (*pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, gravitate[g]);
+ }
+
+ /* remove any overwritten bits from the remaining useful bits */
+
+ REGION_SUBTRACT(pScreen, oldRegion, oldRegion, gravitate[g]);
+
+ /*
+ * recompute exposed regions of child windows
+ */
+
+ for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib)
+ {
+ if (pChild->winGravity != g)
+ continue;
+ REGION_INTERSECT(pScreen, pRegion,
+ &pChild->borderClip, gravitate[g]);
+ TraverseTree (pChild, miRecomputeExposures, (pointer)pRegion);
+ }
+
+ /*
+ * remove the successfully copied regions of the
+ * window from its exposed region
+ */
+
+ if (g == pWin->bitGravity)
+ REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed,
+ &pWin->valdata->after.exposed, gravitate[g]);
+ if (!destClip)
+ destClip = gravitate[g];
+ else
+ {
+ REGION_UNION(pScreen, destClip, destClip, gravitate[g]);
+ REGION_DESTROY(pScreen, gravitate[g]);
+ }
+ }
+
+ REGION_DESTROY(pScreen, oldRegion);
+ REGION_DESTROY(pScreen, pRegion);
+ if (destClip)
+ REGION_DESTROY(pScreen, destClip);
+ if (bsExposed)
+ {
+ RegionPtr valExposed = NullRegion;
+
+ if (pWin->valdata)
+ valExposed = &pWin->valdata->after.exposed;
+ (*pScreen->WindowExposures) (pWin, valExposed, bsExposed);
+ if (valExposed)
+ REGION_EMPTY(pScreen, valExposed);
+ REGION_DESTROY(pScreen, bsExposed);
+ }
+ if (anyMarked)
+ (*pScreen->HandleExposures)(pLayerWin->parent);
+#ifdef DO_SAVE_UNDERS
+ if (dosave)
+ {
+ (*pScreen->PostChangeSaveUnder)(pLayerWin, pFirstChange);
+ }
+#endif /* DO_SAVE_UNDERS */
+ if (anyMarked && pScreen->PostValidateTree)
+ (*pScreen->PostValidateTree)(pLayerWin->parent, pFirstChange,
+ VTOther);
+ }
+ else if (bsExposed)
+ {
+ (*pScreen->WindowExposures) (pWin, NullRegion, bsExposed);
+ REGION_DESTROY(pScreen, bsExposed);
+ }
+ if (pWin->realized)
+ WindowsRestructured ();
+}
+
+WindowPtr
+miGetLayerWindow(pWin)
+ WindowPtr pWin;
+{
+ return pWin->firstChild;
+}
+
+#ifdef SHAPE
+/******
+ *
+ * miSetShape
+ * The border/window shape has changed. Recompute winSize/borderSize
+ * and send appropriate exposure events
+ */
+
+_X_EXPORT void
+miSetShape(pWin)
+ register WindowPtr pWin;
+{
+ Bool WasViewable = (Bool)(pWin->viewable);
+ register ScreenPtr pScreen = pWin->drawable.pScreen;
+ Bool anyMarked = FALSE;
+ RegionPtr pOldClip = NULL, bsExposed;
+#ifdef DO_SAVE_UNDERS
+ Bool dosave = FALSE;
+#endif
+ WindowPtr pLayerWin;
+
+ if (WasViewable)
+ {
+ anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin,
+ &pLayerWin);
+ if (pWin->valdata)
+ {
+ if (HasBorder (pWin))
+ {
+ RegionPtr borderVisible;
+
+ borderVisible = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_SUBTRACT(pScreen, borderVisible,
+ &pWin->borderClip, &pWin->winSize);
+ pWin->valdata->before.borderVisible = borderVisible;
+ }
+ pWin->valdata->before.resized = TRUE;
+ }
+ }
+
+ SetWinSize (pWin);
+ SetBorderSize (pWin);
+
+ ResizeChildrenWinSize(pWin, 0, 0, 0, 0);
+
+ if (WasViewable)
+ {
+ if (pWin->backStorage)
+ {
+ pOldClip = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_COPY(pScreen, pOldClip, &pWin->clipList);
+ }
+
+ anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pWin,
+ (WindowPtr *)NULL);
+
+#ifdef DO_SAVE_UNDERS
+ if (DO_SAVE_UNDERS(pWin))
+ {
+ dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pLayerWin);
+ }
+#endif /* DO_SAVE_UNDERS */
+
+ if (anyMarked)
+ (*pScreen->ValidateTree)(pLayerWin->parent, NullWindow, VTOther);
+ }
+
+ if (pWin->backStorage &&
+ ((pWin->backingStore == Always) || WasViewable))
+ {
+ if (!WasViewable)
+ pOldClip = &pWin->clipList; /* a convenient empty region */
+ bsExposed = (*pScreen->TranslateBackingStore)
+ (pWin, 0, 0, pOldClip,
+ pWin->drawable.x, pWin->drawable.y);
+ if (WasViewable)
+ REGION_DESTROY(pScreen, pOldClip);
+ if (bsExposed)
+ {
+ RegionPtr valExposed = NullRegion;
+
+ if (pWin->valdata)
+ valExposed = &pWin->valdata->after.exposed;
+ (*pScreen->WindowExposures) (pWin, valExposed, bsExposed);
+ if (valExposed)
+ REGION_EMPTY(pScreen, valExposed);
+ REGION_DESTROY(pScreen, bsExposed);
+ }
+ }
+ if (WasViewable)
+ {
+ if (anyMarked)
+ (*pScreen->HandleExposures)(pLayerWin->parent);
+#ifdef DO_SAVE_UNDERS
+ if (dosave)
+ (*pScreen->PostChangeSaveUnder)(pLayerWin, pLayerWin);
+#endif /* DO_SAVE_UNDERS */
+ if (anyMarked && pScreen->PostValidateTree)
+ (*pScreen->PostValidateTree)(pLayerWin->parent, NullWindow, VTOther);
+ }
+ if (pWin->realized)
+ WindowsRestructured ();
+ CheckCursorConfinement(pWin);
+}
+#endif
+
+/* Keeps the same inside(!) origin */
+
+_X_EXPORT void
+miChangeBorderWidth(pWin, width)
+ register WindowPtr pWin;
+ unsigned int width;
+{
+ int oldwidth;
+ Bool anyMarked = FALSE;
+ register ScreenPtr pScreen;
+ Bool WasViewable = (Bool)(pWin->viewable);
+ Bool HadBorder;
+#ifdef DO_SAVE_UNDERS
+ Bool dosave = FALSE;
+#endif
+ WindowPtr pLayerWin;
+
+ oldwidth = wBorderWidth (pWin);
+ if (oldwidth == width)
+ return;
+ HadBorder = HasBorder(pWin);
+ pScreen = pWin->drawable.pScreen;
+ if (WasViewable && width < oldwidth)
+ anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, &pLayerWin);
+
+ pWin->borderWidth = width;
+ SetBorderSize (pWin);
+
+ if (WasViewable)
+ {
+ if (width > oldwidth)
+ {
+ anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin,
+ &pLayerWin);
+ /*
+ * save the old border visible region to correctly compute
+ * borderExposed.
+ */
+ if (pWin->valdata && HadBorder)
+ {
+ RegionPtr borderVisible;
+ borderVisible = REGION_CREATE(pScreen, NULL, 1);
+ REGION_SUBTRACT(pScreen, borderVisible,
+ &pWin->borderClip, &pWin->winSize);
+ pWin->valdata->before.borderVisible = borderVisible;
+ }
+ }
+#ifdef DO_SAVE_UNDERS
+ if (DO_SAVE_UNDERS(pWin))
+ {
+ dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pWin->nextSib);
+ }
+#endif /* DO_SAVE_UNDERS */
+
+ if (anyMarked)
+ {
+ (*pScreen->ValidateTree)(pLayerWin->parent, pLayerWin, VTOther);
+ (*pScreen->HandleExposures)(pLayerWin->parent);
+ }
+#ifdef DO_SAVE_UNDERS
+ if (dosave)
+ (*pScreen->PostChangeSaveUnder)(pLayerWin, pWin->nextSib);
+#endif /* DO_SAVE_UNDERS */
+ if (anyMarked && pScreen->PostValidateTree)
+ (*pScreen->PostValidateTree)(pLayerWin->parent, pLayerWin,
+ VTOther);
+ }
+ if (pWin->realized)
+ WindowsRestructured ();
+}
+
+void
+miMarkUnrealizedWindow(pChild, pWin, fromConfigure)
+ WindowPtr pChild;
+ WindowPtr pWin;
+ Bool fromConfigure;
+{
+ if ((pChild != pWin) || fromConfigure)
+ {
+ REGION_EMPTY(pChild->drawable.pScreen, &pChild->clipList);
+ if (pChild->drawable.pScreen->ClipNotify)
+ (* pChild->drawable.pScreen->ClipNotify)(pChild, 0, 0);
+ REGION_EMPTY(pChild->drawable.pScreen, &pChild->borderClip);
+ }
+}
+
+_X_EXPORT void
+miSegregateChildren(WindowPtr pWin, RegionPtr pReg, int depth)
+{
+ ScreenPtr pScreen;
+ WindowPtr pChild;
+
+ pScreen = pWin->drawable.pScreen;
+
+ for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib)
+ {
+ if (pChild->drawable.depth == depth)
+ REGION_UNION(pScreen, pReg, pReg, &pChild->borderClip);
+
+ if (pChild->firstChild)
+ miSegregateChildren(pChild, pReg, depth);
+ }
+}
diff --git a/xserver/mi/mizerarc.c b/xserver/mi/mizerarc.c
new file mode 100644
index 000000000..33e1acc19
--- /dev/null
+++ b/xserver/mi/mizerarc.c
@@ -0,0 +1,853 @@
+/************************************************************
+
+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.
+
+Author: Bob Scheifler, MIT X Consortium
+
+********************************************************/
+
+
+/* Derived from:
+ * "Algorithm for drawing ellipses or hyperbolae with a digital plotter"
+ * by M. L. V. Pitteway
+ * The Computer Journal, November 1967, Volume 10, Number 3, pp. 282-289
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <math.h>
+#include <X11/X.h>
+#include <X11/Xprotostr.h>
+#include "regionstr.h"
+#include "gcstruct.h"
+#include "pixmapstr.h"
+#include "mi.h"
+#include "mizerarc.h"
+
+#define FULLCIRCLE (360 * 64)
+#define OCTANT (45 * 64)
+#define QUADRANT (90 * 64)
+#define HALFCIRCLE (180 * 64)
+#define QUADRANT3 (270 * 64)
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#define Dsin(d) ((d) == 0 ? 0.0 : ((d) == QUADRANT ? 1.0 : \
+ ((d) == HALFCIRCLE ? 0.0 : \
+ ((d) == QUADRANT3 ? -1.0 : sin((double)d*(M_PI/11520.0))))))
+
+#define Dcos(d) ((d) == 0 ? 1.0 : ((d) == QUADRANT ? 0.0 : \
+ ((d) == HALFCIRCLE ? -1.0 : \
+ ((d) == QUADRANT3 ? 0.0 : cos((double)d*(M_PI/11520.0))))))
+
+#define EPSILON45 64
+
+typedef struct {
+ int skipStart;
+ int haveStart;
+ DDXPointRec startPt;
+ int haveLast;
+ int skipLast;
+ DDXPointRec endPt;
+ int dashIndex;
+ int dashOffset;
+ int dashIndexInit;
+ int dashOffsetInit;
+} DashInfo;
+
+static miZeroArcPtRec oob = {65536, 65536, 0};
+
+/*
+ * (x - l)^2 / (W/2)^2 + (y + H/2)^2 / (H/2)^2 = 1
+ *
+ * where l is either 0 or .5
+ *
+ * alpha = 4(W^2)
+ * beta = 4(H^2)
+ * gamma = 0
+ * u = 2(W^2)H
+ * v = 4(H^2)l
+ * k = -4(H^2)(l^2)
+ *
+ */
+
+_X_EXPORT Bool
+miZeroArcSetup(arc, info, ok360)
+ register xArc *arc;
+ register miZeroArcRec *info;
+ Bool ok360;
+{
+ int l;
+ int angle1, angle2;
+ int startseg, endseg;
+ int startAngle, endAngle;
+ int i, overlap;
+ miZeroArcPtRec start, end;
+
+ l = arc->width & 1;
+ if (arc->width == arc->height)
+ {
+ info->alpha = 4;
+ info->beta = 4;
+ info->k1 = -8;
+ info->k3 = -16;
+ info->b = 12;
+ info->a = (arc->width << 2) - 12;
+ info->d = 17 - (arc->width << 1);
+ if (l)
+ {
+ info->b -= 4;
+ info->a += 4;
+ info->d -= 7;
+ }
+ }
+ else if (!arc->width || !arc->height)
+ {
+ info->alpha = 0;
+ info->beta = 0;
+ info->k1 = 0;
+ info->k3 = 0;
+ info->a = -(int)arc->height;
+ info->b = 0;
+ info->d = -1;
+ }
+ else
+ {
+ /* initial conditions */
+ info->alpha = (arc->width * arc->width) << 2;
+ info->beta = (arc->height * arc->height) << 2;
+ info->k1 = info->beta << 1;
+ info->k3 = info->k1 + (info->alpha << 1);
+ info->b = l ? 0 : -info->beta;
+ info->a = info->alpha * arc->height;
+ info->d = info->b - (info->a >> 1) - (info->alpha >> 2);
+ if (l)
+ info->d -= info->beta >> 2;
+ info->a -= info->b;
+ /* take first step, d < 0 always */
+ info->b -= info->k1;
+ info->a += info->k1;
+ info->d += info->b;
+ /* octant change, b < 0 always */
+ info->k1 = -info->k1;
+ info->k3 = -info->k3;
+ info->b = -info->b;
+ info->d = info->b - info->a - info->d;
+ info->a = info->a - (info->b << 1);
+ }
+ info->dx = 1;
+ info->dy = 0;
+ info->w = (arc->width + 1) >> 1;
+ info->h = arc->height >> 1;
+ info->xorg = arc->x + (arc->width >> 1);
+ info->yorg = arc->y;
+ info->xorgo = info->xorg + l;
+ info->yorgo = info->yorg + arc->height;
+ if (!arc->width)
+ {
+ if (!arc->height)
+ {
+ info->x = 0;
+ info->y = 0;
+ info->initialMask = 0;
+ info->startAngle = 0;
+ info->endAngle = 0;
+ info->start = oob;
+ info->end = oob;
+ return FALSE;
+ }
+ info->x = 0;
+ info->y = 1;
+ }
+ else
+ {
+ info->x = 1;
+ info->y = 0;
+ }
+ angle1 = arc->angle1;
+ angle2 = arc->angle2;
+ if ((angle1 == 0) && (angle2 >= FULLCIRCLE))
+ {
+ startAngle = 0;
+ endAngle = 0;
+ }
+ else
+ {
+ if (angle2 > FULLCIRCLE)
+ angle2 = FULLCIRCLE;
+ else if (angle2 < -FULLCIRCLE)
+ angle2 = -FULLCIRCLE;
+ if (angle2 < 0)
+ {
+ startAngle = angle1 + angle2;
+ endAngle = angle1;
+ }
+ else
+ {
+ startAngle = angle1;
+ endAngle = angle1 + angle2;
+ }
+ if (startAngle < 0)
+ startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
+ if (startAngle >= FULLCIRCLE)
+ startAngle = startAngle % FULLCIRCLE;
+ if (endAngle < 0)
+ endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE;
+ if (endAngle >= FULLCIRCLE)
+ endAngle = endAngle % FULLCIRCLE;
+ }
+ info->startAngle = startAngle;
+ info->endAngle = endAngle;
+ if (ok360 && (startAngle == endAngle) && arc->angle2 &&
+ arc->width && arc->height)
+ {
+ info->initialMask = 0xf;
+ info->start = oob;
+ info->end = oob;
+ return TRUE;
+ }
+ startseg = startAngle / OCTANT;
+ if (!arc->height || (((startseg + 1) & 2) && arc->width))
+ {
+ start.x = Dcos(startAngle) * ((arc->width + 1) / 2.0);
+ if (start.x < 0)
+ start.x = -start.x;
+ start.y = -1;
+ }
+ else
+ {
+ start.y = Dsin(startAngle) * (arc->height / 2.0);
+ if (start.y < 0)
+ start.y = -start.y;
+ start.y = info->h - start.y;
+ start.x = 65536;
+ }
+ endseg = endAngle / OCTANT;
+ if (!arc->height || (((endseg + 1) & 2) && arc->width))
+ {
+ end.x = Dcos(endAngle) * ((arc->width + 1) / 2.0);
+ if (end.x < 0)
+ end.x = -end.x;
+ end.y = -1;
+ }
+ else
+ {
+ end.y = Dsin(endAngle) * (arc->height / 2.0);
+ if (end.y < 0)
+ end.y = -end.y;
+ end.y = info->h - end.y;
+ end.x = 65536;
+ }
+ info->firstx = start.x;
+ info->firsty = start.y;
+ info->initialMask = 0;
+ overlap = arc->angle2 && (endAngle <= startAngle);
+ for (i = 0; i < 4; i++)
+ {
+ if (overlap ?
+ ((i * QUADRANT <= endAngle) || ((i + 1) * QUADRANT > startAngle)) :
+ ((i * QUADRANT <= endAngle) && ((i + 1) * QUADRANT > startAngle)))
+ info->initialMask |= (1 << i);
+ }
+ start.mask = info->initialMask;
+ end.mask = info->initialMask;
+ startseg >>= 1;
+ endseg >>= 1;
+ overlap = overlap && (endseg == startseg);
+ if (start.x != end.x || start.y != end.y || !overlap)
+ {
+ if (startseg & 1)
+ {
+ if (!overlap)
+ info->initialMask &= ~(1 << startseg);
+ if (start.x > end.x || start.y > end.y)
+ end.mask &= ~(1 << startseg);
+ }
+ else
+ {
+ start.mask &= ~(1 << startseg);
+ if (((start.x < end.x || start.y < end.y) ||
+ (start.x == end.x && start.y == end.y && (endseg & 1))) &&
+ !overlap)
+ end.mask &= ~(1 << startseg);
+ }
+ if (endseg & 1)
+ {
+ end.mask &= ~(1 << endseg);
+ if (((start.x > end.x || start.y > end.y) ||
+ (start.x == end.x && start.y == end.y && !(startseg & 1))) &&
+ !overlap)
+ start.mask &= ~(1 << endseg);
+ }
+ else
+ {
+ if (!overlap)
+ info->initialMask &= ~(1 << endseg);
+ if (start.x < end.x || start.y < end.y)
+ start.mask &= ~(1 << endseg);
+ }
+ }
+ /* take care of case when start and stop are both near 45 */
+ /* handle here rather than adding extra code to pixelization loops */
+ if (startAngle &&
+ ((start.y < 0 && end.y >= 0) || (start.y >= 0 && end.y < 0)))
+ {
+ i = (startAngle + OCTANT) % OCTANT;
+ if (i < EPSILON45 || i > OCTANT - EPSILON45)
+ {
+ i = (endAngle + OCTANT) % OCTANT;
+ if (i < EPSILON45 || i > OCTANT - EPSILON45)
+ {
+ if (start.y < 0)
+ {
+ i = Dsin(startAngle) * (arc->height / 2.0);
+ if (i < 0)
+ i = -i;
+ if (info->h - i == end.y)
+ start.mask = end.mask;
+ }
+ else
+ {
+ i = Dsin(endAngle) * (arc->height / 2.0);
+ if (i < 0)
+ i = -i;
+ if (info->h - i == start.y)
+ end.mask = start.mask;
+ }
+ }
+ }
+ }
+ if (startseg & 1)
+ {
+ info->start = start;
+ info->end = oob;
+ }
+ else
+ {
+ info->end = start;
+ info->start = oob;
+ }
+ if (endseg & 1)
+ {
+ info->altend = end;
+ if (info->altend.x < info->end.x || info->altend.y < info->end.y)
+ {
+ miZeroArcPtRec tmp;
+ tmp = info->altend;
+ info->altend = info->end;
+ info->end = tmp;
+ }
+ info->altstart = oob;
+ }
+ else
+ {
+ info->altstart = end;
+ if (info->altstart.x < info->start.x ||
+ info->altstart.y < info->start.y)
+ {
+ miZeroArcPtRec tmp;
+ tmp = info->altstart;
+ info->altstart = info->start;
+ info->start = tmp;
+ }
+ info->altend = oob;
+ }
+ if (!info->start.x || !info->start.y)
+ {
+ info->initialMask = info->start.mask;
+ info->start = info->altstart;
+ }
+ if (!arc->width && (arc->height == 1))
+ {
+ /* kludge! */
+ info->initialMask |= info->end.mask;
+ info->initialMask |= info->initialMask << 1;
+ info->end.x = 0;
+ info->end.mask = 0;
+ }
+ return FALSE;
+}
+
+#define Pixelate(xval,yval) \
+ { \
+ pts->x = xval; \
+ pts->y = yval; \
+ pts++; \
+ }
+
+#define DoPix(idx,xval,yval) if (mask & (1 << idx)) Pixelate(xval, yval);
+
+DDXPointPtr
+miZeroArcPts(arc, pts)
+ xArc *arc;
+ register DDXPointPtr pts;
+{
+ miZeroArcRec info;
+ register int x, y, a, b, d, mask;
+ register int k1, k3, dx, dy;
+ Bool do360;
+
+ do360 = miZeroArcSetup(arc, &info, TRUE);
+ MIARCSETUP();
+ mask = info.initialMask;
+ if (!(arc->width & 1))
+ {
+ DoPix(1, info.xorgo, info.yorg);
+ DoPix(3, info.xorgo, info.yorgo);
+ }
+ if (!info.end.x || !info.end.y)
+ {
+ mask = info.end.mask;
+ info.end = info.altend;
+ }
+ if (do360 && (arc->width == arc->height) && !(arc->width & 1))
+ {
+ int yorgh = info.yorg + info.h;
+ int xorghp = info.xorg + info.h;
+ int xorghn = info.xorg - info.h;
+
+ while (1)
+ {
+ Pixelate(info.xorg + x, info.yorg + y);
+ Pixelate(info.xorg - x, info.yorg + y);
+ Pixelate(info.xorg - x, info.yorgo - y);
+ Pixelate(info.xorg + x, info.yorgo - y);
+ if (a < 0)
+ break;
+ Pixelate(xorghp - y, yorgh - x);
+ Pixelate(xorghn + y, yorgh - x);
+ Pixelate(xorghn + y, yorgh + x);
+ Pixelate(xorghp - y, yorgh + x);
+ MIARCCIRCLESTEP(;);
+ }
+ if (x > 1 && pts[-1].x == pts[-5].x && pts[-1].y == pts[-5].y)
+ pts -= 4;
+ x = info.w;
+ y = info.h;
+ }
+ else if (do360)
+ {
+ while (y < info.h || x < info.w)
+ {
+ MIARCOCTANTSHIFT(;);
+ Pixelate(info.xorg + x, info.yorg + y);
+ Pixelate(info.xorgo - x, info.yorg + y);
+ Pixelate(info.xorgo - x, info.yorgo - y);
+ Pixelate(info.xorg + x, info.yorgo - y);
+ MIARCSTEP(;,;);
+ }
+ }
+ else
+ {
+ while (y < info.h || x < info.w)
+ {
+ MIARCOCTANTSHIFT(;);
+ if ((x == info.start.x) || (y == info.start.y))
+ {
+ mask = info.start.mask;
+ info.start = info.altstart;
+ }
+ DoPix(0, info.xorg + x, info.yorg + y);
+ DoPix(1, info.xorgo - x, info.yorg + y);
+ DoPix(2, info.xorgo - x, info.yorgo - y);
+ DoPix(3, info.xorg + x, info.yorgo - y);
+ if ((x == info.end.x) || (y == info.end.y))
+ {
+ mask = info.end.mask;
+ info.end = info.altend;
+ }
+ MIARCSTEP(;,;);
+ }
+ }
+ if ((x == info.start.x) || (y == info.start.y))
+ mask = info.start.mask;
+ DoPix(0, info.xorg + x, info.yorg + y);
+ DoPix(2, info.xorgo - x, info.yorgo - y);
+ if (arc->height & 1)
+ {
+ DoPix(1, info.xorgo - x, info.yorg + y);
+ DoPix(3, info.xorg + x, info.yorgo - y);
+ }
+ return pts;
+}
+
+#undef DoPix
+#define DoPix(idx,xval,yval) \
+ if (mask & (1 << idx)) \
+ { \
+ arcPts[idx]->x = xval; \
+ arcPts[idx]->y = yval; \
+ arcPts[idx]++; \
+ }
+
+static void
+miZeroArcDashPts(
+ GCPtr pGC,
+ xArc *arc,
+ DashInfo *dinfo,
+ register DDXPointPtr points,
+ int maxPts,
+ register DDXPointPtr *evenPts,
+ register DDXPointPtr *oddPts )
+{
+ miZeroArcRec info;
+ register int x, y, a, b, d, mask;
+ register int k1, k3, dx, dy;
+ int dashRemaining;
+ DDXPointPtr arcPts[4];
+ DDXPointPtr startPts[5], endPts[5];
+ int deltas[5];
+ DDXPointPtr startPt, pt, lastPt, pts;
+ int i, j, delta, ptsdelta, seg, startseg;
+
+ for (i = 0; i < 4; i++)
+ arcPts[i] = points + (i * maxPts);
+ (void)miZeroArcSetup(arc, &info, FALSE);
+ MIARCSETUP();
+ mask = info.initialMask;
+ startseg = info.startAngle / QUADRANT;
+ startPt = arcPts[startseg];
+ if (!(arc->width & 1))
+ {
+ DoPix(1, info.xorgo, info.yorg);
+ DoPix(3, info.xorgo, info.yorgo);
+ }
+ if (!info.end.x || !info.end.y)
+ {
+ mask = info.end.mask;
+ info.end = info.altend;
+ }
+ while (y < info.h || x < info.w)
+ {
+ MIARCOCTANTSHIFT(;);
+ if ((x == info.firstx) || (y == info.firsty))
+ startPt = arcPts[startseg];
+ if ((x == info.start.x) || (y == info.start.y))
+ {
+ mask = info.start.mask;
+ info.start = info.altstart;
+ }
+ DoPix(0, info.xorg + x, info.yorg + y);
+ DoPix(1, info.xorgo - x, info.yorg + y);
+ DoPix(2, info.xorgo - x, info.yorgo - y);
+ DoPix(3, info.xorg + x, info.yorgo - y);
+ if ((x == info.end.x) || (y == info.end.y))
+ {
+ mask = info.end.mask;
+ info.end = info.altend;
+ }
+ MIARCSTEP(;,;);
+ }
+ if ((x == info.firstx) || (y == info.firsty))
+ startPt = arcPts[startseg];
+ if ((x == info.start.x) || (y == info.start.y))
+ mask = info.start.mask;
+ DoPix(0, info.xorg + x, info.yorg + y);
+ DoPix(2, info.xorgo - x, info.yorgo - y);
+ if (arc->height & 1)
+ {
+ DoPix(1, info.xorgo - x, info.yorg + y);
+ DoPix(3, info.xorg + x, info.yorgo - y);
+ }
+ for (i = 0; i < 4; i++)
+ {
+ seg = (startseg + i) & 3;
+ pt = points + (seg * maxPts);
+ if (seg & 1)
+ {
+ startPts[i] = pt;
+ endPts[i] = arcPts[seg];
+ deltas[i] = 1;
+ }
+ else
+ {
+ startPts[i] = arcPts[seg] - 1;
+ endPts[i] = pt - 1;
+ deltas[i] = -1;
+ }
+ }
+ startPts[4] = startPts[0];
+ endPts[4] = startPt;
+ startPts[0] = startPt;
+ if (startseg & 1)
+ {
+ if (startPts[4] != endPts[4])
+ endPts[4]--;
+ deltas[4] = 1;
+ }
+ else
+ {
+ if (startPts[0] > startPts[4])
+ startPts[0]--;
+ if (startPts[4] < endPts[4])
+ endPts[4]--;
+ deltas[4] = -1;
+ }
+ if (arc->angle2 < 0)
+ {
+ DDXPointPtr tmps, tmpe;
+ int tmpd;
+
+ tmpd = deltas[0];
+ tmps = startPts[0] - tmpd;
+ tmpe = endPts[0] - tmpd;
+ startPts[0] = endPts[4] - deltas[4];
+ endPts[0] = startPts[4] - deltas[4];
+ deltas[0] = -deltas[4];
+ startPts[4] = tmpe;
+ endPts[4] = tmps;
+ deltas[4] = -tmpd;
+ tmpd = deltas[1];
+ tmps = startPts[1] - tmpd;
+ tmpe = endPts[1] - tmpd;
+ startPts[1] = endPts[3] - deltas[3];
+ endPts[1] = startPts[3] - deltas[3];
+ deltas[1] = -deltas[3];
+ startPts[3] = tmpe;
+ endPts[3] = tmps;
+ deltas[3] = -tmpd;
+ tmps = startPts[2] - deltas[2];
+ startPts[2] = endPts[2] - deltas[2];
+ endPts[2] = tmps;
+ deltas[2] = -deltas[2];
+ }
+ for (i = 0; i < 5 && startPts[i] == endPts[i]; i++)
+ ;
+ if (i == 5)
+ return;
+ pt = startPts[i];
+ for (j = 4; startPts[j] == endPts[j]; j--)
+ ;
+ lastPt = endPts[j] - deltas[j];
+ if (dinfo->haveLast &&
+ (pt->x == dinfo->endPt.x) && (pt->y == dinfo->endPt.y))
+ {
+ startPts[i] += deltas[i];
+ }
+ else
+ {
+ dinfo->dashIndex = dinfo->dashIndexInit;
+ dinfo->dashOffset = dinfo->dashOffsetInit;
+ }
+ if (!dinfo->skipStart && (info.startAngle != info.endAngle))
+ {
+ dinfo->startPt = *pt;
+ dinfo->haveStart = TRUE;
+ }
+ else if (!dinfo->skipLast && dinfo->haveStart &&
+ (lastPt->x == dinfo->startPt.x) &&
+ (lastPt->y == dinfo->startPt.y) &&
+ (lastPt != startPts[i]))
+ endPts[j] = lastPt;
+ if (info.startAngle != info.endAngle)
+ {
+ dinfo->haveLast = TRUE;
+ dinfo->endPt = *lastPt;
+ }
+ dashRemaining = pGC->dash[dinfo->dashIndex] - dinfo->dashOffset;
+ for (i = 0; i < 5; i++)
+ {
+ pt = startPts[i];
+ lastPt = endPts[i];
+ delta = deltas[i];
+ while (pt != lastPt)
+ {
+ if (dinfo->dashIndex & 1)
+ {
+ pts = *oddPts;
+ ptsdelta = -1;
+ }
+ else
+ {
+ pts = *evenPts;
+ ptsdelta = 1;
+ }
+ while ((pt != lastPt) && --dashRemaining >= 0)
+ {
+ *pts = *pt;
+ pts += ptsdelta;
+ pt += delta;
+ }
+ if (dinfo->dashIndex & 1)
+ *oddPts = pts;
+ else
+ *evenPts = pts;
+ if (dashRemaining <= 0)
+ {
+ if (++(dinfo->dashIndex) == pGC->numInDashList)
+ dinfo->dashIndex = 0;
+ dashRemaining = pGC->dash[dinfo->dashIndex];
+ }
+ }
+ }
+ dinfo->dashOffset = pGC->dash[dinfo->dashIndex] - dashRemaining;
+}
+
+_X_EXPORT void
+miZeroPolyArc(pDraw, pGC, narcs, parcs)
+ DrawablePtr pDraw;
+ GCPtr pGC;
+ int narcs;
+ xArc *parcs;
+{
+ int maxPts = 0;
+ register int n, maxw = 0;
+ register xArc *arc;
+ register int i;
+ DDXPointPtr points, pts, oddPts;
+ register DDXPointPtr pt;
+ int numPts;
+ Bool dospans;
+ int *widths = NULL;
+ XID fgPixel = pGC->fgPixel;
+ DashInfo dinfo;
+
+ for (arc = parcs, i = narcs; --i >= 0; arc++)
+ {
+ if (!miCanZeroArc(arc))
+ miPolyArc(pDraw, pGC, 1, arc);
+ else
+ {
+ if (arc->width > arc->height)
+ n = arc->width + (arc->height >> 1);
+ else
+ n = arc->height + (arc->width >> 1);
+ if (n > maxPts)
+ maxPts = n;
+ }
+ }
+ if (!maxPts)
+ return;
+ numPts = maxPts << 2;
+ dospans = (pGC->fillStyle != FillSolid);
+ if (dospans)
+ {
+ widths = (int *)ALLOCATE_LOCAL(sizeof(int) * numPts);
+ if (!widths)
+ return;
+ maxw = 0;
+ }
+ if (pGC->lineStyle != LineSolid)
+ {
+ numPts <<= 1;
+ dinfo.haveStart = FALSE;
+ dinfo.skipStart = FALSE;
+ dinfo.haveLast = FALSE;
+ dinfo.dashIndexInit = 0;
+ dinfo.dashOffsetInit = 0;
+ miStepDash((int)pGC->dashOffset, &dinfo.dashIndexInit,
+ (unsigned char *) pGC->dash, (int)pGC->numInDashList,
+ &dinfo.dashOffsetInit);
+ }
+ points = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * numPts);
+ if (!points)
+ {
+ if (dospans)
+ {
+ DEALLOCATE_LOCAL(widths);
+ }
+ return;
+ }
+ for (arc = parcs, i = narcs; --i >= 0; arc++)
+ {
+ if (miCanZeroArc(arc))
+ {
+ if (pGC->lineStyle == LineSolid)
+ pts = miZeroArcPts(arc, points);
+ else
+ {
+ pts = points;
+ oddPts = &points[(numPts >> 1) - 1];
+ dinfo.skipLast = i;
+ miZeroArcDashPts(pGC, arc, &dinfo,
+ oddPts + 1, maxPts, &pts, &oddPts);
+ dinfo.skipStart = TRUE;
+ }
+ n = pts - points;
+ if (!dospans)
+ (*pGC->ops->PolyPoint)(pDraw, pGC, CoordModeOrigin, n, points);
+ else
+ {
+ if (n > maxw)
+ {
+ while (maxw < n)
+ widths[maxw++] = 1;
+ }
+ if (pGC->miTranslate)
+ {
+ for (pt = points; pt != pts; pt++)
+ {
+ pt->x += pDraw->x;
+ pt->y += pDraw->y;
+ }
+ }
+ (*pGC->ops->FillSpans)(pDraw, pGC, n, points, widths, FALSE);
+ }
+ if (pGC->lineStyle != LineDoubleDash)
+ continue;
+ if ((pGC->fillStyle == FillSolid) ||
+ (pGC->fillStyle == FillStippled))
+ {
+ DoChangeGC(pGC, GCForeground, (XID *)&pGC->bgPixel, 0);
+ ValidateGC(pDraw, pGC);
+ }
+ pts = &points[numPts >> 1];
+ oddPts++;
+ n = pts - oddPts;
+ if (!dospans)
+ (*pGC->ops->PolyPoint)(pDraw, pGC, CoordModeOrigin, n, oddPts);
+ else
+ {
+ if (n > maxw)
+ {
+ while (maxw < n)
+ widths[maxw++] = 1;
+ }
+ if (pGC->miTranslate)
+ {
+ for (pt = oddPts; pt != pts; pt++)
+ {
+ pt->x += pDraw->x;
+ pt->y += pDraw->y;
+ }
+ }
+ (*pGC->ops->FillSpans)(pDraw, pGC, n, oddPts, widths, FALSE);
+ }
+ if ((pGC->fillStyle == FillSolid) ||
+ (pGC->fillStyle == FillStippled))
+ {
+ DoChangeGC(pGC, GCForeground, &fgPixel, 0);
+ ValidateGC(pDraw, pGC);
+ }
+ }
+ }
+ DEALLOCATE_LOCAL(points);
+ if (dospans)
+ {
+ DEALLOCATE_LOCAL(widths);
+ }
+}
diff --git a/xserver/mi/mizerarc.h b/xserver/mi/mizerarc.h
new file mode 100644
index 000000000..8119d885e
--- /dev/null
+++ b/xserver/mi/mizerarc.h
@@ -0,0 +1,132 @@
+/************************************************************
+
+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.
+
+********************************************************/
+
+
+typedef struct {
+ int x;
+ int y;
+ int mask;
+} miZeroArcPtRec;
+
+typedef struct {
+ int x, y, k1, k3, a, b, d, dx, dy;
+ int alpha, beta;
+ int xorg, yorg;
+ int xorgo, yorgo;
+ int w, h;
+ int initialMask;
+ miZeroArcPtRec start, altstart, end, altend;
+ int firstx, firsty;
+ int startAngle, endAngle;
+} miZeroArcRec;
+
+#define miCanZeroArc(arc) (((arc)->width == (arc)->height) || \
+ (((arc)->width <= 800) && ((arc)->height <= 800)))
+
+#define MIARCSETUP() \
+ x = info.x; \
+ y = info.y; \
+ k1 = info.k1; \
+ k3 = info.k3; \
+ a = info.a; \
+ b = info.b; \
+ d = info.d; \
+ dx = info.dx; \
+ dy = info.dy
+
+#define MIARCOCTANTSHIFT(clause) \
+ if (a < 0) \
+ { \
+ if (y == info.h) \
+ { \
+ d = -1; \
+ a = b = k1 = 0; \
+ } \
+ else \
+ { \
+ dx = (k1 << 1) - k3; \
+ k1 = dx - k1; \
+ k3 = -k3; \
+ b = b + a - (k1 >> 1); \
+ d = b + ((-a) >> 1) - d + (k3 >> 3); \
+ if (dx < 0) \
+ a = -((-dx) >> 1) - a; \
+ else \
+ a = (dx >> 1) - a; \
+ dx = 0; \
+ dy = 1; \
+ clause \
+ } \
+ }
+
+#define MIARCSTEP(move1,move2) \
+ b -= k1; \
+ if (d < 0) \
+ { \
+ x += dx; \
+ y += dy; \
+ a += k1; \
+ d += b; \
+ move1 \
+ } \
+ else \
+ { \
+ x++; \
+ y++; \
+ a += k3; \
+ d -= a; \
+ move2 \
+ }
+
+#define MIARCCIRCLESTEP(clause) \
+ b -= k1; \
+ x++; \
+ if (d < 0) \
+ { \
+ a += k1; \
+ d += b; \
+ } \
+ else \
+ { \
+ y++; \
+ a += k3; \
+ d -= a; \
+ clause \
+ }
+
+/* mizerarc.c */
+
+extern Bool miZeroArcSetup(
+ xArc * /*arc*/,
+ miZeroArcRec * /*info*/,
+ Bool /*ok360*/
+);
+
+extern DDXPointPtr miZeroArcPts(
+ xArc * /*arc*/,
+ DDXPointPtr /*pts*/
+);
+
diff --git a/xserver/mi/mizerclip.c b/xserver/mi/mizerclip.c
new file mode 100644
index 000000000..b167c5475
--- /dev/null
+++ b/xserver/mi/mizerclip.c
@@ -0,0 +1,635 @@
+/***********************************************************
+
+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 "scrnintstr.h"
+#include "gcstruct.h"
+#include "windowstr.h"
+#include "pixmap.h"
+#include "mi.h"
+#include "miline.h"
+
+/*
+
+The bresenham error equation used in the mi/mfb/cfb line routines is:
+
+ e = error
+ dx = difference in raw X coordinates
+ dy = difference in raw Y coordinates
+ M = # of steps in X direction
+ N = # of steps in Y direction
+ B = 0 to prefer diagonal steps in a given octant,
+ 1 to prefer axial steps in a given octant
+
+ For X major lines:
+ e = 2Mdy - 2Ndx - dx - B
+ -2dx <= e < 0
+
+ For Y major lines:
+ e = 2Ndx - 2Mdy - dy - B
+ -2dy <= e < 0
+
+At the start of the line, we have taken 0 X steps and 0 Y steps,
+so M = 0 and N = 0:
+
+ X major e = 2Mdy - 2Ndx - dx - B
+ = -dx - B
+
+ Y major e = 2Ndx - 2Mdy - dy - B
+ = -dy - B
+
+At the end of the line, we have taken dx X steps and dy Y steps,
+so M = dx and N = dy:
+
+ X major e = 2Mdy - 2Ndx - dx - B
+ = 2dxdy - 2dydx - dx - B
+ = -dx - B
+ Y major e = 2Ndx - 2Mdy - dy - B
+ = 2dydx - 2dxdy - dy - B
+ = -dy - B
+
+Thus, the error term is the same at the start and end of the line.
+
+Let us consider clipping an X coordinate. There are 4 cases which
+represent the two independent cases of clipping the start vs. the
+end of the line and an X major vs. a Y major line. In any of these
+cases, we know the number of X steps (M) and we wish to find the
+number of Y steps (N). Thus, we will solve our error term equation.
+If we are clipping the start of the line, we will find the smallest
+N that satisfies our error term inequality. If we are clipping the
+end of the line, we will find the largest number of Y steps that
+satisfies the inequality. In that case, since we are representing
+the Y steps as (dy - N), we will actually want to solve for the
+smallest N in that equation.
+
+Case 1: X major, starting X coordinate moved by M steps
+
+ -2dx <= 2Mdy - 2Ndx - dx - B < 0
+ 2Ndx <= 2Mdy - dx - B + 2dx 2Ndx > 2Mdy - dx - B
+ 2Ndx <= 2Mdy + dx - B N > (2Mdy - dx - B) / 2dx
+ N <= (2Mdy + dx - B) / 2dx
+
+Since we are trying to find the smallest N that satisfies these
+equations, we should use the > inequality to find the smallest:
+
+ N = floor((2Mdy - dx - B) / 2dx) + 1
+ = floor((2Mdy - dx - B + 2dx) / 2dx)
+ = floor((2Mdy + dx - B) / 2dx)
+
+Case 1b: X major, ending X coordinate moved to M steps
+
+Same derivations as Case 1, but we want the largest N that satisfies
+the equations, so we use the <= inequality:
+
+ N = floor((2Mdy + dx - B) / 2dx)
+
+Case 2: X major, ending X coordinate moved by M steps
+
+ -2dx <= 2(dx - M)dy - 2(dy - N)dx - dx - B < 0
+ -2dx <= 2dxdy - 2Mdy - 2dxdy + 2Ndx - dx - B < 0
+ -2dx <= 2Ndx - 2Mdy - dx - B < 0
+ 2Ndx >= 2Mdy + dx + B - 2dx 2Ndx < 2Mdy + dx + B
+ 2Ndx >= 2Mdy - dx + B N < (2Mdy + dx + B) / 2dx
+ N >= (2Mdy - dx + B) / 2dx
+
+Since we are trying to find the highest number of Y steps that
+satisfies these equations, we need to find the smallest N, so
+we should use the >= inequality to find the smallest:
+
+ N = ceiling((2Mdy - dx + B) / 2dx)
+ = floor((2Mdy - dx + B + 2dx - 1) / 2dx)
+ = floor((2Mdy + dx + B - 1) / 2dx)
+
+Case 2b: X major, starting X coordinate moved to M steps from end
+
+Same derivations as Case 2, but we want the smallest number of Y
+steps, so we want the highest N, so we use the < inequality:
+
+ N = ceiling((2Mdy + dx + B) / 2dx) - 1
+ = floor((2Mdy + dx + B + 2dx - 1) / 2dx) - 1
+ = floor((2Mdy + dx + B + 2dx - 1 - 2dx) / 2dx)
+ = floor((2Mdy + dx + B - 1) / 2dx)
+
+Case 3: Y major, starting X coordinate moved by M steps
+
+ -2dy <= 2Ndx - 2Mdy - dy - B < 0
+ 2Ndx >= 2Mdy + dy + B - 2dy 2Ndx < 2Mdy + dy + B
+ 2Ndx >= 2Mdy - dy + B N < (2Mdy + dy + B) / 2dx
+ N >= (2Mdy - dy + B) / 2dx
+
+Since we are trying to find the smallest N that satisfies these
+equations, we should use the >= inequality to find the smallest:
+
+ N = ceiling((2Mdy - dy + B) / 2dx)
+ = floor((2Mdy - dy + B + 2dx - 1) / 2dx)
+ = floor((2Mdy - dy + B - 1) / 2dx) + 1
+
+Case 3b: Y major, ending X coordinate moved to M steps
+
+Same derivations as Case 3, but we want the largest N that satisfies
+the equations, so we use the < inequality:
+
+ N = ceiling((2Mdy + dy + B) / 2dx) - 1
+ = floor((2Mdy + dy + B + 2dx - 1) / 2dx) - 1
+ = floor((2Mdy + dy + B + 2dx - 1 - 2dx) / 2dx)
+ = floor((2Mdy + dy + B - 1) / 2dx)
+
+Case 4: Y major, ending X coordinate moved by M steps
+
+ -2dy <= 2(dy - N)dx - 2(dx - M)dy - dy - B < 0
+ -2dy <= 2dxdy - 2Ndx - 2dxdy + 2Mdy - dy - B < 0
+ -2dy <= 2Mdy - 2Ndx - dy - B < 0
+ 2Ndx <= 2Mdy - dy - B + 2dy 2Ndx > 2Mdy - dy - B
+ 2Ndx <= 2Mdy + dy - B N > (2Mdy - dy - B) / 2dx
+ N <= (2Mdy + dy - B) / 2dx
+
+Since we are trying to find the highest number of Y steps that
+satisfies these equations, we need to find the smallest N, so
+we should use the > inequality to find the smallest:
+
+ N = floor((2Mdy - dy - B) / 2dx) + 1
+
+Case 4b: Y major, starting X coordinate moved to M steps from end
+
+Same analysis as Case 4, but we want the smallest number of Y steps
+which means the largest N, so we use the <= inequality:
+
+ N = floor((2Mdy + dy - B) / 2dx)
+
+Now let's try the Y coordinates, we have the same 4 cases.
+
+Case 5: X major, starting Y coordinate moved by N steps
+
+ -2dx <= 2Mdy - 2Ndx - dx - B < 0
+ 2Mdy >= 2Ndx + dx + B - 2dx 2Mdy < 2Ndx + dx + B
+ 2Mdy >= 2Ndx - dx + B M < (2Ndx + dx + B) / 2dy
+ M >= (2Ndx - dx + B) / 2dy
+
+Since we are trying to find the smallest M, we use the >= inequality:
+
+ M = ceiling((2Ndx - dx + B) / 2dy)
+ = floor((2Ndx - dx + B + 2dy - 1) / 2dy)
+ = floor((2Ndx - dx + B - 1) / 2dy) + 1
+
+Case 5b: X major, ending Y coordinate moved to N steps
+
+Same derivations as Case 5, but we want the largest M that satisfies
+the equations, so we use the < inequality:
+
+ M = ceiling((2Ndx + dx + B) / 2dy) - 1
+ = floor((2Ndx + dx + B + 2dy - 1) / 2dy) - 1
+ = floor((2Ndx + dx + B + 2dy - 1 - 2dy) / 2dy)
+ = floor((2Ndx + dx + B - 1) / 2dy)
+
+Case 6: X major, ending Y coordinate moved by N steps
+
+ -2dx <= 2(dx - M)dy - 2(dy - N)dx - dx - B < 0
+ -2dx <= 2dxdy - 2Mdy - 2dxdy + 2Ndx - dx - B < 0
+ -2dx <= 2Ndx - 2Mdy - dx - B < 0
+ 2Mdy <= 2Ndx - dx - B + 2dx 2Mdy > 2Ndx - dx - B
+ 2Mdy <= 2Ndx + dx - B M > (2Ndx - dx - B) / 2dy
+ M <= (2Ndx + dx - B) / 2dy
+
+Largest # of X steps means smallest M, so use the > inequality:
+
+ M = floor((2Ndx - dx - B) / 2dy) + 1
+
+Case 6b: X major, starting Y coordinate moved to N steps from end
+
+Same derivations as Case 6, but we want the smallest # of X steps
+which means the largest M, so use the <= inequality:
+
+ M = floor((2Ndx + dx - B) / 2dy)
+
+Case 7: Y major, starting Y coordinate moved by N steps
+
+ -2dy <= 2Ndx - 2Mdy - dy - B < 0
+ 2Mdy <= 2Ndx - dy - B + 2dy 2Mdy > 2Ndx - dy - B
+ 2Mdy <= 2Ndx + dy - B M > (2Ndx - dy - B) / 2dy
+ M <= (2Ndx + dy - B) / 2dy
+
+To find the smallest M, use the > inequality:
+
+ M = floor((2Ndx - dy - B) / 2dy) + 1
+ = floor((2Ndx - dy - B + 2dy) / 2dy)
+ = floor((2Ndx + dy - B) / 2dy)
+
+Case 7b: Y major, ending Y coordinate moved to N steps
+
+Same derivations as Case 7, but we want the largest M that satisfies
+the equations, so use the <= inequality:
+
+ M = floor((2Ndx + dy - B) / 2dy)
+
+Case 8: Y major, ending Y coordinate moved by N steps
+
+ -2dy <= 2(dy - N)dx - 2(dx - M)dy - dy - B < 0
+ -2dy <= 2dxdy - 2Ndx - 2dxdy + 2Mdy - dy - B < 0
+ -2dy <= 2Mdy - 2Ndx - dy - B < 0
+ 2Mdy >= 2Ndx + dy + B - 2dy 2Mdy < 2Ndx + dy + B
+ 2Mdy >= 2Ndx - dy + B M < (2Ndx + dy + B) / 2dy
+ M >= (2Ndx - dy + B) / 2dy
+
+To find the highest X steps, find the smallest M, use the >= inequality:
+
+ M = ceiling((2Ndx - dy + B) / 2dy)
+ = floor((2Ndx - dy + B + 2dy - 1) / 2dy)
+ = floor((2Ndx + dy + B - 1) / 2dy)
+
+Case 8b: Y major, starting Y coordinate moved to N steps from the end
+
+Same derivations as Case 8, but we want to find the smallest # of X
+steps which means the largest M, so we use the < inequality:
+
+ M = ceiling((2Ndx + dy + B) / 2dy) - 1
+ = floor((2Ndx + dy + B + 2dy - 1) / 2dy) - 1
+ = floor((2Ndx + dy + B + 2dy - 1 - 2dy) / 2dy)
+ = floor((2Ndx + dy + B - 1) / 2dy)
+
+So, our equations are:
+
+ 1: X major move x1 to x1+M floor((2Mdy + dx - B) / 2dx)
+ 1b: X major move x2 to x1+M floor((2Mdy + dx - B) / 2dx)
+ 2: X major move x2 to x2-M floor((2Mdy + dx + B - 1) / 2dx)
+ 2b: X major move x1 to x2-M floor((2Mdy + dx + B - 1) / 2dx)
+
+ 3: Y major move x1 to x1+M floor((2Mdy - dy + B - 1) / 2dx) + 1
+ 3b: Y major move x2 to x1+M floor((2Mdy + dy + B - 1) / 2dx)
+ 4: Y major move x2 to x2-M floor((2Mdy - dy - B) / 2dx) + 1
+ 4b: Y major move x1 to x2-M floor((2Mdy + dy - B) / 2dx)
+
+ 5: X major move y1 to y1+N floor((2Ndx - dx + B - 1) / 2dy) + 1
+ 5b: X major move y2 to y1+N floor((2Ndx + dx + B - 1) / 2dy)
+ 6: X major move y2 to y2-N floor((2Ndx - dx - B) / 2dy) + 1
+ 6b: X major move y1 to y2-N floor((2Ndx + dx - B) / 2dy)
+
+ 7: Y major move y1 to y1+N floor((2Ndx + dy - B) / 2dy)
+ 7b: Y major move y2 to y1+N floor((2Ndx + dy - B) / 2dy)
+ 8: Y major move y2 to y2-N floor((2Ndx + dy + B - 1) / 2dy)
+ 8b: Y major move y1 to y2-N floor((2Ndx + dy + B - 1) / 2dy)
+
+We have the following constraints on all of the above terms:
+
+ 0 < M,N <= 2^15 2^15 can be imposed by miZeroClipLine
+ 0 <= dx/dy <= 2^16 - 1
+ 0 <= B <= 1
+
+The floor in all of the above equations can be accomplished with a
+simple C divide operation provided that both numerator and denominator
+are positive.
+
+Since dx,dy >= 0 and since moving an X coordinate implies that dx != 0
+and moving a Y coordinate implies dy != 0, we know that the denominators
+are all > 0.
+
+For all lines, (-B) and (B-1) are both either 0 or -1, depending on the
+bias. Thus, we have to show that the 2MNdxy +/- dxy terms are all >= 1
+or > 0 to prove that the numerators are positive (or zero).
+
+For X Major lines we know that dx > 0 and since 2Mdy is >= 0 due to the
+constraints, the first four equations all have numerators >= 0.
+
+For the second four equations, M > 0, so 2Mdy >= 2dy so (2Mdy - dy) >= dy
+So (2Mdy - dy) > 0, since they are Y major lines. Also, (2Mdy + dy) >= 3dy
+or (2Mdy + dy) > 0. So all of their numerators are >= 0.
+
+For the third set of four equations, N > 0, so 2Ndx >= 2dx so (2Ndx - dx)
+>= dx > 0. Similarly (2Ndx + dx) >= 3dx > 0. So all numerators >= 0.
+
+For the fourth set of equations, dy > 0 and 2Ndx >= 0, so all numerators
+are > 0.
+
+To consider overflow, consider the case of 2 * M,N * dx,dy + dx,dy. This
+is bounded <= 2 * 2^15 * (2^16 - 1) + (2^16 - 1)
+ <= 2^16 * (2^16 - 1) + (2^16 - 1)
+ <= 2^32 - 2^16 + 2^16 - 1
+ <= 2^32 - 1
+Since the (-B) and (B-1) terms are all 0 or -1, the maximum value of
+the numerator is therefore (2^32 - 1), which does not overflow an unsigned
+32 bit variable.
+
+*/
+
+/* Bit codes for the terms of the 16 clipping equations defined below. */
+
+#define T_2NDX (1 << 0)
+#define T_2MDY (0) /* implicit term */
+#define T_DXNOTY (1 << 1)
+#define T_DYNOTX (0) /* implicit term */
+#define T_SUBDXORY (1 << 2)
+#define T_ADDDX (T_DXNOTY) /* composite term */
+#define T_SUBDX (T_DXNOTY | T_SUBDXORY) /* composite term */
+#define T_ADDDY (T_DYNOTX) /* composite term */
+#define T_SUBDY (T_DYNOTX | T_SUBDXORY) /* composite term */
+#define T_BIASSUBONE (1 << 3)
+#define T_SUBBIAS (0) /* implicit term */
+#define T_DIV2DX (1 << 4)
+#define T_DIV2DY (0) /* implicit term */
+#define T_ADDONE (1 << 5)
+
+/* Bit masks defining the 16 equations used in miZeroClipLine. */
+
+#define EQN1 (T_2MDY | T_ADDDX | T_SUBBIAS | T_DIV2DX)
+#define EQN1B (T_2MDY | T_ADDDX | T_SUBBIAS | T_DIV2DX)
+#define EQN2 (T_2MDY | T_ADDDX | T_BIASSUBONE | T_DIV2DX)
+#define EQN2B (T_2MDY | T_ADDDX | T_BIASSUBONE | T_DIV2DX)
+
+#define EQN3 (T_2MDY | T_SUBDY | T_BIASSUBONE | T_DIV2DX | T_ADDONE)
+#define EQN3B (T_2MDY | T_ADDDY | T_BIASSUBONE | T_DIV2DX)
+#define EQN4 (T_2MDY | T_SUBDY | T_SUBBIAS | T_DIV2DX | T_ADDONE)
+#define EQN4B (T_2MDY | T_ADDDY | T_SUBBIAS | T_DIV2DX)
+
+#define EQN5 (T_2NDX | T_SUBDX | T_BIASSUBONE | T_DIV2DY | T_ADDONE)
+#define EQN5B (T_2NDX | T_ADDDX | T_BIASSUBONE | T_DIV2DY)
+#define EQN6 (T_2NDX | T_SUBDX | T_SUBBIAS | T_DIV2DY | T_ADDONE)
+#define EQN6B (T_2NDX | T_ADDDX | T_SUBBIAS | T_DIV2DY)
+
+#define EQN7 (T_2NDX | T_ADDDY | T_SUBBIAS | T_DIV2DY)
+#define EQN7B (T_2NDX | T_ADDDY | T_SUBBIAS | T_DIV2DY)
+#define EQN8 (T_2NDX | T_ADDDY | T_BIASSUBONE | T_DIV2DY)
+#define EQN8B (T_2NDX | T_ADDDY | T_BIASSUBONE | T_DIV2DY)
+
+/* miZeroClipLine
+ *
+ * returns: 1 for partially clipped line
+ * -1 for completely clipped line
+ *
+ */
+_X_EXPORT int
+miZeroClipLine(xmin, ymin, xmax, ymax,
+ new_x1, new_y1, new_x2, new_y2,
+ adx, ady,
+ pt1_clipped, pt2_clipped, octant, bias, oc1, oc2)
+ int xmin, ymin, xmax, ymax;
+ int *new_x1, *new_y1, *new_x2, *new_y2;
+ int *pt1_clipped, *pt2_clipped;
+ unsigned int adx, ady;
+ int octant;
+ unsigned int bias;
+ int oc1, oc2;
+{
+ int swapped = 0;
+ int clipDone = 0;
+ CARD32 utmp = 0;
+ int clip1, clip2;
+ int x1, y1, x2, y2;
+ int x1_orig, y1_orig, x2_orig, y2_orig;
+ int xmajor;
+ int negslope = 0, anchorval = 0;
+ unsigned int eqn = 0;
+
+ x1 = x1_orig = *new_x1;
+ y1 = y1_orig = *new_y1;
+ x2 = x2_orig = *new_x2;
+ y2 = y2_orig = *new_y2;
+
+ clip1 = 0;
+ clip2 = 0;
+
+ xmajor = IsXMajorOctant(octant);
+ bias = ((bias >> octant) & 1);
+
+ while (1)
+ {
+ if ((oc1 & oc2) != 0) /* trivial reject */
+ {
+ clipDone = -1;
+ clip1 = oc1;
+ clip2 = oc2;
+ break;
+ }
+ else if ((oc1 | oc2) == 0) /* trivial accept */
+ {
+ clipDone = 1;
+ if (swapped)
+ {
+ SWAPINT_PAIR(x1, y1, x2, y2);
+ SWAPINT(clip1, clip2);
+ }
+ break;
+ }
+ else /* have to clip */
+ {
+ /* only clip one point at a time */
+ if (oc1 == 0)
+ {
+ SWAPINT_PAIR(x1, y1, x2, y2);
+ SWAPINT_PAIR(x1_orig, y1_orig, x2_orig, y2_orig);
+ SWAPINT(oc1, oc2);
+ SWAPINT(clip1, clip2);
+ swapped = !swapped;
+ }
+
+ clip1 |= oc1;
+ if (oc1 & OUT_LEFT)
+ {
+ negslope = IsYDecreasingOctant(octant);
+ utmp = xmin - x1_orig;
+ if (utmp <= 32767) /* clip based on near endpt */
+ {
+ if (xmajor)
+ eqn = (swapped) ? EQN2 : EQN1;
+ else
+ eqn = (swapped) ? EQN4 : EQN3;
+ anchorval = y1_orig;
+ }
+ else /* clip based on far endpt */
+ {
+ utmp = x2_orig - xmin;
+ if (xmajor)
+ eqn = (swapped) ? EQN1B : EQN2B;
+ else
+ eqn = (swapped) ? EQN3B : EQN4B;
+ anchorval = y2_orig;
+ negslope = !negslope;
+ }
+ x1 = xmin;
+ }
+ else if (oc1 & OUT_ABOVE)
+ {
+ negslope = IsXDecreasingOctant(octant);
+ utmp = ymin - y1_orig;
+ if (utmp <= 32767) /* clip based on near endpt */
+ {
+ if (xmajor)
+ eqn = (swapped) ? EQN6 : EQN5;
+ else
+ eqn = (swapped) ? EQN8 : EQN7;
+ anchorval = x1_orig;
+ }
+ else /* clip based on far endpt */
+ {
+ utmp = y2_orig - ymin;
+ if (xmajor)
+ eqn = (swapped) ? EQN5B : EQN6B;
+ else
+ eqn = (swapped) ? EQN7B : EQN8B;
+ anchorval = x2_orig;
+ negslope = !negslope;
+ }
+ y1 = ymin;
+ }
+ else if (oc1 & OUT_RIGHT)
+ {
+ negslope = IsYDecreasingOctant(octant);
+ utmp = x1_orig - xmax;
+ if (utmp <= 32767) /* clip based on near endpt */
+ {
+ if (xmajor)
+ eqn = (swapped) ? EQN2 : EQN1;
+ else
+ eqn = (swapped) ? EQN4 : EQN3;
+ anchorval = y1_orig;
+ }
+ else /* clip based on far endpt */
+ {
+ /*
+ * Technically since the equations can handle
+ * utmp == 32768, this overflow code isn't
+ * needed since X11 protocol can't generate
+ * a line which goes more than 32768 pixels
+ * to the right of a clip rectangle.
+ */
+ utmp = xmax - x2_orig;
+ if (xmajor)
+ eqn = (swapped) ? EQN1B : EQN2B;
+ else
+ eqn = (swapped) ? EQN3B : EQN4B;
+ anchorval = y2_orig;
+ negslope = !negslope;
+ }
+ x1 = xmax;
+ }
+ else if (oc1 & OUT_BELOW)
+ {
+ negslope = IsXDecreasingOctant(octant);
+ utmp = y1_orig - ymax;
+ if (utmp <= 32767) /* clip based on near endpt */
+ {
+ if (xmajor)
+ eqn = (swapped) ? EQN6 : EQN5;
+ else
+ eqn = (swapped) ? EQN8 : EQN7;
+ anchorval = x1_orig;
+ }
+ else /* clip based on far endpt */
+ {
+ /*
+ * Technically since the equations can handle
+ * utmp == 32768, this overflow code isn't
+ * needed since X11 protocol can't generate
+ * a line which goes more than 32768 pixels
+ * below the bottom of a clip rectangle.
+ */
+ utmp = ymax - y2_orig;
+ if (xmajor)
+ eqn = (swapped) ? EQN5B : EQN6B;
+ else
+ eqn = (swapped) ? EQN7B : EQN8B;
+ anchorval = x2_orig;
+ negslope = !negslope;
+ }
+ y1 = ymax;
+ }
+
+ if (swapped)
+ negslope = !negslope;
+
+ utmp <<= 1; /* utmp = 2N or 2M */
+ if (eqn & T_2NDX)
+ utmp = (utmp * adx);
+ else /* (eqn & T_2MDY) */
+ utmp = (utmp * ady);
+ if (eqn & T_DXNOTY)
+ if (eqn & T_SUBDXORY)
+ utmp -= adx;
+ else
+ utmp += adx;
+ else /* (eqn & T_DYNOTX) */
+ if (eqn & T_SUBDXORY)
+ utmp -= ady;
+ else
+ utmp += ady;
+ if (eqn & T_BIASSUBONE)
+ utmp += bias - 1;
+ else /* (eqn & T_SUBBIAS) */
+ utmp -= bias;
+ if (eqn & T_DIV2DX)
+ utmp /= (adx << 1);
+ else /* (eqn & T_DIV2DY) */
+ utmp /= (ady << 1);
+ if (eqn & T_ADDONE)
+ utmp++;
+
+ if (negslope)
+ utmp = -utmp;
+
+ if (eqn & T_2NDX) /* We are calculating X steps */
+ x1 = anchorval + utmp;
+ else /* else, Y steps */
+ y1 = anchorval + utmp;
+
+ oc1 = 0;
+ MIOUTCODES(oc1, x1, y1, xmin, ymin, xmax, ymax);
+ }
+ }
+
+ *new_x1 = x1;
+ *new_y1 = y1;
+ *new_x2 = x2;
+ *new_y2 = y2;
+
+ *pt1_clipped = clip1;
+ *pt2_clipped = clip2;
+
+ return clipDone;
+}
diff --git a/xserver/mi/mizerline.c b/xserver/mi/mizerline.c
new file mode 100644
index 000000000..073f1b20f
--- /dev/null
+++ b/xserver/mi/mizerline.c
@@ -0,0 +1,378 @@
+/***********************************************************
+
+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 "scrnintstr.h"
+#include "gcstruct.h"
+#include "windowstr.h"
+#include "pixmap.h"
+#include "mi.h"
+#include "miline.h"
+
+/* Draw lineSolid, fillStyle-independent zero width lines.
+ *
+ * Must keep X and Y coordinates in "ints" at least until after they're
+ * translated and clipped to accomodate CoordModePrevious lines with very
+ * large coordinates.
+ *
+ * Draws the same pixels regardless of sign(dx) or sign(dy).
+ *
+ * Ken Whaley
+ *
+ */
+
+/* largest positive value that can fit into a component of a point.
+ * Assumes that the point structure is {type x, y;} where type is
+ * a signed type.
+ */
+#define MAX_COORDINATE ((1 << (((sizeof(DDXPointRec) >> 1) << 3) - 1)) - 1)
+
+#define MI_OUTPUT_POINT(xx, yy)\
+{\
+ if ( !new_span && yy == current_y)\
+ {\
+ if (xx < spans->x)\
+ spans->x = xx;\
+ ++*widths;\
+ }\
+ else\
+ {\
+ ++Nspans;\
+ ++spans;\
+ ++widths;\
+ spans->x = xx;\
+ spans->y = yy;\
+ *widths = 1;\
+ current_y = yy;\
+ new_span = FALSE;\
+ }\
+}
+
+_X_EXPORT void
+miZeroLine(pDraw, pGC, mode, npt, pptInit)
+ DrawablePtr pDraw;
+ GCPtr pGC;
+ int mode; /* Origin or Previous */
+ int npt; /* number of points */
+ DDXPointPtr pptInit;
+{
+ int Nspans, current_y = 0;
+ DDXPointPtr ppt;
+ DDXPointPtr pspanInit, spans;
+ int *pwidthInit, *widths, list_len;
+ int xleft, ytop, xright, ybottom;
+ int new_x1, new_y1, new_x2, new_y2;
+ int x = 0, y = 0, x1, y1, x2, y2, xstart, ystart;
+ int oc1, oc2;
+ int result;
+ int pt1_clipped, pt2_clipped = 0;
+ Bool new_span;
+ int signdx, signdy;
+ int clipdx, clipdy;
+ int width, height;
+ int adx, ady;
+ int octant;
+ unsigned int bias = miGetZeroLineBias(pDraw->pScreen);
+ int e, e1, e2, e3; /* Bresenham error terms */
+ int length; /* length of lines == # of pixels on major axis */
+
+ xleft = pDraw->x;
+ ytop = pDraw->y;
+ xright = pDraw->x + pDraw->width - 1;
+ ybottom = pDraw->y + pDraw->height - 1;
+
+ if (!pGC->miTranslate)
+ {
+ /* do everything in drawable-relative coordinates */
+ xleft = 0;
+ ytop = 0;
+ xright -= pDraw->x;
+ ybottom -= pDraw->y;
+ }
+
+ /* it doesn't matter whether we're in drawable or screen coordinates,
+ * FillSpans simply cannot take starting coordinates outside of the
+ * range of a DDXPointRec component.
+ */
+ if (xright > MAX_COORDINATE)
+ xright = MAX_COORDINATE;
+ if (ybottom > MAX_COORDINATE)
+ ybottom = MAX_COORDINATE;
+
+ /* since we're clipping to the drawable's boundaries & coordinate
+ * space boundaries, we're guaranteed that the larger of width/height
+ * is the longest span we'll need to output
+ */
+ width = xright - xleft + 1;
+ height = ybottom - ytop + 1;
+ list_len = (height >= width) ? height : width;
+ pspanInit = (DDXPointPtr)ALLOCATE_LOCAL(list_len * sizeof(DDXPointRec));
+ pwidthInit = (int *)ALLOCATE_LOCAL(list_len * sizeof(int));
+ if (!pspanInit || !pwidthInit)
+ return;
+
+ Nspans = 0;
+ new_span = TRUE;
+ spans = pspanInit - 1;
+ widths = pwidthInit - 1;
+ ppt = pptInit;
+
+ xstart = ppt->x;
+ ystart = ppt->y;
+ if (pGC->miTranslate)
+ {
+ xstart += pDraw->x;
+ ystart += pDraw->y;
+ }
+
+ /* x2, y2, oc2 copied to x1, y1, oc1 at top of loop to simplify
+ * iteration logic
+ */
+ x2 = xstart;
+ y2 = ystart;
+ oc2 = 0;
+ MIOUTCODES(oc2, x2, y2, xleft, ytop, xright, ybottom);
+
+ while (--npt > 0)
+ {
+ if (Nspans > 0)
+ (*pGC->ops->FillSpans)(pDraw, pGC, Nspans, pspanInit,
+ pwidthInit, FALSE);
+ Nspans = 0;
+ new_span = TRUE;
+ spans = pspanInit - 1;
+ widths = pwidthInit - 1;
+
+ x1 = x2;
+ y1 = y2;
+ oc1 = oc2;
+ ++ppt;
+
+ x2 = ppt->x;
+ y2 = ppt->y;
+ if (pGC->miTranslate && (mode != CoordModePrevious))
+ {
+ x2 += pDraw->x;
+ y2 += pDraw->y;
+ }
+ else if (mode == CoordModePrevious)
+ {
+ x2 += x1;
+ y2 += y1;
+ }
+
+ oc2 = 0;
+ MIOUTCODES(oc2, x2, y2, xleft, ytop, xright, ybottom);
+
+ CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy, 1, 1, octant);
+
+ if (adx > ady)
+ {
+ e1 = ady << 1;
+ e2 = e1 - (adx << 1);
+ e = e1 - adx;
+ length = adx; /* don't draw endpoint in main loop */
+
+ FIXUP_ERROR(e, octant, bias);
+
+ new_x1 = x1;
+ new_y1 = y1;
+ new_x2 = x2;
+ new_y2 = y2;
+ pt1_clipped = 0;
+ pt2_clipped = 0;
+
+ if ((oc1 | oc2) != 0)
+ {
+ result = miZeroClipLine(xleft, ytop, xright, ybottom,
+ &new_x1, &new_y1, &new_x2, &new_y2,
+ adx, ady,
+ &pt1_clipped, &pt2_clipped,
+ octant, bias, oc1, oc2);
+ if (result == -1)
+ continue;
+
+ length = abs(new_x2 - new_x1);
+
+ /* if we've clipped the endpoint, always draw the full length
+ * of the segment, because then the capstyle doesn't matter
+ */
+ if (pt2_clipped)
+ length++;
+
+ if (pt1_clipped)
+ {
+ /* must calculate new error terms */
+ clipdx = abs(new_x1 - x1);
+ clipdy = abs(new_y1 - y1);
+ e += (clipdy * e2) + ((clipdx - clipdy) * e1);
+ }
+ }
+
+ /* draw the segment */
+
+ x = new_x1;
+ y = new_y1;
+
+ e3 = e2 - e1;
+ e = e - e1;
+
+ while (length--)
+ {
+ MI_OUTPUT_POINT(x, y);
+ e += e1;
+ if (e >= 0)
+ {
+ y += signdy;
+ e += e3;
+ }
+ x += signdx;
+ }
+ }
+ else /* Y major line */
+ {
+ e1 = adx << 1;
+ e2 = e1 - (ady << 1);
+ e = e1 - ady;
+ length = ady; /* don't draw endpoint in main loop */
+
+ SetYMajorOctant(octant);
+ FIXUP_ERROR(e, octant, bias);
+
+ new_x1 = x1;
+ new_y1 = y1;
+ new_x2 = x2;
+ new_y2 = y2;
+ pt1_clipped = 0;
+ pt2_clipped = 0;
+
+ if ((oc1 | oc2) != 0)
+ {
+ result = miZeroClipLine(xleft, ytop, xright, ybottom,
+ &new_x1, &new_y1, &new_x2, &new_y2,
+ adx, ady,
+ &pt1_clipped, &pt2_clipped,
+ octant, bias, oc1, oc2);
+ if (result == -1)
+ continue;
+
+ length = abs(new_y2 - new_y1);
+
+ /* if we've clipped the endpoint, always draw the full length
+ * of the segment, because then the capstyle doesn't matter
+ */
+ if (pt2_clipped)
+ length++;
+
+ if (pt1_clipped)
+ {
+ /* must calculate new error terms */
+ clipdx = abs(new_x1 - x1);
+ clipdy = abs(new_y1 - y1);
+ e += (clipdx * e2) + ((clipdy - clipdx) * e1);
+ }
+ }
+
+ /* draw the segment */
+
+ x = new_x1;
+ y = new_y1;
+
+ e3 = e2 - e1;
+ e = e - e1;
+
+ while (length--)
+ {
+ MI_OUTPUT_POINT(x, y);
+ e += e1;
+ if (e >= 0)
+ {
+ x += signdx;
+ e += e3;
+ }
+ y += signdy;
+ }
+ }
+ }
+
+ /* only do the capnotlast check on the last segment
+ * and only if the endpoint wasn't clipped. And then, if the last
+ * point is the same as the first point, do not draw it, unless the
+ * line is degenerate
+ */
+ if ( (! pt2_clipped) && (pGC->capStyle != CapNotLast) &&
+ (((xstart != x2) || (ystart != y2)) || (ppt == pptInit + 1)))
+ {
+ MI_OUTPUT_POINT(x, y);
+ }
+
+ if (Nspans > 0)
+ (*pGC->ops->FillSpans)(pDraw, pGC, Nspans, pspanInit,
+ pwidthInit, FALSE);
+
+ DEALLOCATE_LOCAL(pwidthInit);
+ DEALLOCATE_LOCAL(pspanInit);
+}
+
+_X_EXPORT void
+miZeroDashLine(dst, pgc, mode, nptInit, pptInit)
+DrawablePtr dst;
+GCPtr pgc;
+int mode;
+int nptInit; /* number of points in polyline */
+DDXPointRec *pptInit; /* points in the polyline */
+{
+ /* XXX kludge until real zero-width dash code is written */
+ pgc->lineWidth = 1;
+ miWideDash (dst, pgc, mode, nptInit, pptInit);
+ pgc->lineWidth = 0;
+}