diff options
author | marha <marha@users.sourceforge.net> | 2009-06-28 22:07:26 +0000 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2009-06-28 22:07:26 +0000 |
commit | 3562e78743202e43aec8727005182a2558117eca (patch) | |
tree | 8f9113a77d12470c5c851a2a8e4cb02e89df7d43 /xorg-server/mi | |
download | vcxsrv-3562e78743202e43aec8727005182a2558117eca.tar.gz vcxsrv-3562e78743202e43aec8727005182a2558117eca.tar.bz2 vcxsrv-3562e78743202e43aec8727005182a2558117eca.zip |
Checked in the following released items:
xkeyboard-config-1.4.tar.gz
ttf-bitstream-vera-1.10.tar.gz
font-alias-1.0.1.tar.gz
font-sun-misc-1.0.0.tar.gz
font-sun-misc-1.0.0.tar.gz
font-sony-misc-1.0.0.tar.gz
font-schumacher-misc-1.0.0.tar.gz
font-mutt-misc-1.0.0.tar.gz
font-misc-misc-1.0.0.tar.gz
font-misc-meltho-1.0.0.tar.gz
font-micro-misc-1.0.0.tar.gz
font-jis-misc-1.0.0.tar.gz
font-isas-misc-1.0.0.tar.gz
font-dec-misc-1.0.0.tar.gz
font-daewoo-misc-1.0.0.tar.gz
font-cursor-misc-1.0.0.tar.gz
font-arabic-misc-1.0.0.tar.gz
font-winitzki-cyrillic-1.0.0.tar.gz
font-misc-cyrillic-1.0.0.tar.gz
font-cronyx-cyrillic-1.0.0.tar.gz
font-screen-cyrillic-1.0.1.tar.gz
font-xfree86-type1-1.0.1.tar.gz
font-adobe-utopia-type1-1.0.1.tar.gz
font-ibm-type1-1.0.0.tar.gz
font-bitstream-type1-1.0.0.tar.gz
font-bitstream-speedo-1.0.0.tar.gz
font-bh-ttf-1.0.0.tar.gz
font-bh-type1-1.0.0.tar.gz
font-bitstream-100dpi-1.0.0.tar.gz
font-bh-lucidatypewriter-100dpi-1.0.0.tar.gz
font-bh-100dpi-1.0.0.tar.gz
font-adobe-utopia-100dpi-1.0.1.tar.gz
font-adobe-100dpi-1.0.0.tar.gz
font-util-1.0.1.tar.gz
font-bitstream-75dpi-1.0.0.tar.gz
font-bh-lucidatypewriter-75dpi-1.0.0.tar.gz
font-adobe-utopia-75dpi-1.0.1.tar.gz
font-bh-75dpi-1.0.0.tar.gz
bdftopcf-1.0.1.tar.gz
font-adobe-75dpi-1.0.0.tar.gz
mkfontscale-1.0.6.tar.gz
openssl-0.9.8k.tar.gz
bigreqsproto-1.0.2.tar.gz
xtrans-1.2.2.tar.gz
resourceproto-1.0.2.tar.gz
inputproto-1.4.4.tar.gz
compositeproto-0.4.tar.gz
damageproto-1.1.0.tar.gz
zlib-1.2.3.tar.gz
xkbcomp-1.0.5.tar.gz
freetype-2.3.9.tar.gz
pthreads-w32-2-8-0-release.tar.gz
pixman-0.12.0.tar.gz
kbproto-1.0.3.tar.gz
evieext-1.0.2.tar.gz
fixesproto-4.0.tar.gz
recordproto-1.13.2.tar.gz
randrproto-1.2.2.tar.gz
scrnsaverproto-1.1.0.tar.gz
renderproto-0.9.3.tar.gz
xcmiscproto-1.1.2.tar.gz
fontsproto-2.0.2.tar.gz
xextproto-7.0.3.tar.gz
xproto-7.0.14.tar.gz
libXdmcp-1.0.2.tar.gz
libxkbfile-1.0.5.tar.gz
libfontenc-1.0.4.tar.gz
libXfont-1.3.4.tar.gz
libX11-1.1.5.tar.gz
libXau-1.0.4.tar.gz
libxcb-1.1.tar.gz
xorg-server-1.5.3.tar.gz
Diffstat (limited to 'xorg-server/mi')
61 files changed, 29689 insertions, 0 deletions
diff --git a/xorg-server/mi/Makefile.am b/xorg-server/mi/Makefile.am new file mode 100644 index 000000000..7d76929ef --- /dev/null +++ b/xorg-server/mi/Makefile.am @@ -0,0 +1,69 @@ +noinst_LTLIBRARIES = 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) + +libmi_la_SOURCES = \ + 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 diff --git a/xorg-server/mi/Makefile.in b/xorg-server/mi/Makefile.in new file mode 100644 index 000000000..451dcd889 --- /dev/null +++ b/xorg-server/mi/Makefile.in @@ -0,0 +1,782 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 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@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +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_libmi_la_OBJECTS = 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 +libmi_la_OBJECTS = $(am_libmi_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -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 $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libmi_la_SOURCES) +DIST_SOURCES = $(libmi_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@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +APPDEFAULTDIR = @APPDEFAULTDIR@ +APPLE_APPLICATIONS_DIR = @APPLE_APPLICATIONS_DIR@ +APP_MAN_DIR = @APP_MAN_DIR@ +APP_MAN_SUFFIX = @APP_MAN_SUFFIX@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BASE_FONT_PATH = @BASE_FONT_PATH@ +BUILD_DATE = @BUILD_DATE@ +BUILD_TIME = @BUILD_TIME@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +COMPILEDDEFAULTFONTPATH = @COMPILEDDEFAULTFONTPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DARWIN_LIBS = @DARWIN_LIBS@ +DBUS_CFLAGS = @DBUS_CFLAGS@ +DBUS_LIBS = @DBUS_LIBS@ +DEFAULT_LIBRARY_PATH = @DEFAULT_LIBRARY_PATH@ +DEFAULT_LOGPREFIX = @DEFAULT_LOGPREFIX@ +DEFAULT_MODULE_PATH = @DEFAULT_MODULE_PATH@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DGA_CFLAGS = @DGA_CFLAGS@ +DGA_LIBS = @DGA_LIBS@ +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@ +DRI2PROTO_CFLAGS = @DRI2PROTO_CFLAGS@ +DRI2PROTO_LIBS = @DRI2PROTO_LIBS@ +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@ +DSYMUTIL = @DSYMUTIL@ +DTRACE = @DTRACE@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FILE_MAN_DIR = @FILE_MAN_DIR@ +FILE_MAN_SUFFIX = @FILE_MAN_SUFFIX@ +FREETYPE_CFLAGS = @FREETYPE_CFLAGS@ +FREETYPE_LIBS = @FREETYPE_LIBS@ +GLX_ARCH_DEFINES = @GLX_ARCH_DEFINES@ +GLX_DEFINES = @GLX_DEFINES@ +GL_CFLAGS = @GL_CFLAGS@ +GL_LIBS = @GL_LIBS@ +GREP = @GREP@ +HAL_CFLAGS = @HAL_CFLAGS@ +HAL_LIBS = @HAL_LIBS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KDRIVE_CFLAGS = @KDRIVE_CFLAGS@ +KDRIVE_INCS = @KDRIVE_INCS@ +KDRIVE_LIBS = @KDRIVE_LIBS@ +KDRIVE_LOCAL_LIBS = @KDRIVE_LOCAL_LIBS@ +KDRIVE_PURE_INCS = @KDRIVE_PURE_INCS@ +KDRIVE_PURE_LIBS = @KDRIVE_PURE_LIBS@ +LAUNCHD = @LAUNCHD@ +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@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MAKE_HTML = @MAKE_HTML@ +MAKE_PDF = @MAKE_PDF@ +MAKE_PS = @MAKE_PS@ +MAKE_TEXT = @MAKE_TEXT@ +MESA_SOURCE = @MESA_SOURCE@ +MISC_MAN_DIR = @MISC_MAN_DIR@ +MISC_MAN_SUFFIX = @MISC_MAN_SUFFIX@ +MKDIR_P = @MKDIR_P@ +MKFONTDIR = @MKFONTDIR@ +MKFONTSCALE = @MKFONTSCALE@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCCLD = @OBJCCLD@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJCLINK = @OBJCLINK@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_CFLAGS = @OPENSSL_CFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +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@ +PCIACCESS_CFLAGS = @PCIACCESS_CFLAGS@ +PCIACCESS_LIBS = @PCIACCESS_LIBS@ +PCI_TXT_IDS_PATH = @PCI_TXT_IDS_PATH@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PROJECTROOT = @PROJECTROOT@ +PS2PDF = @PS2PDF@ +RANLIB = @RANLIB@ +RAWCPP = @RAWCPP@ +RAWCPPFLAGS = @RAWCPPFLAGS@ +SED = @SED@ +SERVER_MISC_CONFIG_PATH = @SERVER_MISC_CONFIG_PATH@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOLARIS_ASM_CFLAGS = @SOLARIS_ASM_CFLAGS@ +SOLARIS_INOUT_ARCH = @SOLARIS_INOUT_ARCH@ +STRIP = @STRIP@ +TSLIB_CFLAGS = @TSLIB_CFLAGS@ +TSLIB_LIBS = @TSLIB_LIBS@ +UTILS_SYS_LIBS = @UTILS_SYS_LIBS@ +VENDOR_MAN_VERSION = @VENDOR_MAN_VERSION@ +VENDOR_NAME = @VENDOR_NAME@ +VENDOR_NAME_SHORT = @VENDOR_NAME_SHORT@ +VENDOR_RELEASE = @VENDOR_RELEASE@ +VERSION = @VERSION@ +X11APP_ARCHS = @X11APP_ARCHS@ +X11EXAMPLES_DEP_CFLAGS = @X11EXAMPLES_DEP_CFLAGS@ +X11EXAMPLES_DEP_LIBS = @X11EXAMPLES_DEP_LIBS@ +XDMCP_CFLAGS = @XDMCP_CFLAGS@ +XDMCP_LIBS = @XDMCP_LIBS@ +XDMXCONFIG_DEP_CFLAGS = @XDMXCONFIG_DEP_CFLAGS@ +XDMXCONFIG_DEP_LIBS = @XDMXCONFIG_DEP_LIBS@ +XDMX_CFLAGS = @XDMX_CFLAGS@ +XDMX_LIBS = @XDMX_LIBS@ +XDMX_SYS_LIBS = @XDMX_SYS_LIBS@ +XEGLMODULES_CFLAGS = @XEGLMODULES_CFLAGS@ +XEGL_LIBS = @XEGL_LIBS@ +XEGL_SYS_LIBS = @XEGL_SYS_LIBS@ +XEPHYR_CFLAGS = @XEPHYR_CFLAGS@ +XEPHYR_DRI_LIBS = @XEPHYR_DRI_LIBS@ +XEPHYR_INCS = @XEPHYR_INCS@ +XEPHYR_LIBS = @XEPHYR_LIBS@ +XF86CONFIGFILE = @XF86CONFIGFILE@ +XF86MISC_CFLAGS = @XF86MISC_CFLAGS@ +XF86MISC_LIBS = @XF86MISC_LIBS@ +XF86VIDMODE_CFLAGS = @XF86VIDMODE_CFLAGS@ +XF86VIDMODE_LIBS = @XF86VIDMODE_LIBS@ +XGLMODULES_CFLAGS = @XGLMODULES_CFLAGS@ +XGLMODULES_LIBS = @XGLMODULES_LIBS@ +XGLXMODULES_CFLAGS = @XGLXMODULES_CFLAGS@ +XGLXMODULES_LIBS = @XGLXMODULES_LIBS@ +XGLX_LIBS = @XGLX_LIBS@ +XGLX_SYS_LIBS = @XGLX_SYS_LIBS@ +XGL_LIBS = @XGL_LIBS@ +XGL_MODULE_PATH = @XGL_MODULE_PATH@ +XGL_SYS_LIBS = @XGL_SYS_LIBS@ +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_LIBS = @XNEST_LIBS@ +XNEST_SYS_LIBS = @XNEST_SYS_LIBS@ +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_CFLAGS = @XORG_CFLAGS@ +XORG_INCS = @XORG_INCS@ +XORG_LIBS = @XORG_LIBS@ +XORG_MODULES_CFLAGS = @XORG_MODULES_CFLAGS@ +XORG_MODULES_LIBS = @XORG_MODULES_LIBS@ +XORG_OS = @XORG_OS@ +XORG_OS_SUBDIR = @XORG_OS_SUBDIR@ +XORG_SYS_LIBS = @XORG_SYS_LIBS@ +XPRINTMODULES_CFLAGS = @XPRINTMODULES_CFLAGS@ +XPRINTMODULES_LIBS = @XPRINTMODULES_LIBS@ +XPRINTPROTO_CFLAGS = @XPRINTPROTO_CFLAGS@ +XPRINTPROTO_LIBS = @XPRINTPROTO_LIBS@ +XPRINT_CFLAGS = @XPRINT_CFLAGS@ +XPRINT_LIBS = @XPRINT_LIBS@ +XPRINT_SYS_LIBS = @XPRINT_SYS_LIBS@ +XRESEXAMPLES_DEP_CFLAGS = @XRESEXAMPLES_DEP_CFLAGS@ +XRESEXAMPLES_DEP_LIBS = @XRESEXAMPLES_DEP_LIBS@ +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@ +XSERVER_SYS_LIBS = @XSERVER_SYS_LIBS@ +XTSTEXAMPLES_DEP_CFLAGS = @XTSTEXAMPLES_DEP_CFLAGS@ +XTSTEXAMPLES_DEP_LIBS = @XTSTEXAMPLES_DEP_LIBS@ +XVFB_LIBS = @XVFB_LIBS@ +XVFB_SYS_LIBS = @XVFB_SYS_LIBS@ +XWINMODULES_CFLAGS = @XWINMODULES_CFLAGS@ +XWINMODULES_LIBS = @XWINMODULES_LIBS@ +XWIN_LIBS = @XWIN_LIBS@ +XWIN_SERVER_NAME = @XWIN_SERVER_NAME@ +XWIN_SYS_LIBS = @XWIN_SYS_LIBS@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +__XCONFIGFILE__ = @__XCONFIGFILE__@ +abi_ansic = @abi_ansic@ +abi_extension = @abi_extension@ +abi_font = @abi_font@ +abi_videodrv = @abi_videodrv@ +abi_xinput = @abi_xinput@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +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@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +driverdir = @driverdir@ +dvidir = @dvidir@ +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@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +launchagentsdir = @launchagentsdir@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +moduledir = @moduledir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sdkdir = @sdkdir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +xglmoduledir = @xglmoduledir@ +xpconfigdir = @xpconfigdir@ +noinst_LTLIBRARIES = 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) +libmi_la_SOURCES = \ + 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 + +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_OBJECTS) $(libmi_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@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 +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; nonemtpy = 1; } \ + END { if (nonempty) { 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; nonempty = 1; } \ + END { if (nonempty) { 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=; \ + 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; nonempty = 1; } \ + END { if (nonempty) { 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)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + 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-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-sdkHEADERS + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +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-sdkHEADERS + +.MAKE: install-am install-strip + +.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-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + 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-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/xorg-server/mi/mi.h b/xorg-server/mi/mi.h new file mode 100644 index 000000000..8d8f488a0 --- /dev/null +++ b/xorg-server/mi/mi.h @@ -0,0 +1,578 @@ +/*********************************************************** + +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" +#include "privates.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 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 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( + void +); + +extern void mieqEnqueue( + DeviceIntPtr /*pDev*/, + xEventPtr /*e*/ +); + +extern void mieqSwitchScreen( + ScreenPtr /*pScreen*/, + Bool /*fromDIX*/ +); + +extern void mieqProcessInputEvents( + void +); + +typedef void (*mieqHandler)(int, xEventPtr, DeviceIntPtr, int); +void mieqSetHandler(int event, mieqHandler handler); + +/* 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 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 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 int miFindMaxBand( + RegionPtr /*prgn*/ +); + +#ifdef DEBUG +extern Bool miValidRegion( + RegionPtr /*prgn*/ +); +#endif + +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 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 DevPrivateKey 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/xorg-server/mi/miarc.c b/xorg-server/mi/miarc.c new file mode 100644 index 000000000..5ccd11127 --- /dev/null +++ b/xorg-server/mi/miarc.c @@ -0,0 +1,3692 @@ +/*********************************************************** + +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 + +#include <math.h> +#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); + +#ifndef HAVE_CBRT +static double +cbrt(double x) +{ + if (x > 0.0) + return pow(x, 1.0/3.0); + else + return -pow(-x, 1.0/3.0); +} +#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 + +_X_INLINE static int max (const int x, const int y) +{ + return x>y? x:y; +} + +_X_INLINE static int min (const int x, const int y) +{ + return x<y? x:y; +} + +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, int xmin, 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; + +static int +miFreeArcCache (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) +{ + miArcSpan *span; + int doinner; + int x, y, e; + int xk, yk, xm, ym, dx, dy; + 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) +{ + 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, + xArc *parc, + Bool *mustFree) +{ + miArcSpanData *spdata; + arcCacheRec *cent, *lruent; + 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; + DDXPointPtr pts; + int *widths; + int *wids; + miArcSpanData *spdata; + Bool mustFree; + miArcSpan *span; + int xorg, yorgu, yorgl; + int n; + + yorgu = parc->height + pGC->lineWidth; + n = (sizeof(int) * 2) * yorgu; + widths = (int *)xalloc(n + (sizeof(DDXPointRec) * 2) * yorgu); + if (!widths) + return; + points = (DDXPointPtr)((char *)widths + n); + spdata = miComputeWideEllipse((int)pGC->lineWidth, parc, &mustFree); + if (!spdata) + { + xfree(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); + + xfree(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; +{ + 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, + CREATE_PIXMAP_USAGE_SCRATCH); + 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 *) xalloc (narcs * sizeof (struct arcData)); + if (!data) + return (miPolyArcPtr)NULL; + arcs = (miPolyArcPtr) xalloc (sizeof (*arcs) * (isDoubleDash ? 2 : 1)); + if (!arcs) + { + xfree(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; + } + xfree(data); + return arcs; +arcfail: + miFreeArcs(arcs, pGC); + xfree(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; + +static struct finalSpan * +realAllocSpan (void) +{ + struct finalSpanChunk *newChunk; + struct finalSpan *span; + 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) +{ + struct finalSpan *span; + DDXPointPtr xSpan; + int *xWidth; + int i; + struct finalSpan **f; + int spany; + DDXPointPtr xSpans; + int *xWidths; + + if (nspans == 0) + return; + xSpan = xSpans = (DDXPointPtr) xalloc (nspans * sizeof (DDXPointRec)); + xWidth = xWidths = (int *) xalloc (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) + xfree (xSpans); + if (xWidths) + xfree (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, + int xmin, + int xmax) +{ + struct finalSpan *x; + 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/xorg-server/mi/mibank.c b/xorg-server/mi/mibank.c new file mode 100644 index 000000000..ea79e9d36 --- /dev/null +++ b/xorg-server/mi/mibank.c @@ -0,0 +1,2378 @@ +/* + * 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; + CopyWindowProcPtr CopyWindow; +} 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 xalloc_ARRAY(atype, ntype) \ + (atype *)xalloc((ntype) * sizeof(atype)) + +static DevPrivateKey miBankScreenKey = &miBankScreenKey; +static DevPrivateKey miBankGCKey = &miBankGCKey; +static unsigned long miBankGeneration = 0; + +#define BANK_SCRPRIVLVAL dixLookupPrivate(&pScreen->devPrivates, miBankScreenKey) + +#define BANK_SCRPRIVATE ((miBankScreenPtr)(BANK_SCRPRIVLVAL)) + +#define BANK_GCPRIVLVAL(pGC) dixLookupPrivate(&(pGC)->devPrivates, miBankGCKey) + +#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 = xalloc_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; \ + xfree(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 = xalloc_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 *)xalloc(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++; + } + + xfree(pImage); + + BANK_RESTORE; + } + + CLIP_RESTORE; + + pGC->fExpose = fExpose; + + xfree(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, 0); + 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(CopyWindow); + + 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 *)xalloc(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; + + xfree(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 *)xalloc(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; + + xfree(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 +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 = xalloc_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 = xalloc_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); + + xfree(pBoxNew2); + xfree(pBoxNew1); +} + +_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) + miBankGeneration = serverGeneration; + + if (!dixRequestPrivate(miBankGCKey, + (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(CopyWindow, miBankCopyWindow); + + dixSetPrivate(&pScreen->devPrivates, miBankScreenKey, 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/xorg-server/mi/mibank.h b/xorg-server/mi/mibank.h new file mode 100644 index 000000000..fe93ab41b --- /dev/null +++ b/xorg-server/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/xorg-server/mi/mibitblt.c b/xorg-server/mi/mibitblt.c new file mode 100644 index 000000000..14d68e2e1 --- /dev/null +++ b/xorg-server/mi/mibitblt.c @@ -0,0 +1,841 @@ +/*********************************************************** + +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) + DrawablePtr pSrcDrawable; + 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) + xalloc(heightSrc * sizeof(DDXPointRec)); + pwidthFirst = pwidth = (unsigned int *) + xalloc(heightSrc * sizeof(unsigned int)); + numRects = REGION_NUM_RECTS(prgnSrcClip); + boxes = REGION_RECTS(prgnSrcClip); + ordering = (unsigned int *) + xalloc(numRects * sizeof(unsigned int)); + if(!pptFirst || !pwidthFirst || !ordering) + { + if (ordering) + xfree(ordering); + if (pwidthFirst) + xfree(pwidthFirst); + if (pptFirst) + xfree(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); + + xfree(ordering); + xfree(pwidthFirst); + xfree(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. + */ +static void +miOpqStipDrawable(DrawablePtr pDraw, GCPtr pGC, RegionPtr prgnSrc, + MiBits *pbits, int srcx, int w, int h, int dstx, int 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, + CREATE_PIXMAP_USAGE_SCRATCH); + 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)xalloc(h * sizeof(DDXPointRec)); + pwidth = pwidthFirst = (int *)xalloc(h * sizeof(int)); + if(!pptFirst || !pwidthFirst) + { + if (pwidthFirst) xfree(pwidthFirst); + if (pptFirst) xfree(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); + xfree(pwidthFirst); + xfree(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, + CREATE_PIXMAP_USAGE_SCRATCH); + 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)xalloc(h * sizeof(DDXPointRec)); + pwidth = pwidthFirst = (int *)xalloc(h * sizeof(int)); + if(!pptFirst || !pwidthFirst) + { + if (pwidthFirst) + xfree(pwidthFirst); + if (pptFirst) + xfree(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); + xfree(pwidthFirst); + xfree(pptFirst); + break; + } +} diff --git a/xorg-server/mi/mibstore.c b/xorg-server/mi/mibstore.c new file mode 100644 index 000000000..294b2caee --- /dev/null +++ b/xorg-server/mi/mibstore.c @@ -0,0 +1,48 @@ +/* + * Copyright 2007 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software") + * to deal in the software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * them Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTIBILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif +#include "scrnintstr.h" +#include "mibstore.h" + +/* + * There is no longer an mi implementation of backing store. This function + * is only for source compatibility with old drivers. + * + * Note though that you do get backing store for free if your server has + * Composite enabled, since the automatic redirection mechanism provides + * essentially the same functionality. See compChangeWindowAttributes() + * for the implementation. + */ + +_X_EXPORT void +miInitializeBackingStore (ScreenPtr pScreen) +{ + pScreen->SaveDoomedAreas = NULL; + pScreen->RestoreAreas = NULL; + pScreen->ExposeCopy = NULL; + pScreen->TranslateBackingStore = NULL; + pScreen->ClearBackingStore = NULL; + pScreen->DrawGuarantee = NULL; +} diff --git a/xorg-server/mi/mibstore.h b/xorg-server/mi/mibstore.h new file mode 100644 index 000000000..baa59202b --- /dev/null +++ b/xorg-server/mi/mibstore.h @@ -0,0 +1,25 @@ +/*- + * 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/xorg-server/mi/mibstorest.h b/xorg-server/mi/mibstorest.h new file mode 100644 index 000000000..ccf4fb701 --- /dev/null +++ b/xorg-server/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/xorg-server/mi/micmap.c b/xorg-server/mi/micmap.c new file mode 100644 index 000000000..33d948179 --- /dev/null +++ b/xorg-server/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) +{ + unsigned i; + 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) +{ + int red, green, blue; + int maxred, maxgreen, maxblue; + int stepred, stepgreen, stepblue; + VisualPtr pVisual; + int pixel; + int nresult; + 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(void) +{ + 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(void) +{ + miInitVisualsProc = miDoInitVisuals; +} + diff --git a/xorg-server/mi/micmap.h b/xorg-server/mi/micmap.h new file mode 100644 index 000000000..9ee9f4ae4 --- /dev/null +++ b/xorg-server/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/xorg-server/mi/micoord.h b/xorg-server/mi/micoord.h new file mode 100644 index 000000000..876e88c95 --- /dev/null +++ b/xorg-server/mi/micoord.h @@ -0,0 +1,69 @@ +/* + * 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(__s390x__) || defined(__s390__) || \ + defined(__amd64__) || defined(amd64) || defined(__amd64) || defined(__x86_64__) +#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/xorg-server/mi/micursor.c b/xorg-server/mi/micursor.c new file mode 100644 index 000000000..6e06fbc07 --- /dev/null +++ b/xorg-server/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/xorg-server/mi/midash.c b/xorg-server/mi/midash.c new file mode 100644 index 000000000..95a19c295 --- /dev/null +++ b/xorg-server/mi/midash.c @@ -0,0 +1,90 @@ +/*********************************************************** + +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" + +_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/xorg-server/mi/midispcur.c b/xorg-server/mi/midispcur.c new file mode 100644 index 000000000..45e0e9abe --- /dev/null +++ b/xorg-server/mi/midispcur.c @@ -0,0 +1,814 @@ +/* + * 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 DevPrivateKey miDCScreenKey = &miDCScreenKey; + +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; + + 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; + + dixSetPrivate(&pScreen->devPrivates, miDCScreenKey, 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)dixLookupPrivate(&pScreen->devPrivates, + miDCScreenKey); + 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 + 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) + dixSetPrivate(&pCursor->bits->devPrivates, pScreen, 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, + CREATE_PIXMAP_USAGE_SCRATCH); + 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; + } + dixSetPrivate(&pCursor->bits->devPrivates, pScreen, pPriv); + return pPriv; + } + pPriv->pPicture = 0; +#endif + pPriv->sourceBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1, 0); + if (!pPriv->sourceBits) + { + xfree ((pointer) pPriv); + return (miDCCursorPtr)NULL; + } + pPriv->maskBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1, 0); + if (!pPriv->maskBits) + { + (*pScreen->DestroyPixmap) (pPriv->sourceBits); + xfree ((pointer) pPriv); + return (miDCCursorPtr)NULL; + } + dixSetPrivate(&pCursor->bits->devPrivates, pScreen, 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)dixLookupPrivate(&pCursor->bits->devPrivates, + pScreen); + 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); + dixSetPrivate(&pCursor->bits->devPrivates, pScreen, 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, + (XID)0, serverClient); + *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)dixLookupPrivate(&pCursor->bits->devPrivates, + pScreen); + if (!pPriv) + { + pPriv = miDCRealize(pScreen, pCursor); + if (!pPriv) + return FALSE; + } + pScreenPriv = (miDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates, + miDCScreenKey); + 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)dixLookupPrivate(&pScreen->devPrivates, + miDCScreenKey); + 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, 0); + 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)dixLookupPrivate(&pScreen->devPrivates, + miDCScreenKey); + 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)dixLookupPrivate(&pScreen->devPrivates, + miDCScreenKey); + 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)dixLookupPrivate(&pCursor->bits->devPrivates, + pScreen); + if (!pPriv) + { + pPriv = miDCRealize(pScreen, pCursor); + if (!pPriv) + return FALSE; + } + pScreenPriv = (miDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates, + miDCScreenKey); + 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, 0); + if (!pTemp) + return FALSE; + } + if (!pScreenPriv->pMoveGC) + { + pScreenPriv->pMoveGC = CreateGC ((DrawablePtr)pTemp, + GCGraphicsExposures, &gcval, &status, (XID)0, serverClient); + 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, (XID)0, serverClient); + if (!pScreenPriv->pPixSourceGC) + return FALSE; + } + if (!pScreenPriv->pPixMaskGC) + { + pScreenPriv->pPixMaskGC = CreateGC ((DrawablePtr)pTemp, + GCGraphicsExposures, &gcval, &status, (XID)0, serverClient); + 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/xorg-server/mi/mieq.c b/xorg-server/mi/mieq.c new file mode 100644 index 000000000..803724708 --- /dev/null +++ b/xorg-server/mi/mieq.c @@ -0,0 +1,261 @@ +/* + * +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 "mipointer.h" +# include "scrnintstr.h" +# include <X11/extensions/XI.h> +# include <X11/extensions/XIproto.h> +# include "extinit.h" +# include "exglobals.h" + +#ifdef DPMSExtension +# include "dpmsproc.h" +# define DPMS_SERVER +# include <X11/extensions/dpms.h> +#endif + +#define QUEUE_SIZE 512 + +typedef struct _Event { + xEvent event[7]; + int nevents; + ScreenPtr pScreen; + DeviceIntPtr pDev; /* device this event _originated_ from */ +} EventRec, *EventPtr; + +typedef struct _EventQueue { + HWEventQueueType head, tail; /* long for SetInputCheck */ + CARD32 lastEventTime; /* to avoid time running backwards */ + int lastMotion; /* device ID if last event motion? */ + EventRec events[QUEUE_SIZE]; /* static allocation for signals */ + ScreenPtr pEnqueueScreen; /* screen events are being delivered to */ + ScreenPtr pDequeueScreen; /* screen events are being dispatched to */ + mieqHandler handlers[128]; /* custom event handler */ +} EventQueueRec, *EventQueuePtr; + +static EventQueueRec miEventQueue; + +Bool +mieqInit(void) +{ + int i; + + miEventQueue.head = miEventQueue.tail = 0; + miEventQueue.lastEventTime = GetTimeInMillis (); + miEventQueue.lastMotion = FALSE; + miEventQueue.pEnqueueScreen = screenInfo.screens[0]; + miEventQueue.pDequeueScreen = miEventQueue.pEnqueueScreen; + for (i = 0; i < 128; i++) + miEventQueue.handlers[i] = NULL; + 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(DeviceIntPtr pDev, xEvent *e) +{ + unsigned int oldtail = miEventQueue.tail, newtail; + int isMotion = 0; + deviceValuator *v = (deviceValuator *) e; + EventPtr laste = &miEventQueue.events[(oldtail - 1) % + QUEUE_SIZE]; + deviceKeyButtonPointer *lastkbp = (deviceKeyButtonPointer *) + &laste->event[0]; + + if (e->u.u.type == MotionNotify) + isMotion = inputInfo.pointer->id; + else if (e->u.u.type == DeviceMotionNotify) + isMotion = pDev->id; + + /* We silently steal valuator events: just tack them on to the last + * motion event they need to be attached to. Sigh. */ + if (e->u.u.type == DeviceValuator) { + if (laste->nevents > 6) { + ErrorF("[mi] mieqEnqueue: more than six valuator events; dropping.\n"); + return; + } + if (oldtail == miEventQueue.head || + !(lastkbp->type == DeviceMotionNotify || + lastkbp->type == DeviceButtonPress || + lastkbp->type == DeviceButtonRelease || + lastkbp->type == ProximityIn || + lastkbp->type == ProximityOut) || + ((lastkbp->deviceid & DEVICE_BITS) != + (v->deviceid & DEVICE_BITS))) { + ErrorF("[mi] mieqEnequeue: out-of-order valuator event; dropping.\n"); + return; + } + memcpy(&(laste->event[laste->nevents++]), e, sizeof(xEvent)); + return; + } + + if (isMotion && isMotion == miEventQueue.lastMotion && + oldtail != miEventQueue.head) { + oldtail = (oldtail - 1) % QUEUE_SIZE; + } + else { + static int stuck = 0; + newtail = (oldtail + 1) % QUEUE_SIZE; + /* Toss events which come in late. Usually this means your server's + * stuck in an infinite loop somewhere, but SIGIO is still getting + * handled. */ + if (newtail == miEventQueue.head) { + ErrorF("[mi] EQ overflowing. The server is probably stuck " + "in an infinite loop.\n"); + if (!stuck) { + xorg_backtrace(); + stuck = 1; + } + return; + } + stuck = 0; + miEventQueue.tail = newtail; + } + + memcpy(&(miEventQueue.events[oldtail].event[0]), e, sizeof(xEvent)); + miEventQueue.events[oldtail].nevents = 1; + + /* 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[0].u.keyButtonPointer.time = + miEventQueue.lastEventTime; + + miEventQueue.lastEventTime = + miEventQueue.events[oldtail].event[0].u.keyButtonPointer.time; + miEventQueue.events[oldtail].pScreen = miEventQueue.pEnqueueScreen; + miEventQueue.events[oldtail].pDev = pDev; + + miEventQueue.lastMotion = isMotion; +} + +void +mieqSwitchScreen(ScreenPtr pScreen, Bool fromDIX) +{ + miEventQueue.pEnqueueScreen = pScreen; + if (fromDIX) + miEventQueue.pDequeueScreen = pScreen; +} + +void +mieqSetHandler(int event, mieqHandler handler) +{ + if (handler && miEventQueue.handlers[event]) + ErrorF("mieq: warning: overriding existing handler %p with %p for " + "event %d\n", miEventQueue.handlers[event], handler, event); + + miEventQueue.handlers[event] = handler; +} + +/* Call this from ProcessInputEvents(). */ +void +mieqProcessInputEvents(void) +{ + EventRec *e = NULL; + int x = 0, y = 0; + DeviceIntPtr dev = NULL; + + while (miEventQueue.head != miEventQueue.tail) { + if (screenIsSaved == SCREEN_SAVER_ON) + dixSaveScreens (serverClient, SCREEN_SAVER_OFF, ScreenSaverReset); +#ifdef DPMSExtension + else if (DPMSPowerLevel != DPMSModeOn) + SetScreenSaverTimer(); + + if (DPMSPowerLevel != DPMSModeOn) + DPMSSet(serverClient, DPMSModeOn); +#endif + + e = &miEventQueue.events[miEventQueue.head]; + /* Assumption - screen switching can only occur on motion events. */ + miEventQueue.head = (miEventQueue.head + 1) % QUEUE_SIZE; + + if (e->pScreen != miEventQueue.pDequeueScreen) { + miEventQueue.pDequeueScreen = e->pScreen; + x = e->event[0].u.keyButtonPointer.rootX; + y = e->event[0].u.keyButtonPointer.rootY; + NewCurrentScreen (miEventQueue.pDequeueScreen, x, y); + } + else { + /* If someone's registered a custom event handler, let them + * steal it. */ + if (miEventQueue.handlers[e->event->u.u.type]) { + miEventQueue.handlers[e->event->u.u.type](miEventQueue.pDequeueScreen->myNum, + e->event, dev, + e->nevents); + return; + } + + /* If this is a core event, make sure our keymap, et al, is + * changed to suit. */ + if (e->event[0].u.u.type == KeyPress || + e->event[0].u.u.type == KeyRelease) { + SwitchCoreKeyboard(e->pDev); + dev = inputInfo.keyboard; + } + else if (e->event[0].u.u.type == MotionNotify || + e->event[0].u.u.type == ButtonPress || + e->event[0].u.u.type == ButtonRelease) { + SwitchCorePointer(e->pDev); + dev = inputInfo.pointer; + } + else { + dev = e->pDev; + } + + dev->public.processInputProc(e->event, dev, e->nevents); + } + } +} diff --git a/xorg-server/mi/miexpose.c b/xorg-server/mi/miexpose.c new file mode 100644 index 000000000..2fba6a28c --- /dev/null +++ b/xorg-server/mi/miexpose.c @@ -0,0 +1,674 @@ +/*********************************************************** + +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) + DrawablePtr pSrcDrawable; + DrawablePtr pDstDrawable; + GCPtr pGC; + int srcx, srcy; + int width, height; + int dstx, dsty; + unsigned long plane; +{ + 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); + + /* 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) + { + expBox = *REGION_EXTENTS(pscr, &rgnExposed); + REGION_RESET(pscr, &rgnExposed, &expBox); + } + 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); + } + miPaintWindow((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; + xEvent *pe; + BoxPtr pBox; + int i; + int numRects; + + numRects = REGION_NUM_RECTS(pRgn); + pBox = REGION_RECTS(pRgn); + if(!(pEvent = (xEvent *)xalloc(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); + xfree(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; + int dx, dy; +{ + BoxPtr pBox; + int numRects; + xEvent *pEvent, *pe; + int i; + + pBox = REGION_RECTS(pRgn); + numRects = REGION_NUM_RECTS(pRgn); + if(!(pEvent = (xEvent *) xalloc(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) { + xfree(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); + + xfree(pEvent); +} + +_X_EXPORT void +miWindowExposures(pWin, prgn, other_exposed) + WindowPtr pWin; + RegionPtr prgn, other_exposed; +{ + RegionPtr exposures = 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); + } + if (prgn && !REGION_NIL(prgn)) + miPaintWindow(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); +} + +_X_EXPORT void +miPaintWindow(WindowPtr pWin, RegionPtr prgn, int what) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + ChangeGCVal gcval[5]; + BITS32 gcmask; + GCPtr pGC; + int i; + BoxPtr pbox; + xRectangle *prect; + int numRects; + /* + * Distance from screen to destination drawable, use this + * to adjust rendering coordinates which come in in screen space + */ + int draw_x_off, draw_y_off; + /* + * Tile offset for drawing; these need to align the tile + * to the appropriate window origin + */ + int tile_x_off, tile_y_off; + PixUnion fill; + Bool solid = TRUE; + DrawablePtr drawable = &pWin->drawable; + + if (what == PW_BACKGROUND) + { + while (pWin->backgroundState == ParentRelative) + pWin = pWin->parent; + + draw_x_off = drawable->x; + draw_y_off = drawable->y; + + tile_x_off = pWin->drawable.x - draw_x_off; + tile_y_off = pWin->drawable.y - draw_y_off; + fill = pWin->background; + switch (pWin->backgroundState) { + case None: + return; + case BackgroundPixmap: + solid = FALSE; + break; + } + } + else + { + PixmapPtr pixmap; + + tile_x_off = drawable->x; + tile_y_off = drawable->y; + + /* servers without pixmaps draw their own borders */ + if (!pScreen->GetWindowPixmap) + return; + pixmap = (*pScreen->GetWindowPixmap) ((WindowPtr) drawable); + drawable = &pixmap->drawable; +#ifdef COMPOSITE + draw_x_off = pixmap->screen_x; + draw_y_off = pixmap->screen_y; + tile_x_off -= draw_x_off; + tile_y_off -= draw_y_off; +#else + draw_x_off = 0; + draw_y_off = 0; +#endif + fill = pWin->border; + solid = pWin->borderIsPixel; + } + + gcval[0].val = GXcopy; + gcmask = GCFunction; + + if (solid) + { + gcval[1].val = fill.pixel; + gcval[2].val = FillSolid; + gcmask |= GCForeground | GCFillStyle; + } + else + { + gcval[1].val = FillTiled; + gcval[2].ptr = (pointer)fill.pixmap; + gcval[3].val = tile_x_off; + gcval[4].val = tile_y_off; + gcmask |= GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin; + } + + prect = (xRectangle *)xalloc(REGION_NUM_RECTS(prgn) * + sizeof(xRectangle)); + if (!prect) + return; + + pGC = GetScratchGC(drawable->depth, drawable->pScreen); + if (!pGC) + { + xfree(prect); + return; + } + + dixChangeGC (NullClient, pGC, gcmask, NULL, gcval); + ValidateGC (drawable, pGC); + + numRects = REGION_NUM_RECTS(prgn); + pbox = REGION_RECTS(prgn); + for (i= numRects; --i >= 0; pbox++, prect++) + { + prect->x = pbox->x1 - draw_x_off; + prect->y = pbox->y1 - draw_y_off; + prect->width = pbox->x2 - pbox->x1; + prect->height = pbox->y2 - pbox->y1; + } + prect -= numRects; + (*pGC->ops->PolyFillRect)(drawable, pGC, numRects, prect); + xfree(prect); + + 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/xorg-server/mi/mifillarc.c b/xorg-server/mi/mifillarc.c new file mode 100644 index 000000000..f68ddf468 --- /dev/null +++ b/xorg-server/mi/mifillarc.c @@ -0,0 +1,807 @@ +/************************************************************ + +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) + xArc *arc; + 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; + } + } +} + +static void +miFillArcDSetup(xArc *arc, 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( + xArc *arc, + miSliceEdgePtr edge, + int k, + Bool top, + Bool left ) +{ + 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; + } +} + +static void +miEllipseAngleToSlope (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( + xArc *arc, + int angle, + miSliceEdgePtr edge, + Bool top, + Bool left ) +{ + 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) + xArc *arc; + miArcSliceRec *slice; + GCPtr pGC; +{ + 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 ) +{ + int x, y, e; + int yk, xk, ym, xm, dx, dy, xorg, yorg; + int slw; + miFillArcRec info; + DDXPointPtr points; + DDXPointPtr pts; + int *widths; + int *wids; + + points = (DDXPointPtr)xalloc(sizeof(DDXPointRec) * arc->height); + if (!points) + return; + widths = (int *)xalloc(sizeof(int) * arc->height); + if (!widths) + { + xfree(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); + xfree(widths); + xfree(points); +} + +static void +miFillEllipseD( + DrawablePtr pDraw, + GCPtr pGC, + xArc *arc ) +{ + int x, y; + int xorg, yorg, dx, dy, slw; + double e, yk, xk, ym, xm; + miFillArcDRec info; + DDXPointPtr points; + DDXPointPtr pts; + int *widths; + int *wids; + + points = (DDXPointPtr)xalloc(sizeof(DDXPointRec) * arc->height); + if (!points) + return; + widths = (int *)xalloc(sizeof(int) * arc->height); + if (!widths) + { + xfree(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); + xfree(widths); + xfree(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; + int x, y, e; + miFillArcRec info; + miArcSliceRec slice; + int ya, xl, xr, xc; + DDXPointPtr points; + DDXPointPtr pts; + int *widths; + 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)xalloc(sizeof(DDXPointRec) * slw); + if (!points) + return; + widths = (int *)xalloc(sizeof(int) * slw); + if (!widths) + { + xfree(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); + xfree(widths); + xfree(points); +} + +static void +miFillArcSliceD( + DrawablePtr pDraw, + GCPtr pGC, + xArc *arc ) +{ + 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; + DDXPointPtr pts; + int *widths; + 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)xalloc(sizeof(DDXPointRec) * slw); + if (!points) + return; + widths = (int *)xalloc(sizeof(int) * slw); + if (!widths) + { + xfree(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); + xfree(widths); + xfree(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; +{ + int i; + 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/xorg-server/mi/mifillarc.h b/xorg-server/mi/mifillarc.h new file mode 100644 index 000000000..3e3bb9858 --- /dev/null +++ b/xorg-server/mi/mifillarc.h @@ -0,0 +1,190 @@ +/************************************************************ + +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 void miFillArcSetup( + xArc * /*arc*/, + miFillArcRec * /*info*/ +); + +extern void miFillArcSliceSetup( + xArc * /*arc*/, + miArcSliceRec * /*slice*/, + GCPtr /*pGC*/ +); + +#endif /* __MIFILLARC_H__ */ diff --git a/xorg-server/mi/mifillrct.c b/xorg-server/mi/mifillrct.c new file mode 100644 index 000000000..e7646cf38 --- /dev/null +++ b/xorg-server/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; + int height; + int width; + xRectangle *prect; + int xorg; + int yorg; + int maxheight; + DDXPointPtr pptFirst; + DDXPointPtr ppt; + int *pwFirst; + 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) xalloc(maxheight * sizeof(DDXPointRec)); + pwFirst = (int *) xalloc(maxheight * sizeof(int)); + if(!pptFirst || !pwFirst) + { + if (pwFirst) xfree(pwFirst); + if (pptFirst) xfree(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++; + } + xfree(pwFirst); + xfree(pptFirst); +} diff --git a/xorg-server/mi/mifpoly.h b/xorg-server/mi/mifpoly.h new file mode 100644 index 000000000..7bd77b356 --- /dev/null +++ b/xorg-server/mi/mifpoly.h @@ -0,0 +1,102 @@ +/*********************************************************** + +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__ + +#include <X11/Xfuncproto.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 */ + +static _X_INLINE int ICEIL(double x) +{ + int _cTmp = x; + return ((x == _cTmp) || (x < 0.0)) ? _cTmp : _cTmp+1; +} + +/* 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/xorg-server/mi/mifpolycon.c b/xorg-server/mi/mifpolycon.c new file mode 100644 index 000000000..d19f031d7 --- /dev/null +++ b/xorg-server/mi/mifpolycon.c @@ -0,0 +1,278 @@ +/*********************************************************** + +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(SppPointPtr pts, int n, double yFtrans, + int *by, int *ty); + +/* + * 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 */ + 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)xalloc(sizeof(DDXPointRec) * y); + width = FirstWidth = (int *) xalloc(sizeof(int) * y); + Marked = (int *) xalloc(sizeof(int) * count); + + if(!ptsOut || !width || !Marked) + { + if (Marked) xfree(Marked); + if (width) xfree(width); + if (ptsOut) xfree(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); + xfree(Marked); + xfree(FirstWidth); + xfree(FirstPoint); +} + + +/* Find the index of the point with the smallest y.also return the + * smallest and largest y */ +static +int +GetFPolyYBounds( + SppPointPtr pts, + int n, + double yFtrans, + int *by, + int *ty) +{ + 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/xorg-server/mi/migc.c b/xorg-server/mi/migc.c new file mode 100644 index 000000000..46643ab26 --- /dev/null +++ b/xorg-server/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/xorg-server/mi/migc.h b/xorg-server/mi/migc.h new file mode 100644 index 000000000..84dc75c6c --- /dev/null +++ b/xorg-server/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/xorg-server/mi/miglblt.c b/xorg-server/mi/miglblt.c new file mode 100644 index 000000000..0155b5618 --- /dev/null +++ b/xorg-server/mi/miglblt.c @@ -0,0 +1,254 @@ +/*********************************************************** + +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; + int i; + int j; + unsigned char *pbits; /* buffer for PutImage */ + unsigned char *pb; /* temp pointer into buffer */ + CharInfoPtr pci; /* currect char info */ + unsigned char *pglyph; /* pointer bits in glyph */ + int gWidth, gHeight; /* width and height of glyph */ + 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, + CREATE_PIXMAP_USAGE_SCRATCH); + 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 *)xalloc(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); + xfree(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/xorg-server/mi/miinitext.c b/xorg-server/mi/miinitext.c new file mode 100644 index 000000000..55faec333 --- /dev/null +++ b/xorg-server/mi/miinitext.c @@ -0,0 +1,779 @@ +/*********************************************************** + +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 INXQUARTZ +extern Bool noPseudoramiXExtension; +#endif +#ifdef XINPUT +extern Bool noXInputExtension; +#endif +#ifdef XIDLE +extern Bool noXIdleExtension; +#endif +#ifdef XSELINUX +extern Bool noSELinuxExtension; +#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 XCSECURITY +#include "securitysrv.h" +#include <X11/extensions/securstr.h> +#endif +#ifdef XSELINUX +#include "xselinux.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 INXQUARTZ +extern void PseudoramiXExtensionInit(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 XCSECURITY +extern void SecurityExtensionInit(INITARGS); +#endif +#ifdef XSELINUX +extern void SELinuxExtensionInit(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 __glXDRISWRastProvider; +extern void GlxPushProvider(__GLXprovider *impl); +extern void GlxExtensionInit(INITARGS); +#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 +#ifdef XSELINUX + { "SELinux", &noSELinuxExtension }, +#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 PANORAMIX +# if !defined(PRINT_ONLY_SERVER) && !defined(NO_PANORAMIX) + if (!noPanoramiXExtension) PanoramiXExtensionInit(); +# endif +#endif +#ifdef INXQUARTZ + if(!noPseudoramiXExtension) PseudoramiXExtensionInit(); +#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) + 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) + 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 XCSECURITY + if (!noSecurityExtension) SecurityExtensionInit(); +#endif +#ifdef XSELINUX + if (!noSELinuxExtension) SELinuxExtensionInit(); +#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 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 + +#ifdef GLXEXT + GlxPushProvider(&__glXDRISWRastProvider); + if (!noGlxExtension) GlxExtensionInit(); +#endif +} + +void +InitVisualWrap() +{ + miResetInitVisuals(); +} + +#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 XCSECURITY + { SecurityExtensionInit, SECURITY_EXTENSION_NAME, &noSecurityExtension, NULL, 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; + } + + 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/xorg-server/mi/miline.h b/xorg-server/mi/miline.h new file mode 100644 index 000000000..036c2b5df --- /dev/null +++ b/xorg-server/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" +#include "privates.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) \ +{ 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) ((unsigned long) \ + dixLookupPrivate(&(_pScreen)->devPrivates, miZeroLineScreenKey)) + +#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 DevPrivateKey miZeroLineScreenKey; + +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/xorg-server/mi/mioverlay.c b/xorg-server/mi/mioverlay.c new file mode 100644 index 000000000..6ddcc052d --- /dev/null +++ b/xorg-server/mi/mioverlay.c @@ -0,0 +1,1998 @@ + +#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 "privates.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 DevPrivateKey miOverlayWindowKey = &miOverlayWindowKey; +static DevPrivateKey miOverlayScreenKey = &miOverlayScreenKey; + +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) \ + dixLookupPrivate(&(pScreen)->devPrivates, miOverlayScreenKey)) +#define MIOVERLAY_GET_WINDOW_PRIVATE(pWin) ((miOverlayWindowPtr) \ + dixLookupPrivate(&(pWin)->devPrivates, miOverlayWindowKey)) +#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(!dixRequestPrivate(miOverlayWindowKey, sizeof(miOverlayWindowRec))) + return FALSE; + + if(!(pScreenPriv = xalloc(sizeof(miOverlayScreenRec)))) + return FALSE; + + dixSetPrivate(&pScreen->devPrivates, miOverlayScreenKey, 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)) { + miPaintWindow(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)) { + miPaintWindow(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, + RegionPtr prgn, + RegionPtr other_exposed +){ + RegionPtr exposures = prgn; + ScreenPtr pScreen = pWin->drawable.pScreen; + + 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); + } + if (prgn && !REGION_NIL(prgn)) + miPaintWindow(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 +){ + 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; + WindowPtr pChild; + RegionPtr gravitate[StaticGravity + 1]; + RegionPtr gravitate2[StaticGravity + 1]; + 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; + 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); + + (*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 (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); + (*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); + } + if (pWin->realized) + WindowsRestructured (); +} + + +#ifdef SHAPE +static void +miOverlaySetShape(WindowPtr pWin) +{ + Bool WasViewable = (Bool)(pWin->viewable); + ScreenPtr pScreen = pWin->drawable.pScreen; +#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) { + (*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 (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; + 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, ®, &box, 1); + + REGION_INTERSECT(pScreen, ®, ®, clipList); + if (generateExposures) + (*pScreen->WindowExposures)(pWin, ®, pBSReg); + else if (pWin->backgroundState != None) + miPaintWindow(pWin, ®, PW_BACKGROUND); + REGION_UNINIT(pScreen, ®); + 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/xorg-server/mi/mioverlay.h b/xorg-server/mi/mioverlay.h new file mode 100644 index 000000000..24b74f51c --- /dev/null +++ b/xorg-server/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/xorg-server/mi/mipointer.c b/xorg-server/mi/mipointer.c new file mode 100644 index 000000000..b55e68bf0 --- /dev/null +++ b/xorg-server/mi/mipointer.c @@ -0,0 +1,517 @@ +/* + +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" +# include "inputstr.h" + +_X_EXPORT DevPrivateKey miPointerScreenKey = &miPointerScreenKey; + +#define GetScreenPrivate(s) ((miPointerScreenPtr) \ + dixLookupPrivate(&(s)->devPrivates, miPointerScreenKey)) +#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); + +static xEvent* events; /* for WarpPointer MotionNotifies */ + +_X_EXPORT Bool +miPointerInitialize (pScreen, spriteFuncs, screenFuncs, waitForUpdate) + ScreenPtr pScreen; + miPointerSpriteFuncPtr spriteFuncs; + miPointerScreenFuncPtr screenFuncs; + Bool waitForUpdate; +{ + miPointerScreenPtr pScreenPriv; + + 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; + dixSetPrivate(&pScreen->devPrivates, miPointerScreenKey, 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; + + events = NULL; + + 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); + xfree ((pointer) events); + events = NULL; + 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; + miPointerUpdateSprite(inputInfo.pointer); + 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) + miPointerUpdateSprite(inputInfo.pointer); + return TRUE; +} + +/* Once signals are ignored, the WarpCursor function can call this */ + +_X_EXPORT void +miPointerWarpCursor (pScreen, x, y) + ScreenPtr pScreen; + int x, y; +{ + BOOL changedScreen = FALSE; + SetupScreen (pScreen); + + if (miPointer.pScreen != pScreen) + { + (*pScreenPriv->screenFuncs->NewEventScreen) (pScreen, TRUE); + changedScreen = 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; + } + + if (changedScreen) + UpdateSpriteForScreen (pScreen) ; +} + +/* + * Pointer/CursorDisplay interface routines + */ + +/* + * miPointerUpdate + * + * Syncronize the sprite with the cursor - called from ProcessInputEvents + */ + +void +miPointerUpdate () +{ + miPointerUpdateSprite(inputInfo.pointer); +} + +void +miPointerUpdateSprite (DeviceIntPtr pDev) +{ + ScreenPtr pScreen; + miPointerScreenPtr pScreenPriv; + CursorPtr pCursor; + int x, y, devx, devy; + + if (!pDev || !(pDev->coreEvents || pDev == inputInfo.pointer)) + return; + + pScreen = miPointer.pScreen; + if (!pScreen) + return; + + x = miPointer.x; + y = miPointer.y; + devx = miPointer.devx; + devy = miPointer.devy; + + 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 (int dx, int dy, unsigned long time) +{ + int x = miPointer.x + dx, y = miPointer.y + dy; + + miPointerSetPosition(inputInfo.pointer, &x, &y, time); +} + +void +miPointerSetNewScreen(int screen_no, int x, int y) +{ + miPointerSetScreen(inputInfo.pointer, screen_no, x, y); +} + +void +miPointerSetScreen(DeviceIntPtr pDev, 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 miPointerGetScreen(inputInfo.pointer); +} + +_X_EXPORT ScreenPtr +miPointerGetScreen(DeviceIntPtr pDev) +{ + return miPointer.pScreen; +} + +/* Move the pointer to x, y on the current screen, update the sprite, and + * the motion history. Generates no events. Does not return changed x + * and y if they are clipped; use miPointerSetPosition instead. */ +_X_EXPORT void +miPointerAbsoluteCursor (int x, int y, unsigned long time) +{ + miPointerSetPosition(inputInfo.pointer, &x, &y, time); +} + +/* Move the pointer on the current screen, and update the sprite. */ +static void +miPointerMoved (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y, + unsigned long time) +{ + SetupScreen(pScreen); + + if (pDev && (pDev->coreEvents || pDev == inputInfo.pointer) && + !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; +} + +_X_EXPORT void +miPointerSetPosition(DeviceIntPtr pDev, int *x, int *y, unsigned long time) +{ + miPointerScreenPtr pScreenPriv; + ScreenPtr pScreen; + ScreenPtr newScreen; + + pScreen = miPointer.pScreen; + if (!pScreen) + return; /* called before ready */ + + if (!pDev || !(pDev->coreEvents || pDev == inputInfo.pointer)) + return; + + 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 sprite 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; + + miPointerMoved(pDev, pScreen, *x, *y, time); +} + +_X_EXPORT void +miPointerPosition (int *x, int *y) +{ + miPointerGetPosition(inputInfo.pointer, x, y); +} + +_X_EXPORT void +miPointerGetPosition(DeviceIntPtr pDev, int *x, int *y) +{ + *x = miPointer.x; + *y = miPointer.y; +} + +void +miPointerMove (ScreenPtr pScreen, int x, int y, unsigned long time) +{ + int i, nevents; + int valuators[2]; + + miPointerMoved(inputInfo.pointer, pScreen, x, y, time); + + /* generate motion notify */ + valuators[0] = x; + valuators[1] = y; + + if (!events) + { + events = (xEvent*)xcalloc(sizeof(xEvent), GetMaximumEventsNum()); + + if (!events) + { + FatalError("Could not allocate event store.\n"); + return; + } + } + + nevents = GetPointerEvents(events, inputInfo.pointer, MotionNotify, 0, + POINTER_ABSOLUTE, 0, 2, valuators); + + for (i = 0; i < nevents; i++) + mieqEnqueue(inputInfo.pointer, &events[i]); +} diff --git a/xorg-server/mi/mipointer.h b/xorg-server/mi/mipointer.h new file mode 100644 index 000000000..e864fddf4 --- /dev/null +++ b/xorg-server/mi/mipointer.h @@ -0,0 +1,172 @@ +/* + +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" +#include "privates.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)( + DeviceIntPtr /* pDev */, + 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*/ +) _X_DEPRECATED; + +extern int miPointerGetMotionBufferSize( + void +) _X_DEPRECATED; + +extern int miPointerGetMotionEvents( + DeviceIntPtr /*pPtr*/, + xTimecoord * /*coords*/, + unsigned long /*start*/, + unsigned long /*stop*/, + ScreenPtr /*pScreen*/ +); + +/* Deprecated in favour of miPointerUpdateSprite. */ +extern void miPointerUpdate( + void +) _X_DEPRECATED; + +/* Deprecated in favour of miSetPointerPosition. */ +extern void miPointerDeltaCursor( + int /*dx*/, + int /*dy*/, + unsigned long /*time*/ +) _X_DEPRECATED; +extern void miPointerAbsoluteCursor( + int /*x*/, + int /*y*/, + unsigned long /*time*/ +) _X_DEPRECATED; + +/* Deprecated in favour of miGetPointerPosition. */ +extern void miPointerPosition( + int * /*x*/, + int * /*y*/ +) _X_DEPRECATED; + +/* Deprecated in favour of miPointerSetScreen. */ +extern void miPointerSetNewScreen( + int, /*screen_no*/ + int, /*x*/ + int /*y*/ +) _X_DEPRECATED; + +/* Deprecated in favour of miPointerGetScreen. */ +extern ScreenPtr miPointerCurrentScreen( + void +) _X_DEPRECATED; + +extern ScreenPtr miPointerGetScreen( + DeviceIntPtr pDev); +extern void miPointerSetScreen( + DeviceIntPtr pDev, + int screen_num, + int x, + int y); + +/* Returns the current cursor position. */ +extern void miPointerGetPosition( + DeviceIntPtr pDev, + int *x, + int *y); + +/* Moves the cursor to the specified position. May clip the co-ordinates: + * x and y are modified in-place. */ +extern void miPointerSetPosition( + DeviceIntPtr pDev, + int *x, + int *y, + unsigned long time); + +extern void miPointerUpdateSprite( + DeviceIntPtr pDev); + +extern DevPrivateKey miPointerScreenKey; + +#endif /* MIPOINTER_H */ diff --git a/xorg-server/mi/mipointrst.h b/xorg-server/mi/mipointrst.h new file mode 100644 index 000000000..a80c52e7a --- /dev/null +++ b/xorg-server/mi/mipointrst.h @@ -0,0 +1,52 @@ +/* + * 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" + +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 */ +} 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/xorg-server/mi/mipoly.c b/xorg-server/mi/mipoly.c new file mode 100644 index 000000000..4c77fc268 --- /dev/null +++ b/xorg-server/mi/mipoly.c @@ -0,0 +1,127 @@ +/*********************************************************** + +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; + GCPtr pgc; + int shape, mode; + int count; + DDXPointPtr pPts; +{ + int i; + int xorg, yorg; + 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/xorg-server/mi/mipoly.h b/xorg-server/mi/mipoly.h new file mode 100644 index 000000000..c1bab4943 --- /dev/null +++ b/xorg-server/mi/mipoly.h @@ -0,0 +1,207 @@ +/* + +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 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/xorg-server/mi/mipolycon.c b/xorg-server/mi/mipolycon.c new file mode 100644 index 000000000..6aabad675 --- /dev/null +++ b/xorg-server/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 */ +{ + int xl = 0, xr = 0; /* x vals of left and right edges */ + int dl = 0, dr = 0; /* decision variables */ + 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 )xalloc(sizeof(DDXPointRec)*dy); + width = FirstWidth = (int *)xalloc(sizeof(int) * dy); + if(!FirstPoint || !FirstWidth) + { + if (FirstWidth) xfree(FirstWidth); + if (FirstPoint) xfree(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) + { + xfree(FirstWidth); + xfree(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); + xfree(FirstWidth); + xfree(FirstPoint); + return(TRUE); +} + + +/* + * Find the index of the point with the smallest y. + */ +static int +getPolyYBounds(DDXPointPtr pts, int n, int *by, int *ty) +{ + 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/xorg-server/mi/mipolygen.c b/xorg-server/mi/mipolygen.c new file mode 100644 index 000000000..7623fc40a --- /dev/null +++ b/xorg-server/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 */ +{ + EdgeTableEntry *pAET; /* the Active Edge Table */ + int y; /* the current scanline */ + int nPts = 0; /* number of pts in buffer */ + EdgeTableEntry *pWETE; /* Winding Edge Table */ + ScanLineList *pSLL; /* Current ScanLineList */ + 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 *) + xalloc(sizeof(EdgeTableEntry) * count))) + return(FALSE); + ptsOut = FirstPoint; + width = FirstWidth; + if (!miCreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock)) + { + xfree(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); + xfree(pETEs); + miFreeStorage(SLLBlock.next); + return(TRUE); +} diff --git a/xorg-server/mi/mipolypnt.c b/xorg-server/mi/mipolypnt.c new file mode 100644 index 000000000..56026bdbd --- /dev/null +++ b/xorg-server/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; + 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 *)xalloc(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); + } + xfree(pwidthInit); +} + diff --git a/xorg-server/mi/mipolyrect.c b/xorg-server/mi/mipolyrect.c new file mode 100644 index 000000000..788624872 --- /dev/null +++ b/xorg-server/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 *) xalloc(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); + xfree ((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/xorg-server/mi/mipolyseg.c b/xorg-server/mi/mipolyseg.c new file mode 100644 index 000000000..0cd9d416e --- /dev/null +++ b/xorg-server/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/xorg-server/mi/mipolytext.c b/xorg-server/mi/mipolytext.c new file mode 100644 index 000000000..82b16f7d2 --- /dev/null +++ b/xorg-server/mi/mipolytext.c @@ -0,0 +1,149 @@ +/******************************************************************* + +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" + +_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; +} + +_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/xorg-server/mi/mipolyutil.c b/xorg-server/mi/mipolyutil.c new file mode 100644 index 000000000..6ec860a25 --- /dev/null +++ b/xorg-server/mi/mipolyutil.c @@ -0,0 +1,395 @@ +/*********************************************************** + +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. + * + */ +static Bool +miInsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE, int scanline, + ScanLineListBlock **SLLBlock, int *iSLLBlock) +{ + EdgeTableEntry *start, *prev; + 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) + int count; + DDXPointPtr pts; + EdgeTable *ET; + EdgeTableEntry *AET; + EdgeTableEntry *pETEs; + ScanLineListBlock *pSLLBlock; +{ + DDXPointPtr top, bottom; + 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) + EdgeTableEntry *AET, *ETEs; +{ + EdgeTableEntry *pPrevAET; + 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) + EdgeTableEntry *AET; +{ + EdgeTableEntry *pWETE; + int inside = 1; + 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) + EdgeTableEntry *AET; +{ + EdgeTableEntry *pETEchase; + EdgeTableEntry *pETEinsert; + EdgeTableEntry *pETEchaseBackTMP; + 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) + ScanLineListBlock *pSLLBlock; +{ + ScanLineListBlock *tmpSLLBlock; + + while (pSLLBlock) + { + tmpSLLBlock = pSLLBlock->next; + xfree(pSLLBlock); + pSLLBlock = tmpSLLBlock; + } +} diff --git a/xorg-server/mi/mipushpxl.c b/xorg-server/mi/mipushpxl.c new file mode 100644 index 000000000..6fc57db11 --- /dev/null +++ b/xorg-server/mi/mipushpxl.c @@ -0,0 +1,274 @@ +/*********************************************************** + +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 "mi.h" +#include "servermd.h" + +#define NPT 128 + +/* These were stolen from mfb. They don't really belong here. */ +#define LONG2CHARSSAMEORDER(x) ((MiBits)(x)) +#define LONG2CHARSDIFFORDER( x ) ( ( ( ( x ) & (MiBits)0x000000FF ) << 0x18 ) \ + | ( ( ( x ) & (MiBits)0x0000FF00 ) << 0x08 ) \ + | ( ( ( x ) & (MiBits)0x00FF0000 ) >> 0x08 ) \ + | ( ( ( x ) & (MiBits)0xFF000000 ) >> 0x18 ) ) + + +#define PGSZB 4 +#define PPW (PGSZB<<3) /* assuming 8 bits per byte */ +#define PGSZ PPW +#define PLST (PPW-1) +#define PIM PLST +#define PWSH 5 + +/* 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; + MiBits *pw, *pwEnd; + MiBits msk; + int ib, w; + int ipt; /* index into above arrays */ + Bool fInBox; + DDXPointRec pt[NPT], ptThisLine; + int width[NPT]; +#if 1 + MiBits 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/xorg-server/mi/miregion.c b/xorg-server/mi/miregion.c new file mode 100644 index 000000000..45768a34f --- /dev/null +++ b/xorg-server/mi/miregion.c @@ -0,0 +1,1902 @@ +/*********************************************************** + +Copyright 1987, 1988, 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987, 1988, 1989 by +Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* The panoramix components contained the following notice */ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "regionstr.h" +#include <X11/Xprotostr.h> +#include <X11/Xfuncproto.h> +#include "gc.h" +#include "mi.h" +#include "mispans.h" +#include <pixman.h> + +#undef assert +#ifdef DEBUG +#define assert(expr) {if (!(expr)) \ + FatalError("Assertion failed file %s, line %d: expr\n", \ + __FILE__, __LINE__); } +#else +#define assert(expr) +#endif + +#define good(reg) assert(miValidRegion(reg)) + +/* + * The functions in this file implement the Region abstraction used extensively + * throughout the X11 sample server. A Region is simply a set of disjoint + * (non-overlapping) rectangles, plus an "extent" rectangle which is the + * smallest single rectangle that contains all the non-overlapping rectangles. + * + * A Region is implemented as a "y-x-banded" array of rectangles. This array + * imposes two degrees of order. First, all rectangles are sorted by top side + * y coordinate first (y1), and then by left side x coordinate (x1). + * + * Furthermore, the rectangles are grouped into "bands". Each rectangle in a + * band has the same top y coordinate (y1), and each has the same bottom y + * coordinate (y2). Thus all rectangles in a band differ only in their left + * and right side (x1 and x2). Bands are implicit in the array of rectangles: + * there is no separate list of band start pointers. + * + * The y-x band representation does not minimize rectangles. In particular, + * if a rectangle vertically crosses a band (the rectangle has scanlines in + * the y1 to y2 area spanned by the band), then the rectangle may be broken + * down into two or more smaller rectangles stacked one atop the other. + * + * ----------- ----------- + * | | | | band 0 + * | | -------- ----------- -------- + * | | | | in y-x banded | | | | band 1 + * | | | | form is | | | | + * ----------- | | ----------- -------- + * | | | | band 2 + * -------- -------- + * + * An added constraint on the rectangles is that they must cover as much + * horizontal area as possible: no two rectangles within a band are allowed + * to touch. + * + * Whenever possible, bands will be merged together to cover a greater vertical + * distance (and thus reduce the number of rectangles). Two bands can be merged + * only if the bottom of one touches the top of the other and they have + * rectangles in the same places (of the same width, of course). + * + * Adam de Boor wrote most of the original region code. Joel McCormack + * substantially modified or rewrote most of the core arithmetic routines, + * and added miRegionValidate in order to support several speed improvements + * to miValidateTree. Bob Scheifler changed the representation to be more + * compact when empty or a single rectangle, and did a bunch of gratuitous + * reformatting. + */ + +/* true iff two Boxes overlap */ +#define EXTENTCHECK(r1,r2) \ + (!( ((r1)->x2 <= (r2)->x1) || \ + ((r1)->x1 >= (r2)->x2) || \ + ((r1)->y2 <= (r2)->y1) || \ + ((r1)->y1 >= (r2)->y2) ) ) + +/* true iff (x,y) is in Box */ +#define INBOX(r,x,y) \ + ( ((r)->x2 > x) && \ + ((r)->x1 <= x) && \ + ((r)->y2 > y) && \ + ((r)->y1 <= y) ) + +/* true iff Box r1 contains Box r2 */ +#define SUBSUMES(r1,r2) \ + ( ((r1)->x1 <= (r2)->x1) && \ + ((r1)->x2 >= (r2)->x2) && \ + ((r1)->y1 <= (r2)->y1) && \ + ((r1)->y2 >= (r2)->y2) ) + +#define xallocData(n) (RegDataPtr)xalloc(REGION_SZOF(n)) +#define xfreeData(reg) if ((reg)->data && (reg)->data->size) xfree((reg)->data) + +#define RECTALLOC_BAIL(pReg,n,bail) \ +if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \ + if (!miRectAlloc(pReg, n)) { goto bail; } + +#define RECTALLOC(pReg,n) \ +if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \ + if (!miRectAlloc(pReg, n)) { return FALSE; } + +#define ADDRECT(pNextRect,nx1,ny1,nx2,ny2) \ +{ \ + pNextRect->x1 = nx1; \ + pNextRect->y1 = ny1; \ + pNextRect->x2 = nx2; \ + pNextRect->y2 = ny2; \ + pNextRect++; \ +} + +#define NEWRECT(pReg,pNextRect,nx1,ny1,nx2,ny2) \ +{ \ + if (!(pReg)->data || ((pReg)->data->numRects == (pReg)->data->size))\ + { \ + if (!miRectAlloc(pReg, 1)) \ + return FALSE; \ + pNextRect = REGION_TOP(pReg); \ + } \ + ADDRECT(pNextRect,nx1,ny1,nx2,ny2); \ + pReg->data->numRects++; \ + assert(pReg->data->numRects<=pReg->data->size); \ +} + + +#define DOWNSIZE(reg,numRects) \ +if (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) \ +{ \ + RegDataPtr NewData; \ + NewData = (RegDataPtr)xrealloc((reg)->data, REGION_SZOF(numRects)); \ + if (NewData) \ + { \ + NewData->size = (numRects); \ + (reg)->data = NewData; \ + } \ +} + + +_X_EXPORT BoxRec miEmptyBox = {0, 0, 0, 0}; +_X_EXPORT RegDataRec miEmptyData = {0, 0}; + +RegDataRec miBrokenData = {0, 0}; +static RegionRec miBrokenRegion = { { 0, 0, 0, 0 }, &miBrokenData }; + +extern void +InitRegions (void) +{ + pixman_region_set_static_pointers (&miEmptyBox, &miEmptyData, &miBrokenData); +} + +/***************************************************************** + * RegionCreate(rect, size) + * This routine does a simple malloc to make a structure of + * REGION of "size" number of rectangles. + *****************************************************************/ + +_X_EXPORT RegionPtr +miRegionCreate(rect, size) + BoxPtr rect; + int size; +{ + RegionPtr pReg; + + pReg = (RegionPtr)xalloc(sizeof(RegionRec)); + if (!pReg) + return &miBrokenRegion; + + miRegionInit (pReg, rect, size); + + return(pReg); +} + +_X_EXPORT void +miRegionDestroy(pReg) + RegionPtr pReg; +{ + pixman_region_fini (pReg); + if (pReg != &miBrokenRegion) + xfree(pReg); +} + +_X_EXPORT void +miPrintRegion(rgn) + RegionPtr rgn; +{ + int num, size; + int i; + BoxPtr rects; + + num = REGION_NUM_RECTS(rgn); + size = REGION_SIZE(rgn); + rects = REGION_RECTS(rgn); + ErrorF("num: %d size: %d\n", num, size); + ErrorF("extents: %d %d %d %d\n", + rgn->extents.x1, rgn->extents.y1, rgn->extents.x2, rgn->extents.y2); + for (i = 0; i < num; i++) + ErrorF("%d %d %d %d \n", + rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2); + ErrorF("\n"); +} + +_X_EXPORT Bool +miRegionEqual(reg1, reg2) + RegionPtr reg1; + RegionPtr reg2; +{ + return pixman_region_equal (reg1, reg2); +} + +#ifdef DEBUG +Bool +miValidRegion(reg) + RegionPtr reg; +{ + int i, numRects; + + if ((reg->extents.x1 > reg->extents.x2) || + (reg->extents.y1 > reg->extents.y2)) + return FALSE; + numRects = REGION_NUM_RECTS(reg); + if (!numRects) + return ((reg->extents.x1 == reg->extents.x2) && + (reg->extents.y1 == reg->extents.y2) && + (reg->data->size || (reg->data == &miEmptyData))); + else if (numRects == 1) + return (!reg->data); + else + { + BoxPtr pboxP, pboxN; + BoxRec box; + + pboxP = REGION_RECTS(reg); + box = *pboxP; + box.y2 = pboxP[numRects-1].y2; + pboxN = pboxP + 1; + for (i = numRects; --i > 0; pboxP++, pboxN++) + { + if ((pboxN->x1 >= pboxN->x2) || + (pboxN->y1 >= pboxN->y2)) + return FALSE; + if (pboxN->x1 < box.x1) + box.x1 = pboxN->x1; + if (pboxN->x2 > box.x2) + box.x2 = pboxN->x2; + if ((pboxN->y1 < pboxP->y1) || + ((pboxN->y1 == pboxP->y1) && + ((pboxN->x1 < pboxP->x2) || (pboxN->y2 != pboxP->y2)))) + return FALSE; + } + return ((box.x1 == reg->extents.x1) && + (box.x2 == reg->extents.x2) && + (box.y1 == reg->extents.y1) && + (box.y2 == reg->extents.y2)); + } +} +#endif /* DEBUG */ + +/***************************************************************** + * RegionInit(pReg, rect, size) + * Outer region rect is statically allocated. + *****************************************************************/ + +_X_EXPORT void +miRegionInit(pReg, rect, size) + RegionPtr pReg; + BoxPtr rect; + int size; +{ + if (rect) + pixman_region_init_with_extents (pReg, rect); + else + pixman_region_init (pReg); +} + +_X_EXPORT void +miRegionUninit(pReg) + RegionPtr pReg; +{ + pixman_region_fini (pReg); +} + +Bool +miRegionBreak (pReg) + RegionPtr pReg; +{ + xfreeData (pReg); + pReg->extents = miEmptyBox; + pReg->data = &miBrokenData; + return FALSE; +} + +_X_EXPORT Bool +miRectAlloc( + RegionPtr pRgn, + int n) +{ + RegDataPtr data; + + if (!pRgn->data) + { + n++; + pRgn->data = xallocData(n); + if (!pRgn->data) + return miRegionBreak (pRgn); + pRgn->data->numRects = 1; + *REGION_BOXPTR(pRgn) = pRgn->extents; + } + else if (!pRgn->data->size) + { + pRgn->data = xallocData(n); + if (!pRgn->data) + return miRegionBreak (pRgn); + pRgn->data->numRects = 0; + } + else + { + if (n == 1) + { + n = pRgn->data->numRects; + if (n > 500) /* XXX pick numbers out of a hat */ + n = 250; + } + n += pRgn->data->numRects; + data = (RegDataPtr)xrealloc(pRgn->data, REGION_SZOF(n)); + if (!data) + return miRegionBreak (pRgn); + pRgn->data = data; + } + pRgn->data->size = n; + return TRUE; +} + +_X_EXPORT Bool +miRegionCopy(dst, src) + RegionPtr dst; + RegionPtr src; +{ + return pixman_region_copy (dst, src); +} + +/*====================================================================== + * Generic Region Operator + *====================================================================*/ + +/*- + *----------------------------------------------------------------------- + * miCoalesce -- + * Attempt to merge the boxes in the current band with those in the + * previous one. We are guaranteed that the current band extends to + * the end of the rects array. Used only by miRegionOp. + * + * Results: + * The new index for the previous band. + * + * Side Effects: + * If coalescing takes place: + * - rectangles in the previous band will have their y2 fields + * altered. + * - pReg->data->numRects will be decreased. + * + *----------------------------------------------------------------------- + */ +_X_INLINE static int +miCoalesce ( + RegionPtr pReg, /* Region to coalesce */ + int prevStart, /* Index of start of previous band */ + int curStart) /* Index of start of current band */ +{ + BoxPtr pPrevBox; /* Current box in previous band */ + BoxPtr pCurBox; /* Current box in current band */ + int numRects; /* Number rectangles in both bands */ + int y2; /* Bottom of current band */ + /* + * Figure out how many rectangles are in the band. + */ + numRects = curStart - prevStart; + assert(numRects == pReg->data->numRects - curStart); + + if (!numRects) return curStart; + + /* + * The bands may only be coalesced if the bottom of the previous + * matches the top scanline of the current. + */ + pPrevBox = REGION_BOX(pReg, prevStart); + pCurBox = REGION_BOX(pReg, curStart); + if (pPrevBox->y2 != pCurBox->y1) return curStart; + + /* + * Make sure the bands have boxes in the same places. This + * assumes that boxes have been added in such a way that they + * cover the most area possible. I.e. two boxes in a band must + * have some horizontal space between them. + */ + y2 = pCurBox->y2; + + do { + if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) { + return (curStart); + } + pPrevBox++; + pCurBox++; + numRects--; + } while (numRects); + + /* + * The bands may be merged, so set the bottom y of each box + * in the previous band to the bottom y of the current band. + */ + numRects = curStart - prevStart; + pReg->data->numRects -= numRects; + do { + pPrevBox--; + pPrevBox->y2 = y2; + numRects--; + } while (numRects); + return prevStart; +} + + +/* Quicky macro to avoid trivial reject procedure calls to miCoalesce */ + +#define Coalesce(newReg, prevBand, curBand) \ + if (curBand - prevBand == newReg->data->numRects - curBand) { \ + prevBand = miCoalesce(newReg, prevBand, curBand); \ + } else { \ + prevBand = curBand; \ + } + +/*- + *----------------------------------------------------------------------- + * miAppendNonO -- + * Handle a non-overlapping band for the union and subtract operations. + * Just adds the (top/bottom-clipped) rectangles into the region. + * Doesn't have to check for subsumption or anything. + * + * Results: + * None. + * + * Side Effects: + * pReg->data->numRects is incremented and the rectangles overwritten + * with the rectangles we're passed. + * + *----------------------------------------------------------------------- + */ + +_X_INLINE static Bool +miAppendNonO ( + RegionPtr pReg, + BoxPtr r, + BoxPtr rEnd, + int y1, + int y2) +{ + BoxPtr pNextRect; + int newRects; + + newRects = rEnd - r; + + assert(y1 < y2); + assert(newRects != 0); + + /* Make sure we have enough space for all rectangles to be added */ + RECTALLOC(pReg, newRects); + pNextRect = REGION_TOP(pReg); + pReg->data->numRects += newRects; + do { + assert(r->x1 < r->x2); + ADDRECT(pNextRect, r->x1, y1, r->x2, y2); + r++; + } while (r != rEnd); + + return TRUE; +} + +#define FindBand(r, rBandEnd, rEnd, ry1) \ +{ \ + ry1 = r->y1; \ + rBandEnd = r+1; \ + while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) { \ + rBandEnd++; \ + } \ +} + +#define AppendRegions(newReg, r, rEnd) \ +{ \ + int newRects; \ + if ((newRects = rEnd - r)) { \ + RECTALLOC(newReg, newRects); \ + memmove((char *)REGION_TOP(newReg),(char *)r, \ + newRects * sizeof(BoxRec)); \ + newReg->data->numRects += newRects; \ + } \ +} + +/*- + *----------------------------------------------------------------------- + * miRegionOp -- + * Apply an operation to two regions. Called by miUnion, miInverse, + * miSubtract, miIntersect.... Both regions MUST have at least one + * rectangle, and cannot be the same object. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * The new region is overwritten. + * pOverlap set to TRUE if overlapFunc ever returns TRUE. + * + * Notes: + * The idea behind this function is to view the two regions as sets. + * Together they cover a rectangle of area that this function divides + * into horizontal bands where points are covered only by one region + * or by both. For the first case, the nonOverlapFunc is called with + * each the band and the band's upper and lower extents. For the + * second, the overlapFunc is called to process the entire band. It + * is responsible for clipping the rectangles in the band, though + * this function provides the boundaries. + * At the end of each band, the new region is coalesced, if possible, + * to reduce the number of rectangles in the region. + * + *----------------------------------------------------------------------- + */ + +typedef Bool (*OverlapProcPtr)( + RegionPtr pReg, + BoxPtr r1, + BoxPtr r1End, + BoxPtr r2, + BoxPtr r2End, + short y1, + short y2, + Bool *pOverlap); + +static Bool +miRegionOp( + RegionPtr newReg, /* Place to store result */ + RegionPtr reg1, /* First region in operation */ + RegionPtr reg2, /* 2d region in operation */ + OverlapProcPtr overlapFunc, /* Function to call for over- + * lapping bands */ + Bool appendNon1, /* Append non-overlapping bands */ + /* in region 1 ? */ + Bool appendNon2, /* Append non-overlapping bands */ + /* in region 2 ? */ + Bool *pOverlap) +{ + BoxPtr r1; /* Pointer into first region */ + BoxPtr r2; /* Pointer into 2d region */ + BoxPtr r1End; /* End of 1st region */ + BoxPtr r2End; /* End of 2d region */ + short ybot; /* Bottom of intersection */ + short ytop; /* Top of intersection */ + RegDataPtr oldData; /* Old data for newReg */ + int prevBand; /* Index of start of + * previous band in newReg */ + int curBand; /* Index of start of current + * band in newReg */ + BoxPtr r1BandEnd; /* End of current band in r1 */ + BoxPtr r2BandEnd; /* End of current band in r2 */ + short top; /* Top of non-overlapping band */ + short bot; /* Bottom of non-overlapping band*/ + int r1y1; /* Temps for r1->y1 and r2->y1 */ + int r2y1; + int newSize; + int numRects; + + /* + * Break any region computed from a broken region + */ + if (REGION_NAR (reg1) || REGION_NAR(reg2)) + return miRegionBreak (newReg); + + /* + * Initialization: + * set r1, r2, r1End and r2End appropriately, save the rectangles + * of the destination region until the end in case it's one of + * the two source regions, then mark the "new" region empty, allocating + * another array of rectangles for it to use. + */ + + r1 = REGION_RECTS(reg1); + newSize = REGION_NUM_RECTS(reg1); + r1End = r1 + newSize; + numRects = REGION_NUM_RECTS(reg2); + r2 = REGION_RECTS(reg2); + r2End = r2 + numRects; + assert(r1 != r1End); + assert(r2 != r2End); + + oldData = (RegDataPtr)NULL; + if (((newReg == reg1) && (newSize > 1)) || + ((newReg == reg2) && (numRects > 1))) + { + oldData = newReg->data; + newReg->data = &miEmptyData; + } + /* guess at new size */ + if (numRects > newSize) + newSize = numRects; + newSize <<= 1; + if (!newReg->data) + newReg->data = &miEmptyData; + else if (newReg->data->size) + newReg->data->numRects = 0; + if (newSize > newReg->data->size) + if (!miRectAlloc(newReg, newSize)) + return FALSE; + + /* + * Initialize ybot. + * In the upcoming loop, ybot and ytop serve different functions depending + * on whether the band being handled is an overlapping or non-overlapping + * band. + * In the case of a non-overlapping band (only one of the regions + * has points in the band), ybot is the bottom of the most recent + * intersection and thus clips the top of the rectangles in that band. + * ytop is the top of the next intersection between the two regions and + * serves to clip the bottom of the rectangles in the current band. + * For an overlapping band (where the two regions intersect), ytop clips + * the top of the rectangles of both regions and ybot clips the bottoms. + */ + + ybot = min(r1->y1, r2->y1); + + /* + * prevBand serves to mark the start of the previous band so rectangles + * can be coalesced into larger rectangles. qv. miCoalesce, above. + * In the beginning, there is no previous band, so prevBand == curBand + * (curBand is set later on, of course, but the first band will always + * start at index 0). prevBand and curBand must be indices because of + * the possible expansion, and resultant moving, of the new region's + * array of rectangles. + */ + prevBand = 0; + + do { + /* + * This algorithm proceeds one source-band (as opposed to a + * destination band, which is determined by where the two regions + * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the + * rectangle after the last one in the current band for their + * respective regions. + */ + assert(r1 != r1End); + assert(r2 != r2End); + + FindBand(r1, r1BandEnd, r1End, r1y1); + FindBand(r2, r2BandEnd, r2End, r2y1); + + /* + * First handle the band that doesn't intersect, if any. + * + * Note that attention is restricted to one band in the + * non-intersecting region at once, so if a region has n + * bands between the current position and the next place it overlaps + * the other, this entire loop will be passed through n times. + */ + if (r1y1 < r2y1) { + if (appendNon1) { + top = max(r1y1, ybot); + bot = min(r1->y2, r2y1); + if (top != bot) { + curBand = newReg->data->numRects; + miAppendNonO(newReg, r1, r1BandEnd, top, bot); + Coalesce(newReg, prevBand, curBand); + } + } + ytop = r2y1; + } else if (r2y1 < r1y1) { + if (appendNon2) { + top = max(r2y1, ybot); + bot = min(r2->y2, r1y1); + if (top != bot) { + curBand = newReg->data->numRects; + miAppendNonO(newReg, r2, r2BandEnd, top, bot); + Coalesce(newReg, prevBand, curBand); + } + } + ytop = r1y1; + } else { + ytop = r1y1; + } + + /* + * Now see if we've hit an intersecting band. The two bands only + * intersect if ybot > ytop + */ + ybot = min(r1->y2, r2->y2); + if (ybot > ytop) { + curBand = newReg->data->numRects; + (* overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot, + pOverlap); + Coalesce(newReg, prevBand, curBand); + } + + /* + * If we've finished with a band (y2 == ybot) we skip forward + * in the region to the next band. + */ + if (r1->y2 == ybot) r1 = r1BandEnd; + if (r2->y2 == ybot) r2 = r2BandEnd; + + } while (r1 != r1End && r2 != r2End); + + /* + * Deal with whichever region (if any) still has rectangles left. + * + * We only need to worry about banding and coalescing for the very first + * band left. After that, we can just group all remaining boxes, + * regardless of how many bands, into one final append to the list. + */ + + if ((r1 != r1End) && appendNon1) { + /* Do first nonOverlap1Func call, which may be able to coalesce */ + FindBand(r1, r1BandEnd, r1End, r1y1); + curBand = newReg->data->numRects; + miAppendNonO(newReg, r1, r1BandEnd, max(r1y1, ybot), r1->y2); + Coalesce(newReg, prevBand, curBand); + /* Just append the rest of the boxes */ + AppendRegions(newReg, r1BandEnd, r1End); + + } else if ((r2 != r2End) && appendNon2) { + /* Do first nonOverlap2Func call, which may be able to coalesce */ + FindBand(r2, r2BandEnd, r2End, r2y1); + curBand = newReg->data->numRects; + miAppendNonO(newReg, r2, r2BandEnd, max(r2y1, ybot), r2->y2); + Coalesce(newReg, prevBand, curBand); + /* Append rest of boxes */ + AppendRegions(newReg, r2BandEnd, r2End); + } + + if (oldData) + xfree(oldData); + + if (!(numRects = newReg->data->numRects)) + { + xfreeData(newReg); + newReg->data = &miEmptyData; + } + else if (numRects == 1) + { + newReg->extents = *REGION_BOXPTR(newReg); + xfreeData(newReg); + newReg->data = (RegDataPtr)NULL; + } + else + { + DOWNSIZE(newReg, numRects); + } + + return TRUE; +} + +/*- + *----------------------------------------------------------------------- + * miSetExtents -- + * Reset the extents of a region to what they should be. Called by + * miSubtract and miIntersect as they can't figure it out along the + * way or do so easily, as miUnion can. + * + * Results: + * None. + * + * Side Effects: + * The region's 'extents' structure is overwritten. + * + *----------------------------------------------------------------------- + */ +static void +miSetExtents (RegionPtr pReg) +{ + BoxPtr pBox, pBoxEnd; + + if (!pReg->data) + return; + if (!pReg->data->size) + { + pReg->extents.x2 = pReg->extents.x1; + pReg->extents.y2 = pReg->extents.y1; + return; + } + + pBox = REGION_BOXPTR(pReg); + pBoxEnd = REGION_END(pReg); + + /* + * Since pBox is the first rectangle in the region, it must have the + * smallest y1 and since pBoxEnd is the last rectangle in the region, + * it must have the largest y2, because of banding. Initialize x1 and + * x2 from pBox and pBoxEnd, resp., as good things to initialize them + * to... + */ + pReg->extents.x1 = pBox->x1; + pReg->extents.y1 = pBox->y1; + pReg->extents.x2 = pBoxEnd->x2; + pReg->extents.y2 = pBoxEnd->y2; + + assert(pReg->extents.y1 < pReg->extents.y2); + while (pBox <= pBoxEnd) { + if (pBox->x1 < pReg->extents.x1) + pReg->extents.x1 = pBox->x1; + if (pBox->x2 > pReg->extents.x2) + pReg->extents.x2 = pBox->x2; + pBox++; + }; + + assert(pReg->extents.x1 < pReg->extents.x2); +} + +/*====================================================================== + * Region Intersection + *====================================================================*/ +/*- + *----------------------------------------------------------------------- + * miIntersectO -- + * Handle an overlapping band for miIntersect. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * Rectangles may be added to the region. + * + *----------------------------------------------------------------------- + */ +/*ARGSUSED*/ +_X_EXPORT Bool +miIntersect(newReg, reg1, reg2) + RegionPtr newReg; /* destination Region */ + RegionPtr reg1; + RegionPtr reg2; /* source regions */ +{ + return pixman_region_intersect (newReg, reg1, reg2); +} + +#define MERGERECT(r) \ +{ \ + if (r->x1 <= x2) { \ + /* Merge with current rectangle */ \ + if (r->x1 < x2) *pOverlap = TRUE; \ + if (x2 < r->x2) x2 = r->x2; \ + } else { \ + /* Add current rectangle, start new one */ \ + NEWRECT(pReg, pNextRect, x1, y1, x2, y2); \ + x1 = r->x1; \ + x2 = r->x2; \ + } \ + r++; \ +} + +/*====================================================================== + * Region Union + *====================================================================*/ + +/*- + *----------------------------------------------------------------------- + * miUnionO -- + * Handle an overlapping band for the union operation. Picks the + * left-most rectangle each time and merges it into the region. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * pReg is overwritten. + * pOverlap is set to TRUE if any boxes overlap. + * + *----------------------------------------------------------------------- + */ +static Bool +miUnionO ( + RegionPtr pReg, + BoxPtr r1, + BoxPtr r1End, + BoxPtr r2, + BoxPtr r2End, + short y1, + short y2, + Bool *pOverlap) +{ + BoxPtr pNextRect; + int x1; /* left and right side of current union */ + int x2; + + assert (y1 < y2); + assert(r1 != r1End && r2 != r2End); + + pNextRect = REGION_TOP(pReg); + + /* Start off current rectangle */ + if (r1->x1 < r2->x1) + { + x1 = r1->x1; + x2 = r1->x2; + r1++; + } + else + { + x1 = r2->x1; + x2 = r2->x2; + r2++; + } + while (r1 != r1End && r2 != r2End) + { + if (r1->x1 < r2->x1) MERGERECT(r1) else MERGERECT(r2); + } + + /* Finish off whoever (if any) is left */ + if (r1 != r1End) + { + do + { + MERGERECT(r1); + } while (r1 != r1End); + } + else if (r2 != r2End) + { + do + { + MERGERECT(r2); + } while (r2 != r2End); + } + + /* Add current rectangle */ + NEWRECT(pReg, pNextRect, x1, y1, x2, y2); + + return TRUE; +} + +_X_EXPORT Bool +miUnion(newReg, reg1, reg2) + RegionPtr newReg; /* destination Region */ + RegionPtr reg1; + RegionPtr reg2; /* source regions */ +{ + return pixman_region_union (newReg, reg1, reg2); +} + +/*====================================================================== + * Batch Rectangle Union + *====================================================================*/ + +/*- + *----------------------------------------------------------------------- + * miRegionAppend -- + * + * "Append" the rgn rectangles onto the end of dstrgn, maintaining + * knowledge of YX-banding when it's easy. Otherwise, dstrgn just + * becomes a non-y-x-banded random collection of rectangles, and not + * yet a true region. After a sequence of appends, the caller must + * call miRegionValidate to ensure that a valid region is constructed. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * dstrgn is modified if rgn has rectangles. + * + */ +_X_EXPORT Bool +miRegionAppend(dstrgn, rgn) + RegionPtr dstrgn; + RegionPtr rgn; +{ + int numRects, dnumRects, size; + BoxPtr new, old; + Bool prepend; + + if (REGION_NAR(rgn)) + return miRegionBreak (dstrgn); + + if (!rgn->data && (dstrgn->data == &miEmptyData)) + { + dstrgn->extents = rgn->extents; + dstrgn->data = (RegDataPtr)NULL; + return TRUE; + } + + numRects = REGION_NUM_RECTS(rgn); + if (!numRects) + return TRUE; + prepend = FALSE; + size = numRects; + dnumRects = REGION_NUM_RECTS(dstrgn); + if (!dnumRects && (size < 200)) + size = 200; /* XXX pick numbers out of a hat */ + RECTALLOC(dstrgn, size); + old = REGION_RECTS(rgn); + if (!dnumRects) + dstrgn->extents = rgn->extents; + else if (dstrgn->extents.x2 > dstrgn->extents.x1) + { + BoxPtr first, last; + + first = old; + last = REGION_BOXPTR(dstrgn) + (dnumRects - 1); + if ((first->y1 > last->y2) || + ((first->y1 == last->y1) && (first->y2 == last->y2) && + (first->x1 > last->x2))) + { + if (rgn->extents.x1 < dstrgn->extents.x1) + dstrgn->extents.x1 = rgn->extents.x1; + if (rgn->extents.x2 > dstrgn->extents.x2) + dstrgn->extents.x2 = rgn->extents.x2; + dstrgn->extents.y2 = rgn->extents.y2; + } + else + { + first = REGION_BOXPTR(dstrgn); + last = old + (numRects - 1); + if ((first->y1 > last->y2) || + ((first->y1 == last->y1) && (first->y2 == last->y2) && + (first->x1 > last->x2))) + { + prepend = TRUE; + if (rgn->extents.x1 < dstrgn->extents.x1) + dstrgn->extents.x1 = rgn->extents.x1; + if (rgn->extents.x2 > dstrgn->extents.x2) + dstrgn->extents.x2 = rgn->extents.x2; + dstrgn->extents.y1 = rgn->extents.y1; + } + else + dstrgn->extents.x2 = dstrgn->extents.x1; + } + } + if (prepend) + { + new = REGION_BOX(dstrgn, numRects); + if (dnumRects == 1) + *new = *REGION_BOXPTR(dstrgn); + else + memmove((char *)new,(char *)REGION_BOXPTR(dstrgn), + dnumRects * sizeof(BoxRec)); + new = REGION_BOXPTR(dstrgn); + } + else + new = REGION_BOXPTR(dstrgn) + dnumRects; + if (numRects == 1) + *new = *old; + else + memmove((char *)new, (char *)old, numRects * sizeof(BoxRec)); + dstrgn->data->numRects += numRects; + return TRUE; +} + + +#define ExchangeRects(a, b) \ +{ \ + BoxRec t; \ + t = rects[a]; \ + rects[a] = rects[b]; \ + rects[b] = t; \ +} + +static void +QuickSortRects( + BoxRec rects[], + int numRects) +{ + int y1; + int x1; + int i, j; + 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 */ + int j; /* Index into ri */ + RegionInfo *rit; /* &ri[j] */ + RegionPtr reg; /* ri[j].reg */ + BoxPtr box; /* Current box in rects */ + BoxPtr riBox; /* Last box in ri[j].reg */ + RegionPtr hreg; /* ri[j_half].reg */ + Bool ret = TRUE; + + *pOverlap = FALSE; + if (!badreg->data) + { + good(badreg); + return TRUE; + } + numRects = badreg->data->numRects; + if (!numRects) + { + if (REGION_NAR(badreg)) + return FALSE; + good(badreg); + return TRUE; + } + 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; + xRectangle *prect; + int ctype; +{ + + RegionPtr pRgn; + RegDataPtr pData; + BoxPtr pBox; + 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*/ + +/*- + *----------------------------------------------------------------------- + * miSubtract -- + * Subtract regS from regM and leave the result in regD. + * S stands for subtrahend, M for minuend and D for difference. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * regD is overwritten. + * + *----------------------------------------------------------------------- + */ +_X_EXPORT Bool +miSubtract(regD, regM, regS) + RegionPtr regD; + RegionPtr regM; + RegionPtr regS; +{ + return pixman_region_subtract (regD, regM, regS); +} + +/*====================================================================== + * Region Inversion + *====================================================================*/ + +/*- + *----------------------------------------------------------------------- + * miInverse -- + * Take a region and a box and return a region that is everything + * in the box but not in the region. The careful reader will note + * that this is the same as subtracting the region from the box... + * + * Results: + * TRUE. + * + * Side Effects: + * newReg is overwritten. + * + *----------------------------------------------------------------------- + */ +_X_EXPORT Bool +miInverse(newReg, reg1, invRect) + RegionPtr newReg; /* Destination region */ + RegionPtr reg1; /* Region to invert */ + BoxPtr invRect; /* Bounding box for inversion */ +{ + return pixman_region_inverse (newReg, reg1, invRect); +} +_X_EXPORT int +miRectIn(region, prect) + RegionPtr region; + BoxPtr prect; +{ + return pixman_region_contains_rectangle (region, prect); +} + +/* TranslateRegion(pReg, x, y) + translates in place +*/ + +_X_EXPORT void +miTranslateRegion(pReg, x, y) + RegionPtr pReg; + int x; + int y; +{ + pixman_region_translate (pReg, x, y); +} + +_X_EXPORT void +miRegionReset(pReg, pBox) + RegionPtr pReg; + BoxPtr pBox; +{ + pixman_region_reset (pReg, pBox); +} + +_X_EXPORT Bool +miPointInRegion(pReg, x, y, box) + RegionPtr pReg; + int x, y; + BoxPtr box; /* "return" value */ +{ + return pixman_region_contains_point (pReg, x, y, box); +} + +_X_EXPORT Bool +miRegionNotEmpty(pReg) + RegionPtr pReg; +{ + return pixman_region_not_empty (pReg); +} + +Bool +miRegionBroken(RegionPtr pReg) +{ + good(pReg); + return (REGION_NAR(pReg)); +} + +_X_EXPORT void +miRegionEmpty(pReg) + RegionPtr pReg; +{ + good(pReg); + xfreeData(pReg); + pReg->extents.x2 = pReg->extents.x1; + pReg->extents.y2 = pReg->extents.y1; + pReg->data = &miEmptyData; +} + +_X_EXPORT BoxPtr +miRegionExtents(pReg) + RegionPtr pReg; +{ + good(pReg); + return(&pReg->extents); +} + +#define ExchangeSpans(a, b) \ +{ \ + DDXPointRec tpt; \ + int tw; \ + \ + tpt = spans[a]; spans[a] = spans[b]; spans[b] = tpt; \ + tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \ +} + +/* ||| I should apply the merge sort code to rectangle sorting above, and see + if mapping time can be improved. But right now I've been at work 12 hours, + so forget it. +*/ + +static void QuickSortSpans( + DDXPointRec spans[], + int widths[], + int numSpans) +{ + int y; + int i, j, m; + DDXPointPtr r; + + /* Always called with numSpans > 1 */ + /* Sorts only by y, doesn't bother to sort by x */ + + do + { + if (numSpans < 9) + { + /* Do insertion sort */ + int yprev; + + yprev = spans[0].y; + i = 1; + do + { /* while i != numSpans */ + y = spans[i].y; + if (yprev > y) + { + /* spans[i] is out of order. Move into proper location. */ + DDXPointRec tpt; + int tw, k; + + for (j = 0; y >= spans[j].y; j++) {} + tpt = spans[i]; + tw = widths[i]; + for (k = i; k != j; k--) + { + spans[k] = spans[k-1]; + widths[k] = widths[k-1]; + } + spans[j] = tpt; + widths[j] = tw; + y = spans[i].y; + } /* if out of order */ + yprev = y; + i++; + } while (i != numSpans); + return; + } + + /* Choose partition element, stick in location 0 */ + m = numSpans / 2; + if (spans[m].y > spans[0].y) ExchangeSpans(m, 0); + if (spans[m].y > spans[numSpans-1].y) ExchangeSpans(m, numSpans-1); + if (spans[m].y > spans[0].y) ExchangeSpans(m, 0); + y = spans[0].y; + + /* Partition array */ + i = 0; + j = numSpans; + do + { + r = &(spans[i]); + do + { + r++; + i++; + } while (i != numSpans && r->y < y); + r = &(spans[j]); + do + { + r--; + j--; + } while (y < r->y); + if (i < j) + ExchangeSpans(i, j); + } while (i < j); + + /* Move partition element back to middle */ + ExchangeSpans(0, j); + + /* Recurse */ + if (numSpans-j-1 > 1) + QuickSortSpans(&spans[j+1], &widths[j+1], numSpans-j-1); + numSpans = j; + } while (numSpans > 1); +} + +#define NextBand() \ +{ \ + clipy1 = pboxBandStart->y1; \ + clipy2 = pboxBandStart->y2; \ + pboxBandEnd = pboxBandStart + 1; \ + while (pboxBandEnd != pboxLast && pboxBandEnd->y1 == clipy1) { \ + pboxBandEnd++; \ + } \ + for (; ppt != pptLast && ppt->y < clipy1; ppt++, pwidth++) {} \ +} + +/* + Clip a list of scanlines to a region. The caller has allocated the + space. FSorted is non-zero if the scanline origins are in ascending + order. + returns the number of new, clipped scanlines. +*/ + +_X_EXPORT int +miClipSpans( + RegionPtr prgnDst, + DDXPointPtr ppt, + int *pwidth, + int nspans, + DDXPointPtr pptNew, + int *pwidthNew, + int fSorted) +{ + DDXPointPtr pptLast; + int *pwidthNewStart; /* the vengeance of Xerox! */ + int y, x1, x2; + int numRects; + + good(prgnDst); + pptLast = ppt + nspans; + pwidthNewStart = pwidthNew; + + if (!prgnDst->data) + { + /* Do special fast code with clip boundaries in registers(?) */ + /* It doesn't pay much to make use of fSorted in this case, + so we lump everything together. */ + + int clipx1, clipx2, clipy1, clipy2; + + clipx1 = prgnDst->extents.x1; + clipy1 = prgnDst->extents.y1; + clipx2 = prgnDst->extents.x2; + clipy2 = prgnDst->extents.y2; + + for (; ppt != pptLast; ppt++, pwidth++) + { + y = ppt->y; + x1 = ppt->x; + if (clipy1 <= y && y < clipy2) + { + x2 = x1 + *pwidth; + if (x1 < clipx1) x1 = clipx1; + if (x2 > clipx2) x2 = clipx2; + if (x1 < x2) + { + /* part of span in clip rectangle */ + pptNew->x = x1; + pptNew->y = y; + *pwidthNew = x2 - x1; + pptNew++; + pwidthNew++; + } + } + } /* end for */ + + } + else if ((numRects = prgnDst->data->numRects)) + { + /* Have to clip against many boxes */ + BoxPtr pboxBandStart, pboxBandEnd; + BoxPtr pbox; + BoxPtr pboxLast; + int clipy1, clipy2; + + /* In this case, taking advantage of sorted spans gains more than + the sorting costs. */ + if ((! fSorted) && (nspans > 1)) + QuickSortSpans(ppt, pwidth, nspans); + + pboxBandStart = REGION_BOXPTR(prgnDst); + pboxLast = pboxBandStart + numRects; + + NextBand(); + + for (; ppt != pptLast; ) + { + y = ppt->y; + if (y < clipy2) + { + /* span is in the current band */ + pbox = pboxBandStart; + x1 = ppt->x; + x2 = x1 + *pwidth; + do + { /* For each box in band */ + int newx1, newx2; + + newx1 = x1; + newx2 = x2; + if (newx1 < pbox->x1) newx1 = pbox->x1; + if (newx2 > pbox->x2) newx2 = pbox->x2; + if (newx1 < newx2) + { + /* Part of span in clip rectangle */ + pptNew->x = newx1; + pptNew->y = y; + *pwidthNew = newx2 - newx1; + pptNew++; + pwidthNew++; + } + pbox++; + } while (pbox != pboxBandEnd); + ppt++; + pwidth++; + } + else + { + /* Move to next band, adjust ppt as needed */ + pboxBandStart = pboxBandEnd; + if (pboxBandStart == pboxLast) + break; /* We're completely done */ + NextBand(); + } + } + } + return (pwidthNew - pwidthNewStart); +} + +/* find the band in a region with the most rectangles */ +_X_EXPORT int +miFindMaxBand(prgn) + RegionPtr prgn; +{ + int nbox; + BoxPtr pbox; + int nThisBand; + int nMaxBand = 0; + short yThisBand; + + good(prgn); + nbox = REGION_NUM_RECTS(prgn); + pbox = REGION_RECTS(prgn); + + while(nbox > 0) + { + yThisBand = pbox->y1; + nThisBand = 0; + while((nbox > 0) && (pbox->y1 == yThisBand)) + { + nbox--; + pbox++; + nThisBand++; + } + if (nThisBand > nMaxBand) + nMaxBand = nThisBand; + } + return (nMaxBand); +} diff --git a/xorg-server/mi/miscanfill.h b/xorg-server/mi/miscanfill.h new file mode 100644 index 000000000..e318c45b4 --- /dev/null +++ b/xorg-server/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/xorg-server/mi/miscrinit.c b/xorg-server/mi/miscrinit.c new file mode 100644 index 000000000..7ca5f5df1 --- /dev/null +++ b/xorg-server/mi/miscrinit.c @@ -0,0 +1,327 @@ +/* + +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; +} + +static Bool +miCloseScreen (int iScreen, ScreenPtr pScreen) +{ + return ((*pScreen->DestroyPixmap)((PixmapPtr)pScreen->devPrivate)); +} + +/* With the introduction of pixmap privates, the "screen pixmap" can no + * longer be created in miScreenInit, since all the modules that could + * possibly ask for pixmap private space have not been initialized at + * that time. pScreen->CreateScreenResources is called after all + * possible private-requesting modules have been inited; we create the + * screen pixmap here. + */ +_X_EXPORT Bool +miCreateScreenResources(pScreen) + ScreenPtr pScreen; +{ + miScreenInitParmsPtr pScrInitParms; + pointer value; + + pScrInitParms = (miScreenInitParmsPtr)pScreen->devPrivate; + + /* if width is non-zero, pScreen->devPrivate will be a pixmap + * else it will just take the value pbits + */ + if (pScrInitParms->width) + { + PixmapPtr pPixmap; + + /* create a pixmap with no data, then redirect it to point to + * the screen + */ + pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth, 0); + if (!pPixmap) + return FALSE; + + if (!(*pScreen->ModifyPixmapHeader)(pPixmap, pScreen->width, + pScreen->height, pScreen->rootDepth, + BitsPerPixel(pScreen->rootDepth), + PixmapBytePad(pScrInitParms->width, pScreen->rootDepth), + pScrInitParms->pbits)) + return FALSE; + value = (pointer)pPixmap; + } + else + { + value = pScrInitParms->pbits; + } + xfree(pScreen->devPrivate); /* freeing miScreenInitParmsRec */ + pScreen->devPrivate = value; /* pPixmap or pbits */ + return TRUE; +} + +Bool +miScreenDevPrivateInit(pScreen, width, pbits) + ScreenPtr pScreen; + int width; + pointer pbits; +{ + miScreenInitParmsPtr pScrInitParms; + + /* Stash pbits and width in a short-lived miScreenInitParmsRec attached + * to the screen, until CreateScreenResources can put them in the + * screen pixmap. + */ + pScrInitParms = (miScreenInitParmsPtr)xalloc(sizeof(miScreenInitParmsRec)); + if (!pScrInitParms) + return FALSE; + pScrInitParms->pbits = pbits; + pScrInitParms->width = width; + pScreen->devPrivate = (pointer)pScrInitParms; + return TRUE; +} + +_X_EXPORT Bool +miScreenInit(pScreen, pbits, xsize, ysize, dpix, dpiy, width, + rootDepth, numDepths, depths, rootVisual, numVisuals, visuals) + ScreenPtr pScreen; + pointer pbits; /* pointer to screen bits */ + int xsize, ysize; /* in pixels */ + int dpix, dpiy; /* dots per inch */ + int width; /* pixel width of frame buffer */ + int rootDepth; /* depth of root window */ + int numDepths; /* number of depths supported */ + DepthRec *depths; /* supported depths */ + VisualID rootVisual; /* root visual */ + int numVisuals; /* number of visuals supported */ + VisualRec *visuals; /* supported visuals */ +{ + pScreen->width = xsize; + pScreen->height = ysize; + pScreen->mmWidth = (xsize * 254 + dpix * 5) / (dpix * 10); + pScreen->mmHeight = (ysize * 254 + dpiy * 5) / (dpiy * 10); + pScreen->numDepths = numDepths; + pScreen->rootDepth = rootDepth; + pScreen->allowedDepths = depths; + pScreen->rootVisual = rootVisual; + /* defColormap */ + pScreen->minInstalledCmaps = 1; + pScreen->maxInstalledCmaps = 1; + pScreen->backingStoreSupport = NotUseful; + pScreen->saveUnderSupport = NotUseful; + /* whitePixel, blackPixel */ + pScreen->ModifyPixmapHeader = miModifyPixmapHeader; + pScreen->CreateScreenResources = miCreateScreenResources; + pScreen->GetScreenPixmap = miGetScreenPixmap; + pScreen->SetScreenPixmap = miSetScreenPixmap; + pScreen->numVisuals = numVisuals; + pScreen->visuals = visuals; + if (width) + { +#ifdef MITSHM + ShmRegisterFbFuncs(pScreen); +#endif + pScreen->CloseScreen = miCloseScreen; + } + /* else CloseScreen */ + /* QueryBestSize, SaveScreen, GetImage, GetSpans */ + pScreen->PointerNonInterestBox = (PointerNonInterestBoxProcPtr) 0; + pScreen->SourceValidate = (SourceValidateProcPtr) 0; + /* CreateWindow, DestroyWindow, PositionWindow, ChangeWindowAttributes */ + /* RealizeWindow, UnrealizeWindow */ + pScreen->ValidateTree = miValidateTree; + pScreen->PostValidateTree = (PostValidateTreeProcPtr) 0; + pScreen->WindowExposures = miWindowExposures; + /* 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); +} + +static DevPrivateKey privateKey = &privateKey; + +_X_EXPORT DevPrivateKey +miAllocateGCPrivateIndex() +{ + return privateKey; +} + +_X_EXPORT DevPrivateKey miZeroLineScreenKey = &miZeroLineScreenKey; + +_X_EXPORT void +miSetZeroLineBias(pScreen, bias) + ScreenPtr pScreen; + unsigned int bias; +{ + dixSetPrivate(&pScreen->devPrivates, miZeroLineScreenKey, (pointer)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/xorg-server/mi/mispans.c b/xorg-server/mi/mispans.c new file mode 100644 index 000000000..6f30155f5 --- /dev/null +++ b/xorg-server/mi/mispans.c @@ -0,0 +1,537 @@ +/*********************************************************** + +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) + +static void miSubtractSpans (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; +{ + int ymin, ymax; + 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( + DDXPointRec points[], + int widths[], + int numSpans ) +{ + int x; + int i, j, m; + DDXPointPtr r; + +/* Always called with numSpans > 1 */ +/* Sorts only by x, as all y should be the same */ + +#define ExchangeSpans(a, b) \ +{ \ + DDXPointRec tpt; \ + 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 */ + 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, + DDXPointRec *newPoints, + int *newWidths ) +{ + int newx1, newx2, oldpt, i, y; + DDXPointRec *oldPoints; + 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 */ + +static void +miDisposeSpanGroup (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; +{ + int i; + Spans *spans; + Spans *yspans; + int *ysizes; + int ymin, ylength; + + /* Outgoing spans for one big call to FillSpans */ + DDXPointPtr points; + int *widths; + 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)xalloc for these? */ + } + + spanGroup->count = 0; + spanGroup->ymin = MAXSHORT; + spanGroup->ymax = MINSHORT; +} diff --git a/xorg-server/mi/mispans.h b/xorg-server/mi/mispans.h new file mode 100644 index 000000000..258b29279 --- /dev/null +++ b/xorg-server/mi/mispans.h @@ -0,0 +1,99 @@ +/*********************************************************** + +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, 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 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/xorg-server/mi/misprite.c b/xorg-server/mi/misprite.c new file mode 100644 index 000000000..0af3368b6 --- /dev/null +++ b/xorg-server/mi/misprite.c @@ -0,0 +1,780 @@ +/* + * 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 DevPrivateKey miSpriteScreenKey = &miSpriteScreenKey; + +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 miSpriteComputeSaved(ScreenPtr pScreen); + +#define SCREEN_PROLOGUE(pScreen, field) ((pScreen)->field = \ + ((miSpriteScreenPtr)dixLookupPrivate(&(pScreen)->devPrivates, \ + miSpriteScreenKey))->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)dixLookupPrivate(&pScreen->devPrivates, + miSpriteScreenKey); + 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; + + 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->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; + dixSetPrivate(&pScreen->devPrivates, miSpriteScreenKey, pScreenPriv); + + pScreen->CloseScreen = miSpriteCloseScreen; + pScreen->GetImage = miSpriteGetImage; + pScreen->GetSpans = miSpriteGetSpans; + pScreen->SourceValidate = miSpriteSourceValidate; + + pScreen->CopyWindow = miSpriteCopyWindow; + + 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)dixLookupPrivate(&pScreen->devPrivates, + miSpriteScreenKey); + 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; + + 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)dixLookupPrivate(&pScreen->devPrivates, + miSpriteScreenKey); + 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)dixLookupPrivate(&pScreen->devPrivates, + miSpriteScreenKey); + if (pDrawable->type == DRAWABLE_WINDOW && pScreenPriv->isUp) + { + DDXPointPtr pts; + int *widths; + int nPts; + int xorg, + yorg; + + xorg = pDrawable->x; + yorg = pDrawable->y; + + for (pts = ppt, widths = pwidth, nPts = nspans; + nPts--; + pts++, widths++) + { + if (SPN_OVERLAP(&pScreenPriv->saved,pts->y+yorg, + pts->x+xorg,*widths)) + { + SPRITE_DEBUG (("GetSpans remove\n")); + miSpriteRemoveCursor (pScreen); + break; + } + } + } + + (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart); + + SCREEN_EPILOGUE (pScreen, GetSpans); +} + +static void +miSpriteSourceValidate (pDrawable, x, y, width, height) + DrawablePtr pDrawable; + int x, y, width, height; +{ + ScreenPtr pScreen = pDrawable->pScreen; + miSpriteScreenPtr pScreenPriv; + + SCREEN_PROLOGUE (pScreen, SourceValidate); + + pScreenPriv = (miSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates, + miSpriteScreenKey); + 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)dixLookupPrivate(&pScreen->devPrivates, + miSpriteScreenKey); + /* + * 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)dixLookupPrivate(&pScreen->devPrivates, + miSpriteScreenKey); + 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)dixLookupPrivate(&pScreen->devPrivates, + miSpriteScreenKey); + 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)dixLookupPrivate(&pScreen->devPrivates, + miSpriteScreenKey); + 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) + dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); + 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; +} + +/* + * miPointer interface routines + */ + +#define SPRITE_PAD 8 + +static Bool +miSpriteRealizeCursor (pScreen, pCursor) + ScreenPtr pScreen; + CursorPtr pCursor; +{ + miSpriteScreenPtr pScreenPriv; + + pScreenPriv = (miSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates, + miSpriteScreenKey); + 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)dixLookupPrivate(&pScreen->devPrivates, + miSpriteScreenKey); + 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)dixLookupPrivate(&pScreen->devPrivates, + miSpriteScreenKey); + 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)dixLookupPrivate(&pScreen->devPrivates, + miSpriteScreenKey); + miSpriteSetCursor (pScreen, pScreenPriv->pCursor, x, y); +} + +/* + * undraw/draw cursor + */ + +static void +miSpriteRemoveCursor (pScreen) + ScreenPtr pScreen; +{ + miSpriteScreenPtr pScreenPriv; + + DamageDrawInternal (pScreen, TRUE); + pScreenPriv = (miSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates, + miSpriteScreenKey); + 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)dixLookupPrivate(&pScreen->devPrivates, + miSpriteScreenKey); + 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)dixLookupPrivate(&pScreen->devPrivates, + miSpriteScreenKey); + 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/xorg-server/mi/misprite.h b/xorg-server/mi/misprite.h new file mode 100644 index 000000000..5173b7736 --- /dev/null +++ b/xorg-server/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/xorg-server/mi/mispritest.h b/xorg-server/mi/mispritest.h new file mode 100644 index 000000000..e8251ead2 --- /dev/null +++ b/xorg-server/mi/mispritest.h @@ -0,0 +1,129 @@ +/* + * 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; + + /* 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/xorg-server/mi/mistruct.h b/xorg-server/mi/mistruct.h new file mode 100644 index 000000000..e9cfed5a4 --- /dev/null +++ b/xorg-server/mi/mistruct.h @@ -0,0 +1,63 @@ +/*********************************************************** + +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 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/xorg-server/mi/mivalidate.h b/xorg-server/mi/mivalidate.h new file mode 100644 index 000000000..ef258c0f8 --- /dev/null +++ b/xorg-server/mi/mivalidate.h @@ -0,0 +1,52 @@ +/* + +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 + +#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/xorg-server/mi/mivaltree.c b/xorg-server/mi/mivaltree.c new file mode 100644 index 000000000..d9d07caad --- /dev/null +++ b/xorg-server/mi/mivaltree.c @@ -0,0 +1,821 @@ +/* + * 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; + int x, y; +{ + BoxRec box; + BoxPtr boundBox; + int nbox; + Bool someIn, someOut; + 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; +} + +/* + * Manual redirected windows are treated as transparent; they do not obscure + * siblings or parent windows + */ + +#ifdef COMPOSITE +#define TreatAsTransparent(w) ((w)->redirectDraw == RedirectDrawManual) +#else +#define TreatAsTransparent(w) FALSE +#endif + +#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 ( + WindowPtr pParent, + ScreenPtr pScreen, + RegionPtr universe, + VTKind kind, + RegionPtr exposed ) /* for intermediate calculations */ +{ + int dx, + dy; + RegionRec childUniverse; + 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 != RedirectDrawNone) + { + if (miSetRedirectBorderClipProc) + { + if (TreatAsTransparent (pParent)) + REGION_EMPTY (pScreen, universe); + (*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 && !TreatAsTransparent(pChild)) + REGION_APPEND( pScreen, &childUnion, &pChild->borderSize); + } + } + else + { + for (pChild = pParent->lastChild; pChild; pChild = pChild->prevSib) + { + if (pChild->viewable && !TreatAsTransparent(pChild)) + 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 && !TreatAsTransparent (pChild)) + 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); + } + + /* 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( + WindowPtr pParent ) +{ + WindowPtr pChild; + 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 */ + ScreenPtr pScreen; + 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 && !TreatAsTransparent (pWin)) + 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 != RedirectDrawNone && 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 != RedirectDrawNone && 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 && !TreatAsTransparent (pWin)) + REGION_APPEND( pScreen, &childUnion, + &pWin->borderSize); + } + else + { + pWin = pParent->lastChild; + while (1) + { + if (pWin->valdata && pWin->viewable && !TreatAsTransparent (pWin)) + 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 && !TreatAsTransparent (pWin)) + { + 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: + 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/xorg-server/mi/miwideline.c b/xorg-server/mi/miwideline.c new file mode 100644 index 000000000..f080ca11d --- /dev/null +++ b/xorg-server/mi/miwideline.c @@ -0,0 +1,2206 @@ +/* + +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" + +static void miLineArc(DrawablePtr pDraw, GCPtr pGC, + unsigned long pixel, SpanDataPtr spanData, + LineFacePtr leftFace, + LineFacePtr rightFace, + double xorg, double yorg, Bool isInt); + + +/* + * spans-based polygon filler + */ + +static 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) +{ + int left_x = 0, left_e = 0; + int left_stepx = 0; + int left_signdx = 0; + int left_dy = 0, left_dx = 0; + + 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; + + DDXPointPtr ppt; + DDXPointPtr pptInit = NULL; + int *pwidth; + int *pwidthInit = NULL; + XID oldPixel; + int xorg; + Spans spanRec; + + left_height = 0; + right_height = 0; + + if (!spanData) + { + pptInit = (DDXPointPtr) xalloc (overall_height * sizeof(*ppt)); + if (!pptInit) + return; + pwidthInit = (int *) xalloc (overall_height * sizeof(*pwidth)); + if (!pwidthInit) + { + xfree (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); + xfree (pwidthInit); + xfree (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) +{ + DDXPointPtr ppt; + 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 */ + int dx, dy; + int xi, yi; + int left; + 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) + PolyVertexPtr vertices; + PolySlopePtr slopes; + int count; + int xi, yi; + PolyEdgePtr left, right; + int *pnleft, *pnright; + int *h; +{ + int top, bottom; + double miny, maxy; + int i; + int j; + int clockwise; + int slopeoff; + int s; + 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, + LineFacePtr pLeft, + 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) +{ + DDXPointPtr tpts, bpts; + int *twids, *bwids; + 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) +{ + DDXPointPtr pts; + 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); +} + +static int +miRoundJoinFace (LineFacePtr face, 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) + 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) + LineFacePtr face; + Bool isInt; + PolyEdgePtr edge; + Bool *leftEdge; +{ + int y; + 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, + GCPtr pGC, + unsigned long pixel, + SpanDataPtr spanData, + LineFacePtr leftFace, + 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)xalloc(sizeof(DDXPointRec) * pGC->lineWidth); + if (!points) + return; + widths = (int *)xalloc(sizeof(int) * pGC->lineWidth); + if (!widths) + { + xfree(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); + xfree(widths); + xfree(points); + if (pixel != oldPixel) + { + DoChangeGC(pGC, GCForeground, &oldPixel, FALSE); + ValidateGC (pDraw, pGC); + } + } + else + { + spanRec.count = n; + AppendSpanGroup (pGC, pixel, &spanRec, spanData) + } +} + +static void +miLineProjectingCap (DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel, + SpanDataPtr spanData, LineFacePtr face, Bool isLeft, + double xorg, double 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, + int x1, + int y1, + int x2, + int y2, + Bool projectLeft, + Bool projectRight, + LineFacePtr leftFace, + 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); + } +} + +static SpanDataPtr +miSetupSpanData (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; +} + +static void +miCleanupSpanData (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; + GCPtr pGC; + int mode; + int npt; + DDXPointPtr pPts; +{ + int x1, y1, x2, y2; + SpanDataRec spanDataRec; + SpanDataPtr spanData; + long pixel; + Bool projectLeft, projectRight; + LineFaceRec leftFace, rightFace, prevRightFace; + LineFaceRec firstFace; + 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, + 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; + GCPtr pGC; + int mode; + int npt; + DDXPointPtr pPts; +{ + int x1, y1, x2, y2; + unsigned long pixel; + Bool projectLeft, projectRight; + LineFaceRec leftFace, rightFace, prevRightFace; + LineFaceRec firstFace; + int first; + int dashIndex, dashOffset; + 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/xorg-server/mi/miwideline.h b/xorg-server/mi/miwideline.h new file mode 100644 index 000000000..9d1aa03cb --- /dev/null +++ b/xorg-server/mi/miwideline.h @@ -0,0 +1,180 @@ +/* + +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 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 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/xorg-server/mi/miwindow.c b/xorg-server/mi/miwindow.c new file mode 100644 index 000000000..cb8400c0c --- /dev/null +++ b/xorg-server/mi/miwindow.c @@ -0,0 +1,1105 @@ +/*********************************************************** + +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, ®, &box, 1); + + REGION_INTERSECT(pScreen, ®, ®, &pWin->clipList); + if (generateExposures) + (*pScreen->WindowExposures)(pWin, ®, pBSReg); + else if (pWin->backgroundState != None) + miPaintWindow(pWin, ®, PW_BACKGROUND); + REGION_UNINIT(pScreen, ®); + 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( + WindowPtr pParent, /* Parent to check */ + WindowPtr pFirst, /* first reconfigured window */ + RegionPtr pRegion) /* Initial area obscured by saveUnder */ +{ + WindowPtr pChild; /* Current child */ + 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) + WindowPtr pWin; + WindowPtr first; /* First window to check. + * Used when pWin was restacked */ +{ + RegionRec rgn; /* Area obscured by saveUnder windows */ + 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; +{ + 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) + WindowPtr pWin; +{ + 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; +{ + BoxPtr box; + 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; +{ + WindowPtr pChild; + 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)) + miPaintWindow(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) + 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; + 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 ( + WindowPtr pWin, + pointer value) /* must conform to VisitWindowProcPtr */ +{ + 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) + 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; + ScreenPtr pScreen; + WindowPtr pFirstChange; + WindowPtr pChild; + RegionPtr gravitate[StaticGravity + 1]; + 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 */ + 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 (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 (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 (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); + } + 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) + WindowPtr pWin; +{ + Bool WasViewable = (Bool)(pWin->viewable); + ScreenPtr pScreen = pWin->drawable.pScreen; + Bool anyMarked = FALSE; +#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) + { + 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 (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) + WindowPtr pWin; + unsigned int width; +{ + int oldwidth; + Bool anyMarked = FALSE; + 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/xorg-server/mi/mizerarc.c b/xorg-server/mi/mizerarc.c new file mode 100644 index 000000000..947b85aac --- /dev/null +++ b/xorg-server/mi/mizerarc.c @@ -0,0 +1,851 @@ +/************************************************************ + +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) + xArc *arc; + 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); + +static DDXPointPtr +miZeroArcPts(xArc *arc, DDXPointPtr pts) +{ + miZeroArcRec info; + int x, y, a, b, d, mask; + 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, + DDXPointPtr points, + int maxPts, + DDXPointPtr *evenPts, + DDXPointPtr *oddPts ) +{ + miZeroArcRec info; + int x, y, a, b, d, mask; + 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; + int n, maxw = 0; + xArc *arc; + int i; + DDXPointPtr points, pts, oddPts; + 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 *)xalloc(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)xalloc(sizeof(DDXPointRec) * numPts); + if (!points) + { + if (dospans) + { + xfree(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); + } + } + } + xfree(points); + if (dospans) + { + xfree(widths); + } +} diff --git a/xorg-server/mi/mizerarc.h b/xorg-server/mi/mizerarc.h new file mode 100644 index 000000000..28ebbe030 --- /dev/null +++ b/xorg-server/mi/mizerarc.h @@ -0,0 +1,126 @@ +/************************************************************ + +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*/ +); diff --git a/xorg-server/mi/mizerclip.c b/xorg-server/mi/mizerclip.c new file mode 100644 index 000000000..b167c5475 --- /dev/null +++ b/xorg-server/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/xorg-server/mi/mizerline.c b/xorg-server/mi/mizerline.c new file mode 100644 index 000000000..6604a0923 --- /dev/null +++ b/xorg-server/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)xalloc(list_len * sizeof(DDXPointRec)); + pwidthInit = (int *)xalloc(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); + + xfree(pwidthInit); + xfree(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; +} |